1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===// 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/x86-64 jit-link implementation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" 14 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 15 #include "llvm/ExecutionEngine/JITLink/x86_64.h" 16 17 #include "MachOLinkGraphBuilder.h" 18 19 #define DEBUG_TYPE "jitlink" 20 21 using namespace llvm; 22 using namespace llvm::jitlink; 23 24 namespace { 25 26 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder { 27 public: 28 MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj, 29 SubtargetFeatures Features) 30 : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"), 31 std::move(Features), x86_64::getEdgeKindName) {} 32 33 private: 34 enum MachONormalizedRelocationType : unsigned { 35 MachOBranch32, 36 MachOPointer32, 37 MachOPointer64, 38 MachOPointer64Anon, 39 MachOPCRel32, 40 MachOPCRel32Minus1, 41 MachOPCRel32Minus2, 42 MachOPCRel32Minus4, 43 MachOPCRel32Anon, 44 MachOPCRel32Minus1Anon, 45 MachOPCRel32Minus2Anon, 46 MachOPCRel32Minus4Anon, 47 MachOPCRel32GOTLoad, 48 MachOPCRel32GOT, 49 MachOPCRel32TLV, 50 MachOSubtractor32, 51 MachOSubtractor64, 52 }; 53 54 static Expected<MachONormalizedRelocationType> 55 getRelocKind(const MachO::relocation_info &RI) { 56 switch (RI.r_type) { 57 case MachO::X86_64_RELOC_UNSIGNED: 58 if (!RI.r_pcrel) { 59 if (RI.r_length == 3) 60 return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; 61 else if (RI.r_extern && RI.r_length == 2) 62 return MachOPointer32; 63 } 64 break; 65 case MachO::X86_64_RELOC_SIGNED: 66 if (RI.r_pcrel && RI.r_length == 2) 67 return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon; 68 break; 69 case MachO::X86_64_RELOC_BRANCH: 70 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 71 return MachOBranch32; 72 break; 73 case MachO::X86_64_RELOC_GOT_LOAD: 74 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 75 return MachOPCRel32GOTLoad; 76 break; 77 case MachO::X86_64_RELOC_GOT: 78 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 79 return MachOPCRel32GOT; 80 break; 81 case MachO::X86_64_RELOC_SUBTRACTOR: 82 if (!RI.r_pcrel && RI.r_extern) { 83 if (RI.r_length == 2) 84 return MachOSubtractor32; 85 else if (RI.r_length == 3) 86 return MachOSubtractor64; 87 } 88 break; 89 case MachO::X86_64_RELOC_SIGNED_1: 90 if (RI.r_pcrel && RI.r_length == 2) 91 return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon; 92 break; 93 case MachO::X86_64_RELOC_SIGNED_2: 94 if (RI.r_pcrel && RI.r_length == 2) 95 return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon; 96 break; 97 case MachO::X86_64_RELOC_SIGNED_4: 98 if (RI.r_pcrel && RI.r_length == 2) 99 return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon; 100 break; 101 case MachO::X86_64_RELOC_TLV: 102 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) 103 return MachOPCRel32TLV; 104 break; 105 } 106 107 return make_error<JITLinkError>( 108 "Unsupported x86-64 relocation: address=" + 109 formatv("{0:x8}", RI.r_address) + 110 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) + 111 ", kind=" + formatv("{0:x1}", RI.r_type) + 112 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") + 113 ", extern=" + (RI.r_extern ? "true" : "false") + 114 ", length=" + formatv("{0:d}", RI.r_length)); 115 } 116 117 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; 118 119 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, 120 // returns the edge kind and addend to be used. 121 Expected<PairRelocInfo> parsePairRelocation( 122 Block &BlockToFix, MachONormalizedRelocationType SubtractorKind, 123 const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress, 124 const char *FixupContent, object::relocation_iterator &UnsignedRelItr, 125 object::relocation_iterator &RelEnd) { 126 using namespace support; 127 128 assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) || 129 (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) && 130 "Subtractor kind should match length"); 131 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); 132 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); 133 134 if (UnsignedRelItr == RelEnd) 135 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired " 136 "UNSIGNED relocation"); 137 138 auto UnsignedRI = getRelocationInfo(UnsignedRelItr); 139 140 if (SubRI.r_address != UnsignedRI.r_address) 141 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED " 142 "point to different addresses"); 143 144 if (SubRI.r_length != UnsignedRI.r_length) 145 return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired " 146 "UNSIGNED reloc must match"); 147 148 Symbol *FromSymbol; 149 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) 150 FromSymbol = FromSymbolOrErr->GraphSymbol; 151 else 152 return FromSymbolOrErr.takeError(); 153 154 // Read the current fixup value. 155 uint64_t FixupValue = 0; 156 if (SubRI.r_length == 3) 157 FixupValue = *(const little64_t *)FixupContent; 158 else 159 FixupValue = *(const little32_t *)FixupContent; 160 161 // Find 'ToSymbol' using symbol number or address, depending on whether the 162 // paired UNSIGNED relocation is extern. 163 Symbol *ToSymbol = nullptr; 164 if (UnsignedRI.r_extern) { 165 // Find target symbol by symbol index. 166 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) 167 ToSymbol = ToSymbolOrErr->GraphSymbol; 168 else 169 return ToSymbolOrErr.takeError(); 170 } else { 171 auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1); 172 if (!ToSymbolSec) 173 return ToSymbolSec.takeError(); 174 ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address); 175 assert(ToSymbol && "No symbol for section"); 176 FixupValue -= ToSymbol->getAddress().getValue(); 177 } 178 179 Edge::Kind DeltaKind; 180 Symbol *TargetSymbol; 181 uint64_t Addend; 182 183 bool FixingFromSymbol = true; 184 if (&BlockToFix == &FromSymbol->getAddressable()) { 185 if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) { 186 // From and To are symbols in the same block. Decide direction by offset 187 // instead. 188 if (ToSymbol->getAddress() > FixupAddress) 189 FixingFromSymbol = true; 190 else if (FromSymbol->getAddress() > FixupAddress) 191 FixingFromSymbol = false; 192 else 193 FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress(); 194 } else 195 FixingFromSymbol = true; 196 } else { 197 if (&BlockToFix == &ToSymbol->getAddressable()) 198 FixingFromSymbol = false; 199 else { 200 // BlockToFix was neither FromSymbol nor ToSymbol. 201 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 202 "either 'A' or 'B' (or a symbol in one " 203 "of their alt-entry groups)"); 204 } 205 } 206 207 if (FixingFromSymbol) { 208 TargetSymbol = ToSymbol; 209 DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32; 210 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 211 // FIXME: handle extern 'from'. 212 } else { 213 TargetSymbol = FromSymbol; 214 DeltaKind = 215 (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32; 216 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 217 } 218 219 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 220 } 221 222 Error addRelocations() override { 223 using namespace support; 224 auto &Obj = getObject(); 225 226 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 227 228 for (const auto &S : Obj.sections()) { 229 230 orc::ExecutorAddr SectionAddress(S.getAddress()); 231 232 // Skip relocations virtual sections. 233 if (S.isVirtual()) { 234 if (S.relocation_begin() != S.relocation_end()) 235 return make_error<JITLinkError>("Virtual section contains " 236 "relocations"); 237 continue; 238 } 239 240 auto NSec = 241 findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 242 if (!NSec) 243 return NSec.takeError(); 244 245 // Skip relocations for MachO sections without corresponding graph 246 // sections. 247 { 248 if (!NSec->GraphSection) { 249 LLVM_DEBUG({ 250 dbgs() << " Skipping relocations for MachO section " 251 << NSec->SegName << "/" << NSec->SectName 252 << " which has no associated graph section\n"; 253 }); 254 continue; 255 } 256 } 257 258 // Add relocations for section. 259 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 260 RelItr != RelEnd; ++RelItr) { 261 262 MachO::relocation_info RI = getRelocationInfo(RelItr); 263 264 // Find the address of the value to fix up. 265 auto FixupAddress = SectionAddress + (uint32_t)RI.r_address; 266 267 LLVM_DEBUG({ 268 dbgs() << " " << NSec->SectName << " + " 269 << formatv("{0:x8}", RI.r_address) << ":\n"; 270 }); 271 272 // Find the block that the fixup points to. 273 Block *BlockToFix = nullptr; 274 { 275 auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress); 276 if (!SymbolToFixOrErr) 277 return SymbolToFixOrErr.takeError(); 278 BlockToFix = &SymbolToFixOrErr->getBlock(); 279 } 280 281 if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) > 282 BlockToFix->getAddress() + BlockToFix->getContent().size()) 283 return make_error<JITLinkError>( 284 "Relocation extends past end of fixup block"); 285 286 // Get a pointer to the fixup content. 287 const char *FixupContent = BlockToFix->getContent().data() + 288 (FixupAddress - BlockToFix->getAddress()); 289 290 size_t FixupOffset = FixupAddress - BlockToFix->getAddress(); 291 292 // The target symbol and addend will be populated by the switch below. 293 Symbol *TargetSymbol = nullptr; 294 uint64_t Addend = 0; 295 296 // Validate the relocation kind. 297 auto MachORelocKind = getRelocKind(RI); 298 if (!MachORelocKind) 299 return MachORelocKind.takeError(); 300 301 Edge::Kind Kind = Edge::Invalid; 302 303 switch (*MachORelocKind) { 304 case MachOBranch32: 305 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 306 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 307 else 308 return TargetSymbolOrErr.takeError(); 309 Addend = *(const little32_t *)FixupContent; 310 Kind = x86_64::BranchPCRel32; 311 break; 312 case MachOPCRel32: 313 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 314 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 315 else 316 return TargetSymbolOrErr.takeError(); 317 Addend = *(const little32_t *)FixupContent - 4; 318 Kind = x86_64::Delta32; 319 break; 320 case MachOPCRel32GOTLoad: 321 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 322 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 323 else 324 return TargetSymbolOrErr.takeError(); 325 Addend = *(const little32_t *)FixupContent; 326 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable; 327 if (FixupOffset < 3) 328 return make_error<JITLinkError>("GOTLD at invalid offset " + 329 formatv("{0}", FixupOffset)); 330 break; 331 case MachOPCRel32GOT: 332 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 333 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 334 else 335 return TargetSymbolOrErr.takeError(); 336 Addend = *(const little32_t *)FixupContent - 4; 337 Kind = x86_64::RequestGOTAndTransformToDelta32; 338 break; 339 case MachOPCRel32TLV: 340 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 341 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 342 else 343 return TargetSymbolOrErr.takeError(); 344 Addend = *(const little32_t *)FixupContent; 345 Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable; 346 if (FixupOffset < 3) 347 return make_error<JITLinkError>("TLV at invalid offset " + 348 formatv("{0}", FixupOffset)); 349 break; 350 case MachOPointer32: 351 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 352 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 353 else 354 return TargetSymbolOrErr.takeError(); 355 Addend = *(const ulittle32_t *)FixupContent; 356 Kind = x86_64::Pointer32; 357 break; 358 case MachOPointer64: 359 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 360 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 361 else 362 return TargetSymbolOrErr.takeError(); 363 Addend = *(const ulittle64_t *)FixupContent; 364 Kind = x86_64::Pointer64; 365 break; 366 case MachOPointer64Anon: { 367 orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent); 368 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 369 if (!TargetNSec) 370 return TargetNSec.takeError(); 371 if (auto TargetSymbolOrErr = 372 findSymbolByAddress(*TargetNSec, TargetAddress)) 373 TargetSymbol = &*TargetSymbolOrErr; 374 else 375 return TargetSymbolOrErr.takeError(); 376 Addend = TargetAddress - TargetSymbol->getAddress(); 377 Kind = x86_64::Pointer64; 378 break; 379 } 380 case MachOPCRel32Minus1: 381 case MachOPCRel32Minus2: 382 case MachOPCRel32Minus4: 383 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 384 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 385 else 386 return TargetSymbolOrErr.takeError(); 387 Addend = *(const little32_t *)FixupContent - 4; 388 Kind = x86_64::Delta32; 389 break; 390 case MachOPCRel32Anon: { 391 orc::ExecutorAddr TargetAddress(FixupAddress + 4 + 392 *(const little32_t *)FixupContent); 393 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 394 if (!TargetNSec) 395 return TargetNSec.takeError(); 396 if (auto TargetSymbolOrErr = 397 findSymbolByAddress(*TargetNSec, TargetAddress)) 398 TargetSymbol = &*TargetSymbolOrErr; 399 else 400 return TargetSymbolOrErr.takeError(); 401 Addend = TargetAddress - TargetSymbol->getAddress() - 4; 402 Kind = x86_64::Delta32; 403 break; 404 } 405 case MachOPCRel32Minus1Anon: 406 case MachOPCRel32Minus2Anon: 407 case MachOPCRel32Minus4Anon: { 408 orc::ExecutorAddrDiff Delta = 409 4 + orc::ExecutorAddrDiff( 410 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon)); 411 orc::ExecutorAddr TargetAddress = 412 FixupAddress + Delta + *(const little32_t *)FixupContent; 413 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 414 if (!TargetNSec) 415 return TargetNSec.takeError(); 416 if (auto TargetSymbolOrErr = 417 findSymbolByAddress(*TargetNSec, TargetAddress)) 418 TargetSymbol = &*TargetSymbolOrErr; 419 else 420 return TargetSymbolOrErr.takeError(); 421 Addend = TargetAddress - TargetSymbol->getAddress() - Delta; 422 Kind = x86_64::Delta32; 423 break; 424 } 425 case MachOSubtractor32: 426 case MachOSubtractor64: { 427 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 428 // parsePairRelocation handles the paired reloc, and returns the 429 // edge kind to be used (either Delta32/Delta64, or 430 // NegDelta32/NegDelta64, depending on the direction of the 431 // subtraction) along with the addend. 432 auto PairInfo = 433 parsePairRelocation(*BlockToFix, *MachORelocKind, RI, 434 FixupAddress, FixupContent, ++RelItr, RelEnd); 435 if (!PairInfo) 436 return PairInfo.takeError(); 437 std::tie(Kind, TargetSymbol, Addend) = *PairInfo; 438 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 439 break; 440 } 441 } 442 443 LLVM_DEBUG({ 444 dbgs() << " "; 445 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 446 Addend); 447 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); 448 dbgs() << "\n"; 449 }); 450 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), 451 *TargetSymbol, Addend); 452 } 453 } 454 return Error::success(); 455 } 456 }; 457 458 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) { 459 x86_64::GOTTableManager GOT; 460 x86_64::PLTTableManager PLT(GOT); 461 visitExistingEdges(G, GOT, PLT); 462 return Error::success(); 463 } 464 465 } // namespace 466 467 namespace llvm { 468 namespace jitlink { 469 470 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { 471 friend class JITLinker<MachOJITLinker_x86_64>; 472 473 public: 474 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 475 std::unique_ptr<LinkGraph> G, 476 PassConfiguration PassConfig) 477 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 478 479 private: 480 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 481 return x86_64::applyFixup(G, B, E, nullptr); 482 } 483 }; 484 485 Expected<std::unique_ptr<LinkGraph>> 486 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) { 487 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); 488 if (!MachOObj) 489 return MachOObj.takeError(); 490 491 auto Features = (*MachOObj)->getFeatures(); 492 if (!Features) 493 return Features.takeError(); 494 495 return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features)) 496 .buildGraph(); 497 } 498 499 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, 500 std::unique_ptr<JITLinkContext> Ctx) { 501 502 PassConfiguration Config; 503 504 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 505 // Add eh-frame passes. 506 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64()); 507 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64()); 508 509 // Add compact unwind splitter pass. 510 Config.PrePrunePasses.push_back( 511 CompactUnwindSplitter("__LD,__compact_unwind")); 512 513 // Add a mark-live pass. 514 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 515 Config.PrePrunePasses.push_back(std::move(MarkLive)); 516 else 517 Config.PrePrunePasses.push_back(markAllSymbolsLive); 518 519 // Add an in-place GOT/Stubs pass. 520 Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64); 521 522 // Add GOT/Stubs optimizer pass. 523 Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses); 524 } 525 526 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 527 return Ctx->notifyFailed(std::move(Err)); 528 529 // Construct a JITLinker and run the link function. 530 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 531 } 532 533 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() { 534 return DWARFRecordSectionSplitter("__TEXT,__eh_frame"); 535 } 536 537 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() { 538 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize, 539 x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32, 540 x86_64::Delta64, x86_64::NegDelta32); 541 } 542 543 } // end namespace jitlink 544 } // end namespace llvm 545