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