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