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 llvm { 19 namespace orc { 20 21 MachOPlatform::MachOPlatform( 22 ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, 23 std::unique_ptr<MemoryBuffer> StandardSymbolsObject) 24 : ES(ES), ObjLinkingLayer(ObjLinkingLayer), 25 StandardSymbolsObject(std::move(StandardSymbolsObject)) { 26 ObjLinkingLayer.addPlugin(std::make_unique<InitScraperPlugin>(*this)); 27 } 28 29 Error MachOPlatform::setupJITDylib(JITDylib &JD) { 30 auto ObjBuffer = MemoryBuffer::getMemBuffer( 31 StandardSymbolsObject->getMemBufferRef(), false); 32 return ObjLinkingLayer.add(JD, std::move(ObjBuffer)); 33 } 34 35 Error MachOPlatform::notifyAdding(ResourceTracker &RT, 36 const MaterializationUnit &MU) { 37 auto &JD = RT.getJITDylib(); 38 const auto &InitSym = MU.getInitializerSymbol(); 39 if (!InitSym) 40 return Error::success(); 41 42 RegisteredInitSymbols[&JD].add(InitSym, 43 SymbolLookupFlags::WeaklyReferencedSymbol); 44 LLVM_DEBUG({ 45 dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU " 46 << MU.getName() << "\n"; 47 }); 48 return Error::success(); 49 } 50 51 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) { 52 llvm_unreachable("Not supported yet"); 53 } 54 55 Expected<MachOPlatform::InitializerSequence> 56 MachOPlatform::getInitializerSequence(JITDylib &JD) { 57 58 LLVM_DEBUG({ 59 dbgs() << "MachOPlatform: Building initializer sequence for " 60 << JD.getName() << "\n"; 61 }); 62 63 std::vector<JITDylibSP> DFSLinkOrder; 64 65 while (true) { 66 67 DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; 68 69 ES.runSessionLocked([&]() { 70 DFSLinkOrder = JD.getDFSLinkOrder(); 71 72 for (auto &InitJD : DFSLinkOrder) { 73 auto RISItr = RegisteredInitSymbols.find(InitJD.get()); 74 if (RISItr != RegisteredInitSymbols.end()) { 75 NewInitSymbols[InitJD.get()] = std::move(RISItr->second); 76 RegisteredInitSymbols.erase(RISItr); 77 } 78 } 79 }); 80 81 if (NewInitSymbols.empty()) 82 break; 83 84 LLVM_DEBUG({ 85 dbgs() << "MachOPlatform: Issuing lookups for new init symbols: " 86 "(lookup may require multiple rounds)\n"; 87 for (auto &KV : NewInitSymbols) 88 dbgs() << " \"" << KV.first->getName() << "\": " << KV.second << "\n"; 89 }); 90 91 // Outside the lock, issue the lookup. 92 if (auto R = lookupInitSymbols(JD.getExecutionSession(), NewInitSymbols)) 93 ; // Nothing to do in the success case. 94 else 95 return R.takeError(); 96 } 97 98 LLVM_DEBUG({ 99 dbgs() << "MachOPlatform: Init symbol lookup complete, building init " 100 "sequence\n"; 101 }); 102 103 // Lock again to collect the initializers. 104 InitializerSequence FullInitSeq; 105 { 106 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 107 for (auto &InitJD : reverse(DFSLinkOrder)) { 108 LLVM_DEBUG({ 109 dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName() 110 << "\" to sequence\n"; 111 }); 112 auto ISItr = InitSeqs.find(InitJD.get()); 113 if (ISItr != InitSeqs.end()) { 114 FullInitSeq.emplace_back(InitJD.get(), std::move(ISItr->second)); 115 InitSeqs.erase(ISItr); 116 } 117 } 118 } 119 120 return FullInitSeq; 121 } 122 123 Expected<MachOPlatform::DeinitializerSequence> 124 MachOPlatform::getDeinitializerSequence(JITDylib &JD) { 125 std::vector<JITDylibSP> DFSLinkOrder = JD.getDFSLinkOrder(); 126 127 DeinitializerSequence FullDeinitSeq; 128 { 129 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 130 for (auto &DeinitJD : DFSLinkOrder) { 131 FullDeinitSeq.emplace_back(DeinitJD.get(), MachOJITDylibDeinitializers()); 132 } 133 } 134 135 return FullDeinitSeq; 136 } 137 138 void MachOPlatform::registerInitInfo(JITDylib &JD, 139 JITTargetAddress ObjCImageInfoAddr, 140 ExecutorAddressRange ModInits, 141 ExecutorAddressRange ObjCSelRefs, 142 ExecutorAddressRange ObjCClassList) { 143 std::lock_guard<std::mutex> Lock(InitSeqsMutex); 144 145 auto &InitSeq = InitSeqs[&JD]; 146 147 InitSeq.setObjCImageInfoAddr(ObjCImageInfoAddr); 148 149 if (ModInits.StartAddress) 150 InitSeq.addModInitsSection(std::move(ModInits)); 151 152 if (ObjCSelRefs.StartAddress) 153 InitSeq.addObjCSelRefsSection(std::move(ObjCSelRefs)); 154 155 if (ObjCClassList.StartAddress) 156 InitSeq.addObjCClassListSection(std::move(ObjCClassList)); 157 } 158 159 static Expected<ExecutorAddressRange> getSectionExtent(jitlink::LinkGraph &G, 160 StringRef SectionName) { 161 auto *Sec = G.findSectionByName(SectionName); 162 if (!Sec) 163 return ExecutorAddressRange(); 164 jitlink::SectionRange R(*Sec); 165 if (R.getSize() % G.getPointerSize() != 0) 166 return make_error<StringError>(SectionName + " section size is not a " 167 "multiple of the pointer size", 168 inconvertibleErrorCode()); 169 return ExecutorAddressRange(ExecutorAddress(R.getStart()), 170 ExecutorAddress(R.getEnd())); 171 } 172 173 void MachOPlatform::InitScraperPlugin::modifyPassConfig( 174 MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 175 jitlink::PassConfiguration &Config) { 176 177 if (!MR.getInitializerSymbol()) 178 return; 179 180 Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error { 181 JITLinkSymbolSet InitSectionSyms; 182 preserveInitSectionIfPresent(InitSectionSyms, G, "__DATA,__mod_init_func"); 183 preserveInitSectionIfPresent(InitSectionSyms, G, "__DATA,__objc_selrefs"); 184 preserveInitSectionIfPresent(InitSectionSyms, G, "__DATA,__objc_classlist"); 185 186 if (!InitSectionSyms.empty()) { 187 std::lock_guard<std::mutex> Lock(InitScraperMutex); 188 InitSymbolDeps[&MR] = std::move(InitSectionSyms); 189 } 190 191 if (auto Err = processObjCImageInfo(G, MR)) 192 return Err; 193 194 return Error::success(); 195 }); 196 197 Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib()]( 198 jitlink::LinkGraph &G) -> Error { 199 ExecutorAddressRange ModInits, ObjCSelRefs, ObjCClassList; 200 201 JITTargetAddress ObjCImageInfoAddr = 0; 202 if (auto *ObjCImageInfoSec = 203 G.findSectionByName("__DATA,__objc_image_info")) { 204 if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) 205 ObjCImageInfoAddr = Addr; 206 } 207 208 // Record __mod_init_func. 209 if (auto ModInitsOrErr = getSectionExtent(G, "__DATA,__mod_init_func")) 210 ModInits = std::move(*ModInitsOrErr); 211 else 212 return ModInitsOrErr.takeError(); 213 214 // Record __objc_selrefs. 215 if (auto ObjCSelRefsOrErr = getSectionExtent(G, "__DATA,__objc_selrefs")) 216 ObjCSelRefs = std::move(*ObjCSelRefsOrErr); 217 else 218 return ObjCSelRefsOrErr.takeError(); 219 220 // Record __objc_classlist. 221 if (auto ObjCClassListOrErr = 222 getSectionExtent(G, "__DATA,__objc_classlist")) 223 ObjCClassList = std::move(*ObjCClassListOrErr); 224 else 225 return ObjCClassListOrErr.takeError(); 226 227 // Dump the scraped inits. 228 LLVM_DEBUG({ 229 dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; 230 dbgs() << " __objc_selrefs: "; 231 auto NumObjCSelRefs = ObjCSelRefs.size().getValue() / sizeof(uintptr_t); 232 if (NumObjCSelRefs) 233 dbgs() << NumObjCSelRefs << " pointer(s) at " 234 << formatv("{0:x16}", ObjCSelRefs.StartAddress.getValue()) 235 << "\n"; 236 else 237 dbgs() << "none\n"; 238 239 dbgs() << " __objc_classlist: "; 240 auto NumObjCClasses = ObjCClassList.size().getValue() / sizeof(uintptr_t); 241 if (NumObjCClasses) 242 dbgs() << NumObjCClasses << " pointer(s) at " 243 << formatv("{0:x16}", ObjCClassList.StartAddress.getValue()) 244 << "\n"; 245 else 246 dbgs() << "none\n"; 247 248 dbgs() << " __mod_init_func: "; 249 auto NumModInits = ModInits.size().getValue() / sizeof(uintptr_t); 250 if (NumModInits) 251 dbgs() << NumModInits << " pointer(s) at " 252 << formatv("{0:x16}", ModInits.StartAddress.getValue()) << "\n"; 253 else 254 dbgs() << "none\n"; 255 }); 256 257 MP.registerInitInfo(JD, ObjCImageInfoAddr, std::move(ModInits), 258 std::move(ObjCSelRefs), std::move(ObjCClassList)); 259 260 return Error::success(); 261 }); 262 } 263 264 ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap 265 MachOPlatform::InitScraperPlugin::getSyntheticSymbolDependencies( 266 MaterializationResponsibility &MR) { 267 std::lock_guard<std::mutex> Lock(InitScraperMutex); 268 auto I = InitSymbolDeps.find(&MR); 269 if (I != InitSymbolDeps.end()) { 270 SyntheticSymbolDependenciesMap Result; 271 Result[MR.getInitializerSymbol()] = std::move(I->second); 272 InitSymbolDeps.erase(&MR); 273 return Result; 274 } 275 return SyntheticSymbolDependenciesMap(); 276 } 277 278 void MachOPlatform::InitScraperPlugin::preserveInitSectionIfPresent( 279 JITLinkSymbolSet &Symbols, jitlink::LinkGraph &G, StringRef SectionName) { 280 if (auto *Sec = G.findSectionByName(SectionName)) { 281 auto SecBlocks = Sec->blocks(); 282 if (!llvm::empty(SecBlocks)) 283 Symbols.insert( 284 &G.addAnonymousSymbol(**SecBlocks.begin(), 0, 0, false, true)); 285 } 286 } 287 288 Error MachOPlatform::InitScraperPlugin::processObjCImageInfo( 289 jitlink::LinkGraph &G, MaterializationResponsibility &MR) { 290 291 // If there's an ObjC imagine info then either 292 // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In 293 // this case we name and record it. 294 // OR 295 // (2) We already have a recorded __objc_imageinfo for this JITDylib, 296 // in which case we just verify it. 297 auto *ObjCImageInfo = G.findSectionByName("__objc_imageinfo"); 298 if (!ObjCImageInfo) 299 return Error::success(); 300 301 auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); 302 303 // Check that the section is not empty if present. 304 if (llvm::empty(ObjCImageInfoBlocks)) 305 return make_error<StringError>("Empty __objc_imageinfo section in " + 306 G.getName(), 307 inconvertibleErrorCode()); 308 309 // Check that there's only one block in the section. 310 if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) 311 return make_error<StringError>("Multiple blocks in __objc_imageinfo " 312 "section in " + 313 G.getName(), 314 inconvertibleErrorCode()); 315 316 // Check that the __objc_imageinfo section is unreferenced. 317 // FIXME: We could optimize this check if Symbols had a ref-count. 318 for (auto &Sec : G.sections()) { 319 if (&Sec != ObjCImageInfo) 320 for (auto *B : Sec.blocks()) 321 for (auto &E : B->edges()) 322 if (E.getTarget().isDefined() && 323 &E.getTarget().getBlock().getSection() == ObjCImageInfo) 324 return make_error<StringError>("__objc_imageinfo is referenced " 325 "within file " + 326 G.getName(), 327 inconvertibleErrorCode()); 328 } 329 330 auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); 331 auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); 332 auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness()); 333 auto Flags = 334 support::endian::read32(ObjCImageInfoData + 4, G.getEndianness()); 335 336 // Lock the mutex while we verify / update the ObjCImageInfos map. 337 std::lock_guard<std::mutex> Lock(InitScraperMutex); 338 339 auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib()); 340 if (ObjCImageInfoItr != ObjCImageInfos.end()) { 341 // We've already registered an __objc_imageinfo section. Verify the 342 // content of this new section matches, then delete it. 343 if (ObjCImageInfoItr->second.first != Version) 344 return make_error<StringError>( 345 "ObjC version in " + G.getName() + 346 " does not match first registered version", 347 inconvertibleErrorCode()); 348 if (ObjCImageInfoItr->second.second != Flags) 349 return make_error<StringError>("ObjC flags in " + G.getName() + 350 " do not match first registered flags", 351 inconvertibleErrorCode()); 352 353 // __objc_imageinfo is valid. Delete the block. 354 for (auto *S : ObjCImageInfo->symbols()) 355 G.removeDefinedSymbol(*S); 356 G.removeBlock(ObjCImageInfoBlock); 357 } else { 358 // We haven't registered an __objc_imageinfo section yet. Register and 359 // move on. The section should already be marked no-dead-strip. 360 ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags); 361 } 362 363 return Error::success(); 364 } 365 366 } // End namespace orc. 367 } // End namespace llvm. 368