| 1 | //===----- COFFLinkGraphBuilder.h - COFF LinkGraph builder ----*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Generic COFF LinkGraph building code. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |
| 14 | #define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |
| 15 | |
| 16 | #include "llvm/ADT/DenseMap.h" |
| 17 | #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
| 18 | #include "llvm/Object/COFF.h" |
| 19 | |
| 20 | #include "COFFDirectiveParser.h" |
| 21 | #include "EHFrameSupportImpl.h" |
| 22 | #include "JITLinkGeneric.h" |
| 23 | |
| 24 | #define DEBUG_TYPE "jitlink" |
| 25 | |
| 26 | namespace llvm { |
| 27 | namespace jitlink { |
| 28 | |
| 29 | class COFFLinkGraphBuilder { |
| 30 | public: |
| 31 | virtual ~COFFLinkGraphBuilder(); |
| 32 | Expected<std::unique_ptr<LinkGraph>> buildGraph(); |
| 33 | |
| 34 | protected: |
| 35 | using COFFSectionIndex = int32_t; |
| 36 | using COFFSymbolIndex = int32_t; |
| 37 | |
| 38 | COFFLinkGraphBuilder(const object::COFFObjectFile &Obj, |
| 39 | std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT, |
| 40 | SubtargetFeatures Features, |
| 41 | LinkGraph::GetEdgeKindNameFunction GetEdgeKindName); |
| 42 | |
| 43 | LinkGraph &getGraph() const { return *G; } |
| 44 | |
| 45 | const object::COFFObjectFile &getObject() const { return Obj; } |
| 46 | |
| 47 | virtual Error addRelocations() = 0; |
| 48 | |
| 49 | Error graphifySections(); |
| 50 | Error graphifySymbols(); |
| 51 | |
| 52 | void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex, |
| 53 | Symbol &Sym) { |
| 54 | assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index" ); |
| 55 | GraphSymbols[SymIndex] = &Sym; |
| 56 | if (!COFF::isReservedSectionNumber(SectionNumber: SecIndex)) |
| 57 | SymbolSets[SecIndex].insert(x: {Sym.getOffset(), &Sym}); |
| 58 | } |
| 59 | |
| 60 | Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const { |
| 61 | if (SymIndex < 0 || |
| 62 | SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size())) |
| 63 | return nullptr; |
| 64 | return GraphSymbols[SymIndex]; |
| 65 | } |
| 66 | |
| 67 | void setGraphBlock(COFFSectionIndex SecIndex, Block *B) { |
| 68 | assert(!GraphBlocks[SecIndex] && "Duplicate section at index" ); |
| 69 | assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index" ); |
| 70 | GraphBlocks[SecIndex] = B; |
| 71 | } |
| 72 | |
| 73 | Block *getGraphBlock(COFFSectionIndex SecIndex) const { |
| 74 | if (SecIndex <= 0 || |
| 75 | SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size())) |
| 76 | return nullptr; |
| 77 | return GraphBlocks[SecIndex]; |
| 78 | } |
| 79 | |
| 80 | Symbol &addImageBaseSymbol(StringRef Name = "__ImageBase" ) { |
| 81 | auto &ImageBase = G->addExternalSymbol(Name: G->intern(SymbolName: Name), Size: 0, IsWeaklyReferenced: true); |
| 82 | ImageBase.setLive(true); |
| 83 | return ImageBase; |
| 84 | } |
| 85 | |
| 86 | object::COFFObjectFile::section_iterator_range sections() const { |
| 87 | return Obj.sections(); |
| 88 | } |
| 89 | |
| 90 | /// Traverse all matching relocation records in the given section. The handler |
| 91 | /// function Func should be callable with this signature: |
| 92 | /// Error(const object::RelocationRef&, |
| 93 | /// const object::SectionRef&, Section &) |
| 94 | /// |
| 95 | template <typename RelocHandlerFunction> |
| 96 | Error forEachRelocation(const object::SectionRef &RelSec, |
| 97 | RelocHandlerFunction &&Func, |
| 98 | bool ProcessDebugSections = false); |
| 99 | |
| 100 | /// Traverse all matching relocation records in the given section. Convenience |
| 101 | /// wrapper to allow passing a member function for the handler. |
| 102 | /// |
| 103 | template <typename ClassT, typename RelocHandlerMethod> |
| 104 | Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance, |
| 105 | RelocHandlerMethod &&Method, |
| 106 | bool ProcessDebugSections = false) { |
| 107 | return forEachRelocation( |
| 108 | RelSec, |
| 109 | [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { |
| 110 | return (Instance->*Method)(Rel, Target, GS); |
| 111 | }, |
| 112 | ProcessDebugSections); |
| 113 | } |
| 114 | |
| 115 | private: |
| 116 | // Pending comdat symbol export that is initiated by the first symbol of |
| 117 | // COMDAT sequence. |
| 118 | struct ComdatExportRequest { |
| 119 | COFFSymbolIndex SymbolIndex; |
| 120 | jitlink::Linkage Linkage; |
| 121 | orc::ExecutorAddrDiff Size; |
| 122 | }; |
| 123 | std::vector<std::optional<ComdatExportRequest>> PendingComdatExports; |
| 124 | |
| 125 | // This represents a pending request to create a weak external symbol with a |
| 126 | // name. |
| 127 | struct WeakExternalRequest { |
| 128 | COFFSymbolIndex Alias; |
| 129 | COFFSymbolIndex Target; |
| 130 | uint32_t Characteristics; |
| 131 | StringRef SymbolName; |
| 132 | }; |
| 133 | std::vector<WeakExternalRequest> WeakExternalRequests; |
| 134 | |
| 135 | // Per COFF section jitlink symbol set sorted by offset. |
| 136 | // Used for calculating implicit size of defined symbols. |
| 137 | using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>; |
| 138 | std::vector<SymbolSet> SymbolSets; |
| 139 | |
| 140 | Section &getCommonSection(); |
| 141 | |
| 142 | Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, |
| 143 | orc::SymbolStringPtr SymbolName, |
| 144 | object::COFFSymbolRef Symbol, |
| 145 | const object::coff_section *Section); |
| 146 | Expected<Symbol *> createAliasSymbol(orc::SymbolStringPtr SymbolName, |
| 147 | Linkage L, Scope S, Symbol &Target); |
| 148 | Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, |
| 149 | orc::SymbolStringPtr SymbolName, |
| 150 | object::COFFSymbolRef Symbol, |
| 151 | const object::coff_section *Section); |
| 152 | Expected<Symbol *> createCOMDATExportRequest( |
| 153 | COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, |
| 154 | const object::coff_aux_section_definition *Definition); |
| 155 | Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex, |
| 156 | orc::SymbolStringPtr SymbolName, |
| 157 | object::COFFSymbolRef Symbol); |
| 158 | |
| 159 | Error handleDirectiveSection(StringRef Str); |
| 160 | Error flushWeakAliasRequests(); |
| 161 | Error handleAlternateNames(); |
| 162 | Error calculateImplicitSizeOfSymbols(); |
| 163 | |
| 164 | static uint64_t getSectionAddress(const object::COFFObjectFile &Obj, |
| 165 | const object::coff_section *Section); |
| 166 | static uint64_t getSectionSize(const object::COFFObjectFile &Obj, |
| 167 | const object::coff_section *Section); |
| 168 | static bool isComdatSection(const object::coff_section *Section); |
| 169 | static unsigned getPointerSize(const object::COFFObjectFile &Obj); |
| 170 | static llvm::endianness getEndianness(const object::COFFObjectFile &Obj); |
| 171 | static StringRef getDLLImportStubPrefix() { return "__imp_" ; } |
| 172 | static StringRef getDirectiveSectionName() { return ".drectve" ; } |
| 173 | StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, |
| 174 | const object::coff_section *Sec, |
| 175 | object::COFFSymbolRef Sym); |
| 176 | |
| 177 | const object::COFFObjectFile &Obj; |
| 178 | std::unique_ptr<LinkGraph> G; |
| 179 | COFFDirectiveParser DirectiveParser; |
| 180 | |
| 181 | Section *CommonSection = nullptr; |
| 182 | std::vector<Block *> GraphBlocks; |
| 183 | std::vector<Symbol *> GraphSymbols; |
| 184 | |
| 185 | DenseMap<orc::SymbolStringPtr, orc::SymbolStringPtr> AlternateNames; |
| 186 | DenseMap<orc::SymbolStringPtr, Symbol *> ExternalSymbols; |
| 187 | DenseMap<orc::SymbolStringPtr, Symbol *> DefinedSymbols; |
| 188 | }; |
| 189 | |
| 190 | template <typename RelocHandlerFunction> |
| 191 | Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec, |
| 192 | RelocHandlerFunction &&Func, |
| 193 | bool ProcessDebugSections) { |
| 194 | |
| 195 | auto COFFRelSect = Obj.getCOFFSection(Section: RelSec); |
| 196 | |
| 197 | // Target sections have names in valid COFF object files. |
| 198 | Expected<StringRef> Name = Obj.getSectionName(Sec: COFFRelSect); |
| 199 | if (!Name) |
| 200 | return Name.takeError(); |
| 201 | |
| 202 | // Skip the unhandled metadata sections. |
| 203 | if (*Name == ".voltbl" ) |
| 204 | return Error::success(); |
| 205 | LLVM_DEBUG(dbgs() << " " << *Name << ":\n" ); |
| 206 | |
| 207 | // Lookup the link-graph node corresponding to the target section name. |
| 208 | auto *BlockToFix = getGraphBlock(SecIndex: RelSec.getIndex() + 1); |
| 209 | if (!BlockToFix) |
| 210 | return make_error<StringError>( |
| 211 | Args: "Referencing a section that wasn't added to the graph: " + *Name, |
| 212 | Args: inconvertibleErrorCode()); |
| 213 | |
| 214 | // Let the callee process relocation entries one by one. |
| 215 | for (const auto &R : RelSec.relocations()) |
| 216 | if (Error Err = Func(R, RelSec, *BlockToFix)) |
| 217 | return Err; |
| 218 | |
| 219 | LLVM_DEBUG(dbgs() << "\n" ); |
| 220 | return Error::success(); |
| 221 | } |
| 222 | |
| 223 | class GetImageBaseSymbol { |
| 224 | public: |
| 225 | GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase" ) |
| 226 | : ImageBaseName(ImageBaseName) {} |
| 227 | Symbol *operator()(LinkGraph &G); |
| 228 | void reset() { ImageBase = std::nullopt; } |
| 229 | |
| 230 | private: |
| 231 | StringRef ImageBaseName; |
| 232 | std::optional<Symbol *> ImageBase; |
| 233 | }; |
| 234 | |
| 235 | } // end namespace jitlink |
| 236 | } // end namespace llvm |
| 237 | |
| 238 | #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H |
| 239 | |