| //===----- COFFLinkGraphBuilder.h - COFF 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 COFF LinkGraph building code. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |
| #define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
| #include "llvm/Object/COFF.h" |
| |
| #include "COFFDirectiveParser.h" |
| #include "EHFrameSupportImpl.h" |
| #include "JITLinkGeneric.h" |
| |
| #define DEBUG_TYPE "jitlink" |
| |
| #include <list> |
| |
| namespace llvm { |
| namespace jitlink { |
| |
| class COFFLinkGraphBuilder { |
| public: |
| virtual ~COFFLinkGraphBuilder(); |
| Expected<std::unique_ptr<LinkGraph>> buildGraph(); |
| |
| protected: |
| using COFFSectionIndex = int32_t; |
| using COFFSymbolIndex = int32_t; |
| |
| COFFLinkGraphBuilder(const object::COFFObjectFile &Obj, Triple TT, |
| LinkGraph::GetEdgeKindNameFunction GetEdgeKindName); |
| |
| LinkGraph &getGraph() const { return *G; } |
| |
| const object::COFFObjectFile &getObject() const { return Obj; } |
| |
| virtual Error addRelocations() = 0; |
| |
| Error graphifySections(); |
| Error graphifySymbols(); |
| |
| void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex, |
| Symbol &Sym) { |
| assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index"); |
| GraphSymbols[SymIndex] = &Sym; |
| if (!COFF::isReservedSectionNumber(SecIndex)) |
| SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym}); |
| } |
| |
| Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const { |
| if (SymIndex < 0 || |
| SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size())) |
| return nullptr; |
| return GraphSymbols[SymIndex]; |
| } |
| |
| void setGraphBlock(COFFSectionIndex SecIndex, Block *B) { |
| assert(!GraphBlocks[SecIndex] && "Duplicate section at index"); |
| assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index"); |
| GraphBlocks[SecIndex] = B; |
| } |
| |
| Block *getGraphBlock(COFFSectionIndex SecIndex) const { |
| if (SecIndex <= 0 || |
| SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size())) |
| return nullptr; |
| return GraphBlocks[SecIndex]; |
| } |
| |
| object::COFFObjectFile::section_iterator_range sections() const { |
| return Obj.sections(); |
| } |
| |
| /// Traverse all matching relocation records in the given section. The handler |
| /// function Func should be callable with this signature: |
| /// Error(const object::RelocationRef&, |
| /// const object::SectionRef&, Section &) |
| /// |
| template <typename RelocHandlerFunction> |
| Error forEachRelocation(const object::SectionRef &RelSec, |
| RelocHandlerFunction &&Func, |
| bool ProcessDebugSections = false); |
| |
| /// Traverse all matching relocation records in the given section. Convenience |
| /// wrapper to allow passing a member function for the handler. |
| /// |
| template <typename ClassT, typename RelocHandlerMethod> |
| Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance, |
| RelocHandlerMethod &&Method, |
| bool ProcessDebugSections = false) { |
| return forEachRelocation( |
| RelSec, |
| [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { |
| return (Instance->*Method)(Rel, Target, GS); |
| }, |
| ProcessDebugSections); |
| } |
| |
| private: |
| // Pending comdat symbol export that is initiated by the first symbol of |
| // COMDAT sequence. |
| struct ComdatExportRequest { |
| COFFSymbolIndex SymbolIndex; |
| jitlink::Linkage Linkage; |
| orc::ExecutorAddrDiff Size; |
| }; |
| std::vector<std::optional<ComdatExportRequest>> PendingComdatExports; |
| |
| // This represents a pending request to create a weak external symbol with a |
| // name. |
| struct WeakExternalRequest { |
| COFFSymbolIndex Alias; |
| COFFSymbolIndex Target; |
| uint32_t Characteristics; |
| StringRef SymbolName; |
| }; |
| std::vector<WeakExternalRequest> WeakExternalRequests; |
| |
| // Per COFF section jitlink symbol set sorted by offset. |
| // Used for calculating implicit size of defined symbols. |
| using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>; |
| std::vector<SymbolSet> SymbolSets; |
| |
| Section &getCommonSection(); |
| |
| Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, StringRef SymbolName, |
| object::COFFSymbolRef Symbol, |
| const object::coff_section *Section); |
| Expected<Symbol *> createAliasSymbol(StringRef SymbolName, Linkage L, Scope S, |
| Symbol &Target); |
| Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, |
| StringRef SymbolName, |
| object::COFFSymbolRef Symbol, |
| const object::coff_section *Section); |
| Expected<Symbol *> createCOMDATExportRequest( |
| COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, |
| const object::coff_aux_section_definition *Definition); |
| Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex, |
| StringRef SymbolName, |
| object::COFFSymbolRef Symbol); |
| |
| Error handleDirectiveSection(StringRef Str); |
| Error flushWeakAliasRequests(); |
| Error handleAlternateNames(); |
| Error calculateImplicitSizeOfSymbols(); |
| |
| static uint64_t getSectionAddress(const object::COFFObjectFile &Obj, |
| const object::coff_section *Section); |
| static uint64_t getSectionSize(const object::COFFObjectFile &Obj, |
| const object::coff_section *Section); |
| static bool isComdatSection(const object::coff_section *Section); |
| static unsigned getPointerSize(const object::COFFObjectFile &Obj); |
| static support::endianness getEndianness(const object::COFFObjectFile &Obj); |
| static StringRef getDLLImportStubPrefix() { return "__imp_"; } |
| static StringRef getDirectiveSectionName() { return ".drectve"; } |
| StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, |
| const object::coff_section *Sec, |
| object::COFFSymbolRef Sym); |
| |
| const object::COFFObjectFile &Obj; |
| std::unique_ptr<LinkGraph> G; |
| COFFDirectiveParser DirectiveParser; |
| |
| Section *CommonSection = nullptr; |
| std::vector<Block *> GraphBlocks; |
| std::vector<Symbol *> GraphSymbols; |
| |
| DenseMap<StringRef, StringRef> AlternateNames; |
| DenseMap<StringRef, Symbol *> ExternalSymbols; |
| DenseMap<StringRef, Symbol *> DefinedSymbols; |
| }; |
| |
| template <typename RelocHandlerFunction> |
| Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec, |
| RelocHandlerFunction &&Func, |
| bool ProcessDebugSections) { |
| |
| auto COFFRelSect = Obj.getCOFFSection(RelSec); |
| |
| // Target sections have names in valid COFF object files. |
| Expected<StringRef> Name = Obj.getSectionName(COFFRelSect); |
| if (!Name) |
| return Name.takeError(); |
| LLVM_DEBUG(dbgs() << " " << *Name << ":\n"); |
| |
| // Lookup the link-graph node corresponding to the target section name. |
| auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1); |
| if (!BlockToFix) |
| return make_error<StringError>( |
| "Referencing a section that wasn't added to the graph: " + *Name, |
| inconvertibleErrorCode()); |
| |
| // Let the callee process relocation entries one by one. |
| for (const auto &R : RelSec.relocations()) |
| if (Error Err = Func(R, RelSec, *BlockToFix)) |
| return Err; |
| |
| LLVM_DEBUG(dbgs() << "\n"); |
| return Error::success(); |
| } |
| |
| } // end namespace jitlink |
| } // end namespace llvm |
| |
| #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |