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, 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
110private:
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
184template <typename RelocHandlerFunction>
185Error 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