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