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
28namespace llvm {
29namespace jitlink {
30
31class COFFLinkGraphBuilder {
32public:
33 virtual ~COFFLinkGraphBuilder();
34 Expected<std::unique_ptr<LinkGraph>> buildGraph();
35
36protected:
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
117private:
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
192template <typename RelocHandlerFunction>
193Error 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
225class GetImageBaseSymbol {
226public:
227 GetImageBaseSymbol(StringRef ImageBaseName = "__ImageBase")
228 : ImageBaseName(ImageBaseName) {}
229 Symbol *operator()(LinkGraph &G);
230 void reset() { ImageBase = std::nullopt; }
231
232private:
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