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