1a6deaeecSLang Hames //===---- llvm-jitlink-elf.cpp -- ELF parsing support for llvm-jitlink ----===// 2a6deaeecSLang Hames // 3a6deaeecSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a6deaeecSLang Hames // See https://llvm.org/LICENSE.txt for license information. 5a6deaeecSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a6deaeecSLang Hames // 7a6deaeecSLang Hames //===----------------------------------------------------------------------===// 8a6deaeecSLang Hames // 9a6deaeecSLang Hames // ELF parsing support for llvm-jitlink. 10a6deaeecSLang Hames // 11a6deaeecSLang Hames //===----------------------------------------------------------------------===// 12a6deaeecSLang Hames 13a6deaeecSLang Hames #include "llvm-jitlink.h" 14a6deaeecSLang Hames 15a6deaeecSLang Hames #include "llvm/Support/Error.h" 16a6deaeecSLang Hames #include "llvm/Support/Path.h" 17a6deaeecSLang Hames 18a6deaeecSLang Hames #define DEBUG_TYPE "llvm_jitlink" 19a6deaeecSLang Hames 20a6deaeecSLang Hames using namespace llvm; 21a6deaeecSLang Hames using namespace llvm::jitlink; 22a6deaeecSLang Hames 233b55bfadSLang Hames static bool isELFGOTSection(Section &S) { return S.getName() == "$__GOT"; } 243b55bfadSLang Hames 253b55bfadSLang Hames static bool isELFStubsSection(Section &S) { return S.getName() == "$__STUBS"; } 263b55bfadSLang Hames 2795dcb8b4SStefan Gränitz static bool isELFAArch32StubsSection(Section &S) { 2895dcb8b4SStefan Gränitz return S.getName().starts_with("__llvm_jitlink_aarch32_STUBS_"); 2995dcb8b4SStefan Gränitz } 3095dcb8b4SStefan Gränitz 313b55bfadSLang Hames static Expected<Edge &> getFirstRelocationEdge(LinkGraph &G, Block &B) { 32ce9f007cSKazu Hirata auto EItr = 33ce9f007cSKazu Hirata llvm::find_if(B.edges(), [](Edge &E) { return E.isRelocation(); }); 343b55bfadSLang Hames if (EItr == B.edges().end()) 353b55bfadSLang Hames return make_error<StringError>("GOT entry in " + G.getName() + ", \"" + 363b55bfadSLang Hames B.getSection().getName() + 373b55bfadSLang Hames "\" has no relocations", 383b55bfadSLang Hames inconvertibleErrorCode()); 393b55bfadSLang Hames return *EItr; 403b55bfadSLang Hames } 413b55bfadSLang Hames 423b55bfadSLang Hames static Expected<Symbol &> getELFGOTTarget(LinkGraph &G, Block &B) { 433b55bfadSLang Hames auto E = getFirstRelocationEdge(G, B); 443b55bfadSLang Hames if (!E) 453b55bfadSLang Hames return E.takeError(); 463b55bfadSLang Hames auto &TargetSym = E->getTarget(); 473b55bfadSLang Hames if (!TargetSym.hasName()) 483b55bfadSLang Hames return make_error<StringError>( 493b55bfadSLang Hames "GOT entry in " + G.getName() + ", \"" + 503b55bfadSLang Hames TargetSym.getBlock().getSection().getName() + 513b55bfadSLang Hames "\" points to anonymous " 523b55bfadSLang Hames "symbol", 533b55bfadSLang Hames inconvertibleErrorCode()); 543b55bfadSLang Hames return TargetSym; 553b55bfadSLang Hames } 563b55bfadSLang Hames 573b55bfadSLang Hames static Expected<Symbol &> getELFStubTarget(LinkGraph &G, Block &B) { 583b55bfadSLang Hames auto E = getFirstRelocationEdge(G, B); 593b55bfadSLang Hames if (!E) 603b55bfadSLang Hames return E.takeError(); 613b55bfadSLang Hames auto &GOTSym = E->getTarget(); 62c8562e81SStefan Gränitz if (!GOTSym.isDefined()) 63c8562e81SStefan Gränitz return make_error<StringError>("Stubs entry in " + G.getName() + 64c8562e81SStefan Gränitz " does not point to GOT entry", 65c8562e81SStefan Gränitz inconvertibleErrorCode()); 66c8562e81SStefan Gränitz if (!isELFGOTSection(GOTSym.getBlock().getSection())) 673b55bfadSLang Hames return make_error<StringError>( 683b55bfadSLang Hames "Stubs entry in " + G.getName() + ", \"" + 693b55bfadSLang Hames GOTSym.getBlock().getSection().getName() + 703b55bfadSLang Hames "\" does not point to GOT entry", 713b55bfadSLang Hames inconvertibleErrorCode()); 723b55bfadSLang Hames return getELFGOTTarget(G, GOTSym.getBlock()); 733b55bfadSLang Hames } 743b55bfadSLang Hames 7501ba627fSStefan Gränitz static Expected<Symbol &> getELFAArch32StubTarget(LinkGraph &G, Block &B) { 7695dcb8b4SStefan Gränitz auto E = getFirstRelocationEdge(G, B); 7795dcb8b4SStefan Gränitz if (!E) 7895dcb8b4SStefan Gränitz return E.takeError(); 7901ba627fSStefan Gränitz return E->getTarget(); 8001ba627fSStefan Gränitz } 8101ba627fSStefan Gränitz 8201ba627fSStefan Gränitz enum SectionType { GOT, Stubs, AArch32Stubs, Other }; 8301ba627fSStefan Gränitz 8401ba627fSStefan Gränitz static Error registerSymbol(LinkGraph &G, Symbol &Sym, Session::FileInfo &FI, 8501ba627fSStefan Gränitz SectionType SecType) { 8601ba627fSStefan Gränitz switch (SecType) { 8701ba627fSStefan Gränitz case GOT: 8801ba627fSStefan Gränitz if (Sym.getSize() == 0) 8901ba627fSStefan Gränitz return Error::success(); // Skip the GOT start symbol 9001ba627fSStefan Gränitz return FI.registerGOTEntry(G, Sym, getELFGOTTarget); 9101ba627fSStefan Gränitz case Stubs: 9201ba627fSStefan Gränitz return FI.registerStubEntry(G, Sym, getELFStubTarget); 9301ba627fSStefan Gränitz case AArch32Stubs: 946a433d77SStefan Gränitz return FI.registerMultiStubEntry(G, Sym, getELFAArch32StubTarget); 9501ba627fSStefan Gränitz case Other: 9601ba627fSStefan Gränitz return Error::success(); 9701ba627fSStefan Gränitz } 98836dcdb8SSimon Pilgrim llvm_unreachable("Unhandled SectionType enum"); 9995dcb8b4SStefan Gränitz } 10095dcb8b4SStefan Gränitz 101a6deaeecSLang Hames namespace llvm { 102a6deaeecSLang Hames 103a6deaeecSLang Hames Error registerELFGraphInfo(Session &S, LinkGraph &G) { 104*09655153SLang Hames std::lock_guard<std::mutex> Lock(S.M); 105*09655153SLang Hames 106a6deaeecSLang Hames auto FileName = sys::path::filename(G.getName()); 107a6deaeecSLang Hames if (S.FileInfos.count(FileName)) { 108a6deaeecSLang Hames return make_error<StringError>("When -check is passed, file names must be " 109a6deaeecSLang Hames "distinct (duplicate: \"" + 110a6deaeecSLang Hames FileName + "\")", 111a6deaeecSLang Hames inconvertibleErrorCode()); 112a6deaeecSLang Hames } 113a6deaeecSLang Hames 114a6deaeecSLang Hames auto &FileInfo = S.FileInfos[FileName]; 115a6deaeecSLang Hames LLVM_DEBUG({ 116a6deaeecSLang Hames dbgs() << "Registering ELF file info for \"" << FileName << "\"\n"; 117a6deaeecSLang Hames }); 118a6deaeecSLang Hames for (auto &Sec : G.sections()) { 119a6deaeecSLang Hames LLVM_DEBUG({ 120a6deaeecSLang Hames dbgs() << " Section \"" << Sec.getName() << "\": " 12196066084SKazu Hirata << (Sec.symbols().empty() ? "empty. skipping." : "processing...") 122a6deaeecSLang Hames << "\n"; 123a6deaeecSLang Hames }); 124a6deaeecSLang Hames 125a6deaeecSLang Hames // Skip empty sections. 12696066084SKazu Hirata if (Sec.symbols().empty()) 127a6deaeecSLang Hames continue; 128a6deaeecSLang Hames 129a6deaeecSLang Hames if (FileInfo.SectionInfos.count(Sec.getName())) 130a6deaeecSLang Hames return make_error<StringError>("Encountered duplicate section name \"" + 131a6deaeecSLang Hames Sec.getName() + "\" in \"" + FileName + 132a6deaeecSLang Hames "\"", 133a6deaeecSLang Hames inconvertibleErrorCode()); 134a6deaeecSLang Hames 13501ba627fSStefan Gränitz SectionType SecType; 13601ba627fSStefan Gränitz if (isELFGOTSection(Sec)) { 13701ba627fSStefan Gränitz SecType = GOT; 13801ba627fSStefan Gränitz } else if (isELFStubsSection(Sec)) { 13901ba627fSStefan Gränitz SecType = Stubs; 14001ba627fSStefan Gränitz } else if (isELFAArch32StubsSection(Sec)) { 14101ba627fSStefan Gränitz SecType = AArch32Stubs; 14201ba627fSStefan Gränitz } else { 14301ba627fSStefan Gränitz SecType = Other; 14401ba627fSStefan Gränitz } 1453b55bfadSLang Hames 146a6deaeecSLang Hames bool SectionContainsContent = false; 147a6deaeecSLang Hames bool SectionContainsZeroFill = false; 148a6deaeecSLang Hames 149a6deaeecSLang Hames auto *FirstSym = *Sec.symbols().begin(); 150a6deaeecSLang Hames auto *LastSym = FirstSym; 151a6deaeecSLang Hames for (auto *Sym : Sec.symbols()) { 152a6deaeecSLang Hames if (Sym->getAddress() < FirstSym->getAddress()) 153a6deaeecSLang Hames FirstSym = Sym; 154a6deaeecSLang Hames if (Sym->getAddress() > LastSym->getAddress()) 155a6deaeecSLang Hames LastSym = Sym; 156a6deaeecSLang Hames 15701ba627fSStefan Gränitz if (SecType != Other) { 15801ba627fSStefan Gränitz if (Error Err = registerSymbol(G, *Sym, FileInfo, SecType)) 15901ba627fSStefan Gränitz return Err; 16095dcb8b4SStefan Gränitz SectionContainsContent = true; 161fc36a511SLang Hames } 162fc36a511SLang Hames 163fc36a511SLang Hames if (Sym->hasName()) { 164a6deaeecSLang Hames if (Sym->isSymbolZeroFill()) { 165118e953bSLang Hames S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 166118e953bSLang Hames Sym->getAddress().getValue()}; 167a6deaeecSLang Hames SectionContainsZeroFill = true; 168a6deaeecSLang Hames } else { 169a6deaeecSLang Hames S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(), 1709c017a99SEymen Ünay Sym->getAddress().getValue(), 1719c017a99SEymen Ünay Sym->getTargetFlags()}; 172a6deaeecSLang Hames SectionContainsContent = true; 173a6deaeecSLang Hames } 174a6deaeecSLang Hames } 175a6deaeecSLang Hames } 176a6deaeecSLang Hames 177e4b6e686SLang Hames // Add symbol info for absolute symbols. 178e4b6e686SLang Hames for (auto *Sym : G.absolute_symbols()) 179e4b6e686SLang Hames S.SymbolInfos[Sym->getName()] = {Sym->getSize(), 180e4b6e686SLang Hames Sym->getAddress().getValue()}; 181e4b6e686SLang Hames 182118e953bSLang Hames auto SecAddr = FirstSym->getAddress(); 183118e953bSLang Hames auto SecSize = 184a6deaeecSLang Hames (LastSym->getBlock().getAddress() + LastSym->getBlock().getSize()) - 185a6deaeecSLang Hames SecAddr; 186a6deaeecSLang Hames 187a6deaeecSLang Hames if (SectionContainsZeroFill && SectionContainsContent) 188a6deaeecSLang Hames return make_error<StringError>("Mixed zero-fill and content sections not " 189a6deaeecSLang Hames "supported yet", 190a6deaeecSLang Hames inconvertibleErrorCode()); 191a6deaeecSLang Hames if (SectionContainsZeroFill) 192118e953bSLang Hames FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr.getValue()}; 193a6deaeecSLang Hames else 194a6deaeecSLang Hames FileInfo.SectionInfos[Sec.getName()] = { 1950269a407SLang Hames ArrayRef<char>(FirstSym->getBlock().getContent().data(), SecSize), 1969c017a99SEymen Ünay SecAddr.getValue(), FirstSym->getTargetFlags()}; 197a6deaeecSLang Hames } 198a6deaeecSLang Hames 199a6deaeecSLang Hames return Error::success(); 200a6deaeecSLang Hames } 201a6deaeecSLang Hames 202a6deaeecSLang Hames } // end namespace llvm 203