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 36 const Registry::KindStrings *kindStrings() override { return _sKindStrings; } 37 38 Reference::KindArch kindArch() override { 39 return Reference::KindArch::x86_64; 40 } 41 42 /// Used by GOTPass to locate GOT References 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 62 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 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 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 96 bool needsCompactUnwind() override { 97 return true; 98 } 99 100 Reference::KindValue imageOffsetKind() override { 101 return imageOffset; 102 } 103 104 Reference::KindValue imageOffsetKindIndirect() override { 105 return imageOffsetGot; 106 } 107 108 Reference::KindValue unwindRefToPersonalityFunctionKind() override { 109 return ripRel32Got; 110 } 111 112 Reference::KindValue unwindRefToCIEKind() override { 113 return negDelta32; 114 } 115 116 Reference::KindValue unwindRefToFunctionKind() override{ 117 return unwindFDEToFunction; 118 } 119 120 Reference::KindValue lazyImmediateLocationKind() override { 121 return lazyImmediateLocation; 122 } 123 124 Reference::KindValue unwindRefToEhFrameKind() override { 125 return unwindInfoToEhFrame; 126 } 127 128 Reference::KindValue pointerKind() override { 129 return pointer64; 130 } 131 132 uint32_t dwarfCompactUnwindType() override { 133 return 0x04000000U; 134 } 135 136 const StubInfo &stubInfo() override { return _sStubInfo; } 137 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 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 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 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 329 bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) { 330 return (reloc.type == X86_64_RELOC_SUBTRACTOR); 331 } 332 333 Reference::KindValue 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 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 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 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 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 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 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 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