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