1 //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===// 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 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" 10 11 #include "llvm/BinaryFormat/MachO.h" 12 #include "llvm/ExecutionEngine/Orc/DebugUtils.h" 13 #include "llvm/Support/BinaryByteStream.h" 14 #include "llvm/Support/Debug.h" 15 16 #define DEBUG_TYPE "orc" 17 18 namespace { 19 20 struct objc_class; 21 struct objc_image_info; 22 struct objc_object; 23 struct objc_selector; 24 25 using Class = objc_class *; 26 using id = objc_object *; 27 using SEL = objc_selector *; 28 29 using ObjCMsgSendTy = id (*)(id, SEL, ...); 30 using ObjCReadClassPairTy = Class (*)(Class, const objc_image_info *); 31 using SelRegisterNameTy = SEL (*)(const char *); 32 33 enum class ObjCRegistrationAPI { Uninitialized, Unavailable, Initialized }; 34 35 ObjCRegistrationAPI ObjCRegistrationAPIState = 36 ObjCRegistrationAPI::Uninitialized; 37 ObjCMsgSendTy objc_msgSend = nullptr; 38 ObjCReadClassPairTy objc_readClassPair = nullptr; 39 SelRegisterNameTy sel_registerName = nullptr; 40 41 } // end anonymous namespace 42 43 namespace llvm { 44 namespace orc { 45 46 template <typename FnTy> 47 static Error setUpObjCRegAPIFunc(FnTy &Target, sys::DynamicLibrary &LibObjC, 48 const char *Name) { 49 if (void *Addr = LibObjC.getAddressOfSymbol(Name)) 50 Target = reinterpret_cast<FnTy>(Addr); 51 else 52 return make_error<StringError>( 53 (Twine("Could not find address for ") + Name).str(), 54 inconvertibleErrorCode()); 55 return Error::success(); 56 } 57 58 Error enableObjCRegistration(const char *PathToLibObjC) { 59 // If we've already tried to initialize then just bail out. 60 if (ObjCRegistrationAPIState != ObjCRegistrationAPI::Uninitialized) 61 return Error::success(); 62 63 ObjCRegistrationAPIState = ObjCRegistrationAPI::Unavailable; 64 65 std::string ErrMsg; 66 auto LibObjC = 67 sys::DynamicLibrary::getPermanentLibrary(PathToLibObjC, &ErrMsg); 68 69 if (!LibObjC.isValid()) 70 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); 71 72 if (auto Err = setUpObjCRegAPIFunc(objc_msgSend, LibObjC, "objc_msgSend")) 73 return Err; 74 if (auto Err = setUpObjCRegAPIFunc(objc_readClassPair, LibObjC, 75 "objc_readClassPair")) 76 return Err; 77 if (auto Err = 78 setUpObjCRegAPIFunc(sel_registerName, LibObjC, "sel_registerName")) 79 return Err; 80 81 ObjCRegistrationAPIState = ObjCRegistrationAPI::Initialized; 82 return Error::success(); 83 } 84 85 bool objCRegistrationEnabled() { 86 return ObjCRegistrationAPIState == ObjCRegistrationAPI::Initialized; 87 } 88 89 void MachOJITDylibInitializers::runModInits() const { 90 for (const auto &ModInit : ModInitSections) { 91 for (uint64_t I = 0; I != ModInit.NumPtrs; ++I) { 92 auto *InitializerAddr = jitTargetAddressToPointer<uintptr_t *>( 93 ModInit.Address + (I * sizeof(uintptr_t))); 94 auto *Initializer = 95 jitTargetAddressToFunction<void (*)()>(*InitializerAddr); 96 Initializer(); 97 } 98 } 99 } 100 101 void MachOJITDylibInitializers::registerObjCSelectors() const { 102 assert(objCRegistrationEnabled() && "ObjC registration not enabled."); 103 104 for (const auto &ObjCSelRefs : ObjCSelRefsSections) { 105 for (uint64_t I = 0; I != ObjCSelRefs.NumPtrs; ++I) { 106 auto SelEntryAddr = ObjCSelRefs.Address + (I * sizeof(uintptr_t)); 107 const auto *SelName = 108 *jitTargetAddressToPointer<const char **>(SelEntryAddr); 109 auto Sel = sel_registerName(SelName); 110 *jitTargetAddressToPointer<SEL *>(SelEntryAddr) = Sel; 111 } 112 } 113 } 114 115 Error MachOJITDylibInitializers::registerObjCClasses() const { 116 assert(objCRegistrationEnabled() && "ObjC registration not enabled."); 117 118 struct ObjCClassCompiled { 119 void *Metaclass; 120 void *Parent; 121 void *Cache1; 122 void *Cache2; 123 void *Data; 124 }; 125 126 auto *ImageInfo = 127 jitTargetAddressToPointer<const objc_image_info *>(ObjCImageInfoAddr); 128 auto ClassSelector = sel_registerName("class"); 129 130 for (const auto &ObjCClassList : ObjCClassListSections) { 131 for (uint64_t I = 0; I != ObjCClassList.NumPtrs; ++I) { 132 auto ClassPtrAddr = ObjCClassList.Address + (I * sizeof(uintptr_t)); 133 auto Cls = *jitTargetAddressToPointer<Class *>(ClassPtrAddr); 134 auto *ClassCompiled = 135 *jitTargetAddressToPointer<ObjCClassCompiled **>(ClassPtrAddr); 136 objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent), ClassSelector); 137 auto Registered = objc_readClassPair(Cls, ImageInfo); 138 139 // FIXME: Improve diagnostic by reporting the failed class's name. 140 if (Registered != Cls) 141 return make_error<StringError>("Unable to register Objective-C class", 142 inconvertibleErrorCode()); 143 } 144 } 145 return Error::success(); 146 } 147 148 MachOPlatform::MachOPlatform( 149 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 150 std::unique_ptr<MemoryBuffer> StandardSymbolsObject) 151 : ES(ES), ObjLinkingLayer(ObjLinkingLayer), 152 StandardSymbolsObject(std::move(StandardSymbolsObject)) { 153 ObjLinkingLayer.addPlugin(std::make_unique<InitScraperPlugin>(*this)); 154 } 155 156 Error MachOPlatform::setupJITDylib(JITDylib &JD) { 157 auto ObjBuffer = MemoryBuffer::getMemBuffer( 158 StandardSymbolsObject->getMemBufferRef(), false); 159 return ObjLinkingLayer.add(JD, std::move(ObjBuffer)); 160 } 161 162 Error MachOPlatform::notifyAdding(JITDylib &JD, const MaterializationUnit &MU) { 163 const auto &InitSym = MU.getInitializerSymbol(); 164 if (!InitSym) 165 return Error::success(); 166 167 RegisteredInitSymbols[&JD].add(InitSym, 168 SymbolLookupFlags::WeaklyReferencedSymbol); 169 LLVM_DEBUG({ 170 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU " 171 << MU.getName() << "\n"; 172 }); 173 return Error::success(); 174 } 175 176 Error MachOPlatform::notifyRemoving(JITDylib &JD, VModuleKey K) { 177 llvm_unreachable("Not supported yet"); 178 } 179 180 Expected<MachOPlatform::InitializerSequence> 181 MachOPlatform::getInitializerSequence(JITDylib &JD) { 182 183 LLVM_DEBUG({ 184 dbgs() << "MachOPlatform: Building initializer sequence for " 185 << JD.getName() << "\n"; 186 }); 187 188 std::vector<JITDylib *> DFSLinkOrder; 189 190 while (true) { 191 192 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; 193 194 ES.runSessionLocked([&]() { 195 DFSLinkOrder = getDFSLinkOrder(JD); 196 197 for (auto *InitJD : DFSLinkOrder) { 198 auto RISItr = RegisteredInitSymbols.find(InitJD); 199 if (RISItr != RegisteredInitSymbols.end()) { 200 NewInitSymbols[InitJD] = std::move(RISItr->second); 201 RegisteredInitSymbols.erase(RISItr); 202 } 203 } 204 }); 205 206 if (NewInitSymbols.empty()) 207 break; 208 209 LLVM_DEBUG({ 210 dbgs() << "MachOPlatform: Issuing lookups for new init symbols: " 211 "(lookup may require multiple rounds)\n"; 212 for (auto &KV : NewInitSymbols) 213 dbgs() << " \"" << KV.first->getName() << "\": " << KV.second << "\n"; 214 }); 215 216 // Outside the lock, issue the lookup. 217 if (auto R = lookupInitSymbols(JD.getExecutionSession(), NewInitSymbols)) 218 ; // Nothing to do in the success case. 219 else 220 return R.takeError(); 221 } 222 223 LLVM_DEBUG({ 224 dbgs() << "MachOPlatform: Init symbol lookup complete, building init " 225 "sequence\n"; 226 }); 227 228 // Lock again to collect the initializers. 229 InitializerSequence FullInitSeq; 230 { 231 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 232 for (auto *InitJD : reverse(DFSLinkOrder)) { 233 LLVM_DEBUG({ 234 dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName() 235 << "\" to sequence\n"; 236 }); 237 auto ISItr = InitSeqs.find(InitJD); 238 if (ISItr != InitSeqs.end()) { 239 FullInitSeq.emplace_back(InitJD, std::move(ISItr->second)); 240 InitSeqs.erase(ISItr); 241 } 242 } 243 } 244 245 return FullInitSeq; 246 } 247 248 Expected<MachOPlatform::DeinitializerSequence> 249 MachOPlatform::getDeinitializerSequence(JITDylib &JD) { 250 std::vector<JITDylib *> DFSLinkOrder = getDFSLinkOrder(JD); 251 252 DeinitializerSequence FullDeinitSeq; 253 { 254 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 255 for (auto *DeinitJD : DFSLinkOrder) { 256 FullDeinitSeq.emplace_back(DeinitJD, MachOJITDylibDeinitializers()); 257 } 258 } 259 260 return FullDeinitSeq; 261 } 262 263 std::vector<JITDylib *> MachOPlatform::getDFSLinkOrder(JITDylib &JD) { 264 std::vector<JITDylib *> Result, WorkStack({&JD}); 265 DenseSet<JITDylib *> Visited; 266 267 while (!WorkStack.empty()) { 268 auto *NextJD = WorkStack.back(); 269 WorkStack.pop_back(); 270 if (Visited.count(NextJD)) 271 continue; 272 Visited.insert(NextJD); 273 Result.push_back(NextJD); 274 NextJD->withLinkOrderDo([&](const JITDylibSearchOrder &LO) { 275 for (auto &KV : LO) 276 WorkStack.push_back(KV.first); 277 }); 278 } 279 280 return Result; 281 } 282 283 void MachOPlatform::registerInitInfo( 284 JITDylib &JD, JITTargetAddress ObjCImageInfoAddr, 285 MachOJITDylibInitializers::SectionExtent ModInits, 286 MachOJITDylibInitializers::SectionExtent ObjCSelRefs, 287 MachOJITDylibInitializers::SectionExtent ObjCClassList) { 288 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 289 290 auto &InitSeq = InitSeqs[&JD]; 291 292 InitSeq.setObjCImageInfoAddr(ObjCImageInfoAddr); 293 294 if (ModInits.Address) 295 InitSeq.addModInitsSection(std::move(ModInits)); 296 297 if (ObjCSelRefs.Address) 298 InitSeq.addObjCSelRefsSection(std::move(ObjCSelRefs)); 299 300 if (ObjCClassList.Address) 301 InitSeq.addObjCClassListSection(std::move(ObjCClassList)); 302 } 303 304 static Expected<MachOJITDylibInitializers::SectionExtent> 305 getSectionExtent(jitlink::LinkGraph &G, StringRef SectionName) { 306 auto *Sec = G.findSectionByName(SectionName); 307 if (!Sec) 308 return MachOJITDylibInitializers::SectionExtent(); 309 jitlink::SectionRange R(*Sec); 310 if (R.getSize() % G.getPointerSize() != 0) 311 return make_error<StringError>(SectionName + " section size is not a " 312 "multiple of the pointer size", 313 inconvertibleErrorCode()); 314 return MachOJITDylibInitializers::SectionExtent( 315 R.getStart(), R.getSize() / G.getPointerSize()); 316 } 317 318 void MachOPlatform::InitScraperPlugin::modifyPassConfig( 319 MaterializationResponsibility &MR, const Triple &TT, 320 jitlink::PassConfiguration &Config) { 321 322 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error { 323 JITLinkSymbolVector InitSectionSymbols; 324 preserveInitSectionIfPresent(InitSectionSymbols, G, "__mod_init_func"); 325 preserveInitSectionIfPresent(InitSectionSymbols, G, "__objc_selrefs"); 326 preserveInitSectionIfPresent(InitSectionSymbols, G, "__objc_classlist"); 327 328 if (!InitSymbolDeps.empty()) { 329 std::lock_guard<std::mutex> Lock(InitScraperMutex); 330 InitSymbolDeps[&MR] = std::move(InitSectionSymbols); 331 } 332 333 if (auto Err = processObjCImageInfo(G, MR)) 334 return Err; 335 336 return Error::success(); 337 }); 338 339 Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib()]( 340 jitlink::LinkGraph &G) -> Error { 341 MachOJITDylibInitializers::SectionExtent ModInits, ObjCSelRefs, 342 ObjCClassList; 343 344 JITTargetAddress ObjCImageInfoAddr = 0; 345 if (auto *ObjCImageInfoSec = G.findSectionByName("__objc_image_info")) { 346 if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) { 347 ObjCImageInfoAddr = Addr; 348 dbgs() << "Recorded __objc_imageinfo @ " << formatv("{0:x16}", Addr); 349 } 350 } 351 352 // Record __mod_init_func. 353 if (auto ModInitsOrErr = getSectionExtent(G, "__mod_init_func")) 354 ModInits = std::move(*ModInitsOrErr); 355 else 356 return ModInitsOrErr.takeError(); 357 358 // Record __objc_selrefs. 359 if (auto ObjCSelRefsOrErr = getSectionExtent(G, "__objc_selrefs")) 360 ObjCSelRefs = std::move(*ObjCSelRefsOrErr); 361 else 362 return ObjCSelRefsOrErr.takeError(); 363 364 // Record __objc_classlist. 365 if (auto ObjCClassListOrErr = getSectionExtent(G, "__objc_classlist")) 366 ObjCClassList = std::move(*ObjCClassListOrErr); 367 else 368 return ObjCClassListOrErr.takeError(); 369 370 // Dump the scraped inits. 371 LLVM_DEBUG({ 372 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; 373 dbgs() << " __objc_selrefs: "; 374 if (ObjCSelRefs.NumPtrs) 375 dbgs() << ObjCSelRefs.NumPtrs << " pointer(s) at " 376 << formatv("{0:x16}", ObjCSelRefs.Address) << "\n"; 377 else 378 dbgs() << "none\n"; 379 380 dbgs() << " __objc_classlist: "; 381 if (ObjCClassList.NumPtrs) 382 dbgs() << ObjCClassList.NumPtrs << " pointer(s) at " 383 << formatv("{0:x16}", ObjCClassList.Address) << "\n"; 384 else 385 dbgs() << "none\n"; 386 387 dbgs() << " __mod_init_func: "; 388 if (ModInits.NumPtrs) 389 dbgs() << ModInits.NumPtrs << " pointer(s) at " 390 << formatv("{0:x16}", ModInits.Address) << "\n"; 391 else 392 dbgs() << "none\n"; 393 }); 394 395 MP.registerInitInfo(JD, ObjCImageInfoAddr, std::move(ModInits), 396 std::move(ObjCSelRefs), std::move(ObjCClassList)); 397 398 return Error::success(); 399 }); 400 } 401 402 ObjectLinkingLayer::Plugin::LocalDependenciesMap 403 MachOPlatform::InitScraperPlugin::getSyntheticSymbolLocalDependencies( 404 MaterializationResponsibility &MR) { 405 std::lock_guard<std::mutex> Lock(InitScraperMutex); 406 auto I = InitSymbolDeps.find(&MR); 407 if (I != InitSymbolDeps.end()) { 408 LocalDependenciesMap Result; 409 Result[MR.getInitializerSymbol()] = std::move(I->second); 410 InitSymbolDeps.erase(&MR); 411 return Result; 412 } 413 return LocalDependenciesMap(); 414 } 415 416 void MachOPlatform::InitScraperPlugin::preserveInitSectionIfPresent( 417 JITLinkSymbolVector &Symbols, jitlink::LinkGraph &G, 418 StringRef SectionName) { 419 if (auto *Sec = G.findSectionByName(SectionName)) { 420 auto SecBlocks = Sec->blocks(); 421 if (!llvm::empty(SecBlocks)) 422 Symbols.push_back( 423 &G.addAnonymousSymbol(**SecBlocks.begin(), 0, 0, false, true)); 424 } 425 } 426 427 Error MachOPlatform::InitScraperPlugin::processObjCImageInfo( 428 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 429 430 // If there's an ObjC imagine info then either 431 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In 432 // this case we name and record it. 433 // OR 434 // (2) We already have a recorded __objc_imageinfo for this JITDylib, 435 // in which case we just verify it. 436 auto *ObjCImageInfo = G.findSectionByName("__objc_imageinfo"); 437 if (!ObjCImageInfo) 438 return Error::success(); 439 440 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); 441 442 // Check that the section is not empty if present. 443 if (llvm::empty(ObjCImageInfoBlocks)) 444 return make_error<StringError>("Empty __objc_imageinfo section in " + 445 G.getName(), 446 inconvertibleErrorCode()); 447 448 // Check that there's only one block in the section. 449 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) 450 return make_error<StringError>("Multiple blocks in __objc_imageinfo " 451 "section in " + 452 G.getName(), 453 inconvertibleErrorCode()); 454 455 // Check that the __objc_imageinfo section is unreferenced. 456 // FIXME: We could optimize this check if Symbols had a ref-count. 457 for (auto &Sec : G.sections()) { 458 if (&Sec != ObjCImageInfo) 459 for (auto *B : Sec.blocks()) 460 for (auto &E : B->edges()) 461 if (E.getTarget().isDefined() && 462 &E.getTarget().getBlock().getSection() == ObjCImageInfo) 463 return make_error<StringError>("__objc_imageinfo is referenced " 464 "within file " + 465 G.getName(), 466 inconvertibleErrorCode()); 467 } 468 469 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); 470 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); 471 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness()); 472 auto Flags = 473 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness()); 474 475 // Lock the mutex while we verify / update the ObjCImageInfos map. 476 std::lock_guard<std::mutex> Lock(InitScraperMutex); 477 478 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib()); 479 if (ObjCImageInfoItr != ObjCImageInfos.end()) { 480 // We've already registered an __objc_imageinfo section. Verify the 481 // content of this new section matches, then delete it. 482 if (ObjCImageInfoItr->second.first != Version) 483 return make_error<StringError>( 484 "ObjC version in " + G.getName() + 485 " does not match first registered version", 486 inconvertibleErrorCode()); 487 if (ObjCImageInfoItr->second.second != Flags) 488 return make_error<StringError>("ObjC flags in " + G.getName() + 489 " do not match first registered flags", 490 inconvertibleErrorCode()); 491 492 // __objc_imageinfo is valid. Delete the block. 493 for (auto *S : ObjCImageInfo->symbols()) 494 G.removeDefinedSymbol(*S); 495 G.removeBlock(ObjCImageInfoBlock); 496 } else { 497 // We haven't registered an __objc_imageinfo section yet. Register and 498 // move on. The section should already be marked no-dead-strip. 499 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags); 500 } 501 502 return Error::success(); 503 } 504 505 } // End namespace orc. 506 } // End namespace llvm. 507