111c8dfa5SLang Hames //===-- llvm-jitlink-macho.cpp -- MachO parsing support for llvm-jitlink --===// 211c8dfa5SLang Hames // 311c8dfa5SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 411c8dfa5SLang Hames // See https://llvm.org/LICENSE.txt for license information. 511c8dfa5SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 611c8dfa5SLang Hames // 711c8dfa5SLang Hames //===----------------------------------------------------------------------===// 811c8dfa5SLang Hames // 923085ec3SLang Hames // MachO parsing support for llvm-jitlink. 1011c8dfa5SLang Hames // 1111c8dfa5SLang Hames //===----------------------------------------------------------------------===// 1211c8dfa5SLang Hames 1311c8dfa5SLang Hames #include "llvm-jitlink.h" 1411c8dfa5SLang Hames 1511c8dfa5SLang Hames #include "llvm/Support/Error.h" 1611c8dfa5SLang Hames #include "llvm/Support/Path.h" 1711c8dfa5SLang Hames 180caed13fSLang Hames #define DEBUG_TYPE "llvm_jitlink" 1911c8dfa5SLang Hames 2011c8dfa5SLang Hames using namespace llvm; 2111c8dfa5SLang Hames using namespace llvm::jitlink; 2211c8dfa5SLang Hames 2311c8dfa5SLang Hames static bool isMachOGOTSection(Section &S) { return S.getName() == "$__GOT"; } 2411c8dfa5SLang Hames 2511c8dfa5SLang Hames static bool isMachOStubsSection(Section &S) { 2611c8dfa5SLang Hames return S.getName() == "$__STUBS"; 2711c8dfa5SLang Hames } 2811c8dfa5SLang Hames 294e920e58SLang Hames static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) { 30ce9f007cSKazu Hirata auto EItr = 31ce9f007cSKazu Hirata llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); }); 324e920e58SLang Hames if (EItr == B.edges().end()) 3311c8dfa5SLang Hames return make_error<StringError>("GOT entry in " + G.getName() + ", \"" + 344e920e58SLang Hames B.getSection().getName() + 3511c8dfa5SLang Hames "\" has no relocations", 3611c8dfa5SLang Hames inconvertibleErrorCode()); 3711c8dfa5SLang Hames return *EItr; 3811c8dfa5SLang Hames } 3911c8dfa5SLang Hames 404e920e58SLang Hames static Expected<Symbol &> getMachOGOTTarget(LinkGraph &G, Block &B) { 414e920e58SLang Hames auto E = getFirstRelocationEdge(G, B); 4211c8dfa5SLang Hames if (!E) 4311c8dfa5SLang Hames return E.takeError(); 444e920e58SLang Hames auto &TargetSym = E->getTarget(); 454e920e58SLang Hames if (!TargetSym.hasName()) 4611c8dfa5SLang Hames return make_error<StringError>( 474e920e58SLang Hames "GOT entry in " + G.getName() + ", \"" + 484e920e58SLang Hames TargetSym.getBlock().getSection().getName() + 494e920e58SLang Hames "\" points to anonymous " 504e920e58SLang Hames "symbol", 5111c8dfa5SLang Hames inconvertibleErrorCode()); 524e920e58SLang Hames return TargetSym; 5311c8dfa5SLang Hames } 5411c8dfa5SLang Hames 554e920e58SLang Hames static Expected<Symbol &> getMachOStubTarget(LinkGraph &G, Block &B) { 564e920e58SLang Hames auto E = getFirstRelocationEdge(G, B); 5711c8dfa5SLang Hames if (!E) 5811c8dfa5SLang Hames return E.takeError(); 594e920e58SLang Hames auto &GOTSym = E->getTarget(); 604e920e58SLang Hames if (!GOTSym.isDefined() || !isMachOGOTSection(GOTSym.getBlock().getSection())) 614e920e58SLang Hames return make_error<StringError>( 624e920e58SLang Hames "Stubs entry in " + G.getName() + ", \"" + 634e920e58SLang Hames GOTSym.getBlock().getSection().getName() + 6411c8dfa5SLang Hames "\" does not point to GOT entry", 6511c8dfa5SLang Hames inconvertibleErrorCode()); 664e920e58SLang Hames return getMachOGOTTarget(G, GOTSym.getBlock()); 6711c8dfa5SLang Hames } 6811c8dfa5SLang Hames 6911c8dfa5SLang Hames namespace llvm { 7011c8dfa5SLang Hames 71a6deaeecSLang Hames Error registerMachOGraphInfo(Session &S, LinkGraph &G) { 72*09655153SLang Hames std::lock_guard<std::mutex> Lock(S.M); 73*09655153SLang Hames 7411c8dfa5SLang Hames auto FileName = sys::path::filename(G.getName()); 7511c8dfa5SLang Hames if (S.FileInfos.count(FileName)) { 7611c8dfa5SLang Hames return make_error<StringError>("When -check is passed, file names must be " 7711c8dfa5SLang Hames "distinct (duplicate: \"" + 7811c8dfa5SLang Hames FileName + "\")", 7911c8dfa5SLang Hames inconvertibleErrorCode()); 8011c8dfa5SLang Hames } 8111c8dfa5SLang Hames 8211c8dfa5SLang Hames auto &FileInfo = S.FileInfos[FileName]; 8311c8dfa5SLang Hames LLVM_DEBUG({ 8411c8dfa5SLang Hames dbgs() << "Registering MachO file info for \"" << FileName << "\"\n"; 8511c8dfa5SLang Hames }); 8611c8dfa5SLang Hames for (auto &Sec : G.sections()) { 8711c8dfa5SLang Hames LLVM_DEBUG({ 8811c8dfa5SLang Hames dbgs() << " Section \"" << Sec.getName() << "\": " 8996066084SKazu Hirata << (Sec.symbols().empty() ? "empty. skipping." : "processing...") 9011c8dfa5SLang Hames << "\n"; 9111c8dfa5SLang Hames }); 9211c8dfa5SLang Hames 9311c8dfa5SLang Hames // Skip empty sections. 9496066084SKazu Hirata if (Sec.symbols().empty()) 9511c8dfa5SLang Hames continue; 9611c8dfa5SLang Hames 9711c8dfa5SLang Hames if (FileInfo.SectionInfos.count(Sec.getName())) 9811c8dfa5SLang Hames return make_error<StringError>("Encountered duplicate section name \"" + 9911c8dfa5SLang Hames Sec.getName() + "\" in \"" + FileName + 10011c8dfa5SLang Hames "\"", 10111c8dfa5SLang Hames inconvertibleErrorCode()); 10211c8dfa5SLang Hames 10311c8dfa5SLang Hames bool isGOTSection = isMachOGOTSection(Sec); 10411c8dfa5SLang Hames bool isStubsSection = isMachOStubsSection(Sec); 10511c8dfa5SLang Hames 1064e920e58SLang Hames bool SectionContainsContent = false; 1074e920e58SLang Hames bool SectionContainsZeroFill = false; 1084e920e58SLang Hames 1094e920e58SLang Hames auto *FirstSym = *Sec.symbols().begin(); 1104e920e58SLang Hames auto *LastSym = FirstSym; 1114e920e58SLang Hames for (auto *Sym : Sec.symbols()) { 1124e920e58SLang Hames if (Sym->getAddress() < FirstSym->getAddress()) 1134e920e58SLang Hames FirstSym = Sym; 1144e920e58SLang Hames if (Sym->getAddress() > LastSym->getAddress()) 1154e920e58SLang Hames LastSym = Sym; 11601ba627fSStefan Gränitz if (isGOTSection || isStubsSection) { 11701ba627fSStefan Gränitz Error Err = 11801ba627fSStefan Gränitz isGOTSection 11901ba627fSStefan Gränitz ? FileInfo.registerGOTEntry(G, *Sym, getMachOGOTTarget) 12001ba627fSStefan Gränitz : FileInfo.registerStubEntry(G, *Sym, getMachOStubTarget); 12101ba627fSStefan Gränitz if (Err) 12201ba627fSStefan Gränitz return Err; 1234e920e58SLang Hames SectionContainsContent = true; 1244e920e58SLang Hames } else if (Sym->hasName()) { 1254e920e58SLang Hames if (Sym->isSymbolZeroFill()) { 126118e953bSLang Hames S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 127118e953bSLang Hames Sym->getAddress().getValue()}; 1284e920e58SLang Hames SectionContainsZeroFill = true; 1294e920e58SLang Hames } else { 1304e920e58SLang Hames S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(), 1319c017a99SEymen Ünay Sym->getAddress().getValue(), 1329c017a99SEymen Ünay Sym->getTargetFlags()}; 1334e920e58SLang Hames SectionContainsContent = true; 13411c8dfa5SLang Hames } 13523085ec3SLang Hames } 13623085ec3SLang Hames } 13723085ec3SLang Hames 138118e953bSLang Hames auto SecAddr = FirstSym->getAddress(); 139118e953bSLang Hames auto SecSize = 1404e920e58SLang Hames (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) - 1414e920e58SLang Hames SecAddr; 14223085ec3SLang Hames 1434e920e58SLang Hames if (SectionContainsZeroFill && SectionContainsContent) 1444e920e58SLang Hames return make_error<StringError>("Mixed zero-fill and content sections not " 1454e920e58SLang Hames "supported yet", 1464e920e58SLang Hames inconvertibleErrorCode()); 1474e920e58SLang Hames if (SectionContainsZeroFill) 148118e953bSLang Hames FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()}; 14923085ec3SLang Hames else 15023085ec3SLang Hames FileInfo.SectionInfos[Sec.getName()] = { 1510269a407SLang Hames ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize), 1529c017a99SEymen Ünay SecAddr.getValue(), FirstSym->getTargetFlags()}; 15311c8dfa5SLang Hames } 15411c8dfa5SLang Hames 15511c8dfa5SLang Hames return Error::success(); 15611c8dfa5SLang Hames } 15711c8dfa5SLang Hames 15811c8dfa5SLang Hames } // end namespace llvm 159