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