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 static inline bool isInRangeForImmS32(int64_t Value) {
166   return (Value >= std::numeric_limits<int32_t>::min() &&
167           Value <= std::numeric_limits<int32_t>::max());
168 }
169 
170 class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
171   friend class JITLinker<ELFJITLinker_riscv>;
172 
173 public:
174   ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,
175                      std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
176       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
177 
178 private:
179   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
180     using namespace riscv;
181     using namespace llvm::support;
182 
183     char *BlockWorkingMem = B.getAlreadyMutableContent().data();
184     char *FixupPtr = BlockWorkingMem + E.getOffset();
185     orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();
186     switch (E.getKind()) {
187     case R_RISCV_32: {
188       int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
189       *(little32_t *)FixupPtr = static_cast<uint32_t>(Value);
190       break;
191     }
192     case R_RISCV_64: {
193       int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
194       *(little64_t *)FixupPtr = static_cast<uint64_t>(Value);
195       break;
196     }
197     case R_RISCV_HI20: {
198       int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
199       int64_t Hi = Value + 0x800;
200       if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
201         return makeTargetOutOfRangeError(G, B, E);
202       uint32_t RawInstr = *(little32_t *)FixupPtr;
203       *(little32_t *)FixupPtr =
204           (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));
205       break;
206     }
207     case R_RISCV_LO12_I: {
208       // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs
209       // with current relocation R_RISCV_LO12_I. So here may need a check.
210       int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();
211       int32_t Lo = Value & 0xFFF;
212       uint32_t RawInstr = *(little32_t *)FixupPtr;
213       *(little32_t *)FixupPtr =
214           (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
215       break;
216     }
217     case R_RISCV_CALL: {
218       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
219       int64_t Hi = Value + 0x800;
220       if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
221         return makeTargetOutOfRangeError(G, B, E);
222       int32_t Lo = Value & 0xFFF;
223       uint32_t RawInstrAuipc = *(little32_t *)FixupPtr;
224       uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4);
225       *(little32_t *)FixupPtr =
226           RawInstrAuipc | (static_cast<uint32_t>(Hi & 0xFFFFF000));
227       *(little32_t *)(FixupPtr + 4) =
228           RawInstrJalr | (static_cast<uint32_t>(Lo) << 20);
229       break;
230     }
231     case R_RISCV_PCREL_HI20: {
232       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
233       int64_t Hi = Value + 0x800;
234       if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi)))
235         return makeTargetOutOfRangeError(G, B, E);
236       uint32_t RawInstr = *(little32_t *)FixupPtr;
237       *(little32_t *)FixupPtr =
238           (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));
239       break;
240     }
241     case R_RISCV_PCREL_LO12_I: {
242       // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and
243       // pairs with current relocation R_RISCV_PCREL_LO12_I. So here may need a
244       // check.
245       auto RelHI20 = getRISCVPCRelHi20(E);
246       if (!RelHI20)
247         return RelHI20.takeError();
248       int64_t Value = RelHI20->getTarget().getAddress() +
249                       RelHI20->getAddend() - E.getTarget().getAddress();
250       int64_t Lo = Value & 0xFFF;
251       uint32_t RawInstr = *(little32_t *)FixupPtr;
252       *(little32_t *)FixupPtr =
253           (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
254       break;
255     }
256     case R_RISCV_PCREL_LO12_S: {
257       // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and
258       // pairs with current relocation R_RISCV_PCREL_LO12_S. So here may need a
259       // check.
260       auto RelHI20 = getRISCVPCRelHi20(E);
261       int64_t Value = RelHI20->getTarget().getAddress() +
262                       RelHI20->getAddend() - E.getTarget().getAddress();
263       int64_t Lo = Value & 0xFFF;
264       uint32_t Imm31_25 = extractBits(Lo, 5, 7) << 25;
265       uint32_t Imm11_7 = extractBits(Lo, 0, 5) << 7;
266       uint32_t RawInstr = *(little32_t *)FixupPtr;
267 
268       *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7;
269       break;
270     }
271     }
272     return Error::success();
273   }
274 };
275 
276 template <typename ELFT>
277 class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
278 private:
279   static Expected<riscv::EdgeKind_riscv>
280   getRelocationKind(const uint32_t Type) {
281     using namespace riscv;
282     switch (Type) {
283     case ELF::R_RISCV_32:
284       return EdgeKind_riscv::R_RISCV_32;
285     case ELF::R_RISCV_64:
286       return EdgeKind_riscv::R_RISCV_64;
287     case ELF::R_RISCV_HI20:
288       return EdgeKind_riscv::R_RISCV_HI20;
289     case ELF::R_RISCV_LO12_I:
290       return EdgeKind_riscv::R_RISCV_LO12_I;
291     case ELF::R_RISCV_CALL:
292       return EdgeKind_riscv::R_RISCV_CALL;
293     case ELF::R_RISCV_PCREL_HI20:
294       return EdgeKind_riscv::R_RISCV_PCREL_HI20;
295     case ELF::R_RISCV_PCREL_LO12_I:
296       return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;
297     case ELF::R_RISCV_PCREL_LO12_S:
298       return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;
299     case ELF::R_RISCV_GOT_HI20:
300       return EdgeKind_riscv::R_RISCV_GOT_HI20;
301     case ELF::R_RISCV_CALL_PLT:
302       return EdgeKind_riscv::R_RISCV_CALL_PLT;
303     }
304 
305     return make_error<JITLinkError>("Unsupported riscv relocation:" +
306                                     formatv("{0:d}", Type));
307   }
308 
309   Error addRelocations() override {
310     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
311 
312     using Base = ELFLinkGraphBuilder<ELFT>;
313     using Self = ELFLinkGraphBuilder_riscv<ELFT>;
314     for (const auto &RelSect : Base::Sections)
315       if (Error Err = Base::forEachRelocation(RelSect, this,
316                                               &Self::addSingleRelocation))
317         return Err;
318 
319     return Error::success();
320   }
321 
322   Error addSingleRelocation(const typename ELFT::Rela &Rel,
323                             const typename ELFT::Shdr &FixupSect,
324                             Section &GraphSection) {
325     using Base = ELFLinkGraphBuilder<ELFT>;
326 
327     uint32_t SymbolIndex = Rel.getSymbol(false);
328     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
329     if (!ObjSymbol)
330       return ObjSymbol.takeError();
331 
332     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
333     if (!GraphSymbol)
334       return make_error<StringError>(
335           formatv("Could not find symbol at given index, did you add it to "
336                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
337                   SymbolIndex, (*ObjSymbol)->st_shndx,
338                   Base::GraphSymbols.size()),
339           inconvertibleErrorCode());
340 
341     uint32_t Type = Rel.getType(false);
342     Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type);
343     if (!Kind)
344       return Kind.takeError();
345 
346     int64_t Addend = Rel.r_addend;
347     Block *BlockToFix = *(GraphSection.blocks().begin());
348     auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
349     Edge::OffsetT Offset = FixupAddress - BlockToFix->getAddress();
350     Edge GE(*Kind, Offset, *GraphSymbol, Addend);
351     LLVM_DEBUG({
352       dbgs() << "    ";
353       printEdge(dbgs(), *BlockToFix, GE, riscv::getEdgeKindName(*Kind));
354       dbgs() << "\n";
355     });
356 
357     BlockToFix->addEdge(std::move(GE));
358     return Error::success();
359   }
360 
361 public:
362   ELFLinkGraphBuilder_riscv(StringRef FileName,
363                             const object::ELFFile<ELFT> &Obj, const Triple T)
364       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
365                                   riscv::getEdgeKindName) {}
366 };
367 
368 Expected<std::unique_ptr<LinkGraph>>
369 createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) {
370   LLVM_DEBUG({
371     dbgs() << "Building jitlink graph for new input "
372            << ObjectBuffer.getBufferIdentifier() << "...\n";
373   });
374 
375   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
376   if (!ELFObj)
377     return ELFObj.takeError();
378 
379   if ((*ELFObj)->getArch() == Triple::riscv64) {
380     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
381     return ELFLinkGraphBuilder_riscv<object::ELF64LE>(
382                (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
383                (*ELFObj)->makeTriple())
384         .buildGraph();
385   } else {
386     assert((*ELFObj)->getArch() == Triple::riscv32 &&
387            "Invalid triple for RISCV ELF object file");
388     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
389     return ELFLinkGraphBuilder_riscv<object::ELF32LE>(
390                (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
391                (*ELFObj)->makeTriple())
392         .buildGraph();
393   }
394 }
395 
396 void link_ELF_riscv(std::unique_ptr<LinkGraph> G,
397                     std::unique_ptr<JITLinkContext> Ctx) {
398   PassConfiguration Config;
399   const Triple &TT = G->getTargetTriple();
400   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
401     if (auto MarkLive = Ctx->getMarkLivePass(TT))
402       Config.PrePrunePasses.push_back(std::move(MarkLive));
403     else
404       Config.PrePrunePasses.push_back(markAllSymbolsLive);
405     Config.PostPrunePasses.push_back(
406         PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass);
407   }
408   if (auto Err = Ctx->modifyPassConfig(*G, Config))
409     return Ctx->notifyFailed(std::move(Err));
410 
411   ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config));
412 }
413 
414 } // namespace jitlink
415 } // namespace llvm
416