1 //===- lib/FileFormat/MachO/ArchHandler_x86_64.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::ulittle32_t;
26 using llvm::support::ulittle64_t;
27 
28 using llvm::support::little32_t;
29 using llvm::support::little64_t;
30 
31 class ArchHandler_x86_64 : public ArchHandler {
32 public:
33   ArchHandler_x86_64() = default;
34   ~ArchHandler_x86_64() override = default;
35 
36   const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
37 
38   Reference::KindArch kindArch() override {
39     return Reference::KindArch::x86_64;
40   }
41 
42   /// Used by GOTPass to locate GOT References
43   bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
44     if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
45       return false;
46     assert(ref.kindArch() == Reference::KindArch::x86_64);
47     switch (ref.kindValue()) {
48     case ripRel32GotLoad:
49       canBypassGOT = true;
50       return true;
51     case ripRel32Got:
52       canBypassGOT = false;
53       return true;
54     case imageOffsetGot:
55       canBypassGOT = false;
56       return true;
57     default:
58       return false;
59     }
60   }
61 
62   bool isTLVAccess(const Reference &ref) const override {
63     assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
64     assert(ref.kindArch() == Reference::KindArch::x86_64);
65     return ref.kindValue() == ripRel32Tlv;
66   }
67 
68   void updateReferenceToTLV(const Reference *ref) override {
69     assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
70     assert(ref->kindArch() == Reference::KindArch::x86_64);
71     assert(ref->kindValue() == ripRel32Tlv);
72     const_cast<Reference*>(ref)->setKindValue(ripRel32);
73   }
74 
75   /// Used by GOTPass to update GOT References
76   void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
77     assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
78     assert(ref->kindArch() == Reference::KindArch::x86_64);
79 
80     switch (ref->kindValue()) {
81     case ripRel32Got:
82       assert(targetNowGOT && "target must be GOT");
83       LLVM_FALLTHROUGH;
84     case ripRel32GotLoad:
85       const_cast<Reference *>(ref)
86         ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
87       break;
88     case imageOffsetGot:
89       const_cast<Reference *>(ref)->setKindValue(imageOffset);
90       break;
91     default:
92       llvm_unreachable("unknown GOT reference kind");
93     }
94   }
95 
96   bool needsCompactUnwind() override {
97     return true;
98   }
99 
100   Reference::KindValue imageOffsetKind() override {
101     return imageOffset;
102   }
103 
104   Reference::KindValue imageOffsetKindIndirect() override {
105     return imageOffsetGot;
106   }
107 
108   Reference::KindValue unwindRefToPersonalityFunctionKind() override {
109     return ripRel32Got;
110   }
111 
112   Reference::KindValue unwindRefToCIEKind() override {
113     return negDelta32;
114   }
115 
116   Reference::KindValue unwindRefToFunctionKind() override{
117     return unwindFDEToFunction;
118   }
119 
120   Reference::KindValue lazyImmediateLocationKind() override {
121     return lazyImmediateLocation;
122   }
123 
124   Reference::KindValue unwindRefToEhFrameKind() override {
125     return unwindInfoToEhFrame;
126   }
127 
128   Reference::KindValue pointerKind() override {
129     return pointer64;
130   }
131 
132   uint32_t dwarfCompactUnwindType() override {
133     return 0x04000000U;
134   }
135 
136   const StubInfo &stubInfo() override { return _sStubInfo; }
137 
138   bool isNonCallBranch(const Reference &) override {
139     return false;
140   }
141 
142   bool isCallSite(const Reference &) override;
143   bool isPointer(const Reference &) override;
144   bool isPairedReloc(const normalized::Relocation &) override;
145 
146   llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
147                                const DefinedAtom *inAtom,
148                                uint32_t offsetInAtom,
149                                uint64_t fixupAddress, bool swap,
150                                FindAtomBySectionAndAddress atomFromAddress,
151                                FindAtomBySymbolIndex atomFromSymbolIndex,
152                                Reference::KindValue *kind,
153                                const lld::Atom **target,
154                                Reference::Addend *addend) override;
155   llvm::Error
156       getPairReferenceInfo(const normalized::Relocation &reloc1,
157                            const normalized::Relocation &reloc2,
158                            const DefinedAtom *inAtom,
159                            uint32_t offsetInAtom,
160                            uint64_t fixupAddress, bool swap, bool scatterable,
161                            FindAtomBySectionAndAddress atomFromAddress,
162                            FindAtomBySymbolIndex atomFromSymbolIndex,
163                            Reference::KindValue *kind,
164                            const lld::Atom **target,
165                            Reference::Addend *addend) override;
166 
167   bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
168     return (atom->contentType() == DefinedAtom::typeCString);
169   }
170 
171   void generateAtomContent(const DefinedAtom &atom, bool relocatable,
172                            FindAddressForAtom findAddress,
173                            FindAddressForAtom findSectionAddress,
174                            uint64_t imageBase,
175                     llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
176 
177   void appendSectionRelocations(const DefinedAtom &atom,
178                                 uint64_t atomSectionOffset,
179                                 const Reference &ref,
180                                 FindSymbolIndexForAtom symbolIndexForAtom,
181                                 FindSectionIndexForAtom sectionIndexForAtom,
182                                 FindAddressForAtom addressForAtom,
183                                 normalized::Relocations &relocs) override;
184 
185 private:
186   static const Registry::KindStrings _sKindStrings[];
187   static const StubInfo              _sStubInfo;
188 
189   enum X86_64Kind: Reference::KindValue {
190     invalid,               /// for error condition
191 
192     // Kinds found in mach-o .o files:
193     branch32,              /// ex: call _foo
194     ripRel32,              /// ex: movq _foo(%rip), %rax
195     ripRel32Minus1,        /// ex: movb $0x12, _foo(%rip)
196     ripRel32Minus2,        /// ex: movw $0x1234, _foo(%rip)
197     ripRel32Minus4,        /// ex: movl $0x12345678, _foo(%rip)
198     ripRel32Anon,          /// ex: movq L1(%rip), %rax
199     ripRel32Minus1Anon,    /// ex: movb $0x12, L1(%rip)
200     ripRel32Minus2Anon,    /// ex: movw $0x1234, L1(%rip)
201     ripRel32Minus4Anon,    /// ex: movw $0x12345678, L1(%rip)
202     ripRel32GotLoad,       /// ex: movq  _foo@GOTPCREL(%rip), %rax
203     ripRel32Got,           /// ex: pushq _foo@GOTPCREL(%rip)
204     ripRel32Tlv,           /// ex: movq  _foo@TLVP(%rip), %rdi
205     pointer64,             /// ex: .quad _foo
206     pointer64Anon,         /// ex: .quad L1
207     delta64,               /// ex: .quad _foo - .
208     delta32,               /// ex: .long _foo - .
209     delta64Anon,           /// ex: .quad L1 - .
210     delta32Anon,           /// ex: .long L1 - .
211     negDelta64,            /// ex: .quad . - _foo
212     negDelta32,            /// ex: .long . - _foo
213 
214     // Kinds introduced by Passes:
215     ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
216                            ///  "movq  _foo@GOTPCREL(%rip), %rax" can be changed
217                            /// to "leaq _foo(%rip), %rax
218     lazyPointer,           /// Location contains a lazy pointer.
219     lazyImmediateLocation, /// Location contains immediate value used in stub.
220 
221     imageOffset,           /// Location contains offset of atom in final image
222     imageOffsetGot,        /// Location contains offset of GOT entry for atom in
223                            /// final image (typically personality function).
224     unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
225                            /// relocatable object (yay for implicit contracts!).
226     unwindInfoToEhFrame,   /// Fix low 24 bits of compact unwind encoding to
227                            /// refer to __eh_frame entry.
228     tlvInitSectionOffset   /// Location contains offset tlv init-value atom
229                            /// within the __thread_data section.
230   };
231 
232   Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
233 
234   void applyFixupFinal(const Reference &ref, uint8_t *location,
235                        uint64_t fixupAddress, uint64_t targetAddress,
236                        uint64_t inAtomAddress, uint64_t imageBaseAddress,
237                        FindAddressForAtom findSectionAddress);
238 
239   void applyFixupRelocatable(const Reference &ref, uint8_t *location,
240                              uint64_t fixupAddress,
241                              uint64_t targetAddress,
242                              uint64_t inAtomAddress);
243 };
244 
245 const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
246   LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
247   LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
248   LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
249   LLD_KIND_STRING_ENTRY(ripRel32Anon),
250   LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
251   LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
252   LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
253   LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
254   LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
255   LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
256   LLD_KIND_STRING_ENTRY(lazyPointer),
257   LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
258   LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
259   LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
260   LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
261   LLD_KIND_STRING_ENTRY(negDelta64),
262   LLD_KIND_STRING_ENTRY(negDelta32),
263   LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
264   LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
265   LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
266   LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
267   LLD_KIND_STRING_END
268 };
269 
270 const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
271   "dyld_stub_binder",
272 
273   // Lazy pointer references
274   { Reference::KindArch::x86_64, pointer64, 0, 0 },
275   { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
276 
277   // GOT pointer to dyld_stub_binder
278   { Reference::KindArch::x86_64, pointer64, 0, 0 },
279 
280   // x86_64 code alignment 2^1
281   1,
282 
283   // Stub size and code
284   6,
285   { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
286   { Reference::KindArch::x86_64, ripRel32, 2, 0 },
287   { false, 0, 0, 0 },
288 
289   // Stub Helper size and code
290   10,
291   { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushq $lazy-info-offset
292     0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
293   { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
294   { Reference::KindArch::x86_64, branch32, 6, 0 },
295 
296   // Stub helper image cache content type
297   DefinedAtom::typeNonLazyPointer,
298 
299   // Stub Helper-Common size and code
300   16,
301   // Stub helper alignment
302   2,
303   { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
304     0x41, 0x53,                                 // push %r11
305     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
306     0x90 },                                     // nop
307   { Reference::KindArch::x86_64, ripRel32, 3, 0 },
308   { false, 0, 0, 0 },
309   { Reference::KindArch::x86_64, ripRel32, 11, 0 },
310   { false, 0, 0, 0 }
311 
312 };
313 
314 bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
315   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
316     return false;
317   assert(ref.kindArch() == Reference::KindArch::x86_64);
318   return (ref.kindValue() == branch32);
319 }
320 
321 bool ArchHandler_x86_64::isPointer(const Reference &ref) {
322   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
323     return false;
324   assert(ref.kindArch() == Reference::KindArch::x86_64);
325   Reference::KindValue kind = ref.kindValue();
326   return (kind == pointer64 || kind == pointer64Anon);
327 }
328 
329 bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
330   return (reloc.type == X86_64_RELOC_SUBTRACTOR);
331 }
332 
333 Reference::KindValue
334 ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
335   switch(relocPattern(reloc)) {
336   case X86_64_RELOC_BRANCH   | rPcRel | rExtern | rLength4:
337     return branch32;
338   case X86_64_RELOC_SIGNED   | rPcRel | rExtern | rLength4:
339     return ripRel32;
340   case X86_64_RELOC_SIGNED   | rPcRel |           rLength4:
341     return ripRel32Anon;
342   case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
343     return ripRel32Minus1;
344   case X86_64_RELOC_SIGNED_1 | rPcRel |           rLength4:
345     return ripRel32Minus1Anon;
346   case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
347     return ripRel32Minus2;
348   case X86_64_RELOC_SIGNED_2 | rPcRel |           rLength4:
349     return ripRel32Minus2Anon;
350   case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
351     return ripRel32Minus4;
352   case X86_64_RELOC_SIGNED_4 | rPcRel |           rLength4:
353     return ripRel32Minus4Anon;
354   case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
355     return ripRel32GotLoad;
356   case X86_64_RELOC_GOT      | rPcRel | rExtern | rLength4:
357     return ripRel32Got;
358   case X86_64_RELOC_TLV      | rPcRel | rExtern | rLength4:
359     return ripRel32Tlv;
360   case X86_64_RELOC_UNSIGNED          | rExtern | rLength8:
361     return pointer64;
362   case X86_64_RELOC_UNSIGNED                    | rLength8:
363     return pointer64Anon;
364   default:
365     return invalid;
366   }
367 }
368 
369 llvm::Error
370 ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
371                                     const DefinedAtom *inAtom,
372                                     uint32_t offsetInAtom,
373                                     uint64_t fixupAddress, bool swap,
374                                     FindAtomBySectionAndAddress atomFromAddress,
375                                     FindAtomBySymbolIndex atomFromSymbolIndex,
376                                     Reference::KindValue *kind,
377                                     const lld::Atom **target,
378                                     Reference::Addend *addend) {
379   *kind = kindFromReloc(reloc);
380   if (*kind == invalid)
381     return llvm::make_error<GenericError>("unknown type");
382   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
383   uint64_t targetAddress;
384   switch (*kind) {
385   case branch32:
386   case ripRel32:
387     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
388       return ec;
389     *addend = *(const little32_t *)fixupContent;
390     return llvm::Error::success();
391   case ripRel32Minus1:
392     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
393       return ec;
394     *addend = (int32_t)*(const little32_t *)fixupContent + 1;
395     return llvm::Error::success();
396   case ripRel32Minus2:
397     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
398       return ec;
399     *addend = (int32_t)*(const little32_t *)fixupContent + 2;
400     return llvm::Error::success();
401   case ripRel32Minus4:
402     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
403       return ec;
404     *addend = (int32_t)*(const little32_t *)fixupContent + 4;
405     return llvm::Error::success();
406   case ripRel32Anon:
407     targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
408     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
409   case ripRel32Minus1Anon:
410     targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
411     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
412   case ripRel32Minus2Anon:
413     targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
414     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
415   case ripRel32Minus4Anon:
416     targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
417     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
418   case ripRel32GotLoad:
419   case ripRel32Got:
420   case ripRel32Tlv:
421     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
422       return ec;
423     *addend = *(const little32_t *)fixupContent;
424     return llvm::Error::success();
425   case tlvInitSectionOffset:
426   case pointer64:
427     if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
428       return ec;
429     // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's
430     // initial value) we need to handle it specially.
431     if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
432         offsetInAtom == 16) {
433       *kind = tlvInitSectionOffset;
434       assert(*addend == 0 && "TLV-init has non-zero addend?");
435     } else
436       *addend = *(const little64_t *)fixupContent;
437     return llvm::Error::success();
438   case pointer64Anon:
439     targetAddress = *(const little64_t *)fixupContent;
440     return atomFromAddress(reloc.symbol, targetAddress, target, addend);
441   default:
442     llvm_unreachable("bad reloc kind");
443   }
444 }
445 
446 llvm::Error
447 ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
448                                    const normalized::Relocation &reloc2,
449                                    const DefinedAtom *inAtom,
450                                    uint32_t offsetInAtom,
451                                    uint64_t fixupAddress, bool swap,
452                                    bool scatterable,
453                                    FindAtomBySectionAndAddress atomFromAddress,
454                                    FindAtomBySymbolIndex atomFromSymbolIndex,
455                                    Reference::KindValue *kind,
456                                    const lld::Atom **target,
457                                    Reference::Addend *addend) {
458   const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
459   uint64_t targetAddress;
460   const lld::Atom *fromTarget;
461   if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
462     return ec;
463 
464   switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
465   case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
466         X86_64_RELOC_UNSIGNED    | rExtern | rLength8): {
467     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
468       return ec;
469     uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent;
470     if (inAtom == fromTarget) {
471       if (inAtom->contentType() == DefinedAtom::typeCFI)
472         *kind = unwindFDEToFunction;
473       else
474         *kind = delta64;
475       *addend = encodedAddend + offsetInAtom;
476     } else if (inAtom == *target) {
477       *kind = negDelta64;
478       *addend = encodedAddend - offsetInAtom;
479       *target = fromTarget;
480     } else
481       return llvm::make_error<GenericError>("Invalid pointer diff");
482     return llvm::Error::success();
483   }
484   case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
485         X86_64_RELOC_UNSIGNED    | rExtern | rLength4): {
486     if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
487       return ec;
488     uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent;
489     if (inAtom == fromTarget) {
490       *kind = delta32;
491       *addend = encodedAddend + offsetInAtom;
492     } else if (inAtom == *target) {
493       *kind = negDelta32;
494       *addend = encodedAddend - offsetInAtom;
495       *target = fromTarget;
496     } else
497       return llvm::make_error<GenericError>("Invalid pointer diff");
498     return llvm::Error::success();
499   }
500   case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
501         X86_64_RELOC_UNSIGNED              | rLength8):
502     if (fromTarget != inAtom)
503       return llvm::make_error<GenericError>("pointer diff not in base atom");
504     *kind = delta64Anon;
505     targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
506     return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
507   case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
508         X86_64_RELOC_UNSIGNED              | rLength4):
509     if (fromTarget != inAtom)
510       return llvm::make_error<GenericError>("pointer diff not in base atom");
511     *kind = delta32Anon;
512     targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
513     return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
514   default:
515     return llvm::make_error<GenericError>("unknown pair");
516   }
517 }
518 
519 void ArchHandler_x86_64::generateAtomContent(
520     const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
521     FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
522     llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
523   // Copy raw bytes.
524   std::copy(atom.rawContent().begin(), atom.rawContent().end(),
525             atomContentBuffer.begin());
526   // Apply fix-ups.
527   for (const Reference *ref : atom) {
528     uint32_t offset = ref->offsetInAtom();
529     const Atom *target = ref->target();
530     uint64_t targetAddress = 0;
531     if (isa<DefinedAtom>(target))
532       targetAddress = findAddress(*target);
533     uint64_t atomAddress = findAddress(atom);
534     uint64_t fixupAddress = atomAddress + offset;
535     if (relocatable) {
536       applyFixupRelocatable(*ref, &atomContentBuffer[offset],
537                                         fixupAddress, targetAddress,
538                                         atomAddress);
539     } else {
540       applyFixupFinal(*ref, &atomContentBuffer[offset],
541                       fixupAddress, targetAddress,
542                       atomAddress, imageBaseAddress, findSectionAddress);
543     }
544   }
545 }
546 
547 void ArchHandler_x86_64::applyFixupFinal(
548     const Reference &ref, uint8_t *loc, uint64_t fixupAddress,
549     uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress,
550     FindAddressForAtom findSectionAddress) {
551   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
552     return;
553   assert(ref.kindArch() == Reference::KindArch::x86_64);
554   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
555   ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
556   switch (static_cast<X86_64Kind>(ref.kindValue())) {
557   case branch32:
558   case ripRel32:
559   case ripRel32Anon:
560   case ripRel32Got:
561   case ripRel32GotLoad:
562   case ripRel32Tlv:
563     *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
564     return;
565   case pointer64:
566   case pointer64Anon:
567     *loc64 = targetAddress + ref.addend();
568     return;
569   case tlvInitSectionOffset:
570     *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
571     return;
572   case ripRel32Minus1:
573   case ripRel32Minus1Anon:
574     *loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
575     return;
576   case ripRel32Minus2:
577   case ripRel32Minus2Anon:
578     *loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
579     return;
580   case ripRel32Minus4:
581   case ripRel32Minus4Anon:
582     *loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
583     return;
584   case delta32:
585   case delta32Anon:
586     *loc32 = targetAddress - fixupAddress + ref.addend();
587     return;
588   case delta64:
589   case delta64Anon:
590   case unwindFDEToFunction:
591     *loc64 = targetAddress - fixupAddress + ref.addend();
592     return;
593   case ripRel32GotLoadNowLea:
594     // Change MOVQ to LEA
595     assert(loc[-2] == 0x8B);
596     loc[-2] = 0x8D;
597     *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
598     return;
599   case negDelta64:
600     *loc64 = fixupAddress - targetAddress + ref.addend();
601     return;
602   case negDelta32:
603     *loc32 = fixupAddress - targetAddress + ref.addend();
604     return;
605   case lazyPointer:
606     // Do nothing
607     return;
608   case lazyImmediateLocation:
609     *loc32 = ref.addend();
610     return;
611   case imageOffset:
612   case imageOffsetGot:
613     *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
614     return;
615   case unwindInfoToEhFrame: {
616     uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
617     assert(val < 0xffffffU && "offset in __eh_frame too large");
618     *loc32 = (*loc32 & 0xff000000U) | val;
619     return;
620   }
621   case invalid:
622     // Fall into llvm_unreachable().
623     break;
624   }
625   llvm_unreachable("invalid x86_64 Reference Kind");
626 }
627 
628 void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
629                                                uint8_t *loc,
630                                                uint64_t fixupAddress,
631                                                uint64_t targetAddress,
632                                                uint64_t inAtomAddress)  {
633   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
634     return;
635   assert(ref.kindArch() == Reference::KindArch::x86_64);
636   ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
637   ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
638   switch (static_cast<X86_64Kind>(ref.kindValue())) {
639   case branch32:
640   case ripRel32:
641   case ripRel32Got:
642   case ripRel32GotLoad:
643   case ripRel32Tlv:
644     *loc32 = ref.addend();
645     return;
646   case ripRel32Anon:
647     *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
648     return;
649   case tlvInitSectionOffset:
650   case pointer64:
651     *loc64 = ref.addend();
652     return;
653   case pointer64Anon:
654     *loc64 = targetAddress + ref.addend();
655     return;
656   case ripRel32Minus1:
657     *loc32 = ref.addend() - 1;
658     return;
659   case ripRel32Minus1Anon:
660     *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
661     return;
662   case ripRel32Minus2:
663     *loc32 = ref.addend() - 2;
664     return;
665   case ripRel32Minus2Anon:
666     *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
667     return;
668   case ripRel32Minus4:
669     *loc32 = ref.addend() - 4;
670     return;
671   case ripRel32Minus4Anon:
672     *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
673     return;
674   case delta32:
675     *loc32 = ref.addend() + inAtomAddress - fixupAddress;
676     return;
677   case delta32Anon:
678     // The value we write here should be the delta to the target
679     // after taking in to account the difference from the fixup back to the
680     // last defined label
681     // ie, if we have:
682     // _base: ...
683     // Lfixup: .quad Ltarget - .
684     // ...
685     // Ltarget:
686     //
687     // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
688     *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
689     return;
690   case delta64:
691     *loc64 = ref.addend() + inAtomAddress - fixupAddress;
692     return;
693   case delta64Anon:
694     // The value we write here should be the delta to the target
695     // after taking in to account the difference from the fixup back to the
696     // last defined label
697     // ie, if we have:
698     // _base: ...
699     // Lfixup: .quad Ltarget - .
700     // ...
701     // Ltarget:
702     //
703     // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
704     *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
705     return;
706   case negDelta64:
707     *loc64 = ref.addend() + fixupAddress - inAtomAddress;
708     return;
709   case negDelta32:
710     *loc32 = ref.addend() + fixupAddress - inAtomAddress;
711     return;
712   case ripRel32GotLoadNowLea:
713     llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
714     return;
715   case lazyPointer:
716   case lazyImmediateLocation:
717     llvm_unreachable("lazy reference kind implies Stubs pass was run");
718     return;
719   case imageOffset:
720   case imageOffsetGot:
721   case unwindInfoToEhFrame:
722     llvm_unreachable("fixup implies __unwind_info");
723     return;
724   case unwindFDEToFunction:
725     // Do nothing for now
726     return;
727   case invalid:
728     // Fall into llvm_unreachable().
729     break;
730   }
731   llvm_unreachable("unknown x86_64 Reference Kind");
732 }
733 
734 void ArchHandler_x86_64::appendSectionRelocations(
735                                    const DefinedAtom &atom,
736                                    uint64_t atomSectionOffset,
737                                    const Reference &ref,
738                                    FindSymbolIndexForAtom symbolIndexForAtom,
739                                    FindSectionIndexForAtom sectionIndexForAtom,
740                                    FindAddressForAtom addressForAtom,
741                                    normalized::Relocations &relocs) {
742   if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
743     return;
744   assert(ref.kindArch() == Reference::KindArch::x86_64);
745   uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
746   switch (static_cast<X86_64Kind>(ref.kindValue())) {
747   case branch32:
748     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
749                 X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
750     return;
751   case ripRel32:
752     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
753                 X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 );
754     return;
755   case ripRel32Anon:
756     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
757                 X86_64_RELOC_SIGNED | rPcRel           | rLength4 );
758     return;
759   case ripRel32Got:
760     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
761                 X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 );
762     return;
763   case ripRel32GotLoad:
764     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
765                 X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
766     return;
767   case ripRel32Tlv:
768     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
769                 X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
770     return;
771   case tlvInitSectionOffset:
772   case pointer64:
773     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
774                 X86_64_RELOC_UNSIGNED  | rExtern | rLength8);
775     return;
776   case pointer64Anon:
777     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
778                 X86_64_RELOC_UNSIGNED | rLength8);
779     return;
780   case ripRel32Minus1:
781     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
782                 X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
783     return;
784   case ripRel32Minus1Anon:
785     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
786                 X86_64_RELOC_SIGNED_1 | rPcRel           | rLength4 );
787     return;
788   case ripRel32Minus2:
789     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
790                 X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
791     return;
792   case ripRel32Minus2Anon:
793     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
794                 X86_64_RELOC_SIGNED_2 | rPcRel           | rLength4 );
795     return;
796   case ripRel32Minus4:
797     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
798                 X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
799     return;
800   case ripRel32Minus4Anon:
801     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
802                 X86_64_RELOC_SIGNED_4 | rPcRel           | rLength4 );
803     return;
804   case delta32:
805     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
806                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
807     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
808                 X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
809     return;
810   case delta32Anon:
811     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
812                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
813     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
814                 X86_64_RELOC_UNSIGNED             | rLength4 );
815     return;
816   case delta64:
817     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
818                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
819     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
820                 X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
821     return;
822   case delta64Anon:
823     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
824                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
825     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
826                 X86_64_RELOC_UNSIGNED             | rLength8 );
827     return;
828   case unwindFDEToFunction:
829   case unwindInfoToEhFrame:
830     return;
831   case negDelta32:
832     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
833                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
834     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
835                 X86_64_RELOC_UNSIGNED   | rExtern | rLength4 );
836     return;
837   case negDelta64:
838     appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
839                 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
840     appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
841                 X86_64_RELOC_UNSIGNED   | rExtern | rLength8 );
842     return;
843   case ripRel32GotLoadNowLea:
844     llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
845     return;
846   case lazyPointer:
847   case lazyImmediateLocation:
848     llvm_unreachable("lazy reference kind implies Stubs pass was run");
849     return;
850   case imageOffset:
851   case imageOffsetGot:
852     llvm_unreachable("__unwind_info references should have been resolved");
853     return;
854   case invalid:
855     // Fall into llvm_unreachable().
856     break;
857   }
858   llvm_unreachable("unknown x86_64 Reference Kind");
859 }
860 
861 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
862   return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
863 }
864 
865 } // namespace mach_o
866 } // namespace lld
867