1 //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
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
7 //===----------------------------------------------------------------------===//
9 // COFF/x86_64 jit-link implementation.
11 //===----------------------------------------------------------------------===//
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"
22 #define DEBUG_TYPE "jitlink"
25 using namespace llvm::jitlink
;
29 enum EdgeKind_coff_x86_64
: Edge::Kind
{
30 PCRel32
= x86_64::FirstPlatformRelocation
,
37 class COFFJITLinker_x86_64
: public JITLinker
<COFFJITLinker_x86_64
> {
38 friend class JITLinker
<COFFJITLinker_x86_64
>;
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
)) {}
47 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
48 return x86_64::applyFixup(G
, B
, E
, nullptr);
52 class COFFLinkGraphBuilder_x86_64
: public COFFLinkGraphBuilder
{
54 Error
addRelocations() override
{
55 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
57 for (const auto &RelSect
: sections())
58 if (Error Err
= COFFLinkGraphBuilder::forEachRelocation(
59 RelSect
, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation
))
62 return Error::success();
65 Error
addSingleRelocation(const object::RelocationRef
&Rel
,
66 const object::SectionRef
&FixupSect
,
68 const object::coff_relocation
*COFFRel
= getObject().getCOFFRelocation(Rel
);
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()),
75 inconvertibleErrorCode());
78 object::COFFSymbolRef COFFSymbol
= getObject().getCOFFSymbol(*SymbolIt
);
79 COFFSymbolIndex SymIndex
= getObject().getSymbolIndex(COFFSymbol
);
81 Symbol
*GraphSymbol
= getGraphSymbol(SymIndex
);
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()),
87 inconvertibleErrorCode());
90 orc::ExecutorAddr FixupAddress
=
91 orc::ExecutorAddr(FixupSect
.getAddress()) + Rel
.getOffset();
92 Edge::OffsetT Offset
= FixupAddress
- BlockToFix
.getAddress();
94 Edge::Kind Kind
= Edge::Invalid
;
95 const char *FixupPtr
= BlockToFix
.getContent().data() + Offset
;
97 switch (Rel
.getType()) {
98 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB
: {
99 Kind
= EdgeKind_coff_x86_64::Pointer32NB
;
100 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
103 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32
: {
104 Kind
= EdgeKind_coff_x86_64::PCRel32
;
105 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
108 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1
: {
109 Kind
= EdgeKind_coff_x86_64::PCRel32
;
110 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
114 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2
: {
115 Kind
= EdgeKind_coff_x86_64::PCRel32
;
116 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
120 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3
: {
121 Kind
= EdgeKind_coff_x86_64::PCRel32
;
122 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
126 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4
: {
127 Kind
= EdgeKind_coff_x86_64::PCRel32
;
128 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
132 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5
: {
133 Kind
= EdgeKind_coff_x86_64::PCRel32
;
134 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
138 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64
: {
139 Kind
= EdgeKind_coff_x86_64::Pointer64
;
140 Addend
= *reinterpret_cast<const support::little64_t
*>(FixupPtr
);
143 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION
: {
144 Kind
= EdgeKind_coff_x86_64::SectionIdx16
;
145 Addend
= *reinterpret_cast<const support::little16_t
*>(FixupPtr
);
146 uint64_t SectionIdx
= 0;
147 if (COFFSymbol
.isAbsolute())
148 SectionIdx
= getObject().getNumberOfSections() + 1;
150 SectionIdx
= COFFSymbol
.getSectionNumber();
151 auto *AbsSym
= &getGraph().addAbsoluteSymbol(
152 "secidx", orc::ExecutorAddr(SectionIdx
), 2, Linkage::Strong
,
153 Scope::Local
, false);
154 GraphSymbol
= AbsSym
;
157 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL
: {
158 // FIXME: SECREL to external symbol should be handled
159 if (!GraphSymbol
->isDefined())
160 return Error::success();
161 Kind
= EdgeKind_coff_x86_64::SecRel32
;
162 Addend
= *reinterpret_cast<const support::little32_t
*>(FixupPtr
);
166 return make_error
<JITLinkError
>("Unsupported x86_64 relocation:" +
167 formatv("{0:d}", Rel
.getType()));
171 Edge
GE(Kind
, Offset
, *GraphSymbol
, Addend
);
174 printEdge(dbgs(), BlockToFix
, GE
, getCOFFX86RelocationKindName(Kind
));
178 BlockToFix
.addEdge(std::move(GE
));
180 return Error::success();
184 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile
&Obj
, const Triple T
,
185 const SubtargetFeatures Features
)
186 : COFFLinkGraphBuilder(Obj
, std::move(T
), std::move(Features
),
187 getCOFFX86RelocationKindName
) {}
190 class COFFLinkGraphLowering_x86_64
{
192 // Lowers COFF x86_64 specific edges to generic x86_64 edges.
193 Error
lowerCOFFRelocationEdges(LinkGraph
&G
, JITLinkContext
&Ctx
) {
194 for (auto *B
: G
.blocks()) {
195 for (auto &E
: B
->edges()) {
196 switch (E
.getKind()) {
197 case EdgeKind_coff_x86_64::Pointer32NB
: {
198 auto ImageBase
= getImageBaseAddress(G
, Ctx
);
200 return ImageBase
.takeError();
201 E
.setAddend(E
.getAddend() - ImageBase
->getValue());
202 E
.setKind(x86_64::Pointer32
);
205 case EdgeKind_coff_x86_64::PCRel32
: {
206 E
.setKind(x86_64::PCRel32
);
209 case EdgeKind_coff_x86_64::Pointer64
: {
210 E
.setKind(x86_64::Pointer64
);
213 case EdgeKind_coff_x86_64::SectionIdx16
: {
214 E
.setKind(x86_64::Pointer16
);
217 case EdgeKind_coff_x86_64::SecRel32
: {
218 E
.setAddend(E
.getAddend() -
219 getSectionStart(E
.getTarget().getBlock().getSection())
221 E
.setKind(x86_64::Pointer32
);
229 return Error::success();
233 static StringRef
getImageBaseSymbolName() { return "__ImageBase"; }
235 orc::ExecutorAddr
getSectionStart(Section
&Sec
) {
236 if (!SectionStartCache
.count(&Sec
)) {
237 SectionRange
Range(Sec
);
238 SectionStartCache
[&Sec
] = Range
.getStart();
240 return SectionStartCache
[&Sec
];
243 Expected
<orc::ExecutorAddr
> getImageBaseAddress(LinkGraph
&G
,
244 JITLinkContext
&Ctx
) {
246 return this->ImageBase
;
247 for (auto *S
: G
.defined_symbols())
248 if (S
->getName() == getImageBaseSymbolName()) {
249 this->ImageBase
= S
->getAddress();
250 return this->ImageBase
;
253 JITLinkContext::LookupMap Symbols
;
254 Symbols
[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol
;
255 orc::ExecutorAddr ImageBase
;
256 Error Err
= Error::success();
258 createLookupContinuation([&](Expected
<AsyncLookupResult
> LR
) {
259 ErrorAsOutParameter
EAO(&Err
);
261 Err
= LR
.takeError();
264 ImageBase
= LR
->begin()->second
.getAddress();
267 return std::move(Err
);
268 this->ImageBase
= ImageBase
;
272 DenseMap
<Section
*, orc::ExecutorAddr
> SectionStartCache
;
273 orc::ExecutorAddr ImageBase
;
276 Error
lowerEdges_COFF_x86_64(LinkGraph
&G
, JITLinkContext
*Ctx
) {
277 LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
278 COFFLinkGraphLowering_x86_64 GraphLowering
;
280 if (auto Err
= GraphLowering
.lowerCOFFRelocationEdges(G
, *Ctx
))
283 return Error::success();
290 /// Return the string name of the given COFF x86_64 edge kind.
291 const char *getCOFFX86RelocationKindName(Edge::Kind R
) {
296 return "Pointer32NB";
300 return "SectionIdx16";
304 return x86_64::getEdgeKindName(R
);
308 Expected
<std::unique_ptr
<LinkGraph
>>
309 createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer
) {
311 dbgs() << "Building jitlink graph for new input "
312 << ObjectBuffer
.getBufferIdentifier() << "...\n";
315 auto COFFObj
= object::ObjectFile::createCOFFObjectFile(ObjectBuffer
);
317 return COFFObj
.takeError();
319 auto Features
= (*COFFObj
)->getFeatures();
321 return Features
.takeError();
323 return COFFLinkGraphBuilder_x86_64(**COFFObj
, (*COFFObj
)->makeTriple(),
324 std::move(*Features
))
328 void link_COFF_x86_64(std::unique_ptr
<LinkGraph
> G
,
329 std::unique_ptr
<JITLinkContext
> Ctx
) {
330 PassConfiguration Config
;
331 const Triple
&TT
= G
->getTargetTriple();
332 if (Ctx
->shouldAddDefaultTargetPasses(TT
)) {
333 // Add a mark-live pass.
334 if (auto MarkLive
= Ctx
->getMarkLivePass(TT
)) {
335 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
336 Config
.PrePrunePasses
.push_back(SEHFrameKeepAlivePass(".pdata"));
338 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
340 // Add COFF edge lowering passes.
341 JITLinkContext
*CtxPtr
= Ctx
.get();
342 Config
.PreFixupPasses
.push_back(
343 [CtxPtr
](LinkGraph
&G
) { return lowerEdges_COFF_x86_64(G
, CtxPtr
); });
346 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
347 return Ctx
->notifyFailed(std::move(Err
));
349 COFFJITLinker_x86_64::link(std::move(Ctx
), std::move(G
), std::move(Config
));
352 } // namespace jitlink