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