xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1fe6060f1SDimitry Andric //===------- ELF_riscv.cpp -JIT linker implementation for ELF/riscv -------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // ELF/riscv jit-link implementation.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric 
13fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
14*349cc55cSDimitry Andric #include "ELFLinkGraphBuilder.h"
15*349cc55cSDimitry Andric #include "JITLinkGeneric.h"
16*349cc55cSDimitry Andric #include "PerGraphGOTAndPLTStubsBuilder.h"
17*349cc55cSDimitry Andric #include "llvm/BinaryFormat/ELF.h"
18fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/riscv.h"
20fe6060f1SDimitry Andric #include "llvm/Object/ELF.h"
21fe6060f1SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
22fe6060f1SDimitry Andric 
23fe6060f1SDimitry Andric #define DEBUG_TYPE "jitlink"
24fe6060f1SDimitry Andric using namespace llvm;
25*349cc55cSDimitry Andric using namespace llvm::jitlink;
26*349cc55cSDimitry Andric using namespace llvm::jitlink::riscv;
27fe6060f1SDimitry Andric 
28*349cc55cSDimitry Andric namespace {
29*349cc55cSDimitry Andric 
30*349cc55cSDimitry Andric class PerGraphGOTAndPLTStubsBuilder_ELF_riscv
31*349cc55cSDimitry Andric     : public PerGraphGOTAndPLTStubsBuilder<
32*349cc55cSDimitry Andric           PerGraphGOTAndPLTStubsBuilder_ELF_riscv> {
33*349cc55cSDimitry Andric public:
34*349cc55cSDimitry Andric   static constexpr size_t StubEntrySize = 16;
35*349cc55cSDimitry Andric   static const uint8_t NullGOTEntryContent[8];
36*349cc55cSDimitry Andric   static const uint8_t RV64StubContent[StubEntrySize];
37*349cc55cSDimitry Andric   static const uint8_t RV32StubContent[StubEntrySize];
38*349cc55cSDimitry Andric 
39*349cc55cSDimitry Andric   using PerGraphGOTAndPLTStubsBuilder<
40*349cc55cSDimitry Andric       PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder;
41*349cc55cSDimitry Andric 
42*349cc55cSDimitry Andric   bool isRV64() const { return G.getPointerSize() == 8; }
43*349cc55cSDimitry Andric 
44*349cc55cSDimitry Andric   bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; }
45*349cc55cSDimitry Andric 
46*349cc55cSDimitry Andric   Symbol &createGOTEntry(Symbol &Target) {
47*349cc55cSDimitry Andric     Block &GOTBlock = G.createContentBlock(
48*349cc55cSDimitry Andric         getGOTSection(), getGOTEntryBlockContent(), 0, G.getPointerSize(), 0);
49*349cc55cSDimitry Andric     GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0);
50*349cc55cSDimitry Andric     return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false);
51*349cc55cSDimitry Andric   }
52*349cc55cSDimitry Andric 
53*349cc55cSDimitry Andric   Symbol &createPLTStub(Symbol &Target) {
54*349cc55cSDimitry Andric     Block &StubContentBlock =
55*349cc55cSDimitry Andric         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 4, 0);
56*349cc55cSDimitry Andric     auto &GOTEntrySymbol = getGOTEntry(Target);
57*349cc55cSDimitry Andric     StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0);
58*349cc55cSDimitry Andric     return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true,
59*349cc55cSDimitry Andric                                 false);
60*349cc55cSDimitry Andric   }
61*349cc55cSDimitry Andric 
62*349cc55cSDimitry Andric   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
63*349cc55cSDimitry Andric     // Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12)
64*349cc55cSDimitry Andric     // with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12)
65*349cc55cSDimitry Andric     // Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI20
66*349cc55cSDimitry Andric     E.setKind(R_RISCV_PCREL_HI20);
67*349cc55cSDimitry Andric     E.setTarget(GOTEntry);
68*349cc55cSDimitry Andric   }
69*349cc55cSDimitry Andric 
70*349cc55cSDimitry Andric   void fixPLTEdge(Edge &E, Symbol &PLTStubs) {
71*349cc55cSDimitry Andric     assert(E.getKind() == R_RISCV_CALL_PLT && "Not a R_RISCV_CALL_PLT edge?");
72*349cc55cSDimitry Andric     E.setKind(R_RISCV_CALL);
73*349cc55cSDimitry Andric     E.setTarget(PLTStubs);
74*349cc55cSDimitry Andric   }
75*349cc55cSDimitry Andric 
76*349cc55cSDimitry Andric   bool isExternalBranchEdge(Edge &E) const {
77*349cc55cSDimitry Andric     return E.getKind() == R_RISCV_CALL_PLT;
78*349cc55cSDimitry Andric   }
79*349cc55cSDimitry Andric 
80*349cc55cSDimitry Andric private:
81*349cc55cSDimitry Andric   Section &getGOTSection() const {
82*349cc55cSDimitry Andric     if (!GOTSection)
83*349cc55cSDimitry Andric       GOTSection = &G.createSection("$__GOT", MemProt::Read);
84*349cc55cSDimitry Andric     return *GOTSection;
85*349cc55cSDimitry Andric   }
86*349cc55cSDimitry Andric 
87*349cc55cSDimitry Andric   Section &getStubsSection() const {
88*349cc55cSDimitry Andric     if (!StubsSection)
89*349cc55cSDimitry Andric       StubsSection =
90*349cc55cSDimitry Andric           &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
91*349cc55cSDimitry Andric     return *StubsSection;
92*349cc55cSDimitry Andric   }
93*349cc55cSDimitry Andric 
94*349cc55cSDimitry Andric   ArrayRef<char> getGOTEntryBlockContent() {
95*349cc55cSDimitry Andric     return {reinterpret_cast<const char *>(NullGOTEntryContent),
96*349cc55cSDimitry Andric             G.getPointerSize()};
97*349cc55cSDimitry Andric   }
98*349cc55cSDimitry Andric 
99*349cc55cSDimitry Andric   ArrayRef<char> getStubBlockContent() {
100*349cc55cSDimitry Andric     auto StubContent = isRV64() ? RV64StubContent : RV32StubContent;
101*349cc55cSDimitry Andric     return {reinterpret_cast<const char *>(StubContent), StubEntrySize};
102*349cc55cSDimitry Andric   }
103*349cc55cSDimitry Andric 
104*349cc55cSDimitry Andric   mutable Section *GOTSection = nullptr;
105*349cc55cSDimitry Andric   mutable Section *StubsSection = nullptr;
106*349cc55cSDimitry Andric };
107*349cc55cSDimitry Andric 
108*349cc55cSDimitry Andric const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] =
109*349cc55cSDimitry Andric     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
110*349cc55cSDimitry Andric 
111*349cc55cSDimitry Andric const uint8_t
112*349cc55cSDimitry Andric     PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = {
113*349cc55cSDimitry Andric         0x17, 0x0e, 0x00, 0x00,  // auipc t3, literal
114*349cc55cSDimitry Andric         0x03, 0x3e, 0x0e, 0x00,  // ld    t3, literal(t3)
115*349cc55cSDimitry Andric         0x67, 0x00, 0x0e, 0x00,  // jr    t3
116*349cc55cSDimitry Andric         0x13, 0x00, 0x00, 0x00}; // nop
117*349cc55cSDimitry Andric 
118*349cc55cSDimitry Andric const uint8_t
119*349cc55cSDimitry Andric     PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = {
120*349cc55cSDimitry Andric         0x17, 0x0e, 0x00, 0x00,  // auipc t3, literal
121*349cc55cSDimitry Andric         0x03, 0x2e, 0x0e, 0x00,  // lw    t3, literal(t3)
122*349cc55cSDimitry Andric         0x67, 0x00, 0x0e, 0x00,  // jr    t3
123*349cc55cSDimitry Andric         0x13, 0x00, 0x00, 0x00}; // nop
124*349cc55cSDimitry Andric } // namespace
125fe6060f1SDimitry Andric namespace llvm {
126fe6060f1SDimitry Andric namespace jitlink {
127fe6060f1SDimitry Andric 
128fe6060f1SDimitry Andric static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) {
129fe6060f1SDimitry Andric   using namespace riscv;
130fe6060f1SDimitry Andric   assert((E.getKind() == R_RISCV_PCREL_LO12_I ||
131fe6060f1SDimitry Andric           E.getKind() == R_RISCV_PCREL_LO12_S) &&
132fe6060f1SDimitry Andric          "Can only have high relocation for R_RISCV_PCREL_LO12_I or "
133fe6060f1SDimitry Andric          "R_RISCV_PCREL_LO12_S");
134fe6060f1SDimitry Andric 
135fe6060f1SDimitry Andric   const Symbol &Sym = E.getTarget();
136fe6060f1SDimitry Andric   const Block &B = Sym.getBlock();
137fe6060f1SDimitry Andric   JITTargetAddress Offset = Sym.getOffset();
138fe6060f1SDimitry Andric 
139fe6060f1SDimitry Andric   struct Comp {
140fe6060f1SDimitry Andric     bool operator()(const Edge &Lhs, JITTargetAddress Offset) {
141fe6060f1SDimitry Andric       return Lhs.getOffset() < Offset;
142fe6060f1SDimitry Andric     }
143fe6060f1SDimitry Andric     bool operator()(JITTargetAddress Offset, const Edge &Rhs) {
144fe6060f1SDimitry Andric       return Offset < Rhs.getOffset();
145fe6060f1SDimitry Andric     }
146fe6060f1SDimitry Andric   };
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric   auto Bound =
149fe6060f1SDimitry Andric       std::equal_range(B.edges().begin(), B.edges().end(), Offset, Comp{});
150fe6060f1SDimitry Andric 
151fe6060f1SDimitry Andric   for (auto It = Bound.first; It != Bound.second; ++It) {
152fe6060f1SDimitry Andric     if (It->getKind() == R_RISCV_PCREL_HI20)
153fe6060f1SDimitry Andric       return *It;
154fe6060f1SDimitry Andric   }
155fe6060f1SDimitry Andric 
156fe6060f1SDimitry Andric   return make_error<JITLinkError>(
157fe6060f1SDimitry Andric       "No HI20 PCREL relocation type be found for LO12 PCREL relocation type");
158fe6060f1SDimitry Andric }
159fe6060f1SDimitry Andric 
160fe6060f1SDimitry Andric static uint32_t extractBits(uint64_t Num, unsigned High, unsigned Low) {
161fe6060f1SDimitry Andric   return (Num & ((1ULL << (High + 1)) - 1)) >> Low;
162fe6060f1SDimitry Andric }
163fe6060f1SDimitry Andric 
164fe6060f1SDimitry Andric class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
165fe6060f1SDimitry Andric   friend class JITLinker<ELFJITLinker_riscv>;
166fe6060f1SDimitry Andric 
167fe6060f1SDimitry Andric public:
168fe6060f1SDimitry Andric   ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,
169fe6060f1SDimitry Andric                      std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
170fe6060f1SDimitry Andric       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
171fe6060f1SDimitry Andric 
172fe6060f1SDimitry Andric private:
173fe6060f1SDimitry Andric   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
174fe6060f1SDimitry Andric     using namespace riscv;
175fe6060f1SDimitry Andric     using namespace llvm::support;
176fe6060f1SDimitry Andric 
177fe6060f1SDimitry Andric     char *BlockWorkingMem = B.getAlreadyMutableContent().data();
178fe6060f1SDimitry Andric     char *FixupPtr = BlockWorkingMem + E.getOffset();
179fe6060f1SDimitry Andric     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
180fe6060f1SDimitry Andric     switch (E.getKind()) {
181*349cc55cSDimitry Andric     case R_RISCV_32: {
182*349cc55cSDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend();
183*349cc55cSDimitry Andric       *(little32_t *)FixupPtr = static_cast<uint32_t>(Value);
184*349cc55cSDimitry Andric       break;
185*349cc55cSDimitry Andric     }
186*349cc55cSDimitry Andric     case R_RISCV_64: {
187*349cc55cSDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend();
188*349cc55cSDimitry Andric       *(little64_t *)FixupPtr = static_cast<uint64_t>(Value);
189*349cc55cSDimitry Andric       break;
190*349cc55cSDimitry Andric     }
191fe6060f1SDimitry Andric     case R_RISCV_HI20: {
192fe6060f1SDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend();
193fe6060f1SDimitry Andric       int32_t Hi = (Value + 0x800) & 0xFFFFF000;
194fe6060f1SDimitry Andric       uint32_t RawInstr = *(little32_t *)FixupPtr;
195fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = (RawInstr & 0xFFF) | static_cast<uint32_t>(Hi);
196fe6060f1SDimitry Andric       break;
197fe6060f1SDimitry Andric     }
198fe6060f1SDimitry Andric     case R_RISCV_LO12_I: {
199fe6060f1SDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend();
200fe6060f1SDimitry Andric       int32_t Lo = Value & 0xFFF;
201fe6060f1SDimitry Andric       uint32_t RawInstr = *(little32_t *)FixupPtr;
202fe6060f1SDimitry Andric       *(little32_t *)FixupPtr =
203fe6060f1SDimitry Andric           (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
204fe6060f1SDimitry Andric       break;
205fe6060f1SDimitry Andric     }
206fe6060f1SDimitry Andric     case R_RISCV_CALL: {
207fe6060f1SDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
208fe6060f1SDimitry Andric       int32_t Hi = (Value + 0x800) & 0xFFFFF000;
209fe6060f1SDimitry Andric       int32_t Lo = Value & 0xFFF;
210fe6060f1SDimitry Andric       uint32_t RawInstrAuipc = *(little32_t *)FixupPtr;
211fe6060f1SDimitry Andric       uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4);
212fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = RawInstrAuipc | static_cast<uint32_t>(Hi);
213fe6060f1SDimitry Andric       *(little32_t *)(FixupPtr + 4) =
214fe6060f1SDimitry Andric           RawInstrJalr | (static_cast<uint32_t>(Lo) << 20);
215fe6060f1SDimitry Andric       break;
216fe6060f1SDimitry Andric     }
217fe6060f1SDimitry Andric     case R_RISCV_PCREL_HI20: {
218fe6060f1SDimitry Andric       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
219fe6060f1SDimitry Andric       int32_t Hi = (Value + 0x800) & 0xFFFFF000;
220fe6060f1SDimitry Andric       uint32_t RawInstr = *(little32_t *)FixupPtr;
221fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = (RawInstr & 0xFFF) | static_cast<uint32_t>(Hi);
222fe6060f1SDimitry Andric       break;
223fe6060f1SDimitry Andric     }
224fe6060f1SDimitry Andric     case R_RISCV_PCREL_LO12_I: {
225fe6060f1SDimitry Andric       auto RelHI20 = getRISCVPCRelHi20(E);
226fe6060f1SDimitry Andric       if (!RelHI20)
227fe6060f1SDimitry Andric         return RelHI20.takeError();
228fe6060f1SDimitry Andric       int64_t Value = RelHI20->getTarget().getAddress() +
229fe6060f1SDimitry Andric                       RelHI20->getAddend() - E.getTarget().getAddress();
230fe6060f1SDimitry Andric       int64_t Lo = Value & 0xFFF;
231fe6060f1SDimitry Andric       uint32_t RawInstr = *(little32_t *)FixupPtr;
232fe6060f1SDimitry Andric       *(little32_t *)FixupPtr =
233fe6060f1SDimitry Andric           (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
234fe6060f1SDimitry Andric       break;
235fe6060f1SDimitry Andric     }
236fe6060f1SDimitry Andric     case R_RISCV_PCREL_LO12_S: {
237fe6060f1SDimitry Andric       auto RelHI20 = getRISCVPCRelHi20(E);
238fe6060f1SDimitry Andric       int64_t Value = RelHI20->getTarget().getAddress() +
239fe6060f1SDimitry Andric                       RelHI20->getAddend() - E.getTarget().getAddress();
240fe6060f1SDimitry Andric       int64_t Lo = Value & 0xFFF;
241fe6060f1SDimitry Andric       uint32_t Imm31_25 = extractBits(Lo, 11, 5) << 25;
242fe6060f1SDimitry Andric       uint32_t Imm11_7 = extractBits(Lo, 4, 0) << 7;
243fe6060f1SDimitry Andric       uint32_t RawInstr = *(little32_t *)FixupPtr;
244fe6060f1SDimitry Andric 
245fe6060f1SDimitry Andric       *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7;
246fe6060f1SDimitry Andric       break;
247fe6060f1SDimitry Andric     }
248fe6060f1SDimitry Andric     }
249fe6060f1SDimitry Andric     return Error::success();
250fe6060f1SDimitry Andric   }
251fe6060f1SDimitry Andric };
252fe6060f1SDimitry Andric 
253fe6060f1SDimitry Andric template <typename ELFT>
254fe6060f1SDimitry Andric class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
255fe6060f1SDimitry Andric private:
256fe6060f1SDimitry Andric   static Expected<riscv::EdgeKind_riscv>
257fe6060f1SDimitry Andric   getRelocationKind(const uint32_t Type) {
258fe6060f1SDimitry Andric     using namespace riscv;
259fe6060f1SDimitry Andric     switch (Type) {
260fe6060f1SDimitry Andric     case ELF::R_RISCV_32:
261fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_32;
262fe6060f1SDimitry Andric     case ELF::R_RISCV_64:
263fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_64;
264fe6060f1SDimitry Andric     case ELF::R_RISCV_HI20:
265fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_HI20;
266fe6060f1SDimitry Andric     case ELF::R_RISCV_LO12_I:
267fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_LO12_I;
268fe6060f1SDimitry Andric     case ELF::R_RISCV_CALL:
269fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_CALL;
270fe6060f1SDimitry Andric     case ELF::R_RISCV_PCREL_HI20:
271fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_PCREL_HI20;
272fe6060f1SDimitry Andric     case ELF::R_RISCV_PCREL_LO12_I:
273fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;
274fe6060f1SDimitry Andric     case ELF::R_RISCV_PCREL_LO12_S:
275fe6060f1SDimitry Andric       return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;
276*349cc55cSDimitry Andric     case ELF::R_RISCV_GOT_HI20:
277*349cc55cSDimitry Andric       return EdgeKind_riscv::R_RISCV_GOT_HI20;
278*349cc55cSDimitry Andric     case ELF::R_RISCV_CALL_PLT:
279*349cc55cSDimitry Andric       return EdgeKind_riscv::R_RISCV_CALL_PLT;
280fe6060f1SDimitry Andric     }
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric     return make_error<JITLinkError>("Unsupported riscv relocation:" +
283fe6060f1SDimitry Andric                                     formatv("{0:d}", Type));
284fe6060f1SDimitry Andric   }
285fe6060f1SDimitry Andric 
286fe6060f1SDimitry Andric   Error addRelocations() override {
287*349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
288*349cc55cSDimitry Andric 
289fe6060f1SDimitry Andric     using Base = ELFLinkGraphBuilder<ELFT>;
290*349cc55cSDimitry Andric     using Self = ELFLinkGraphBuilder_riscv<ELFT>;
291*349cc55cSDimitry Andric     for (const auto &RelSect : Base::Sections)
292*349cc55cSDimitry Andric       if (Error Err = Base::forEachRelocation(RelSect, this,
293*349cc55cSDimitry Andric                                               &Self::addSingleRelocation))
294*349cc55cSDimitry Andric         return Err;
295fe6060f1SDimitry Andric 
296*349cc55cSDimitry Andric     return Error::success();
297fe6060f1SDimitry Andric   }
298fe6060f1SDimitry Andric 
299*349cc55cSDimitry Andric   Error addSingleRelocation(const typename ELFT::Rela &Rel,
300*349cc55cSDimitry Andric                             const typename ELFT::Shdr &FixupSect,
301*349cc55cSDimitry Andric                             Section &GraphSection) {
302*349cc55cSDimitry Andric     using Base = ELFLinkGraphBuilder<ELFT>;
303*349cc55cSDimitry Andric 
304*349cc55cSDimitry Andric     uint32_t SymbolIndex = Rel.getSymbol(false);
305*349cc55cSDimitry Andric     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
306*349cc55cSDimitry Andric     if (!ObjSymbol)
307*349cc55cSDimitry Andric       return ObjSymbol.takeError();
308*349cc55cSDimitry Andric 
309*349cc55cSDimitry Andric     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
310*349cc55cSDimitry Andric     if (!GraphSymbol)
311*349cc55cSDimitry Andric       return make_error<StringError>(
312*349cc55cSDimitry Andric           formatv("Could not find symbol at given index, did you add it to "
313*349cc55cSDimitry Andric                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
314*349cc55cSDimitry Andric                   SymbolIndex, (*ObjSymbol)->st_shndx,
315*349cc55cSDimitry Andric                   Base::GraphSymbols.size()),
316*349cc55cSDimitry Andric           inconvertibleErrorCode());
317*349cc55cSDimitry Andric 
318*349cc55cSDimitry Andric     uint32_t Type = Rel.getType(false);
319*349cc55cSDimitry Andric     Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type);
320fe6060f1SDimitry Andric     if (!Kind)
321fe6060f1SDimitry Andric       return Kind.takeError();
322fe6060f1SDimitry Andric 
323*349cc55cSDimitry Andric     int64_t Addend = Rel.r_addend;
324*349cc55cSDimitry Andric     Block *BlockToFix = *(GraphSection.blocks().begin());
325*349cc55cSDimitry Andric     JITTargetAddress FixupAddress = FixupSect.sh_addr + Rel.r_offset;
326*349cc55cSDimitry Andric     Edge::OffsetT Offset = FixupAddress - BlockToFix->getAddress();
327*349cc55cSDimitry Andric     Edge GE(*Kind, Offset, *GraphSymbol, Addend);
328*349cc55cSDimitry Andric     LLVM_DEBUG({
329*349cc55cSDimitry Andric       dbgs() << "    ";
330*349cc55cSDimitry Andric       printEdge(dbgs(), *BlockToFix, GE, riscv::getEdgeKindName(*Kind));
331*349cc55cSDimitry Andric       dbgs() << "\n";
332*349cc55cSDimitry Andric     });
333*349cc55cSDimitry Andric 
334*349cc55cSDimitry Andric     BlockToFix->addEdge(std::move(GE));
335fe6060f1SDimitry Andric     return Error::success();
336fe6060f1SDimitry Andric   }
337fe6060f1SDimitry Andric 
338fe6060f1SDimitry Andric public:
339fe6060f1SDimitry Andric   ELFLinkGraphBuilder_riscv(StringRef FileName,
340fe6060f1SDimitry Andric                             const object::ELFFile<ELFT> &Obj, const Triple T)
341fe6060f1SDimitry Andric       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
342fe6060f1SDimitry Andric                                   riscv::getEdgeKindName) {}
343fe6060f1SDimitry Andric };
344fe6060f1SDimitry Andric 
345fe6060f1SDimitry Andric Expected<std::unique_ptr<LinkGraph>>
346fe6060f1SDimitry Andric createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) {
347fe6060f1SDimitry Andric   LLVM_DEBUG({
348fe6060f1SDimitry Andric     dbgs() << "Building jitlink graph for new input "
349fe6060f1SDimitry Andric            << ObjectBuffer.getBufferIdentifier() << "...\n";
350fe6060f1SDimitry Andric   });
351fe6060f1SDimitry Andric 
352fe6060f1SDimitry Andric   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
353fe6060f1SDimitry Andric   if (!ELFObj)
354fe6060f1SDimitry Andric     return ELFObj.takeError();
355fe6060f1SDimitry Andric 
356fe6060f1SDimitry Andric   if ((*ELFObj)->getArch() == Triple::riscv64) {
357fe6060f1SDimitry Andric     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
358fe6060f1SDimitry Andric     return ELFLinkGraphBuilder_riscv<object::ELF64LE>(
359fe6060f1SDimitry Andric                (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
360fe6060f1SDimitry Andric                (*ELFObj)->makeTriple())
361fe6060f1SDimitry Andric         .buildGraph();
362fe6060f1SDimitry Andric   } else {
363fe6060f1SDimitry Andric     assert((*ELFObj)->getArch() == Triple::riscv32 &&
364fe6060f1SDimitry Andric            "Invalid triple for RISCV ELF object file");
365fe6060f1SDimitry Andric     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
366fe6060f1SDimitry Andric     return ELFLinkGraphBuilder_riscv<object::ELF32LE>(
367fe6060f1SDimitry Andric                (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
368fe6060f1SDimitry Andric                (*ELFObj)->makeTriple())
369fe6060f1SDimitry Andric         .buildGraph();
370fe6060f1SDimitry Andric   }
371fe6060f1SDimitry Andric }
372fe6060f1SDimitry Andric 
373fe6060f1SDimitry Andric void link_ELF_riscv(std::unique_ptr<LinkGraph> G,
374fe6060f1SDimitry Andric                     std::unique_ptr<JITLinkContext> Ctx) {
375fe6060f1SDimitry Andric   PassConfiguration Config;
376fe6060f1SDimitry Andric   const Triple &TT = G->getTargetTriple();
377fe6060f1SDimitry Andric   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
378fe6060f1SDimitry Andric     if (auto MarkLive = Ctx->getMarkLivePass(TT))
379fe6060f1SDimitry Andric       Config.PrePrunePasses.push_back(std::move(MarkLive));
380fe6060f1SDimitry Andric     else
381fe6060f1SDimitry Andric       Config.PrePrunePasses.push_back(markAllSymbolsLive);
382*349cc55cSDimitry Andric     Config.PostPrunePasses.push_back(
383*349cc55cSDimitry Andric         PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass);
384fe6060f1SDimitry Andric   }
385fe6060f1SDimitry Andric   if (auto Err = Ctx->modifyPassConfig(*G, Config))
386fe6060f1SDimitry Andric     return Ctx->notifyFailed(std::move(Err));
387fe6060f1SDimitry Andric 
388fe6060f1SDimitry Andric   ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config));
389fe6060f1SDimitry Andric }
390fe6060f1SDimitry Andric 
391fe6060f1SDimitry Andric } // namespace jitlink
392fe6060f1SDimitry Andric } // namespace llvm
393