xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
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