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