|  | //===----- 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/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, | 
|  | std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT, | 
|  | SubtargetFeatures Features, | 
|  | 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]; | 
|  | } | 
|  |  | 
|  | Symbol &addImageBaseSymbol(StringRef Name = "__ImageBase") { | 
|  | auto &ImageBase = G->addExternalSymbol(G->intern(Name), 0, true); | 
|  | ImageBase.setLive(true); | 
|  | return ImageBase; | 
|  | } | 
|  |  | 
|  | 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, | 
|  | orc::SymbolStringPtr SymbolName, | 
|  | object::COFFSymbolRef Symbol, | 
|  | const object::coff_section *Section); | 
|  | Expected<Symbol *> createAliasSymbol(orc::SymbolStringPtr SymbolName, | 
|  | Linkage L, Scope S, Symbol &Target); | 
|  | Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, | 
|  | orc::SymbolStringPtr 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, | 
|  | orc::SymbolStringPtr 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 llvm::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<orc::SymbolStringPtr, orc::SymbolStringPtr> AlternateNames; | 
|  | DenseMap<orc::SymbolStringPtr, Symbol *> ExternalSymbols; | 
|  | DenseMap<orc::SymbolStringPtr, 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(); | 
|  |  | 
|  | // Skip the unhandled metadata sections. | 
|  | if (*Name == ".voltbl") | 
|  | return Error::success(); | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | class GetImageBaseSymbol { | 
|  | public: | 
|  | GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase") | 
|  | : ImageBaseName(ImageBaseName) {} | 
|  | Symbol *operator()(LinkGraph &G); | 
|  | void reset() { ImageBase = std::nullopt; } | 
|  |  | 
|  | private: | 
|  | StringRef ImageBaseName; | 
|  | std::optional<Symbol *> ImageBase; | 
|  | }; | 
|  |  | 
|  | } // end namespace jitlink | 
|  | } // end namespace llvm | 
|  |  | 
|  | #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |