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 "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 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(SecIndex)) 57 SymbolSets[SecIndex].insert({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 object::COFFObjectFile::section_iterator_range sections() const { 81 return Obj.sections(); 82 } 83 84 /// Traverse all matching relocation records in the given section. The handler 85 /// function Func should be callable with this signature: 86 /// Error(const object::RelocationRef&, 87 /// const object::SectionRef&, Section &) 88 /// 89 template <typename RelocHandlerFunction> 90 Error forEachRelocation(const object::SectionRef &RelSec, 91 RelocHandlerFunction &&Func, 92 bool ProcessDebugSections = false); 93 94 /// Traverse all matching relocation records in the given section. Convenience 95 /// wrapper to allow passing a member function for the handler. 96 /// 97 template <typename ClassT, typename RelocHandlerMethod> 98 Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance, 99 RelocHandlerMethod &&Method, 100 bool ProcessDebugSections = false) { 101 return forEachRelocation( 102 RelSec, 103 [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { 104 return (Instance->*Method)(Rel, Target, GS); 105 }, 106 ProcessDebugSections); 107 } 108 109 private: 110 // Pending comdat symbol export that is initiated by the first symbol of 111 // COMDAT sequence. 112 struct ComdatExportRequest { 113 COFFSymbolIndex SymbolIndex; 114 jitlink::Linkage Linkage; 115 }; 116 std::vector<Optional<ComdatExportRequest>> PendingComdatExports; 117 118 // This represents a pending request to create a weak external symbol with a 119 // name. 120 struct WeakExternalRequest { 121 COFFSymbolIndex Alias; 122 COFFSymbolIndex Target; 123 uint32_t Characteristics; 124 StringRef SymbolName; 125 }; 126 std::vector<WeakExternalRequest> WeakExternalRequests; 127 128 // Per COFF section jitlink symbol set sorted by offset. 129 // Used for calculating implicit size of defined symbols. 130 using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>; 131 std::vector<SymbolSet> SymbolSets; 132 133 Section &getCommonSection(); 134 135 Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, 136 StringRef SymbolName, 137 object::COFFSymbolRef Symbol, 138 const object::coff_section *Section); 139 Expected<Symbol *> createCOMDATExportRequest( 140 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, 141 const object::coff_aux_section_definition *Definition); 142 Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex, 143 StringRef SymbolName, 144 object::COFFSymbolRef Symbol); 145 Error flushWeakAliasRequests(); 146 Error calculateImplicitSizeOfSymbols(); 147 148 static uint64_t getSectionAddress(const object::COFFObjectFile &Obj, 149 const object::coff_section *Section); 150 static uint64_t getSectionSize(const object::COFFObjectFile &Obj, 151 const object::coff_section *Section); 152 static bool isComdatSection(const object::coff_section *Section); 153 static unsigned getPointerSize(const object::COFFObjectFile &Obj); 154 static support::endianness getEndianness(const object::COFFObjectFile &Obj); 155 StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, 156 const object::coff_section *Sec, 157 object::COFFSymbolRef Sym); 158 159 const object::COFFObjectFile &Obj; 160 std::unique_ptr<LinkGraph> G; 161 162 Section *CommonSection = nullptr; 163 std::vector<Block *> GraphBlocks; 164 std::vector<Symbol *> GraphSymbols; 165 166 DenseMap<StringRef, Symbol *> ExternalSymbols; 167 }; 168 169 template <typename RelocHandlerFunction> 170 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec, 171 RelocHandlerFunction &&Func, 172 bool ProcessDebugSections) { 173 174 auto COFFRelSect = Obj.getCOFFSection(RelSec); 175 176 // Target sections have names in valid COFF object files. 177 Expected<StringRef> Name = Obj.getSectionName(COFFRelSect); 178 if (!Name) 179 return Name.takeError(); 180 LLVM_DEBUG(dbgs() << " " << *Name << ":\n"); 181 182 // Lookup the link-graph node corresponding to the target section name. 183 auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1); 184 if (!BlockToFix) 185 return make_error<StringError>( 186 "Referencing a section that wasn't added to the graph: " + *Name, 187 inconvertibleErrorCode()); 188 189 // Let the callee process relocation entries one by one. 190 for (const auto &R : RelSec.relocations()) 191 if (Error Err = Func(R, RelSec, *BlockToFix)) 192 return Err; 193 194 LLVM_DEBUG(dbgs() << "\n"); 195 return Error::success(); 196 } 197 198 } // end namespace jitlink 199 } // end namespace llvm 200 201 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H 202