[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / ELF_riscv.cpp
blobd0e65ef1c3ac5852005e8dc54435608b4fbed962
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.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
14 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
15 #include "llvm/ExecutionEngine/JITLink/riscv.h"
16 #include "llvm/Object/ELF.h"
17 #include "llvm/Object/ELFObjectFile.h"
19 #include "ELFLinkGraphBuilder.h"
20 #include "JITLinkGeneric.h"
22 #define DEBUG_TYPE "jitlink"
23 using namespace llvm;
25 namespace llvm {
26 namespace jitlink {
28 static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) {
29 using namespace riscv;
30 assert((E.getKind() == R_RISCV_PCREL_LO12_I ||
31 E.getKind() == R_RISCV_PCREL_LO12_S) &&
32 "Can only have high relocation for R_RISCV_PCREL_LO12_I or "
33 "R_RISCV_PCREL_LO12_S");
35 const Symbol &Sym = E.getTarget();
36 const Block &B = Sym.getBlock();
37 JITTargetAddress Offset = Sym.getOffset();
39 struct Comp {
40 bool operator()(const Edge &Lhs, JITTargetAddress Offset) {
41 return Lhs.getOffset() < Offset;
43 bool operator()(JITTargetAddress Offset, const Edge &Rhs) {
44 return Offset < Rhs.getOffset();
48 auto Bound =
49 std::equal_range(B.edges().begin(), B.edges().end(), Offset, Comp{});
51 for (auto It = Bound.first; It != Bound.second; ++It) {
52 if (It->getKind() == R_RISCV_PCREL_HI20)
53 return *It;
56 return make_error<JITLinkError>(
57 "No HI20 PCREL relocation type be found for LO12 PCREL relocation type");
60 static uint32_t extractBits(uint64_t Num, unsigned High, unsigned Low) {
61 return (Num & ((1ULL << (High + 1)) - 1)) >> Low;
64 class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
65 friend class JITLinker<ELFJITLinker_riscv>;
67 public:
68 ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,
69 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
70 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
72 private:
73 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
74 using namespace riscv;
75 using namespace llvm::support;
77 char *BlockWorkingMem = B.getAlreadyMutableContent().data();
78 char *FixupPtr = BlockWorkingMem + E.getOffset();
79 JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
80 switch (E.getKind()) {
81 case R_RISCV_HI20: {
82 int64_t Value = E.getTarget().getAddress() + E.getAddend();
83 int32_t Hi = (Value + 0x800) & 0xFFFFF000;
84 uint32_t RawInstr = *(little32_t *)FixupPtr;
85 *(little32_t *)FixupPtr = (RawInstr & 0xFFF) | static_cast<uint32_t>(Hi);
86 break;
88 case R_RISCV_LO12_I: {
89 int64_t Value = E.getTarget().getAddress() + E.getAddend();
90 int32_t Lo = Value & 0xFFF;
91 uint32_t RawInstr = *(little32_t *)FixupPtr;
92 *(little32_t *)FixupPtr =
93 (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
94 break;
96 case R_RISCV_CALL: {
97 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
98 int32_t Hi = (Value + 0x800) & 0xFFFFF000;
99 int32_t Lo = Value & 0xFFF;
100 uint32_t RawInstrAuipc = *(little32_t *)FixupPtr;
101 uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4);
102 *(little32_t *)FixupPtr = RawInstrAuipc | static_cast<uint32_t>(Hi);
103 *(little32_t *)(FixupPtr + 4) =
104 RawInstrJalr | (static_cast<uint32_t>(Lo) << 20);
105 break;
107 case R_RISCV_PCREL_HI20: {
108 int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
109 int32_t Hi = (Value + 0x800) & 0xFFFFF000;
110 uint32_t RawInstr = *(little32_t *)FixupPtr;
111 *(little32_t *)FixupPtr = (RawInstr & 0xFFF) | static_cast<uint32_t>(Hi);
112 break;
114 case R_RISCV_PCREL_LO12_I: {
115 auto RelHI20 = getRISCVPCRelHi20(E);
116 if (!RelHI20)
117 return RelHI20.takeError();
118 int64_t Value = RelHI20->getTarget().getAddress() +
119 RelHI20->getAddend() - E.getTarget().getAddress();
120 int64_t Lo = Value & 0xFFF;
121 uint32_t RawInstr = *(little32_t *)FixupPtr;
122 *(little32_t *)FixupPtr =
123 (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);
124 break;
126 case R_RISCV_PCREL_LO12_S: {
127 auto RelHI20 = getRISCVPCRelHi20(E);
128 int64_t Value = RelHI20->getTarget().getAddress() +
129 RelHI20->getAddend() - E.getTarget().getAddress();
130 int64_t Lo = Value & 0xFFF;
131 uint32_t Imm31_25 = extractBits(Lo, 11, 5) << 25;
132 uint32_t Imm11_7 = extractBits(Lo, 4, 0) << 7;
133 uint32_t RawInstr = *(little32_t *)FixupPtr;
135 *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7;
136 break;
139 return Error::success();
143 template <typename ELFT>
144 class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
145 private:
146 static Expected<riscv::EdgeKind_riscv>
147 getRelocationKind(const uint32_t Type) {
148 using namespace riscv;
149 switch (Type) {
150 case ELF::R_RISCV_32:
151 return EdgeKind_riscv::R_RISCV_32;
152 case ELF::R_RISCV_64:
153 return EdgeKind_riscv::R_RISCV_64;
154 case ELF::R_RISCV_HI20:
155 return EdgeKind_riscv::R_RISCV_HI20;
156 case ELF::R_RISCV_LO12_I:
157 return EdgeKind_riscv::R_RISCV_LO12_I;
158 case ELF::R_RISCV_CALL:
159 return EdgeKind_riscv::R_RISCV_CALL;
160 case ELF::R_RISCV_PCREL_HI20:
161 return EdgeKind_riscv::R_RISCV_PCREL_HI20;
162 case ELF::R_RISCV_PCREL_LO12_I:
163 return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;
164 case ELF::R_RISCV_PCREL_LO12_S:
165 return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;
168 return make_error<JITLinkError>("Unsupported riscv relocation:" +
169 formatv("{0:d}", Type));
172 Error addRelocations() override {
173 using Base = ELFLinkGraphBuilder<ELFT>;
174 LLVM_DEBUG(dbgs() << "Adding relocations\n");
176 // TODO a partern is forming of iterate some sections but only give me
177 // ones I am interested, I should abstract that concept some where
178 for (auto &SecRef : Base::Sections) {
179 if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
180 continue;
181 auto RelSectName = Base::Obj.getSectionName(SecRef);
182 if (!RelSectName)
183 return RelSectName.takeError();
185 LLVM_DEBUG({
186 dbgs() << "Adding relocations from section " << *RelSectName << "\n";
189 auto UpdateSection = Base::Obj.getSection(SecRef.sh_info);
190 if (!UpdateSection)
191 return UpdateSection.takeError();
193 auto UpdateSectionName = Base::Obj.getSectionName(**UpdateSection);
194 if (!UpdateSectionName)
195 return UpdateSectionName.takeError();
196 // Don't process relocations for debug sections.
197 if (Base::isDwarfSection(*UpdateSectionName)) {
198 LLVM_DEBUG({
199 dbgs() << " Target is dwarf section " << *UpdateSectionName
200 << ". Skipping.\n";
202 continue;
203 } else
204 LLVM_DEBUG({
205 dbgs() << " For target section " << *UpdateSectionName << "\n";
208 auto *JITSection = Base::G->findSectionByName(*UpdateSectionName);
209 if (!JITSection)
210 return make_error<llvm::StringError>(
211 "Refencing a section that wasn't added to graph" +
212 *UpdateSectionName,
213 llvm::inconvertibleErrorCode());
215 auto Relocations = Base::Obj.relas(SecRef);
216 if (!Relocations)
217 return Relocations.takeError();
219 for (const auto &Rela : *Relocations) {
220 auto Type = Rela.getType(false);
222 LLVM_DEBUG({
223 dbgs() << "Relocation Type: " << Type << "\n"
224 << "Name: " << Base::Obj.getRelocationTypeName(Type) << "\n";
227 auto SymbolIndex = Rela.getSymbol(false);
228 auto Symbol = Base::Obj.getRelocationSymbol(Rela, Base::SymTabSec);
229 if (!Symbol)
230 return Symbol.takeError();
232 auto BlockToFix = *(JITSection->blocks().begin());
233 auto *TargetSymbol = Base::getGraphSymbol(SymbolIndex);
235 if (!TargetSymbol) {
236 return make_error<llvm::StringError>(
237 "Could not find symbol at given index, did you add it to "
238 "JITSymbolTable? index: " +
239 std::to_string(SymbolIndex) + ", shndx: " +
240 std::to_string((*Symbol)->st_shndx) + " Size of table: " +
241 std::to_string(Base::GraphSymbols.size()),
242 llvm::inconvertibleErrorCode());
244 int64_t Addend = Rela.r_addend;
245 JITTargetAddress FixupAddress =
246 (*UpdateSection)->sh_addr + Rela.r_offset;
248 LLVM_DEBUG({
249 dbgs() << "Processing relocation at "
250 << format("0x%016" PRIx64, FixupAddress) << "\n";
252 auto Kind = getRelocationKind(Type);
253 if (!Kind)
254 return Kind.takeError();
256 BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
257 *TargetSymbol, Addend);
260 return Error::success();
263 public:
264 ELFLinkGraphBuilder_riscv(StringRef FileName,
265 const object::ELFFile<ELFT> &Obj, const Triple T)
266 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
267 riscv::getEdgeKindName) {}
270 Expected<std::unique_ptr<LinkGraph>>
271 createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) {
272 LLVM_DEBUG({
273 dbgs() << "Building jitlink graph for new input "
274 << ObjectBuffer.getBufferIdentifier() << "...\n";
277 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
278 if (!ELFObj)
279 return ELFObj.takeError();
281 if ((*ELFObj)->getArch() == Triple::riscv64) {
282 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
283 return ELFLinkGraphBuilder_riscv<object::ELF64LE>(
284 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
285 (*ELFObj)->makeTriple())
286 .buildGraph();
287 } else {
288 assert((*ELFObj)->getArch() == Triple::riscv32 &&
289 "Invalid triple for RISCV ELF object file");
290 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
291 return ELFLinkGraphBuilder_riscv<object::ELF32LE>(
292 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(),
293 (*ELFObj)->makeTriple())
294 .buildGraph();
298 void link_ELF_riscv(std::unique_ptr<LinkGraph> G,
299 std::unique_ptr<JITLinkContext> Ctx) {
300 PassConfiguration Config;
301 const Triple &TT = G->getTargetTriple();
302 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
303 if (auto MarkLive = Ctx->getMarkLivePass(TT))
304 Config.PrePrunePasses.push_back(std::move(MarkLive));
305 else
306 Config.PrePrunePasses.push_back(markAllSymbolsLive);
308 if (auto Err = Ctx->modifyPassConfig(*G, Config))
309 return Ctx->notifyFailed(std::move(Err));
311 ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config));
314 } // namespace jitlink
315 } // namespace llvm