Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
35271 views
//===------- ELF_riscv.cpp -JIT linker implementation for ELF/riscv -------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// ELF/riscv jit-link implementation.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"13#include "EHFrameSupportImpl.h"14#include "ELFLinkGraphBuilder.h"15#include "JITLinkGeneric.h"16#include "PerGraphGOTAndPLTStubsBuilder.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"19#include "llvm/ExecutionEngine/JITLink/JITLink.h"20#include "llvm/ExecutionEngine/JITLink/riscv.h"21#include "llvm/Object/ELF.h"22#include "llvm/Object/ELFObjectFile.h"23#include "llvm/Support/Endian.h"2425#define DEBUG_TYPE "jitlink"26using namespace llvm;27using namespace llvm::jitlink;28using namespace llvm::jitlink::riscv;2930namespace {3132class PerGraphGOTAndPLTStubsBuilder_ELF_riscv33: public PerGraphGOTAndPLTStubsBuilder<34PerGraphGOTAndPLTStubsBuilder_ELF_riscv> {35public:36static constexpr size_t StubEntrySize = 16;37static const uint8_t NullGOTEntryContent[8];38static const uint8_t RV64StubContent[StubEntrySize];39static const uint8_t RV32StubContent[StubEntrySize];4041using PerGraphGOTAndPLTStubsBuilder<42PerGraphGOTAndPLTStubsBuilder_ELF_riscv>::PerGraphGOTAndPLTStubsBuilder;4344bool isRV64() const { return G.getPointerSize() == 8; }4546bool isGOTEdgeToFix(Edge &E) const { return E.getKind() == R_RISCV_GOT_HI20; }4748Symbol &createGOTEntry(Symbol &Target) {49Block &GOTBlock =50G.createContentBlock(getGOTSection(), getGOTEntryBlockContent(),51orc::ExecutorAddr(), G.getPointerSize(), 0);52GOTBlock.addEdge(isRV64() ? R_RISCV_64 : R_RISCV_32, 0, Target, 0);53return G.addAnonymousSymbol(GOTBlock, 0, G.getPointerSize(), false, false);54}5556Symbol &createPLTStub(Symbol &Target) {57Block &StubContentBlock = G.createContentBlock(58getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 4, 0);59auto &GOTEntrySymbol = getGOTEntry(Target);60StubContentBlock.addEdge(R_RISCV_CALL, 0, GOTEntrySymbol, 0);61return G.addAnonymousSymbol(StubContentBlock, 0, StubEntrySize, true,62false);63}6465void fixGOTEdge(Edge &E, Symbol &GOTEntry) {66// Replace the relocation pair (R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12)67// with (R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12)68// Therefore, here just change the R_RISCV_GOT_HI20 to R_RISCV_PCREL_HI2069E.setKind(R_RISCV_PCREL_HI20);70E.setTarget(GOTEntry);71}7273void fixPLTEdge(Edge &E, Symbol &PLTStubs) {74assert((E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT ||75E.getKind() == CallRelaxable) &&76"Not a PLT edge?");77E.setKind(R_RISCV_CALL);78E.setTarget(PLTStubs);79}8081bool isExternalBranchEdge(Edge &E) const {82return (E.getKind() == R_RISCV_CALL || E.getKind() == R_RISCV_CALL_PLT ||83E.getKind() == CallRelaxable) &&84!E.getTarget().isDefined();85}8687private:88Section &getGOTSection() const {89if (!GOTSection)90GOTSection = &G.createSection("$__GOT", orc::MemProt::Read);91return *GOTSection;92}9394Section &getStubsSection() const {95if (!StubsSection)96StubsSection =97&G.createSection("$__STUBS", orc::MemProt::Read | orc::MemProt::Exec);98return *StubsSection;99}100101ArrayRef<char> getGOTEntryBlockContent() {102return {reinterpret_cast<const char *>(NullGOTEntryContent),103G.getPointerSize()};104}105106ArrayRef<char> getStubBlockContent() {107auto StubContent = isRV64() ? RV64StubContent : RV32StubContent;108return {reinterpret_cast<const char *>(StubContent), StubEntrySize};109}110111mutable Section *GOTSection = nullptr;112mutable Section *StubsSection = nullptr;113};114115const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_riscv::NullGOTEntryContent[8] =116{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};117118const uint8_t119PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV64StubContent[StubEntrySize] = {1200x17, 0x0e, 0x00, 0x00, // auipc t3, literal1210x03, 0x3e, 0x0e, 0x00, // ld t3, literal(t3)1220x67, 0x00, 0x0e, 0x00, // jr t31230x13, 0x00, 0x00, 0x00}; // nop124125const uint8_t126PerGraphGOTAndPLTStubsBuilder_ELF_riscv::RV32StubContent[StubEntrySize] = {1270x17, 0x0e, 0x00, 0x00, // auipc t3, literal1280x03, 0x2e, 0x0e, 0x00, // lw t3, literal(t3)1290x67, 0x00, 0x0e, 0x00, // jr t31300x13, 0x00, 0x00, 0x00}; // nop131} // namespace132namespace llvm {133namespace jitlink {134135static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) {136return (Num & (((1ULL << Size) - 1) << Low)) >> Low;137}138139static inline bool isAlignmentCorrect(uint64_t Value, int N) {140return (Value & (N - 1)) ? false : true;141}142143// Requires 0 < N <= 64.144static inline bool isInRangeForImm(int64_t Value, int N) {145return Value == llvm::SignExtend64(Value, N);146}147148class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {149friend class JITLinker<ELFJITLinker_riscv>;150151public:152ELFJITLinker_riscv(std::unique_ptr<JITLinkContext> Ctx,153std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)154: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {155JITLinkerBase::getPassConfig().PostAllocationPasses.push_back(156[this](LinkGraph &G) { return gatherRISCVPCRelHi20(G); });157}158159private:160DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *>161RelHi20;162163Error gatherRISCVPCRelHi20(LinkGraph &G) {164for (Block *B : G.blocks())165for (Edge &E : B->edges())166if (E.getKind() == R_RISCV_PCREL_HI20)167RelHi20[{B, E.getOffset()}] = &E;168169return Error::success();170}171172Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) const {173using namespace riscv;174assert((E.getKind() == R_RISCV_PCREL_LO12_I ||175E.getKind() == R_RISCV_PCREL_LO12_S) &&176"Can only have high relocation for R_RISCV_PCREL_LO12_I or "177"R_RISCV_PCREL_LO12_S");178179const Symbol &Sym = E.getTarget();180const Block &B = Sym.getBlock();181orc::ExecutorAddrDiff Offset = Sym.getOffset();182183auto It = RelHi20.find({&B, Offset});184if (It != RelHi20.end())185return *It->second;186187return make_error<JITLinkError>("No HI20 PCREL relocation type be found "188"for LO12 PCREL relocation type");189}190191Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {192using namespace riscv;193using namespace llvm::support;194195char *BlockWorkingMem = B.getAlreadyMutableContent().data();196char *FixupPtr = BlockWorkingMem + E.getOffset();197orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset();198switch (E.getKind()) {199case R_RISCV_32: {200int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();201*(little32_t *)FixupPtr = static_cast<uint32_t>(Value);202break;203}204case R_RISCV_64: {205int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();206*(little64_t *)FixupPtr = static_cast<uint64_t>(Value);207break;208}209case R_RISCV_BRANCH: {210int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;211if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 12)))212return makeTargetOutOfRangeError(G, B, E);213if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2)))214return makeAlignmentError(FixupAddress, Value, 2, E);215uint32_t Imm12 = extractBits(Value, 12, 1) << 31;216uint32_t Imm10_5 = extractBits(Value, 5, 6) << 25;217uint32_t Imm4_1 = extractBits(Value, 1, 4) << 8;218uint32_t Imm11 = extractBits(Value, 11, 1) << 7;219uint32_t RawInstr = *(little32_t *)FixupPtr;220*(little32_t *)FixupPtr =221(RawInstr & 0x1FFF07F) | Imm12 | Imm10_5 | Imm4_1 | Imm11;222break;223}224case R_RISCV_JAL: {225int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;226if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 20)))227return makeTargetOutOfRangeError(G, B, E);228if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2)))229return makeAlignmentError(FixupAddress, Value, 2, E);230uint32_t Imm20 = extractBits(Value, 20, 1) << 31;231uint32_t Imm10_1 = extractBits(Value, 1, 10) << 21;232uint32_t Imm11 = extractBits(Value, 11, 1) << 20;233uint32_t Imm19_12 = extractBits(Value, 12, 8) << 12;234uint32_t RawInstr = *(little32_t *)FixupPtr;235*(little32_t *)FixupPtr =236(RawInstr & 0xFFF) | Imm20 | Imm10_1 | Imm11 | Imm19_12;237break;238}239case CallRelaxable:240// Treat as R_RISCV_CALL when the relaxation pass did not run241case R_RISCV_CALL_PLT:242case R_RISCV_CALL: {243int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;244int64_t Hi = Value + 0x800;245if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32)))246return makeTargetOutOfRangeError(G, B, E);247int32_t Lo = Value & 0xFFF;248uint32_t RawInstrAuipc = *(little32_t *)FixupPtr;249uint32_t RawInstrJalr = *(little32_t *)(FixupPtr + 4);250*(little32_t *)FixupPtr =251RawInstrAuipc | (static_cast<uint32_t>(Hi & 0xFFFFF000));252*(little32_t *)(FixupPtr + 4) =253RawInstrJalr | (static_cast<uint32_t>(Lo) << 20);254break;255}256// The relocations R_RISCV_CALL_PLT and R_RISCV_GOT_HI20 are handled by257// PerGraphGOTAndPLTStubsBuilder_ELF_riscv and are transformed into258// R_RISCV_CALL and R_RISCV_PCREL_HI20.259case R_RISCV_PCREL_HI20: {260int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;261int64_t Hi = Value + 0x800;262if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32)))263return makeTargetOutOfRangeError(G, B, E);264uint32_t RawInstr = *(little32_t *)FixupPtr;265*(little32_t *)FixupPtr =266(RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));267break;268}269case R_RISCV_PCREL_LO12_I: {270// FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and271// pairs with current relocation R_RISCV_PCREL_LO12_I. So here may need a272// check.273auto RelHI20 = getRISCVPCRelHi20(E);274if (!RelHI20)275return RelHI20.takeError();276int64_t Value = RelHI20->getTarget().getAddress() +277RelHI20->getAddend() - E.getTarget().getAddress();278int64_t Lo = Value & 0xFFF;279uint32_t RawInstr = *(little32_t *)FixupPtr;280*(little32_t *)FixupPtr =281(RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);282break;283}284case R_RISCV_PCREL_LO12_S: {285// FIXME: We assume that R_RISCV_PCREL_HI20 is present in object code and286// pairs with current relocation R_RISCV_PCREL_LO12_S. So here may need a287// check.288auto RelHI20 = getRISCVPCRelHi20(E);289if (!RelHI20)290return RelHI20.takeError();291int64_t Value = RelHI20->getTarget().getAddress() +292RelHI20->getAddend() - E.getTarget().getAddress();293int64_t Lo = Value & 0xFFF;294uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25;295uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7;296uint32_t RawInstr = *(little32_t *)FixupPtr;297298*(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0;299break;300}301case R_RISCV_HI20: {302int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();303int64_t Hi = Value + 0x800;304if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32)))305return makeTargetOutOfRangeError(G, B, E);306uint32_t RawInstr = *(little32_t *)FixupPtr;307*(little32_t *)FixupPtr =308(RawInstr & 0xFFF) | (static_cast<uint32_t>(Hi & 0xFFFFF000));309break;310}311case R_RISCV_LO12_I: {312// FIXME: We assume that R_RISCV_HI20 is present in object code and pairs313// with current relocation R_RISCV_LO12_I. So here may need a check.314int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();315int32_t Lo = Value & 0xFFF;316uint32_t RawInstr = *(little32_t *)FixupPtr;317*(little32_t *)FixupPtr =318(RawInstr & 0xFFFFF) | (static_cast<uint32_t>(Lo & 0xFFF) << 20);319break;320}321case R_RISCV_LO12_S: {322// FIXME: We assume that R_RISCV_HI20 is present in object code and pairs323// with current relocation R_RISCV_LO12_S. So here may need a check.324int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();325int64_t Lo = Value & 0xFFF;326uint32_t Imm11_5 = extractBits(Lo, 5, 7) << 25;327uint32_t Imm4_0 = extractBits(Lo, 0, 5) << 7;328uint32_t RawInstr = *(little32_t *)FixupPtr;329*(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm11_5 | Imm4_0;330break;331}332case R_RISCV_ADD8: {333int64_t Value =334(E.getTarget().getAddress() +335*(reinterpret_cast<const uint8_t *>(FixupPtr)) + E.getAddend())336.getValue();337*FixupPtr = static_cast<uint8_t>(Value);338break;339}340case R_RISCV_ADD16: {341int64_t Value = (E.getTarget().getAddress() +342support::endian::read16le(FixupPtr) + E.getAddend())343.getValue();344*(little16_t *)FixupPtr = static_cast<uint16_t>(Value);345break;346}347case R_RISCV_ADD32: {348int64_t Value = (E.getTarget().getAddress() +349support::endian::read32le(FixupPtr) + E.getAddend())350.getValue();351*(little32_t *)FixupPtr = static_cast<uint32_t>(Value);352break;353}354case R_RISCV_ADD64: {355int64_t Value = (E.getTarget().getAddress() +356support::endian::read64le(FixupPtr) + E.getAddend())357.getValue();358*(little64_t *)FixupPtr = static_cast<uint64_t>(Value);359break;360}361case R_RISCV_SUB8: {362int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) -363E.getTarget().getAddress().getValue() - E.getAddend();364*FixupPtr = static_cast<uint8_t>(Value);365break;366}367case R_RISCV_SUB16: {368int64_t Value = support::endian::read16le(FixupPtr) -369E.getTarget().getAddress().getValue() - E.getAddend();370*(little16_t *)FixupPtr = static_cast<uint32_t>(Value);371break;372}373case R_RISCV_SUB32: {374int64_t Value = support::endian::read32le(FixupPtr) -375E.getTarget().getAddress().getValue() - E.getAddend();376*(little32_t *)FixupPtr = static_cast<uint32_t>(Value);377break;378}379case R_RISCV_SUB64: {380int64_t Value = support::endian::read64le(FixupPtr) -381E.getTarget().getAddress().getValue() - E.getAddend();382*(little64_t *)FixupPtr = static_cast<uint64_t>(Value);383break;384}385case R_RISCV_RVC_BRANCH: {386int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;387if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 8)))388return makeTargetOutOfRangeError(G, B, E);389if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2)))390return makeAlignmentError(FixupAddress, Value, 2, E);391uint16_t Imm8 = extractBits(Value, 8, 1) << 12;392uint16_t Imm4_3 = extractBits(Value, 3, 2) << 10;393uint16_t Imm7_6 = extractBits(Value, 6, 2) << 5;394uint16_t Imm2_1 = extractBits(Value, 1, 2) << 3;395uint16_t Imm5 = extractBits(Value, 5, 1) << 2;396uint16_t RawInstr = *(little16_t *)FixupPtr;397*(little16_t *)FixupPtr =398(RawInstr & 0xE383) | Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5;399break;400}401case R_RISCV_RVC_JUMP: {402int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;403if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 11)))404return makeTargetOutOfRangeError(G, B, E);405if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2)))406return makeAlignmentError(FixupAddress, Value, 2, E);407uint16_t Imm11 = extractBits(Value, 11, 1) << 12;408uint16_t Imm4 = extractBits(Value, 4, 1) << 11;409uint16_t Imm9_8 = extractBits(Value, 8, 2) << 9;410uint16_t Imm10 = extractBits(Value, 10, 1) << 8;411uint16_t Imm6 = extractBits(Value, 6, 1) << 7;412uint16_t Imm7 = extractBits(Value, 7, 1) << 6;413uint16_t Imm3_1 = extractBits(Value, 1, 3) << 3;414uint16_t Imm5 = extractBits(Value, 5, 1) << 2;415uint16_t RawInstr = *(little16_t *)FixupPtr;416*(little16_t *)FixupPtr = (RawInstr & 0xE003) | Imm11 | Imm4 | Imm9_8 |417Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5;418break;419}420case R_RISCV_SUB6: {421int64_t Value = *(reinterpret_cast<const uint8_t *>(FixupPtr)) & 0x3f;422Value -= E.getTarget().getAddress().getValue() - E.getAddend();423*FixupPtr = (*FixupPtr & 0xc0) | (static_cast<uint8_t>(Value) & 0x3f);424break;425}426case R_RISCV_SET6: {427int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();428uint32_t RawData = *(little32_t *)FixupPtr;429int64_t Word6 = Value & 0x3f;430*(little32_t *)FixupPtr = (RawData & 0xffffffc0) | Word6;431break;432}433case R_RISCV_SET8: {434int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();435uint32_t RawData = *(little32_t *)FixupPtr;436int64_t Word8 = Value & 0xff;437*(little32_t *)FixupPtr = (RawData & 0xffffff00) | Word8;438break;439}440case R_RISCV_SET16: {441int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();442uint32_t RawData = *(little32_t *)FixupPtr;443int64_t Word16 = Value & 0xffff;444*(little32_t *)FixupPtr = (RawData & 0xffff0000) | Word16;445break;446}447case R_RISCV_SET32: {448int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue();449int64_t Word32 = Value & 0xffffffff;450*(little32_t *)FixupPtr = Word32;451break;452}453case R_RISCV_32_PCREL: {454int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;455int64_t Word32 = Value & 0xffffffff;456*(little32_t *)FixupPtr = Word32;457break;458}459case AlignRelaxable:460// Ignore when the relaxation pass did not run461break;462case NegDelta32: {463int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();464if (LLVM_UNLIKELY(!isInRangeForImm(Value, 32)))465return makeTargetOutOfRangeError(G, B, E);466*(little32_t *)FixupPtr = static_cast<uint32_t>(Value);467break;468}469}470return Error::success();471}472};473474namespace {475476struct SymbolAnchor {477uint64_t Offset;478Symbol *Sym;479bool End; // true for the anchor of getOffset() + getSize()480};481482struct BlockRelaxAux {483// This records symbol start and end offsets which will be adjusted according484// to the nearest RelocDeltas element.485SmallVector<SymbolAnchor, 0> Anchors;486// All edges that either 1) are R_RISCV_ALIGN or 2) have a R_RISCV_RELAX edge487// at the same offset.488SmallVector<Edge *, 0> RelaxEdges;489// For RelaxEdges[I], the actual offset is RelaxEdges[I]->getOffset() - (I ?490// RelocDeltas[I - 1] : 0).491SmallVector<uint32_t, 0> RelocDeltas;492// For RelaxEdges[I], the actual type is EdgeKinds[I].493SmallVector<Edge::Kind, 0> EdgeKinds;494// List of rewritten instructions. Contains one raw encoded instruction per495// element in EdgeKinds that isn't Invalid or R_RISCV_ALIGN.496SmallVector<uint32_t, 0> Writes;497};498499struct RelaxConfig {500bool IsRV32;501bool HasRVC;502};503504struct RelaxAux {505RelaxConfig Config;506DenseMap<Block *, BlockRelaxAux> Blocks;507};508509} // namespace510511static bool shouldRelax(const Section &S) {512return (S.getMemProt() & orc::MemProt::Exec) != orc::MemProt::None;513}514515static bool isRelaxable(const Edge &E) {516switch (E.getKind()) {517default:518return false;519case CallRelaxable:520case AlignRelaxable:521return true;522}523}524525static RelaxAux initRelaxAux(LinkGraph &G) {526RelaxAux Aux;527Aux.Config.IsRV32 = G.getTargetTriple().isRISCV32();528const auto &Features = G.getFeatures().getFeatures();529Aux.Config.HasRVC = llvm::is_contained(Features, "+c") ||530llvm::is_contained(Features, "+zca");531532for (auto &S : G.sections()) {533if (!shouldRelax(S))534continue;535for (auto *B : S.blocks()) {536auto BlockEmplaceResult = Aux.Blocks.try_emplace(B);537assert(BlockEmplaceResult.second && "Block encountered twice");538auto &BlockAux = BlockEmplaceResult.first->second;539540for (auto &E : B->edges())541if (isRelaxable(E))542BlockAux.RelaxEdges.push_back(&E);543544if (BlockAux.RelaxEdges.empty()) {545Aux.Blocks.erase(BlockEmplaceResult.first);546continue;547}548549const auto NumEdges = BlockAux.RelaxEdges.size();550BlockAux.RelocDeltas.resize(NumEdges, 0);551BlockAux.EdgeKinds.resize_for_overwrite(NumEdges);552553// Store anchors (offset and offset+size) for symbols.554for (auto *Sym : S.symbols()) {555if (!Sym->isDefined() || &Sym->getBlock() != B)556continue;557558BlockAux.Anchors.push_back({Sym->getOffset(), Sym, false});559BlockAux.Anchors.push_back(560{Sym->getOffset() + Sym->getSize(), Sym, true});561}562}563}564565// Sort anchors by offset so that we can find the closest relocation566// efficiently. For a zero size symbol, ensure that its start anchor precedes567// its end anchor. For two symbols with anchors at the same offset, their568// order does not matter.569for (auto &BlockAuxIter : Aux.Blocks) {570llvm::sort(BlockAuxIter.second.Anchors, [](auto &A, auto &B) {571return std::make_pair(A.Offset, A.End) < std::make_pair(B.Offset, B.End);572});573}574575return Aux;576}577578static void relaxAlign(orc::ExecutorAddr Loc, const Edge &E, uint32_t &Remove,579Edge::Kind &NewEdgeKind) {580// E points to the start of the padding bytes.581// E + Addend points to the instruction to be aligned by removing padding.582// Alignment is the smallest power of 2 strictly greater than Addend.583const auto Align = NextPowerOf2(E.getAddend());584const auto DestLoc = alignTo(Loc.getValue(), Align);585const auto SrcLoc = Loc.getValue() + E.getAddend();586Remove = SrcLoc - DestLoc;587assert(static_cast<int32_t>(Remove) >= 0 &&588"R_RISCV_ALIGN needs expanding the content");589NewEdgeKind = AlignRelaxable;590}591592static void relaxCall(const Block &B, BlockRelaxAux &Aux,593const RelaxConfig &Config, orc::ExecutorAddr Loc,594const Edge &E, uint32_t &Remove,595Edge::Kind &NewEdgeKind) {596const auto JALR =597support::endian::read32le(B.getContent().data() + E.getOffset() + 4);598const auto RD = extractBits(JALR, 7, 5);599const auto Dest = E.getTarget().getAddress() + E.getAddend();600const auto Displace = Dest - Loc;601602if (Config.HasRVC && isInt<12>(Displace) && RD == 0) {603NewEdgeKind = R_RISCV_RVC_JUMP;604Aux.Writes.push_back(0xa001); // c.j605Remove = 6;606} else if (Config.HasRVC && Config.IsRV32 && isInt<12>(Displace) && RD == 1) {607NewEdgeKind = R_RISCV_RVC_JUMP;608Aux.Writes.push_back(0x2001); // c.jal609Remove = 6;610} else if (isInt<21>(Displace)) {611NewEdgeKind = R_RISCV_JAL;612Aux.Writes.push_back(0x6f | RD << 7); // jal613Remove = 4;614} else {615// Not relaxable616NewEdgeKind = R_RISCV_CALL_PLT;617Remove = 0;618}619}620621static bool relaxBlock(LinkGraph &G, Block &Block, BlockRelaxAux &Aux,622const RelaxConfig &Config) {623const auto BlockAddr = Block.getAddress();624bool Changed = false;625ArrayRef<SymbolAnchor> SA = ArrayRef(Aux.Anchors);626uint32_t Delta = 0;627628Aux.EdgeKinds.assign(Aux.EdgeKinds.size(), Edge::Invalid);629Aux.Writes.clear();630631for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {632const auto Loc = BlockAddr + E->getOffset() - Delta;633auto &Cur = Aux.RelocDeltas[I];634uint32_t Remove = 0;635switch (E->getKind()) {636case AlignRelaxable:637relaxAlign(Loc, *E, Remove, Aux.EdgeKinds[I]);638break;639case CallRelaxable:640relaxCall(Block, Aux, Config, Loc, *E, Remove, Aux.EdgeKinds[I]);641break;642default:643llvm_unreachable("Unexpected relaxable edge kind");644}645646// For all anchors whose offsets are <= E->getOffset(), they are preceded by647// the previous relocation whose RelocDeltas value equals Delta.648// Decrease their offset and update their size.649for (; SA.size() && SA[0].Offset <= E->getOffset(); SA = SA.slice(1)) {650if (SA[0].End)651SA[0].Sym->setSize(SA[0].Offset - Delta - SA[0].Sym->getOffset());652else653SA[0].Sym->setOffset(SA[0].Offset - Delta);654}655656Delta += Remove;657if (Delta != Cur) {658Cur = Delta;659Changed = true;660}661}662663for (const SymbolAnchor &A : SA) {664if (A.End)665A.Sym->setSize(A.Offset - Delta - A.Sym->getOffset());666else667A.Sym->setOffset(A.Offset - Delta);668}669670return Changed;671}672673static bool relaxOnce(LinkGraph &G, RelaxAux &Aux) {674bool Changed = false;675676for (auto &[B, BlockAux] : Aux.Blocks)677Changed |= relaxBlock(G, *B, BlockAux, Aux.Config);678679return Changed;680}681682static void finalizeBlockRelax(LinkGraph &G, Block &Block, BlockRelaxAux &Aux) {683auto Contents = Block.getAlreadyMutableContent();684auto *Dest = Contents.data();685auto NextWrite = Aux.Writes.begin();686uint32_t Offset = 0;687uint32_t Delta = 0;688689// Update section content: remove NOPs for R_RISCV_ALIGN and rewrite690// instructions for relaxed relocations.691for (auto [I, E] : llvm::enumerate(Aux.RelaxEdges)) {692uint32_t Remove = Aux.RelocDeltas[I] - Delta;693Delta = Aux.RelocDeltas[I];694if (Remove == 0 && Aux.EdgeKinds[I] == Edge::Invalid)695continue;696697// Copy from last location to the current relocated location.698const auto Size = E->getOffset() - Offset;699std::memmove(Dest, Contents.data() + Offset, Size);700Dest += Size;701702uint32_t Skip = 0;703switch (Aux.EdgeKinds[I]) {704case Edge::Invalid:705break;706case AlignRelaxable:707// For R_RISCV_ALIGN, we will place Offset in a location (among NOPs) to708// satisfy the alignment requirement. If both Remove and E->getAddend()709// are multiples of 4, it is as if we have skipped some NOPs. Otherwise we710// are in the middle of a 4-byte NOP, and we need to rewrite the NOP711// sequence.712if (Remove % 4 || E->getAddend() % 4) {713Skip = E->getAddend() - Remove;714uint32_t J = 0;715for (; J + 4 <= Skip; J += 4)716support::endian::write32le(Dest + J, 0x00000013); // nop717if (J != Skip) {718assert(J + 2 == Skip);719support::endian::write16le(Dest + J, 0x0001); // c.nop720}721}722break;723case R_RISCV_RVC_JUMP:724Skip = 2;725support::endian::write16le(Dest, *NextWrite++);726break;727case R_RISCV_JAL:728Skip = 4;729support::endian::write32le(Dest, *NextWrite++);730break;731}732733Dest += Skip;734Offset = E->getOffset() + Skip + Remove;735}736737std::memmove(Dest, Contents.data() + Offset, Contents.size() - Offset);738739// Fixup edge offsets and kinds.740Delta = 0;741size_t I = 0;742for (auto &E : Block.edges()) {743E.setOffset(E.getOffset() - Delta);744745if (I < Aux.RelaxEdges.size() && Aux.RelaxEdges[I] == &E) {746if (Aux.EdgeKinds[I] != Edge::Invalid)747E.setKind(Aux.EdgeKinds[I]);748749Delta = Aux.RelocDeltas[I];750++I;751}752}753754// Remove AlignRelaxable edges: all other relaxable edges got modified and755// will be used later while linking. Alignment is entirely handled here so we756// don't need these edges anymore.757for (auto IE = Block.edges().begin(); IE != Block.edges().end();) {758if (IE->getKind() == AlignRelaxable)759IE = Block.removeEdge(IE);760else761++IE;762}763}764765static void finalizeRelax(LinkGraph &G, RelaxAux &Aux) {766for (auto &[B, BlockAux] : Aux.Blocks)767finalizeBlockRelax(G, *B, BlockAux);768}769770static Error relax(LinkGraph &G) {771auto Aux = initRelaxAux(G);772while (relaxOnce(G, Aux)) {773}774finalizeRelax(G, Aux);775return Error::success();776}777778template <typename ELFT>779class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {780private:781static Expected<riscv::EdgeKind_riscv>782getRelocationKind(const uint32_t Type) {783using namespace riscv;784switch (Type) {785case ELF::R_RISCV_32:786return EdgeKind_riscv::R_RISCV_32;787case ELF::R_RISCV_64:788return EdgeKind_riscv::R_RISCV_64;789case ELF::R_RISCV_BRANCH:790return EdgeKind_riscv::R_RISCV_BRANCH;791case ELF::R_RISCV_JAL:792return EdgeKind_riscv::R_RISCV_JAL;793case ELF::R_RISCV_CALL:794return EdgeKind_riscv::R_RISCV_CALL;795case ELF::R_RISCV_CALL_PLT:796return EdgeKind_riscv::R_RISCV_CALL_PLT;797case ELF::R_RISCV_GOT_HI20:798return EdgeKind_riscv::R_RISCV_GOT_HI20;799case ELF::R_RISCV_PCREL_HI20:800return EdgeKind_riscv::R_RISCV_PCREL_HI20;801case ELF::R_RISCV_PCREL_LO12_I:802return EdgeKind_riscv::R_RISCV_PCREL_LO12_I;803case ELF::R_RISCV_PCREL_LO12_S:804return EdgeKind_riscv::R_RISCV_PCREL_LO12_S;805case ELF::R_RISCV_HI20:806return EdgeKind_riscv::R_RISCV_HI20;807case ELF::R_RISCV_LO12_I:808return EdgeKind_riscv::R_RISCV_LO12_I;809case ELF::R_RISCV_LO12_S:810return EdgeKind_riscv::R_RISCV_LO12_S;811case ELF::R_RISCV_ADD8:812return EdgeKind_riscv::R_RISCV_ADD8;813case ELF::R_RISCV_ADD16:814return EdgeKind_riscv::R_RISCV_ADD16;815case ELF::R_RISCV_ADD32:816return EdgeKind_riscv::R_RISCV_ADD32;817case ELF::R_RISCV_ADD64:818return EdgeKind_riscv::R_RISCV_ADD64;819case ELF::R_RISCV_SUB8:820return EdgeKind_riscv::R_RISCV_SUB8;821case ELF::R_RISCV_SUB16:822return EdgeKind_riscv::R_RISCV_SUB16;823case ELF::R_RISCV_SUB32:824return EdgeKind_riscv::R_RISCV_SUB32;825case ELF::R_RISCV_SUB64:826return EdgeKind_riscv::R_RISCV_SUB64;827case ELF::R_RISCV_RVC_BRANCH:828return EdgeKind_riscv::R_RISCV_RVC_BRANCH;829case ELF::R_RISCV_RVC_JUMP:830return EdgeKind_riscv::R_RISCV_RVC_JUMP;831case ELF::R_RISCV_SUB6:832return EdgeKind_riscv::R_RISCV_SUB6;833case ELF::R_RISCV_SET6:834return EdgeKind_riscv::R_RISCV_SET6;835case ELF::R_RISCV_SET8:836return EdgeKind_riscv::R_RISCV_SET8;837case ELF::R_RISCV_SET16:838return EdgeKind_riscv::R_RISCV_SET16;839case ELF::R_RISCV_SET32:840return EdgeKind_riscv::R_RISCV_SET32;841case ELF::R_RISCV_32_PCREL:842return EdgeKind_riscv::R_RISCV_32_PCREL;843case ELF::R_RISCV_ALIGN:844return EdgeKind_riscv::AlignRelaxable;845}846847return make_error<JITLinkError>(848"Unsupported riscv relocation:" + formatv("{0:d}: ", Type) +849object::getELFRelocationTypeName(ELF::EM_RISCV, Type));850}851852EdgeKind_riscv getRelaxableRelocationKind(EdgeKind_riscv Kind) {853switch (Kind) {854default:855// Just ignore unsupported relaxations856return Kind;857case R_RISCV_CALL:858case R_RISCV_CALL_PLT:859return CallRelaxable;860}861}862863Error addRelocations() override {864LLVM_DEBUG(dbgs() << "Processing relocations:\n");865866using Base = ELFLinkGraphBuilder<ELFT>;867using Self = ELFLinkGraphBuilder_riscv<ELFT>;868for (const auto &RelSect : Base::Sections)869if (Error Err = Base::forEachRelaRelocation(RelSect, this,870&Self::addSingleRelocation))871return Err;872873return Error::success();874}875876Error addSingleRelocation(const typename ELFT::Rela &Rel,877const typename ELFT::Shdr &FixupSect,878Block &BlockToFix) {879using Base = ELFLinkGraphBuilder<ELFT>;880881uint32_t Type = Rel.getType(false);882int64_t Addend = Rel.r_addend;883884if (Type == ELF::R_RISCV_RELAX) {885if (BlockToFix.edges_empty())886return make_error<StringError>(887"R_RISCV_RELAX without preceding relocation",888inconvertibleErrorCode());889890auto &PrevEdge = *std::prev(BlockToFix.edges().end());891auto Kind = static_cast<EdgeKind_riscv>(PrevEdge.getKind());892PrevEdge.setKind(getRelaxableRelocationKind(Kind));893return Error::success();894}895896Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type);897if (!Kind)898return Kind.takeError();899900uint32_t SymbolIndex = Rel.getSymbol(false);901auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);902if (!ObjSymbol)903return ObjSymbol.takeError();904905Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);906if (!GraphSymbol)907return make_error<StringError>(908formatv("Could not find symbol at given index, did you add it to "909"JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",910SymbolIndex, (*ObjSymbol)->st_shndx,911Base::GraphSymbols.size()),912inconvertibleErrorCode());913914auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;915Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();916Edge GE(*Kind, Offset, *GraphSymbol, Addend);917LLVM_DEBUG({918dbgs() << " ";919printEdge(dbgs(), BlockToFix, GE, riscv::getEdgeKindName(*Kind));920dbgs() << "\n";921});922923BlockToFix.addEdge(std::move(GE));924return Error::success();925}926927public:928ELFLinkGraphBuilder_riscv(StringRef FileName,929const object::ELFFile<ELFT> &Obj, Triple TT,930SubtargetFeatures Features)931: ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features),932FileName, riscv::getEdgeKindName) {}933};934935Expected<std::unique_ptr<LinkGraph>>936createLinkGraphFromELFObject_riscv(MemoryBufferRef ObjectBuffer) {937LLVM_DEBUG({938dbgs() << "Building jitlink graph for new input "939<< ObjectBuffer.getBufferIdentifier() << "...\n";940});941942auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);943if (!ELFObj)944return ELFObj.takeError();945946auto Features = (*ELFObj)->getFeatures();947if (!Features)948return Features.takeError();949950if ((*ELFObj)->getArch() == Triple::riscv64) {951auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);952return ELFLinkGraphBuilder_riscv<object::ELF64LE>(953(*ELFObj)->getFileName(), ELFObjFile.getELFFile(),954(*ELFObj)->makeTriple(), std::move(*Features))955.buildGraph();956} else {957assert((*ELFObj)->getArch() == Triple::riscv32 &&958"Invalid triple for RISCV ELF object file");959auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);960return ELFLinkGraphBuilder_riscv<object::ELF32LE>(961(*ELFObj)->getFileName(), ELFObjFile.getELFFile(),962(*ELFObj)->makeTriple(), std::move(*Features))963.buildGraph();964}965}966967void link_ELF_riscv(std::unique_ptr<LinkGraph> G,968std::unique_ptr<JITLinkContext> Ctx) {969PassConfiguration Config;970const Triple &TT = G->getTargetTriple();971if (Ctx->shouldAddDefaultTargetPasses(TT)) {972973Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));974Config.PrePrunePasses.push_back(EHFrameEdgeFixer(975".eh_frame", G->getPointerSize(), Edge::Invalid, Edge::Invalid,976Edge::Invalid, Edge::Invalid, NegDelta32));977Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));978979if (auto MarkLive = Ctx->getMarkLivePass(TT))980Config.PrePrunePasses.push_back(std::move(MarkLive));981else982Config.PrePrunePasses.push_back(markAllSymbolsLive);983Config.PostPrunePasses.push_back(984PerGraphGOTAndPLTStubsBuilder_ELF_riscv::asPass);985Config.PostAllocationPasses.push_back(relax);986}987if (auto Err = Ctx->modifyPassConfig(*G, Config))988return Ctx->notifyFailed(std::move(Err));989990ELFJITLinker_riscv::link(std::move(Ctx), std::move(G), std::move(Config));991}992993LinkGraphPassFunction createRelaxationPass_ELF_riscv() { return relax; }994995} // namespace jitlink996} // namespace llvm997998999