diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def @@ -55,3 +55,5 @@ ELF_RELOC(R_RISCV_32_PCREL, 57) ELF_RELOC(R_RISCV_IRELATIVE, 58) ELF_RELOC(R_RISCV_PLT32, 59) +ELF_RELOC(R_RISCV_SET_ULEB128, 60) +ELF_RELOC(R_RISCV_SUB_ULEB128, 61) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -94,6 +94,9 @@ {"fixup_riscv_set_6b", 2, 6, 0}, {"fixup_riscv_sub_6b", 2, 6, 0}, + + {"fixup_riscv_set_uleb128", 0, 0, 0}, + {"fixup_riscv_sub_uleb128", 0, 0, 0}, }; static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -411,6 +414,8 @@ case RISCV::fixup_riscv_sub_32: case RISCV::fixup_riscv_add_64: case RISCV::fixup_riscv_sub_64: + case RISCV::fixup_riscv_set_uleb128: + case RISCV::fixup_riscv_sub_uleb128: case FK_Data_1: case FK_Data_2: case FK_Data_4: diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -169,6 +169,10 @@ return ELF::R_RISCV_ADD64; case RISCV::fixup_riscv_sub_64: return ELF::R_RISCV_SUB64; + case RISCV::fixup_riscv_set_uleb128: + return ELF::R_RISCV_SET_ULEB128; + case RISCV::fixup_riscv_sub_uleb128: + return ELF::R_RISCV_SUB_ULEB128; } } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -26,6 +26,7 @@ : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override; + void emitULEB128Value(const MCExpr *Value) override; }; namespace llvm { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -23,11 +23,16 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/RISCVAttributes.h" using namespace llvm; +static cl::opt + EnableULEB128Reloc("riscv-enable-uleb128", cl::Hidden, + cl::desc("Enable relocation emission for ULEB128.")); + // This part is for ELF object output. RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) @@ -200,6 +205,47 @@ DF->getContents().resize(DF->getContents().size() + Size, 0); } +void RISCVELFStreamer::emitULEB128Value(const MCExpr *Value) { + const MCExpr *A, *B; + if (!EnableULEB128Reloc || !requiresFixups(getContext(), Value, A, B)) + return MCELFStreamer::emitULEB128Value(Value); + + SMLoc Loc = Value->getLoc(); + + int64_t IntValue; + unsigned PadTo = 0; + if (!Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) { + const FeatureBitset &Features = + getContext().getSubtargetInfo()->getFeatureBits(); + unsigned XLen = Features[RISCV::Feature64Bit] ? 64 : 32; + + // Emit a placeholder to make sure we'll emit enough space could be filled + // by linker later. + IntValue = 0; + // Each byte in ULEB128 format can encoding at most 7 bits. + PadTo = divideCeil(XLen, 7); + } + + if (IntValue < 0) + report_fatal_error("Can't encoding negative value in uleb128 format."); + + MCDataFragment *DF = getOrCreateDataFragment(); + flushPendingLabels(DF, DF->getContents().size()); + MCDwarfLineEntry::make(this, getCurrentSectionOnly()); + + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), A, + MCFixupKind(RISCV::fixup_riscv_set_uleb128), Loc)); + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), B, + MCFixupKind(RISCV::fixup_riscv_sub_uleb128), Loc)); + + SmallString<128> Tmp; + raw_svector_ostream OSE(Tmp); + encodeULEB128(IntValue, OSE, PadTo); + emitBytes(OSE.str()); +} + namespace llvm { MCELFStreamer *createRISCVELFStreamer(MCContext &C, std::unique_ptr MAB, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -106,6 +106,10 @@ // 6-bit fixup corresponding to R_RISCV_SUB6 for local label assignment in // DWARF CFA. fixup_riscv_sub_6b, + // fixup corresponding to R_RISCV_SET_ULEB128 for local label assignment. + fixup_riscv_set_uleb128, + // fixup corresponding to R_RISCV_SUB_ULEB128 for local label assignment. + fixup_riscv_sub_uleb128, // Used as a sentinel, must be the last fixup_riscv_invalid, diff --git a/llvm/test/MC/RISCV/fixups-expr-uleb128.s b/llvm/test/MC/RISCV/fixups-expr-uleb128.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/fixups-expr-uleb128.s @@ -0,0 +1,76 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix EMIT-RELOC-32 %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix EMIT-RELOC-32 %s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix EMIT-RELOC-64 %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix EMIT-RELOC-64 %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix NO-EMIT-RELOC %s + + +# Check that subtraction expressions are emitted as two relocations always. + +.text +.globl G1 +.globl G2 +.L1: +G1: +addi a0, a0, 0 +.L2: +G2: + +.data +.uleb128 G3-G1 +.uleb128 .L2-.L1 +.uleb128 G2-G1 + +# NO-EMIT-RELOC-NOT: R_RISCV_SET_ULEB128 +# NO-EMIT-RELOC-NOT: R_RISCV_SUB_ULEB128 + +# EMIT-RELOC-32: 0x0 R_RISCV_SET_ULEB128 G3 0x0 +# EMIT-RELOC-32: 0x0 R_RISCV_SUB_ULEB128 G1 0x0 +# EMIT-RELOC-32: 0x5 R_RISCV_SET_ULEB128 .L2 0x0 +# EMIT-RELOC-32: 0x5 R_RISCV_SUB_ULEB128 .L1 0x0 +# EMIT-RELOC-32: 0x6 R_RISCV_SET_ULEB128 G2 0x0 +# EMIT-RELOC-32: 0x6 R_RISCV_SUB_ULEB128 G1 0x0 + +# EMIT-RELOC-64: 0x0 R_RISCV_SET_ULEB128 G3 0x0 +# EMIT-RELOC-64: 0x0 R_RISCV_SUB_ULEB128 G1 0x0 +# EMIT-RELOC-64: 0xA R_RISCV_SET_ULEB128 .L2 0x0 +# EMIT-RELOC-64: 0xA R_RISCV_SUB_ULEB128 .L1 0x0 +# EMIT-RELOC-64: 0xB R_RISCV_SET_ULEB128 G2 0x0 +# EMIT-RELOC-64: 0xB R_RISCV_SUB_ULEB128 G1 0x0 + +.text +.globl G3 +G3: +nop