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