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