1 //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // MachO/arm64 jit-link implementation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" 14 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 15 #include "llvm/ExecutionEngine/JITLink/aarch64.h" 16 17 #include "DefineExternalSectionStartAndEndSymbols.h" 18 #include "MachOLinkGraphBuilder.h" 19 20 #define DEBUG_TYPE "jitlink" 21 22 using namespace llvm; 23 using namespace llvm::jitlink; 24 25 namespace { 26 27 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder { 28 public: 29 MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj, 30 std::shared_ptr<orc::SymbolStringPool> SSP, 31 SubtargetFeatures Features) 32 : MachOLinkGraphBuilder(Obj, std::move(SSP), getObjectTriple(Obj), 33 std::move(Features), aarch64::getEdgeKindName), 34 NumSymbols(Obj.getSymtabLoadCommand().nsyms) {} 35 36 private: 37 enum MachOARM64RelocationKind : Edge::Kind { 38 MachOBranch26 = Edge::FirstRelocation, 39 MachOPointer32, 40 MachOPointer64, 41 MachOPointer64Anon, 42 MachOPointer64Authenticated, 43 MachOPage21, 44 MachOPageOffset12, 45 MachOGOTPage21, 46 MachOGOTPageOffset12, 47 MachOTLVPage21, 48 MachOTLVPageOffset12, 49 MachOPointerToGOT, 50 MachOPairedAddend, 51 MachOLDRLiteral19, 52 MachODelta32, 53 MachODelta64, 54 MachONegDelta32, 55 MachONegDelta64, 56 }; 57 58 static Triple getObjectTriple(const object::MachOObjectFile &Obj) { 59 // Get the CPU sub-type from the header. 60 // jitLink_MachO should already have validated that the buffer is big enough 61 // to cover a mach_header64 so this is safe. 62 uint32_t CPUSubType = 63 *(const support::ulittle32_t *)(Obj.getData().data() + 8); 64 CPUSubType &= ~MachO::CPU_SUBTYPE_MASK; 65 if (CPUSubType == MachO::CPU_SUBTYPE_ARM64E) 66 return Triple("arm64e-apple-darwin"); 67 return Triple("arm64-apple-darwin"); 68 } 69 70 static Expected<MachOARM64RelocationKind> 71 getRelocationKind(const MachO::relocation_info &RI) { 72 switch (RI.r_type) { 73 case MachO::ARM64_RELOC_UNSIGNED: 74 if (!RI.r_pcrel) { 75 if (RI.r_length == 3) 76 return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; 77 else if (RI.r_length == 2) 78 return MachOPointer32; 79 } 80 break; 81 case MachO::ARM64_RELOC_SUBTRACTOR: 82 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3. 83 // Initially represent SUBTRACTOR relocations with 'Delta<W>'. 84 // They may be turned into NegDelta<W> by parsePairRelocation. 85 if (!RI.r_pcrel && RI.r_extern) { 86 if (RI.r_length == 2) 87 return MachODelta32; 88 else if (RI.r_length == 3) 89 return MachODelta64; 90 } 91 break; 92 case MachO::ARM64_RELOC_BRANCH26: 93 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 94 return MachOBranch26; 95 break; 96 case MachO::ARM64_RELOC_PAGE21: 97 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 98 return MachOPage21; 99 break; 100 case MachO::ARM64_RELOC_PAGEOFF12: 101 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) 102 return MachOPageOffset12; 103 break; 104 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: 105 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 106 return MachOGOTPage21; 107 break; 108 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: 109 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) 110 return MachOGOTPageOffset12; 111 break; 112 case MachO::ARM64_RELOC_POINTER_TO_GOT: 113 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 114 return MachOPointerToGOT; 115 break; 116 case MachO::ARM64_RELOC_ADDEND: 117 if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2) 118 return MachOPairedAddend; 119 break; 120 case MachO::ARM64_RELOC_AUTHENTICATED_POINTER: 121 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 3) 122 return MachOPointer64Authenticated; 123 break; 124 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: 125 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 126 return MachOTLVPage21; 127 break; 128 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: 129 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) 130 return MachOTLVPageOffset12; 131 break; 132 } 133 134 return make_error<JITLinkError>( 135 "Unsupported arm64 relocation: address=" + 136 formatv("{0:x8}", RI.r_address) + 137 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) + 138 ", kind=" + formatv("{0:x1}", RI.r_type) + 139 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") + 140 ", extern=" + (RI.r_extern ? "true" : "false") + 141 ", length=" + formatv("{0:d}", RI.r_length)); 142 } 143 144 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; 145 146 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, 147 // returns the edge kind and addend to be used. 148 Expected<PairRelocInfo> 149 parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind, 150 const MachO::relocation_info &SubRI, 151 orc::ExecutorAddr FixupAddress, const char *FixupContent, 152 object::relocation_iterator &UnsignedRelItr, 153 object::relocation_iterator &RelEnd) { 154 using namespace support; 155 156 assert(((SubtractorKind == MachODelta32 && SubRI.r_length == 2) || 157 (SubtractorKind == MachODelta64 && SubRI.r_length == 3)) && 158 "Subtractor kind should match length"); 159 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); 160 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); 161 162 if (UnsignedRelItr == RelEnd) 163 return make_error<JITLinkError>("arm64 SUBTRACTOR without paired " 164 "UNSIGNED relocation"); 165 166 auto UnsignedRI = getRelocationInfo(UnsignedRelItr); 167 168 if (SubRI.r_address != UnsignedRI.r_address) 169 return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED " 170 "point to different addresses"); 171 172 if (SubRI.r_length != UnsignedRI.r_length) 173 return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired " 174 "UNSIGNED reloc must match"); 175 176 Symbol *FromSymbol; 177 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) 178 FromSymbol = FromSymbolOrErr->GraphSymbol; 179 else 180 return FromSymbolOrErr.takeError(); 181 182 // Read the current fixup value. 183 uint64_t FixupValue = 0; 184 if (SubRI.r_length == 3) 185 FixupValue = *(const little64_t *)FixupContent; 186 else 187 FixupValue = *(const little32_t *)FixupContent; 188 189 // Find 'ToSymbol' using symbol number or address, depending on whether the 190 // paired UNSIGNED relocation is extern. 191 Symbol *ToSymbol = nullptr; 192 if (UnsignedRI.r_extern) { 193 // Find target symbol by symbol index. 194 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) 195 ToSymbol = ToSymbolOrErr->GraphSymbol; 196 else 197 return ToSymbolOrErr.takeError(); 198 } else { 199 auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1); 200 if (!ToSymbolSec) 201 return ToSymbolSec.takeError(); 202 ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address); 203 assert(ToSymbol && "No symbol for section"); 204 FixupValue -= ToSymbol->getAddress().getValue(); 205 } 206 207 Edge::Kind DeltaKind; 208 Symbol *TargetSymbol; 209 uint64_t Addend; 210 211 bool FixingFromSymbol = true; 212 if (&BlockToFix == &FromSymbol->getAddressable()) { 213 if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) { 214 // From and To are symbols in the same block. Decide direction by offset 215 // instead. 216 if (ToSymbol->getAddress() > FixupAddress) 217 FixingFromSymbol = true; 218 else if (FromSymbol->getAddress() > FixupAddress) 219 FixingFromSymbol = false; 220 else 221 FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress(); 222 } else 223 FixingFromSymbol = true; 224 } else { 225 if (&BlockToFix == &ToSymbol->getAddressable()) 226 FixingFromSymbol = false; 227 else { 228 // BlockToFix was neither FromSymbol nor ToSymbol. 229 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 230 "either 'A' or 'B' (or a symbol in one " 231 "of their alt-entry groups)"); 232 } 233 } 234 235 if (FixingFromSymbol) { 236 TargetSymbol = ToSymbol; 237 DeltaKind = (SubRI.r_length == 3) ? aarch64::Delta64 : aarch64::Delta32; 238 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 239 // FIXME: handle extern 'from'. 240 } else { 241 TargetSymbol = &*FromSymbol; 242 DeltaKind = 243 (SubRI.r_length == 3) ? aarch64::NegDelta64 : aarch64::NegDelta32; 244 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 245 } 246 247 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 248 } 249 250 Error addRelocations() override { 251 using namespace support; 252 auto &Obj = getObject(); 253 254 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 255 256 for (auto &S : Obj.sections()) { 257 258 orc::ExecutorAddr SectionAddress(S.getAddress()); 259 260 // Skip relocations virtual sections. 261 if (S.isVirtual()) { 262 if (S.relocation_begin() != S.relocation_end()) 263 return make_error<JITLinkError>("Virtual section contains " 264 "relocations"); 265 continue; 266 } 267 268 auto NSec = 269 findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 270 if (!NSec) 271 return NSec.takeError(); 272 273 // Skip relocations for MachO sections without corresponding graph 274 // sections. 275 { 276 if (!NSec->GraphSection) { 277 LLVM_DEBUG({ 278 dbgs() << " Skipping relocations for MachO section " 279 << NSec->SegName << "/" << NSec->SectName 280 << " which has no associated graph section\n"; 281 }); 282 continue; 283 } 284 } 285 286 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 287 RelItr != RelEnd; ++RelItr) { 288 289 MachO::relocation_info RI = getRelocationInfo(RelItr); 290 291 // Validate the relocation kind. 292 auto MachORelocKind = getRelocationKind(RI); 293 if (!MachORelocKind) 294 return MachORelocKind.takeError(); 295 296 // Find the address of the value to fix up. 297 orc::ExecutorAddr FixupAddress = 298 SectionAddress + (uint32_t)RI.r_address; 299 LLVM_DEBUG({ 300 dbgs() << " " << NSec->SectName << " + " 301 << formatv("{0:x8}", RI.r_address) << ":\n"; 302 }); 303 304 // Find the block that the fixup points to. 305 Block *BlockToFix = nullptr; 306 { 307 auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress); 308 if (!SymbolToFixOrErr) 309 return SymbolToFixOrErr.takeError(); 310 BlockToFix = &SymbolToFixOrErr->getBlock(); 311 } 312 313 if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) > 314 BlockToFix->getAddress() + BlockToFix->getContent().size()) 315 return make_error<JITLinkError>( 316 "Relocation content extends past end of fixup block"); 317 318 Edge::Kind Kind = Edge::Invalid; 319 320 // Get a pointer to the fixup content. 321 const char *FixupContent = BlockToFix->getContent().data() + 322 (FixupAddress - BlockToFix->getAddress()); 323 324 // The target symbol and addend will be populated by the switch below. 325 Symbol *TargetSymbol = nullptr; 326 uint64_t Addend = 0; 327 328 if (*MachORelocKind == MachOPairedAddend) { 329 // If this is an Addend relocation then process it and move to the 330 // paired reloc. 331 332 Addend = SignExtend64(RI.r_symbolnum, 24); 333 334 ++RelItr; 335 if (RelItr == RelEnd) 336 return make_error<JITLinkError>("Unpaired Addend reloc at " + 337 formatv("{0:x16}", FixupAddress)); 338 RI = getRelocationInfo(RelItr); 339 340 MachORelocKind = getRelocationKind(RI); 341 if (!MachORelocKind) 342 return MachORelocKind.takeError(); 343 344 if (*MachORelocKind != MachOBranch26 && 345 *MachORelocKind != MachOPage21 && 346 *MachORelocKind != MachOPageOffset12) 347 return make_error<JITLinkError>( 348 "Invalid relocation pair: Addend + " + 349 StringRef(getMachOARM64RelocationKindName(*MachORelocKind))); 350 351 LLVM_DEBUG({ 352 dbgs() << " Addend: value = " << formatv("{0:x6}", Addend) 353 << ", pair is " 354 << getMachOARM64RelocationKindName(*MachORelocKind) << "\n"; 355 }); 356 357 // Find the address of the value to fix up. 358 orc::ExecutorAddr PairedFixupAddress = 359 SectionAddress + (uint32_t)RI.r_address; 360 if (PairedFixupAddress != FixupAddress) 361 return make_error<JITLinkError>("Paired relocation points at " 362 "different target"); 363 } 364 365 switch (*MachORelocKind) { 366 case MachOBranch26: { 367 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 368 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 369 else 370 return TargetSymbolOrErr.takeError(); 371 uint32_t Instr = *(const ulittle32_t *)FixupContent; 372 if ((Instr & 0x7fffffff) != 0x14000000) 373 return make_error<JITLinkError>("BRANCH26 target is not a B or BL " 374 "instruction with a zero addend"); 375 Kind = aarch64::Branch26PCRel; 376 break; 377 } 378 case MachOPointer32: 379 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 380 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 381 else 382 return TargetSymbolOrErr.takeError(); 383 Addend = *(const ulittle32_t *)FixupContent; 384 Kind = aarch64::Pointer32; 385 break; 386 case MachOPointer64: 387 case MachOPointer64Authenticated: 388 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 389 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 390 else 391 return TargetSymbolOrErr.takeError(); 392 Addend = *(const ulittle64_t *)FixupContent; 393 Kind = *MachORelocKind == MachOPointer64 394 ? aarch64::Pointer64 395 : aarch64::Pointer64Authenticated; 396 break; 397 case MachOPointer64Anon: { 398 orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent); 399 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 400 if (!TargetNSec) 401 return TargetNSec.takeError(); 402 if (auto TargetSymbolOrErr = 403 findSymbolByAddress(*TargetNSec, TargetAddress)) 404 TargetSymbol = &*TargetSymbolOrErr; 405 else 406 return TargetSymbolOrErr.takeError(); 407 Addend = TargetAddress - TargetSymbol->getAddress(); 408 Kind = aarch64::Pointer64; 409 break; 410 } 411 case MachOPage21: 412 case MachOGOTPage21: 413 case MachOTLVPage21: { 414 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 415 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 416 else 417 return TargetSymbolOrErr.takeError(); 418 uint32_t Instr = *(const ulittle32_t *)FixupContent; 419 if ((Instr & 0xffffffe0) != 0x90000000) 420 return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an " 421 "ADRP instruction with a zero " 422 "addend"); 423 424 if (*MachORelocKind == MachOPage21) { 425 Kind = aarch64::Page21; 426 } else if (*MachORelocKind == MachOGOTPage21) { 427 Kind = aarch64::RequestGOTAndTransformToPage21; 428 } else if (*MachORelocKind == MachOTLVPage21) { 429 Kind = aarch64::RequestTLVPAndTransformToPage21; 430 } 431 break; 432 } 433 case MachOPageOffset12: { 434 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 435 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 436 else 437 return TargetSymbolOrErr.takeError(); 438 uint32_t Instr = *(const ulittle32_t *)FixupContent; 439 uint32_t EncodedAddend = (Instr & 0x003FFC00) >> 10; 440 if (EncodedAddend != 0) 441 return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero " 442 "encoded addend"); 443 Kind = aarch64::PageOffset12; 444 break; 445 } 446 case MachOGOTPageOffset12: 447 case MachOTLVPageOffset12: { 448 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 449 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 450 else 451 return TargetSymbolOrErr.takeError(); 452 uint32_t Instr = *(const ulittle32_t *)FixupContent; 453 if ((Instr & 0xfffffc00) != 0xf9400000) 454 return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR " 455 "immediate instruction with a zero " 456 "addend"); 457 458 if (*MachORelocKind == MachOGOTPageOffset12) { 459 Kind = aarch64::RequestGOTAndTransformToPageOffset12; 460 } else if (*MachORelocKind == MachOTLVPageOffset12) { 461 Kind = aarch64::RequestTLVPAndTransformToPageOffset12; 462 } 463 break; 464 } 465 case MachOPointerToGOT: 466 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 467 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 468 else 469 return TargetSymbolOrErr.takeError(); 470 471 Kind = aarch64::RequestGOTAndTransformToDelta32; 472 break; 473 case MachODelta32: 474 case MachODelta64: { 475 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 476 // parsePairRelocation handles the paired reloc, and returns the 477 // edge kind to be used (either Delta32/Delta64, or 478 // NegDelta32/NegDelta64, depending on the direction of the 479 // subtraction) along with the addend. 480 auto PairInfo = 481 parsePairRelocation(*BlockToFix, *MachORelocKind, RI, 482 FixupAddress, FixupContent, ++RelItr, RelEnd); 483 if (!PairInfo) 484 return PairInfo.takeError(); 485 std::tie(Kind, TargetSymbol, Addend) = *PairInfo; 486 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 487 break; 488 } 489 default: 490 llvm_unreachable("Special relocation kind should not appear in " 491 "mach-o file"); 492 } 493 494 LLVM_DEBUG({ 495 dbgs() << " "; 496 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 497 Addend); 498 printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(Kind)); 499 dbgs() << "\n"; 500 }); 501 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), 502 *TargetSymbol, Addend); 503 } 504 } 505 return Error::success(); 506 } 507 508 /// Return the string name of the given MachO arm64 edge kind. 509 const char *getMachOARM64RelocationKindName(Edge::Kind R) { 510 switch (R) { 511 case MachOBranch26: 512 return "MachOBranch26"; 513 case MachOPointer64: 514 return "MachOPointer64"; 515 case MachOPointer64Anon: 516 return "MachOPointer64Anon"; 517 case MachOPointer64Authenticated: 518 return "MachOPointer64Authenticated"; 519 case MachOPage21: 520 return "MachOPage21"; 521 case MachOPageOffset12: 522 return "MachOPageOffset12"; 523 case MachOGOTPage21: 524 return "MachOGOTPage21"; 525 case MachOGOTPageOffset12: 526 return "MachOGOTPageOffset12"; 527 case MachOTLVPage21: 528 return "MachOTLVPage21"; 529 case MachOTLVPageOffset12: 530 return "MachOTLVPageOffset12"; 531 case MachOPointerToGOT: 532 return "MachOPointerToGOT"; 533 case MachOPairedAddend: 534 return "MachOPairedAddend"; 535 case MachOLDRLiteral19: 536 return "MachOLDRLiteral19"; 537 case MachODelta32: 538 return "MachODelta32"; 539 case MachODelta64: 540 return "MachODelta64"; 541 case MachONegDelta32: 542 return "MachONegDelta32"; 543 case MachONegDelta64: 544 return "MachONegDelta64"; 545 default: 546 return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); 547 } 548 } 549 550 unsigned NumSymbols = 0; 551 }; 552 553 } // namespace 554 555 namespace llvm { 556 namespace jitlink { 557 558 Error buildTables_MachO_arm64(LinkGraph &G) { 559 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); 560 561 aarch64::GOTTableManager GOT(G); 562 aarch64::PLTTableManager PLT(G, GOT); 563 visitExistingEdges(G, GOT, PLT); 564 return Error::success(); 565 } 566 567 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> { 568 friend class JITLinker<MachOJITLinker_arm64>; 569 570 public: 571 MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx, 572 std::unique_ptr<LinkGraph> G, 573 PassConfiguration PassConfig) 574 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 575 576 private: 577 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 578 return aarch64::applyFixup(G, B, E, nullptr); 579 } 580 581 uint64_t NullValue = 0; 582 }; 583 584 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromMachOObject_arm64( 585 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { 586 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); 587 if (!MachOObj) 588 return MachOObj.takeError(); 589 590 auto Features = (*MachOObj)->getFeatures(); 591 if (!Features) 592 return Features.takeError(); 593 594 return MachOLinkGraphBuilder_arm64(**MachOObj, std::move(SSP), 595 std::move(*Features)) 596 .buildGraph(); 597 } 598 599 static Error applyPACSigningToModInitPointers(LinkGraph &G) { 600 assert(G.getTargetTriple().getSubArch() == Triple::AArch64SubArch_arm64e && 601 "PAC signing only valid for arm64e"); 602 603 if (auto *ModInitSec = G.findSectionByName("__DATA,__mod_init_func")) { 604 for (auto *B : ModInitSec->blocks()) { 605 for (auto &E : B->edges()) { 606 if (E.getKind() == aarch64::Pointer64) { 607 608 // Check that we have room to encode pointer signing bits. 609 if (E.getAddend() >> 32) 610 return make_error<JITLinkError>( 611 "In " + G.getName() + ", __mod_init_func pointer at " + 612 formatv("{0:x}", B->getFixupAddress(E).getValue()) + 613 " has data in high bits of addend (addend >= 2^32)"); 614 615 // Change edge to Pointer64Authenticated, encode signing: 616 // key = asia, discriminator = 0, diversity = 0. 617 Edge::AddendT SigningBits = 0x1ULL << 63; 618 E.setKind(aarch64::Pointer64Authenticated); 619 E.setAddend(E.getAddend() | SigningBits); 620 } 621 } 622 } 623 } 624 625 return Error::success(); 626 } 627 628 void link_MachO_arm64(std::unique_ptr<LinkGraph> G, 629 std::unique_ptr<JITLinkContext> Ctx) { 630 631 PassConfiguration Config; 632 633 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 634 // Add a mark-live pass. 635 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 636 Config.PrePrunePasses.push_back(std::move(MarkLive)); 637 else 638 Config.PrePrunePasses.push_back(markAllSymbolsLive); 639 640 // Add compact unwind splitter pass. 641 Config.PrePrunePasses.push_back( 642 CompactUnwindSplitter("__LD,__compact_unwind")); 643 644 // Add eh-frame passes. 645 // FIXME: Prune eh-frames for which compact-unwind is available once 646 // we support compact-unwind registration with libunwind. 647 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64()); 648 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64()); 649 650 // Resolve any external section start / end symbols. 651 Config.PostAllocationPasses.push_back( 652 createDefineExternalSectionStartAndEndSymbolsPass( 653 identifyMachOSectionStartAndEndSymbols)); 654 655 // Add an in-place GOT/Stubs pass. 656 Config.PostPrunePasses.push_back(buildTables_MachO_arm64); 657 658 // If this is an arm64e graph then add pointer signing passes. 659 if (G->getTargetTriple().isArm64e()) { 660 Config.PostPrunePasses.push_back(applyPACSigningToModInitPointers); 661 Config.PostPrunePasses.push_back( 662 aarch64::createEmptyPointerSigningFunction); 663 Config.PreFixupPasses.push_back( 664 aarch64::lowerPointer64AuthEdgesToSigningFunction); 665 } 666 } 667 668 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 669 return Ctx->notifyFailed(std::move(Err)); 670 671 // Construct a JITLinker and run the link function. 672 MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config)); 673 } 674 675 LinkGraphPassFunction createEHFrameSplitterPass_MachO_arm64() { 676 return DWARFRecordSectionSplitter("__TEXT,__eh_frame"); 677 } 678 679 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_arm64() { 680 return EHFrameEdgeFixer("__TEXT,__eh_frame", aarch64::PointerSize, 681 aarch64::Pointer32, aarch64::Pointer64, 682 aarch64::Delta32, aarch64::Delta64, 683 aarch64::NegDelta32); 684 } 685 686 } // end namespace jitlink 687 } // end namespace llvm 688