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(SectionNumber: SecIndex)) |
58 | SymbolSets[SecIndex].insert(x: {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(Section: RelSec); |
190 | |
191 | // Target sections have names in valid COFF object files. |
192 | Expected<StringRef> Name = Obj.getSectionName(Sec: 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(SecIndex: RelSec.getIndex() + 1); |
203 | if (!BlockToFix) |
204 | return make_error<StringError>( |
205 | Args: "Referencing a section that wasn't added to the graph: " + *Name, |
206 | Args: 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 | |