1 //===- 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 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/ErrorHandling.h"
18 
19 using namespace llvm::MachO;
20 using namespace lld::mach_o::normalized;
21 
22 namespace lld {
23 namespace mach_o {
24 
25 using llvm::support::ulittle16_t;
26 using llvm::support::ulittle32_t;
27 
28 using llvm::support::little16_t;
29 using llvm::support::little32_t;
30 
31 class ArchHandler_x86 : public ArchHandler {
32 public:
33   ArchHandler_x86() = default;
34   ~ArchHandler_x86() override = default;
35 
kindStrings()36   const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
37 
kindArch()38   Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
39 
stubInfo()40   const StubInfo &stubInfo() override { return _sStubInfo; }
41   bool isCallSite(const Reference &) override;
isNonCallBranch(const Reference &)42   bool isNonCallBranch(const Reference &) override {
43     return false;
44   }
45 
46   bool isPointer(const Reference &) override;
47   bool isPairedReloc(const normalized::Relocation &) override;
48 
needsCompactUnwind()49   bool needsCompactUnwind() override {
50     return false;
51   }
52 
imageOffsetKind()53   Reference::KindValue imageOffsetKind() override {
54     return invalid;
55   }
56 
imageOffsetKindIndirect()57   Reference::KindValue imageOffsetKindIndirect() override {
58     return invalid;
59   }
60 
unwindRefToPersonalityFunctionKind()61   Reference::KindValue unwindRefToPersonalityFunctionKind() override {
62     return invalid;
63   }
64 
unwindRefToCIEKind()65   Reference::KindValue unwindRefToCIEKind() override {
66     return negDelta32;
67   }
68 
unwindRefToFunctionKind()69   Reference::KindValue unwindRefToFunctionKind() override{
70     return delta32;
71   }
72 
lazyImmediateLocationKind()73   Reference::KindValue lazyImmediateLocationKind() override {
74     return lazyImmediateLocation;
75   }
76 
unwindRefToEhFrameKind()77   Reference::KindValue unwindRefToEhFrameKind() override {
78     return invalid;
79   }
80 
pointerKind()81   Reference::KindValue pointerKind() override {
82     return invalid;
83   }
84 
dwarfCompactUnwindType()85   uint32_t dwarfCompactUnwindType() override {
86     return 0x04000000U;
87   }
88 
89   llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
90                                const DefinedAtom *inAtom,
91                                uint32_t offsetInAtom,
92                                uint64_t fixupAddress, bool swap,
93                                FindAtomBySectionAndAddress atomFromAddress,
94                                FindAtomBySymbolIndex atomFromSymbolIndex,
95                                Reference::KindValue *kind,
96                                const lld::Atom **target,
97                                Reference::Addend *addend) override;
98   llvm::Error
99       getPairReferenceInfo(const normalized::Relocation &reloc1,
100                            const normalized::Relocation &reloc2,
101                            const DefinedAtom *inAtom,
102                            uint32_t offsetInAtom,
103                            uint64_t fixupAddress, bool swap, bool scatterable,
104                            FindAtomBySectionAndAddress atomFromAddress,
105                            FindAtomBySymbolIndex atomFromSymbolIndex,
106                            Reference::KindValue *kind,
107                            const lld::Atom **target,
108                            Reference::Addend *addend) override;
109 
110   void generateAtomContent(const DefinedAtom &atom, bool relocatable,
111                            FindAddressForAtom findAddress,
112                            FindAddressForAtom findSectionAddress,
113                            uint64_t imageBaseAddress,
114                     llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
115 
116   void appendSectionRelocations(const DefinedAtom &atom,
117                                 uint64_t atomSectionOffset,
118                                 const Reference &ref,
119                                 FindSymbolIndexForAtom symbolIndexForAtom,
120                                 FindSectionIndexForAtom sectionIndexForAtom,
121                                 FindAddressForAtom addressForAtom,
122                                 normalized::Relocations &relocs) override;
123 
isDataInCodeTransition(Reference::KindValue refKind)124   bool isDataInCodeTransition(Reference::KindValue refKind) override {
125     return refKind == modeCode || refKind == modeData;
126   }
127 
dataInCodeTransitionStart(const MachODefinedAtom & atom)128   Reference::KindValue dataInCodeTransitionStart(
129                                         const MachODefinedAtom &atom) override {
130     return modeData;
131   }
132 
dataInCodeTransitionEnd(const MachODefinedAtom & atom)133   Reference::KindValue dataInCodeTransitionEnd(
134                                         const MachODefinedAtom &atom) override {
135     return modeCode;
136   }
137 
138 private:
139   static const Registry::KindStrings _sKindStrings[];
140   static const StubInfo              _sStubInfo;
141 
142   enum X86Kind : Reference::KindValue {
143     invalid,               /// for error condition
144 
145     modeCode,              /// Content starting at this offset is code.
146     modeData,              /// Content starting at this offset is data.
147 
148     // Kinds found in mach-o .o files:
149     branch32,              /// ex: call _foo
150     branch16,              /// ex: callw _foo
151     abs32,                 /// ex: movl _foo, %eax
152     funcRel32,             /// ex: movl _foo-L1(%eax), %eax
153     pointer32,             /// ex: .long _foo
154     delta32,               /// ex: .long _foo - .
155     negDelta32,            /// ex: .long . - _foo
156 
157     // Kinds introduced by Passes:
158     lazyPointer,           /// Location contains a lazy pointer.
159     lazyImmediateLocation, /// Location contains immediate value used in stub.
160   };
161 
162   static bool useExternalRelocationTo(const Atom &target);
163 
164   void applyFixupFinal(const Reference &ref, uint8_t *location,
165                        uint64_t fixupAddress, uint64_t targetAddress,
166                        uint64_t inAtomAddress);
167 
168   void applyFixupRelocatable(const Reference &ref, uint8_t *location,
169                              uint64_t fixupAddress,
170                              uint64_t targetAddress,
171                              uint64_t inAtomAddress);
172 };
173 
174 //===----------------------------------------------------------------------===//
175 //  ArchHandler_x86
176 //===----------------------------------------------------------------------===//
177 
178 const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
179   LLD_KIND_STRING_ENTRY(invalid),
180   LLD_KIND_STRING_ENTRY(modeCode),
181   LLD_KIND_STRING_ENTRY(modeData),
182   LLD_KIND_STRING_ENTRY(branch32),
183   LLD_KIND_STRING_ENTRY(branch16),
184   LLD_KIND_STRING_ENTRY(abs32),
185   LLD_KIND_STRING_ENTRY(funcRel32),
186   LLD_KIND_STRING_ENTRY(pointer32),
187   LLD_KIND_STRING_ENTRY(delta32),
188   LLD_KIND_STRING_ENTRY(negDelta32),
189   LLD_KIND_STRING_ENTRY(lazyPointer),
190   LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
191   LLD_KIND_STRING_END
192 };
193 
194 const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
195   "dyld_stub_binder",
196 
197   // Lazy pointer references
198   { Reference::KindArch::x86, pointer32, 0, 0 },
199   { Reference::KindArch::x86, lazyPointer, 0, 0 },
200 
201   // GOT pointer to dyld_stub_binder
202   { Reference::KindArch::x86, pointer32, 0, 0 },
203 
204   // x86 code alignment
205   1,
206 
207   // Stub size and code
208   6,
209   { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
210   { Reference::KindArch::x86, abs32, 2, 0 },
211   { false, 0, 0, 0 },
212 
213   // Stub Helper size and code
214   10,
215   { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $lazy-info-offset
216     0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
217   { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
218   { Reference::KindArch::x86, branch32, 6, 0 },
219 
220   // Stub helper image cache content type
221   DefinedAtom::typeNonLazyPointer,
222 
223   // Stub Helper-Common size and code
224   12,
225   // Stub helper alignment
226   2,
227   { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $dyld_ImageLoaderCache
228     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *_fast_lazy_bind
229     0x90 },                                     // nop
230   { Reference::KindArch::x86, abs32, 1, 0 },
231   { false, 0, 0, 0 },
232   { Reference::KindArch::x86, abs32, 7, 0 },
233   { false, 0, 0, 0 }
234 };
235 
isCallSite(const Reference & ref)236 bool ArchHandler_x86::isCallSite(const Reference &ref) {
237   return (ref.kindValue() == branch32);
238 }
239 
isPointer(const Reference & ref)240 bool ArchHandler_x86::isPointer(const Reference &ref) {
241   return (ref.kindValue() == pointer32);
242 }
243 
isPairedReloc(const Relocation & reloc)244 bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
245   if (!reloc.scattered)
246     return false;
247   return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
248          (reloc.type == GENERIC_RELOC_SECTDIFF);
249 }
250 
251 llvm::Error
getReferenceInfo(const Relocation & reloc,const DefinedAtom * inAtom,uint32_t offsetInAtom,uint64_t fixupAddress,bool swap,FindAtomBySectionAndAddress atomFromAddress,FindAtomBySymbolIndex atomFromSymbolIndex,Reference::KindValue * kind,const lld::Atom ** target,Reference::Addend * addend)252 ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
253                                   const DefinedAtom *inAtom,
254                                   uint32_t offsetInAtom,
255                                   uint64_t fixupAddress, bool swap,
256                                   FindAtomBySectionAndAddress atomFromAddress,
257                                   FindAtomBySymbolIndex atomFromSymbolIndex,
258                                   Reference::KindValue *kind,
259                                   const lld::Atom **target,
260                                   Reference::Addend *addend) {
261   DefinedAtom::ContentPermissions perms;
262   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
263   uint64_t targetAddress;
264   switch (relocPattern(reloc)) {
265   case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
266     // ex: call _foo (and _foo undefined)
267     *kind = branch32;
268     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
269       return ec;
270     *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
271     break;
272   case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
273     // ex: call _foo (and _foo defined)
274     *kind = branch32;
275     targetAddress =
276         fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
277     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
278     break;
279   case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
280     // ex: call _foo+n (and _foo defined)
281     *kind = branch32;
282     targetAddress =
283         fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
284     if (auto ec = atomFromAddress(0, reloc.value, target, addend))
285       return ec;
286     *addend = targetAddress - reloc.value;
287     break;
288   case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
289     // ex: callw _foo (and _foo undefined)
290     *kind = branch16;
291     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
292       return ec;
293     *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
294     break;
295   case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
296     // ex: callw _foo (and _foo defined)
297     *kind = branch16;
298     targetAddress =
299         fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
300     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
301     break;
302   case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
303     // ex: callw _foo+n (and _foo defined)
304     *kind = branch16;
305     targetAddress =
306         fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
307     if (auto ec = atomFromAddress(0, reloc.value, target, addend))
308       return ec;
309     *addend = targetAddress - reloc.value;
310     break;
311   case GENERIC_RELOC_VANILLA | rExtern | rLength4:
312     // ex: movl	_foo, %eax   (and _foo undefined)
313     // ex: .long _foo        (and _foo undefined)
314     perms = inAtom->permissions();
315     *kind =
316         ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
317                                                                  : pointer32;
318     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
319       return ec;
320     *addend = *(const ulittle32_t *)fixupContent;
321     break;
322   case GENERIC_RELOC_VANILLA | rLength4:
323     // ex: movl	_foo, %eax   (and _foo defined)
324     // ex: .long _foo        (and _foo defined)
325     perms = inAtom->permissions();
326     *kind =
327         ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
328                                                                  : pointer32;
329     targetAddress = *(const ulittle32_t *)fixupContent;
330     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
331     break;
332   case GENERIC_RELOC_VANILLA | rScattered | rLength4:
333     // ex: .long _foo+n      (and _foo defined)
334     perms = inAtom->permissions();
335     *kind =
336         ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
337                                                                  : pointer32;
338     if (auto ec = atomFromAddress(0, reloc.value, target, addend))
339       return ec;
340     *addend = *(const ulittle32_t *)fixupContent - reloc.value;
341     break;
342   default:
343     return llvm::make_error<GenericError>("unsupported i386 relocation type");
344   }
345   return llvm::Error::success();
346 }
347 
348 llvm::Error
getPairReferenceInfo(const normalized::Relocation & reloc1,const normalized::Relocation & reloc2,const DefinedAtom * inAtom,uint32_t offsetInAtom,uint64_t fixupAddress,bool swap,bool scatterable,FindAtomBySectionAndAddress atomFromAddr,FindAtomBySymbolIndex atomFromSymbolIndex,Reference::KindValue * kind,const lld::Atom ** target,Reference::Addend * addend)349 ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
350                                       const normalized::Relocation &reloc2,
351                                       const DefinedAtom *inAtom,
352                                       uint32_t offsetInAtom,
353                                       uint64_t fixupAddress, bool swap,
354                                       bool scatterable,
355                                       FindAtomBySectionAndAddress atomFromAddr,
356                                       FindAtomBySymbolIndex atomFromSymbolIndex,
357                                       Reference::KindValue *kind,
358                                       const lld::Atom **target,
359                                       Reference::Addend *addend) {
360   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
361   DefinedAtom::ContentPermissions perms = inAtom->permissions();
362   uint32_t fromAddress;
363   uint32_t toAddress;
364   uint32_t value;
365   const lld::Atom *fromTarget;
366   Reference::Addend offsetInTo;
367   Reference::Addend offsetInFrom;
368   switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
369   case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
370          GENERIC_RELOC_PAIR | rScattered | rLength4):
371   case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
372          GENERIC_RELOC_PAIR | rScattered | rLength4):
373     toAddress = reloc1.value;
374     fromAddress = reloc2.value;
375     value = *(const little32_t *)fixupContent;
376     if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
377       return ec;
378     if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
379       return ec;
380     if (fromTarget != inAtom) {
381       if (*target != inAtom)
382         return llvm::make_error<GenericError>(
383             "SECTDIFF relocation where neither target is in atom");
384       *kind = negDelta32;
385       *addend = toAddress - value - fromAddress;
386       *target = fromTarget;
387     } else {
388       if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
389         // SECTDIFF relocations are used in i386 codegen where the function
390         // prolog does a CALL to the next instruction which POPs the return
391         // address into EBX which becomes the pic-base register.  The POP
392         // instruction is label the used for the subtrahend in expressions.
393         // The funcRel32 kind represents the 32-bit delta to some symbol from
394         // the start of the function (atom) containing the funcRel32.
395         *kind = funcRel32;
396         uint32_t ta = fromAddress + value - toAddress;
397         *addend = ta - offsetInFrom;
398       } else {
399         *kind = delta32;
400         *addend = fromAddress + value - toAddress;
401       }
402     }
403     return llvm::Error::success();
404     break;
405   default:
406     return llvm::make_error<GenericError>("unsupported i386 relocation type");
407   }
408 }
409 
generateAtomContent(const DefinedAtom & atom,bool relocatable,FindAddressForAtom findAddress,FindAddressForAtom findSectionAddress,uint64_t imageBaseAddress,llvm::MutableArrayRef<uint8_t> atomContentBuffer)410 void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
411                                           bool relocatable,
412                                           FindAddressForAtom findAddress,
413                                           FindAddressForAtom findSectionAddress,
414                                           uint64_t imageBaseAddress,
415                             llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
416   // Copy raw bytes.
417   std::copy(atom.rawContent().begin(), atom.rawContent().end(),
418             atomContentBuffer.begin());
419   // Apply fix-ups.
420   for (const Reference *ref : atom) {
421     uint32_t offset = ref->offsetInAtom();
422     const Atom *target = ref->target();
423     uint64_t targetAddress = 0;
424     if (isa<DefinedAtom>(target))
425       targetAddress = findAddress(*target);
426     uint64_t atomAddress = findAddress(atom);
427     uint64_t fixupAddress = atomAddress + offset;
428     if (relocatable) {
429       applyFixupRelocatable(*ref, &atomContentBuffer[offset],
430                                         fixupAddress, targetAddress,
431                                         atomAddress);
432     } else {
433       applyFixupFinal(*ref, &atomContentBuffer[offset],
434                                   fixupAddress, targetAddress,
435                                   atomAddress);
436     }
437   }
438 }
439 
applyFixupFinal(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress)440 void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
441                                       uint64_t fixupAddress,
442                                       uint64_t targetAddress,
443                                       uint64_t inAtomAddress) {
444   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
445     return;
446   assert(ref.kindArch() == Reference::KindArch::x86);
447   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
448   switch (static_cast<X86Kind>(ref.kindValue())) {
449   case branch32:
450     *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
451     break;
452   case branch16:
453     *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
454     break;
455   case pointer32:
456   case abs32:
457     *loc32 = targetAddress + ref.addend();
458     break;
459   case funcRel32:
460     *loc32 = targetAddress - inAtomAddress + ref.addend();
461     break;
462   case delta32:
463     *loc32 = targetAddress - fixupAddress + ref.addend();
464     break;
465   case negDelta32:
466     *loc32 = fixupAddress - targetAddress + ref.addend();
467     break;
468   case modeCode:
469   case modeData:
470   case lazyPointer:
471     // do nothing
472     break;
473   case lazyImmediateLocation:
474     *loc32 = ref.addend();
475     break;
476   case invalid:
477     llvm_unreachable("invalid x86 Reference Kind");
478     break;
479   }
480 }
481 
applyFixupRelocatable(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress)482 void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
483                                                uint8_t *loc,
484                                                uint64_t fixupAddress,
485                                                uint64_t targetAddress,
486                                                uint64_t inAtomAddress) {
487   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
488     return;
489   assert(ref.kindArch() == Reference::KindArch::x86);
490   bool useExternalReloc = useExternalRelocationTo(*ref.target());
491   ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
492   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
493   switch (static_cast<X86Kind>(ref.kindValue())) {
494   case branch32:
495     if (useExternalReloc)
496       *loc32 = ref.addend() - (fixupAddress + 4);
497     else
498       *loc32  =(targetAddress - (fixupAddress+4)) + ref.addend();
499     break;
500   case branch16:
501     if (useExternalReloc)
502       *loc16 = ref.addend() - (fixupAddress + 2);
503     else
504       *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
505     break;
506   case pointer32:
507   case abs32:
508     *loc32 = targetAddress + ref.addend();
509     break;
510   case funcRel32:
511     *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
512     break;
513   case delta32:
514     *loc32 = targetAddress - fixupAddress + ref.addend();
515     break;
516   case negDelta32:
517     *loc32 = fixupAddress - targetAddress + ref.addend();
518     break;
519   case modeCode:
520   case modeData:
521   case lazyPointer:
522   case lazyImmediateLocation:
523     // do nothing
524     break;
525   case invalid:
526     llvm_unreachable("invalid x86 Reference Kind");
527     break;
528   }
529 }
530 
useExternalRelocationTo(const Atom & target)531 bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
532   // Undefined symbols are referenced via external relocations.
533   if (isa<UndefinedAtom>(&target))
534     return true;
535   if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
536      switch (defAtom->merge()) {
537      case DefinedAtom::mergeAsTentative:
538        // Tentative definitions are referenced via external relocations.
539        return true;
540      case DefinedAtom::mergeAsWeak:
541      case DefinedAtom::mergeAsWeakAndAddressUsed:
542        // Global weak-defs are referenced via external relocations.
543        return (defAtom->scope() == DefinedAtom::scopeGlobal);
544      default:
545        break;
546     }
547   }
548   // Everything else is reference via an internal relocation.
549   return false;
550 }
551 
appendSectionRelocations(const DefinedAtom & atom,uint64_t atomSectionOffset,const Reference & ref,FindSymbolIndexForAtom symbolIndexForAtom,FindSectionIndexForAtom sectionIndexForAtom,FindAddressForAtom addressForAtom,normalized::Relocations & relocs)552 void ArchHandler_x86::appendSectionRelocations(
553                                    const DefinedAtom &atom,
554                                    uint64_t atomSectionOffset,
555                                    const Reference &ref,
556                                    FindSymbolIndexForAtom symbolIndexForAtom,
557                                    FindSectionIndexForAtom sectionIndexForAtom,
558                                    FindAddressForAtom addressForAtom,
559                                    normalized::Relocations &relocs) {
560   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
561     return;
562   assert(ref.kindArch() == Reference::KindArch::x86);
563   uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
564   bool useExternalReloc = useExternalRelocationTo(*ref.target());
565   switch (static_cast<X86Kind>(ref.kindValue())) {
566   case modeCode:
567   case modeData:
568     break;
569   case branch32:
570     if (useExternalReloc) {
571       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
572                   GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength4);
573     } else {
574       if (ref.addend() != 0)
575         appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
576                   GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength4);
577       else
578         appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
579                   GENERIC_RELOC_VANILLA |              rPcRel | rLength4);
580     }
581     break;
582   case branch16:
583     if (useExternalReloc) {
584       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
585                   GENERIC_RELOC_VANILLA | rExtern    | rPcRel | rLength2);
586     } else {
587       if (ref.addend() != 0)
588         appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
589                   GENERIC_RELOC_VANILLA | rScattered | rPcRel |  rLength2);
590       else
591         appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
592                   GENERIC_RELOC_VANILLA |              rPcRel | rLength2);
593     }
594     break;
595   case pointer32:
596   case abs32:
597     if (useExternalReloc)
598       appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
599                 GENERIC_RELOC_VANILLA |    rExtern     |  rLength4);
600     else {
601       if (ref.addend() != 0)
602         appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
603                 GENERIC_RELOC_VANILLA |    rScattered  |  rLength4);
604       else
605         appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
606                 GENERIC_RELOC_VANILLA |                   rLength4);
607     }
608     break;
609   case funcRel32:
610     appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
611               GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
612     appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
613               GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
614     break;
615   case delta32:
616     appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
617               GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
618     appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
619                                                            ref.offsetInAtom(),
620               GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
621     break;
622   case negDelta32:
623     appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
624                                                            ref.offsetInAtom(),
625               GENERIC_RELOC_SECTDIFF |  rScattered    | rLength4);
626     appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
627               GENERIC_RELOC_PAIR     |  rScattered    | rLength4);
628     break;
629   case lazyPointer:
630   case lazyImmediateLocation:
631     llvm_unreachable("lazy reference kind implies Stubs pass was run");
632     break;
633   case invalid:
634     llvm_unreachable("unknown x86 Reference Kind");
635     break;
636   }
637 }
638 
create_x86()639 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
640   return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
641 }
642 
643 } // namespace mach_o
644 } // namespace lld
645