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