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(); 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(); 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(); 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(); 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(); 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(); 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 *kind = delta64; 467 *addend = encodedAddend + offsetInAtom; 468 } else if (inAtom == *target) { 469 *kind = negDelta64; 470 *addend = encodedAddend - offsetInAtom; 471 *target = fromTarget; 472 } else 473 return llvm::make_error<GenericError>("Invalid pointer diff"); 474 return llvm::Error(); 475 } 476 case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | 477 X86_64_RELOC_UNSIGNED | rExtern | rLength4): { 478 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 479 return ec; 480 uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent; 481 if (inAtom == fromTarget) { 482 *kind = delta32; 483 *addend = encodedAddend + offsetInAtom; 484 } else if (inAtom == *target) { 485 *kind = negDelta32; 486 *addend = encodedAddend - offsetInAtom; 487 *target = fromTarget; 488 } else 489 return llvm::make_error<GenericError>("Invalid pointer diff"); 490 return llvm::Error(); 491 } 492 case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | 493 X86_64_RELOC_UNSIGNED | rLength8): 494 if (fromTarget != inAtom) 495 return llvm::make_error<GenericError>("pointer diff not in base atom"); 496 *kind = delta64Anon; 497 targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent; 498 return atomFromAddress(reloc2.symbol, targetAddress, target, addend); 499 case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | 500 X86_64_RELOC_UNSIGNED | rLength4): 501 if (fromTarget != inAtom) 502 return llvm::make_error<GenericError>("pointer diff not in base atom"); 503 *kind = delta32Anon; 504 targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent; 505 return atomFromAddress(reloc2.symbol, targetAddress, target, addend); 506 default: 507 return llvm::make_error<GenericError>("unknown pair"); 508 } 509 } 510 511 void ArchHandler_x86_64::generateAtomContent( 512 const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, 513 FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, 514 llvm::MutableArrayRef<uint8_t> atomContentBuffer) { 515 // Copy raw bytes. 516 std::copy(atom.rawContent().begin(), atom.rawContent().end(), 517 atomContentBuffer.begin()); 518 // Apply fix-ups. 519 for (const Reference *ref : atom) { 520 uint32_t offset = ref->offsetInAtom(); 521 const Atom *target = ref->target(); 522 uint64_t targetAddress = 0; 523 if (isa<DefinedAtom>(target)) 524 targetAddress = findAddress(*target); 525 uint64_t atomAddress = findAddress(atom); 526 uint64_t fixupAddress = atomAddress + offset; 527 if (relocatable) { 528 applyFixupRelocatable(*ref, &atomContentBuffer[offset], 529 fixupAddress, targetAddress, 530 atomAddress); 531 } else { 532 applyFixupFinal(*ref, &atomContentBuffer[offset], 533 fixupAddress, targetAddress, 534 atomAddress, imageBaseAddress, findSectionAddress); 535 } 536 } 537 } 538 539 void ArchHandler_x86_64::applyFixupFinal( 540 const Reference &ref, uint8_t *loc, uint64_t fixupAddress, 541 uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress, 542 FindAddressForAtom findSectionAddress) { 543 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 544 return; 545 assert(ref.kindArch() == Reference::KindArch::x86_64); 546 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 547 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc); 548 switch (static_cast<X86_64Kind>(ref.kindValue())) { 549 case branch32: 550 case ripRel32: 551 case ripRel32Anon: 552 case ripRel32Got: 553 case ripRel32GotLoad: 554 case ripRel32Tlv: 555 *loc32 = targetAddress - (fixupAddress + 4) + ref.addend(); 556 return; 557 case pointer64: 558 case pointer64Anon: 559 *loc64 = targetAddress + ref.addend(); 560 return; 561 case tlvInitSectionOffset: 562 *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend(); 563 return; 564 case ripRel32Minus1: 565 case ripRel32Minus1Anon: 566 *loc32 = targetAddress - (fixupAddress + 5) + ref.addend(); 567 return; 568 case ripRel32Minus2: 569 case ripRel32Minus2Anon: 570 *loc32 = targetAddress - (fixupAddress + 6) + ref.addend(); 571 return; 572 case ripRel32Minus4: 573 case ripRel32Minus4Anon: 574 *loc32 = targetAddress - (fixupAddress + 8) + ref.addend(); 575 return; 576 case delta32: 577 case delta32Anon: 578 *loc32 = targetAddress - fixupAddress + ref.addend(); 579 return; 580 case delta64: 581 case delta64Anon: 582 case unwindFDEToFunction: 583 *loc64 = targetAddress - fixupAddress + ref.addend(); 584 return; 585 case ripRel32GotLoadNowLea: 586 // Change MOVQ to LEA 587 assert(loc[-2] == 0x8B); 588 loc[-2] = 0x8D; 589 *loc32 = targetAddress - (fixupAddress + 4) + ref.addend(); 590 return; 591 case negDelta64: 592 *loc64 = fixupAddress - targetAddress + ref.addend(); 593 return; 594 case negDelta32: 595 *loc32 = fixupAddress - targetAddress + ref.addend(); 596 return; 597 case lazyPointer: 598 // Do nothing 599 return; 600 case lazyImmediateLocation: 601 *loc32 = ref.addend(); 602 return; 603 case imageOffset: 604 case imageOffsetGot: 605 *loc32 = (targetAddress - imageBaseAddress) + ref.addend(); 606 return; 607 case unwindInfoToEhFrame: { 608 uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend(); 609 assert(val < 0xffffffU && "offset in __eh_frame too large"); 610 *loc32 = (*loc32 & 0xff000000U) | val; 611 return; 612 } 613 case invalid: 614 // Fall into llvm_unreachable(). 615 break; 616 } 617 llvm_unreachable("invalid x86_64 Reference Kind"); 618 } 619 620 void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, 621 uint8_t *loc, 622 uint64_t fixupAddress, 623 uint64_t targetAddress, 624 uint64_t inAtomAddress) { 625 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 626 return; 627 assert(ref.kindArch() == Reference::KindArch::x86_64); 628 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 629 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc); 630 switch (static_cast<X86_64Kind>(ref.kindValue())) { 631 case branch32: 632 case ripRel32: 633 case ripRel32Got: 634 case ripRel32GotLoad: 635 case ripRel32Tlv: 636 *loc32 = ref.addend(); 637 return; 638 case ripRel32Anon: 639 *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend(); 640 return; 641 case tlvInitSectionOffset: 642 case pointer64: 643 *loc64 = ref.addend(); 644 return; 645 case pointer64Anon: 646 *loc64 = targetAddress + ref.addend(); 647 return; 648 case ripRel32Minus1: 649 *loc32 = ref.addend() - 1; 650 return; 651 case ripRel32Minus1Anon: 652 *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend(); 653 return; 654 case ripRel32Minus2: 655 *loc32 = ref.addend() - 2; 656 return; 657 case ripRel32Minus2Anon: 658 *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend(); 659 return; 660 case ripRel32Minus4: 661 *loc32 = ref.addend() - 4; 662 return; 663 case ripRel32Minus4Anon: 664 *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend(); 665 return; 666 case delta32: 667 *loc32 = ref.addend() + inAtomAddress - fixupAddress; 668 return; 669 case delta32Anon: 670 // The value we write here should be the the delta to the target 671 // after taking in to account the difference from the fixup back to the 672 // last defined label 673 // ie, if we have: 674 // _base: ... 675 // Lfixup: .quad Ltarget - . 676 // ... 677 // Ltarget: 678 // 679 // Then we want to encode the value (Ltarget + addend) - (LFixup - _base) 680 *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress); 681 return; 682 case delta64: 683 *loc64 = ref.addend() + inAtomAddress - fixupAddress; 684 return; 685 case delta64Anon: 686 // The value we write here should be the the delta to the target 687 // after taking in to account the difference from the fixup back to the 688 // last defined label 689 // ie, if we have: 690 // _base: ... 691 // Lfixup: .quad Ltarget - . 692 // ... 693 // Ltarget: 694 // 695 // Then we want to encode the value (Ltarget + addend) - (LFixup - _base) 696 *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress); 697 return; 698 case negDelta64: 699 *loc64 = ref.addend() + fixupAddress - inAtomAddress; 700 return; 701 case negDelta32: 702 *loc32 = ref.addend() + fixupAddress - inAtomAddress; 703 return; 704 case ripRel32GotLoadNowLea: 705 llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); 706 return; 707 case lazyPointer: 708 case lazyImmediateLocation: 709 llvm_unreachable("lazy reference kind implies Stubs pass was run"); 710 return; 711 case imageOffset: 712 case imageOffsetGot: 713 case unwindInfoToEhFrame: 714 llvm_unreachable("fixup implies __unwind_info"); 715 return; 716 case unwindFDEToFunction: 717 // Do nothing for now 718 return; 719 case invalid: 720 // Fall into llvm_unreachable(). 721 break; 722 } 723 llvm_unreachable("unknown x86_64 Reference Kind"); 724 } 725 726 void ArchHandler_x86_64::appendSectionRelocations( 727 const DefinedAtom &atom, 728 uint64_t atomSectionOffset, 729 const Reference &ref, 730 FindSymbolIndexForAtom symbolIndexForAtom, 731 FindSectionIndexForAtom sectionIndexForAtom, 732 FindAddressForAtom addressForAtom, 733 normalized::Relocations &relocs) { 734 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 735 return; 736 assert(ref.kindArch() == Reference::KindArch::x86_64); 737 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); 738 switch (static_cast<X86_64Kind>(ref.kindValue())) { 739 case branch32: 740 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 741 X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4); 742 return; 743 case ripRel32: 744 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 745 X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 ); 746 return; 747 case ripRel32Anon: 748 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 749 X86_64_RELOC_SIGNED | rPcRel | rLength4 ); 750 return; 751 case ripRel32Got: 752 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 753 X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 ); 754 return; 755 case ripRel32GotLoad: 756 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 757 X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 ); 758 return; 759 case ripRel32Tlv: 760 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 761 X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 ); 762 return; 763 case tlvInitSectionOffset: 764 case pointer64: 765 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 766 X86_64_RELOC_UNSIGNED | rExtern | rLength8); 767 return; 768 case pointer64Anon: 769 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 770 X86_64_RELOC_UNSIGNED | rLength8); 771 return; 772 case ripRel32Minus1: 773 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 774 X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 ); 775 return; 776 case ripRel32Minus1Anon: 777 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 778 X86_64_RELOC_SIGNED_1 | rPcRel | rLength4 ); 779 return; 780 case ripRel32Minus2: 781 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 782 X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 ); 783 return; 784 case ripRel32Minus2Anon: 785 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 786 X86_64_RELOC_SIGNED_2 | rPcRel | rLength4 ); 787 return; 788 case ripRel32Minus4: 789 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 790 X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 ); 791 return; 792 case ripRel32Minus4Anon: 793 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 794 X86_64_RELOC_SIGNED_4 | rPcRel | rLength4 ); 795 return; 796 case delta32: 797 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 798 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); 799 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 800 X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); 801 return; 802 case delta32Anon: 803 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 804 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); 805 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 806 X86_64_RELOC_UNSIGNED | rLength4 ); 807 return; 808 case delta64: 809 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 810 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); 811 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 812 X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); 813 return; 814 case delta64Anon: 815 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 816 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); 817 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 818 X86_64_RELOC_UNSIGNED | rLength8 ); 819 return; 820 case unwindFDEToFunction: 821 case unwindInfoToEhFrame: 822 return; 823 case negDelta32: 824 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 825 X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); 826 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 827 X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); 828 return; 829 case negDelta64: 830 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 831 X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); 832 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 833 X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); 834 return; 835 case ripRel32GotLoadNowLea: 836 llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); 837 return; 838 case lazyPointer: 839 case lazyImmediateLocation: 840 llvm_unreachable("lazy reference kind implies Stubs pass was run"); 841 return; 842 case imageOffset: 843 case imageOffsetGot: 844 llvm_unreachable("__unwind_info references should have been resolved"); 845 return; 846 case invalid: 847 // Fall into llvm_unreachable(). 848 break; 849 } 850 llvm_unreachable("unknown x86_64 Reference Kind"); 851 } 852 853 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() { 854 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64()); 855 } 856 857 } // namespace mach_o 858 } // namespace lld 859