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/include/llvm/MC/MCFixup.h b/llvm/include/llvm/MC/MCFixup.h --- a/llvm/include/llvm/MC/MCFixup.h +++ b/llvm/include/llvm/MC/MCFixup.h @@ -19,28 +19,29 @@ /// Extensible enumeration to represent the type of a fixup. enum MCFixupKind { - FK_NONE = 0, ///< A no-op fixup. - FK_Data_1, ///< A one-byte fixup. - FK_Data_2, ///< A two-byte fixup. - FK_Data_4, ///< A four-byte fixup. - FK_Data_8, ///< A eight-byte fixup. - FK_Data_6b, ///< A six-bits fixup. - FK_PCRel_1, ///< A one-byte pc relative fixup. - FK_PCRel_2, ///< A two-byte pc relative fixup. - FK_PCRel_4, ///< A four-byte pc relative fixup. - FK_PCRel_8, ///< A eight-byte pc relative fixup. - FK_GPRel_1, ///< A one-byte gp relative fixup. - FK_GPRel_2, ///< A two-byte gp relative fixup. - FK_GPRel_4, ///< A four-byte gp relative fixup. - FK_GPRel_8, ///< A eight-byte gp relative fixup. - FK_DTPRel_4, ///< A four-byte dtp relative fixup. - FK_DTPRel_8, ///< A eight-byte dtp relative fixup. - FK_TPRel_4, ///< A four-byte tp relative fixup. - FK_TPRel_8, ///< A eight-byte tp relative fixup. - FK_SecRel_1, ///< A one-byte section relative fixup. - FK_SecRel_2, ///< A two-byte section relative fixup. - FK_SecRel_4, ///< A four-byte section relative fixup. - FK_SecRel_8, ///< A eight-byte section relative fixup. + FK_NONE = 0, ///< A no-op fixup. + FK_Data_1, ///< A one-byte fixup. + FK_Data_2, ///< A two-byte fixup. + FK_Data_4, ///< A four-byte fixup. + FK_Data_8, ///< A eight-byte fixup. + FK_Data_6b, ///< A six-bits fixup. + FK_Data_uleb128, ///< A uleb128 fixup. + FK_PCRel_1, ///< A one-byte pc relative fixup. + FK_PCRel_2, ///< A two-byte pc relative fixup. + FK_PCRel_4, ///< A four-byte pc relative fixup. + FK_PCRel_8, ///< A eight-byte pc relative fixup. + FK_GPRel_1, ///< A one-byte gp relative fixup. + FK_GPRel_2, ///< A two-byte gp relative fixup. + FK_GPRel_4, ///< A four-byte gp relative fixup. + FK_GPRel_8, ///< A eight-byte gp relative fixup. + FK_DTPRel_4, ///< A four-byte dtp relative fixup. + FK_DTPRel_8, ///< A eight-byte dtp relative fixup. + FK_TPRel_4, ///< A four-byte tp relative fixup. + FK_TPRel_8, ///< A eight-byte tp relative fixup. + FK_SecRel_1, ///< A one-byte section relative fixup. + FK_SecRel_2, ///< A two-byte section relative fixup. + FK_SecRel_4, ///< A four-byte section relative fixup. + FK_SecRel_8, ///< A eight-byte section relative fixup. FirstTargetFixupKind = 128, @@ -109,6 +110,8 @@ static MCFixupKind getKindForSize(unsigned Size, bool IsPCRel) { switch (Size) { default: llvm_unreachable("Invalid generic fixup size!"); + case 0: + return FK_Data_uleb128; case 1: return IsPCRel ? FK_PCRel_1 : FK_Data_1; case 2: @@ -126,6 +129,8 @@ switch (Size) { default: llvm_unreachable("Invalid generic fixup size!"); + case 0: + return FK_Data_uleb128; case 6: assert(!IsPCRel && "Invalid pc-relative fixup size!"); return FK_Data_6b; diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -89,6 +89,7 @@ {"FK_Data_4", 0, 32, 0}, {"FK_Data_8", 0, 64, 0}, {"FK_Data_6b", 0, 6, 0}, + {"FK_Data_uleb128", 0, 0, 0}, {"FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel}, {"FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, {"FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, 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,11 +414,14 @@ 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: case FK_Data_8: case FK_Data_6b: + case FK_Data_uleb128: return Value; case RISCV::fixup_riscv_set_6b: return Value & 0x03; @@ -596,6 +602,10 @@ TA = ELF::R_RISCV_ADD64; TB = ELF::R_RISCV_SUB64; break; + case llvm::FK_Data_uleb128: + TA = ELF::R_RISCV_SET_ULEB128; + TB = ELF::R_RISCV_SUB_ULEB128; + break; default: llvm_unreachable("unsupported fixup size"); } 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 @@ -22,6 +22,8 @@ std::unique_ptr MOW, std::unique_ptr MCE) : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {} + + 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) @@ -122,6 +127,43 @@ cast(Symbol).setOther(ELF::STO_RISCV_VARIANT_CC); } +void RISCVELFStreamer::emitULEB128Value(const MCExpr *Value) { + if (!EnableULEB128Reloc) + 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(), Value, MCFixup::getKindForSize(0, false), Loc)); + + SmallString<128> Tmp; + raw_svector_ostream OSE(Tmp); + encodeULEB128(IntValue, OSE, PadTo); + emitBytes(OSE.str()); +} + void RISCVELFStreamer::reset() { static_cast(getTargetStreamer())->reset(); MCELFStreamer::reset(); 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,96 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NORELAX,NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,EMIT-RELOC,EMIT-RELOC-32 %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NORELAX,NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax %s \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NORELAX,NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,EMIT-RELOC,EMIT-RELOC-64 %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128 \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NORELAX,NO-EMIT-RELOC %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NO-EMIT-RELOC %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax \ +# RUN: %s -riscv-enable-uleb128=false \ +# RUN: | llvm-readobj -r - \ +# RUN: | FileCheck -check-prefixes CHECK,NORELAX,NO-EMIT-RELOC %s + +# Check that subtraction expressions are emitted as two relocations always. + +.text +.globl G1 +.globl G2 +.L1: +G1: +call extern +.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 + +# CHECK: Relocations [ + +# NORELAX-NEXT: .rela.text { +# NORELAX-NEXT: R_RISCV_CALL_PLT +# NORELAX-NEXT: } + +# EMIT-RELOC: Section (5) .rela.data { +# EMIT-RELOC-32: 0x0 R_RISCV_SET_ULEB128 G3 0x0 +# EMIT-RELOC-32-NEXT: 0x0 R_RISCV_SUB_ULEB128 G1 0x0 +# EMIT-RELOC-32-NEXT: 0x5 R_RISCV_SET_ULEB128 .L2 0x0 +# EMIT-RELOC-32-NEXT: 0x5 R_RISCV_SUB_ULEB128 .L1 0x0 +# EMIT-RELOC-32-NEXT: 0xA R_RISCV_SET_ULEB128 G2 0x0 +# EMIT-RELOC-32-NEXT: 0xA R_RISCV_SUB_ULEB128 G1 0x0 + +# EMIT-RELOC-64: 0x0 R_RISCV_SET_ULEB128 G3 0x0 +# EMIT-RELOC-64-NEXT: 0x0 R_RISCV_SUB_ULEB128 G1 0x0 +# EMIT-RELOC-64-NEXT: 0xA R_RISCV_SET_ULEB128 .L2 0x0 +# EMIT-RELOC-64-NEXT: 0xA R_RISCV_SUB_ULEB128 .L1 0x0 +# EMIT-RELOC-64-NEXT: 0x14 R_RISCV_SET_ULEB128 G2 0x0 +# EMIT-RELOC-64-NEXT: 0x14 R_RISCV_SUB_ULEB128 G1 0x0 +# EMIT-RELOC: } +# CHECK: ] + +.text +.globl G3 +G3: +nop