blob: 4618d53315efa9f91760cf802304f80fed6850de [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"
13
14namespace {
15
16struct objc_class;
17struct objc_image_info;
18struct objc_object;
19struct objc_selector;
20
21using Class = objc_class *;
22using id = objc_object *;
23using SEL = objc_selector *;
24
25using ObjCMsgSendTy = id (*)(id, SEL, ...);
26using ObjCReadClassPairTy = Class (*)(Class, const objc_image_info *);
27using SelRegisterNameTy = SEL (*)(const char *);
28
29enum class ObjCRegistrationAPI { Uninitialized, Unavailable, Initialized };
30
31ObjCRegistrationAPI ObjCRegistrationAPIState =
32 ObjCRegistrationAPI::Uninitialized;
33ObjCMsgSendTy objc_msgSend = nullptr;
34ObjCReadClassPairTy objc_readClassPair = nullptr;
35SelRegisterNameTy sel_registerName = nullptr;
36
37} // end anonymous namespace
38
39namespace llvm {
40namespace orc {
41
42template <typename FnTy>
43static 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
54Error 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
81bool objcRegistrationEnabled() {
82 return ObjCRegistrationAPIState == ObjCRegistrationAPI::Initialized;
83}
84
85void 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
97void 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
111Error 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
144void 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
150MachOPlatform::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
158Error MachOPlatform::setupJITDylib(JITDylib &JD) {
159 auto ObjBuffer = MemoryBuffer::getMemBuffer(
160 StandardSymbolsObject->getMemBufferRef(), false);
161 return ObjLinkingLayer.add(JD, std::move(ObjBuffer));
162}
163
164Error 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
174Error MachOPlatform::notifyRemoving(JITDylib &JD, VModuleKey K) {
175 llvm_unreachable("Not supported yet");
176}
177
178Expected<MachOPlatform::InitializerSequence>
179MachOPlatform::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
226Expected<MachOPlatform::DeinitializerSequence>
227MachOPlatform::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
241std::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
261void 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
282static Expected<MachOJITDylibInitializers::SectionExtent>
283getSectionExtent(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
296void 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
355ObjectLinkingLayer::Plugin::LocalDependenciesMap
356MachOPlatform::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
369void 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
380Error 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.