Home | History | Annotate | Line # | Download | only in Orc
      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     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 
    101 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 
    115 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 
    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 
    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 
    162 Error MachOPlatform::notifyAdding(ResourceTracker &RT,
    163                                   const MaterializationUnit &MU) {
    164   auto &JD = RT.getJITDylib();
    165   const auto &InitSym = MU.getInitializerSymbol();
    166   if (!InitSym)
    167     return Error::success();
    168 
    169   RegisteredInitSymbols[&JD].add(InitSym,
    170                                  SymbolLookupFlags::WeaklyReferencedSymbol);
    171   LLVM_DEBUG({
    172     dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU "
    173            << MU.getName() << "\n";
    174   });
    175   return Error::success();
    176 }
    177 
    178 Error MachOPlatform::notifyRemoving(ResourceTracker &RT) {
    179   llvm_unreachable("Not supported yet");
    180 }
    181 
    182 Expected<MachOPlatform::InitializerSequence>
    183 MachOPlatform::getInitializerSequence(JITDylib &JD) {
    184 
    185   LLVM_DEBUG({
    186     dbgs() << "MachOPlatform: Building initializer sequence for "
    187            << JD.getName() << "\n";
    188   });
    189 
    190   std::vector<JITDylibSP> DFSLinkOrder;
    191 
    192   while (true) {
    193 
    194     DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols;
    195 
    196     ES.runSessionLocked([&]() {
    197       DFSLinkOrder = JD.getDFSLinkOrder();
    198 
    199       for (auto &InitJD : DFSLinkOrder) {
    200         auto RISItr = RegisteredInitSymbols.find(InitJD.get());
    201         if (RISItr != RegisteredInitSymbols.end()) {
    202           NewInitSymbols[InitJD.get()] = std::move(RISItr->second);
    203           RegisteredInitSymbols.erase(RISItr);
    204         }
    205       }
    206     });
    207 
    208     if (NewInitSymbols.empty())
    209       break;
    210 
    211     LLVM_DEBUG({
    212       dbgs() << "MachOPlatform: Issuing lookups for new init symbols: "
    213                 "(lookup may require multiple rounds)\n";
    214       for (auto &KV : NewInitSymbols)
    215         dbgs() << "  \"" << KV.first->getName() << "\": " << KV.second << "\n";
    216     });
    217 
    218     // Outside the lock, issue the lookup.
    219     if (auto R = lookupInitSymbols(JD.getExecutionSession(), NewInitSymbols))
    220       ; // Nothing to do in the success case.
    221     else
    222       return R.takeError();
    223   }
    224 
    225   LLVM_DEBUG({
    226     dbgs() << "MachOPlatform: Init symbol lookup complete, building init "
    227               "sequence\n";
    228   });
    229 
    230   // Lock again to collect the initializers.
    231   InitializerSequence FullInitSeq;
    232   {
    233     std::lock_guard<std::mutex> Lock(InitSeqsMutex);
    234     for (auto &InitJD : reverse(DFSLinkOrder)) {
    235       LLVM_DEBUG({
    236         dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName()
    237                << "\" to sequence\n";
    238       });
    239       auto ISItr = InitSeqs.find(InitJD.get());
    240       if (ISItr != InitSeqs.end()) {
    241         FullInitSeq.emplace_back(InitJD.get(), std::move(ISItr->second));
    242         InitSeqs.erase(ISItr);
    243       }
    244     }
    245   }
    246 
    247   return FullInitSeq;
    248 }
    249 
    250 Expected<MachOPlatform::DeinitializerSequence>
    251 MachOPlatform::getDeinitializerSequence(JITDylib &JD) {
    252   std::vector<JITDylibSP> DFSLinkOrder = JD.getDFSLinkOrder();
    253 
    254   DeinitializerSequence FullDeinitSeq;
    255   {
    256     std::lock_guard<std::mutex> Lock(InitSeqsMutex);
    257     for (auto &DeinitJD : DFSLinkOrder) {
    258       FullDeinitSeq.emplace_back(DeinitJD.get(), MachOJITDylibDeinitializers());
    259     }
    260   }
    261 
    262   return FullDeinitSeq;
    263 }
    264 
    265 void MachOPlatform::registerInitInfo(
    266     JITDylib &JD, JITTargetAddress ObjCImageInfoAddr,
    267     MachOJITDylibInitializers::SectionExtent ModInits,
    268     MachOJITDylibInitializers::SectionExtent ObjCSelRefs,
    269     MachOJITDylibInitializers::SectionExtent ObjCClassList) {
    270   std::lock_guard<std::mutex> Lock(InitSeqsMutex);
    271 
    272   auto &InitSeq = InitSeqs[&JD];
    273 
    274   InitSeq.setObjCImageInfoAddr(ObjCImageInfoAddr);
    275 
    276   if (ModInits.Address)
    277     InitSeq.addModInitsSection(std::move(ModInits));
    278 
    279   if (ObjCSelRefs.Address)
    280     InitSeq.addObjCSelRefsSection(std::move(ObjCSelRefs));
    281 
    282   if (ObjCClassList.Address)
    283     InitSeq.addObjCClassListSection(std::move(ObjCClassList));
    284 }
    285 
    286 static Expected<MachOJITDylibInitializers::SectionExtent>
    287 getSectionExtent(jitlink::LinkGraph &G, StringRef SectionName) {
    288   auto *Sec = G.findSectionByName(SectionName);
    289   if (!Sec)
    290     return MachOJITDylibInitializers::SectionExtent();
    291   jitlink::SectionRange R(*Sec);
    292   if (R.getSize() % G.getPointerSize() != 0)
    293     return make_error<StringError>(SectionName + " section size is not a "
    294                                                  "multiple of the pointer size",
    295                                    inconvertibleErrorCode());
    296   return MachOJITDylibInitializers::SectionExtent(
    297       R.getStart(), R.getSize() / G.getPointerSize());
    298 }
    299 
    300 void MachOPlatform::InitScraperPlugin::modifyPassConfig(
    301     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
    302     jitlink::PassConfiguration &Config) {
    303 
    304   if (!MR.getInitializerSymbol())
    305     return;
    306 
    307   Config.PrePrunePasses.push_back([this, &MR](jitlink::LinkGraph &G) -> Error {
    308     JITLinkSymbolVector InitSectionSymbols;
    309     preserveInitSectionIfPresent(InitSectionSymbols, G,
    310                                  "__DATA,__mod_init_func");
    311     preserveInitSectionIfPresent(InitSectionSymbols, G,
    312                                  "__DATA,__objc_selrefs");
    313     preserveInitSectionIfPresent(InitSectionSymbols, G,
    314                                  "__DATA,__objc_classlist");
    315 
    316     if (!InitSectionSymbols.empty()) {
    317       std::lock_guard<std::mutex> Lock(InitScraperMutex);
    318       InitSymbolDeps[&MR] = std::move(InitSectionSymbols);
    319     }
    320 
    321     if (auto Err = processObjCImageInfo(G, MR))
    322       return Err;
    323 
    324     return Error::success();
    325   });
    326 
    327   Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib()](
    328                                        jitlink::LinkGraph &G) -> Error {
    329     MachOJITDylibInitializers::SectionExtent ModInits, ObjCSelRefs,
    330         ObjCClassList;
    331 
    332     JITTargetAddress ObjCImageInfoAddr = 0;
    333     if (auto *ObjCImageInfoSec =
    334             G.findSectionByName("__DATA,__objc_image_info")) {
    335       if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart())
    336         ObjCImageInfoAddr = Addr;
    337     }
    338 
    339     // Record __mod_init_func.
    340     if (auto ModInitsOrErr = getSectionExtent(G, "__DATA,__mod_init_func"))
    341       ModInits = std::move(*ModInitsOrErr);
    342     else
    343       return ModInitsOrErr.takeError();
    344 
    345     // Record __objc_selrefs.
    346     if (auto ObjCSelRefsOrErr = getSectionExtent(G, "__DATA,__objc_selrefs"))
    347       ObjCSelRefs = std::move(*ObjCSelRefsOrErr);
    348     else
    349       return ObjCSelRefsOrErr.takeError();
    350 
    351     // Record __objc_classlist.
    352     if (auto ObjCClassListOrErr =
    353             getSectionExtent(G, "__DATA,__objc_classlist"))
    354       ObjCClassList = std::move(*ObjCClassListOrErr);
    355     else
    356       return ObjCClassListOrErr.takeError();
    357 
    358     // Dump the scraped inits.
    359     LLVM_DEBUG({
    360       dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
    361       dbgs() << "  __objc_selrefs: ";
    362       if (ObjCSelRefs.NumPtrs)
    363         dbgs() << ObjCSelRefs.NumPtrs << " pointer(s) at "
    364                << formatv("{0:x16}", ObjCSelRefs.Address) << "\n";
    365       else
    366         dbgs() << "none\n";
    367 
    368       dbgs() << "  __objc_classlist: ";
    369       if (ObjCClassList.NumPtrs)
    370         dbgs() << ObjCClassList.NumPtrs << " pointer(s) at "
    371                << formatv("{0:x16}", ObjCClassList.Address) << "\n";
    372       else
    373         dbgs() << "none\n";
    374 
    375       dbgs() << "  __mod_init_func: ";
    376       if (ModInits.NumPtrs)
    377         dbgs() << ModInits.NumPtrs << " pointer(s) at "
    378                << formatv("{0:x16}", ModInits.Address) << "\n";
    379       else
    380         dbgs() << "none\n";
    381     });
    382 
    383     MP.registerInitInfo(JD, ObjCImageInfoAddr, std::move(ModInits),
    384                         std::move(ObjCSelRefs), std::move(ObjCClassList));
    385 
    386     return Error::success();
    387   });
    388 }
    389 
    390 ObjectLinkingLayer::Plugin::LocalDependenciesMap
    391 MachOPlatform::InitScraperPlugin::getSyntheticSymbolLocalDependencies(
    392     MaterializationResponsibility &MR) {
    393   std::lock_guard<std::mutex> Lock(InitScraperMutex);
    394   auto I = InitSymbolDeps.find(&MR);
    395   if (I != InitSymbolDeps.end()) {
    396     LocalDependenciesMap Result;
    397     Result[MR.getInitializerSymbol()] = std::move(I->second);
    398     InitSymbolDeps.erase(&MR);
    399     return Result;
    400   }
    401   return LocalDependenciesMap();
    402 }
    403 
    404 void MachOPlatform::InitScraperPlugin::preserveInitSectionIfPresent(
    405     JITLinkSymbolVector &Symbols, jitlink::LinkGraph &G,
    406     StringRef SectionName) {
    407   if (auto *Sec = G.findSectionByName(SectionName)) {
    408     auto SecBlocks = Sec->blocks();
    409     if (!llvm::empty(SecBlocks))
    410       Symbols.push_back(
    411           &G.addAnonymousSymbol(**SecBlocks.begin(), 0, 0, false, true));
    412   }
    413 }
    414 
    415 Error MachOPlatform::InitScraperPlugin::processObjCImageInfo(
    416     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
    417 
    418   // If there's an ObjC imagine info then either
    419   //   (1) It's the first __objc_imageinfo we've seen in this JITDylib. In
    420   //       this case we name and record it.
    421   // OR
    422   //   (2) We already have a recorded __objc_imageinfo for this JITDylib,
    423   //       in which case we just verify it.
    424   auto *ObjCImageInfo = G.findSectionByName("__objc_imageinfo");
    425   if (!ObjCImageInfo)
    426     return Error::success();
    427 
    428   auto ObjCImageInfoBlocks = ObjCImageInfo->blocks();
    429 
    430   // Check that the section is not empty if present.
    431   if (llvm::empty(ObjCImageInfoBlocks))
    432     return make_error<StringError>("Empty __objc_imageinfo section in " +
    433                                        G.getName(),
    434                                    inconvertibleErrorCode());
    435 
    436   // Check that there's only one block in the section.
    437   if (std::next(ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end())
    438     return make_error<StringError>("Multiple blocks in __objc_imageinfo "
    439                                    "section in " +
    440                                        G.getName(),
    441                                    inconvertibleErrorCode());
    442 
    443   // Check that the __objc_imageinfo section is unreferenced.
    444   // FIXME: We could optimize this check if Symbols had a ref-count.
    445   for (auto &Sec : G.sections()) {
    446     if (&Sec != ObjCImageInfo)
    447       for (auto *B : Sec.blocks())
    448         for (auto &E : B->edges())
    449           if (E.getTarget().isDefined() &&
    450               &E.getTarget().getBlock().getSection() == ObjCImageInfo)
    451             return make_error<StringError>("__objc_imageinfo is referenced "
    452                                            "within file " +
    453                                                G.getName(),
    454                                            inconvertibleErrorCode());
    455   }
    456 
    457   auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin();
    458   auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data();
    459   auto Version = support::endian::read32(ObjCImageInfoData, G.getEndianness());
    460   auto Flags =
    461       support::endian::read32(ObjCImageInfoData + 4, G.getEndianness());
    462 
    463   // Lock the mutex while we verify / update the ObjCImageInfos map.
    464   std::lock_guard<std::mutex> Lock(InitScraperMutex);
    465 
    466   auto ObjCImageInfoItr = ObjCImageInfos.find(&MR.getTargetJITDylib());
    467   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
    468     // We've already registered an __objc_imageinfo section. Verify the
    469     // content of this new section matches, then delete it.
    470     if (ObjCImageInfoItr->second.first != Version)
    471       return make_error<StringError>(
    472           "ObjC version in " + G.getName() +
    473               " does not match first registered version",
    474           inconvertibleErrorCode());
    475     if (ObjCImageInfoItr->second.second != Flags)
    476       return make_error<StringError>("ObjC flags in " + G.getName() +
    477                                          " do not match first registered flags",
    478                                      inconvertibleErrorCode());
    479 
    480     // __objc_imageinfo is valid. Delete the block.
    481     for (auto *S : ObjCImageInfo->symbols())
    482       G.removeDefinedSymbol(*S);
    483     G.removeBlock(ObjCImageInfoBlock);
    484   } else {
    485     // We haven't registered an __objc_imageinfo section yet. Register and
    486     // move on. The section should already be marked no-dead-strip.
    487     ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
    488   }
    489 
    490   return Error::success();
    491 }
    492 
    493 } // End namespace orc.
    494 } // End namespace llvm.
    495