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(SectionNumber: SecIndex)) |
59 | SymbolSets[SecIndex].insert(x: {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(Name: G->intern(SymbolName: Name), Size: 0, IsWeaklyReferenced: 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(Section: RelSec); |
198 | |
199 | // Target sections have names in valid COFF object files. |
200 | Expected<StringRef> Name = Obj.getSectionName(Sec: 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(SecIndex: RelSec.getIndex() + 1); |
211 | if (!BlockToFix) |
212 | return make_error<StringError>( |
213 | Args: "Referencing a section that wasn't added to the graph: " + *Name, |
214 | Args: 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 | |