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