LLVM 23.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"
20#include "llvm/Object/COFF.h"
21#include "llvm/Support/Endian.h"
22
23#define DEBUG_TYPE "jitlink"
24
25using namespace llvm;
26using namespace llvm::jitlink;
27
28namespace {
29
30enum EdgeKind_coff_x86_64 : Edge::Kind {
32 Pointer32NB,
33 Pointer64,
34 SectionIdx16,
35 SecRel32,
36};
37
38class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
39 friend class JITLinker<COFFJITLinker_x86_64>;
40
41public:
42 COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
43 std::unique_ptr<LinkGraph> G,
44 PassConfiguration PassConfig)
45 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
46
47private:
48 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
49 return x86_64::applyFixup(G, B, E, nullptr);
50 }
51};
52
53class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
54private:
55 Error addRelocations() override {
56 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
57
58 for (const auto &RelSect : sections())
60 RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
61 return Err;
62
63 return Error::success();
64 }
65
66 Error addSingleRelocation(const object::RelocationRef &Rel,
67 const object::SectionRef &FixupSect,
68 Block &BlockToFix) {
69 const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
70 auto SymbolIt = Rel.getSymbol();
71 if (SymbolIt == getObject().symbol_end()) {
73 formatv("Invalid symbol index in relocation entry. "
74 "index: {0}, section: {1}",
75 COFFRel->SymbolTableIndex, FixupSect.getIndex()),
77 }
78
79 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
80 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
81
82 Symbol *GraphSymbol = getGraphSymbol(SymIndex);
83 if (!GraphSymbol)
85 formatv("Could not find symbol at given index, did you add it to "
86 "JITSymbolTable? index: {0}, section: {1}",
87 SymIndex, FixupSect.getIndex()),
89
90 int64_t Addend = 0;
91 orc::ExecutorAddr FixupAddress =
92 orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
93 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
94
95 Edge::Kind Kind = Edge::Invalid;
96 const char *FixupPtr = BlockToFix.getContent().data() + Offset;
97 Symbol *ImageBase = GetImageBaseSymbol()(getGraph());
98
99 switch (Rel.getType()) {
101 if (!ImageBase)
102 ImageBase = &addImageBaseSymbol();
103 Kind = EdgeKind_coff_x86_64::Pointer32NB;
104 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
105 break;
106 }
108 Kind = EdgeKind_coff_x86_64::PCRel32;
109 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
110 break;
111 }
113 Kind = EdgeKind_coff_x86_64::PCRel32;
114 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
115 Addend -= 1;
116 break;
117 }
119 Kind = EdgeKind_coff_x86_64::PCRel32;
120 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
121 Addend -= 2;
122 break;
123 }
125 Kind = EdgeKind_coff_x86_64::PCRel32;
126 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
127 Addend -= 3;
128 break;
129 }
131 Kind = EdgeKind_coff_x86_64::PCRel32;
132 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
133 Addend -= 4;
134 break;
135 }
137 Kind = EdgeKind_coff_x86_64::PCRel32;
138 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
139 Addend -= 5;
140 break;
141 }
143 Kind = EdgeKind_coff_x86_64::Pointer64;
144 Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
145 break;
146 }
148 Kind = EdgeKind_coff_x86_64::SectionIdx16;
149 Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
150 uint64_t SectionIdx = 0;
151 if (COFFSymbol.isAbsolute())
152 SectionIdx = getObject().getNumberOfSections() + 1;
153 else
154 SectionIdx = COFFSymbol.getSectionNumber();
155
156 auto *AbsSym = &getGraph().addAbsoluteSymbol(
157 "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
158 Scope::Local, false);
159 GraphSymbol = AbsSym;
160 break;
161 }
163 // FIXME: SECREL to external symbol should be handled
164 if (!GraphSymbol->isDefined())
165 return Error::success();
166 Kind = EdgeKind_coff_x86_64::SecRel32;
167 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
168 break;
169 }
170 default: {
171 return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
172 formatv("{0:d}", Rel.getType()));
173 }
174 };
175
176 Edge GE(Kind, Offset, *GraphSymbol, Addend);
177 LLVM_DEBUG({
178 dbgs() << " ";
179 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
180 dbgs() << "\n";
181 });
182
183 BlockToFix.addEdge(std::move(GE));
184
185 return Error::success();
186 }
187
188public:
189 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj,
190 std::shared_ptr<orc::SymbolStringPool> SSP,
191 const Triple T, const SubtargetFeatures Features)
192 : COFFLinkGraphBuilder(Obj, std::move(SSP), std::move(T),
193 std::move(Features),
195};
196
197class COFFLinkGraphLowering_x86_64 {
198public:
199 // Lowers COFF x86_64 specific edges to generic x86_64 edges.
200 Error operator()(LinkGraph &G) {
201 for (auto *B : G.blocks()) {
202 for (auto &E : B->edges()) {
203 switch (E.getKind()) {
204 case EdgeKind_coff_x86_64::Pointer32NB: {
205 auto ImageBase = GetImageBase(G);
206 assert(ImageBase && "__ImageBase symbol must be defined");
207 E.setAddend(E.getAddend() - ImageBase->getAddress().getValue());
208 E.setKind(x86_64::Pointer32);
209 break;
210 }
211 case EdgeKind_coff_x86_64::PCRel32: {
212 E.setKind(x86_64::PCRel32);
213 break;
214 }
215 case EdgeKind_coff_x86_64::Pointer64: {
216 E.setKind(x86_64::Pointer64);
217 break;
218 }
219 case EdgeKind_coff_x86_64::SectionIdx16: {
220 E.setKind(x86_64::Pointer16);
221 break;
222 }
223 case EdgeKind_coff_x86_64::SecRel32: {
224 E.setAddend(E.getAddend() -
225 getSectionStart(E.getTarget().getSection()).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 auto [It, Inserted] = SectionStartCache.try_emplace(&Sec);
240 if (Inserted) {
241 SectionRange Range(Sec);
242 It->second = Range.getStart();
243 }
244 return It->second;
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.
256const char *getCOFFX86RelocationKindName(Edge::Kind R) {
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) {
296 PassConfiguration Config;
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
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
bbsections Prepares for basic block sections
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr, const uint64_t Size=sizeof(T))
#define G(x, y, z)
Definition MD5.cpp:55
#define T
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define LLVM_DEBUG(...)
Definition Debug.h:114
const T * data() const
Definition ArrayRef.h:139
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef getBufferIdentifier() const
Manages the enabling and disabling of subtarget specific features.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
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:54
uint64_t getType() const
Definition ObjectFile.h:633
uint64_t getOffset() const
Definition ObjectFile.h:625
symbol_iterator getSymbol() const
Definition ObjectFile.h:629
This is a value type class that represents a single section in the list of sections in the object fil...
Definition ObjectFile.h:83
uint64_t getIndex() const
Definition ObjectFile.h:530
uint64_t getAddress() const
Definition ObjectFile.h:526
Represents an address in the executor process.
@ IMAGE_REL_AMD64_REL32
Definition COFF.h:365
@ IMAGE_REL_AMD64_REL32_5
Definition COFF.h:370
@ IMAGE_REL_AMD64_ADDR64
Definition COFF.h:362
@ IMAGE_REL_AMD64_REL32_3
Definition COFF.h:368
@ IMAGE_REL_AMD64_ADDR32NB
Definition COFF.h:364
@ IMAGE_REL_AMD64_SECTION
Definition COFF.h:371
@ IMAGE_REL_AMD64_REL32_2
Definition COFF.h:367
@ IMAGE_REL_AMD64_REL32_1
Definition COFF.h:366
@ IMAGE_REL_AMD64_SECREL
Definition COFF.h:372
@ IMAGE_REL_AMD64_REL32_4
Definition COFF.h:369
detail::packed_endian_specific_integral< int16_t, llvm::endianness::little, unaligned > little16_t
Definition Endian.h:297
detail::packed_endian_specific_integral< int32_t, llvm::endianness::little, unaligned > little32_t
Definition Endian.h:300
detail::packed_endian_specific_integral< int64_t, llvm::endianness::little, unaligned > little64_t
Definition Endian.h:303
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:557
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
support::ulittle32_t SymbolTableIndex
Definition COFF.h:485