ArchHandler_x86_64.cpp revision 360784
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
18using namespace llvm::MachO;
19using namespace lld::mach_o::normalized;
20
21namespace lld {
22namespace mach_o {
23
24using llvm::support::ulittle32_t;
25using llvm::support::ulittle64_t;
26
27using llvm::support::little32_t;
28using llvm::support::little64_t;
29
30class ArchHandler_x86_64 : public ArchHandler {
31public:
32  ArchHandler_x86_64() = default;
33  ~ArchHandler_x86_64() override = default;
34
35  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
36
37  Reference::KindArch kindArch() override {
38    return Reference::KindArch::x86_64;
39  }
40
41  /// Used by GOTPass to locate GOT References
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
61  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
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
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
95  bool needsCompactUnwind() override {
96    return true;
97  }
98
99  Reference::KindValue imageOffsetKind() override {
100    return imageOffset;
101  }
102
103  Reference::KindValue imageOffsetKindIndirect() override {
104    return imageOffsetGot;
105  }
106
107  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
108    return ripRel32Got;
109  }
110
111  Reference::KindValue unwindRefToCIEKind() override {
112    return negDelta32;
113  }
114
115  Reference::KindValue unwindRefToFunctionKind() override{
116    return unwindFDEToFunction;
117  }
118
119  Reference::KindValue lazyImmediateLocationKind() override {
120    return lazyImmediateLocation;
121  }
122
123  Reference::KindValue unwindRefToEhFrameKind() override {
124    return unwindInfoToEhFrame;
125  }
126
127  Reference::KindValue pointerKind() override {
128    return pointer64;
129  }
130
131  uint32_t dwarfCompactUnwindType() override {
132    return 0x04000000U;
133  }
134
135  const StubInfo &stubInfo() override { return _sStubInfo; }
136
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
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
184  bool isDataInCodeTransition(Reference::KindValue refKind) override {
185    return refKind == modeCode || refKind == modeData;
186  }
187
188  Reference::KindValue dataInCodeTransitionStart(
189                                        const MachODefinedAtom &atom) override {
190    return modeData;
191  }
192
193  Reference::KindValue dataInCodeTransitionEnd(
194                                        const MachODefinedAtom &atom) override {
195    return modeCode;
196  }
197
198private:
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
261const 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
296const 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
340bool 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
347bool 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
355bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
356  return (reloc.type == X86_64_RELOC_SUBTRACTOR);
357}
358
359Reference::KindValue
360ArchHandler_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
395llvm::Error
396ArchHandler_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
472llvm::Error
473ArchHandler_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
545void 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
573void 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
656void 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
764void 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
894std::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