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