blob: bd086f2839ba4fbfc49ca8e4887b6816c0a83b00 [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 Northovera6a6ab92014-10-15 18:19:31 +000054 Reference::KindValue unwindRefToFunctionKind() override{
55 return delta32;
56 }
57
Nick Kledzik2458bec2014-07-16 19:49:02 +000058 std::error_code getReferenceInfo(const normalized::Relocation &reloc,
59 const DefinedAtom *inAtom,
60 uint32_t offsetInAtom,
61 uint64_t fixupAddress, bool swap,
62 FindAtomBySectionAndAddress atomFromAddress,
63 FindAtomBySymbolIndex atomFromSymbolIndex,
64 Reference::KindValue *kind,
65 const lld::Atom **target,
66 Reference::Addend *addend) override;
67 std::error_code
68 getPairReferenceInfo(const normalized::Relocation &reloc1,
69 const normalized::Relocation &reloc2,
70 const DefinedAtom *inAtom,
71 uint32_t offsetInAtom,
72 uint64_t fixupAddress, bool swap,
73 FindAtomBySectionAndAddress atomFromAddress,
74 FindAtomBySymbolIndex atomFromSymbolIndex,
75 Reference::KindValue *kind,
76 const lld::Atom **target,
77 Reference::Addend *addend) override;
78
Nick Kledzik2d432352014-07-17 23:16:21 +000079 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
80 FindAddressForAtom findAddress,
Tim Northovercf78d372014-09-30 21:29:54 +000081 uint64_t imageBaseAddress,
Nick Kledzik2d432352014-07-17 23:16:21 +000082 uint8_t *atomContentBuffer) override;
83
84 void appendSectionRelocations(const DefinedAtom &atom,
85 uint64_t atomSectionOffset,
86 const Reference &ref,
87 FindSymbolIndexForAtom symbolIndexForAtom,
88 FindSectionIndexForAtom sectionIndexForAtom,
89 FindAddressForAtom addressForAtom,
90 normalized::Relocations &relocs) override;
Nick Kledzik2458bec2014-07-16 19:49:02 +000091
Nick Kledzik21921372014-07-24 23:06:56 +000092 bool isDataInCodeTransition(Reference::KindValue refKind) override {
93 switch (refKind) {
94 case modeCode:
95 case modeData:
96 return true;
97 default:
98 return false;
99 break;
100 }
101 }
102
103 Reference::KindValue dataInCodeTransitionStart(
104 const MachODefinedAtom &atom) override {
105 return modeData;
106 }
107
108 Reference::KindValue dataInCodeTransitionEnd(
109 const MachODefinedAtom &atom) override {
110 return modeCode;
111 }
112
Nick Kledzik2458bec2014-07-16 19:49:02 +0000113private:
114 static const Registry::KindStrings _sKindStrings[];
115 static const StubInfo _sStubInfo;
116
117 enum : Reference::KindValue {
118 invalid, /// for error condition
119
Nick Kledzik21921372014-07-24 23:06:56 +0000120 modeCode, /// Content starting at this offset is code.
121 modeData, /// Content starting at this offset is data.
122
Nick Kledzik2458bec2014-07-16 19:49:02 +0000123 // Kinds found in mach-o .o files:
124 branch32, /// ex: call _foo
125 branch16, /// ex: callw _foo
126 abs32, /// ex: movl _foo, %eax
127 funcRel32, /// ex: movl _foo-L1(%eax), %eax
128 pointer32, /// ex: .long _foo
129 delta32, /// ex: .long _foo - .
Nick Kledzik03e16f22014-07-21 22:06:57 +0000130 negDelta32, /// ex: .long . - _foo
Nick Kledzik2458bec2014-07-16 19:49:02 +0000131
132 // Kinds introduced by Passes:
133 lazyPointer, /// Location contains a lazy pointer.
134 lazyImmediateLocation, /// Location contains immediate value used in stub.
135 };
136
Nick Kledzik2d432352014-07-17 23:16:21 +0000137 static bool useExternalRelocationTo(const Atom &target);
138
139 void applyFixupFinal(const Reference &ref, uint8_t *location,
140 uint64_t fixupAddress, uint64_t targetAddress,
141 uint64_t inAtomAddress);
142
143 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
144 uint64_t fixupAddress,
145 uint64_t targetAddress,
146 uint64_t inAtomAddress);
147
Nick Kledzik2458bec2014-07-16 19:49:02 +0000148 const bool _swap;
149};
150
151//===----------------------------------------------------------------------===//
152// ArchHandler_x86
153//===----------------------------------------------------------------------===//
154
155ArchHandler_x86::ArchHandler_x86() :
156 _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86)) {}
157
158ArchHandler_x86::~ArchHandler_x86() { }
159
160const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
161 LLD_KIND_STRING_ENTRY(invalid),
Nick Kledzik21921372014-07-24 23:06:56 +0000162 LLD_KIND_STRING_ENTRY(modeCode),
163 LLD_KIND_STRING_ENTRY(modeData),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000164 LLD_KIND_STRING_ENTRY(branch32),
165 LLD_KIND_STRING_ENTRY(branch16),
166 LLD_KIND_STRING_ENTRY(abs32),
167 LLD_KIND_STRING_ENTRY(funcRel32),
168 LLD_KIND_STRING_ENTRY(pointer32),
169 LLD_KIND_STRING_ENTRY(delta32),
Nick Kledzik03e16f22014-07-21 22:06:57 +0000170 LLD_KIND_STRING_ENTRY(negDelta32),
Nick Kledzik2458bec2014-07-16 19:49:02 +0000171 LLD_KIND_STRING_ENTRY(lazyPointer),
172 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
173 LLD_KIND_STRING_END
174};
175
176const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
177 "dyld_stub_binder",
178
179 // Lazy pointer references
180 { Reference::KindArch::x86, pointer32, 0, 0 },
181 { Reference::KindArch::x86, lazyPointer, 0, 0 },
182
183 // GOT pointer to dyld_stub_binder
184 { Reference::KindArch::x86, pointer32, 0, 0 },
185
186 // x86 code alignment
187 1,
188
189 // Stub size and code
190 6,
191 { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
192 { Reference::KindArch::x86, abs32, 2, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000193 { false, 0, 0, 0 },
Nick Kledzik2458bec2014-07-16 19:49:02 +0000194
195 // Stub Helper size and code
196 10,
197 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
198 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
199 { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
200 { Reference::KindArch::x86, branch32, 6, 0 },
201
202 // Stub Helper-Common size and code
203 12,
204 { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
205 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
206 0x90 }, // nop
207 { Reference::KindArch::x86, abs32, 1, 0 },
Nick Kledzik1bebb282014-09-09 23:52:59 +0000208 { false, 0, 0, 0 },
209 { Reference::KindArch::x86, abs32, 7, 0 },
210 { false, 0, 0, 0 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000211};
212
213bool ArchHandler_x86::isCallSite(const Reference &ref) {
214 return (ref.kindValue() == branch32);
215}
216
217bool ArchHandler_x86::isPointer(const Reference &ref) {
218 return (ref.kindValue() == pointer32);
219}
220
221bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
222 if (!reloc.scattered)
223 return false;
224 return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
225 (reloc.type == GENERIC_RELOC_SECTDIFF);
226}
227
228std::error_code
229ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
230 const DefinedAtom *inAtom,
231 uint32_t offsetInAtom,
232 uint64_t fixupAddress, bool swap,
233 FindAtomBySectionAndAddress atomFromAddress,
234 FindAtomBySymbolIndex atomFromSymbolIndex,
235 Reference::KindValue *kind,
236 const lld::Atom **target,
237 Reference::Addend *addend) {
238 typedef std::error_code E;
239 DefinedAtom::ContentPermissions perms;
240 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
241 uint64_t targetAddress;
242 switch (relocPattern(reloc)) {
243 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
244 // ex: call _foo (and _foo undefined)
245 *kind = branch32;
246 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
247 return ec;
248 *addend = fixupAddress + 4 + readS32(swap, fixupContent);
249 break;
250 case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
251 // ex: call _foo (and _foo defined)
252 *kind = branch32;
253 targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
254 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
255 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000256 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
257 // ex: call _foo+n (and _foo defined)
258 *kind = branch32;
259 targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
260 if (E ec = atomFromAddress(0, reloc.value, target, addend))
261 return ec;
262 *addend = targetAddress - reloc.value;
263 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000264 case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
265 // ex: callw _foo (and _foo undefined)
266 *kind = branch16;
267 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
268 return ec;
269 *addend = fixupAddress + 2 + readS16(swap, fixupContent);
270 break;
271 case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
272 // ex: callw _foo (and _foo defined)
273 *kind = branch16;
274 targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
275 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
276 break;
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000277 case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
278 // ex: callw _foo+n (and _foo defined)
279 *kind = branch16;
280 targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
281 if (E ec = atomFromAddress(0, reloc.value, target, addend))
282 return ec;
283 *addend = targetAddress - reloc.value;
284 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000285 case GENERIC_RELOC_VANILLA | rExtern | rLength4:
286 // ex: movl _foo, %eax (and _foo undefined)
287 // ex: .long _foo (and _foo undefined)
288 perms = inAtom->permissions();
289 *kind =
290 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
291 : pointer32;
292 if (E ec = atomFromSymbolIndex(reloc.symbol, target))
293 return ec;
294 *addend = readU32(swap, fixupContent);
295 break;
296 case GENERIC_RELOC_VANILLA | rLength4:
297 // ex: movl _foo, %eax (and _foo defined)
298 // ex: .long _foo (and _foo defined)
299 perms = inAtom->permissions();
300 *kind =
301 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
302 : pointer32;
303 targetAddress = readU32(swap, fixupContent);
304 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
305 break;
Nick Kledzik7e246a42014-07-18 01:05:35 +0000306 case GENERIC_RELOC_VANILLA | rScattered | rLength4:
307 // ex: .long _foo+n (and _foo defined)
308 perms = inAtom->permissions();
309 *kind =
310 ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
311 : pointer32;
312 if (E ec = atomFromAddress(0, reloc.value, target, addend))
313 return ec;
314 *addend = readU32(swap, fixupContent) - reloc.value;
315 break;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000316 default:
317 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
318 }
319 return std::error_code();
320}
321
322std::error_code
323ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
324 const normalized::Relocation &reloc2,
325 const DefinedAtom *inAtom,
326 uint32_t offsetInAtom,
327 uint64_t fixupAddress, bool swap,
328 FindAtomBySectionAndAddress atomFromAddr,
329 FindAtomBySymbolIndex atomFromSymbolIndex,
330 Reference::KindValue *kind,
331 const lld::Atom **target,
332 Reference::Addend *addend) {
333 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
334 std::error_code ec;
335 DefinedAtom::ContentPermissions perms = inAtom->permissions();
336 uint32_t fromAddress;
337 uint32_t toAddress;
338 uint32_t value;
339 const lld::Atom *fromTarget;
340 Reference::Addend offsetInTo;
341 Reference::Addend offsetInFrom;
342 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000343 case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
344 GENERIC_RELOC_PAIR | rScattered | rLength4):
345 case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
346 GENERIC_RELOC_PAIR | rScattered | rLength4):
Nick Kledzik2458bec2014-07-16 19:49:02 +0000347 toAddress = reloc1.value;
348 fromAddress = reloc2.value;
349 value = readS32(swap, fixupContent);
350 ec = atomFromAddr(0, toAddress, target, &offsetInTo);
351 if (ec)
352 return ec;
353 ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
354 if (ec)
355 return ec;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000356 if (fromTarget != inAtom) {
357 if (*target != inAtom)
358 return make_dynamic_error_code(Twine("SECTDIFF relocation where "
359 "neither target is in atom"));
360 *kind = negDelta32;
361 *addend = toAddress - value - fromAddress;
362 *target = fromTarget;
Nick Kledzik2458bec2014-07-16 19:49:02 +0000363 } else {
Nick Kledzik03e16f22014-07-21 22:06:57 +0000364 if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
365 // SECTDIFF relocations are used in i386 codegen where the function
366 // prolog does a CALL to the next instruction which POPs the return
367 // address into EBX which becomes the pic-base register. The POP
368 // instruction is label the used for the subtrahend in expressions.
369 // The funcRel32 kind represents the 32-bit delta to some symbol from
370 // the start of the function (atom) containing the funcRel32.
371 *kind = funcRel32;
372 uint32_t ta = fromAddress + value - toAddress;
373 *addend = ta - offsetInFrom;
374 } else {
375 *kind = delta32;
376 *addend = fromAddress + value - toAddress;
377 }
Nick Kledzik2458bec2014-07-16 19:49:02 +0000378 }
379 return std::error_code();
380 break;
381 default:
382 return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
383 }
384}
385
Nick Kledzik2d432352014-07-17 23:16:21 +0000386void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
Tim Northovercf78d372014-09-30 21:29:54 +0000387 bool relocatable,
388 FindAddressForAtom findAddress,
389 uint64_t imageBaseAddress,
390 uint8_t *atomContentBuffer) {
Nick Kledzik2d432352014-07-17 23:16:21 +0000391 // Copy raw bytes.
392 memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
393 // Apply fix-ups.
394 for (const Reference *ref : atom) {
395 uint32_t offset = ref->offsetInAtom();
396 const Atom *target = ref->target();
397 uint64_t targetAddress = 0;
398 if (isa<DefinedAtom>(target))
399 targetAddress = findAddress(*target);
400 uint64_t atomAddress = findAddress(atom);
401 uint64_t fixupAddress = atomAddress + offset;
402 if (relocatable) {
403 applyFixupRelocatable(*ref, &atomContentBuffer[offset],
404 fixupAddress, targetAddress,
405 atomAddress);
406 } else {
407 applyFixupFinal(*ref, &atomContentBuffer[offset],
408 fixupAddress, targetAddress,
409 atomAddress);
410 }
411 }
412}
413
414void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *location,
415 uint64_t fixupAddress,
416 uint64_t targetAddress,
417 uint64_t inAtomAddress) {
418 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
Nick Kledzik2458bec2014-07-16 19:49:02 +0000419 return;
Nick Kledzik2d432352014-07-17 23:16:21 +0000420 assert(ref.kindArch() == Reference::KindArch::x86);
Nick Kledzik2458bec2014-07-16 19:49:02 +0000421 int32_t *loc32 = reinterpret_cast<int32_t *>(location);
422 int16_t *loc16 = reinterpret_cast<int16_t *>(location);
Nick Kledzik2d432352014-07-17 23:16:21 +0000423 switch (ref.kindValue()) {
Nick Kledzik2458bec2014-07-16 19:49:02 +0000424 case branch32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000425 write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000426 break;
427 case branch16:
Nick Kledzik2d432352014-07-17 23:16:21 +0000428 write16(*loc16, _swap, (targetAddress - (fixupAddress + 2)) + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000429 break;
430 case pointer32:
431 case abs32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000432 write32(*loc32, _swap, targetAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000433 break;
434 case funcRel32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000435 write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000436 break;
437 case delta32:
Nick Kledzik2d432352014-07-17 23:16:21 +0000438 write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
Nick Kledzik2458bec2014-07-16 19:49:02 +0000439 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000440 case negDelta32:
441 write32(*loc32, _swap, fixupAddress - targetAddress + ref.addend());
442 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000443 case modeCode:
444 case modeData:
Nick Kledzik2458bec2014-07-16 19:49:02 +0000445 case lazyPointer:
446 case lazyImmediateLocation:
447 // do nothing
448 break;
449 default:
450 llvm_unreachable("invalid x86 Reference Kind");
451 break;
452 }
453}
454
Nick Kledzik2d432352014-07-17 23:16:21 +0000455void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
456 uint8_t *location,
457 uint64_t fixupAddress,
458 uint64_t targetAddress,
459 uint64_t inAtomAddress) {
460 int32_t *loc32 = reinterpret_cast<int32_t *>(location);
461 int16_t *loc16 = reinterpret_cast<int16_t *>(location);
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000462 bool useExternalReloc = useExternalRelocationTo(*ref.target());
Nick Kledzik2d432352014-07-17 23:16:21 +0000463 switch (ref.kindValue()) {
464 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000465 if (useExternalReloc)
466 write32(*loc32, _swap, ref.addend() - (fixupAddress + 4));
467 else
468 write32(*loc32, _swap, (targetAddress - (fixupAddress+4)) + ref.addend());
Nick Kledzik2d432352014-07-17 23:16:21 +0000469 break;
470 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000471 if (useExternalReloc)
472 write16(*loc16, _swap, ref.addend() - (fixupAddress + 2));
473 else
474 write16(*loc16, _swap, (targetAddress - (fixupAddress+2)) + ref.addend());
Nick Kledzik2d432352014-07-17 23:16:21 +0000475 break;
476 case pointer32:
477 case abs32:
478 write32(*loc32, _swap, targetAddress + ref.addend());
479 break;
480 case funcRel32:
481 write32(*loc32, _swap, targetAddress - inAtomAddress + ref.addend()); // FIXME
482 break;
483 case delta32:
484 write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
485 break;
Nick Kledzik03e16f22014-07-21 22:06:57 +0000486 case negDelta32:
487 write32(*loc32, _swap, fixupAddress - targetAddress + ref.addend());
488 break;
Nick Kledzik21921372014-07-24 23:06:56 +0000489 case modeCode:
490 case modeData:
Nick Kledzik2d432352014-07-17 23:16:21 +0000491 case lazyPointer:
492 case lazyImmediateLocation:
493 // do nothing
494 break;
495 default:
496 llvm_unreachable("invalid x86 Reference Kind");
497 break;
498 }
499}
500
501bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
502 // Undefined symbols are referenced via external relocations.
503 if (isa<UndefinedAtom>(&target))
504 return true;
505 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
506 switch (defAtom->merge()) {
507 case DefinedAtom::mergeAsTentative:
508 // Tentative definitions are referenced via external relocations.
509 return true;
510 case DefinedAtom::mergeAsWeak:
511 case DefinedAtom::mergeAsWeakAndAddressUsed:
512 // Global weak-defs are referenced via external relocations.
513 return (defAtom->scope() == DefinedAtom::scopeGlobal);
514 default:
515 break;
516 }
517 }
518 // Everything else is reference via an internal relocation.
519 return false;
520}
521
522
523void ArchHandler_x86::appendSectionRelocations(
524 const DefinedAtom &atom,
525 uint64_t atomSectionOffset,
526 const Reference &ref,
527 FindSymbolIndexForAtom symbolIndexForAtom,
528 FindSectionIndexForAtom sectionIndexForAtom,
529 FindAddressForAtom addressForAtom,
530 normalized::Relocations &relocs) {
531 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
532 return;
533 assert(ref.kindArch() == Reference::KindArch::x86);
534 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
535 bool useExternalReloc = useExternalRelocationTo(*ref.target());
536 switch (ref.kindValue()) {
Nick Kledzik21921372014-07-24 23:06:56 +0000537 case modeCode:
538 case modeData:
539 break;
Nick Kledzik2d432352014-07-17 23:16:21 +0000540 case branch32:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000541 if (useExternalReloc) {
542 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
543 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
544 } else {
545 if (ref.addend() != 0)
546 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
547 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
548 else
549 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
550 GENERIC_RELOC_VANILLA | rPcRel | rLength4);
551 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000552 break;
553 case branch16:
Nick Kledzik68a1abd2014-07-18 00:37:52 +0000554 if (useExternalReloc) {
555 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
556 GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
557 } else {
558 if (ref.addend() != 0)
559 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
560 GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
561 else
562 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
563 GENERIC_RELOC_VANILLA | rPcRel | rLength2);
564 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000565 break;
566 case pointer32:
567 case abs32:
568 if (useExternalReloc)
569 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
Nick Kledzik7e246a42014-07-18 01:05:35 +0000570 GENERIC_RELOC_VANILLA | rExtern | rLength4);
571 else {
572 if (ref.addend() != 0)
573 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
574 GENERIC_RELOC_VANILLA | rScattered | rLength4);
575 else
576 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
Nick Kledzik2d432352014-07-17 23:16:21 +0000577 GENERIC_RELOC_VANILLA | rLength4);
Nick Kledzik7e246a42014-07-18 01:05:35 +0000578 }
Nick Kledzik2d432352014-07-17 23:16:21 +0000579 break;
580 case funcRel32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000581 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
582 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
583 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
584 GENERIC_RELOC_PAIR | rScattered | rLength4);
Nick Kledzik2d432352014-07-17 23:16:21 +0000585 break;
586 case delta32:
Nick Kledzik03e16f22014-07-21 22:06:57 +0000587 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
588 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
589 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
590 ref.offsetInAtom(),
591 GENERIC_RELOC_PAIR | rScattered | rLength4);
592 break;
593 case negDelta32:
594 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
595 ref.offsetInAtom(),
596 GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
597 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
598 GENERIC_RELOC_PAIR | rScattered | rLength4);
Nick Kledzik2d432352014-07-17 23:16:21 +0000599 break;
600 case lazyPointer:
601 case lazyImmediateLocation:
602 llvm_unreachable("lazy reference kind implies Stubs pass was run");
603 break;
604 default:
605 llvm_unreachable("unknown x86 Reference Kind");
606 break;
607
608 }
609}
610
611
Nick Kledzik2458bec2014-07-16 19:49:02 +0000612std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
613 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
614}
615
616} // namespace mach_o
617} // namespace lld