1753f127fSDimitry Andric //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric //
9753f127fSDimitry Andric // COFF/x86_64 jit-link implementation.
10753f127fSDimitry Andric //
11753f127fSDimitry Andric //===----------------------------------------------------------------------===//
12753f127fSDimitry Andric
13753f127fSDimitry Andric #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
14753f127fSDimitry Andric #include "COFFLinkGraphBuilder.h"
15753f127fSDimitry Andric #include "JITLinkGeneric.h"
16972a253aSDimitry Andric #include "SEHFrameSupport.h"
17753f127fSDimitry Andric #include "llvm/BinaryFormat/COFF.h"
18753f127fSDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h"
19753f127fSDimitry Andric #include "llvm/Object/COFF.h"
20753f127fSDimitry Andric #include "llvm/Support/Endian.h"
21753f127fSDimitry Andric
22753f127fSDimitry Andric #define DEBUG_TYPE "jitlink"
23753f127fSDimitry Andric
24753f127fSDimitry Andric using namespace llvm;
25753f127fSDimitry Andric using namespace llvm::jitlink;
26753f127fSDimitry Andric
27753f127fSDimitry Andric namespace {
28753f127fSDimitry Andric
29972a253aSDimitry Andric enum EdgeKind_coff_x86_64 : Edge::Kind {
30972a253aSDimitry Andric PCRel32 = x86_64::FirstPlatformRelocation,
31972a253aSDimitry Andric Pointer32NB,
32bdd1243dSDimitry Andric Pointer64,
33bdd1243dSDimitry Andric SectionIdx16,
34bdd1243dSDimitry Andric SecRel32,
35972a253aSDimitry Andric };
36972a253aSDimitry Andric
37753f127fSDimitry Andric class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
38753f127fSDimitry Andric friend class JITLinker<COFFJITLinker_x86_64>;
39753f127fSDimitry Andric
40753f127fSDimitry Andric public:
COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)41753f127fSDimitry Andric COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
42753f127fSDimitry Andric std::unique_ptr<LinkGraph> G,
43753f127fSDimitry Andric PassConfiguration PassConfig)
44753f127fSDimitry Andric : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
45753f127fSDimitry Andric
46753f127fSDimitry Andric private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const47753f127fSDimitry Andric Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
48753f127fSDimitry Andric return x86_64::applyFixup(G, B, E, nullptr);
49753f127fSDimitry Andric }
50753f127fSDimitry Andric };
51753f127fSDimitry Andric
52753f127fSDimitry Andric class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
53753f127fSDimitry Andric private:
addRelocations()54753f127fSDimitry Andric Error addRelocations() override {
55753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "Processing relocations:\n");
56753f127fSDimitry Andric
57753f127fSDimitry Andric for (const auto &RelSect : sections())
58753f127fSDimitry Andric if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
59753f127fSDimitry Andric RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
60753f127fSDimitry Andric return Err;
61753f127fSDimitry Andric
62753f127fSDimitry Andric return Error::success();
63753f127fSDimitry Andric }
64753f127fSDimitry Andric
addSingleRelocation(const object::RelocationRef & Rel,const object::SectionRef & FixupSect,Block & BlockToFix)65753f127fSDimitry Andric Error addSingleRelocation(const object::RelocationRef &Rel,
66753f127fSDimitry Andric const object::SectionRef &FixupSect,
67753f127fSDimitry Andric Block &BlockToFix) {
68753f127fSDimitry Andric const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
69753f127fSDimitry Andric auto SymbolIt = Rel.getSymbol();
70753f127fSDimitry Andric if (SymbolIt == getObject().symbol_end()) {
71753f127fSDimitry Andric return make_error<StringError>(
72753f127fSDimitry Andric formatv("Invalid symbol index in relocation entry. "
73753f127fSDimitry Andric "index: {0}, section: {1}",
74753f127fSDimitry Andric COFFRel->SymbolTableIndex, FixupSect.getIndex()),
75753f127fSDimitry Andric inconvertibleErrorCode());
76753f127fSDimitry Andric }
77753f127fSDimitry Andric
78753f127fSDimitry Andric object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
79753f127fSDimitry Andric COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
80753f127fSDimitry Andric
81753f127fSDimitry Andric Symbol *GraphSymbol = getGraphSymbol(SymIndex);
82753f127fSDimitry Andric if (!GraphSymbol)
83753f127fSDimitry Andric return make_error<StringError>(
84753f127fSDimitry Andric formatv("Could not find symbol at given index, did you add it to "
85753f127fSDimitry Andric "JITSymbolTable? index: {0}, section: {1}",
86753f127fSDimitry Andric SymIndex, FixupSect.getIndex()),
87753f127fSDimitry Andric inconvertibleErrorCode());
88753f127fSDimitry Andric
89753f127fSDimitry Andric int64_t Addend = 0;
90753f127fSDimitry Andric orc::ExecutorAddr FixupAddress =
91753f127fSDimitry Andric orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
92753f127fSDimitry Andric Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
93753f127fSDimitry Andric
94753f127fSDimitry Andric Edge::Kind Kind = Edge::Invalid;
95972a253aSDimitry Andric const char *FixupPtr = BlockToFix.getContent().data() + Offset;
96753f127fSDimitry Andric
97972a253aSDimitry Andric switch (Rel.getType()) {
98972a253aSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
99972a253aSDimitry Andric Kind = EdgeKind_coff_x86_64::Pointer32NB;
100972a253aSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
101753f127fSDimitry Andric break;
102753f127fSDimitry Andric }
103972a253aSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
104972a253aSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
105972a253aSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
106753f127fSDimitry Andric break;
107753f127fSDimitry Andric }
108972a253aSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
109972a253aSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
110972a253aSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
111972a253aSDimitry Andric Addend -= 1;
112972a253aSDimitry Andric break;
113972a253aSDimitry Andric }
114bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {
115bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
116bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
117bdd1243dSDimitry Andric Addend -= 2;
118bdd1243dSDimitry Andric break;
119bdd1243dSDimitry Andric }
120bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {
121bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
122bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
123bdd1243dSDimitry Andric Addend -= 3;
124bdd1243dSDimitry Andric break;
125bdd1243dSDimitry Andric }
126bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {
127bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
128bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
129bdd1243dSDimitry Andric Addend -= 4;
130bdd1243dSDimitry Andric break;
131bdd1243dSDimitry Andric }
132bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {
133bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::PCRel32;
134bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
135bdd1243dSDimitry Andric Addend -= 5;
136bdd1243dSDimitry Andric break;
137bdd1243dSDimitry Andric }
138bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {
139bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::Pointer64;
140bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
141bdd1243dSDimitry Andric break;
142bdd1243dSDimitry Andric }
143bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {
144bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::SectionIdx16;
145bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
146bdd1243dSDimitry Andric uint64_t SectionIdx = 0;
147bdd1243dSDimitry Andric if (COFFSymbol.isAbsolute())
148bdd1243dSDimitry Andric SectionIdx = getObject().getNumberOfSections() + 1;
149bdd1243dSDimitry Andric else
150bdd1243dSDimitry Andric SectionIdx = COFFSymbol.getSectionNumber();
151bdd1243dSDimitry Andric auto *AbsSym = &getGraph().addAbsoluteSymbol(
152bdd1243dSDimitry Andric "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
153bdd1243dSDimitry Andric Scope::Local, false);
154bdd1243dSDimitry Andric GraphSymbol = AbsSym;
155bdd1243dSDimitry Andric break;
156bdd1243dSDimitry Andric }
157bdd1243dSDimitry Andric case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {
158bdd1243dSDimitry Andric // FIXME: SECREL to external symbol should be handled
159bdd1243dSDimitry Andric if (!GraphSymbol->isDefined())
160bdd1243dSDimitry Andric return Error::success();
161bdd1243dSDimitry Andric Kind = EdgeKind_coff_x86_64::SecRel32;
162bdd1243dSDimitry Andric Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
163bdd1243dSDimitry Andric break;
164bdd1243dSDimitry Andric }
165972a253aSDimitry Andric default: {
166972a253aSDimitry Andric return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
167972a253aSDimitry Andric formatv("{0:d}", Rel.getType()));
168972a253aSDimitry Andric }
169753f127fSDimitry Andric };
170753f127fSDimitry Andric
171753f127fSDimitry Andric Edge GE(Kind, Offset, *GraphSymbol, Addend);
172753f127fSDimitry Andric LLVM_DEBUG({
173753f127fSDimitry Andric dbgs() << " ";
174972a253aSDimitry Andric printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
175753f127fSDimitry Andric dbgs() << "\n";
176753f127fSDimitry Andric });
177753f127fSDimitry Andric
178753f127fSDimitry Andric BlockToFix.addEdge(std::move(GE));
179753f127fSDimitry Andric
180972a253aSDimitry Andric return Error::success();
181753f127fSDimitry Andric }
182753f127fSDimitry Andric
183753f127fSDimitry Andric public:
COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile & Obj,const Triple T,const SubtargetFeatures Features)184*06c3fb27SDimitry Andric COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T,
185*06c3fb27SDimitry Andric const SubtargetFeatures Features)
186*06c3fb27SDimitry Andric : COFFLinkGraphBuilder(Obj, std::move(T), std::move(Features),
187*06c3fb27SDimitry Andric getCOFFX86RelocationKindName) {}
188753f127fSDimitry Andric };
189753f127fSDimitry Andric
190972a253aSDimitry Andric class COFFLinkGraphLowering_x86_64 {
191972a253aSDimitry Andric public:
192972a253aSDimitry Andric // Lowers COFF x86_64 specific edges to generic x86_64 edges.
lowerCOFFRelocationEdges(LinkGraph & G,JITLinkContext & Ctx)193972a253aSDimitry Andric Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
194972a253aSDimitry Andric for (auto *B : G.blocks()) {
195972a253aSDimitry Andric for (auto &E : B->edges()) {
196972a253aSDimitry Andric switch (E.getKind()) {
197972a253aSDimitry Andric case EdgeKind_coff_x86_64::Pointer32NB: {
198972a253aSDimitry Andric auto ImageBase = getImageBaseAddress(G, Ctx);
199972a253aSDimitry Andric if (!ImageBase)
200972a253aSDimitry Andric return ImageBase.takeError();
201*06c3fb27SDimitry Andric E.setAddend(E.getAddend() - ImageBase->getValue());
202972a253aSDimitry Andric E.setKind(x86_64::Pointer32);
203972a253aSDimitry Andric break;
204972a253aSDimitry Andric }
205972a253aSDimitry Andric case EdgeKind_coff_x86_64::PCRel32: {
206972a253aSDimitry Andric E.setKind(x86_64::PCRel32);
207972a253aSDimitry Andric break;
208972a253aSDimitry Andric }
209bdd1243dSDimitry Andric case EdgeKind_coff_x86_64::Pointer64: {
210bdd1243dSDimitry Andric E.setKind(x86_64::Pointer64);
211bdd1243dSDimitry Andric break;
212bdd1243dSDimitry Andric }
213bdd1243dSDimitry Andric case EdgeKind_coff_x86_64::SectionIdx16: {
214bdd1243dSDimitry Andric E.setKind(x86_64::Pointer16);
215bdd1243dSDimitry Andric break;
216bdd1243dSDimitry Andric }
217bdd1243dSDimitry Andric case EdgeKind_coff_x86_64::SecRel32: {
218bdd1243dSDimitry Andric E.setAddend(E.getAddend() -
219bdd1243dSDimitry Andric getSectionStart(E.getTarget().getBlock().getSection())
220bdd1243dSDimitry Andric .getValue());
221bdd1243dSDimitry Andric E.setKind(x86_64::Pointer32);
222bdd1243dSDimitry Andric break;
223bdd1243dSDimitry Andric }
224972a253aSDimitry Andric default:
225972a253aSDimitry Andric break;
226972a253aSDimitry Andric }
227972a253aSDimitry Andric }
228972a253aSDimitry Andric }
229972a253aSDimitry Andric return Error::success();
230972a253aSDimitry Andric }
231753f127fSDimitry Andric
232972a253aSDimitry Andric private:
getImageBaseSymbolName()233972a253aSDimitry Andric static StringRef getImageBaseSymbolName() { return "__ImageBase"; }
234bdd1243dSDimitry Andric
getSectionStart(Section & Sec)235bdd1243dSDimitry Andric orc::ExecutorAddr getSectionStart(Section &Sec) {
236bdd1243dSDimitry Andric if (!SectionStartCache.count(&Sec)) {
237bdd1243dSDimitry Andric SectionRange Range(Sec);
238bdd1243dSDimitry Andric SectionStartCache[&Sec] = Range.getStart();
239bdd1243dSDimitry Andric }
240bdd1243dSDimitry Andric return SectionStartCache[&Sec];
241bdd1243dSDimitry Andric }
242bdd1243dSDimitry Andric
getImageBaseAddress(LinkGraph & G,JITLinkContext & Ctx)243*06c3fb27SDimitry Andric Expected<orc::ExecutorAddr> getImageBaseAddress(LinkGraph &G,
244972a253aSDimitry Andric JITLinkContext &Ctx) {
245972a253aSDimitry Andric if (this->ImageBase)
246972a253aSDimitry Andric return this->ImageBase;
247972a253aSDimitry Andric for (auto *S : G.defined_symbols())
248972a253aSDimitry Andric if (S->getName() == getImageBaseSymbolName()) {
249*06c3fb27SDimitry Andric this->ImageBase = S->getAddress();
250972a253aSDimitry Andric return this->ImageBase;
251972a253aSDimitry Andric }
252972a253aSDimitry Andric
253972a253aSDimitry Andric JITLinkContext::LookupMap Symbols;
254972a253aSDimitry Andric Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
255*06c3fb27SDimitry Andric orc::ExecutorAddr ImageBase;
256972a253aSDimitry Andric Error Err = Error::success();
257972a253aSDimitry Andric Ctx.lookup(Symbols,
258972a253aSDimitry Andric createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
259972a253aSDimitry Andric ErrorAsOutParameter EAO(&Err);
260972a253aSDimitry Andric if (!LR) {
261972a253aSDimitry Andric Err = LR.takeError();
262972a253aSDimitry Andric return;
263972a253aSDimitry Andric }
264*06c3fb27SDimitry Andric ImageBase = LR->begin()->second.getAddress();
265972a253aSDimitry Andric }));
266972a253aSDimitry Andric if (Err)
267972a253aSDimitry Andric return std::move(Err);
268972a253aSDimitry Andric this->ImageBase = ImageBase;
269972a253aSDimitry Andric return ImageBase;
270972a253aSDimitry Andric }
271bdd1243dSDimitry Andric
272bdd1243dSDimitry Andric DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
273*06c3fb27SDimitry Andric orc::ExecutorAddr ImageBase;
274972a253aSDimitry Andric };
275972a253aSDimitry Andric
lowerEdges_COFF_x86_64(LinkGraph & G,JITLinkContext * Ctx)276972a253aSDimitry Andric Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
277972a253aSDimitry Andric LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
278972a253aSDimitry Andric COFFLinkGraphLowering_x86_64 GraphLowering;
279972a253aSDimitry Andric
280972a253aSDimitry Andric if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
281972a253aSDimitry Andric return Err;
282972a253aSDimitry Andric
283753f127fSDimitry Andric return Error::success();
284753f127fSDimitry Andric }
285753f127fSDimitry Andric } // namespace
286753f127fSDimitry Andric
287753f127fSDimitry Andric namespace llvm {
288753f127fSDimitry Andric namespace jitlink {
289753f127fSDimitry Andric
290972a253aSDimitry Andric /// Return the string name of the given COFF x86_64 edge kind.
getCOFFX86RelocationKindName(Edge::Kind R)291972a253aSDimitry Andric const char *getCOFFX86RelocationKindName(Edge::Kind R) {
292972a253aSDimitry Andric switch (R) {
293972a253aSDimitry Andric case PCRel32:
294972a253aSDimitry Andric return "PCRel32";
295972a253aSDimitry Andric case Pointer32NB:
296972a253aSDimitry Andric return "Pointer32NB";
297bdd1243dSDimitry Andric case Pointer64:
298bdd1243dSDimitry Andric return "Pointer64";
299bdd1243dSDimitry Andric case SectionIdx16:
300bdd1243dSDimitry Andric return "SectionIdx16";
301bdd1243dSDimitry Andric case SecRel32:
302bdd1243dSDimitry Andric return "SecRel32";
303972a253aSDimitry Andric default:
304972a253aSDimitry Andric return x86_64::getEdgeKindName(R);
305972a253aSDimitry Andric }
306972a253aSDimitry Andric }
307972a253aSDimitry Andric
308753f127fSDimitry Andric Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer)309753f127fSDimitry Andric createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {
310753f127fSDimitry Andric LLVM_DEBUG({
311753f127fSDimitry Andric dbgs() << "Building jitlink graph for new input "
312753f127fSDimitry Andric << ObjectBuffer.getBufferIdentifier() << "...\n";
313753f127fSDimitry Andric });
314753f127fSDimitry Andric
315753f127fSDimitry Andric auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
316753f127fSDimitry Andric if (!COFFObj)
317753f127fSDimitry Andric return COFFObj.takeError();
318753f127fSDimitry Andric
319*06c3fb27SDimitry Andric auto Features = (*COFFObj)->getFeatures();
320*06c3fb27SDimitry Andric if (!Features)
321*06c3fb27SDimitry Andric return Features.takeError();
322*06c3fb27SDimitry Andric
323*06c3fb27SDimitry Andric return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple(),
324*06c3fb27SDimitry Andric std::move(*Features))
325753f127fSDimitry Andric .buildGraph();
326753f127fSDimitry Andric }
327753f127fSDimitry Andric
link_COFF_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)328753f127fSDimitry Andric void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
329753f127fSDimitry Andric std::unique_ptr<JITLinkContext> Ctx) {
330753f127fSDimitry Andric PassConfiguration Config;
331753f127fSDimitry Andric const Triple &TT = G->getTargetTriple();
332753f127fSDimitry Andric if (Ctx->shouldAddDefaultTargetPasses(TT)) {
333753f127fSDimitry Andric // Add a mark-live pass.
334972a253aSDimitry Andric if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
335753f127fSDimitry Andric Config.PrePrunePasses.push_back(std::move(MarkLive));
336972a253aSDimitry Andric Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
337972a253aSDimitry Andric } else
338753f127fSDimitry Andric Config.PrePrunePasses.push_back(markAllSymbolsLive);
339753f127fSDimitry Andric
340972a253aSDimitry Andric // Add COFF edge lowering passes.
341972a253aSDimitry Andric JITLinkContext *CtxPtr = Ctx.get();
342972a253aSDimitry Andric Config.PreFixupPasses.push_back(
343972a253aSDimitry Andric [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
344753f127fSDimitry Andric }
345753f127fSDimitry Andric
346753f127fSDimitry Andric if (auto Err = Ctx->modifyPassConfig(*G, Config))
347753f127fSDimitry Andric return Ctx->notifyFailed(std::move(Err));
348753f127fSDimitry Andric
349753f127fSDimitry Andric COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
350753f127fSDimitry Andric }
351753f127fSDimitry Andric
352753f127fSDimitry Andric } // namespace jitlink
353753f127fSDimitry Andric } // namespace llvm
354