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/ADT/StringMap.h"
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/Object/COFF.h"
20
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 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
42
getGraph()43 LinkGraph &getGraph() const { return *G; }
44
getObject()45 const object::COFFObjectFile &getObject() const { return Obj; }
46
47 virtual Error addRelocations() = 0;
48
49 Error graphifySections();
50 Error graphifySymbols();
51
setGraphSymbol(COFFSectionIndex SecIndex,COFFSymbolIndex SymIndex,Symbol & Sym)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(SecIndex))
57 SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym});
58 }
59
getGraphSymbol(COFFSymbolIndex SymIndex)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
setGraphBlock(COFFSectionIndex SecIndex,Block * B)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
getGraphBlock(COFFSectionIndex SecIndex)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
sections()80 object::COFFObjectFile::section_iterator_range sections() const {
81 return Obj.sections();
82 }
83
84 /// Traverse all matching relocation records in the given section. The handler
85 /// function Func should be callable with this signature:
86 /// Error(const object::RelocationRef&,
87 /// const object::SectionRef&, Section &)
88 ///
89 template <typename RelocHandlerFunction>
90 Error forEachRelocation(const object::SectionRef &RelSec,
91 RelocHandlerFunction &&Func,
92 bool ProcessDebugSections = false);
93
94 /// Traverse all matching relocation records in the given section. Convenience
95 /// wrapper to allow passing a member function for the handler.
96 ///
97 template <typename ClassT, typename RelocHandlerMethod>
98 Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance,
99 RelocHandlerMethod &&Method,
100 bool ProcessDebugSections = false) {
101 return forEachRelocation(
102 RelSec,
103 [Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
104 return (Instance->*Method)(Rel, Target, GS);
105 },
106 ProcessDebugSections);
107 }
108
109 private:
110 // Pending comdat symbol export that is initiated by the first symbol of
111 // COMDAT sequence.
112 struct ComdatExportRequest {
113 COFFSymbolIndex SymbolIndex;
114 jitlink::Linkage Linkage;
115 };
116 std::vector<Optional<ComdatExportRequest>> PendingComdatExports;
117
118 // This represents a pending request to create a weak external symbol with a
119 // name.
120 struct WeakExternalRequest {
121 COFFSymbolIndex Alias;
122 COFFSymbolIndex Target;
123 uint32_t Characteristics;
124 StringRef SymbolName;
125 };
126 std::vector<WeakExternalRequest> WeakExternalRequests;
127
128 // Per COFF section jitlink symbol set sorted by offset.
129 // Used for calculating implicit size of defined symbols.
130 using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>;
131 std::vector<SymbolSet> SymbolSets;
132
133 Section &getCommonSection();
134
135 Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
136 StringRef SymbolName,
137 object::COFFSymbolRef Symbol,
138 const object::coff_section *Section);
139 Expected<Symbol *> createCOMDATExportRequest(
140 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,
141 const object::coff_aux_section_definition *Definition);
142 Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
143 StringRef SymbolName,
144 object::COFFSymbolRef Symbol);
145 Error flushWeakAliasRequests();
146 Error calculateImplicitSizeOfSymbols();
147
148 static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
149 const object::coff_section *Section);
150 static uint64_t getSectionSize(const object::COFFObjectFile &Obj,
151 const object::coff_section *Section);
152 static bool isComdatSection(const object::coff_section *Section);
153 static unsigned getPointerSize(const object::COFFObjectFile &Obj);
154 static support::endianness getEndianness(const object::COFFObjectFile &Obj);
155 StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
156 const object::coff_section *Sec,
157 object::COFFSymbolRef Sym);
158
159 const object::COFFObjectFile &Obj;
160 std::unique_ptr<LinkGraph> G;
161
162 Section *CommonSection = nullptr;
163 std::vector<Block *> GraphBlocks;
164 std::vector<Symbol *> GraphSymbols;
165
166 DenseMap<StringRef, Symbol *> ExternalSymbols;
167 };
168
169 template <typename RelocHandlerFunction>
forEachRelocation(const object::SectionRef & RelSec,RelocHandlerFunction && Func,bool ProcessDebugSections)170 Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec,
171 RelocHandlerFunction &&Func,
172 bool ProcessDebugSections) {
173
174 auto COFFRelSect = Obj.getCOFFSection(RelSec);
175
176 // Target sections have names in valid COFF object files.
177 Expected<StringRef> Name = Obj.getSectionName(COFFRelSect);
178 if (!Name)
179 return Name.takeError();
180 LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
181
182 // Lookup the link-graph node corresponding to the target section name.
183 auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1);
184 if (!BlockToFix)
185 return make_error<StringError>(
186 "Referencing a section that wasn't added to the graph: " + *Name,
187 inconvertibleErrorCode());
188
189 // Let the callee process relocation entries one by one.
190 for (const auto &R : RelSec.relocations())
191 if (Error Err = Func(R, RelSec, *BlockToFix))
192 return Err;
193
194 LLVM_DEBUG(dbgs() << "\n");
195 return Error::success();
196 }
197
198 } // end namespace jitlink
199 } // end namespace llvm
200
201 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
202