1 //===- lib/FileFormat/MachO/ArchHandler_arm64.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 #include "llvm/Support/Format.h" 19 20 using namespace llvm::MachO; 21 using namespace lld::mach_o::normalized; 22 23 namespace lld { 24 namespace mach_o { 25 26 using llvm::support::ulittle32_t; 27 using llvm::support::ulittle64_t; 28 29 using llvm::support::little32_t; 30 using llvm::support::little64_t; 31 32 class ArchHandler_arm64 : public ArchHandler { 33 public: 34 ArchHandler_arm64() = default; 35 ~ArchHandler_arm64() override = default; 36 37 const Registry::KindStrings *kindStrings() override { return _sKindStrings; } 38 39 Reference::KindArch kindArch() override { 40 return Reference::KindArch::AArch64; 41 } 42 43 /// Used by GOTPass to locate GOT References 44 bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override { 45 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 46 return false; 47 assert(ref.kindArch() == Reference::KindArch::AArch64); 48 switch (ref.kindValue()) { 49 case gotPage21: 50 case gotOffset12: 51 canBypassGOT = true; 52 return true; 53 case delta32ToGOT: 54 case unwindCIEToPersonalityFunction: 55 case imageOffsetGot: 56 canBypassGOT = false; 57 return true; 58 default: 59 return false; 60 } 61 } 62 63 /// Used by GOTPass to update GOT References. 64 void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override { 65 // If GOT slot was instanciated, transform: 66 // gotPage21/gotOffset12 -> page21/offset12scale8 67 // If GOT slot optimized away, transform: 68 // gotPage21/gotOffset12 -> page21/addOffset12 69 assert(ref->kindNamespace() == Reference::KindNamespace::mach_o); 70 assert(ref->kindArch() == Reference::KindArch::AArch64); 71 switch (ref->kindValue()) { 72 case gotPage21: 73 const_cast<Reference *>(ref)->setKindValue(page21); 74 break; 75 case gotOffset12: 76 const_cast<Reference *>(ref)->setKindValue(targetNowGOT ? 77 offset12scale8 : addOffset12); 78 break; 79 case delta32ToGOT: 80 const_cast<Reference *>(ref)->setKindValue(delta32); 81 break; 82 case imageOffsetGot: 83 const_cast<Reference *>(ref)->setKindValue(imageOffset); 84 break; 85 default: 86 llvm_unreachable("Not a GOT reference"); 87 } 88 } 89 90 const StubInfo &stubInfo() override { return _sStubInfo; } 91 92 bool isCallSite(const Reference &) override; 93 bool isNonCallBranch(const Reference &) override { 94 return false; 95 } 96 97 bool isPointer(const Reference &) override; 98 bool isPairedReloc(const normalized::Relocation &) override; 99 100 bool needsCompactUnwind() override { 101 return true; 102 } 103 Reference::KindValue imageOffsetKind() override { 104 return imageOffset; 105 } 106 Reference::KindValue imageOffsetKindIndirect() override { 107 return imageOffsetGot; 108 } 109 110 Reference::KindValue unwindRefToPersonalityFunctionKind() override { 111 return unwindCIEToPersonalityFunction; 112 } 113 114 Reference::KindValue unwindRefToCIEKind() override { 115 return negDelta32; 116 } 117 118 Reference::KindValue unwindRefToFunctionKind() override { 119 return unwindFDEToFunction; 120 } 121 122 Reference::KindValue unwindRefToEhFrameKind() override { 123 return unwindInfoToEhFrame; 124 } 125 126 Reference::KindValue pointerKind() override { 127 return pointer64; 128 } 129 130 uint32_t dwarfCompactUnwindType() override { 131 return 0x03000000; 132 } 133 134 llvm::Error getReferenceInfo(const normalized::Relocation &reloc, 135 const DefinedAtom *inAtom, 136 uint32_t offsetInAtom, 137 uint64_t fixupAddress, bool isBig, 138 FindAtomBySectionAndAddress atomFromAddress, 139 FindAtomBySymbolIndex atomFromSymbolIndex, 140 Reference::KindValue *kind, 141 const lld::Atom **target, 142 Reference::Addend *addend) override; 143 llvm::Error 144 getPairReferenceInfo(const normalized::Relocation &reloc1, 145 const normalized::Relocation &reloc2, 146 const DefinedAtom *inAtom, 147 uint32_t offsetInAtom, 148 uint64_t fixupAddress, bool isBig, bool scatterable, 149 FindAtomBySectionAndAddress atomFromAddress, 150 FindAtomBySymbolIndex atomFromSymbolIndex, 151 Reference::KindValue *kind, 152 const lld::Atom **target, 153 Reference::Addend *addend) override; 154 155 bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override { 156 return (atom->contentType() == DefinedAtom::typeCString); 157 } 158 159 void generateAtomContent(const DefinedAtom &atom, bool relocatable, 160 FindAddressForAtom findAddress, 161 FindAddressForAtom findSectionAddress, 162 uint64_t imageBaseAddress, 163 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override; 164 165 void appendSectionRelocations(const DefinedAtom &atom, 166 uint64_t atomSectionOffset, 167 const Reference &ref, 168 FindSymbolIndexForAtom symbolIndexForAtom, 169 FindSectionIndexForAtom sectionIndexForAtom, 170 FindAddressForAtom addressForAtom, 171 normalized::Relocations &relocs) override; 172 173 private: 174 static const Registry::KindStrings _sKindStrings[]; 175 static const StubInfo _sStubInfo; 176 177 enum Arm64Kind : Reference::KindValue { 178 invalid, /// for error condition 179 180 // Kinds found in mach-o .o files: 181 branch26, /// ex: bl _foo 182 page21, /// ex: adrp x1, _foo@PAGE 183 offset12, /// ex: ldrb w0, [x1, _foo@PAGEOFF] 184 offset12scale2, /// ex: ldrs w0, [x1, _foo@PAGEOFF] 185 offset12scale4, /// ex: ldr w0, [x1, _foo@PAGEOFF] 186 offset12scale8, /// ex: ldr x0, [x1, _foo@PAGEOFF] 187 offset12scale16, /// ex: ldr q0, [x1, _foo@PAGEOFF] 188 gotPage21, /// ex: adrp x1, _foo@GOTPAGE 189 gotOffset12, /// ex: ldr w0, [x1, _foo@GOTPAGEOFF] 190 tlvPage21, /// ex: adrp x1, _foo@TLVPAGE 191 tlvOffset12, /// ex: ldr w0, [x1, _foo@TLVPAGEOFF] 192 193 pointer64, /// ex: .quad _foo 194 delta64, /// ex: .quad _foo - . 195 delta32, /// ex: .long _foo - . 196 negDelta32, /// ex: .long . - _foo 197 pointer64ToGOT, /// ex: .quad _foo@GOT 198 delta32ToGOT, /// ex: .long _foo@GOT - . 199 200 // Kinds introduced by Passes: 201 addOffset12, /// Location contains LDR to change into ADD. 202 lazyPointer, /// Location contains a lazy pointer. 203 lazyImmediateLocation, /// Location contains immediate value used in stub. 204 imageOffset, /// Location contains offset of atom in final image 205 imageOffsetGot, /// Location contains offset of GOT entry for atom in 206 /// final image (typically personality function). 207 unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be 208 /// rematerialized in relocatable object 209 /// (yay for implicit contracts!). 210 unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in 211 /// relocatable object (yay for implicit contracts!). 212 unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to 213 /// refer to __eh_frame entry. 214 }; 215 216 void applyFixupFinal(const Reference &ref, uint8_t *location, 217 uint64_t fixupAddress, uint64_t targetAddress, 218 uint64_t inAtomAddress, uint64_t imageBaseAddress, 219 FindAddressForAtom findSectionAddress); 220 221 void applyFixupRelocatable(const Reference &ref, uint8_t *location, 222 uint64_t fixupAddress, uint64_t targetAddress, 223 uint64_t inAtomAddress, bool targetUnnamed); 224 225 // Utility functions for inspecting/updating instructions. 226 static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp); 227 static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp); 228 static Arm64Kind offset12KindFromInstruction(uint32_t instr); 229 static uint32_t setImm12(uint32_t instr, uint32_t offset); 230 }; 231 232 const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = { 233 LLD_KIND_STRING_ENTRY(invalid), 234 LLD_KIND_STRING_ENTRY(branch26), 235 LLD_KIND_STRING_ENTRY(page21), 236 LLD_KIND_STRING_ENTRY(offset12), 237 LLD_KIND_STRING_ENTRY(offset12scale2), 238 LLD_KIND_STRING_ENTRY(offset12scale4), 239 LLD_KIND_STRING_ENTRY(offset12scale8), 240 LLD_KIND_STRING_ENTRY(offset12scale16), 241 LLD_KIND_STRING_ENTRY(gotPage21), 242 LLD_KIND_STRING_ENTRY(gotOffset12), 243 LLD_KIND_STRING_ENTRY(tlvPage21), 244 LLD_KIND_STRING_ENTRY(tlvOffset12), 245 LLD_KIND_STRING_ENTRY(pointer64), 246 LLD_KIND_STRING_ENTRY(delta64), 247 LLD_KIND_STRING_ENTRY(delta32), 248 LLD_KIND_STRING_ENTRY(negDelta32), 249 LLD_KIND_STRING_ENTRY(pointer64ToGOT), 250 LLD_KIND_STRING_ENTRY(delta32ToGOT), 251 252 LLD_KIND_STRING_ENTRY(addOffset12), 253 LLD_KIND_STRING_ENTRY(lazyPointer), 254 LLD_KIND_STRING_ENTRY(lazyImmediateLocation), 255 LLD_KIND_STRING_ENTRY(imageOffset), 256 LLD_KIND_STRING_ENTRY(imageOffsetGot), 257 LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction), 258 LLD_KIND_STRING_ENTRY(unwindFDEToFunction), 259 LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame), 260 261 LLD_KIND_STRING_END 262 }; 263 264 const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = { 265 "dyld_stub_binder", 266 267 // Lazy pointer references 268 { Reference::KindArch::AArch64, pointer64, 0, 0 }, 269 { Reference::KindArch::AArch64, lazyPointer, 0, 0 }, 270 271 // GOT pointer to dyld_stub_binder 272 { Reference::KindArch::AArch64, pointer64, 0, 0 }, 273 274 // arm64 code alignment 2^1 275 1, 276 277 // Stub size and code 278 12, 279 { 0x10, 0x00, 0x00, 0x90, // ADRP X16, lazy_pointer@page 280 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16, lazy_pointer@pageoff] 281 0x00, 0x02, 0x1F, 0xD6 }, // BR X16 282 { Reference::KindArch::AArch64, page21, 0, 0 }, 283 { true, offset12scale8, 4, 0 }, 284 285 // Stub Helper size and code 286 12, 287 { 0x50, 0x00, 0x00, 0x18, // LDR W16, L0 288 0x00, 0x00, 0x00, 0x14, // LDR B helperhelper 289 0x00, 0x00, 0x00, 0x00 }, // L0: .long 0 290 { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 }, 291 { Reference::KindArch::AArch64, branch26, 4, 0 }, 292 293 // Stub helper image cache content type 294 DefinedAtom::typeGOT, 295 296 // Stub Helper-Common size and code 297 24, 298 // Stub helper alignment 299 2, 300 { 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page 301 0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff 302 0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]! 303 0x10, 0x00, 0x00, 0x90, // ADRP X16, _fast_lazy_bind@page 304 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16,_fast_lazy_bind@pageoff] 305 0x00, 0x02, 0x1F, 0xD6 }, // BR X16 306 { Reference::KindArch::AArch64, page21, 0, 0 }, 307 { true, offset12, 4, 0 }, 308 { Reference::KindArch::AArch64, page21, 12, 0 }, 309 { true, offset12scale8, 16, 0 } 310 }; 311 312 bool ArchHandler_arm64::isCallSite(const Reference &ref) { 313 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 314 return false; 315 assert(ref.kindArch() == Reference::KindArch::AArch64); 316 return (ref.kindValue() == branch26); 317 } 318 319 bool ArchHandler_arm64::isPointer(const Reference &ref) { 320 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 321 return false; 322 assert(ref.kindArch() == Reference::KindArch::AArch64); 323 Reference::KindValue kind = ref.kindValue(); 324 return (kind == pointer64); 325 } 326 327 bool ArchHandler_arm64::isPairedReloc(const Relocation &r) { 328 return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR)); 329 } 330 331 uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr, 332 int32_t displacement) { 333 assert((displacement <= 134217727) && (displacement > (-134217728)) && 334 "arm64 branch out of range"); 335 return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF); 336 } 337 338 uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction, 339 int64_t displacement) { 340 assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) && 341 "arm64 ADRP out of range"); 342 assert(((instruction & 0x9F000000) == 0x90000000) && 343 "reloc not on ADRP instruction"); 344 uint32_t immhi = (displacement >> 9) & (0x00FFFFE0); 345 uint32_t immlo = (displacement << 17) & (0x60000000); 346 return (instruction & 0x9F00001F) | immlo | immhi; 347 } 348 349 ArchHandler_arm64::Arm64Kind 350 ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) { 351 if (instruction & 0x08000000) { 352 switch ((instruction >> 30) & 0x3) { 353 case 0: 354 if ((instruction & 0x04800000) == 0x04800000) 355 return offset12scale16; 356 return offset12; 357 case 1: 358 return offset12scale2; 359 case 2: 360 return offset12scale4; 361 case 3: 362 return offset12scale8; 363 } 364 } 365 return offset12; 366 } 367 368 uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) { 369 assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range"); 370 uint32_t imm12 = offset << 10; 371 return (instruction & 0xFFC003FF) | imm12; 372 } 373 374 llvm::Error ArchHandler_arm64::getReferenceInfo( 375 const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, 376 uint64_t fixupAddress, bool isBig, 377 FindAtomBySectionAndAddress atomFromAddress, 378 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, 379 const lld::Atom **target, Reference::Addend *addend) { 380 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; 381 switch (relocPattern(reloc)) { 382 case ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4: 383 // ex: bl _foo 384 *kind = branch26; 385 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 386 return ec; 387 *addend = 0; 388 return llvm::Error::success(); 389 case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4: 390 // ex: adrp x1, _foo@PAGE 391 *kind = page21; 392 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 393 return ec; 394 *addend = 0; 395 return llvm::Error::success(); 396 case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4: 397 // ex: ldr x0, [x1, _foo@PAGEOFF] 398 *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent); 399 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 400 return ec; 401 *addend = 0; 402 return llvm::Error::success(); 403 case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4: 404 // ex: adrp x1, _foo@GOTPAGE 405 *kind = gotPage21; 406 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 407 return ec; 408 *addend = 0; 409 return llvm::Error::success(); 410 case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4: 411 // ex: ldr x0, [x1, _foo@GOTPAGEOFF] 412 *kind = gotOffset12; 413 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 414 return ec; 415 *addend = 0; 416 return llvm::Error::success(); 417 case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4: 418 // ex: adrp x1, _foo@TLVPAGE 419 *kind = tlvPage21; 420 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 421 return ec; 422 *addend = 0; 423 return llvm::Error::success(); 424 case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4: 425 // ex: ldr x0, [x1, _foo@TLVPAGEOFF] 426 *kind = tlvOffset12; 427 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 428 return ec; 429 *addend = 0; 430 return llvm::Error::success(); 431 case ARM64_RELOC_UNSIGNED | rExtern | rLength8: 432 // ex: .quad _foo + N 433 *kind = pointer64; 434 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 435 return ec; 436 *addend = *(const little64_t *)fixupContent; 437 return llvm::Error::success(); 438 case ARM64_RELOC_UNSIGNED | rLength8: 439 // ex: .quad Lfoo + N 440 *kind = pointer64; 441 return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent, 442 target, addend); 443 case ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8: 444 // ex: .quad _foo@GOT 445 *kind = pointer64ToGOT; 446 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 447 return ec; 448 *addend = 0; 449 return llvm::Error::success(); 450 case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4: 451 // ex: .long _foo@GOT - . 452 453 // If we are in an .eh_frame section, then the kind of the relocation should 454 // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction. 455 if (inAtom->contentType() == DefinedAtom::typeCFI) 456 *kind = unwindCIEToPersonalityFunction; 457 else 458 *kind = delta32ToGOT; 459 460 if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) 461 return ec; 462 *addend = 0; 463 return llvm::Error::success(); 464 default: 465 return llvm::make_error<GenericError>("unsupported arm64 relocation type"); 466 } 467 } 468 469 llvm::Error ArchHandler_arm64::getPairReferenceInfo( 470 const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, 471 const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, 472 bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, 473 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, 474 const lld::Atom **target, Reference::Addend *addend) { 475 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; 476 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) { 477 case ((ARM64_RELOC_ADDEND | rLength4) << 16 | 478 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4): 479 // ex: bl _foo+8 480 *kind = branch26; 481 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 482 return ec; 483 *addend = reloc1.symbol; 484 return llvm::Error::success(); 485 case ((ARM64_RELOC_ADDEND | rLength4) << 16 | 486 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4): 487 // ex: adrp x1, _foo@PAGE 488 *kind = page21; 489 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 490 return ec; 491 *addend = reloc1.symbol; 492 return llvm::Error::success(); 493 case ((ARM64_RELOC_ADDEND | rLength4) << 16 | 494 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): { 495 // ex: ldr w0, [x1, _foo@PAGEOFF] 496 uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent; 497 *kind = offset12KindFromInstruction(cont32); 498 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 499 return ec; 500 *addend = reloc1.symbol; 501 return llvm::Error::success(); 502 } 503 case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | 504 ARM64_RELOC_UNSIGNED | rExtern | rLength8): 505 // ex: .quad _foo - . 506 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 507 return ec; 508 509 // If we are in an .eh_frame section, then the kind of the relocation should 510 // not be delta64. It may instead be unwindFDEToFunction. 511 if (inAtom->contentType() == DefinedAtom::typeCFI) 512 *kind = unwindFDEToFunction; 513 else 514 *kind = delta64; 515 516 // The offsets of the 2 relocations must match 517 if (reloc1.offset != reloc2.offset) 518 return llvm::make_error<GenericError>( 519 "paired relocs must have the same offset"); 520 *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom; 521 return llvm::Error::success(); 522 case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | 523 ARM64_RELOC_UNSIGNED | rExtern | rLength4): 524 // ex: .quad _foo - . 525 *kind = delta32; 526 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) 527 return ec; 528 *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom; 529 return llvm::Error::success(); 530 default: 531 return llvm::make_error<GenericError>("unsupported arm64 relocation pair"); 532 } 533 } 534 535 void ArchHandler_arm64::generateAtomContent( 536 const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, 537 FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, 538 llvm::MutableArrayRef<uint8_t> atomContentBuffer) { 539 // Copy raw bytes. 540 std::copy(atom.rawContent().begin(), atom.rawContent().end(), 541 atomContentBuffer.begin()); 542 // Apply fix-ups. 543 #ifndef NDEBUG 544 if (atom.begin() != atom.end()) { 545 DEBUG_WITH_TYPE("atom-content", llvm::dbgs() 546 << "Applying fixups to atom:\n" 547 << " address=" 548 << llvm::format(" 0x%09lX", &atom) 549 << ", file=#" 550 << atom.file().ordinal() 551 << ", atom=#" 552 << atom.ordinal() 553 << ", name=" 554 << atom.name() 555 << ", type=" 556 << atom.contentType() 557 << "\n"); 558 } 559 #endif 560 for (const Reference *ref : atom) { 561 uint32_t offset = ref->offsetInAtom(); 562 const Atom *target = ref->target(); 563 bool targetUnnamed = target->name().empty(); 564 uint64_t targetAddress = 0; 565 if (isa<DefinedAtom>(target)) 566 targetAddress = findAddress(*target); 567 uint64_t atomAddress = findAddress(atom); 568 uint64_t fixupAddress = atomAddress + offset; 569 if (relocatable) { 570 applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress, 571 targetAddress, atomAddress, targetUnnamed); 572 } else { 573 applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress, 574 targetAddress, atomAddress, imageBaseAddress, 575 findSectionAddress); 576 } 577 } 578 } 579 580 void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc, 581 uint64_t fixupAddress, 582 uint64_t targetAddress, 583 uint64_t inAtomAddress, 584 uint64_t imageBaseAddress, 585 FindAddressForAtom findSectionAddress) { 586 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 587 return; 588 assert(ref.kindArch() == Reference::KindArch::AArch64); 589 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 590 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc); 591 int32_t displacement; 592 uint32_t instruction; 593 uint32_t value32; 594 uint32_t value64; 595 switch (static_cast<Arm64Kind>(ref.kindValue())) { 596 case branch26: 597 displacement = (targetAddress - fixupAddress) + ref.addend(); 598 *loc32 = setDisplacementInBranch26(*loc32, displacement); 599 return; 600 case page21: 601 case gotPage21: 602 case tlvPage21: 603 displacement = 604 ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096)); 605 *loc32 = setDisplacementInADRP(*loc32, displacement); 606 return; 607 case offset12: 608 case gotOffset12: 609 case tlvOffset12: 610 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 611 *loc32 = setImm12(*loc32, displacement); 612 return; 613 case offset12scale2: 614 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 615 assert(((displacement & 0x1) == 0) && 616 "scaled imm12 not accessing 2-byte aligneds"); 617 *loc32 = setImm12(*loc32, displacement >> 1); 618 return; 619 case offset12scale4: 620 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 621 assert(((displacement & 0x3) == 0) && 622 "scaled imm12 not accessing 4-byte aligned"); 623 *loc32 = setImm12(*loc32, displacement >> 2); 624 return; 625 case offset12scale8: 626 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 627 assert(((displacement & 0x7) == 0) && 628 "scaled imm12 not accessing 8-byte aligned"); 629 *loc32 = setImm12(*loc32, displacement >> 3); 630 return; 631 case offset12scale16: 632 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 633 assert(((displacement & 0xF) == 0) && 634 "scaled imm12 not accessing 16-byte aligned"); 635 *loc32 = setImm12(*loc32, displacement >> 4); 636 return; 637 case addOffset12: 638 instruction = *loc32; 639 assert(((instruction & 0xFFC00000) == 0xF9400000) && 640 "GOT reloc is not an LDR instruction"); 641 displacement = (targetAddress + ref.addend()) & 0x00000FFF; 642 value32 = 0x91000000 | (instruction & 0x000003FF); 643 instruction = setImm12(value32, displacement); 644 *loc32 = instruction; 645 return; 646 case pointer64: 647 case pointer64ToGOT: 648 *loc64 = targetAddress + ref.addend(); 649 return; 650 case delta64: 651 case unwindFDEToFunction: 652 *loc64 = (targetAddress - fixupAddress) + ref.addend(); 653 return; 654 case delta32: 655 case delta32ToGOT: 656 case unwindCIEToPersonalityFunction: 657 *loc32 = (targetAddress - fixupAddress) + ref.addend(); 658 return; 659 case negDelta32: 660 *loc32 = fixupAddress - targetAddress + ref.addend(); 661 return; 662 case lazyPointer: 663 // Do nothing 664 return; 665 case lazyImmediateLocation: 666 *loc32 = ref.addend(); 667 return; 668 case imageOffset: 669 *loc32 = (targetAddress - imageBaseAddress) + ref.addend(); 670 return; 671 case imageOffsetGot: 672 llvm_unreachable("imageOffsetGot should have been changed to imageOffset"); 673 break; 674 case unwindInfoToEhFrame: 675 value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend(); 676 assert(value64 < 0xffffffU && "offset in __eh_frame too large"); 677 *loc32 = (*loc32 & 0xff000000U) | value64; 678 return; 679 case invalid: 680 // Fall into llvm_unreachable(). 681 break; 682 } 683 llvm_unreachable("invalid arm64 Reference Kind"); 684 } 685 686 void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref, 687 uint8_t *loc, 688 uint64_t fixupAddress, 689 uint64_t targetAddress, 690 uint64_t inAtomAddress, 691 bool targetUnnamed) { 692 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 693 return; 694 assert(ref.kindArch() == Reference::KindArch::AArch64); 695 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc); 696 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc); 697 switch (static_cast<Arm64Kind>(ref.kindValue())) { 698 case branch26: 699 *loc32 = setDisplacementInBranch26(*loc32, 0); 700 return; 701 case page21: 702 case gotPage21: 703 case tlvPage21: 704 *loc32 = setDisplacementInADRP(*loc32, 0); 705 return; 706 case offset12: 707 case offset12scale2: 708 case offset12scale4: 709 case offset12scale8: 710 case offset12scale16: 711 case gotOffset12: 712 case tlvOffset12: 713 *loc32 = setImm12(*loc32, 0); 714 return; 715 case pointer64: 716 if (targetUnnamed) 717 *loc64 = targetAddress + ref.addend(); 718 else 719 *loc64 = ref.addend(); 720 return; 721 case delta64: 722 *loc64 = ref.addend() + inAtomAddress - fixupAddress; 723 return; 724 case unwindFDEToFunction: 725 // We don't emit unwindFDEToFunction in -r mode as they are implicitly 726 // generated from the data in the __eh_frame section. So here we need 727 // to use the targetAddress so that we can generate the full relocation 728 // when we parse again later. 729 *loc64 = targetAddress - fixupAddress; 730 return; 731 case delta32: 732 *loc32 = ref.addend() + inAtomAddress - fixupAddress; 733 return; 734 case negDelta32: 735 // We don't emit negDelta32 in -r mode as they are implicitly 736 // generated from the data in the __eh_frame section. So here we need 737 // to use the targetAddress so that we can generate the full relocation 738 // when we parse again later. 739 *loc32 = fixupAddress - targetAddress + ref.addend(); 740 return; 741 case pointer64ToGOT: 742 *loc64 = 0; 743 return; 744 case delta32ToGOT: 745 *loc32 = inAtomAddress - fixupAddress; 746 return; 747 case unwindCIEToPersonalityFunction: 748 // We don't emit unwindCIEToPersonalityFunction in -r mode as they are 749 // implicitly generated from the data in the __eh_frame section. So here we 750 // need to use the targetAddress so that we can generate the full relocation 751 // when we parse again later. 752 *loc32 = targetAddress - fixupAddress; 753 return; 754 case addOffset12: 755 llvm_unreachable("lazy reference kind implies GOT pass was run"); 756 case lazyPointer: 757 case lazyImmediateLocation: 758 llvm_unreachable("lazy reference kind implies Stubs pass was run"); 759 case imageOffset: 760 case imageOffsetGot: 761 case unwindInfoToEhFrame: 762 llvm_unreachable("fixup implies __unwind_info"); 763 return; 764 case invalid: 765 // Fall into llvm_unreachable(). 766 break; 767 } 768 llvm_unreachable("unknown arm64 Reference Kind"); 769 } 770 771 void ArchHandler_arm64::appendSectionRelocations( 772 const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref, 773 FindSymbolIndexForAtom symbolIndexForAtom, 774 FindSectionIndexForAtom sectionIndexForAtom, 775 FindAddressForAtom addressForAtom, normalized::Relocations &relocs) { 776 if (ref.kindNamespace() != Reference::KindNamespace::mach_o) 777 return; 778 assert(ref.kindArch() == Reference::KindArch::AArch64); 779 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); 780 switch (static_cast<Arm64Kind>(ref.kindValue())) { 781 case branch26: 782 if (ref.addend()) { 783 appendReloc(relocs, sectionOffset, ref.addend(), 0, 784 ARM64_RELOC_ADDEND | rLength4); 785 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 786 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4); 787 } else { 788 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 789 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4); 790 } 791 return; 792 case page21: 793 if (ref.addend()) { 794 appendReloc(relocs, sectionOffset, ref.addend(), 0, 795 ARM64_RELOC_ADDEND | rLength4); 796 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 797 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4); 798 } else { 799 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 800 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4); 801 } 802 return; 803 case offset12: 804 case offset12scale2: 805 case offset12scale4: 806 case offset12scale8: 807 case offset12scale16: 808 if (ref.addend()) { 809 appendReloc(relocs, sectionOffset, ref.addend(), 0, 810 ARM64_RELOC_ADDEND | rLength4); 811 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 812 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4); 813 } else { 814 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 815 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4); 816 } 817 return; 818 case gotPage21: 819 assert(ref.addend() == 0); 820 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 821 ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4); 822 return; 823 case gotOffset12: 824 assert(ref.addend() == 0); 825 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 826 ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4); 827 return; 828 case tlvPage21: 829 assert(ref.addend() == 0); 830 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 831 ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4); 832 return; 833 case tlvOffset12: 834 assert(ref.addend() == 0); 835 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 836 ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4); 837 return; 838 case pointer64: 839 if (ref.target()->name().empty()) 840 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, 841 ARM64_RELOC_UNSIGNED | rLength8); 842 else 843 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 844 ARM64_RELOC_UNSIGNED | rExtern | rLength8); 845 return; 846 case delta64: 847 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 848 ARM64_RELOC_SUBTRACTOR | rExtern | rLength8); 849 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 850 ARM64_RELOC_UNSIGNED | rExtern | rLength8); 851 return; 852 case delta32: 853 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, 854 ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 ); 855 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 856 ARM64_RELOC_UNSIGNED | rExtern | rLength4 ); 857 return; 858 case pointer64ToGOT: 859 assert(ref.addend() == 0); 860 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 861 ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8); 862 return; 863 case delta32ToGOT: 864 assert(ref.addend() == 0); 865 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, 866 ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4); 867 return; 868 case addOffset12: 869 llvm_unreachable("lazy reference kind implies GOT pass was run"); 870 case lazyPointer: 871 case lazyImmediateLocation: 872 llvm_unreachable("lazy reference kind implies Stubs pass was run"); 873 case imageOffset: 874 case imageOffsetGot: 875 llvm_unreachable("deltas from mach_header can only be in final images"); 876 case unwindCIEToPersonalityFunction: 877 case unwindFDEToFunction: 878 case unwindInfoToEhFrame: 879 case negDelta32: 880 // Do nothing. 881 return; 882 case invalid: 883 // Fall into llvm_unreachable(). 884 break; 885 } 886 llvm_unreachable("unknown arm64 Reference Kind"); 887 } 888 889 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() { 890 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64()); 891 } 892 893 } // namespace mach_o 894 } // namespace lld 895