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 if (&BlockToFix == &FromSymbol->getAddressable()) { 183 TargetSymbol = ToSymbol; 184 DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32; 185 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); 186 // FIXME: handle extern 'from'. 187 } else if (&BlockToFix == &ToSymbol->getAddressable()) { 188 TargetSymbol = FromSymbol; 189 DeltaKind = 190 (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32; 191 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); 192 } else { 193 // BlockToFix was neither FromSymbol nor ToSymbol. 194 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " 195 "either 'A' or 'B' (or a symbol in one " 196 "of their alt-entry chains)"); 197 } 198 199 return PairRelocInfo(DeltaKind, TargetSymbol, Addend); 200 } 201 202 Error addRelocations() override { 203 using namespace support; 204 auto &Obj = getObject(); 205 206 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 207 208 for (const auto &S : Obj.sections()) { 209 210 orc::ExecutorAddr SectionAddress(S.getAddress()); 211 212 // Skip relocations virtual sections. 213 if (S.isVirtual()) { 214 if (S.relocation_begin() != S.relocation_end()) 215 return make_error<JITLinkError>("Virtual section contains " 216 "relocations"); 217 continue; 218 } 219 220 auto NSec = 221 findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); 222 if (!NSec) 223 return NSec.takeError(); 224 225 // Skip relocations for MachO sections without corresponding graph 226 // sections. 227 { 228 if (!NSec->GraphSection) { 229 LLVM_DEBUG({ 230 dbgs() << " Skipping relocations for MachO section " 231 << NSec->SegName << "/" << NSec->SectName 232 << " which has no associated graph section\n"; 233 }); 234 continue; 235 } 236 } 237 238 // Add relocations for section. 239 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); 240 RelItr != RelEnd; ++RelItr) { 241 242 MachO::relocation_info RI = getRelocationInfo(RelItr); 243 244 // Find the address of the value to fix up. 245 auto FixupAddress = SectionAddress + (uint32_t)RI.r_address; 246 247 LLVM_DEBUG({ 248 dbgs() << " " << NSec->SectName << " + " 249 << formatv("{0:x8}", RI.r_address) << ":\n"; 250 }); 251 252 // Find the block that the fixup points to. 253 Block *BlockToFix = nullptr; 254 { 255 auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress); 256 if (!SymbolToFixOrErr) 257 return SymbolToFixOrErr.takeError(); 258 BlockToFix = &SymbolToFixOrErr->getBlock(); 259 } 260 261 if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) > 262 BlockToFix->getAddress() + BlockToFix->getContent().size()) 263 return make_error<JITLinkError>( 264 "Relocation extends past end of fixup block"); 265 266 // Get a pointer to the fixup content. 267 const char *FixupContent = BlockToFix->getContent().data() + 268 (FixupAddress - BlockToFix->getAddress()); 269 270 size_t FixupOffset = FixupAddress - BlockToFix->getAddress(); 271 272 // The target symbol and addend will be populated by the switch below. 273 Symbol *TargetSymbol = nullptr; 274 uint64_t Addend = 0; 275 276 // Validate the relocation kind. 277 auto MachORelocKind = getRelocKind(RI); 278 if (!MachORelocKind) 279 return MachORelocKind.takeError(); 280 281 Edge::Kind Kind = Edge::Invalid; 282 283 switch (*MachORelocKind) { 284 case MachOBranch32: 285 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 286 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 287 else 288 return TargetSymbolOrErr.takeError(); 289 Addend = *(const little32_t *)FixupContent; 290 Kind = x86_64::BranchPCRel32; 291 break; 292 case MachOPCRel32: 293 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 294 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 295 else 296 return TargetSymbolOrErr.takeError(); 297 Addend = *(const little32_t *)FixupContent - 4; 298 Kind = x86_64::Delta32; 299 break; 300 case MachOPCRel32GOTLoad: 301 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 302 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 303 else 304 return TargetSymbolOrErr.takeError(); 305 Addend = *(const little32_t *)FixupContent; 306 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable; 307 if (FixupOffset < 3) 308 return make_error<JITLinkError>("GOTLD at invalid offset " + 309 formatv("{0}", FixupOffset)); 310 break; 311 case MachOPCRel32GOT: 312 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 313 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 314 else 315 return TargetSymbolOrErr.takeError(); 316 Addend = *(const little32_t *)FixupContent - 4; 317 Kind = x86_64::RequestGOTAndTransformToDelta32; 318 break; 319 case MachOPCRel32TLV: 320 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 321 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 322 else 323 return TargetSymbolOrErr.takeError(); 324 Addend = *(const little32_t *)FixupContent; 325 Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable; 326 if (FixupOffset < 3) 327 return make_error<JITLinkError>("TLV at invalid offset " + 328 formatv("{0}", FixupOffset)); 329 break; 330 case MachOPointer32: 331 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 332 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 333 else 334 return TargetSymbolOrErr.takeError(); 335 Addend = *(const ulittle32_t *)FixupContent; 336 Kind = x86_64::Pointer32; 337 break; 338 case MachOPointer64: 339 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 340 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 341 else 342 return TargetSymbolOrErr.takeError(); 343 Addend = *(const ulittle64_t *)FixupContent; 344 Kind = x86_64::Pointer64; 345 break; 346 case MachOPointer64Anon: { 347 orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent); 348 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 349 if (!TargetNSec) 350 return TargetNSec.takeError(); 351 if (auto TargetSymbolOrErr = 352 findSymbolByAddress(*TargetNSec, TargetAddress)) 353 TargetSymbol = &*TargetSymbolOrErr; 354 else 355 return TargetSymbolOrErr.takeError(); 356 Addend = TargetAddress - TargetSymbol->getAddress(); 357 Kind = x86_64::Pointer64; 358 break; 359 } 360 case MachOPCRel32Minus1: 361 case MachOPCRel32Minus2: 362 case MachOPCRel32Minus4: 363 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) 364 TargetSymbol = TargetSymbolOrErr->GraphSymbol; 365 else 366 return TargetSymbolOrErr.takeError(); 367 Addend = *(const little32_t *)FixupContent - 4; 368 Kind = x86_64::Delta32; 369 break; 370 case MachOPCRel32Anon: { 371 orc::ExecutorAddr TargetAddress(FixupAddress + 4 + 372 *(const little32_t *)FixupContent); 373 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); 374 if (!TargetNSec) 375 return TargetNSec.takeError(); 376 if (auto TargetSymbolOrErr = 377 findSymbolByAddress(*TargetNSec, TargetAddress)) 378 TargetSymbol = &*TargetSymbolOrErr; 379 else 380 return TargetSymbolOrErr.takeError(); 381 Addend = TargetAddress - TargetSymbol->getAddress() - 4; 382 Kind = x86_64::Delta32; 383 break; 384 } 385 case MachOPCRel32Minus1Anon: 386 case MachOPCRel32Minus2Anon: 387 case MachOPCRel32Minus4Anon: { 388 orc::ExecutorAddrDiff Delta = 389 4 + orc::ExecutorAddrDiff( 390 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon)); 391 orc::ExecutorAddr TargetAddress = 392 FixupAddress + Delta + *(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() - Delta; 402 Kind = x86_64::Delta32; 403 break; 404 } 405 case MachOSubtractor32: 406 case MachOSubtractor64: { 407 // We use Delta32/Delta64 to represent SUBTRACTOR relocations. 408 // parsePairRelocation handles the paired reloc, and returns the 409 // edge kind to be used (either Delta32/Delta64, or 410 // NegDelta32/NegDelta64, depending on the direction of the 411 // subtraction) along with the addend. 412 auto PairInfo = 413 parsePairRelocation(*BlockToFix, *MachORelocKind, RI, 414 FixupAddress, FixupContent, ++RelItr, RelEnd); 415 if (!PairInfo) 416 return PairInfo.takeError(); 417 std::tie(Kind, TargetSymbol, Addend) = *PairInfo; 418 assert(TargetSymbol && "No target symbol from parsePairRelocation?"); 419 break; 420 } 421 } 422 423 LLVM_DEBUG({ 424 dbgs() << " "; 425 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, 426 Addend); 427 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); 428 dbgs() << "\n"; 429 }); 430 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), 431 *TargetSymbol, Addend); 432 } 433 } 434 return Error::success(); 435 } 436 }; 437 438 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) { 439 x86_64::GOTTableManager GOT; 440 x86_64::PLTTableManager PLT(GOT); 441 visitExistingEdges(G, GOT, PLT); 442 return Error::success(); 443 } 444 445 } // namespace 446 447 namespace llvm { 448 namespace jitlink { 449 450 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { 451 friend class JITLinker<MachOJITLinker_x86_64>; 452 453 public: 454 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, 455 std::unique_ptr<LinkGraph> G, 456 PassConfiguration PassConfig) 457 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 458 459 private: 460 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 461 return x86_64::applyFixup(G, B, E, nullptr); 462 } 463 }; 464 465 Expected<std::unique_ptr<LinkGraph>> 466 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) { 467 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); 468 if (!MachOObj) 469 return MachOObj.takeError(); 470 471 auto Features = (*MachOObj)->getFeatures(); 472 if (!Features) 473 return Features.takeError(); 474 475 return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features)) 476 .buildGraph(); 477 } 478 479 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, 480 std::unique_ptr<JITLinkContext> Ctx) { 481 482 PassConfiguration Config; 483 484 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 485 // Add eh-frame passses. 486 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64()); 487 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64()); 488 489 // Add compact unwind splitter pass. 490 Config.PrePrunePasses.push_back( 491 CompactUnwindSplitter("__LD,__compact_unwind")); 492 493 // Add a mark-live pass. 494 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 495 Config.PrePrunePasses.push_back(std::move(MarkLive)); 496 else 497 Config.PrePrunePasses.push_back(markAllSymbolsLive); 498 499 // Add an in-place GOT/Stubs pass. 500 Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64); 501 502 // Add GOT/Stubs optimizer pass. 503 Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses); 504 } 505 506 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 507 return Ctx->notifyFailed(std::move(Err)); 508 509 // Construct a JITLinker and run the link function. 510 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); 511 } 512 513 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() { 514 return DWARFRecordSectionSplitter("__TEXT,__eh_frame"); 515 } 516 517 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() { 518 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize, 519 x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32, 520 x86_64::Delta64, x86_64::NegDelta32); 521 } 522 523 } // end namespace jitlink 524 } // end namespace llvm 525