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
24 using namespace llvm;
25 using namespace llvm::jitlink;
26
27 namespace {
28
29 enum EdgeKind_coff_x86_64 : Edge::Kind {
30 PCRel32 = x86_64::FirstPlatformRelocation,
31 Pointer32NB,
32 };
33
34 class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
35 friend class JITLinker<COFFJITLinker_x86_64>;
36
37 public:
COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)38 COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
39 std::unique_ptr<LinkGraph> G,
40 PassConfiguration PassConfig)
41 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
42
43 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const44 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
45 return x86_64::applyFixup(G, B, E, nullptr);
46 }
47 };
48
49 class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
50 private:
addRelocations()51 Error addRelocations() override {
52 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
53
54 for (const auto &RelSect : sections())
55 if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
56 RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
57 return Err;
58
59 return Error::success();
60 }
61
addSingleRelocation(const object::RelocationRef & Rel,const object::SectionRef & FixupSect,Block & BlockToFix)62 Error addSingleRelocation(const object::RelocationRef &Rel,
63 const object::SectionRef &FixupSect,
64 Block &BlockToFix) {
65 const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
66 auto SymbolIt = Rel.getSymbol();
67 if (SymbolIt == getObject().symbol_end()) {
68 return make_error<StringError>(
69 formatv("Invalid symbol index in relocation entry. "
70 "index: {0}, section: {1}",
71 COFFRel->SymbolTableIndex, FixupSect.getIndex()),
72 inconvertibleErrorCode());
73 }
74
75 object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
76 COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
77
78 Symbol *GraphSymbol = getGraphSymbol(SymIndex);
79 if (!GraphSymbol)
80 return make_error<StringError>(
81 formatv("Could not find symbol at given index, did you add it to "
82 "JITSymbolTable? index: {0}, section: {1}",
83 SymIndex, FixupSect.getIndex()),
84 inconvertibleErrorCode());
85
86 int64_t Addend = 0;
87 orc::ExecutorAddr FixupAddress =
88 orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
89 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
90
91 Edge::Kind Kind = Edge::Invalid;
92 const char *FixupPtr = BlockToFix.getContent().data() + Offset;
93
94 switch (Rel.getType()) {
95 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
96 Kind = EdgeKind_coff_x86_64::Pointer32NB;
97 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
98 break;
99 }
100 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
101 Kind = EdgeKind_coff_x86_64::PCRel32;
102 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
103 break;
104 }
105 case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
106 Kind = EdgeKind_coff_x86_64::PCRel32;
107 Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
108 Addend -= 1;
109 break;
110 }
111 default: {
112 return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
113 formatv("{0:d}", Rel.getType()));
114 }
115 };
116
117 Edge GE(Kind, Offset, *GraphSymbol, Addend);
118 LLVM_DEBUG({
119 dbgs() << " ";
120 printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
121 dbgs() << "\n";
122 });
123
124 BlockToFix.addEdge(std::move(GE));
125
126 return Error::success();
127 }
128
129 public:
COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile & Obj,const Triple T)130 COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T)
131 : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {}
132 };
133
134 class COFFLinkGraphLowering_x86_64 {
135 public:
136 // Lowers COFF x86_64 specific edges to generic x86_64 edges.
lowerCOFFRelocationEdges(LinkGraph & G,JITLinkContext & Ctx)137 Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
138 for (auto *B : G.blocks()) {
139 for (auto &E : B->edges()) {
140 switch (E.getKind()) {
141 case EdgeKind_coff_x86_64::Pointer32NB: {
142 auto ImageBase = getImageBaseAddress(G, Ctx);
143 if (!ImageBase)
144 return ImageBase.takeError();
145 E.setAddend(E.getAddend() - *ImageBase);
146 E.setKind(x86_64::Pointer32);
147 break;
148 }
149 case EdgeKind_coff_x86_64::PCRel32: {
150 E.setKind(x86_64::PCRel32);
151 break;
152 }
153 default:
154 break;
155 }
156 }
157 }
158 return Error::success();
159 }
160
161 private:
getImageBaseSymbolName()162 static StringRef getImageBaseSymbolName() { return "__ImageBase"; }
getImageBaseAddress(LinkGraph & G,JITLinkContext & Ctx)163 Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G,
164 JITLinkContext &Ctx) {
165 if (this->ImageBase)
166 return this->ImageBase;
167 for (auto *S : G.defined_symbols())
168 if (S->getName() == getImageBaseSymbolName()) {
169 this->ImageBase = S->getAddress().getValue();
170 return this->ImageBase;
171 }
172
173 JITLinkContext::LookupMap Symbols;
174 Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
175 JITTargetAddress ImageBase;
176 Error Err = Error::success();
177 Ctx.lookup(Symbols,
178 createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
179 ErrorAsOutParameter EAO(&Err);
180 if (!LR) {
181 Err = LR.takeError();
182 return;
183 }
184 auto &ImageBaseSymbol = LR->begin()->second;
185 ImageBase = ImageBaseSymbol.getAddress();
186 }));
187 if (Err)
188 return std::move(Err);
189 this->ImageBase = ImageBase;
190 return ImageBase;
191 }
192 JITTargetAddress ImageBase = 0;
193 };
194
lowerEdges_COFF_x86_64(LinkGraph & G,JITLinkContext * Ctx)195 Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
196 LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
197 COFFLinkGraphLowering_x86_64 GraphLowering;
198
199 if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
200 return Err;
201
202 return Error::success();
203 }
204 } // namespace
205
206 namespace llvm {
207 namespace jitlink {
208
209 /// Return the string name of the given COFF x86_64 edge kind.
getCOFFX86RelocationKindName(Edge::Kind R)210 const char *getCOFFX86RelocationKindName(Edge::Kind R) {
211 switch (R) {
212 case PCRel32:
213 return "PCRel32";
214 case Pointer32NB:
215 return "Pointer32NB";
216 default:
217 return x86_64::getEdgeKindName(R);
218 }
219 }
220
221 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer)222 createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {
223 LLVM_DEBUG({
224 dbgs() << "Building jitlink graph for new input "
225 << ObjectBuffer.getBufferIdentifier() << "...\n";
226 });
227
228 auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
229 if (!COFFObj)
230 return COFFObj.takeError();
231
232 return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple())
233 .buildGraph();
234 }
235
link_COFF_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)236 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
237 std::unique_ptr<JITLinkContext> Ctx) {
238 PassConfiguration Config;
239 const Triple &TT = G->getTargetTriple();
240 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
241 // Add a mark-live pass.
242 if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
243 Config.PrePrunePasses.push_back(std::move(MarkLive));
244 Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
245 } else
246 Config.PrePrunePasses.push_back(markAllSymbolsLive);
247
248 // Add COFF edge lowering passes.
249 JITLinkContext *CtxPtr = Ctx.get();
250 Config.PreFixupPasses.push_back(
251 [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
252 }
253
254 if (auto Err = Ctx->modifyPassConfig(*G, Config))
255 return Ctx->notifyFailed(std::move(Err));
256
257 COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
258 }
259
260 } // namespace jitlink
261 } // namespace llvm
262