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" 14349cc55cSDimitry Andric #include "ELFLinkGraphBuilder.h" 15349cc55cSDimitry Andric #include "JITLinkGeneric.h" 16349cc55cSDimitry Andric #include "PerGraphGOTAndPLTStubsBuilder.h" 17349cc55cSDimitry 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" 2204eeddc0SDimitry Andric #include "llvm/Support/Endian.h" 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric #define DEBUG_TYPE "jitlink" 25fe6060f1SDimitry Andric using namespace llvm; 26349cc55cSDimitry Andric using namespace llvm::jitlink; 27349cc55cSDimitry Andric using namespace llvm::jitlink::riscv; 28fe6060f1SDimitry Andric 29349cc55cSDimitry Andric namespace { 30349cc55cSDimitry Andric 31349cc55cSDimitry Andric class PerGraphGOTAndPLTStubsBuilder_ELF_riscv 32349cc55cSDimitry Andric : public PerGraphGOTAndPLTStubsBuilder< 33349cc55cSDimitry Andric PerGraphGOTAndPLTStubsBuilder_ELF_riscv> { 34349cc55cSDimitry Andric public: 35349cc55cSDimitry Andric static constexpr size_t StubEntrySize = 16; 36349cc55cSDimitry Andric static const uint8_t NullGOTEntryContent[8]; 37349cc55cSDimitry Andric static const uint8_t RV64StubContent[StubEntrySize]; 38349cc55cSDimitry Andric static const uint8_t RV32StubContent[StubEntrySize]; 39349cc55cSDimitry Andric 40349cc55cSDimitry Andric using PerGraphGOTAndPLTStubsBuilder< 41349cc55cSDimitry Andric PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder; 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric bool isRV64() const { return G.getPointerSize() == 8; } 44349cc55cSDimitry Andric 45349cc55cSDimitry Andric bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; } 46349cc55cSDimitry Andric 47349cc55cSDimitry Andric Symbol &createGOTEntry(Symbol &Target) { 4804eeddc0SDimitry Andric Block &GOTBlock = 4904eeddc0SDimitry Andric G.createContentBlock(getGOTSection(), getGOTEntryBlockContent(), 5004eeddc0SDimitry Andric orc::ExecutorAddr(), G.getPointerSize(), 0); 51349cc55cSDimitry Andric GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0); 52349cc55cSDimitry Andric return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false); 53349cc55cSDimitry Andric } 54349cc55cSDimitry Andric 55349cc55cSDimitry Andric Symbol &createPLTStub(Symbol &Target) { 5604eeddc0SDimitry Andric Block &StubContentBlock = G.createContentBlock( 5704eeddc0SDimitry Andric getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 4, 0); 58349cc55cSDimitry Andric auto &GOTEntrySymbol = getGOTEntry(Target); 59349cc55cSDimitry Andric StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0); 60349cc55cSDimitry Andric return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true, 61349cc55cSDimitry Andric false); 62349cc55cSDimitry Andric } 63349cc55cSDimitry Andric 64349cc55cSDimitry Andric void fixGOTEdge(Edge &E, Symbol &GOTEntry) { 65349cc55cSDimitry Andric // Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12) 66349cc55cSDimitry Andric // with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12) 67349cc55cSDimitry Andric // Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI20 68349cc55cSDimitry Andric E.setKind(R_RISCV_PCREL_HI20); 69349cc55cSDimitry Andric E.setTarget(GOTEntry); 70349cc55cSDimitry Andric } 71349cc55cSDimitry Andric 72349cc55cSDimitry Andric void fixPLTEdge(Edge &E, Symbol &PLTStubs) { 73*06c3fb27SDimitry Andric assert((E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT || 74*06c3fb27SDimitry Andric E.getKind() == CallRelaxable) && 75*06c3fb27SDimitry Andric "Not a PLT edge?"); 76349cc55cSDimitry Andric E.setKind(R_RISCV_CALL); 77349cc55cSDimitry Andric E.setTarget(PLTStubs); 78349cc55cSDimitry Andric } 79349cc55cSDimitry Andric 80349cc55cSDimitry Andric bool isExternalBranchEdge(Edge &E) const { 81*06c3fb27SDimitry Andric return (E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT || 82*06c3fb27SDimitry Andric E.getKind() == CallRelaxable) && 83*06c3fb27SDimitry Andric !E.getTarget().isDefined(); 84349cc55cSDimitry Andric } 85349cc55cSDimitry Andric 86349cc55cSDimitry Andric private: 87349cc55cSDimitry Andric Section &getGOTSection() const { 88349cc55cSDimitry Andric if (!GOTSection) 89bdd1243dSDimitry Andric GOTSection = &G.createSection("$__GOT", orc::MemProt::Read); 90349cc55cSDimitry Andric return *GOTSection; 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric 93349cc55cSDimitry Andric Section &getStubsSection() const { 94349cc55cSDimitry Andric if (!StubsSection) 95349cc55cSDimitry Andric StubsSection = 96bdd1243dSDimitry Andric &G.createSection("$__STUBS", orc::MemProt::Read | orc::MemProt::Exec); 97349cc55cSDimitry Andric return *StubsSection; 98349cc55cSDimitry Andric } 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric ArrayRef<char> getGOTEntryBlockContent() { 101349cc55cSDimitry Andric return {reinterpret_cast<const char *>(NullGOTEntryContent), 102349cc55cSDimitry Andric G.getPointerSize()}; 103349cc55cSDimitry Andric } 104349cc55cSDimitry Andric 105349cc55cSDimitry Andric ArrayRef<char> getStubBlockContent() { 106349cc55cSDimitry Andric auto StubContent = isRV64() ? RV64StubContent : RV32StubContent; 107349cc55cSDimitry Andric return {reinterpret_cast<const char *>(StubContent), StubEntrySize}; 108349cc55cSDimitry Andric } 109349cc55cSDimitry Andric 110349cc55cSDimitry Andric mutable Section *GOTSection = nullptr; 111349cc55cSDimitry Andric mutable Section *StubsSection = nullptr; 112349cc55cSDimitry Andric }; 113349cc55cSDimitry Andric 114349cc55cSDimitry Andric const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] = 115349cc55cSDimitry Andric {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 116349cc55cSDimitry Andric 117349cc55cSDimitry Andric const uint8_t 118349cc55cSDimitry Andric PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = { 119349cc55cSDimitry Andric 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal 120349cc55cSDimitry Andric 0x03, 0x3e, 0x0e, 0x00, // ld t3, literal(t3) 121349cc55cSDimitry Andric 0x67, 0x00, 0x0e, 0x00, // jr t3 122349cc55cSDimitry Andric 0x13, 0x00, 0x00, 0x00}; // nop 123349cc55cSDimitry Andric 124349cc55cSDimitry Andric const uint8_t 125349cc55cSDimitry Andric PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = { 126349cc55cSDimitry Andric 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal 127349cc55cSDimitry Andric 0x03, 0x2e, 0x0e, 0x00, // lw t3, literal(t3) 128349cc55cSDimitry Andric 0x67, 0x00, 0x0e, 0x00, // jr t3 129349cc55cSDimitry Andric 0x13, 0x00, 0x00, 0x00}; // nop 130349cc55cSDimitry Andric } // namespace 131fe6060f1SDimitry Andric namespace llvm { 132fe6060f1SDimitry Andric namespace jitlink { 133fe6060f1SDimitry Andric 134fe6060f1SDimitry Andric static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) { 135fe6060f1SDimitry Andric using namespace riscv; 136fe6060f1SDimitry Andric assert((E.getKind() == R_RISCV_PCREL_LO12_I || 137fe6060f1SDimitry Andric E.getKind() == R_RISCV_PCREL_LO12_S) && 138fe6060f1SDimitry Andric "Can only have high relocation for R_RISCV_PCREL_LO12_I or " 139fe6060f1SDimitry Andric "R_RISCV_PCREL_LO12_S"); 140fe6060f1SDimitry Andric 141fe6060f1SDimitry Andric const Symbol &Sym = E.getTarget(); 142fe6060f1SDimitry Andric const Block &B = Sym.getBlock(); 14304eeddc0SDimitry Andric orc::ExecutorAddrDiff Offset = Sym.getOffset(); 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric struct Comp { 14604eeddc0SDimitry Andric bool operator()(const Edge &Lhs, orc::ExecutorAddrDiff Offset) { 147fe6060f1SDimitry Andric return Lhs.getOffset() < Offset; 148fe6060f1SDimitry Andric } 14904eeddc0SDimitry Andric bool operator()(orc::ExecutorAddrDiff Offset, const Edge &Rhs) { 150fe6060f1SDimitry Andric return Offset < Rhs.getOffset(); 151fe6060f1SDimitry Andric } 152fe6060f1SDimitry Andric }; 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric auto Bound = 155fe6060f1SDimitry Andric std::equal_range(B.edges().begin(), B.edges().end(), Offset, Comp{}); 156fe6060f1SDimitry Andric 157fe6060f1SDimitry Andric for (auto It = Bound.first; It != Bound.second; ++It) { 158fe6060f1SDimitry Andric if (It->getKind() == R_RISCV_PCREL_HI20) 159fe6060f1SDimitry Andric return *It; 160fe6060f1SDimitry Andric } 161fe6060f1SDimitry Andric 162fe6060f1SDimitry Andric return make_error<JITLinkError>( 163fe6060f1SDimitry Andric "No HI20 PCREL relocation type be found for LO12 PCREL relocation type"); 164fe6060f1SDimitry Andric } 165fe6060f1SDimitry Andric 16604eeddc0SDimitry Andric static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) { 16781ad6265SDimitry Andric return (Num & (((1ULL << Size) - 1) << Low)) >> Low; 16804eeddc0SDimitry Andric } 16904eeddc0SDimitry Andric 17081ad6265SDimitry Andric static inline bool isAlignmentCorrect(uint64_t Value, int N) { 17181ad6265SDimitry Andric return (Value & (N - 1)) ? false : true; 17204eeddc0SDimitry Andric } 17304eeddc0SDimitry Andric 17481ad6265SDimitry Andric // Requires 0 < N <= 64. 17581ad6265SDimitry Andric static inline bool isInRangeForImm(int64_t Value, int N) { 17681ad6265SDimitry Andric return Value == llvm::SignExtend64(Value, N); 177fe6060f1SDimitry Andric } 178fe6060f1SDimitry Andric 179fe6060f1SDimitry Andric class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> { 180fe6060f1SDimitry Andric friend class JITLinker<ELFJITLinker_riscv>; 181fe6060f1SDimitry Andric 182fe6060f1SDimitry Andric public: 183fe6060f1SDimitry Andric ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx, 184fe6060f1SDimitry Andric std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) 185fe6060f1SDimitry Andric : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric private: 188fe6060f1SDimitry Andric Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 189fe6060f1SDimitry Andric using namespace riscv; 190fe6060f1SDimitry Andric using namespace llvm::support; 191fe6060f1SDimitry Andric 192fe6060f1SDimitry Andric char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 193fe6060f1SDimitry Andric char *FixupPtr = BlockWorkingMem + E.getOffset(); 19404eeddc0SDimitry Andric orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset(); 195fe6060f1SDimitry Andric switch (E.getKind()) { 196349cc55cSDimitry Andric case R_RISCV_32: { 19704eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 198349cc55cSDimitry Andric *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 199349cc55cSDimitry Andric break; 200349cc55cSDimitry Andric } 201349cc55cSDimitry Andric case R_RISCV_64: { 20204eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 203349cc55cSDimitry Andric *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 204349cc55cSDimitry Andric break; 205349cc55cSDimitry Andric } 20604eeddc0SDimitry Andric case R_RISCV_BRANCH: { 20704eeddc0SDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 20881ad6265SDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 12))) 20981ad6265SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 21081ad6265SDimitry Andric if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 21181ad6265SDimitry Andric return makeAlignmentError(FixupAddress, Value, 2, E); 212bdd1243dSDimitry Andric uint32_t Imm12 = extractBits(Value, 12, 1) << 31; 213bdd1243dSDimitry Andric uint32_t Imm10_5 = extractBits(Value, 5, 6) << 25; 214bdd1243dSDimitry Andric uint32_t Imm4_1 = extractBits(Value, 1, 4) << 8; 215bdd1243dSDimitry Andric uint32_t Imm11 = extractBits(Value, 11, 1) << 7; 216fe6060f1SDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 217bdd1243dSDimitry Andric *(little32_t *)FixupPtr = 218bdd1243dSDimitry Andric (RawInstr & 0x1FFF07F) | Imm12 | Imm10_5 | Imm4_1 | Imm11; 21904eeddc0SDimitry Andric break; 22004eeddc0SDimitry Andric } 22181ad6265SDimitry Andric case R_RISCV_JAL: { 22281ad6265SDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 22381ad6265SDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 20))) 22481ad6265SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 22581ad6265SDimitry Andric if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 22681ad6265SDimitry Andric return makeAlignmentError(FixupAddress, Value, 2, E); 22781ad6265SDimitry Andric uint32_t Imm20 = extractBits(Value, 20, 1) << 31; 22881ad6265SDimitry Andric uint32_t Imm10_1 = extractBits(Value, 1, 10) << 21; 22981ad6265SDimitry Andric uint32_t Imm11 = extractBits(Value, 11, 1) << 20; 23081ad6265SDimitry Andric uint32_t Imm19_12 = extractBits(Value, 12, 8) << 12; 23181ad6265SDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 23204eeddc0SDimitry Andric *(little32_t *)FixupPtr = 233bdd1243dSDimitry Andric (RawInstr & 0xFFF) | Imm20 | Imm10_1 | Imm11 | Imm19_12; 234fe6060f1SDimitry Andric break; 235fe6060f1SDimitry Andric } 236*06c3fb27SDimitry Andric case CallRelaxable: 237*06c3fb27SDimitry Andric // Treat as R_RISCV_CALL when the relaxation pass did not run 238*06c3fb27SDimitry Andric case R_RISCV_CALL_PLT: 239fe6060f1SDimitry Andric case R_RISCV_CALL: { 240fe6060f1SDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 24104eeddc0SDimitry Andric int64_t Hi = Value + 0x800; 24281ad6265SDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 24304eeddc0SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 244fe6060f1SDimitry Andric int32_t Lo = Value & 0xFFF; 245fe6060f1SDimitry Andric uint32_t RawInstrAuipc = *(little32_t *)FixupPtr; 246fe6060f1SDimitry Andric uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4); 24704eeddc0SDimitry Andric *(little32_t *)FixupPtr = 24804eeddc0SDimitry Andric RawInstrAuipc | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 249fe6060f1SDimitry Andric *(little32_t *)(FixupPtr + 4) = 250fe6060f1SDimitry Andric RawInstrJalr | (static_cast<uint32_t>(Lo) << 20); 251fe6060f1SDimitry Andric break; 252fe6060f1SDimitry Andric } 253bdd1243dSDimitry Andric // The relocations R_RISCV_CALL_PLT and R_RISCV_GOT_HI20 are handled by 254bdd1243dSDimitry Andric // PerGraphGOTAndPLTStubsBuilder_ELF_riscv and are transformed into 255bdd1243dSDimitry Andric // R_RISCV_CALL and R_RISCV_PCREL_HI20. 256fe6060f1SDimitry Andric case R_RISCV_PCREL_HI20: { 257fe6060f1SDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 25804eeddc0SDimitry Andric int64_t Hi = Value + 0x800; 25981ad6265SDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 26004eeddc0SDimitry Andric return makeTargetOutOfRangeError(G, B, E); 261fe6060f1SDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 26204eeddc0SDimitry Andric *(little32_t *)FixupPtr = 26304eeddc0SDimitry Andric (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 264fe6060f1SDimitry Andric break; 265fe6060f1SDimitry Andric } 266fe6060f1SDimitry Andric case R_RISCV_PCREL_LO12_I: { 26704eeddc0SDimitry Andric // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and 26804eeddc0SDimitry Andric // pairs with current relocation R_RISCV_PCREL_LO12_I. So here may need a 26904eeddc0SDimitry Andric // check. 270fe6060f1SDimitry Andric auto RelHI20 = getRISCVPCRelHi20(E); 271fe6060f1SDimitry Andric if (!RelHI20) 272fe6060f1SDimitry Andric return RelHI20.takeError(); 273fe6060f1SDimitry Andric int64_t Value = RelHI20->getTarget().getAddress() + 274fe6060f1SDimitry Andric RelHI20->getAddend() - E.getTarget().getAddress(); 275fe6060f1SDimitry Andric int64_t Lo = Value & 0xFFF; 276fe6060f1SDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 277fe6060f1SDimitry Andric *(little32_t *)FixupPtr = 278fe6060f1SDimitry Andric (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20); 279fe6060f1SDimitry Andric break; 280fe6060f1SDimitry Andric } 281fe6060f1SDimitry Andric case R_RISCV_PCREL_LO12_S: { 28204eeddc0SDimitry Andric // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and 28304eeddc0SDimitry Andric // pairs with current relocation R_RISCV_PCREL_LO12_S. So here may need a 28404eeddc0SDimitry Andric // check. 285fe6060f1SDimitry Andric auto RelHI20 = getRISCVPCRelHi20(E); 286bdd1243dSDimitry Andric if (!RelHI20) 287bdd1243dSDimitry Andric return RelHI20.takeError(); 288fe6060f1SDimitry Andric int64_t Value = RelHI20->getTarget().getAddress() + 289fe6060f1SDimitry Andric RelHI20->getAddend() - E.getTarget().getAddress(); 290fe6060f1SDimitry Andric int64_t Lo = Value & 0xFFF; 291bdd1243dSDimitry Andric uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25; 292bdd1243dSDimitry Andric uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7; 293fe6060f1SDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 294fe6060f1SDimitry Andric 295bdd1243dSDimitry Andric *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0; 296fe6060f1SDimitry Andric break; 297fe6060f1SDimitry Andric } 298bdd1243dSDimitry Andric case R_RISCV_HI20: { 299bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 300bdd1243dSDimitry Andric int64_t Hi = Value + 0x800; 301bdd1243dSDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 302bdd1243dSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 303bdd1243dSDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 304bdd1243dSDimitry Andric *(little32_t *)FixupPtr = 305bdd1243dSDimitry Andric (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 30604eeddc0SDimitry Andric break; 30704eeddc0SDimitry Andric } 308bdd1243dSDimitry Andric case R_RISCV_LO12_I: { 309bdd1243dSDimitry Andric // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs 310bdd1243dSDimitry Andric // with current relocation R_RISCV_LO12_I. So here may need a check. 311bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 312bdd1243dSDimitry Andric int32_t Lo = Value & 0xFFF; 313bdd1243dSDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 314bdd1243dSDimitry Andric *(little32_t *)FixupPtr = 315bdd1243dSDimitry Andric (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20); 31604eeddc0SDimitry Andric break; 31704eeddc0SDimitry Andric } 318bdd1243dSDimitry Andric case R_RISCV_LO12_S: { 319bdd1243dSDimitry Andric // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs 320bdd1243dSDimitry Andric // with current relocation R_RISCV_LO12_S. So here may need a check. 321bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 322bdd1243dSDimitry Andric int64_t Lo = Value & 0xFFF; 323bdd1243dSDimitry Andric uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25; 324bdd1243dSDimitry Andric uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7; 325bdd1243dSDimitry Andric uint32_t RawInstr = *(little32_t *)FixupPtr; 326bdd1243dSDimitry Andric *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0; 32704eeddc0SDimitry Andric break; 32804eeddc0SDimitry Andric } 32904eeddc0SDimitry Andric case R_RISCV_ADD8: { 33004eeddc0SDimitry Andric int64_t Value = 33104eeddc0SDimitry Andric (E.getTarget().getAddress() + 332*06c3fb27SDimitry Andric *(reinterpret_cast<const uint8_t *>(FixupPtr)) + E.getAddend()) 33304eeddc0SDimitry Andric .getValue(); 33404eeddc0SDimitry Andric *FixupPtr = static_cast<uint8_t>(Value); 33504eeddc0SDimitry Andric break; 33604eeddc0SDimitry Andric } 337bdd1243dSDimitry Andric case R_RISCV_ADD16: { 338bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + 339*06c3fb27SDimitry Andric support::endian::read16le(FixupPtr) + E.getAddend()) 340bdd1243dSDimitry Andric .getValue(); 341bdd1243dSDimitry Andric *(little16_t *)FixupPtr = static_cast<uint16_t>(Value); 342bdd1243dSDimitry Andric break; 343bdd1243dSDimitry Andric } 344bdd1243dSDimitry Andric case R_RISCV_ADD32: { 345bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + 346*06c3fb27SDimitry Andric support::endian::read32le(FixupPtr) + E.getAddend()) 347bdd1243dSDimitry Andric .getValue(); 348bdd1243dSDimitry Andric *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 349bdd1243dSDimitry Andric break; 350bdd1243dSDimitry Andric } 351bdd1243dSDimitry Andric case R_RISCV_ADD64: { 352bdd1243dSDimitry Andric int64_t Value = (E.getTarget().getAddress() + 353*06c3fb27SDimitry Andric support::endian::read64le(FixupPtr) + E.getAddend()) 354bdd1243dSDimitry Andric .getValue(); 35504eeddc0SDimitry Andric *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 35604eeddc0SDimitry Andric break; 35704eeddc0SDimitry Andric } 358bdd1243dSDimitry Andric case R_RISCV_SUB8: { 359*06c3fb27SDimitry Andric int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) - 36004eeddc0SDimitry Andric E.getTarget().getAddress().getValue() - E.getAddend(); 361bdd1243dSDimitry Andric *FixupPtr = static_cast<uint8_t>(Value); 36204eeddc0SDimitry Andric break; 36304eeddc0SDimitry Andric } 36404eeddc0SDimitry Andric case R_RISCV_SUB16: { 365*06c3fb27SDimitry Andric int64_t Value = support::endian::read16le(FixupPtr) - 36604eeddc0SDimitry Andric E.getTarget().getAddress().getValue() - E.getAddend(); 36704eeddc0SDimitry Andric *(little16_t *)FixupPtr = static_cast<uint32_t>(Value); 36804eeddc0SDimitry Andric break; 36904eeddc0SDimitry Andric } 370bdd1243dSDimitry Andric case R_RISCV_SUB32: { 371*06c3fb27SDimitry Andric int64_t Value = support::endian::read32le(FixupPtr) - 37204eeddc0SDimitry Andric E.getTarget().getAddress().getValue() - E.getAddend(); 373bdd1243dSDimitry Andric *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 374bdd1243dSDimitry Andric break; 375bdd1243dSDimitry Andric } 376bdd1243dSDimitry Andric case R_RISCV_SUB64: { 377*06c3fb27SDimitry Andric int64_t Value = support::endian::read64le(FixupPtr) - 378bdd1243dSDimitry Andric E.getTarget().getAddress().getValue() - E.getAddend(); 379bdd1243dSDimitry Andric *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 380bdd1243dSDimitry Andric break; 381bdd1243dSDimitry Andric } 382bdd1243dSDimitry Andric case R_RISCV_RVC_BRANCH: { 383bdd1243dSDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 384bdd1243dSDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 8))) 385bdd1243dSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 386bdd1243dSDimitry Andric if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 387bdd1243dSDimitry Andric return makeAlignmentError(FixupAddress, Value, 2, E); 388bdd1243dSDimitry Andric uint16_t Imm8 = extractBits(Value, 8, 1) << 12; 389bdd1243dSDimitry Andric uint16_t Imm4_3 = extractBits(Value, 3, 2) << 10; 390bdd1243dSDimitry Andric uint16_t Imm7_6 = extractBits(Value, 6, 2) << 5; 391bdd1243dSDimitry Andric uint16_t Imm2_1 = extractBits(Value, 1, 2) << 3; 392bdd1243dSDimitry Andric uint16_t Imm5 = extractBits(Value, 5, 1) << 2; 393bdd1243dSDimitry Andric uint16_t RawInstr = *(little16_t *)FixupPtr; 394bdd1243dSDimitry Andric *(little16_t *)FixupPtr = 395bdd1243dSDimitry Andric (RawInstr & 0xE383) | Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; 396bdd1243dSDimitry Andric break; 397bdd1243dSDimitry Andric } 398bdd1243dSDimitry Andric case R_RISCV_RVC_JUMP: { 399bdd1243dSDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 400bdd1243dSDimitry Andric if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 11))) 401bdd1243dSDimitry Andric return makeTargetOutOfRangeError(G, B, E); 402bdd1243dSDimitry Andric if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 403bdd1243dSDimitry Andric return makeAlignmentError(FixupAddress, Value, 2, E); 404bdd1243dSDimitry Andric uint16_t Imm11 = extractBits(Value, 11, 1) << 12; 405bdd1243dSDimitry Andric uint16_t Imm4 = extractBits(Value, 4, 1) << 11; 406bdd1243dSDimitry Andric uint16_t Imm9_8 = extractBits(Value, 8, 2) << 9; 407bdd1243dSDimitry Andric uint16_t Imm10 = extractBits(Value, 10, 1) << 8; 408bdd1243dSDimitry Andric uint16_t Imm6 = extractBits(Value, 6, 1) << 7; 409bdd1243dSDimitry Andric uint16_t Imm7 = extractBits(Value, 7, 1) << 6; 410bdd1243dSDimitry Andric uint16_t Imm3_1 = extractBits(Value, 1, 3) << 3; 411bdd1243dSDimitry Andric uint16_t Imm5 = extractBits(Value, 5, 1) << 2; 412bdd1243dSDimitry Andric uint16_t RawInstr = *(little16_t *)FixupPtr; 413bdd1243dSDimitry Andric *(little16_t *)FixupPtr = (RawInstr & 0xE003) | Imm11 | Imm4 | Imm9_8 | 414bdd1243dSDimitry Andric Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; 41504eeddc0SDimitry Andric break; 41604eeddc0SDimitry Andric } 41781ad6265SDimitry Andric case R_RISCV_SUB6: { 418*06c3fb27SDimitry Andric int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) & 0x3f; 41981ad6265SDimitry Andric Value -= E.getTarget().getAddress().getValue() - E.getAddend(); 42081ad6265SDimitry Andric *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<uint8_t>(Value) & 0x3f); 42181ad6265SDimitry Andric break; 42281ad6265SDimitry Andric } 42304eeddc0SDimitry Andric case R_RISCV_SET6: { 42404eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 42504eeddc0SDimitry Andric uint32_t RawData = *(little32_t *)FixupPtr; 42604eeddc0SDimitry Andric int64_t Word6 = Value & 0x3f; 42704eeddc0SDimitry Andric *(little32_t *)FixupPtr = (RawData & 0xffffffc0) | Word6; 42804eeddc0SDimitry Andric break; 42904eeddc0SDimitry Andric } 43004eeddc0SDimitry Andric case R_RISCV_SET8: { 43104eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 43204eeddc0SDimitry Andric uint32_t RawData = *(little32_t *)FixupPtr; 43304eeddc0SDimitry Andric int64_t Word8 = Value & 0xff; 43404eeddc0SDimitry Andric *(little32_t *)FixupPtr = (RawData & 0xffffff00) | Word8; 43504eeddc0SDimitry Andric break; 43604eeddc0SDimitry Andric } 43704eeddc0SDimitry Andric case R_RISCV_SET16: { 43804eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 43904eeddc0SDimitry Andric uint32_t RawData = *(little32_t *)FixupPtr; 44004eeddc0SDimitry Andric int64_t Word16 = Value & 0xffff; 44104eeddc0SDimitry Andric *(little32_t *)FixupPtr = (RawData & 0xffff0000) | Word16; 44204eeddc0SDimitry Andric break; 44304eeddc0SDimitry Andric } 44404eeddc0SDimitry Andric case R_RISCV_SET32: { 44504eeddc0SDimitry Andric int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 44604eeddc0SDimitry Andric int64_t Word32 = Value & 0xffffffff; 44704eeddc0SDimitry Andric *(little32_t *)FixupPtr = Word32; 44804eeddc0SDimitry Andric break; 44904eeddc0SDimitry Andric } 45004eeddc0SDimitry Andric case R_RISCV_32_PCREL: { 45104eeddc0SDimitry Andric int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 45204eeddc0SDimitry Andric int64_t Word32 = Value & 0xffffffff; 45304eeddc0SDimitry Andric *(little32_t *)FixupPtr = Word32; 45404eeddc0SDimitry Andric break; 45504eeddc0SDimitry Andric } 456*06c3fb27SDimitry Andric case AlignRelaxable: 457*06c3fb27SDimitry Andric // Ignore when the relaxation pass did not run 458*06c3fb27SDimitry Andric break; 459fe6060f1SDimitry Andric } 460fe6060f1SDimitry Andric return Error::success(); 461fe6060f1SDimitry Andric } 462fe6060f1SDimitry Andric }; 463fe6060f1SDimitry Andric 464*06c3fb27SDimitry Andric namespace { 465*06c3fb27SDimitry Andric 466*06c3fb27SDimitry Andric struct SymbolAnchor { 467*06c3fb27SDimitry Andric uint64_t Offset; 468*06c3fb27SDimitry Andric Symbol *Sym; 469*06c3fb27SDimitry Andric bool End; // true for the anchor of getOffset() + getSize() 470*06c3fb27SDimitry Andric }; 471*06c3fb27SDimitry Andric 472*06c3fb27SDimitry Andric struct BlockRelaxAux { 473*06c3fb27SDimitry Andric // This records symbol start and end offsets which will be adjusted according 474*06c3fb27SDimitry Andric // to the nearest RelocDeltas element. 475*06c3fb27SDimitry Andric SmallVector<SymbolAnchor, 0> Anchors; 476*06c3fb27SDimitry Andric // All edges that either 1) are R_RISCV_ALIGN or 2) have a R_RISCV_RELAX edge 477*06c3fb27SDimitry Andric // at the same offset. 478*06c3fb27SDimitry Andric SmallVector<Edge *, 0> RelaxEdges; 479*06c3fb27SDimitry Andric // For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ? 480*06c3fb27SDimitry Andric // RelocDeltas[I - 1] : 0). 481*06c3fb27SDimitry Andric SmallVector<uint32_t, 0> RelocDeltas; 482*06c3fb27SDimitry Andric // For RelaxEdges[I], the actual type is EdgeKinds[I]. 483*06c3fb27SDimitry Andric SmallVector<Edge::Kind, 0> EdgeKinds; 484*06c3fb27SDimitry Andric // List of rewritten instructions. Contains one raw encoded instruction per 485*06c3fb27SDimitry Andric // element in EdgeKinds that isn't Invalid or R_RISCV_ALIGN. 486*06c3fb27SDimitry Andric SmallVector<uint32_t, 0> Writes; 487*06c3fb27SDimitry Andric }; 488*06c3fb27SDimitry Andric 489*06c3fb27SDimitry Andric struct RelaxConfig { 490*06c3fb27SDimitry Andric bool IsRV32; 491*06c3fb27SDimitry Andric bool HasRVC; 492*06c3fb27SDimitry Andric }; 493*06c3fb27SDimitry Andric 494*06c3fb27SDimitry Andric struct RelaxAux { 495*06c3fb27SDimitry Andric RelaxConfig Config; 496*06c3fb27SDimitry Andric DenseMap<Block *, BlockRelaxAux> Blocks; 497*06c3fb27SDimitry Andric }; 498*06c3fb27SDimitry Andric 499*06c3fb27SDimitry Andric } // namespace 500*06c3fb27SDimitry Andric 501*06c3fb27SDimitry Andric static bool shouldRelax(const Section &S) { 502*06c3fb27SDimitry Andric return (S.getMemProt() & orc::MemProt::Exec) != orc::MemProt::None; 503*06c3fb27SDimitry Andric } 504*06c3fb27SDimitry Andric 505*06c3fb27SDimitry Andric static bool isRelaxable(const Edge &E) { 506*06c3fb27SDimitry Andric switch (E.getKind()) { 507*06c3fb27SDimitry Andric default: 508*06c3fb27SDimitry Andric return false; 509*06c3fb27SDimitry Andric case CallRelaxable: 510*06c3fb27SDimitry Andric case AlignRelaxable: 511*06c3fb27SDimitry Andric return true; 512*06c3fb27SDimitry Andric } 513*06c3fb27SDimitry Andric } 514*06c3fb27SDimitry Andric 515*06c3fb27SDimitry Andric static RelaxAux initRelaxAux(LinkGraph &G) { 516*06c3fb27SDimitry Andric RelaxAux Aux; 517*06c3fb27SDimitry Andric Aux.Config.IsRV32 = G.getTargetTriple().isRISCV32(); 518*06c3fb27SDimitry Andric const auto &Features = G.getFeatures().getFeatures(); 519*06c3fb27SDimitry Andric Aux.Config.HasRVC = 520*06c3fb27SDimitry Andric std::find(Features.begin(), Features.end(), "+c") != Features.end(); 521*06c3fb27SDimitry Andric 522*06c3fb27SDimitry Andric for (auto &S : G.sections()) { 523*06c3fb27SDimitry Andric if (!shouldRelax(S)) 524*06c3fb27SDimitry Andric continue; 525*06c3fb27SDimitry Andric for (auto *B : S.blocks()) { 526*06c3fb27SDimitry Andric auto BlockEmplaceResult = Aux.Blocks.try_emplace(B); 527*06c3fb27SDimitry Andric assert(BlockEmplaceResult.second && "Block encountered twice"); 528*06c3fb27SDimitry Andric auto &BlockAux = BlockEmplaceResult.first->second; 529*06c3fb27SDimitry Andric 530*06c3fb27SDimitry Andric for (auto &E : B->edges()) 531*06c3fb27SDimitry Andric if (isRelaxable(E)) 532*06c3fb27SDimitry Andric BlockAux.RelaxEdges.push_back(&E); 533*06c3fb27SDimitry Andric 534*06c3fb27SDimitry Andric if (BlockAux.RelaxEdges.empty()) { 535*06c3fb27SDimitry Andric Aux.Blocks.erase(BlockEmplaceResult.first); 536*06c3fb27SDimitry Andric continue; 537*06c3fb27SDimitry Andric } 538*06c3fb27SDimitry Andric 539*06c3fb27SDimitry Andric const auto NumEdges = BlockAux.RelaxEdges.size(); 540*06c3fb27SDimitry Andric BlockAux.RelocDeltas.resize(NumEdges, 0); 541*06c3fb27SDimitry Andric BlockAux.EdgeKinds.resize_for_overwrite(NumEdges); 542*06c3fb27SDimitry Andric 543*06c3fb27SDimitry Andric // Store anchors (offset and offset+size) for symbols. 544*06c3fb27SDimitry Andric for (auto *Sym : S.symbols()) { 545*06c3fb27SDimitry Andric if (!Sym->isDefined() || &Sym->getBlock() != B) 546*06c3fb27SDimitry Andric continue; 547*06c3fb27SDimitry Andric 548*06c3fb27SDimitry Andric BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false}); 549*06c3fb27SDimitry Andric BlockAux.Anchors.push_back( 550*06c3fb27SDimitry Andric {Sym->getOffset() + Sym->getSize(), Sym, true}); 551*06c3fb27SDimitry Andric } 552*06c3fb27SDimitry Andric } 553*06c3fb27SDimitry Andric } 554*06c3fb27SDimitry Andric 555*06c3fb27SDimitry Andric // Sort anchors by offset so that we can find the closest relocation 556*06c3fb27SDimitry Andric // efficiently. For a zero size symbol, ensure that its start anchor precedes 557*06c3fb27SDimitry Andric // its end anchor. For two symbols with anchors at the same offset, their 558*06c3fb27SDimitry Andric // order does not matter. 559*06c3fb27SDimitry Andric for (auto &BlockAuxIter : Aux.Blocks) { 560*06c3fb27SDimitry Andric llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) { 561*06c3fb27SDimitry Andric return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End); 562*06c3fb27SDimitry Andric }); 563*06c3fb27SDimitry Andric } 564*06c3fb27SDimitry Andric 565*06c3fb27SDimitry Andric return Aux; 566*06c3fb27SDimitry Andric } 567*06c3fb27SDimitry Andric 568*06c3fb27SDimitry Andric static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove, 569*06c3fb27SDimitry Andric Edge::Kind &NewEdgeKind) { 570*06c3fb27SDimitry Andric // E points to the start of the padding bytes. 571*06c3fb27SDimitry Andric // E + Addend points to the instruction to be aligned by removing padding. 572*06c3fb27SDimitry Andric // Alignment is the smallest power of 2 strictly greater than Addend. 573*06c3fb27SDimitry Andric const auto Align = NextPowerOf2(E.getAddend()); 574*06c3fb27SDimitry Andric const auto DestLoc = alignTo(Loc.getValue(), Align); 575*06c3fb27SDimitry Andric const auto SrcLoc = Loc.getValue() + E.getAddend(); 576*06c3fb27SDimitry Andric Remove = SrcLoc - DestLoc; 577*06c3fb27SDimitry Andric assert(static_cast<int32_t>(Remove) >= 0 && 578*06c3fb27SDimitry Andric "R_RISCV_ALIGN needs expanding the content"); 579*06c3fb27SDimitry Andric NewEdgeKind = AlignRelaxable; 580*06c3fb27SDimitry Andric } 581*06c3fb27SDimitry Andric 582*06c3fb27SDimitry Andric static void relaxCall(const Block &B, BlockRelaxAux &Aux, 583*06c3fb27SDimitry Andric const RelaxConfig &Config, orc::ExecutorAddr Loc, 584*06c3fb27SDimitry Andric const Edge &E, uint32_t &Remove, 585*06c3fb27SDimitry Andric Edge::Kind &NewEdgeKind) { 586*06c3fb27SDimitry Andric const auto JALR = 587*06c3fb27SDimitry Andric support::endian::read32le(B.getContent().data() + E.getOffset() + 4); 588*06c3fb27SDimitry Andric const auto RD = extractBits(JALR, 7, 5); 589*06c3fb27SDimitry Andric const auto Dest = E.getTarget().getAddress() + E.getAddend(); 590*06c3fb27SDimitry Andric const auto Displace = Dest - Loc; 591*06c3fb27SDimitry Andric 592*06c3fb27SDimitry Andric if (Config.HasRVC && isInt<12>(Displace) && RD == 0) { 593*06c3fb27SDimitry Andric NewEdgeKind = R_RISCV_RVC_JUMP; 594*06c3fb27SDimitry Andric Aux.Writes.push_back(0xa001); // c.j 595*06c3fb27SDimitry Andric Remove = 6; 596*06c3fb27SDimitry Andric } else if (Config.HasRVC && Config.IsRV32 && isInt<12>(Displace) && RD == 1) { 597*06c3fb27SDimitry Andric NewEdgeKind = R_RISCV_RVC_JUMP; 598*06c3fb27SDimitry Andric Aux.Writes.push_back(0x2001); // c.jal 599*06c3fb27SDimitry Andric Remove = 6; 600*06c3fb27SDimitry Andric } else if (isInt<21>(Displace)) { 601*06c3fb27SDimitry Andric NewEdgeKind = R_RISCV_JAL; 602*06c3fb27SDimitry Andric Aux.Writes.push_back(0x6f | RD << 7); // jal 603*06c3fb27SDimitry Andric Remove = 4; 604*06c3fb27SDimitry Andric } else { 605*06c3fb27SDimitry Andric // Not relaxable 606*06c3fb27SDimitry Andric NewEdgeKind = R_RISCV_CALL_PLT; 607*06c3fb27SDimitry Andric Remove = 0; 608*06c3fb27SDimitry Andric } 609*06c3fb27SDimitry Andric } 610*06c3fb27SDimitry Andric 611*06c3fb27SDimitry Andric static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux, 612*06c3fb27SDimitry Andric const RelaxConfig &Config) { 613*06c3fb27SDimitry Andric const auto BlockAddr = Block.getAddress(); 614*06c3fb27SDimitry Andric bool Changed = false; 615*06c3fb27SDimitry Andric ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors); 616*06c3fb27SDimitry Andric uint32_t Delta = 0; 617*06c3fb27SDimitry Andric 618*06c3fb27SDimitry Andric Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid); 619*06c3fb27SDimitry Andric Aux.Writes.clear(); 620*06c3fb27SDimitry Andric 621*06c3fb27SDimitry Andric for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 622*06c3fb27SDimitry Andric const auto Loc = BlockAddr + E->getOffset() - Delta; 623*06c3fb27SDimitry Andric auto &Cur = Aux.RelocDeltas[I]; 624*06c3fb27SDimitry Andric uint32_t Remove = 0; 625*06c3fb27SDimitry Andric switch (E->getKind()) { 626*06c3fb27SDimitry Andric case AlignRelaxable: 627*06c3fb27SDimitry Andric relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]); 628*06c3fb27SDimitry Andric break; 629*06c3fb27SDimitry Andric case CallRelaxable: 630*06c3fb27SDimitry Andric relaxCall(Block, Aux, Config, Loc, *E, Remove, Aux.EdgeKinds[I]); 631*06c3fb27SDimitry Andric break; 632*06c3fb27SDimitry Andric default: 633*06c3fb27SDimitry Andric llvm_unreachable("Unexpected relaxable edge kind"); 634*06c3fb27SDimitry Andric } 635*06c3fb27SDimitry Andric 636*06c3fb27SDimitry Andric // For all anchors whose offsets are <= E->getOffset(), they are preceded by 637*06c3fb27SDimitry Andric // the previous relocation whose RelocDeltas value equals Delta. 638*06c3fb27SDimitry Andric // Decrease their offset and update their size. 639*06c3fb27SDimitry Andric for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) { 640*06c3fb27SDimitry Andric if (SA[0].End) 641*06c3fb27SDimitry Andric SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset()); 642*06c3fb27SDimitry Andric else 643*06c3fb27SDimitry Andric SA[0].Sym->setOffset(SA[0].Offset - Delta); 644*06c3fb27SDimitry Andric } 645*06c3fb27SDimitry Andric 646*06c3fb27SDimitry Andric Delta += Remove; 647*06c3fb27SDimitry Andric if (Delta != Cur) { 648*06c3fb27SDimitry Andric Cur = Delta; 649*06c3fb27SDimitry Andric Changed = true; 650*06c3fb27SDimitry Andric } 651*06c3fb27SDimitry Andric } 652*06c3fb27SDimitry Andric 653*06c3fb27SDimitry Andric for (const SymbolAnchor &A : SA) { 654*06c3fb27SDimitry Andric if (A.End) 655*06c3fb27SDimitry Andric A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset()); 656*06c3fb27SDimitry Andric else 657*06c3fb27SDimitry Andric A.Sym->setOffset(A.Offset - Delta); 658*06c3fb27SDimitry Andric } 659*06c3fb27SDimitry Andric 660*06c3fb27SDimitry Andric return Changed; 661*06c3fb27SDimitry Andric } 662*06c3fb27SDimitry Andric 663*06c3fb27SDimitry Andric static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) { 664*06c3fb27SDimitry Andric bool Changed = false; 665*06c3fb27SDimitry Andric 666*06c3fb27SDimitry Andric for (auto &[B, BlockAux] : Aux.Blocks) 667*06c3fb27SDimitry Andric Changed |= relaxBlock(G, *B, BlockAux, Aux.Config); 668*06c3fb27SDimitry Andric 669*06c3fb27SDimitry Andric return Changed; 670*06c3fb27SDimitry Andric } 671*06c3fb27SDimitry Andric 672*06c3fb27SDimitry Andric static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) { 673*06c3fb27SDimitry Andric auto Contents = Block.getAlreadyMutableContent(); 674*06c3fb27SDimitry Andric auto *Dest = Contents.data(); 675*06c3fb27SDimitry Andric auto NextWrite = Aux.Writes.begin(); 676*06c3fb27SDimitry Andric uint32_t Offset = 0; 677*06c3fb27SDimitry Andric uint32_t Delta = 0; 678*06c3fb27SDimitry Andric 679*06c3fb27SDimitry Andric // Update section content: remove NOPs for R_RISCV_ALIGN and rewrite 680*06c3fb27SDimitry Andric // instructions for relaxed relocations. 681*06c3fb27SDimitry Andric for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 682*06c3fb27SDimitry Andric uint32_t Remove = Aux.RelocDeltas[I] - Delta; 683*06c3fb27SDimitry Andric Delta = Aux.RelocDeltas[I]; 684*06c3fb27SDimitry Andric if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid) 685*06c3fb27SDimitry Andric continue; 686*06c3fb27SDimitry Andric 687*06c3fb27SDimitry Andric // Copy from last location to the current relocated location. 688*06c3fb27SDimitry Andric const auto Size = E->getOffset() - Offset; 689*06c3fb27SDimitry Andric std::memmove(Dest, Contents.data() + Offset, Size); 690*06c3fb27SDimitry Andric Dest += Size; 691*06c3fb27SDimitry Andric 692*06c3fb27SDimitry Andric uint32_t Skip = 0; 693*06c3fb27SDimitry Andric switch (Aux.EdgeKinds[I]) { 694*06c3fb27SDimitry Andric case Edge::Invalid: 695*06c3fb27SDimitry Andric break; 696*06c3fb27SDimitry Andric case AlignRelaxable: 697*06c3fb27SDimitry Andric // For R_RISCV_ALIGN, we will place Offset in a location (among NOPs) to 698*06c3fb27SDimitry Andric // satisfy the alignment requirement. If both Remove and E->getAddend() 699*06c3fb27SDimitry Andric // are multiples of 4, it is as if we have skipped some NOPs. Otherwise we 700*06c3fb27SDimitry Andric // are in the middle of a 4-byte NOP, and we need to rewrite the NOP 701*06c3fb27SDimitry Andric // sequence. 702*06c3fb27SDimitry Andric if (Remove % 4 || E->getAddend() % 4) { 703*06c3fb27SDimitry Andric Skip = E->getAddend() - Remove; 704*06c3fb27SDimitry Andric uint32_t J = 0; 705*06c3fb27SDimitry Andric for (; J + 4 <= Skip; J += 4) 706*06c3fb27SDimitry Andric support::endian::write32le(Dest + J, 0x00000013); // nop 707*06c3fb27SDimitry Andric if (J != Skip) { 708*06c3fb27SDimitry Andric assert(J + 2 == Skip); 709*06c3fb27SDimitry Andric support::endian::write16le(Dest + J, 0x0001); // c.nop 710*06c3fb27SDimitry Andric } 711*06c3fb27SDimitry Andric } 712*06c3fb27SDimitry Andric break; 713*06c3fb27SDimitry Andric case R_RISCV_RVC_JUMP: 714*06c3fb27SDimitry Andric Skip = 2; 715*06c3fb27SDimitry Andric support::endian::write16le(Dest, *NextWrite++); 716*06c3fb27SDimitry Andric break; 717*06c3fb27SDimitry Andric case R_RISCV_JAL: 718*06c3fb27SDimitry Andric Skip = 4; 719*06c3fb27SDimitry Andric support::endian::write32le(Dest, *NextWrite++); 720*06c3fb27SDimitry Andric break; 721*06c3fb27SDimitry Andric } 722*06c3fb27SDimitry Andric 723*06c3fb27SDimitry Andric Dest += Skip; 724*06c3fb27SDimitry Andric Offset = E->getOffset() + Skip + Remove; 725*06c3fb27SDimitry Andric } 726*06c3fb27SDimitry Andric 727*06c3fb27SDimitry Andric std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset); 728*06c3fb27SDimitry Andric 729*06c3fb27SDimitry Andric // Fixup edge offsets and kinds. 730*06c3fb27SDimitry Andric Delta = 0; 731*06c3fb27SDimitry Andric size_t I = 0; 732*06c3fb27SDimitry Andric for (auto &E : Block.edges()) { 733*06c3fb27SDimitry Andric E.setOffset(E.getOffset() - Delta); 734*06c3fb27SDimitry Andric 735*06c3fb27SDimitry Andric if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) { 736*06c3fb27SDimitry Andric if (Aux.EdgeKinds[I] != Edge::Invalid) 737*06c3fb27SDimitry Andric E.setKind(Aux.EdgeKinds[I]); 738*06c3fb27SDimitry Andric 739*06c3fb27SDimitry Andric Delta = Aux.RelocDeltas[I]; 740*06c3fb27SDimitry Andric ++I; 741*06c3fb27SDimitry Andric } 742*06c3fb27SDimitry Andric } 743*06c3fb27SDimitry Andric 744*06c3fb27SDimitry Andric // Remove AlignRelaxable edges: all other relaxable edges got modified and 745*06c3fb27SDimitry Andric // will be used later while linking. Alignment is entirely handled here so we 746*06c3fb27SDimitry Andric // don't need these edges anymore. 747*06c3fb27SDimitry Andric for (auto IE = Block.edges().begin(); IE != Block.edges().end();) { 748*06c3fb27SDimitry Andric if (IE->getKind() == AlignRelaxable) 749*06c3fb27SDimitry Andric IE = Block.removeEdge(IE); 750*06c3fb27SDimitry Andric else 751*06c3fb27SDimitry Andric ++IE; 752*06c3fb27SDimitry Andric } 753*06c3fb27SDimitry Andric } 754*06c3fb27SDimitry Andric 755*06c3fb27SDimitry Andric static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) { 756*06c3fb27SDimitry Andric for (auto &[B, BlockAux] : Aux.Blocks) 757*06c3fb27SDimitry Andric finalizeBlockRelax(G, *B, BlockAux); 758*06c3fb27SDimitry Andric } 759*06c3fb27SDimitry Andric 760*06c3fb27SDimitry Andric static Error relax(LinkGraph &G) { 761*06c3fb27SDimitry Andric auto Aux = initRelaxAux(G); 762*06c3fb27SDimitry Andric while (relaxOnce(G, Aux)) { 763*06c3fb27SDimitry Andric } 764*06c3fb27SDimitry Andric finalizeRelax(G, Aux); 765*06c3fb27SDimitry Andric return Error::success(); 766*06c3fb27SDimitry Andric } 767*06c3fb27SDimitry Andric 768fe6060f1SDimitry Andric template <typename ELFT> 769fe6060f1SDimitry Andric class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> { 770fe6060f1SDimitry Andric private: 771fe6060f1SDimitry Andric static Expected<riscv::EdgeKind_riscv> 772fe6060f1SDimitry Andric getRelocationKind(const uint32_t Type) { 773fe6060f1SDimitry Andric using namespace riscv; 774fe6060f1SDimitry Andric switch (Type) { 775fe6060f1SDimitry Andric case ELF::R_RISCV_32: 776fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_32; 777fe6060f1SDimitry Andric case ELF::R_RISCV_64: 778fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_64; 77904eeddc0SDimitry Andric case ELF::R_RISCV_BRANCH: 78004eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_BRANCH; 78181ad6265SDimitry Andric case ELF::R_RISCV_JAL: 78281ad6265SDimitry Andric return EdgeKind_riscv::R_RISCV_JAL; 783fe6060f1SDimitry Andric case ELF::R_RISCV_CALL: 784fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_CALL; 785bdd1243dSDimitry Andric case ELF::R_RISCV_CALL_PLT: 786bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_CALL_PLT; 787bdd1243dSDimitry Andric case ELF::R_RISCV_GOT_HI20: 788bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_GOT_HI20; 789fe6060f1SDimitry Andric case ELF::R_RISCV_PCREL_HI20: 790fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_PCREL_HI20; 791fe6060f1SDimitry Andric case ELF::R_RISCV_PCREL_LO12_I: 792fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_PCREL_LO12_I; 793fe6060f1SDimitry Andric case ELF::R_RISCV_PCREL_LO12_S: 794fe6060f1SDimitry Andric return EdgeKind_riscv::R_RISCV_PCREL_LO12_S; 795bdd1243dSDimitry Andric case ELF::R_RISCV_HI20: 796bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_HI20; 797bdd1243dSDimitry Andric case ELF::R_RISCV_LO12_I: 798bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_LO12_I; 799bdd1243dSDimitry Andric case ELF::R_RISCV_LO12_S: 800bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_LO12_S; 80104eeddc0SDimitry Andric case ELF::R_RISCV_ADD8: 80204eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_ADD8; 803bdd1243dSDimitry Andric case ELF::R_RISCV_ADD16: 804bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_ADD16; 805bdd1243dSDimitry Andric case ELF::R_RISCV_ADD32: 806bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_ADD32; 807bdd1243dSDimitry Andric case ELF::R_RISCV_ADD64: 808bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_ADD64; 80904eeddc0SDimitry Andric case ELF::R_RISCV_SUB8: 81004eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_SUB8; 811bdd1243dSDimitry Andric case ELF::R_RISCV_SUB16: 812bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_SUB16; 813bdd1243dSDimitry Andric case ELF::R_RISCV_SUB32: 814bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_SUB32; 815bdd1243dSDimitry Andric case ELF::R_RISCV_SUB64: 816bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_SUB64; 817bdd1243dSDimitry Andric case ELF::R_RISCV_RVC_BRANCH: 818bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_RVC_BRANCH; 819bdd1243dSDimitry Andric case ELF::R_RISCV_RVC_JUMP: 820bdd1243dSDimitry Andric return EdgeKind_riscv::R_RISCV_RVC_JUMP; 82181ad6265SDimitry Andric case ELF::R_RISCV_SUB6: 82281ad6265SDimitry Andric return EdgeKind_riscv::R_RISCV_SUB6; 82304eeddc0SDimitry Andric case ELF::R_RISCV_SET6: 82404eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_SET6; 82504eeddc0SDimitry Andric case ELF::R_RISCV_SET8: 82604eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_SET8; 82704eeddc0SDimitry Andric case ELF::R_RISCV_SET16: 82804eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_SET16; 82904eeddc0SDimitry Andric case ELF::R_RISCV_SET32: 83004eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_SET32; 83104eeddc0SDimitry Andric case ELF::R_RISCV_32_PCREL: 83204eeddc0SDimitry Andric return EdgeKind_riscv::R_RISCV_32_PCREL; 833*06c3fb27SDimitry Andric case ELF::R_RISCV_ALIGN: 834*06c3fb27SDimitry Andric return EdgeKind_riscv::AlignRelaxable; 835fe6060f1SDimitry Andric } 836fe6060f1SDimitry Andric 83781ad6265SDimitry Andric return make_error<JITLinkError>( 83881ad6265SDimitry Andric "Unsupported riscv relocation:" + formatv("{0:d}: ", Type) + 83981ad6265SDimitry Andric object::getELFRelocationTypeName(ELF::EM_RISCV, Type)); 840fe6060f1SDimitry Andric } 841fe6060f1SDimitry Andric 842*06c3fb27SDimitry Andric EdgeKind_riscv getRelaxableRelocationKind(EdgeKind_riscv Kind) { 843*06c3fb27SDimitry Andric switch (Kind) { 844*06c3fb27SDimitry Andric default: 845*06c3fb27SDimitry Andric // Just ignore unsupported relaxations 846*06c3fb27SDimitry Andric return Kind; 847*06c3fb27SDimitry Andric case R_RISCV_CALL: 848*06c3fb27SDimitry Andric case R_RISCV_CALL_PLT: 849*06c3fb27SDimitry Andric return CallRelaxable; 850*06c3fb27SDimitry Andric } 851*06c3fb27SDimitry Andric } 852*06c3fb27SDimitry Andric 853fe6060f1SDimitry Andric Error addRelocations() override { 854349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 855349cc55cSDimitry Andric 856fe6060f1SDimitry Andric using Base = ELFLinkGraphBuilder<ELFT>; 857349cc55cSDimitry Andric using Self = ELFLinkGraphBuilder_riscv<ELFT>; 858349cc55cSDimitry Andric for (const auto &RelSect : Base::Sections) 859bdd1243dSDimitry Andric if (Error Err = Base::forEachRelaRelocation(RelSect, this, 860349cc55cSDimitry Andric &Self::addSingleRelocation)) 861349cc55cSDimitry Andric return Err; 862fe6060f1SDimitry Andric 863349cc55cSDimitry Andric return Error::success(); 864fe6060f1SDimitry Andric } 865fe6060f1SDimitry Andric 866349cc55cSDimitry Andric Error addSingleRelocation(const typename ELFT::Rela &Rel, 867349cc55cSDimitry Andric const typename ELFT::Shdr &FixupSect, 86804eeddc0SDimitry Andric Block &BlockToFix) { 869349cc55cSDimitry Andric using Base = ELFLinkGraphBuilder<ELFT>; 870349cc55cSDimitry Andric 871753f127fSDimitry Andric uint32_t Type = Rel.getType(false); 872753f127fSDimitry Andric int64_t Addend = Rel.r_addend; 873*06c3fb27SDimitry Andric 874*06c3fb27SDimitry Andric if (Type == ELF::R_RISCV_RELAX) { 875*06c3fb27SDimitry Andric if (BlockToFix.edges_empty()) 876*06c3fb27SDimitry Andric return make_error<StringError>( 877*06c3fb27SDimitry Andric "R_RISCV_RELAX without preceding relocation", 878*06c3fb27SDimitry Andric inconvertibleErrorCode()); 879*06c3fb27SDimitry Andric 880*06c3fb27SDimitry Andric auto &PrevEdge = *std::prev(BlockToFix.edges().end()); 881*06c3fb27SDimitry Andric auto Kind = static_cast<EdgeKind_riscv>(PrevEdge.getKind()); 882*06c3fb27SDimitry Andric PrevEdge.setKind(getRelaxableRelocationKind(Kind)); 883753f127fSDimitry Andric return Error::success(); 884753f127fSDimitry Andric } 885753f127fSDimitry Andric 886753f127fSDimitry Andric Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type); 887753f127fSDimitry Andric if (!Kind) 888753f127fSDimitry Andric return Kind.takeError(); 889753f127fSDimitry Andric 890349cc55cSDimitry Andric uint32_t SymbolIndex = Rel.getSymbol(false); 891349cc55cSDimitry Andric auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 892349cc55cSDimitry Andric if (!ObjSymbol) 893349cc55cSDimitry Andric return ObjSymbol.takeError(); 894349cc55cSDimitry Andric 895349cc55cSDimitry Andric Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 896349cc55cSDimitry Andric if (!GraphSymbol) 897349cc55cSDimitry Andric return make_error<StringError>( 898349cc55cSDimitry Andric formatv("Could not find symbol at given index, did you add it to " 899349cc55cSDimitry Andric "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 900349cc55cSDimitry Andric SymbolIndex, (*ObjSymbol)->st_shndx, 901349cc55cSDimitry Andric Base::GraphSymbols.size()), 902349cc55cSDimitry Andric inconvertibleErrorCode()); 903349cc55cSDimitry Andric 90404eeddc0SDimitry Andric auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; 90504eeddc0SDimitry Andric Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 906349cc55cSDimitry Andric Edge GE(*Kind, Offset, *GraphSymbol, Addend); 907349cc55cSDimitry Andric LLVM_DEBUG({ 908349cc55cSDimitry Andric dbgs() << " "; 90904eeddc0SDimitry Andric printEdge(dbgs(), BlockToFix, GE, riscv::getEdgeKindName(*Kind)); 910349cc55cSDimitry Andric dbgs() << "\n"; 911349cc55cSDimitry Andric }); 912349cc55cSDimitry Andric 91304eeddc0SDimitry Andric BlockToFix.addEdge(std::move(GE)); 914fe6060f1SDimitry Andric return Error::success(); 915fe6060f1SDimitry Andric } 916fe6060f1SDimitry Andric 917fe6060f1SDimitry Andric public: 918fe6060f1SDimitry Andric ELFLinkGraphBuilder_riscv(StringRef FileName, 919*06c3fb27SDimitry Andric const object::ELFFile<ELFT> &Obj, Triple TT, 920*06c3fb27SDimitry Andric SubtargetFeatures Features) 921*06c3fb27SDimitry Andric : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), 922*06c3fb27SDimitry Andric FileName, riscv::getEdgeKindName) {} 923fe6060f1SDimitry Andric }; 924fe6060f1SDimitry Andric 925fe6060f1SDimitry Andric Expected<std::unique_ptr<LinkGraph>> 926fe6060f1SDimitry Andric createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) { 927fe6060f1SDimitry Andric LLVM_DEBUG({ 928fe6060f1SDimitry Andric dbgs() << "Building jitlink graph for new input " 929fe6060f1SDimitry Andric << ObjectBuffer.getBufferIdentifier() << "...\n"; 930fe6060f1SDimitry Andric }); 931fe6060f1SDimitry Andric 932fe6060f1SDimitry Andric auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 933fe6060f1SDimitry Andric if (!ELFObj) 934fe6060f1SDimitry Andric return ELFObj.takeError(); 935fe6060f1SDimitry Andric 936*06c3fb27SDimitry Andric auto Features = (*ELFObj)->getFeatures(); 937*06c3fb27SDimitry Andric if (!Features) 938*06c3fb27SDimitry Andric return Features.takeError(); 939*06c3fb27SDimitry Andric 940fe6060f1SDimitry Andric if ((*ELFObj)->getArch() == Triple::riscv64) { 941fe6060f1SDimitry Andric auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 942fe6060f1SDimitry Andric return ELFLinkGraphBuilder_riscv<object::ELF64LE>( 943fe6060f1SDimitry Andric (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 944*06c3fb27SDimitry Andric (*ELFObj)->makeTriple(), std::move(*Features)) 945fe6060f1SDimitry Andric .buildGraph(); 946fe6060f1SDimitry Andric } else { 947fe6060f1SDimitry Andric assert((*ELFObj)->getArch() == Triple::riscv32 && 948fe6060f1SDimitry Andric "Invalid triple for RISCV ELF object file"); 949fe6060f1SDimitry Andric auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj); 950fe6060f1SDimitry Andric return ELFLinkGraphBuilder_riscv<object::ELF32LE>( 951fe6060f1SDimitry Andric (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 952*06c3fb27SDimitry Andric (*ELFObj)->makeTriple(), std::move(*Features)) 953fe6060f1SDimitry Andric .buildGraph(); 954fe6060f1SDimitry Andric } 955fe6060f1SDimitry Andric } 956fe6060f1SDimitry Andric 957fe6060f1SDimitry Andric void link_ELF_riscv(std::unique_ptr<LinkGraph> G, 958fe6060f1SDimitry Andric std::unique_ptr<JITLinkContext> Ctx) { 959fe6060f1SDimitry Andric PassConfiguration Config; 960fe6060f1SDimitry Andric const Triple &TT = G->getTargetTriple(); 961fe6060f1SDimitry Andric if (Ctx->shouldAddDefaultTargetPasses(TT)) { 962fe6060f1SDimitry Andric if (auto MarkLive = Ctx->getMarkLivePass(TT)) 963fe6060f1SDimitry Andric Config.PrePrunePasses.push_back(std::move(MarkLive)); 964fe6060f1SDimitry Andric else 965fe6060f1SDimitry Andric Config.PrePrunePasses.push_back(markAllSymbolsLive); 966349cc55cSDimitry Andric Config.PostPrunePasses.push_back( 967349cc55cSDimitry Andric PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass); 968*06c3fb27SDimitry Andric Config.PostAllocationPasses.push_back(relax); 969fe6060f1SDimitry Andric } 970fe6060f1SDimitry Andric if (auto Err = Ctx->modifyPassConfig(*G, Config)) 971fe6060f1SDimitry Andric return Ctx->notifyFailed(std::move(Err)); 972fe6060f1SDimitry Andric 973fe6060f1SDimitry Andric ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config)); 974fe6060f1SDimitry Andric } 975fe6060f1SDimitry Andric 976*06c3fb27SDimitry Andric LinkGraphPassFunction createRelaxationPass_ELF_riscv() { return relax; } 977*06c3fb27SDimitry Andric 978fe6060f1SDimitry Andric } // namespace jitlink 979fe6060f1SDimitry Andric } // namespace llvm 980