123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- //===------- ELFLinkGraphBuilder.h - ELF LinkGraph builder ------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Generic ELF LinkGraph building code.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
- #define LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
- #include "llvm/ExecutionEngine/JITLink/JITLink.h"
- #include "llvm/Object/ELF.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/FormatVariadic.h"
- #define DEBUG_TYPE "jitlink"
- namespace llvm {
- namespace jitlink {
- /// Common link-graph building code shared between all ELFFiles.
- class ELFLinkGraphBuilderBase {
- public:
- ELFLinkGraphBuilderBase(std::unique_ptr<LinkGraph> G) : G(std::move(G)) {}
- virtual ~ELFLinkGraphBuilderBase();
- protected:
- static bool isDwarfSection(StringRef SectionName) {
- return llvm::is_contained(DwarfSectionNames, SectionName);
- }
- Section &getCommonSection() {
- if (!CommonSection)
- CommonSection = &G->createSection(
- CommonSectionName, orc::MemProt::Read | orc::MemProt::Write);
- return *CommonSection;
- }
- std::unique_ptr<LinkGraph> G;
- private:
- static StringRef CommonSectionName;
- static ArrayRef<const char *> DwarfSectionNames;
- Section *CommonSection = nullptr;
- };
- /// Ling-graph building code that's specific to the given ELFT, but common
- /// across all architectures.
- template <typename ELFT>
- class ELFLinkGraphBuilder : public ELFLinkGraphBuilderBase {
- using ELFFile = object::ELFFile<ELFT>;
- public:
- ELFLinkGraphBuilder(const object::ELFFile<ELFT> &Obj, Triple TT,
- StringRef FileName,
- LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
- /// Attempt to construct and return the LinkGraph.
- Expected<std::unique_ptr<LinkGraph>> buildGraph();
- /// Call to derived class to handle relocations. These require
- /// architecture specific knowledge to map to JITLink edge kinds.
- virtual Error addRelocations() = 0;
- protected:
- using ELFSectionIndex = unsigned;
- using ELFSymbolIndex = unsigned;
- bool isRelocatable() const {
- return Obj.getHeader().e_type == llvm::ELF::ET_REL;
- }
- void setGraphBlock(ELFSectionIndex SecIndex, Block *B) {
- assert(!GraphBlocks.count(SecIndex) && "Duplicate section at index");
- GraphBlocks[SecIndex] = B;
- }
- Block *getGraphBlock(ELFSectionIndex SecIndex) {
- auto I = GraphBlocks.find(SecIndex);
- if (I == GraphBlocks.end())
- return nullptr;
- return I->second;
- }
- void setGraphSymbol(ELFSymbolIndex SymIndex, Symbol &Sym) {
- assert(!GraphSymbols.count(SymIndex) && "Duplicate symbol at index");
- GraphSymbols[SymIndex] = &Sym;
- }
- Symbol *getGraphSymbol(ELFSymbolIndex SymIndex) {
- auto I = GraphSymbols.find(SymIndex);
- if (I == GraphSymbols.end())
- return nullptr;
- return I->second;
- }
- Expected<std::pair<Linkage, Scope>>
- getSymbolLinkageAndScope(const typename ELFT::Sym &Sym, StringRef Name);
- Error prepare();
- Error graphifySections();
- Error graphifySymbols();
- /// Traverse all matching ELFT::Rela relocation records in the given section.
- /// The handler function Func should be callable with this signature:
- /// Error(const typename ELFT::Rela &,
- /// const typename ELFT::Shdr &, Section &)
- ///
- template <typename RelocHandlerMethod>
- Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,
- RelocHandlerMethod &&Func,
- bool ProcessDebugSections = false);
- /// Traverse all matching ELFT::Rel relocation records in the given section.
- /// The handler function Func should be callable with this signature:
- /// Error(const typename ELFT::Rel &,
- /// const typename ELFT::Shdr &, Section &)
- ///
- template <typename RelocHandlerMethod>
- Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,
- RelocHandlerMethod &&Func,
- bool ProcessDebugSections = false);
- /// Traverse all matching rela relocation records in the given section.
- /// Convenience wrapper to allow passing a member function for the handler.
- ///
- template <typename ClassT, typename RelocHandlerMethod>
- Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,
- ClassT *Instance, RelocHandlerMethod &&Method,
- bool ProcessDebugSections = false) {
- return forEachRelaRelocation(
- RelSect,
- [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
- return (Instance->*Method)(Rel, Target, GS);
- },
- ProcessDebugSections);
- }
- /// Traverse all matching rel relocation records in the given section.
- /// Convenience wrapper to allow passing a member function for the handler.
- ///
- template <typename ClassT, typename RelocHandlerMethod>
- Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,
- ClassT *Instance, RelocHandlerMethod &&Method,
- bool ProcessDebugSections = false) {
- return forEachRelRelocation(
- RelSect,
- [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
- return (Instance->*Method)(Rel, Target, GS);
- },
- ProcessDebugSections);
- }
- const ELFFile &Obj;
- typename ELFFile::Elf_Shdr_Range Sections;
- const typename ELFFile::Elf_Shdr *SymTabSec = nullptr;
- StringRef SectionStringTab;
- // Maps ELF section indexes to LinkGraph Blocks.
- // Only SHF_ALLOC sections will have graph blocks.
- DenseMap<ELFSectionIndex, Block *> GraphBlocks;
- DenseMap<ELFSymbolIndex, Symbol *> GraphSymbols;
- DenseMap<const typename ELFFile::Elf_Shdr *,
- ArrayRef<typename ELFFile::Elf_Word>>
- ShndxTables;
- };
- template <typename ELFT>
- ELFLinkGraphBuilder<ELFT>::ELFLinkGraphBuilder(
- const ELFFile &Obj, Triple TT, StringRef FileName,
- LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
- : ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(
- FileName.str(), Triple(std::move(TT)), ELFT::Is64Bits ? 8 : 4,
- support::endianness(ELFT::TargetEndianness),
- std::move(GetEdgeKindName))),
- Obj(Obj) {
- LLVM_DEBUG(
- { dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });
- }
- template <typename ELFT>
- Expected<std::unique_ptr<LinkGraph>> ELFLinkGraphBuilder<ELFT>::buildGraph() {
- if (!isRelocatable())
- return make_error<JITLinkError>("Object is not a relocatable ELF file");
- if (auto Err = prepare())
- return std::move(Err);
- if (auto Err = graphifySections())
- return std::move(Err);
- if (auto Err = graphifySymbols())
- return std::move(Err);
- if (auto Err = addRelocations())
- return std::move(Err);
- return std::move(G);
- }
- template <typename ELFT>
- Expected<std::pair<Linkage, Scope>>
- ELFLinkGraphBuilder<ELFT>::getSymbolLinkageAndScope(
- const typename ELFT::Sym &Sym, StringRef Name) {
- Linkage L = Linkage::Strong;
- Scope S = Scope::Default;
- switch (Sym.getBinding()) {
- case ELF::STB_LOCAL:
- S = Scope::Local;
- break;
- case ELF::STB_GLOBAL:
- // Nothing to do here.
- break;
- case ELF::STB_WEAK:
- case ELF::STB_GNU_UNIQUE:
- L = Linkage::Weak;
- break;
- default:
- return make_error<StringError>(
- "Unrecognized symbol binding " +
- Twine(static_cast<int>(Sym.getBinding())) + " for " + Name,
- inconvertibleErrorCode());
- }
- switch (Sym.getVisibility()) {
- case ELF::STV_DEFAULT:
- case ELF::STV_PROTECTED:
- // FIXME: Make STV_DEFAULT symbols pre-emptible? This probably needs
- // Orc support.
- // Otherwise nothing to do here.
- break;
- case ELF::STV_HIDDEN:
- // Default scope -> Hidden scope. No effect on local scope.
- if (S == Scope::Default)
- S = Scope::Hidden;
- break;
- case ELF::STV_INTERNAL:
- return make_error<StringError>(
- "Unrecognized symbol visibility " +
- Twine(static_cast<int>(Sym.getVisibility())) + " for " + Name,
- inconvertibleErrorCode());
- }
- return std::make_pair(L, S);
- }
- template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::prepare() {
- LLVM_DEBUG(dbgs() << " Preparing to build...\n");
- // Get the sections array.
- if (auto SectionsOrErr = Obj.sections())
- Sections = *SectionsOrErr;
- else
- return SectionsOrErr.takeError();
- // Get the section string table.
- if (auto SectionStringTabOrErr = Obj.getSectionStringTable(Sections))
- SectionStringTab = *SectionStringTabOrErr;
- else
- return SectionStringTabOrErr.takeError();
- // Get the SHT_SYMTAB section.
- for (auto &Sec : Sections) {
- if (Sec.sh_type == ELF::SHT_SYMTAB) {
- if (!SymTabSec)
- SymTabSec = &Sec;
- else
- return make_error<JITLinkError>("Multiple SHT_SYMTAB sections in " +
- G->getName());
- }
- // Extended table.
- if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {
- uint32_t SymtabNdx = Sec.sh_link;
- if (SymtabNdx >= Sections.size())
- return make_error<JITLinkError>("sh_link is out of bound");
- auto ShndxTable = Obj.getSHNDXTable(Sec);
- if (!ShndxTable)
- return ShndxTable.takeError();
- ShndxTables.insert({&Sections[SymtabNdx], *ShndxTable});
- }
- }
- return Error::success();
- }
- template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {
- LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
- // For each section...
- for (ELFSectionIndex SecIndex = 0; SecIndex != Sections.size(); ++SecIndex) {
- auto &Sec = Sections[SecIndex];
- // Start by getting the section name.
- auto Name = Obj.getSectionName(Sec, SectionStringTab);
- if (!Name)
- return Name.takeError();
- // If the name indicates that it's a debug section then skip it: We don't
- // support those yet.
- if (isDwarfSection(*Name)) {
- LLVM_DEBUG({
- dbgs() << " " << SecIndex << ": \"" << *Name
- << "\" is a debug section: "
- "No graph section will be created.\n";
- });
- continue;
- }
- // Skip non-SHF_ALLOC sections
- if (!(Sec.sh_flags & ELF::SHF_ALLOC)) {
- LLVM_DEBUG({
- dbgs() << " " << SecIndex << ": \"" << *Name
- << "\" is not an SHF_ALLOC section: "
- "No graph section will be created.\n";
- });
- continue;
- }
- LLVM_DEBUG({
- dbgs() << " " << SecIndex << ": Creating section for \"" << *Name
- << "\"\n";
- });
- // Get the section's memory protection flags.
- orc::MemProt Prot;
- if (Sec.sh_flags & ELF::SHF_EXECINSTR)
- Prot = orc::MemProt::Read | orc::MemProt::Exec;
- else
- Prot = orc::MemProt::Read | orc::MemProt::Write;
- // Look for existing sections first.
- auto *GraphSec = G->findSectionByName(*Name);
- if (!GraphSec)
- GraphSec = &G->createSection(*Name, Prot);
- assert(GraphSec->getMemProt() == Prot && "MemProt should match");
- Block *B = nullptr;
- if (Sec.sh_type != ELF::SHT_NOBITS) {
- auto Data = Obj.template getSectionContentsAsArray<char>(Sec);
- if (!Data)
- return Data.takeError();
- B = &G->createContentBlock(*GraphSec, *Data,
- orc::ExecutorAddr(Sec.sh_addr),
- Sec.sh_addralign, 0);
- } else
- B = &G->createZeroFillBlock(*GraphSec, Sec.sh_size,
- orc::ExecutorAddr(Sec.sh_addr),
- Sec.sh_addralign, 0);
- setGraphBlock(SecIndex, B);
- }
- return Error::success();
- }
- template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySymbols() {
- LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
- // No SYMTAB -- Bail out early.
- if (!SymTabSec)
- return Error::success();
- // Get the section content as a Symbols array.
- auto Symbols = Obj.symbols(SymTabSec);
- if (!Symbols)
- return Symbols.takeError();
- // Get the string table for this section.
- auto StringTab = Obj.getStringTableForSymtab(*SymTabSec, Sections);
- if (!StringTab)
- return StringTab.takeError();
- LLVM_DEBUG({
- StringRef SymTabName;
- if (auto SymTabNameOrErr = Obj.getSectionName(*SymTabSec, SectionStringTab))
- SymTabName = *SymTabNameOrErr;
- else {
- dbgs() << "Could not get ELF SHT_SYMTAB section name for logging: "
- << toString(SymTabNameOrErr.takeError()) << "\n";
- SymTabName = "<SHT_SYMTAB section with invalid name>";
- }
- dbgs() << " Adding symbols from symtab section \"" << SymTabName
- << "\"\n";
- });
- for (ELFSymbolIndex SymIndex = 0; SymIndex != Symbols->size(); ++SymIndex) {
- auto &Sym = (*Symbols)[SymIndex];
- // Check symbol type.
- switch (Sym.getType()) {
- case ELF::STT_FILE:
- LLVM_DEBUG({
- if (auto Name = Sym.getName(*StringTab))
- dbgs() << " " << SymIndex << ": Skipping STT_FILE symbol \""
- << *Name << "\"\n";
- else {
- dbgs() << "Could not get STT_FILE symbol name: "
- << toString(Name.takeError()) << "\n";
- dbgs() << " " << SymIndex
- << ": Skipping STT_FILE symbol with invalid name\n";
- }
- });
- continue;
- break;
- }
- // Get the symbol name.
- auto Name = Sym.getName(*StringTab);
- if (!Name)
- return Name.takeError();
- // Handle common symbols specially.
- if (Sym.isCommon()) {
- Symbol &GSym = G->addDefinedSymbol(
- G->createZeroFillBlock(getCommonSection(), Sym.st_size,
- orc::ExecutorAddr(), Sym.getValue(), 0),
- 0, *Name, Sym.st_size, Linkage::Strong, Scope::Default, false, false);
- setGraphSymbol(SymIndex, GSym);
- continue;
- }
- if (Sym.isDefined() &&
- (Sym.getType() == ELF::STT_NOTYPE || Sym.getType() == ELF::STT_FUNC ||
- Sym.getType() == ELF::STT_OBJECT ||
- Sym.getType() == ELF::STT_SECTION || Sym.getType() == ELF::STT_TLS)) {
- // Map Visibility and Binding to Scope and Linkage:
- Linkage L;
- Scope S;
- if (auto LSOrErr = getSymbolLinkageAndScope(Sym, *Name))
- std::tie(L, S) = *LSOrErr;
- else
- return LSOrErr.takeError();
- // Handle extended tables.
- unsigned Shndx = Sym.st_shndx;
- if (Shndx == ELF::SHN_XINDEX) {
- auto ShndxTable = ShndxTables.find(SymTabSec);
- if (ShndxTable == ShndxTables.end())
- continue;
- auto NdxOrErr = object::getExtendedSymbolTableIndex<ELFT>(
- Sym, SymIndex, ShndxTable->second);
- if (!NdxOrErr)
- return NdxOrErr.takeError();
- Shndx = *NdxOrErr;
- }
- if (auto *B = getGraphBlock(Shndx)) {
- LLVM_DEBUG({
- dbgs() << " " << SymIndex
- << ": Creating defined graph symbol for ELF symbol \"" << *Name
- << "\"\n";
- });
- // In RISCV, temporary symbols (Used to generate dwarf, eh_frame
- // sections...) will appear in object code's symbol table, and LLVM does
- // not use names on these temporary symbols (RISCV gnu toolchain uses
- // names on these temporary symbols). If the symbol is unnamed, add an
- // anonymous symbol.
- auto &GSym =
- Name->empty()
- ? G->addAnonymousSymbol(*B, Sym.getValue(), Sym.st_size,
- false, false)
- : G->addDefinedSymbol(*B, Sym.getValue(), *Name, Sym.st_size, L,
- S, Sym.getType() == ELF::STT_FUNC, false);
- setGraphSymbol(SymIndex, GSym);
- }
- } else if (Sym.isUndefined() && Sym.isExternal()) {
- LLVM_DEBUG({
- dbgs() << " " << SymIndex
- << ": Creating external graph symbol for ELF symbol \"" << *Name
- << "\"\n";
- });
- if (Sym.getBinding() != ELF::STB_GLOBAL &&
- Sym.getBinding() != ELF::STB_WEAK)
- return make_error<StringError>(
- "Invalid symbol binding " +
- Twine(static_cast<int>(Sym.getBinding())) +
- " for external symbol " + *Name,
- inconvertibleErrorCode());
- // If L is Linkage::Weak that means this is a weakly referenced symbol.
- auto &GSym = G->addExternalSymbol(*Name, Sym.st_size,
- Sym.getBinding() == ELF::STB_WEAK);
- setGraphSymbol(SymIndex, GSym);
- } else {
- LLVM_DEBUG({
- dbgs() << " " << SymIndex
- << ": Not creating graph symbol for ELF symbol \"" << *Name
- << "\" with unrecognized type\n";
- });
- }
- }
- return Error::success();
- }
- template <typename ELFT>
- template <typename RelocHandlerFunction>
- Error ELFLinkGraphBuilder<ELFT>::forEachRelaRelocation(
- const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
- bool ProcessDebugSections) {
- // Only look into sections that store relocation entries.
- if (RelSect.sh_type != ELF::SHT_RELA)
- return Error::success();
- // sh_info contains the section header index of the target (FixupSection),
- // which is the section to which all relocations in RelSect apply.
- auto FixupSection = Obj.getSection(RelSect.sh_info);
- if (!FixupSection)
- return FixupSection.takeError();
- // Target sections have names in valid ELF object files.
- Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
- if (!Name)
- return Name.takeError();
- LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
- // Consider skipping these relocations.
- if (!ProcessDebugSections && isDwarfSection(*Name)) {
- LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
- return Error::success();
- }
- // Lookup the link-graph node corresponding to the target section name.
- auto *BlockToFix = getGraphBlock(RelSect.sh_info);
- if (!BlockToFix)
- return make_error<StringError>(
- "Refencing a section that wasn't added to the graph: " + *Name,
- inconvertibleErrorCode());
- auto RelEntries = Obj.relas(RelSect);
- if (!RelEntries)
- return RelEntries.takeError();
- // Let the callee process relocation entries one by one.
- for (const typename ELFT::Rela &R : *RelEntries)
- if (Error Err = Func(R, **FixupSection, *BlockToFix))
- return Err;
- LLVM_DEBUG(dbgs() << "\n");
- return Error::success();
- }
- template <typename ELFT>
- template <typename RelocHandlerFunction>
- Error ELFLinkGraphBuilder<ELFT>::forEachRelRelocation(
- const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
- bool ProcessDebugSections) {
- // Only look into sections that store relocation entries.
- if (RelSect.sh_type != ELF::SHT_REL)
- return Error::success();
- // sh_info contains the section header index of the target (FixupSection),
- // which is the section to which all relocations in RelSect apply.
- auto FixupSection = Obj.getSection(RelSect.sh_info);
- if (!FixupSection)
- return FixupSection.takeError();
- // Target sections have names in valid ELF object files.
- Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
- if (!Name)
- return Name.takeError();
- LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
- // Consider skipping these relocations.
- if (!ProcessDebugSections && isDwarfSection(*Name)) {
- LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
- return Error::success();
- }
- // Lookup the link-graph node corresponding to the target section name.
- auto *BlockToFix = getGraphBlock(RelSect.sh_info);
- if (!BlockToFix)
- return make_error<StringError>(
- "Refencing a section that wasn't added to the graph: " + *Name,
- inconvertibleErrorCode());
- auto RelEntries = Obj.rels(RelSect);
- if (!RelEntries)
- return RelEntries.takeError();
- // Let the callee process relocation entries one by one.
- for (const typename ELFT::Rel &R : *RelEntries)
- if (Error Err = Func(R, **FixupSection, *BlockToFix))
- return Err;
- LLVM_DEBUG(dbgs() << "\n");
- return Error::success();
- }
- } // end namespace jitlink
- } // end namespace llvm
- #undef DEBUG_TYPE
- #endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
|