blob: 7aac2584d078467626a5af98cab64d2ea37c117d [file] [log] [blame]
Nick Kledzik2458bec2014-07-16 19:49:02 +00001//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ArchHandler.h"
11#include "Atoms.h"
12#include "MachONormalizedFileBinaryUtils.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000013#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/StringSwitch.h"
15#include "llvm/ADT/Triple.h"
Tim Northover40d3ad32014-10-27 22:48:35 +000016#include "llvm/Support/Endian.h"
Nick Kledzik2458bec2014-07-16 19:49:02 +000017#include "llvm/Support/ErrorHandling.h"
18
19using namespace llvm::MachO;
20using namespace lld::mach_o::normalized;
21
22namespace lld {
23namespace mach_o {
24
Tim Northover40d3ad32014-10-27 22:48:35 +000025using llvm::support::ulittle16_t;
26using llvm::support::ulittle32_t;
27
28using llvm::support::little16_t;
29using llvm::support::little32_t;
30
Nick Kledzik2458bec2014-07-16 19:49:02 +000031class ArchHandler_x86 : public ArchHandler {
32public:
Rui Ueyama9071e4a2015-09-10 18:51:36 +000033 ArchHandler_x86() = default;
34 ~ArchHandler_x86() override = default;
Nick Kledzik2458bec2014-07-16 19:49:02 +000035
36 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
37
38 Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
39
40 const StubInfo &stubInfo() override { return _sStubInfo; }
41 bool isCallSite(const Reference &) override;
Nick Kledzik4121bce2014-10-14 01:51:42 +000042 bool isNonCallBranch(const Reference &) override {
43 return false;
44 }
45
Nick Kledzik2458bec2014-07-16 19:49:02 +000046 bool isPointer(const Reference &) override;
47 bool isPairedReloc(const normalized::Relocation &) override;
Tim Northovercf78d372014-09-30 21:29:54 +000048
49 bool needsCompactUnwind() override {
50 return false;
51 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000052
Tim Northovercf78d372014-09-30 21:29:54 +000053 Reference::KindValue imageOffsetKind() override {
54 return invalid;
55 }
Rui Ueyama9071e4a2015-09-10 18:51:36 +000056
Tim Northovercf78d372014-09-30 21:29:54 +000057 Reference::KindValue imageOffsetKindIndirect() override {
58 return invalid;
59 }
60
Tim Northover995abe32014-10-15 20:26:24 +000061 Reference::KindValue unwindRefToCIEKind() override {
62 return negDelta32;
63 }
64
Tim Northovera6a6ab92014-10-15 18:19:31 +000065 Reference::KindValue unwindRefToFunctionKind() override{
66 return delta32;
67 }
68
Tim Northover1cc4fb72014-10-15 19:32:21 +000069 Reference::KindValue unwindRefToEhFrameKind() override {
70 return invalid;
71 }
72
Tim Northover1cc4fb72014-10-15 19:32:21 +000073 uint32_t dwarfCompactUnwindType() override {
74 return 0x04000000U;
75 }
76
Nick Kledzik2458bec2014-07-16 19:49:02 +000077 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
78 const DefinedAtom *inAtom,
79 uint32_t offsetInAtom,
80 uint64_t fixupAddress, bool swap,
81 FindAtomBySectionAndAddress atomFromAddress,
82 FindAtomBySymbolIndex atomFromSymbolIndex,
83 Reference::KindValue *kind,
84 const lld::Atom **target,
85 Reference::Addend *addend) override;
86 std::error_code
87 getPairReferenceInfo(const normalized::Relocation &reloc1,
88 const normalized::Relocation &reloc2,
89 const DefinedAtom *inAtom,
90 uint32_t offsetInAtom,
Nick Kledzik9133f8c2014-10-21 23:45:37 +000091 uint64_t fixupAddress, bool swap, bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +000092 FindAtomBySectionAndAddress atomFromAddress,
93 FindAtomBySymbolIndex atomFromSymbolIndex,
94 Reference::KindValue *kind,
95 const lld::Atom **target,
96 Reference::Addend *addend) override;
97
Nick Kledzik2d432352014-07-17 23:16:21 +000098 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
99 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000100 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000101 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +0000102 uint8_t *atomContentBuffer) override;
103
104 void appendSectionRelocations(const DefinedAtom &atom,
105 uint64_t atomSectionOffset,
106 const Reference &ref,
107 FindSymbolIndexForAtom symbolIndexForAtom,
108 FindSectionIndexForAtom sectionIndexForAtom,
109 FindAddressForAtom addressForAtom,
110 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000111
Nick Kledzik21921372014-07-24 23:06:56 +0000112 bool isDataInCodeTransition(Reference::KindValue refKind) override {
113 switch (refKind) {
114 case modeCode:
115 case modeData:
116 return true;
117 default:
118 return false;
119 break;
120 }
121 }
122
123 Reference::KindValue dataInCodeTransitionStart(
124 const MachODefinedAtom &atom) override {
125 return modeData;
126 }
127
128 Reference::KindValue dataInCodeTransitionEnd(
129 const MachODefinedAtom &atom) override {
130 return modeCode;
131 }
132
Nick Kledzik2458bec2014-07-16 19:49:02 +0000133private:
134 static const Registry::KindStrings _sKindStrings[];
135 static const StubInfo _sStubInfo;
136
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000137 enum X86Kind : Reference::KindValue {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000138 invalid, /// for error condition
139
Nick Kledzik21921372014-07-24 23:06:56 +0000140 modeCode, /// Content starting at this offset is code.
141 modeData, /// Content starting at this offset is data.
142
Nick Kledzik2458bec2014-07-16 19:49:02 +0000143 // Kinds found in mach-o .o files:
144 branch32, /// ex: call _foo
145 branch16, /// ex: callw _foo
146 abs32, /// ex: movl _foo, %eax
147 funcRel32, /// ex: movl _foo-L1(%eax), %eax
148 pointer32, /// ex: .long _foo
149 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000150 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000151
152 // Kinds introduced by Passes:
153 lazyPointer, /// Location contains a lazy pointer.
154 lazyImmediateLocation, /// Location contains immediate value used in stub.
155 };
Shankar Easwarana1d36372015-02-22 23:54:38 +0000156
Nick Kledzik2d432352014-07-17 23:16:21 +0000157 static bool useExternalRelocationTo(const Atom &target);
158
159 void applyFixupFinal(const Reference &ref, uint8_t *location,
160 uint64_t fixupAddress, uint64_t targetAddress,
161 uint64_t inAtomAddress);
162
163 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
164 uint64_t fixupAddress,
165 uint64_t targetAddress,
166 uint64_t inAtomAddress);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000167};
168
169//===----------------------------------------------------------------------===//
170// ArchHandler_x86
171//===----------------------------------------------------------------------===//
172
Nick Kledzik2458bec2014-07-16 19:49:02 +0000173const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
174 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000175 LLD_KIND_STRING_ENTRY(modeCode),
176 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000177 LLD_KIND_STRING_ENTRY(branch32),
178 LLD_KIND_STRING_ENTRY(branch16),
179 LLD_KIND_STRING_ENTRY(abs32),
180 LLD_KIND_STRING_ENTRY(funcRel32),
181 LLD_KIND_STRING_ENTRY(pointer32),
182 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000183 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000184 LLD_KIND_STRING_ENTRY(lazyPointer),
185 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
186 LLD_KIND_STRING_END
187};
188
189const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
190 "dyld_stub_binder",
191
Shankar Easwarana1d36372015-02-22 23:54:38 +0000192 // Lazy pointer references
Nick Kledzik2458bec2014-07-16 19:49:02 +0000193 { Reference::KindArch::x86, pointer32, 0, 0 },
194 { Reference::KindArch::x86, lazyPointer, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000195
Nick Kledzik2458bec2014-07-16 19:49:02 +0000196 // GOT pointer to dyld_stub_binder
197 { Reference::KindArch::x86, pointer32, 0, 0 },
198
199 // x86 code alignment
Shankar Easwarana1d36372015-02-22 23:54:38 +0000200 1,
201
Nick Kledzik2458bec2014-07-16 19:49:02 +0000202 // Stub size and code
Shankar Easwarana1d36372015-02-22 23:54:38 +0000203 6,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000204 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
205 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000206 { false, 0, 0, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000207
Nick Kledzik2458bec2014-07-16 19:49:02 +0000208 // Stub Helper size and code
209 10,
210 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
211 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
212 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
213 { Reference::KindArch::x86, branch32, 6, 0 },
Shankar Easwarana1d36372015-02-22 23:54:38 +0000214
Nick Kledzik2458bec2014-07-16 19:49:02 +0000215 // Stub Helper-Common size and code
216 12,
217 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
218 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
219 0x90 }, // nop
220 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000221 { false, 0, 0, 0 },
222 { Reference::KindArch::x86, abs32, 7, 0 },
223 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000224};
225
226bool ArchHandler_x86::isCallSite(const Reference &ref) {
227 return (ref.kindValue() == branch32);
228}
229
230bool ArchHandler_x86::isPointer(const Reference &ref) {
231 return (ref.kindValue() == pointer32);
232}
233
234bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
235 if (!reloc.scattered)
236 return false;
237 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
238 (reloc.type == GENERIC_RELOC_SECTDIFF);
239}
240
241std::error_code
242ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
243 const DefinedAtom *inAtom,
244 uint32_t offsetInAtom,
245 uint64_t fixupAddress, bool swap,
246 FindAtomBySectionAndAddress atomFromAddress,
247 FindAtomBySymbolIndex atomFromSymbolIndex,
248 Reference::KindValue *kind,
249 const lld::Atom **target,
250 Reference::Addend *addend) {
251 typedef std::error_code E;
252 DefinedAtom::ContentPermissions perms;
253 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
254 uint64_t targetAddress;
255 switch (relocPattern(reloc)) {
256 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
257 // ex: call _foo (and _foo undefined)
258 *kind = branch32;
259 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
260 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000261 *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000262 break;
263 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
264 // ex: call _foo (and _foo defined)
265 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000266 targetAddress =
267 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000268 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
269 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000270 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
271 // ex: call _foo+n (and _foo defined)
272 *kind = branch32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000273 targetAddress =
274 fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000275 if (E ec = atomFromAddress(0, reloc.value, target, addend))
276 return ec;
277 *addend = targetAddress - reloc.value;
278 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000279 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
280 // ex: callw _foo (and _foo undefined)
281 *kind = branch16;
282 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
283 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000284 *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000285 break;
286 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
287 // ex: callw _foo (and _foo defined)
288 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000289 targetAddress =
290 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000291 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
292 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000293 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
294 // ex: callw _foo+n (and _foo defined)
295 *kind = branch16;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000296 targetAddress =
297 fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000298 if (E ec = atomFromAddress(0, reloc.value, target, addend))
299 return ec;
300 *addend = targetAddress - reloc.value;
301 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000302 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
303 // ex: movl _foo, %eax (and _foo undefined)
304 // ex: .long _foo (and _foo undefined)
305 perms = inAtom->permissions();
306 *kind =
307 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
308 : pointer32;
309 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
310 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000311 *addend = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000312 break;
313 case GENERIC_RELOC_VANILLA | rLength4:
314 // ex: movl _foo, %eax (and _foo defined)
315 // ex: .long _foo (and _foo defined)
316 perms = inAtom->permissions();
317 *kind =
318 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
319 : pointer32;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000320 targetAddress = *(const ulittle32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000321 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
322 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000323 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
324 // ex: .long _foo+n (and _foo defined)
325 perms = inAtom->permissions();
326 *kind =
327 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
328 : pointer32;
329 if (E ec = atomFromAddress(0, reloc.value, target, addend))
330 return ec;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000331 *addend = *(const ulittle32_t *)fixupContent - reloc.value;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000332 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000333 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000334 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000335 }
336 return std::error_code();
337}
338
339std::error_code
340ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
341 const normalized::Relocation &reloc2,
342 const DefinedAtom *inAtom,
343 uint32_t offsetInAtom,
344 uint64_t fixupAddress, bool swap,
Nick Kledzik9133f8c2014-10-21 23:45:37 +0000345 bool scatterable,
Nick Kledzik2458bec2014-07-16 19:49:02 +0000346 FindAtomBySectionAndAddress atomFromAddr,
347 FindAtomBySymbolIndex atomFromSymbolIndex,
348 Reference::KindValue *kind,
349 const lld::Atom **target,
350 Reference::Addend *addend) {
351 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
352 std::error_code ec;
353 DefinedAtom::ContentPermissions perms = inAtom->permissions();
354 uint32_t fromAddress;
355 uint32_t toAddress;
356 uint32_t value;
357 const lld::Atom *fromTarget;
358 Reference::Addend offsetInTo;
359 Reference::Addend offsetInFrom;
360 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000361 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
362 GENERIC_RELOC_PAIR | rScattered | rLength4):
363 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
364 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000365 toAddress = reloc1.value;
366 fromAddress = reloc2.value;
Simon Atanasyan55c26992014-11-14 07:15:43 +0000367 value = *(const little32_t *)fixupContent;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000368 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
369 if (ec)
370 return ec;
371 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
372 if (ec)
373 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000374 if (fromTarget != inAtom) {
Shankar Easwarana1d36372015-02-22 23:54:38 +0000375 if (*target != inAtom)
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000376 return make_dynamic_error_code(
377 "SECTDIFF relocation where neither target is in atom");
Nick Kledzik03e16f22014-07-21 22:06:57 +0000378 *kind = negDelta32;
379 *addend = toAddress - value - fromAddress;
380 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000381 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000382 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
383 // SECTDIFF relocations are used in i386 codegen where the function
384 // prolog does a CALL to the next instruction which POPs the return
385 // address into EBX which becomes the pic-base register. The POP
386 // instruction is label the used for the subtrahend in expressions.
387 // The funcRel32 kind represents the 32-bit delta to some symbol from
388 // the start of the function (atom) containing the funcRel32.
389 *kind = funcRel32;
390 uint32_t ta = fromAddress + value - toAddress;
391 *addend = ta - offsetInFrom;
392 } else {
393 *kind = delta32;
394 *addend = fromAddress + value - toAddress;
395 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000396 }
397 return std::error_code();
398 break;
399 default:
Rui Ueyamae75e50c2015-04-14 02:34:09 +0000400 return make_dynamic_error_code("unsupported i386 relocation type");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000401 }
402}
403
Nick Kledzik2d432352014-07-17 23:16:21 +0000404void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000405 bool relocatable,
406 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000407 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000408 uint64_t imageBaseAddress,
409 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000410 // Copy raw bytes.
411 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
412 // Apply fix-ups.
413 for (const Reference *ref : atom) {
414 uint32_t offset = ref->offsetInAtom();
415 const Atom *target = ref->target();
416 uint64_t targetAddress = 0;
417 if (isa<DefinedAtom>(target))
418 targetAddress = findAddress(*target);
419 uint64_t atomAddress = findAddress(atom);
420 uint64_t fixupAddress = atomAddress + offset;
421 if (relocatable) {
422 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
423 fixupAddress, targetAddress,
424 atomAddress);
425 } else {
426 applyFixupFinal(*ref, &atomContentBuffer[offset],
427 fixupAddress, targetAddress,
428 atomAddress);
429 }
430 }
431}
432
Tim Northover40d3ad32014-10-27 22:48:35 +0000433void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000434 uint64_t fixupAddress,
435 uint64_t targetAddress,
436 uint64_t inAtomAddress) {
437 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000438 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000439 assert(ref.kindArch() == Reference::KindArch::x86);
Tim Northover40d3ad32014-10-27 22:48:35 +0000440 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000441 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000442 case branch32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000443 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000444 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000445 case branch16:
Tim Northover40d3ad32014-10-27 22:48:35 +0000446 *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000447 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000448 case pointer32:
449 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000450 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000451 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000452 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000453 *loc32 = targetAddress - inAtomAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000454 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000455 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000456 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000457 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000458 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000459 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000460 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000461 case modeCode:
462 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000463 case lazyPointer:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000464 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000465 break;
Nick Kledzikf373c772014-11-11 01:31:18 +0000466 case lazyImmediateLocation:
467 *loc32 = ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000468 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000469 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000470 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2458bec2014-07-16 19:49:02 +0000471 break;
472 }
473}
474
Nick Kledzik2d432352014-07-17 23:16:21 +0000475void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
Tim Northover40d3ad32014-10-27 22:48:35 +0000476 uint8_t *loc,
Nick Kledzik2d432352014-07-17 23:16:21 +0000477 uint64_t fixupAddress,
478 uint64_t targetAddress,
479 uint64_t inAtomAddress) {
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000480 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
481 return;
482 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000483 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Tim Northover40d3ad32014-10-27 22:48:35 +0000484 ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
485 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000486 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000487 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000488 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000489 *loc32 = ref.addend() - (fixupAddress + 4);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000490 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000491 *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000492 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000493 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000494 if (useExternalReloc)
Tim Northover40d3ad32014-10-27 22:48:35 +0000495 *loc16 = ref.addend() - (fixupAddress + 2);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000496 else
Tim Northover40d3ad32014-10-27 22:48:35 +0000497 *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000498 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000499 case pointer32:
500 case abs32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000501 *loc32 = targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000502 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000503 case funcRel32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000504 *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000505 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000506 case delta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000507 *loc32 = targetAddress - fixupAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000508 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000509 case negDelta32:
Tim Northover40d3ad32014-10-27 22:48:35 +0000510 *loc32 = fixupAddress - targetAddress + ref.addend();
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000511 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000512 case modeCode:
513 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000514 case lazyPointer:
515 case lazyImmediateLocation:
516 // do nothing
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000517 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000518 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000519 llvm_unreachable("invalid x86 Reference Kind");
Nick Kledzik2d432352014-07-17 23:16:21 +0000520 break;
521 }
522}
523
524bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
525 // Undefined symbols are referenced via external relocations.
526 if (isa<UndefinedAtom>(&target))
527 return true;
528 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
529 switch (defAtom->merge()) {
530 case DefinedAtom::mergeAsTentative:
531 // Tentative definitions are referenced via external relocations.
532 return true;
533 case DefinedAtom::mergeAsWeak:
534 case DefinedAtom::mergeAsWeakAndAddressUsed:
535 // Global weak-defs are referenced via external relocations.
536 return (defAtom->scope() == DefinedAtom::scopeGlobal);
537 default:
538 break;
539 }
540 }
541 // Everything else is reference via an internal relocation.
542 return false;
543}
544
Nick Kledzik2d432352014-07-17 23:16:21 +0000545void ArchHandler_x86::appendSectionRelocations(
546 const DefinedAtom &atom,
547 uint64_t atomSectionOffset,
548 const Reference &ref,
549 FindSymbolIndexForAtom symbolIndexForAtom,
550 FindSectionIndexForAtom sectionIndexForAtom,
551 FindAddressForAtom addressForAtom,
552 normalized::Relocations &relocs) {
553 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
554 return;
555 assert(ref.kindArch() == Reference::KindArch::x86);
556 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
557 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Jean-Daniel Dupasc31da702015-02-19 12:38:54 +0000558 switch (static_cast<X86Kind>(ref.kindValue())) {
Nick Kledzik21921372014-07-24 23:06:56 +0000559 case modeCode:
560 case modeData:
561 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000562 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000563 if (useExternalReloc) {
564 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
565 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
566 } else {
567 if (ref.addend() != 0)
568 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
569 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
570 else
571 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
572 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
573 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000574 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000575 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000576 if (useExternalReloc) {
577 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
578 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
579 } else {
580 if (ref.addend() != 0)
581 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
582 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
583 else
584 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
585 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
586 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000587 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000588 case pointer32:
589 case abs32:
590 if (useExternalReloc)
591 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000592 GENERIC_RELOC_VANILLA | rExtern | rLength4);
593 else {
594 if (ref.addend() != 0)
595 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
596 GENERIC_RELOC_VANILLA | rScattered | rLength4);
597 else
598 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000599 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000600 }
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000601 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000602 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000603 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
604 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
605 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
606 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000607 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000608 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000609 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
610 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
611 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
612 ref.offsetInAtom(),
613 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000614 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000615 case negDelta32:
616 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
617 ref.offsetInAtom(),
618 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
619 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
620 GENERIC_RELOC_PAIR | rScattered | rLength4);
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000621 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000622 case lazyPointer:
623 case lazyImmediateLocation:
624 llvm_unreachable("lazy reference kind implies Stubs pass was run");
625 break;
Jean-Daniel Dupas9c222632015-02-15 15:23:48 +0000626 case invalid:
Jean-Daniel Dupas1536f062015-02-14 09:10:25 +0000627 llvm_unreachable("unknown x86 Reference Kind");
628 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000629 }
630}
631
Nick Kledzik2458bec2014-07-16 19:49:02 +0000632std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
633 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
634}
635
636} // namespace mach_o
637} // namespace lld