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