1//===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
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// COFF/x86_64 jit-link implementation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
14#include "COFFLinkGraphBuilder.h"
15#include "JITLinkGeneric.h"
16#include "SEHFrameSupport.h"
17#include "llvm/BinaryFormat/COFF.h"
18#include "llvm/ExecutionEngine/JITLink/x86_64.h"
19#include "llvm/Object/COFF.h"
20#include "llvm/Support/Endian.h"
21
22#define DEBUG_TYPE "jitlink"
23
24using namespace llvm;
25using namespace llvm::jitlink;
26
27namespace {
28
29enum EdgeKind_coff_x86_64 : Edge::Kind {
30 PCRel32 = x86_64::FirstPlatformRelocation,
31 Pointer32NB,
32 Pointer64,
33 SectionIdx16,
34 SecRel32,
35};
36
37class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
38 friend class JITLinker<COFFJITLinker_x86_64>;
39
40public:
41 COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
42 std::unique_ptr<LinkGraph> G,
43 PassConfiguration PassConfig)
44 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
45
46private:
47 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
48 return x86_64::applyFixup(G, B, E, GOTSymbol: nullptr);
49 }
50};
51
52class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
53private:
54 Error addRelocations() override {
55 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
56
57 for (const auto &RelSect : sections())
58 if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
59 RelSec: RelSect, Instance: this, Method: &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
60 return Err;
61
62 return Error::success();
63 }
64
65 Error addSingleRelocation(const object::RelocationRef &Rel,
66 const object::SectionRef &FixupSect,
67 Block &BlockToFix) {
68 const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Reloc: Rel);
69 auto SymbolIt = Rel.getSymbol();
70 if (SymbolIt == getObject().symbol_end()) {
71 return make_error<StringError>(
72 Args: formatv(Fmt: "Invalid symbol index in relocation entry. "
73 "index: {0}, section: {1}",
74 Vals: COFFRel->SymbolTableIndex, Vals: FixupSect.getIndex()),
75 Args: inconvertibleErrorCode());
76 }
77
78 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(Symbol: *SymbolIt);
79 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(Symbol: COFFSymbol);
80
81 Symbol *GraphSymbol = getGraphSymbol(SymIndex);
82 if (!GraphSymbol)
83 return make_error<StringError>(
84 Args: formatv(Fmt: "Could not find symbol at given index, did you add it to "
85 "JITSymbolTable? index: {0}, section: {1}",
86 Vals&: SymIndex, Vals: FixupSect.getIndex()),
87 Args: inconvertibleErrorCode());
88
89 int64_t Addend = 0;
90 orc::ExecutorAddr FixupAddress =
91 orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
92 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
93
94 Edge::Kind Kind = Edge::Invalid;
95 const char *FixupPtr = BlockToFix.getContent().data() + Offset;
96 Symbol *ImageBase = GetImageBaseSymbol()(getGraph());
97
98 switch (Rel.getType()) {
99 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
100 if (!ImageBase)
101 ImageBase = &addImageBaseSymbol();
102 Kind = EdgeKind_coff_x86_64::Pointer32NB;
103 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
104 break;
105 }
106 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
107 Kind = EdgeKind_coff_x86_64::PCRel32;
108 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
109 break;
110 }
111 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
112 Kind = EdgeKind_coff_x86_64::PCRel32;
113 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
114 Addend -= 1;
115 break;
116 }
117 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {
118 Kind = EdgeKind_coff_x86_64::PCRel32;
119 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
120 Addend -= 2;
121 break;
122 }
123 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {
124 Kind = EdgeKind_coff_x86_64::PCRel32;
125 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
126 Addend -= 3;
127 break;
128 }
129 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {
130 Kind = EdgeKind_coff_x86_64::PCRel32;
131 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
132 Addend -= 4;
133 break;
134 }
135 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {
136 Kind = EdgeKind_coff_x86_64::PCRel32;
137 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
138 Addend -= 5;
139 break;
140 }
141 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {
142 Kind = EdgeKind_coff_x86_64::Pointer64;
143 Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
144 break;
145 }
146 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {
147 Kind = EdgeKind_coff_x86_64::SectionIdx16;
148 Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
149 uint64_t SectionIdx = 0;
150 if (COFFSymbol.isAbsolute())
151 SectionIdx = getObject().getNumberOfSections() + 1;
152 else
153 SectionIdx = COFFSymbol.getSectionNumber();
154
155 auto *AbsSym = &getGraph().addAbsoluteSymbol(
156 Name: "secidx", Address: orc::ExecutorAddr(SectionIdx), Size: 2, L: Linkage::Strong,
157 S: Scope::Local, IsLive: false);
158 GraphSymbol = AbsSym;
159 break;
160 }
161 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {
162 // FIXME: SECREL to external symbol should be handled
163 if (!GraphSymbol->isDefined())
164 return Error::success();
165 Kind = EdgeKind_coff_x86_64::SecRel32;
166 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
167 break;
168 }
169 default: {
170 return make_error<JITLinkError>(Args: "Unsupported x86_64 relocation:" +
171 formatv(Fmt: "{0:d}", Vals: Rel.getType()));
172 }
173 };
174
175 Edge GE(Kind, Offset, *GraphSymbol, Addend);
176 LLVM_DEBUG({
177 dbgs() << " ";
178 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
179 dbgs() << "\n";
180 });
181
182 BlockToFix.addEdge(E: std::move(GE));
183
184 return Error::success();
185 }
186
187public:
188 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj,
189 std::shared_ptr<orc::SymbolStringPool> SSP,
190 const Triple T, const SubtargetFeatures Features)
191 : COFFLinkGraphBuilder(Obj, std::move(SSP), std::move(T),
192 std::move(Features),
193 getCOFFX86RelocationKindName) {}
194};
195
196class COFFLinkGraphLowering_x86_64 {
197public:
198 // Lowers COFF x86_64 specific edges to generic x86_64 edges.
199 Error operator()(LinkGraph &G) {
200 for (auto *B : G.blocks()) {
201 for (auto &E : B->edges()) {
202 switch (E.getKind()) {
203 case EdgeKind_coff_x86_64::Pointer32NB: {
204 auto ImageBase = GetImageBase(G);
205 assert(ImageBase && "__ImageBase symbol must be defined");
206 E.setAddend(E.getAddend() - ImageBase->getAddress().getValue());
207 E.setKind(x86_64::Pointer32);
208 break;
209 }
210 case EdgeKind_coff_x86_64::PCRel32: {
211 E.setKind(x86_64::PCRel32);
212 break;
213 }
214 case EdgeKind_coff_x86_64::Pointer64: {
215 E.setKind(x86_64::Pointer64);
216 break;
217 }
218 case EdgeKind_coff_x86_64::SectionIdx16: {
219 E.setKind(x86_64::Pointer16);
220 break;
221 }
222 case EdgeKind_coff_x86_64::SecRel32: {
223 E.setAddend(E.getAddend() -
224 getSectionStart(Sec&: E.getTarget().getSection()).getValue());
225 E.setKind(x86_64::Pointer32);
226 break;
227 }
228 default:
229 break;
230 }
231 }
232 }
233 return Error::success();
234 }
235
236private:
237 orc::ExecutorAddr getSectionStart(Section &Sec) {
238 auto [It, Inserted] = SectionStartCache.try_emplace(Key: &Sec);
239 if (Inserted) {
240 SectionRange Range(Sec);
241 It->second = Range.getStart();
242 }
243 return It->second;
244 }
245
246 GetImageBaseSymbol GetImageBase;
247 DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
248};
249} // namespace
250
251namespace llvm {
252namespace jitlink {
253
254/// Return the string name of the given COFF x86_64 edge kind.
255const char *getCOFFX86RelocationKindName(Edge::Kind R) {
256 switch (R) {
257 case PCRel32:
258 return "PCRel32";
259 case Pointer32NB:
260 return "Pointer32NB";
261 case Pointer64:
262 return "Pointer64";
263 case SectionIdx16:
264 return "SectionIdx16";
265 case SecRel32:
266 return "SecRel32";
267 default:
268 return x86_64::getEdgeKindName(K: R);
269 }
270}
271
272Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromCOFFObject_x86_64(
273 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
274 LLVM_DEBUG({
275 dbgs() << "Building jitlink graph for new input "
276 << ObjectBuffer.getBufferIdentifier() << "...\n";
277 });
278
279 auto COFFObj = object::ObjectFile::createCOFFObjectFile(Object: ObjectBuffer);
280 if (!COFFObj)
281 return COFFObj.takeError();
282
283 auto Features = (*COFFObj)->getFeatures();
284 if (!Features)
285 return Features.takeError();
286
287 return COFFLinkGraphBuilder_x86_64(**COFFObj, std::move(SSP),
288 (*COFFObj)->makeTriple(),
289 std::move(*Features))
290 .buildGraph();
291}
292
293void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
294 std::unique_ptr<JITLinkContext> Ctx) {
295 PassConfiguration Config;
296 const Triple &TT = G->getTargetTriple();
297 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
298 // Add a mark-live pass.
299 if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
300 Config.PrePrunePasses.push_back(x: std::move(MarkLive));
301 Config.PrePrunePasses.push_back(x: SEHFrameKeepAlivePass(".pdata"));
302 } else
303 Config.PrePrunePasses.push_back(x: markAllSymbolsLive);
304
305 // Add COFF edge lowering passes.
306 Config.PreFixupPasses.push_back(x: COFFLinkGraphLowering_x86_64());
307 }
308
309 if (auto Err = Ctx->modifyPassConfig(G&: *G, Config))
310 return Ctx->notifyFailed(Err: std::move(Err));
311
312 COFFJITLinker_x86_64::link(Args: std::move(Ctx), Args: std::move(G), Args: std::move(Config));
313}
314
315} // namespace jitlink
316} // namespace llvm
317