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