LLVM 20.0.0git
COFF_x86_64.cpp
Go to the documentation of this file.
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
15#include "JITLinkGeneric.h"
16#include "SEHFrameSupport.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 {
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, 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())
59 RelSect, this, &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) {
69 auto SymbolIt = Rel.getSymbol();
70 if (SymbolIt == getObject().symbol_end()) {
71 return make_error<StringError>(
72 formatv("Invalid symbol index in relocation entry. "
73 "index: {0}, section: {1}",
74 COFFRel->SymbolTableIndex, FixupSect.getIndex()),
76 }
77
78 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
79 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
80
81 Symbol *GraphSymbol = getGraphSymbol(SymIndex);
82 if (!GraphSymbol)
83 return make_error<StringError>(
84 formatv("Could not find symbol at given index, did you add it to "
85 "JITSymbolTable? index: {0}, section: {1}",
86 SymIndex, FixupSect.getIndex()),
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
95 const char *FixupPtr = BlockToFix.getContent().data() + Offset;
96 Symbol *ImageBase = GetImageBaseSymbol()(getGraph());
97
98 switch (Rel.getType()) {
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 }
107 Kind = EdgeKind_coff_x86_64::PCRel32;
108 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
109 break;
110 }
112 Kind = EdgeKind_coff_x86_64::PCRel32;
113 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
114 Addend -= 1;
115 break;
116 }
118 Kind = EdgeKind_coff_x86_64::PCRel32;
119 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
120 Addend -= 2;
121 break;
122 }
124 Kind = EdgeKind_coff_x86_64::PCRel32;
125 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
126 Addend -= 3;
127 break;
128 }
130 Kind = EdgeKind_coff_x86_64::PCRel32;
131 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
132 Addend -= 4;
133 break;
134 }
136 Kind = EdgeKind_coff_x86_64::PCRel32;
137 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
138 Addend -= 5;
139 break;
140 }
142 Kind = EdgeKind_coff_x86_64::Pointer64;
143 Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
144 break;
145 }
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 "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
157 Scope::Local, false);
158 GraphSymbol = AbsSym;
159 break;
160 }
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>("Unsupported x86_64 relocation:" +
171 formatv("{0:d}", 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(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),
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(E.getTarget().getBlock().getSection())
225 .getValue());
226 E.setKind(x86_64::Pointer32);
227 break;
228 }
229 default:
230 break;
231 }
232 }
233 }
234 return Error::success();
235 }
236
237private:
238 orc::ExecutorAddr getSectionStart(Section &Sec) {
239 if (!SectionStartCache.count(&Sec)) {
240 SectionRange Range(Sec);
241 SectionStartCache[&Sec] = Range.getStart();
242 return Range.getStart();
243 }
244 return SectionStartCache[&Sec];
245 }
246
247 GetImageBaseSymbol GetImageBase;
249};
250} // namespace
251
252namespace llvm {
253namespace jitlink {
254
255/// Return the string name of the given COFF x86_64 edge kind.
257 switch (R) {
258 case PCRel32:
259 return "PCRel32";
260 case Pointer32NB:
261 return "Pointer32NB";
262 case Pointer64:
263 return "Pointer64";
264 case SectionIdx16:
265 return "SectionIdx16";
266 case SecRel32:
267 return "SecRel32";
268 default:
269 return x86_64::getEdgeKindName(R);
270 }
271}
272
274 MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
275 LLVM_DEBUG({
276 dbgs() << "Building jitlink graph for new input "
277 << ObjectBuffer.getBufferIdentifier() << "...\n";
278 });
279
280 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
281 if (!COFFObj)
282 return COFFObj.takeError();
283
284 auto Features = (*COFFObj)->getFeatures();
285 if (!Features)
286 return Features.takeError();
287
288 return COFFLinkGraphBuilder_x86_64(**COFFObj, std::move(SSP),
289 (*COFFObj)->makeTriple(),
290 std::move(*Features))
291 .buildGraph();
292}
293
294void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
295 std::unique_ptr<JITLinkContext> Ctx) {
297 const Triple &TT = G->getTargetTriple();
298 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
299 // Add a mark-live pass.
300 if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
301 Config.PrePrunePasses.push_back(std::move(MarkLive));
302 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
303 } else
304 Config.PrePrunePasses.push_back(markAllSymbolsLive);
305
306 // Add COFF edge lowering passes.
307 Config.PreFixupPasses.push_back(COFFLinkGraphLowering_x86_64());
308 }
309
310 if (auto Err = Ctx->modifyPassConfig(*G, Config))
311 return Ctx->notifyFailed(std::move(Err));
312
313 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
314}
315
316} // namespace jitlink
317} // namespace llvm
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DEBUG(...)
Definition: Debug.h:106
RelaxConfig Config
Definition: ELF_riscv.cpp:506
#define G(x, y, z)
Definition: MD5.cpp:56
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const T * data() const
Definition: ArrayRef.h:165
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
StringRef getBufferIdentifier() const
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
const coff_relocation * getCOFFRelocation(const RelocationRef &Reloc) const
uint32_t getNumberOfSections() const
Definition: COFF.h:983
uint32_t getSymbolIndex(COFFSymbolRef Symbol) const
COFFSymbolRef getCOFFSymbol(const DataRefImpl &Ref) const
bool isAbsolute() const
Definition: COFF.h:377
int32_t getSectionNumber() const
Definition: COFF.h:326
static Expected< std::unique_ptr< COFFObjectFile > > createCOFFObjectFile(MemoryBufferRef Object)
This is a value type class that represents a single relocation in the list of relocations in the obje...
Definition: ObjectFile.h:52
uint64_t getType() const
Definition: ObjectFile.h:628
uint64_t getOffset() const
Definition: ObjectFile.h:620
symbol_iterator getSymbol() const
Definition: ObjectFile.h:624
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:81
uint64_t getIndex() const
Definition: ObjectFile.h:525
uint64_t getAddress() const
Definition: ObjectFile.h:521
Represents an address in the executor process.
@ IMAGE_REL_AMD64_REL32
Definition: COFF.h:364
@ IMAGE_REL_AMD64_REL32_5
Definition: COFF.h:369
@ IMAGE_REL_AMD64_ADDR64
Definition: COFF.h:361
@ IMAGE_REL_AMD64_REL32_3
Definition: COFF.h:367
@ IMAGE_REL_AMD64_ADDR32NB
Definition: COFF.h:363
@ IMAGE_REL_AMD64_SECTION
Definition: COFF.h:370
@ IMAGE_REL_AMD64_REL32_2
Definition: COFF.h:366
@ IMAGE_REL_AMD64_REL32_1
Definition: COFF.h:365
@ IMAGE_REL_AMD64_SECREL
Definition: COFF.h:371
@ IMAGE_REL_AMD64_REL32_4
Definition: COFF.h:368
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:480
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
support::ulittle32_t SymbolTableIndex
Definition: COFF.h:480