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