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, 41 std::shared_ptr<orc::SymbolStringPool> SSP, 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 Symbol &addImageBaseSymbol(StringRef Name = "__ImageBase") { 83 auto &ImageBase = G->addExternalSymbol(G->intern(Name), 0, true); 84 ImageBase.setLive(true); 85 return ImageBase; 86 } 87 88 object::COFFObjectFile::section_iterator_range sections() const { 89 return Obj.sections(); 90 } 91 92 /// Traverse all matching relocation records in the given section. The handler 93 /// function Func should be callable with this signature: 94 /// Error(const object::RelocationRef&, 95 /// const object::SectionRef&, Section &) 96 /// 97 template <typename RelocHandlerFunction> 98 Error forEachRelocation(const object::SectionRef &RelSec, 99 RelocHandlerFunction &&Func, 100 bool ProcessDebugSections = false); 101 102 /// Traverse all matching relocation records in the given section. Convenience 103 /// wrapper to allow passing a member function for the handler. 104 /// 105 template <typename ClassT, typename RelocHandlerMethod> 106 Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance, 107 RelocHandlerMethod &&Method, 108 bool ProcessDebugSections = false) { 109 return forEachRelocation( 110 RelSec, 111 [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { 112 return (Instance->*Method)(Rel, Target, GS); 113 }, 114 ProcessDebugSections); 115 } 116 117 private: 118 // Pending comdat symbol export that is initiated by the first symbol of 119 // COMDAT sequence. 120 struct ComdatExportRequest { 121 COFFSymbolIndex SymbolIndex; 122 jitlink::Linkage Linkage; 123 orc::ExecutorAddrDiff Size; 124 }; 125 std::vector<std::optional<ComdatExportRequest>> PendingComdatExports; 126 127 // This represents a pending request to create a weak external symbol with a 128 // name. 129 struct WeakExternalRequest { 130 COFFSymbolIndex Alias; 131 COFFSymbolIndex Target; 132 uint32_t Characteristics; 133 StringRef SymbolName; 134 }; 135 std::vector<WeakExternalRequest> WeakExternalRequests; 136 137 // Per COFF section jitlink symbol set sorted by offset. 138 // Used for calculating implicit size of defined symbols. 139 using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>; 140 std::vector<SymbolSet> SymbolSets; 141 142 Section &getCommonSection(); 143 144 Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, 145 orc::SymbolStringPtr SymbolName, 146 object::COFFSymbolRef Symbol, 147 const object::coff_section *Section); 148 Expected<Symbol *> createAliasSymbol(orc::SymbolStringPtr SymbolName, 149 Linkage L, Scope S, Symbol &Target); 150 Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, 151 orc::SymbolStringPtr SymbolName, 152 object::COFFSymbolRef Symbol, 153 const object::coff_section *Section); 154 Expected<Symbol *> createCOMDATExportRequest( 155 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 156 const object::coff_aux_section_definition *Definition); 157 Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex, 158 orc::SymbolStringPtr SymbolName, 159 object::COFFSymbolRef Symbol); 160 161 Error handleDirectiveSection(StringRef Str); 162 Error flushWeakAliasRequests(); 163 Error handleAlternateNames(); 164 Error calculateImplicitSizeOfSymbols(); 165 166 static uint64_t getSectionAddress(const object::COFFObjectFile &Obj, 167 const object::coff_section *Section); 168 static uint64_t getSectionSize(const object::COFFObjectFile &Obj, 169 const object::coff_section *Section); 170 static bool isComdatSection(const object::coff_section *Section); 171 static unsigned getPointerSize(const object::COFFObjectFile &Obj); 172 static llvm::endianness getEndianness(const object::COFFObjectFile &Obj); 173 static StringRef getDLLImportStubPrefix() { return "__imp_"; } 174 static StringRef getDirectiveSectionName() { return ".drectve"; } 175 StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, 176 const object::coff_section *Sec, 177 object::COFFSymbolRef Sym); 178 179 const object::COFFObjectFile &Obj; 180 std::unique_ptr<LinkGraph> G; 181 COFFDirectiveParser DirectiveParser; 182 183 Section *CommonSection = nullptr; 184 std::vector<Block *> GraphBlocks; 185 std::vector<Symbol *> GraphSymbols; 186 187 DenseMap<orc::SymbolStringPtr, orc::SymbolStringPtr> AlternateNames; 188 DenseMap<orc::SymbolStringPtr, Symbol *> ExternalSymbols; 189 DenseMap<orc::SymbolStringPtr, Symbol *> DefinedSymbols; 190 }; 191 192 template <typename RelocHandlerFunction> 193 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec, 194 RelocHandlerFunction &&Func, 195 bool ProcessDebugSections) { 196 197 auto COFFRelSect = Obj.getCOFFSection(RelSec); 198 199 // Target sections have names in valid COFF object files. 200 Expected<StringRef> Name = Obj.getSectionName(COFFRelSect); 201 if (!Name) 202 return Name.takeError(); 203 204 // Skip the unhandled metadata sections. 205 if (*Name == ".voltbl") 206 return Error::success(); 207 LLVM_DEBUG(dbgs() << " " << *Name << ":\n"); 208 209 // Lookup the link-graph node corresponding to the target section name. 210 auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1); 211 if (!BlockToFix) 212 return make_error<StringError>( 213 "Referencing a section that wasn't added to the graph: " + *Name, 214 inconvertibleErrorCode()); 215 216 // Let the callee process relocation entries one by one. 217 for (const auto &R : RelSec.relocations()) 218 if (Error Err = Func(R, RelSec, *BlockToFix)) 219 return Err; 220 221 LLVM_DEBUG(dbgs() << "\n"); 222 return Error::success(); 223 } 224 225 class GetImageBaseSymbol { 226 public: 227 GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase") 228 : ImageBaseName(ImageBaseName) {} 229 Symbol *operator()(LinkGraph &G); 230 void reset() { ImageBase = std::nullopt; } 231 232 private: 233 StringRef ImageBaseName; 234 std::optional<Symbol *> ImageBase; 235 }; 236 237 } // end namespace jitlink 238 } // end namespace llvm 239 240 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H 241