blob: b46670929ed5e5afd9afb0503d136e570c238152 [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"
13
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/StringSwitch.h"
16#include "llvm/ADT/Triple.h"
17
18#include "llvm/Support/ErrorHandling.h"
19
20using namespace llvm::MachO;
21using namespace lld::mach_o::normalized;
22
23namespace lld {
24namespace mach_o {
25
26class ArchHandler_x86 : public ArchHandler {
27public:
28 ArchHandler_x86();
29 virtual ~ArchHandler_x86();
30
31 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
32
33 Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
34
35 const StubInfo &stubInfo() override { return _sStubInfo; }
36 bool isCallSite(const Reference &) override;
Nick Kledzik4121bce2014-10-14 01:51:42 +000037 bool isNonCallBranch(const Reference &) override {
38 return false;
39 }
40
Nick Kledzik2458bec2014-07-16 19:49:02 +000041 bool isPointer(const Reference &) override;
42 bool isPairedReloc(const normalized::Relocation &) override;
Tim Northovercf78d372014-09-30 21:29:54 +000043
44 bool needsCompactUnwind() override {
45 return false;
46 }
47 Reference::KindValue imageOffsetKind() override {
48 return invalid;
49 }
50 Reference::KindValue imageOffsetKindIndirect() override {
51 return invalid;
52 }
53
Tim Northover995abe32014-10-15 20:26:24 +000054 Reference::KindValue unwindRefToCIEKind() override {
55 return negDelta32;
56 }
57
Tim Northovera6a6ab92014-10-15 18:19:31 +000058 Reference::KindValue unwindRefToFunctionKind() override{
59 return delta32;
60 }
61
Tim Northover1cc4fb72014-10-15 19:32:21 +000062 Reference::KindValue unwindRefToEhFrameKind() override {
63 return invalid;
64 }
65
66
67 uint32_t dwarfCompactUnwindType() override {
68 return 0x04000000U;
69 }
70
Nick Kledzik2458bec2014-07-16 19:49:02 +000071 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
72 const DefinedAtom *inAtom,
73 uint32_t offsetInAtom,
74 uint64_t fixupAddress, bool swap,
75 FindAtomBySectionAndAddress atomFromAddress,
76 FindAtomBySymbolIndex atomFromSymbolIndex,
77 Reference::KindValue *kind,
78 const lld::Atom **target,
79 Reference::Addend *addend) override;
80 std::error_code
81 getPairReferenceInfo(const normalized::Relocation &reloc1,
82 const normalized::Relocation &reloc2,
83 const DefinedAtom *inAtom,
84 uint32_t offsetInAtom,
85 uint64_t fixupAddress, bool swap,
86 FindAtomBySectionAndAddress atomFromAddress,
87 FindAtomBySymbolIndex atomFromSymbolIndex,
88 Reference::KindValue *kind,
89 const lld::Atom **target,
90 Reference::Addend *addend) override;
91
Nick Kledzik2d432352014-07-17 23:16:21 +000092 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
93 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +000094 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +000095 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +000096 uint8_t *atomContentBuffer) override;
97
98 void appendSectionRelocations(const DefinedAtom &atom,
99 uint64_t atomSectionOffset,
100 const Reference &ref,
101 FindSymbolIndexForAtom symbolIndexForAtom,
102 FindSectionIndexForAtom sectionIndexForAtom,
103 FindAddressForAtom addressForAtom,
104 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000105
Nick Kledzik21921372014-07-24 23:06:56 +0000106 bool isDataInCodeTransition(Reference::KindValue refKind) override {
107 switch (refKind) {
108 case modeCode:
109 case modeData:
110 return true;
111 default:
112 return false;
113 break;
114 }
115 }
116
117 Reference::KindValue dataInCodeTransitionStart(
118 const MachODefinedAtom &atom) override {
119 return modeData;
120 }
121
122 Reference::KindValue dataInCodeTransitionEnd(
123 const MachODefinedAtom &atom) override {
124 return modeCode;
125 }
126
Nick Kledzik2458bec2014-07-16 19:49:02 +0000127private:
128 static const Registry::KindStrings _sKindStrings[];
129 static const StubInfo _sStubInfo;
130
131 enum : Reference::KindValue {
132 invalid, /// for error condition
133
Nick Kledzik21921372014-07-24 23:06:56 +0000134 modeCode, /// Content starting at this offset is code.
135 modeData, /// Content starting at this offset is data.
136
Nick Kledzik2458bec2014-07-16 19:49:02 +0000137 // Kinds found in mach-o .o files:
138 branch32, /// ex: call _foo
139 branch16, /// ex: callw _foo
140 abs32, /// ex: movl _foo, %eax
141 funcRel32, /// ex: movl _foo-L1(%eax), %eax
142 pointer32, /// ex: .long _foo
143 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000144 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000145
146 // Kinds introduced by Passes:
147 lazyPointer, /// Location contains a lazy pointer.
148 lazyImmediateLocation, /// Location contains immediate value used in stub.
149 };
150
Nick Kledzik2d432352014-07-17 23:16:21 +0000151 static bool useExternalRelocationTo(const Atom &target);
152
153 void applyFixupFinal(const Reference &ref, uint8_t *location,
154 uint64_t fixupAddress, uint64_t targetAddress,
155 uint64_t inAtomAddress);
156
157 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
158 uint64_t fixupAddress,
159 uint64_t targetAddress,
160 uint64_t inAtomAddress);
161
Nick Kledzik2458bec2014-07-16 19:49:02 +0000162 const bool _swap;
163};
164
165//===----------------------------------------------------------------------===//
166// ArchHandler_x86
167//===----------------------------------------------------------------------===//
168
169ArchHandler_x86::ArchHandler_x86() :
170 _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86)) {}
171
172ArchHandler_x86::~ArchHandler_x86() { }
173
174const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
175 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000176 LLD_KIND_STRING_ENTRY(modeCode),
177 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000178 LLD_KIND_STRING_ENTRY(branch32),
179 LLD_KIND_STRING_ENTRY(branch16),
180 LLD_KIND_STRING_ENTRY(abs32),
181 LLD_KIND_STRING_ENTRY(funcRel32),
182 LLD_KIND_STRING_ENTRY(pointer32),
183 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000184 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000185 LLD_KIND_STRING_ENTRY(lazyPointer),
186 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
187 LLD_KIND_STRING_END
188};
189
190const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
191 "dyld_stub_binder",
192
193 // Lazy pointer references
194 { Reference::KindArch::x86, pointer32, 0, 0 },
195 { Reference::KindArch::x86, lazyPointer, 0, 0 },
196
197 // GOT pointer to dyld_stub_binder
198 { Reference::KindArch::x86, pointer32, 0, 0 },
199
200 // x86 code alignment
201 1,
202
203 // Stub size and code
204 6,
205 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
206 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000207 { false, 0, 0, 0 },
Nick Kledzik2458bec2014-07-16 19:49:02 +0000208
209 // Stub Helper size and code
210 10,
211 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
212 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
213 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
214 { Reference::KindArch::x86, branch32, 6, 0 },
215
216 // Stub Helper-Common size and code
217 12,
218 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
219 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
220 0x90 }, // nop
221 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000222 { false, 0, 0, 0 },
223 { Reference::KindArch::x86, abs32, 7, 0 },
224 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000225};
226
227bool ArchHandler_x86::isCallSite(const Reference &ref) {
228 return (ref.kindValue() == branch32);
229}
230
231bool ArchHandler_x86::isPointer(const Reference &ref) {
232 return (ref.kindValue() == pointer32);
233}
234
235bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
236 if (!reloc.scattered)
237 return false;
238 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
239 (reloc.type == GENERIC_RELOC_SECTDIFF);
240}
241
242std::error_code
243ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
244 const DefinedAtom *inAtom,
245 uint32_t offsetInAtom,
246 uint64_t fixupAddress, bool swap,
247 FindAtomBySectionAndAddress atomFromAddress,
248 FindAtomBySymbolIndex atomFromSymbolIndex,
249 Reference::KindValue *kind,
250 const lld::Atom **target,
251 Reference::Addend *addend) {
252 typedef std::error_code E;
253 DefinedAtom::ContentPermissions perms;
254 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
255 uint64_t targetAddress;
256 switch (relocPattern(reloc)) {
257 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
258 // ex: call _foo (and _foo undefined)
259 *kind = branch32;
260 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
261 return ec;
262 *addend = fixupAddress + 4 + readS32(swap, fixupContent);
263 break;
264 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
265 // ex: call _foo (and _foo defined)
266 *kind = branch32;
267 targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
268 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;
273 targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
274 if (E ec = atomFromAddress(0, reloc.value, target, addend))
275 return ec;
276 *addend = targetAddress - reloc.value;
277 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000278 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
279 // ex: callw _foo (and _foo undefined)
280 *kind = branch16;
281 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
282 return ec;
283 *addend = fixupAddress + 2 + readS16(swap, fixupContent);
284 break;
285 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
286 // ex: callw _foo (and _foo defined)
287 *kind = branch16;
288 targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
289 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
290 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000291 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
292 // ex: callw _foo+n (and _foo defined)
293 *kind = branch16;
294 targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
295 if (E ec = atomFromAddress(0, reloc.value, target, addend))
296 return ec;
297 *addend = targetAddress - reloc.value;
298 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000299 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
300 // ex: movl _foo, %eax (and _foo undefined)
301 // ex: .long _foo (and _foo undefined)
302 perms = inAtom->permissions();
303 *kind =
304 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
305 : pointer32;
306 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
307 return ec;
308 *addend = readU32(swap, fixupContent);
309 break;
310 case GENERIC_RELOC_VANILLA | rLength4:
311 // ex: movl _foo, %eax (and _foo defined)
312 // ex: .long _foo (and _foo defined)
313 perms = inAtom->permissions();
314 *kind =
315 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
316 : pointer32;
317 targetAddress = readU32(swap, fixupContent);
318 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
319 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000320 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
321 // ex: .long _foo+n (and _foo defined)
322 perms = inAtom->permissions();
323 *kind =
324 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
325 : pointer32;
326 if (E ec = atomFromAddress(0, reloc.value, target, addend))
327 return ec;
328 *addend = readU32(swap, fixupContent) - reloc.value;
329 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000330 default:
331 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
332 }
333 return std::error_code();
334}
335
336std::error_code
337ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
338 const normalized::Relocation &reloc2,
339 const DefinedAtom *inAtom,
340 uint32_t offsetInAtom,
341 uint64_t fixupAddress, bool swap,
342 FindAtomBySectionAndAddress atomFromAddr,
343 FindAtomBySymbolIndex atomFromSymbolIndex,
344 Reference::KindValue *kind,
345 const lld::Atom **target,
346 Reference::Addend *addend) {
347 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
348 std::error_code ec;
349 DefinedAtom::ContentPermissions perms = inAtom->permissions();
350 uint32_t fromAddress;
351 uint32_t toAddress;
352 uint32_t value;
353 const lld::Atom *fromTarget;
354 Reference::Addend offsetInTo;
355 Reference::Addend offsetInFrom;
356 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000357 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
358 GENERIC_RELOC_PAIR | rScattered | rLength4):
359 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
360 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000361 toAddress = reloc1.value;
362 fromAddress = reloc2.value;
363 value = readS32(swap, fixupContent);
364 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
365 if (ec)
366 return ec;
367 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
368 if (ec)
369 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000370 if (fromTarget != inAtom) {
371 if (*target != inAtom)
372 return make_dynamic_error_code(Twine("SECTDIFF relocation where "
373 "neither target is in atom"));
374 *kind = negDelta32;
375 *addend = toAddress - value - fromAddress;
376 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000377 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000378 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
379 // SECTDIFF relocations are used in i386 codegen where the function
380 // prolog does a CALL to the next instruction which POPs the return
381 // address into EBX which becomes the pic-base register. The POP
382 // instruction is label the used for the subtrahend in expressions.
383 // The funcRel32 kind represents the 32-bit delta to some symbol from
384 // the start of the function (atom) containing the funcRel32.
385 *kind = funcRel32;
386 uint32_t ta = fromAddress + value - toAddress;
387 *addend = ta - offsetInFrom;
388 } else {
389 *kind = delta32;
390 *addend = fromAddress + value - toAddress;
391 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000392 }
393 return std::error_code();
394 break;
395 default:
396 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
397 }
398}
399
Nick Kledzik2d432352014-07-17 23:16:21 +0000400void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000401 bool relocatable,
402 FindAddressForAtom findAddress,
Tim Northover1cc4fb72014-10-15 19:32:21 +0000403 FindAddressForAtom findSectionAddress,
Tim Northovercf78d372014-09-30 21:29:54 +0000404 uint64_t imageBaseAddress,
405 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000406 // Copy raw bytes.
407 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
408 // Apply fix-ups.
409 for (const Reference *ref : atom) {
410 uint32_t offset = ref->offsetInAtom();
411 const Atom *target = ref->target();
412 uint64_t targetAddress = 0;
413 if (isa<DefinedAtom>(target))
414 targetAddress = findAddress(*target);
415 uint64_t atomAddress = findAddress(atom);
416 uint64_t fixupAddress = atomAddress + offset;
417 if (relocatable) {
418 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
419 fixupAddress, targetAddress,
420 atomAddress);
421 } else {
422 applyFixupFinal(*ref, &atomContentBuffer[offset],
423 fixupAddress, targetAddress,
424 atomAddress);
425 }
426 }
427}
428
429void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *location,
430 uint64_t fixupAddress,
431 uint64_t targetAddress,
432 uint64_t inAtomAddress) {
433 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000434 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000435 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000436 int32_t *loc32 = reinterpret_cast<int32_t *>(location);
437 int16_t *loc16 = reinterpret_cast<int16_t *>(location);
Nick Kledzik2d432352014-07-17 23:16:21 +0000438 switch (ref.kindValue()) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000439 case branch32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000440 write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000441 break;
442 case branch16:
Nick Kledzik2d432352014-07-17 23:16:21 +0000443 write16(*loc16, _swap, (targetAddress - (fixupAddress + 2)) + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000444 break;
445 case pointer32:
446 case abs32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000447 write32(*loc32, _swap, targetAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000448 break;
449 case funcRel32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000450 write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000451 break;
452 case delta32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000453 write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000454 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000455 case negDelta32:
456 write32(*loc32, _swap, fixupAddress - targetAddress + ref.addend());
457 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000458 case modeCode:
459 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000460 case lazyPointer:
461 case lazyImmediateLocation:
462 // do nothing
463 break;
464 default:
465 llvm_unreachable("invalid x86 Reference Kind");
466 break;
467 }
468}
469
Nick Kledzik2d432352014-07-17 23:16:21 +0000470void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
471 uint8_t *location,
472 uint64_t fixupAddress,
473 uint64_t targetAddress,
474 uint64_t inAtomAddress) {
475 int32_t *loc32 = reinterpret_cast<int32_t *>(location);
476 int16_t *loc16 = reinterpret_cast<int16_t *>(location);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000477 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Nick Kledzik2d432352014-07-17 23:16:21 +0000478 switch (ref.kindValue()) {
479 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000480 if (useExternalReloc)
481 write32(*loc32, _swap, ref.addend() - (fixupAddress + 4));
482 else
483 write32(*loc32, _swap, (targetAddress - (fixupAddress+4)) + ref.addend());
Nick Kledzik2d432352014-07-17 23:16:21 +0000484 break;
485 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000486 if (useExternalReloc)
487 write16(*loc16, _swap, ref.addend() - (fixupAddress + 2));
488 else
489 write16(*loc16, _swap, (targetAddress - (fixupAddress+2)) + ref.addend());
Nick Kledzik2d432352014-07-17 23:16:21 +0000490 break;
491 case pointer32:
492 case abs32:
493 write32(*loc32, _swap, targetAddress + ref.addend());
494 break;
495 case funcRel32:
496 write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend()); // FIXME
497 break;
498 case delta32:
499 write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
500 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000501 case negDelta32:
502 write32(*loc32, _swap, fixupAddress - targetAddress + ref.addend());
503 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000504 case modeCode:
505 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000506 case lazyPointer:
507 case lazyImmediateLocation:
508 // do nothing
509 break;
510 default:
511 llvm_unreachable("invalid x86 Reference Kind");
512 break;
513 }
514}
515
516bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
517 // Undefined symbols are referenced via external relocations.
518 if (isa<UndefinedAtom>(&target))
519 return true;
520 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
521 switch (defAtom->merge()) {
522 case DefinedAtom::mergeAsTentative:
523 // Tentative definitions are referenced via external relocations.
524 return true;
525 case DefinedAtom::mergeAsWeak:
526 case DefinedAtom::mergeAsWeakAndAddressUsed:
527 // Global weak-defs are referenced via external relocations.
528 return (defAtom->scope() == DefinedAtom::scopeGlobal);
529 default:
530 break;
531 }
532 }
533 // Everything else is reference via an internal relocation.
534 return false;
535}
536
537
538void ArchHandler_x86::appendSectionRelocations(
539 const DefinedAtom &atom,
540 uint64_t atomSectionOffset,
541 const Reference &ref,
542 FindSymbolIndexForAtom symbolIndexForAtom,
543 FindSectionIndexForAtom sectionIndexForAtom,
544 FindAddressForAtom addressForAtom,
545 normalized::Relocations &relocs) {
546 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
547 return;
548 assert(ref.kindArch() == Reference::KindArch::x86);
549 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
550 bool useExternalReloc = useExternalRelocationTo(*ref.target());
551 switch (ref.kindValue()) {
Nick Kledzik21921372014-07-24 23:06:56 +0000552 case modeCode:
553 case modeData:
554 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000555 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000556 if (useExternalReloc) {
557 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
558 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
559 } else {
560 if (ref.addend() != 0)
561 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
562 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
563 else
564 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
565 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
566 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000567 break;
568 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000569 if (useExternalReloc) {
570 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
571 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
572 } else {
573 if (ref.addend() != 0)
574 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
575 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
576 else
577 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
578 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
579 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000580 break;
581 case pointer32:
582 case abs32:
583 if (useExternalReloc)
584 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000585 GENERIC_RELOC_VANILLA | rExtern | rLength4);
586 else {
587 if (ref.addend() != 0)
588 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
589 GENERIC_RELOC_VANILLA | rScattered | rLength4);
590 else
591 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000592 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000593 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000594 break;
595 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000596 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
597 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
598 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
599 GENERIC_RELOC_PAIR | rScattered | rLength4);
Nick Kledzik2d432352014-07-17 23:16:21 +0000600 break;
601 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000602 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
603 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
604 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
605 ref.offsetInAtom(),
606 GENERIC_RELOC_PAIR | rScattered | rLength4);
607 break;
608 case negDelta32:
609 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
610 ref.offsetInAtom(),
611 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
612 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
613 GENERIC_RELOC_PAIR | rScattered | rLength4);
Nick Kledzik2d432352014-07-17 23:16:21 +0000614 break;
615 case lazyPointer:
616 case lazyImmediateLocation:
617 llvm_unreachable("lazy reference kind implies Stubs pass was run");
618 break;
619 default:
620 llvm_unreachable("unknown x86 Reference Kind");
621 break;
622
623 }
624}
625
626
Nick Kledzik2458bec2014-07-16 19:49:02 +0000627std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
628 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
629}
630
631} // namespace mach_o
632} // namespace lld