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