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