10ad562b4Sluxufan //===------- ELF_riscv.cpp -JIT linker implementation for ELF/riscv -------===// 20ad562b4Sluxufan // 30ad562b4Sluxufan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40ad562b4Sluxufan // See https://llvm.org/LICENSE.txt for license information. 50ad562b4Sluxufan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60ad562b4Sluxufan // 70ad562b4Sluxufan //===----------------------------------------------------------------------===// 80ad562b4Sluxufan // 90ad562b4Sluxufan // ELF/riscv jit-link implementation. 100ad562b4Sluxufan // 110ad562b4Sluxufan //===----------------------------------------------------------------------===// 120ad562b4Sluxufan 130ad562b4Sluxufan #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h" 144f6757ceSJonas Hahnfeld #include "EHFrameSupportImpl.h" 1589f546f6Sluxufan #include "ELFLinkGraphBuilder.h" 1689f546f6Sluxufan #include "JITLinkGeneric.h" 1789f546f6Sluxufan #include "PerGraphGOTAndPLTStubsBuilder.h" 1889f546f6Sluxufan #include "llvm/BinaryFormat/ELF.h" 194f6757ceSJonas Hahnfeld #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 200ad562b4Sluxufan #include "llvm/ExecutionEngine/JITLink/JITLink.h" 210ad562b4Sluxufan #include "llvm/ExecutionEngine/JITLink/riscv.h" 220ad562b4Sluxufan #include "llvm/Object/ELF.h" 230ad562b4Sluxufan #include "llvm/Object/ELFObjectFile.h" 24dc18c5faSluxufan #include "llvm/Support/Endian.h" 250ad562b4Sluxufan 260ad562b4Sluxufan #define DEBUG_TYPE "jitlink" 270ad562b4Sluxufan using namespace llvm; 2889f546f6Sluxufan using namespace llvm::jitlink; 2989f546f6Sluxufan using namespace llvm::jitlink::riscv; 300ad562b4Sluxufan 3189f546f6Sluxufan namespace { 3289f546f6Sluxufan 3389f546f6Sluxufan class PerGraphGOTAndPLTStubsBuilder_ELF_riscv 3489f546f6Sluxufan : public PerGraphGOTAndPLTStubsBuilder< 3589f546f6Sluxufan PerGraphGOTAndPLTStubsBuilder_ELF_riscv> { 3689f546f6Sluxufan public: 3789f546f6Sluxufan static constexpr size_t StubEntrySize = 16; 3889f546f6Sluxufan static const uint8_t NullGOTEntryContent[8]; 3989f546f6Sluxufan static const uint8_t RV64StubContent[StubEntrySize]; 4089f546f6Sluxufan static const uint8_t RV32StubContent[StubEntrySize]; 4189f546f6Sluxufan 4289f546f6Sluxufan using PerGraphGOTAndPLTStubsBuilder< 4389f546f6Sluxufan PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder; 4489f546f6Sluxufan 4589f546f6Sluxufan bool isRV64() const { return G.getPointerSize() == 8; } 4689f546f6Sluxufan 4789f546f6Sluxufan bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; } 4889f546f6Sluxufan 4989f546f6Sluxufan Symbol &createGOTEntry(Symbol &Target) { 50118e953bSLang Hames Block &GOTBlock = 51118e953bSLang Hames G.createContentBlock(getGOTSection(), getGOTEntryBlockContent(), 52118e953bSLang Hames orc::ExecutorAddr(), G.getPointerSize(), 0); 5389f546f6Sluxufan GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0); 5489f546f6Sluxufan return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false); 5589f546f6Sluxufan } 5689f546f6Sluxufan 5789f546f6Sluxufan Symbol &createPLTStub(Symbol &Target) { 58118e953bSLang Hames Block &StubContentBlock = G.createContentBlock( 59118e953bSLang Hames getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 4, 0); 6089f546f6Sluxufan auto &GOTEntrySymbol = getGOTEntry(Target); 6189f546f6Sluxufan StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0); 6289f546f6Sluxufan return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true, 6389f546f6Sluxufan false); 6489f546f6Sluxufan } 6589f546f6Sluxufan 6689f546f6Sluxufan void fixGOTEdge(Edge &E, Symbol &GOTEntry) { 6789f546f6Sluxufan // Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12) 6889f546f6Sluxufan // with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12) 6989f546f6Sluxufan // Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI20 7089f546f6Sluxufan E.setKind(R_RISCV_PCREL_HI20); 7189f546f6Sluxufan E.setTarget(GOTEntry); 7289f546f6Sluxufan } 7389f546f6Sluxufan 7489f546f6Sluxufan void fixPLTEdge(Edge &E, Symbol &PLTStubs) { 75bcd1296aSJob Noorman assert((E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT || 76bcd1296aSJob Noorman E.getKind() == CallRelaxable) && 77bcd1296aSJob Noorman "Not a PLT edge?"); 7889f546f6Sluxufan E.setKind(R_RISCV_CALL); 7989f546f6Sluxufan E.setTarget(PLTStubs); 8089f546f6Sluxufan } 8189f546f6Sluxufan 8289f546f6Sluxufan bool isExternalBranchEdge(Edge &E) const { 83bcd1296aSJob Noorman return (E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT || 84bcd1296aSJob Noorman E.getKind() == CallRelaxable) && 8526ee8947SJob Noorman !E.getTarget().isDefined(); 8689f546f6Sluxufan } 8789f546f6Sluxufan 8889f546f6Sluxufan private: 8989f546f6Sluxufan Section &getGOTSection() const { 9089f546f6Sluxufan if (!GOTSection) 91d3d9f7caSLang Hames GOTSection = &G.createSection("$__GOT", orc::MemProt::Read); 9289f546f6Sluxufan return *GOTSection; 9389f546f6Sluxufan } 9489f546f6Sluxufan 9589f546f6Sluxufan Section &getStubsSection() const { 96962a2479SLang Hames if (!StubsSection) 97962a2479SLang Hames StubsSection = 98d3d9f7caSLang Hames &G.createSection("$__STUBS", orc::MemProt::Read | orc::MemProt::Exec); 9989f546f6Sluxufan return *StubsSection; 10089f546f6Sluxufan } 10189f546f6Sluxufan 10289f546f6Sluxufan ArrayRef<char> getGOTEntryBlockContent() { 10389f546f6Sluxufan return {reinterpret_cast<const char *>(NullGOTEntryContent), 10489f546f6Sluxufan G.getPointerSize()}; 10589f546f6Sluxufan } 10689f546f6Sluxufan 10789f546f6Sluxufan ArrayRef<char> getStubBlockContent() { 10889f546f6Sluxufan auto StubContent = isRV64() ? RV64StubContent : RV32StubContent; 10989f546f6Sluxufan return {reinterpret_cast<const char *>(StubContent), StubEntrySize}; 11089f546f6Sluxufan } 11189f546f6Sluxufan 11289f546f6Sluxufan mutable Section *GOTSection = nullptr; 11389f546f6Sluxufan mutable Section *StubsSection = nullptr; 11489f546f6Sluxufan }; 11589f546f6Sluxufan 11689f546f6Sluxufan const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] = 11789f546f6Sluxufan {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 11889f546f6Sluxufan 11989f546f6Sluxufan const uint8_t 12089f546f6Sluxufan PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = { 12189f546f6Sluxufan 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal 12289f546f6Sluxufan 0x03, 0x3e, 0x0e, 0x00, // ld t3, literal(t3) 12389f546f6Sluxufan 0x67, 0x00, 0x0e, 0x00, // jr t3 12489f546f6Sluxufan 0x13, 0x00, 0x00, 0x00}; // nop 12589f546f6Sluxufan 12689f546f6Sluxufan const uint8_t 12789f546f6Sluxufan PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = { 12889f546f6Sluxufan 0x17, 0x0e, 0x00, 0x00, // auipc t3, literal 12989f546f6Sluxufan 0x03, 0x2e, 0x0e, 0x00, // lw t3, literal(t3) 13089f546f6Sluxufan 0x67, 0x00, 0x0e, 0x00, // jr t3 13189f546f6Sluxufan 0x13, 0x00, 0x00, 0x00}; // nop 13289f546f6Sluxufan } // namespace 1330ad562b4Sluxufan namespace llvm { 1340ad562b4Sluxufan namespace jitlink { 1350ad562b4Sluxufan 13695b74d4dSluxufan static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) { 1379920943eSluxufan return (Num & (((1ULL << Size) - 1) << Low)) >> Low; 1380ad562b4Sluxufan } 1390ad562b4Sluxufan 14016dc90cbSfourdim static inline bool isAlignmentCorrect(uint64_t Value, int N) { 14116dc90cbSfourdim return (Value & (N - 1)) ? false : true; 1420c6f7626Sfourdim } 1430c6f7626Sfourdim 14416dc90cbSfourdim // Requires 0 < N <= 64. 14516dc90cbSfourdim static inline bool isInRangeForImm(int64_t Value, int N) { 14616dc90cbSfourdim return Value == llvm::SignExtend64(Value, N); 1470ef5aa69Sluxufan } 1480ef5aa69Sluxufan 1490ad562b4Sluxufan class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> { 1500ad562b4Sluxufan friend class JITLinker<ELFJITLinker_riscv>; 1510ad562b4Sluxufan 1520ad562b4Sluxufan public: 1530ad562b4Sluxufan ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx, 1540ad562b4Sluxufan std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) 15578f39dc7SJonas Hahnfeld : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { 15678f39dc7SJonas Hahnfeld JITLinkerBase::getPassConfig().PostAllocationPasses.push_back( 15778f39dc7SJonas Hahnfeld [this](LinkGraph &G) { return gatherRISCVPCRelHi20(G); }); 15878f39dc7SJonas Hahnfeld } 1590ad562b4Sluxufan 1600ad562b4Sluxufan private: 16178f39dc7SJonas Hahnfeld DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *> 16278f39dc7SJonas Hahnfeld RelHi20; 16378f39dc7SJonas Hahnfeld 16478f39dc7SJonas Hahnfeld Error gatherRISCVPCRelHi20(LinkGraph &G) { 16578f39dc7SJonas Hahnfeld for (Block *B : G.blocks()) 16678f39dc7SJonas Hahnfeld for (Edge &E : B->edges()) 16778f39dc7SJonas Hahnfeld if (E.getKind() == R_RISCV_PCREL_HI20) 16878f39dc7SJonas Hahnfeld RelHi20[{B, E.getOffset()}] = &E; 16978f39dc7SJonas Hahnfeld 17078f39dc7SJonas Hahnfeld return Error::success(); 17178f39dc7SJonas Hahnfeld } 17278f39dc7SJonas Hahnfeld 17378f39dc7SJonas Hahnfeld Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) const { 17478f39dc7SJonas Hahnfeld using namespace riscv; 17578f39dc7SJonas Hahnfeld assert((E.getKind() == R_RISCV_PCREL_LO12_I || 17678f39dc7SJonas Hahnfeld E.getKind() == R_RISCV_PCREL_LO12_S) && 17778f39dc7SJonas Hahnfeld "Can only have high relocation for R_RISCV_PCREL_LO12_I or " 17878f39dc7SJonas Hahnfeld "R_RISCV_PCREL_LO12_S"); 17978f39dc7SJonas Hahnfeld 18078f39dc7SJonas Hahnfeld const Symbol &Sym = E.getTarget(); 18178f39dc7SJonas Hahnfeld const Block &B = Sym.getBlock(); 18278f39dc7SJonas Hahnfeld orc::ExecutorAddrDiff Offset = Sym.getOffset(); 18378f39dc7SJonas Hahnfeld 18478f39dc7SJonas Hahnfeld auto It = RelHi20.find({&B, Offset}); 18578f39dc7SJonas Hahnfeld if (It != RelHi20.end()) 18678f39dc7SJonas Hahnfeld return *It->second; 18778f39dc7SJonas Hahnfeld 18878f39dc7SJonas Hahnfeld return make_error<JITLinkError>("No HI20 PCREL relocation type be found " 18978f39dc7SJonas Hahnfeld "for LO12 PCREL relocation type"); 19078f39dc7SJonas Hahnfeld } 19178f39dc7SJonas Hahnfeld 1920ad562b4Sluxufan Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 1930ad562b4Sluxufan using namespace riscv; 1940ad562b4Sluxufan using namespace llvm::support; 1950ad562b4Sluxufan 1960ad562b4Sluxufan char *BlockWorkingMem = B.getAlreadyMutableContent().data(); 1970ad562b4Sluxufan char *FixupPtr = BlockWorkingMem + E.getOffset(); 198118e953bSLang Hames orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset(); 1990ad562b4Sluxufan switch (E.getKind()) { 20089f546f6Sluxufan case R_RISCV_32: { 201118e953bSLang Hames int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 20289f546f6Sluxufan *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 20389f546f6Sluxufan break; 20489f546f6Sluxufan } 20589f546f6Sluxufan case R_RISCV_64: { 206118e953bSLang Hames int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 20789f546f6Sluxufan *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 20889f546f6Sluxufan break; 20989f546f6Sluxufan } 2100c6f7626Sfourdim case R_RISCV_BRANCH: { 2110c6f7626Sfourdim int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 21216dc90cbSfourdim if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 12))) 21316dc90cbSfourdim return makeTargetOutOfRangeError(G, B, E); 21416dc90cbSfourdim if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 21516dc90cbSfourdim return makeAlignmentError(FixupAddress, Value, 2, E); 216850adc1dSJonas Hahnfeld uint32_t Imm12 = extractBits(Value, 12, 1) << 31; 217850adc1dSJonas Hahnfeld uint32_t Imm10_5 = extractBits(Value, 5, 6) << 25; 218850adc1dSJonas Hahnfeld uint32_t Imm4_1 = extractBits(Value, 1, 4) << 8; 219850adc1dSJonas Hahnfeld uint32_t Imm11 = extractBits(Value, 11, 1) << 7; 2200c6f7626Sfourdim uint32_t RawInstr = *(little32_t *)FixupPtr; 221850adc1dSJonas Hahnfeld *(little32_t *)FixupPtr = 222850adc1dSJonas Hahnfeld (RawInstr & 0x1FFF07F) | Imm12 | Imm10_5 | Imm4_1 | Imm11; 2230c6f7626Sfourdim break; 2240c6f7626Sfourdim } 2251ece3eeeSfourdim case R_RISCV_JAL: { 2261ece3eeeSfourdim int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 22716dc90cbSfourdim if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 20))) 22816dc90cbSfourdim return makeTargetOutOfRangeError(G, B, E); 22916dc90cbSfourdim if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 23016dc90cbSfourdim return makeAlignmentError(FixupAddress, Value, 2, E); 2311ece3eeeSfourdim uint32_t Imm20 = extractBits(Value, 20, 1) << 31; 2321ece3eeeSfourdim uint32_t Imm10_1 = extractBits(Value, 1, 10) << 21; 2331ece3eeeSfourdim uint32_t Imm11 = extractBits(Value, 11, 1) << 20; 2341ece3eeeSfourdim uint32_t Imm19_12 = extractBits(Value, 12, 8) << 12; 2351ece3eeeSfourdim uint32_t RawInstr = *(little32_t *)FixupPtr; 236e7d432fdSJonas Hahnfeld *(little32_t *)FixupPtr = 237e7d432fdSJonas Hahnfeld (RawInstr & 0xFFF) | Imm20 | Imm10_1 | Imm11 | Imm19_12; 2381ece3eeeSfourdim break; 2391ece3eeeSfourdim } 240f4bb62e8SJob Noorman case CallRelaxable: 241f4bb62e8SJob Noorman // Treat as R_RISCV_CALL when the relaxation pass did not run 2424752787cSJob Noorman case R_RISCV_CALL_PLT: 2430ad562b4Sluxufan case R_RISCV_CALL: { 2440ad562b4Sluxufan int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 2450ef5aa69Sluxufan int64_t Hi = Value + 0x800; 24616dc90cbSfourdim if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 2470ef5aa69Sluxufan return makeTargetOutOfRangeError(G, B, E); 2480ad562b4Sluxufan int32_t Lo = Value & 0xFFF; 2490ad562b4Sluxufan uint32_t RawInstrAuipc = *(little32_t *)FixupPtr; 2500ad562b4Sluxufan uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4); 2510ef5aa69Sluxufan *(little32_t *)FixupPtr = 2520ef5aa69Sluxufan RawInstrAuipc | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 2530ad562b4Sluxufan *(little32_t *)(FixupPtr + 4) = 2540ad562b4Sluxufan RawInstrJalr | (static_cast<uint32_t>(Lo) << 20); 2550ad562b4Sluxufan break; 2560ad562b4Sluxufan } 2576f539de7SJonas Hahnfeld // The relocations R_RISCV_CALL_PLT and R_RISCV_GOT_HI20 are handled by 2586f539de7SJonas Hahnfeld // PerGraphGOTAndPLTStubsBuilder_ELF_riscv and are transformed into 2596f539de7SJonas Hahnfeld // R_RISCV_CALL and R_RISCV_PCREL_HI20. 2600ad562b4Sluxufan case R_RISCV_PCREL_HI20: { 2610ad562b4Sluxufan int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 2620ef5aa69Sluxufan int64_t Hi = Value + 0x800; 26316dc90cbSfourdim if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 2640ef5aa69Sluxufan return makeTargetOutOfRangeError(G, B, E); 2650ad562b4Sluxufan uint32_t RawInstr = *(little32_t *)FixupPtr; 2660ef5aa69Sluxufan *(little32_t *)FixupPtr = 2670ef5aa69Sluxufan (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 2680ad562b4Sluxufan break; 2690ad562b4Sluxufan } 2700ad562b4Sluxufan case R_RISCV_PCREL_LO12_I: { 2710ef5aa69Sluxufan // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and 2720ef5aa69Sluxufan // pairs with current relocation R_RISCV_PCREL_LO12_I. So here may need a 2730ef5aa69Sluxufan // check. 2740ad562b4Sluxufan auto RelHI20 = getRISCVPCRelHi20(E); 2750ad562b4Sluxufan if (!RelHI20) 2760ad562b4Sluxufan return RelHI20.takeError(); 2770ad562b4Sluxufan int64_t Value = RelHI20->getTarget().getAddress() + 2780ad562b4Sluxufan RelHI20->getAddend() - E.getTarget().getAddress(); 2790ad562b4Sluxufan int64_t Lo = Value & 0xFFF; 2800ad562b4Sluxufan uint32_t RawInstr = *(little32_t *)FixupPtr; 2810ad562b4Sluxufan *(little32_t *)FixupPtr = 2820ad562b4Sluxufan (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20); 2830ad562b4Sluxufan break; 2840ad562b4Sluxufan } 2850ad562b4Sluxufan case R_RISCV_PCREL_LO12_S: { 2860ef5aa69Sluxufan // FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and 2870ef5aa69Sluxufan // pairs with current relocation R_RISCV_PCREL_LO12_S. So here may need a 2880ef5aa69Sluxufan // check. 2890ad562b4Sluxufan auto RelHI20 = getRISCVPCRelHi20(E); 290a2c9f12dSDmitry Kurtaev if (!RelHI20) 291a2c9f12dSDmitry Kurtaev return RelHI20.takeError(); 2920ad562b4Sluxufan int64_t Value = RelHI20->getTarget().getAddress() + 2930ad562b4Sluxufan RelHI20->getAddend() - E.getTarget().getAddress(); 2940ad562b4Sluxufan int64_t Lo = Value & 0xFFF; 295850adc1dSJonas Hahnfeld uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25; 296850adc1dSJonas Hahnfeld uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7; 2970ad562b4Sluxufan uint32_t RawInstr = *(little32_t *)FixupPtr; 2980ad562b4Sluxufan 299850adc1dSJonas Hahnfeld *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0; 3000ad562b4Sluxufan break; 3010ad562b4Sluxufan } 3026f539de7SJonas Hahnfeld case R_RISCV_HI20: { 3036f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 3046f539de7SJonas Hahnfeld int64_t Hi = Value + 0x800; 3056f539de7SJonas Hahnfeld if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) 3066f539de7SJonas Hahnfeld return makeTargetOutOfRangeError(G, B, E); 3076f539de7SJonas Hahnfeld uint32_t RawInstr = *(little32_t *)FixupPtr; 3086f539de7SJonas Hahnfeld *(little32_t *)FixupPtr = 3096f539de7SJonas Hahnfeld (RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000)); 310dc18c5faSluxufan break; 311dc18c5faSluxufan } 3126f539de7SJonas Hahnfeld case R_RISCV_LO12_I: { 3136f539de7SJonas Hahnfeld // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs 3146f539de7SJonas Hahnfeld // with current relocation R_RISCV_LO12_I. So here may need a check. 3156f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 3166f539de7SJonas Hahnfeld int32_t Lo = Value & 0xFFF; 3176f539de7SJonas Hahnfeld uint32_t RawInstr = *(little32_t *)FixupPtr; 3186f539de7SJonas Hahnfeld *(little32_t *)FixupPtr = 3196f539de7SJonas Hahnfeld (RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20); 320dc18c5faSluxufan break; 321dc18c5faSluxufan } 3226f539de7SJonas Hahnfeld case R_RISCV_LO12_S: { 3236f539de7SJonas Hahnfeld // FIXME: We assume that R_RISCV_HI20 is present in object code and pairs 3246f539de7SJonas Hahnfeld // with current relocation R_RISCV_LO12_S. So here may need a check. 3256f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 3266f539de7SJonas Hahnfeld int64_t Lo = Value & 0xFFF; 327850adc1dSJonas Hahnfeld uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25; 328850adc1dSJonas Hahnfeld uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7; 3296f539de7SJonas Hahnfeld uint32_t RawInstr = *(little32_t *)FixupPtr; 330850adc1dSJonas Hahnfeld *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0; 331dc18c5faSluxufan break; 332dc18c5faSluxufan } 333dc18c5faSluxufan case R_RISCV_ADD8: { 334dc18c5faSluxufan int64_t Value = 335dc18c5faSluxufan (E.getTarget().getAddress() + 3366a14a56aSJob Noorman *(reinterpret_cast<const uint8_t *>(FixupPtr)) + E.getAddend()) 337dc18c5faSluxufan .getValue(); 338dc18c5faSluxufan *FixupPtr = static_cast<uint8_t>(Value); 339dc18c5faSluxufan break; 340dc18c5faSluxufan } 3416f539de7SJonas Hahnfeld case R_RISCV_ADD16: { 3426f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + 3436a14a56aSJob Noorman support::endian::read16le(FixupPtr) + E.getAddend()) 3446f539de7SJonas Hahnfeld .getValue(); 3456f539de7SJonas Hahnfeld *(little16_t *)FixupPtr = static_cast<uint16_t>(Value); 3466f539de7SJonas Hahnfeld break; 3476f539de7SJonas Hahnfeld } 3486f539de7SJonas Hahnfeld case R_RISCV_ADD32: { 3496f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + 3506a14a56aSJob Noorman support::endian::read32le(FixupPtr) + E.getAddend()) 3516f539de7SJonas Hahnfeld .getValue(); 3526f539de7SJonas Hahnfeld *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 3536f539de7SJonas Hahnfeld break; 3546f539de7SJonas Hahnfeld } 3556f539de7SJonas Hahnfeld case R_RISCV_ADD64: { 3566f539de7SJonas Hahnfeld int64_t Value = (E.getTarget().getAddress() + 3576a14a56aSJob Noorman support::endian::read64le(FixupPtr) + E.getAddend()) 3586f539de7SJonas Hahnfeld .getValue(); 359dc18c5faSluxufan *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 360dc18c5faSluxufan break; 361dc18c5faSluxufan } 3626f539de7SJonas Hahnfeld case R_RISCV_SUB8: { 3636a14a56aSJob Noorman int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) - 364dc18c5faSluxufan E.getTarget().getAddress().getValue() - E.getAddend(); 3656f539de7SJonas Hahnfeld *FixupPtr = static_cast<uint8_t>(Value); 366dc18c5faSluxufan break; 367dc18c5faSluxufan } 368dc18c5faSluxufan case R_RISCV_SUB16: { 3696a14a56aSJob Noorman int64_t Value = support::endian::read16le(FixupPtr) - 370dc18c5faSluxufan E.getTarget().getAddress().getValue() - E.getAddend(); 371dc18c5faSluxufan *(little16_t *)FixupPtr = static_cast<uint32_t>(Value); 372dc18c5faSluxufan break; 373dc18c5faSluxufan } 3746f539de7SJonas Hahnfeld case R_RISCV_SUB32: { 3756a14a56aSJob Noorman int64_t Value = support::endian::read32le(FixupPtr) - 376dc18c5faSluxufan E.getTarget().getAddress().getValue() - E.getAddend(); 3776f539de7SJonas Hahnfeld *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 3786f539de7SJonas Hahnfeld break; 3796f539de7SJonas Hahnfeld } 3806f539de7SJonas Hahnfeld case R_RISCV_SUB64: { 3816a14a56aSJob Noorman int64_t Value = support::endian::read64le(FixupPtr) - 3826f539de7SJonas Hahnfeld E.getTarget().getAddress().getValue() - E.getAddend(); 3836f539de7SJonas Hahnfeld *(little64_t *)FixupPtr = static_cast<uint64_t>(Value); 384dc18c5faSluxufan break; 385dc18c5faSluxufan } 386c8d43dcaSJonas Hahnfeld case R_RISCV_RVC_BRANCH: { 387c8d43dcaSJonas Hahnfeld int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 388c8d43dcaSJonas Hahnfeld if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 8))) 389c8d43dcaSJonas Hahnfeld return makeTargetOutOfRangeError(G, B, E); 390c8d43dcaSJonas Hahnfeld if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 391c8d43dcaSJonas Hahnfeld return makeAlignmentError(FixupAddress, Value, 2, E); 392c8d43dcaSJonas Hahnfeld uint16_t Imm8 = extractBits(Value, 8, 1) << 12; 393c8d43dcaSJonas Hahnfeld uint16_t Imm4_3 = extractBits(Value, 3, 2) << 10; 394c8d43dcaSJonas Hahnfeld uint16_t Imm7_6 = extractBits(Value, 6, 2) << 5; 395c8d43dcaSJonas Hahnfeld uint16_t Imm2_1 = extractBits(Value, 1, 2) << 3; 396c8d43dcaSJonas Hahnfeld uint16_t Imm5 = extractBits(Value, 5, 1) << 2; 397c8d43dcaSJonas Hahnfeld uint16_t RawInstr = *(little16_t *)FixupPtr; 398c8d43dcaSJonas Hahnfeld *(little16_t *)FixupPtr = 399c8d43dcaSJonas Hahnfeld (RawInstr & 0xE383) | Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; 400c8d43dcaSJonas Hahnfeld break; 401c8d43dcaSJonas Hahnfeld } 402c8d43dcaSJonas Hahnfeld case R_RISCV_RVC_JUMP: { 403c8d43dcaSJonas Hahnfeld int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 404c8d43dcaSJonas Hahnfeld if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 11))) 405c8d43dcaSJonas Hahnfeld return makeTargetOutOfRangeError(G, B, E); 406c8d43dcaSJonas Hahnfeld if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) 407c8d43dcaSJonas Hahnfeld return makeAlignmentError(FixupAddress, Value, 2, E); 408c8d43dcaSJonas Hahnfeld uint16_t Imm11 = extractBits(Value, 11, 1) << 12; 409c8d43dcaSJonas Hahnfeld uint16_t Imm4 = extractBits(Value, 4, 1) << 11; 410c8d43dcaSJonas Hahnfeld uint16_t Imm9_8 = extractBits(Value, 8, 2) << 9; 411c8d43dcaSJonas Hahnfeld uint16_t Imm10 = extractBits(Value, 10, 1) << 8; 412c8d43dcaSJonas Hahnfeld uint16_t Imm6 = extractBits(Value, 6, 1) << 7; 413c8d43dcaSJonas Hahnfeld uint16_t Imm7 = extractBits(Value, 7, 1) << 6; 414c8d43dcaSJonas Hahnfeld uint16_t Imm3_1 = extractBits(Value, 1, 3) << 3; 415c8d43dcaSJonas Hahnfeld uint16_t Imm5 = extractBits(Value, 5, 1) << 2; 416c8d43dcaSJonas Hahnfeld uint16_t RawInstr = *(little16_t *)FixupPtr; 417c8d43dcaSJonas Hahnfeld *(little16_t *)FixupPtr = (RawInstr & 0xE003) | Imm11 | Imm4 | Imm9_8 | 418c8d43dcaSJonas Hahnfeld Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; 419c8d43dcaSJonas Hahnfeld break; 420c8d43dcaSJonas Hahnfeld } 4213362f54dSluxufan case R_RISCV_SUB6: { 4226a14a56aSJob Noorman int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) & 0x3f; 4231df20fa8SSimon Pilgrim Value -= E.getTarget().getAddress().getValue() - E.getAddend(); 4243362f54dSluxufan *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<uint8_t>(Value) & 0x3f); 4253362f54dSluxufan break; 4263362f54dSluxufan } 427f7d4cafeSfourdim case R_RISCV_SET6: { 428f7d4cafeSfourdim int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 429f7d4cafeSfourdim uint32_t RawData = *(little32_t *)FixupPtr; 430f7d4cafeSfourdim int64_t Word6 = Value & 0x3f; 431f7d4cafeSfourdim *(little32_t *)FixupPtr = (RawData & 0xffffffc0) | Word6; 432f7d4cafeSfourdim break; 433f7d4cafeSfourdim } 434f7d4cafeSfourdim case R_RISCV_SET8: { 435f7d4cafeSfourdim int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 436f7d4cafeSfourdim uint32_t RawData = *(little32_t *)FixupPtr; 437f7d4cafeSfourdim int64_t Word8 = Value & 0xff; 438f7d4cafeSfourdim *(little32_t *)FixupPtr = (RawData & 0xffffff00) | Word8; 439f7d4cafeSfourdim break; 440f7d4cafeSfourdim } 441f7d4cafeSfourdim case R_RISCV_SET16: { 442f7d4cafeSfourdim int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 443f7d4cafeSfourdim uint32_t RawData = *(little32_t *)FixupPtr; 444f7d4cafeSfourdim int64_t Word16 = Value & 0xffff; 445f7d4cafeSfourdim *(little32_t *)FixupPtr = (RawData & 0xffff0000) | Word16; 446f7d4cafeSfourdim break; 447f7d4cafeSfourdim } 448f7d4cafeSfourdim case R_RISCV_SET32: { 449f7d4cafeSfourdim int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); 450f7d4cafeSfourdim int64_t Word32 = Value & 0xffffffff; 451f7d4cafeSfourdim *(little32_t *)FixupPtr = Word32; 452f7d4cafeSfourdim break; 453f7d4cafeSfourdim } 454f7d4cafeSfourdim case R_RISCV_32_PCREL: { 455f7d4cafeSfourdim int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; 456f7d4cafeSfourdim int64_t Word32 = Value & 0xffffffff; 457f7d4cafeSfourdim *(little32_t *)FixupPtr = Word32; 458f7d4cafeSfourdim break; 459f7d4cafeSfourdim } 460f4bb62e8SJob Noorman case AlignRelaxable: 461f4bb62e8SJob Noorman // Ignore when the relaxation pass did not run 462f4bb62e8SJob Noorman break; 4634f6757ceSJonas Hahnfeld case NegDelta32: { 4644f6757ceSJonas Hahnfeld int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); 4654f6757ceSJonas Hahnfeld if (LLVM_UNLIKELY(!isInRangeForImm(Value, 32))) 4664f6757ceSJonas Hahnfeld return makeTargetOutOfRangeError(G, B, E); 4674f6757ceSJonas Hahnfeld *(little32_t *)FixupPtr = static_cast<uint32_t>(Value); 4684f6757ceSJonas Hahnfeld break; 4694f6757ceSJonas Hahnfeld } 4700ad562b4Sluxufan } 4710ad562b4Sluxufan return Error::success(); 4720ad562b4Sluxufan } 4730ad562b4Sluxufan }; 4740ad562b4Sluxufan 475310473c5SJob Noorman namespace { 476310473c5SJob Noorman 477310473c5SJob Noorman struct SymbolAnchor { 478310473c5SJob Noorman uint64_t Offset; 479310473c5SJob Noorman Symbol *Sym; 480310473c5SJob Noorman bool End; // true for the anchor of getOffset() + getSize() 481310473c5SJob Noorman }; 482310473c5SJob Noorman 483310473c5SJob Noorman struct BlockRelaxAux { 484310473c5SJob Noorman // This records symbol start and end offsets which will be adjusted according 485310473c5SJob Noorman // to the nearest RelocDeltas element. 486310473c5SJob Noorman SmallVector<SymbolAnchor, 0> Anchors; 487310473c5SJob Noorman // All edges that either 1) are R_RISCV_ALIGN or 2) have a R_RISCV_RELAX edge 488310473c5SJob Noorman // at the same offset. 489310473c5SJob Noorman SmallVector<Edge *, 0> RelaxEdges; 490310473c5SJob Noorman // For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ? 491310473c5SJob Noorman // RelocDeltas[I - 1] : 0). 492310473c5SJob Noorman SmallVector<uint32_t, 0> RelocDeltas; 493310473c5SJob Noorman // For RelaxEdges[I], the actual type is EdgeKinds[I]. 494310473c5SJob Noorman SmallVector<Edge::Kind, 0> EdgeKinds; 495310473c5SJob Noorman // List of rewritten instructions. Contains one raw encoded instruction per 496310473c5SJob Noorman // element in EdgeKinds that isn't Invalid or R_RISCV_ALIGN. 497310473c5SJob Noorman SmallVector<uint32_t, 0> Writes; 498310473c5SJob Noorman }; 499310473c5SJob Noorman 500310473c5SJob Noorman struct RelaxConfig { 501310473c5SJob Noorman bool IsRV32; 502310473c5SJob Noorman bool HasRVC; 503310473c5SJob Noorman }; 504310473c5SJob Noorman 505310473c5SJob Noorman struct RelaxAux { 506310473c5SJob Noorman RelaxConfig Config; 507310473c5SJob Noorman DenseMap<Block *, BlockRelaxAux> Blocks; 508310473c5SJob Noorman }; 509310473c5SJob Noorman 510310473c5SJob Noorman } // namespace 511310473c5SJob Noorman 512310473c5SJob Noorman static bool shouldRelax(const Section &S) { 513310473c5SJob Noorman return (S.getMemProt() & orc::MemProt::Exec) != orc::MemProt::None; 514310473c5SJob Noorman } 515310473c5SJob Noorman 516310473c5SJob Noorman static bool isRelaxable(const Edge &E) { 517310473c5SJob Noorman switch (E.getKind()) { 518310473c5SJob Noorman default: 519310473c5SJob Noorman return false; 520310473c5SJob Noorman case CallRelaxable: 521310473c5SJob Noorman case AlignRelaxable: 522310473c5SJob Noorman return true; 523310473c5SJob Noorman } 524310473c5SJob Noorman } 525310473c5SJob Noorman 526310473c5SJob Noorman static RelaxAux initRelaxAux(LinkGraph &G) { 527310473c5SJob Noorman RelaxAux Aux; 528310473c5SJob Noorman Aux.Config.IsRV32 = G.getTargetTriple().isRISCV32(); 52952b88457SJob Noorman const auto &Features = G.getFeatures().getFeatures(); 5308c37e3e6SCraig Topper Aux.Config.HasRVC = llvm::is_contained(Features, "+c") || 5318c37e3e6SCraig Topper llvm::is_contained(Features, "+zca"); 532310473c5SJob Noorman 533310473c5SJob Noorman for (auto &S : G.sections()) { 534310473c5SJob Noorman if (!shouldRelax(S)) 535310473c5SJob Noorman continue; 536310473c5SJob Noorman for (auto *B : S.blocks()) { 537310473c5SJob Noorman auto BlockEmplaceResult = Aux.Blocks.try_emplace(B); 538310473c5SJob Noorman assert(BlockEmplaceResult.second && "Block encountered twice"); 539310473c5SJob Noorman auto &BlockAux = BlockEmplaceResult.first->second; 540310473c5SJob Noorman 541310473c5SJob Noorman for (auto &E : B->edges()) 542310473c5SJob Noorman if (isRelaxable(E)) 543310473c5SJob Noorman BlockAux.RelaxEdges.push_back(&E); 544310473c5SJob Noorman 545310473c5SJob Noorman if (BlockAux.RelaxEdges.empty()) { 546310473c5SJob Noorman Aux.Blocks.erase(BlockEmplaceResult.first); 547310473c5SJob Noorman continue; 548310473c5SJob Noorman } 549310473c5SJob Noorman 550310473c5SJob Noorman const auto NumEdges = BlockAux.RelaxEdges.size(); 551310473c5SJob Noorman BlockAux.RelocDeltas.resize(NumEdges, 0); 552310473c5SJob Noorman BlockAux.EdgeKinds.resize_for_overwrite(NumEdges); 553310473c5SJob Noorman 554310473c5SJob Noorman // Store anchors (offset and offset+size) for symbols. 555310473c5SJob Noorman for (auto *Sym : S.symbols()) { 556310473c5SJob Noorman if (!Sym->isDefined() || &Sym->getBlock() != B) 557310473c5SJob Noorman continue; 558310473c5SJob Noorman 559310473c5SJob Noorman BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false}); 560310473c5SJob Noorman BlockAux.Anchors.push_back( 561310473c5SJob Noorman {Sym->getOffset() + Sym->getSize(), Sym, true}); 562310473c5SJob Noorman } 563310473c5SJob Noorman } 564310473c5SJob Noorman } 565310473c5SJob Noorman 566310473c5SJob Noorman // Sort anchors by offset so that we can find the closest relocation 567310473c5SJob Noorman // efficiently. For a zero size symbol, ensure that its start anchor precedes 568310473c5SJob Noorman // its end anchor. For two symbols with anchors at the same offset, their 569310473c5SJob Noorman // order does not matter. 570310473c5SJob Noorman for (auto &BlockAuxIter : Aux.Blocks) { 571310473c5SJob Noorman llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) { 572310473c5SJob Noorman return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End); 573310473c5SJob Noorman }); 574310473c5SJob Noorman } 575310473c5SJob Noorman 576310473c5SJob Noorman return Aux; 577310473c5SJob Noorman } 578310473c5SJob Noorman 579310473c5SJob Noorman static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove, 580310473c5SJob Noorman Edge::Kind &NewEdgeKind) { 581310473c5SJob Noorman // E points to the start of the padding bytes. 582310473c5SJob Noorman // E + Addend points to the instruction to be aligned by removing padding. 583310473c5SJob Noorman // Alignment is the smallest power of 2 strictly greater than Addend. 584310473c5SJob Noorman const auto Align = NextPowerOf2(E.getAddend()); 585310473c5SJob Noorman const auto DestLoc = alignTo(Loc.getValue(), Align); 586310473c5SJob Noorman const auto SrcLoc = Loc.getValue() + E.getAddend(); 587310473c5SJob Noorman Remove = SrcLoc - DestLoc; 588310473c5SJob Noorman assert(static_cast<int32_t>(Remove) >= 0 && 589310473c5SJob Noorman "R_RISCV_ALIGN needs expanding the content"); 590310473c5SJob Noorman NewEdgeKind = AlignRelaxable; 591310473c5SJob Noorman } 592310473c5SJob Noorman 593310473c5SJob Noorman static void relaxCall(const Block &B, BlockRelaxAux &Aux, 594310473c5SJob Noorman const RelaxConfig &Config, orc::ExecutorAddr Loc, 595310473c5SJob Noorman const Edge &E, uint32_t &Remove, 596310473c5SJob Noorman Edge::Kind &NewEdgeKind) { 597310473c5SJob Noorman const auto JALR = 598310473c5SJob Noorman support::endian::read32le(B.getContent().data() + E.getOffset() + 4); 599310473c5SJob Noorman const auto RD = extractBits(JALR, 7, 5); 600310473c5SJob Noorman const auto Dest = E.getTarget().getAddress() + E.getAddend(); 601310473c5SJob Noorman const auto Displace = Dest - Loc; 602310473c5SJob Noorman 603310473c5SJob Noorman if (Config.HasRVC && isInt<12>(Displace) && RD == 0) { 604310473c5SJob Noorman NewEdgeKind = R_RISCV_RVC_JUMP; 605310473c5SJob Noorman Aux.Writes.push_back(0xa001); // c.j 606310473c5SJob Noorman Remove = 6; 607310473c5SJob Noorman } else if (Config.HasRVC && Config.IsRV32 && isInt<12>(Displace) && RD == 1) { 608310473c5SJob Noorman NewEdgeKind = R_RISCV_RVC_JUMP; 609310473c5SJob Noorman Aux.Writes.push_back(0x2001); // c.jal 610310473c5SJob Noorman Remove = 6; 611310473c5SJob Noorman } else if (isInt<21>(Displace)) { 612310473c5SJob Noorman NewEdgeKind = R_RISCV_JAL; 613310473c5SJob Noorman Aux.Writes.push_back(0x6f | RD << 7); // jal 614310473c5SJob Noorman Remove = 4; 615310473c5SJob Noorman } else { 616310473c5SJob Noorman // Not relaxable 617310473c5SJob Noorman NewEdgeKind = R_RISCV_CALL_PLT; 618310473c5SJob Noorman Remove = 0; 619310473c5SJob Noorman } 620310473c5SJob Noorman } 621310473c5SJob Noorman 622310473c5SJob Noorman static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux, 623310473c5SJob Noorman const RelaxConfig &Config) { 624310473c5SJob Noorman const auto BlockAddr = Block.getAddress(); 625310473c5SJob Noorman bool Changed = false; 626310473c5SJob Noorman ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors); 627310473c5SJob Noorman uint32_t Delta = 0; 628310473c5SJob Noorman 629310473c5SJob Noorman Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid); 630310473c5SJob Noorman Aux.Writes.clear(); 631310473c5SJob Noorman 632310473c5SJob Noorman for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 633310473c5SJob Noorman const auto Loc = BlockAddr + E->getOffset() - Delta; 634310473c5SJob Noorman auto &Cur = Aux.RelocDeltas[I]; 635310473c5SJob Noorman uint32_t Remove = 0; 636310473c5SJob Noorman switch (E->getKind()) { 637310473c5SJob Noorman case AlignRelaxable: 638310473c5SJob Noorman relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]); 639310473c5SJob Noorman break; 640310473c5SJob Noorman case CallRelaxable: 641310473c5SJob Noorman relaxCall(Block, Aux, Config, Loc, *E, Remove, Aux.EdgeKinds[I]); 642310473c5SJob Noorman break; 643310473c5SJob Noorman default: 644310473c5SJob Noorman llvm_unreachable("Unexpected relaxable edge kind"); 645310473c5SJob Noorman } 646310473c5SJob Noorman 647310473c5SJob Noorman // For all anchors whose offsets are <= E->getOffset(), they are preceded by 648310473c5SJob Noorman // the previous relocation whose RelocDeltas value equals Delta. 649310473c5SJob Noorman // Decrease their offset and update their size. 650310473c5SJob Noorman for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) { 651310473c5SJob Noorman if (SA[0].End) 652310473c5SJob Noorman SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset()); 653310473c5SJob Noorman else 654310473c5SJob Noorman SA[0].Sym->setOffset(SA[0].Offset - Delta); 655310473c5SJob Noorman } 656310473c5SJob Noorman 657310473c5SJob Noorman Delta += Remove; 658310473c5SJob Noorman if (Delta != Cur) { 659310473c5SJob Noorman Cur = Delta; 660310473c5SJob Noorman Changed = true; 661310473c5SJob Noorman } 662310473c5SJob Noorman } 663310473c5SJob Noorman 664310473c5SJob Noorman for (const SymbolAnchor &A : SA) { 665310473c5SJob Noorman if (A.End) 666310473c5SJob Noorman A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset()); 667310473c5SJob Noorman else 668310473c5SJob Noorman A.Sym->setOffset(A.Offset - Delta); 669310473c5SJob Noorman } 670310473c5SJob Noorman 671310473c5SJob Noorman return Changed; 672310473c5SJob Noorman } 673310473c5SJob Noorman 674310473c5SJob Noorman static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) { 675310473c5SJob Noorman bool Changed = false; 676310473c5SJob Noorman 677310473c5SJob Noorman for (auto &[B, BlockAux] : Aux.Blocks) 678310473c5SJob Noorman Changed |= relaxBlock(G, *B, BlockAux, Aux.Config); 679310473c5SJob Noorman 680310473c5SJob Noorman return Changed; 681310473c5SJob Noorman } 682310473c5SJob Noorman 683310473c5SJob Noorman static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) { 684310473c5SJob Noorman auto Contents = Block.getAlreadyMutableContent(); 685310473c5SJob Noorman auto *Dest = Contents.data(); 686310473c5SJob Noorman auto NextWrite = Aux.Writes.begin(); 687310473c5SJob Noorman uint32_t Offset = 0; 688310473c5SJob Noorman uint32_t Delta = 0; 689310473c5SJob Noorman 690310473c5SJob Noorman // Update section content: remove NOPs for R_RISCV_ALIGN and rewrite 691310473c5SJob Noorman // instructions for relaxed relocations. 692310473c5SJob Noorman for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) { 693310473c5SJob Noorman uint32_t Remove = Aux.RelocDeltas[I] - Delta; 694310473c5SJob Noorman Delta = Aux.RelocDeltas[I]; 695310473c5SJob Noorman if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid) 696310473c5SJob Noorman continue; 697310473c5SJob Noorman 698310473c5SJob Noorman // Copy from last location to the current relocated location. 699310473c5SJob Noorman const auto Size = E->getOffset() - Offset; 700310473c5SJob Noorman std::memmove(Dest, Contents.data() + Offset, Size); 701310473c5SJob Noorman Dest += Size; 702310473c5SJob Noorman 703310473c5SJob Noorman uint32_t Skip = 0; 704310473c5SJob Noorman switch (Aux.EdgeKinds[I]) { 705310473c5SJob Noorman case Edge::Invalid: 706310473c5SJob Noorman break; 707310473c5SJob Noorman case AlignRelaxable: 708310473c5SJob Noorman // For R_RISCV_ALIGN, we will place Offset in a location (among NOPs) to 709310473c5SJob Noorman // satisfy the alignment requirement. If both Remove and E->getAddend() 710310473c5SJob Noorman // are multiples of 4, it is as if we have skipped some NOPs. Otherwise we 711310473c5SJob Noorman // are in the middle of a 4-byte NOP, and we need to rewrite the NOP 712310473c5SJob Noorman // sequence. 713310473c5SJob Noorman if (Remove % 4 || E->getAddend() % 4) { 714310473c5SJob Noorman Skip = E->getAddend() - Remove; 715310473c5SJob Noorman uint32_t J = 0; 716310473c5SJob Noorman for (; J + 4 <= Skip; J += 4) 717310473c5SJob Noorman support::endian::write32le(Dest + J, 0x00000013); // nop 718310473c5SJob Noorman if (J != Skip) { 719310473c5SJob Noorman assert(J + 2 == Skip); 720310473c5SJob Noorman support::endian::write16le(Dest + J, 0x0001); // c.nop 721310473c5SJob Noorman } 722310473c5SJob Noorman } 723310473c5SJob Noorman break; 724310473c5SJob Noorman case R_RISCV_RVC_JUMP: 725310473c5SJob Noorman Skip = 2; 726310473c5SJob Noorman support::endian::write16le(Dest, *NextWrite++); 727310473c5SJob Noorman break; 728310473c5SJob Noorman case R_RISCV_JAL: 729310473c5SJob Noorman Skip = 4; 730310473c5SJob Noorman support::endian::write32le(Dest, *NextWrite++); 731310473c5SJob Noorman break; 732310473c5SJob Noorman } 733310473c5SJob Noorman 734310473c5SJob Noorman Dest += Skip; 735310473c5SJob Noorman Offset = E->getOffset() + Skip + Remove; 736310473c5SJob Noorman } 737310473c5SJob Noorman 738310473c5SJob Noorman std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset); 739310473c5SJob Noorman 740310473c5SJob Noorman // Fixup edge offsets and kinds. 741310473c5SJob Noorman Delta = 0; 74279497098SJob Noorman size_t I = 0; 74379497098SJob Noorman for (auto &E : Block.edges()) { 74479497098SJob Noorman E.setOffset(E.getOffset() - Delta); 745310473c5SJob Noorman 74679497098SJob Noorman if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) { 747310473c5SJob Noorman if (Aux.EdgeKinds[I] != Edge::Invalid) 74879497098SJob Noorman E.setKind(Aux.EdgeKinds[I]); 749310473c5SJob Noorman 750310473c5SJob Noorman Delta = Aux.RelocDeltas[I]; 75179497098SJob Noorman ++I; 75279497098SJob Noorman } 753310473c5SJob Noorman } 754310473c5SJob Noorman 755310473c5SJob Noorman // Remove AlignRelaxable edges: all other relaxable edges got modified and 756310473c5SJob Noorman // will be used later while linking. Alignment is entirely handled here so we 757310473c5SJob Noorman // don't need these edges anymore. 75867f7efbbSJob Noorman for (auto IE = Block.edges().begin(); IE != Block.edges().end();) { 759310473c5SJob Noorman if (IE->getKind() == AlignRelaxable) 76067f7efbbSJob Noorman IE = Block.removeEdge(IE); 761310473c5SJob Noorman else 762310473c5SJob Noorman ++IE; 763310473c5SJob Noorman } 764310473c5SJob Noorman } 765310473c5SJob Noorman 766310473c5SJob Noorman static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) { 767310473c5SJob Noorman for (auto &[B, BlockAux] : Aux.Blocks) 768310473c5SJob Noorman finalizeBlockRelax(G, *B, BlockAux); 769310473c5SJob Noorman } 770310473c5SJob Noorman 771310473c5SJob Noorman static Error relax(LinkGraph &G) { 772310473c5SJob Noorman auto Aux = initRelaxAux(G); 773310473c5SJob Noorman while (relaxOnce(G, Aux)) { 774310473c5SJob Noorman } 775310473c5SJob Noorman finalizeRelax(G, Aux); 776310473c5SJob Noorman return Error::success(); 777310473c5SJob Noorman } 778310473c5SJob Noorman 7790ad562b4Sluxufan template <typename ELFT> 7800ad562b4Sluxufan class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> { 7810ad562b4Sluxufan private: 7820ad562b4Sluxufan static Expected<riscv::EdgeKind_riscv> 7830ad562b4Sluxufan getRelocationKind(const uint32_t Type) { 7840ad562b4Sluxufan using namespace riscv; 7850ad562b4Sluxufan switch (Type) { 7860ad562b4Sluxufan case ELF::R_RISCV_32: 7870ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_32; 7880ad562b4Sluxufan case ELF::R_RISCV_64: 7890ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_64; 7900c6f7626Sfourdim case ELF::R_RISCV_BRANCH: 7910c6f7626Sfourdim return EdgeKind_riscv::R_RISCV_BRANCH; 7921ece3eeeSfourdim case ELF::R_RISCV_JAL: 7931ece3eeeSfourdim return EdgeKind_riscv::R_RISCV_JAL; 7940ad562b4Sluxufan case ELF::R_RISCV_CALL: 7950ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_CALL; 7966f539de7SJonas Hahnfeld case ELF::R_RISCV_CALL_PLT: 7976f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_CALL_PLT; 7986f539de7SJonas Hahnfeld case ELF::R_RISCV_GOT_HI20: 7996f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_GOT_HI20; 8000ad562b4Sluxufan case ELF::R_RISCV_PCREL_HI20: 8010ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_PCREL_HI20; 8020ad562b4Sluxufan case ELF::R_RISCV_PCREL_LO12_I: 8030ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_PCREL_LO12_I; 8040ad562b4Sluxufan case ELF::R_RISCV_PCREL_LO12_S: 8050ad562b4Sluxufan return EdgeKind_riscv::R_RISCV_PCREL_LO12_S; 8066f539de7SJonas Hahnfeld case ELF::R_RISCV_HI20: 8076f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_HI20; 8086f539de7SJonas Hahnfeld case ELF::R_RISCV_LO12_I: 8096f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_LO12_I; 8106f539de7SJonas Hahnfeld case ELF::R_RISCV_LO12_S: 8116f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_LO12_S; 812dc18c5faSluxufan case ELF::R_RISCV_ADD8: 813dc18c5faSluxufan return EdgeKind_riscv::R_RISCV_ADD8; 8146f539de7SJonas Hahnfeld case ELF::R_RISCV_ADD16: 8156f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_ADD16; 8166f539de7SJonas Hahnfeld case ELF::R_RISCV_ADD32: 8176f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_ADD32; 8186f539de7SJonas Hahnfeld case ELF::R_RISCV_ADD64: 8196f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_ADD64; 820dc18c5faSluxufan case ELF::R_RISCV_SUB8: 821dc18c5faSluxufan return EdgeKind_riscv::R_RISCV_SUB8; 8226f539de7SJonas Hahnfeld case ELF::R_RISCV_SUB16: 8236f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_SUB16; 8246f539de7SJonas Hahnfeld case ELF::R_RISCV_SUB32: 8256f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_SUB32; 8266f539de7SJonas Hahnfeld case ELF::R_RISCV_SUB64: 8276f539de7SJonas Hahnfeld return EdgeKind_riscv::R_RISCV_SUB64; 828c8d43dcaSJonas Hahnfeld case ELF::R_RISCV_RVC_BRANCH: 829c8d43dcaSJonas Hahnfeld return EdgeKind_riscv::R_RISCV_RVC_BRANCH; 830c8d43dcaSJonas Hahnfeld case ELF::R_RISCV_RVC_JUMP: 831c8d43dcaSJonas Hahnfeld return EdgeKind_riscv::R_RISCV_RVC_JUMP; 8323362f54dSluxufan case ELF::R_RISCV_SUB6: 8333362f54dSluxufan return EdgeKind_riscv::R_RISCV_SUB6; 834f7d4cafeSfourdim case ELF::R_RISCV_SET6: 835f7d4cafeSfourdim return EdgeKind_riscv::R_RISCV_SET6; 836f7d4cafeSfourdim case ELF::R_RISCV_SET8: 837f7d4cafeSfourdim return EdgeKind_riscv::R_RISCV_SET8; 838f7d4cafeSfourdim case ELF::R_RISCV_SET16: 839f7d4cafeSfourdim return EdgeKind_riscv::R_RISCV_SET16; 840f7d4cafeSfourdim case ELF::R_RISCV_SET32: 841f7d4cafeSfourdim return EdgeKind_riscv::R_RISCV_SET32; 842f7d4cafeSfourdim case ELF::R_RISCV_32_PCREL: 843f7d4cafeSfourdim return EdgeKind_riscv::R_RISCV_32_PCREL; 844310473c5SJob Noorman case ELF::R_RISCV_ALIGN: 845310473c5SJob Noorman return EdgeKind_riscv::AlignRelaxable; 8460ad562b4Sluxufan } 8470ad562b4Sluxufan 8489fc0aa45SSunho Kim return make_error<JITLinkError>( 8499fc0aa45SSunho Kim "Unsupported riscv relocation:" + formatv("{0:d}: ", Type) + 8509fc0aa45SSunho Kim object::getELFRelocationTypeName(ELF::EM_RISCV, Type)); 8510ad562b4Sluxufan } 8520ad562b4Sluxufan 853310473c5SJob Noorman EdgeKind_riscv getRelaxableRelocationKind(EdgeKind_riscv Kind) { 854310473c5SJob Noorman switch (Kind) { 855310473c5SJob Noorman default: 856310473c5SJob Noorman // Just ignore unsupported relaxations 857310473c5SJob Noorman return Kind; 858310473c5SJob Noorman case R_RISCV_CALL: 859310473c5SJob Noorman case R_RISCV_CALL_PLT: 860310473c5SJob Noorman return CallRelaxable; 861310473c5SJob Noorman } 862310473c5SJob Noorman } 863310473c5SJob Noorman 8640ad562b4Sluxufan Error addRelocations() override { 865e8d81d80SStefan Gränitz LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 866e8d81d80SStefan Gränitz 8670ad562b4Sluxufan using Base = ELFLinkGraphBuilder<ELFT>; 868e8d81d80SStefan Gränitz using Self = ELFLinkGraphBuilder_riscv<ELFT>; 869e8d81d80SStefan Gränitz for (const auto &RelSect : Base::Sections) 8702a3b257aSKshitij Jain if (Error Err = Base::forEachRelaRelocation(RelSect, this, 871e8d81d80SStefan Gränitz &Self::addSingleRelocation)) 872e8d81d80SStefan Gränitz return Err; 8730ad562b4Sluxufan 874e8d81d80SStefan Gränitz return Error::success(); 8750ad562b4Sluxufan } 8760ad562b4Sluxufan 877e8d81d80SStefan Gränitz Error addSingleRelocation(const typename ELFT::Rela &Rel, 878e8d81d80SStefan Gränitz const typename ELFT::Shdr &FixupSect, 879091e3648SSteven Wu Block &BlockToFix) { 880e8d81d80SStefan Gränitz using Base = ELFLinkGraphBuilder<ELFT>; 881e8d81d80SStefan Gränitz 882f5b5398eSJonas Hahnfeld uint32_t Type = Rel.getType(false); 883f5b5398eSJonas Hahnfeld int64_t Addend = Rel.r_addend; 884310473c5SJob Noorman 885310473c5SJob Noorman if (Type == ELF::R_RISCV_RELAX) { 886310473c5SJob Noorman if (BlockToFix.edges_empty()) 887310473c5SJob Noorman return make_error<StringError>( 888310473c5SJob Noorman "R_RISCV_RELAX without preceding relocation", 889310473c5SJob Noorman inconvertibleErrorCode()); 890310473c5SJob Noorman 891310473c5SJob Noorman auto &PrevEdge = *std::prev(BlockToFix.edges().end()); 892310473c5SJob Noorman auto Kind = static_cast<EdgeKind_riscv>(PrevEdge.getKind()); 893310473c5SJob Noorman PrevEdge.setKind(getRelaxableRelocationKind(Kind)); 894f5b5398eSJonas Hahnfeld return Error::success(); 895f5b5398eSJonas Hahnfeld } 896f5b5398eSJonas Hahnfeld 897f5b5398eSJonas Hahnfeld Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type); 898f5b5398eSJonas Hahnfeld if (!Kind) 899f5b5398eSJonas Hahnfeld return Kind.takeError(); 900f5b5398eSJonas Hahnfeld 901e8d81d80SStefan Gränitz uint32_t SymbolIndex = Rel.getSymbol(false); 902e8d81d80SStefan Gränitz auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 903e8d81d80SStefan Gränitz if (!ObjSymbol) 904e8d81d80SStefan Gränitz return ObjSymbol.takeError(); 905e8d81d80SStefan Gränitz 906e8d81d80SStefan Gränitz Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 907e8d81d80SStefan Gränitz if (!GraphSymbol) 908e8d81d80SStefan Gränitz return make_error<StringError>( 909e8d81d80SStefan Gränitz formatv("Could not find symbol at given index, did you add it to " 910e8d81d80SStefan Gränitz "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 911e8d81d80SStefan Gränitz SymbolIndex, (*ObjSymbol)->st_shndx, 912e8d81d80SStefan Gränitz Base::GraphSymbols.size()), 913e8d81d80SStefan Gränitz inconvertibleErrorCode()); 914e8d81d80SStefan Gränitz 915118e953bSLang Hames auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; 916091e3648SSteven Wu Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 917e8d81d80SStefan Gränitz Edge GE(*Kind, Offset, *GraphSymbol, Addend); 918e8d81d80SStefan Gränitz LLVM_DEBUG({ 919e8d81d80SStefan Gränitz dbgs() << " "; 920091e3648SSteven Wu printEdge(dbgs(), BlockToFix, GE, riscv::getEdgeKindName(*Kind)); 921e8d81d80SStefan Gränitz dbgs() << "\n"; 922e8d81d80SStefan Gränitz }); 923e8d81d80SStefan Gränitz 924091e3648SSteven Wu BlockToFix.addEdge(std::move(GE)); 9250ad562b4Sluxufan return Error::success(); 9260ad562b4Sluxufan } 9270ad562b4Sluxufan 9280ad562b4Sluxufan public: 9290ad562b4Sluxufan ELFLinkGraphBuilder_riscv(StringRef FileName, 930*2ccf7ed2SJared Wyles const object::ELFFile<ELFT> &Obj, 931*2ccf7ed2SJared Wyles std::shared_ptr<orc::SymbolStringPool> SSP, 932*2ccf7ed2SJared Wyles Triple TT, SubtargetFeatures Features) 933*2ccf7ed2SJared Wyles : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT), 934*2ccf7ed2SJared Wyles std::move(Features), FileName, 935*2ccf7ed2SJared Wyles riscv::getEdgeKindName) {} 9360ad562b4Sluxufan }; 9370ad562b4Sluxufan 9380ad562b4Sluxufan Expected<std::unique_ptr<LinkGraph>> 939*2ccf7ed2SJared Wyles createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer, 940*2ccf7ed2SJared Wyles std::shared_ptr<orc::SymbolStringPool> SSP) { 9410ad562b4Sluxufan LLVM_DEBUG({ 9420ad562b4Sluxufan dbgs() << "Building jitlink graph for new input " 9430ad562b4Sluxufan << ObjectBuffer.getBufferIdentifier() << "...\n"; 9440ad562b4Sluxufan }); 9450ad562b4Sluxufan 9460ad562b4Sluxufan auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 9470ad562b4Sluxufan if (!ELFObj) 9480ad562b4Sluxufan return ELFObj.takeError(); 9490ad562b4Sluxufan 950348d0a6bSJob Noorman auto Features = (*ELFObj)->getFeatures(); 951348d0a6bSJob Noorman if (!Features) 952348d0a6bSJob Noorman return Features.takeError(); 953348d0a6bSJob Noorman 9540ad562b4Sluxufan if ((*ELFObj)->getArch() == Triple::riscv64) { 9550ad562b4Sluxufan auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj); 9560ad562b4Sluxufan return ELFLinkGraphBuilder_riscv<object::ELF64LE>( 9570ad562b4Sluxufan (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 958*2ccf7ed2SJared Wyles std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features)) 9590ad562b4Sluxufan .buildGraph(); 9600ad562b4Sluxufan } else { 9610ad562b4Sluxufan assert((*ELFObj)->getArch() == Triple::riscv32 && 9620ad562b4Sluxufan "Invalid triple for RISCV ELF object file"); 9630ad562b4Sluxufan auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj); 9640ad562b4Sluxufan return ELFLinkGraphBuilder_riscv<object::ELF32LE>( 9650ad562b4Sluxufan (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 966*2ccf7ed2SJared Wyles std::move(SSP), (*ELFObj)->makeTriple(), std::move(*Features)) 9670ad562b4Sluxufan .buildGraph(); 9680ad562b4Sluxufan } 9690ad562b4Sluxufan } 9700ad562b4Sluxufan 9710ad562b4Sluxufan void link_ELF_riscv(std::unique_ptr<LinkGraph> G, 9720ad562b4Sluxufan std::unique_ptr<JITLinkContext> Ctx) { 9730ad562b4Sluxufan PassConfiguration Config; 9740ad562b4Sluxufan const Triple &TT = G->getTargetTriple(); 9750ad562b4Sluxufan if (Ctx->shouldAddDefaultTargetPasses(TT)) { 9764f6757ceSJonas Hahnfeld 9774f6757ceSJonas Hahnfeld Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); 9784f6757ceSJonas Hahnfeld Config.PrePrunePasses.push_back(EHFrameEdgeFixer( 9794f6757ceSJonas Hahnfeld ".eh_frame", G->getPointerSize(), Edge::Invalid, Edge::Invalid, 9804f6757ceSJonas Hahnfeld Edge::Invalid, Edge::Invalid, NegDelta32)); 9814f6757ceSJonas Hahnfeld Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); 9824f6757ceSJonas Hahnfeld 9830ad562b4Sluxufan if (auto MarkLive = Ctx->getMarkLivePass(TT)) 9840ad562b4Sluxufan Config.PrePrunePasses.push_back(std::move(MarkLive)); 9850ad562b4Sluxufan else 9860ad562b4Sluxufan Config.PrePrunePasses.push_back(markAllSymbolsLive); 98789f546f6Sluxufan Config.PostPrunePasses.push_back( 98889f546f6Sluxufan PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass); 9891e60ab0fSJob Noorman Config.PostAllocationPasses.push_back(relax); 9900ad562b4Sluxufan } 9910ad562b4Sluxufan if (auto Err = Ctx->modifyPassConfig(*G, Config)) 9920ad562b4Sluxufan return Ctx->notifyFailed(std::move(Err)); 9930ad562b4Sluxufan 9940ad562b4Sluxufan ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config)); 9950ad562b4Sluxufan } 9960ad562b4Sluxufan 997de5198b0SJob Noorman LinkGraphPassFunction createRelaxationPass_ELF_riscv() { return relax; } 998de5198b0SJob Noorman 9990ad562b4Sluxufan } // namespace jitlink 10000ad562b4Sluxufan } // namespace llvm 1001