From 22ac783c6ce2845278c866bf8dbb5a75c2ed44d4 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 02:42:13 +0100 Subject: [PATCH 1/7] [RISCV] Use common code for R_RISCV_CHERI_CAPABILITY in getRelocType Currently it's a one-liner but more code will be added here, so avoid needing to duplicate it. --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 4e6a1d4f8ad5..a6a1d3293bca 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -156,7 +156,7 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, "8-byte capability relocations not supported on RV64"); return ELF::R_RISCV_NONE; } - return ELF::R_RISCV_CHERI_CAPABILITY; + goto CheriCapability; case FK_Cap_16: if (!is64Bit()) { getContext().reportError( @@ -164,6 +164,8 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, "16-byte capability relocations not supported on RV32"); return ELF::R_RISCV_NONE; } + goto CheriCapability; + CheriCapability: return ELF::R_RISCV_CHERI_CAPABILITY; case RISCV::fixup_riscv_cheriot_compartment_hi: return ELF::R_RISCV_CHERIOT_COMPARTMENT_HI; From 2da350a7102c4dcce771ef4751136c1a5120e1e5 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 02:20:37 +0100 Subject: [PATCH 2/7] [NFC][Target][AsmPrinter] Introduce and use lowerCheriCodeReference This will allow targets to create a target-specific MCExpr for referring to code, bypassing any use of trampolines in the presence of a c18n runtime. --- llvm/include/llvm/Target/TargetLoweringObjectFile.h | 7 +++++++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 6 ++++-- llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp | 4 ++-- llvm/lib/Target/TargetLoweringObjectFile.cpp | 12 ++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 670f14802aad..54a9f26963f7 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -215,6 +215,13 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo { return nullptr; } + /// Return an MCExpr to use for a reference to the specified symbol with the + /// specified offset, where the symbol is a function symbol but we do not + /// want any interposition, as this reference is for a specific instruction + /// within the function (e.g. a BlockAddress). + virtual const MCExpr *lowerCheriCodeReference(const MCSymbol *Sym, + const MCExpr *Addend) const; + /// Target supports a PC-relative relocation that references the PLT of a /// function. bool hasPLTPCRelative() const { return PLTPCRelativeSpecifier; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d978b6ebac27..6696b99880c0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -4193,12 +4193,14 @@ static void emitGlobalConstantCHERICap(const DataLayout &DL, const Constant *CV, return; } else if (const MCSymbolRefExpr *SRE = dyn_cast(Expr)) { if (auto BA = dyn_cast(CV)) { - // For block addresses we emit `.chericap FN+(.LtmpN - FN)` + // For block addresses we emit `.chericap FN+(.LtmpN - FN)` as a code + // capability. // NB: Must use a non-preemptible symbol auto FnStart = AP.getSymbolPreferLocal(*BA->getFunction(), true); const MCExpr *Start = MCSymbolRefExpr::create(FnStart, Ctx); const MCExpr *DiffToStart = MCBinaryExpr::createSub(SRE, Start, Ctx); - const MCExpr *CapExpr = MCBinaryExpr::createAdd(Start, DiffToStart, Ctx); + const MCExpr *CapExpr = + AP.getObjFileLowering().lowerCheriCodeReference(FnStart, DiffToStart); AP.OutStreamer->emitCheriCapability(CapExpr, CapWidth); return; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index a8b3a8199a17..527a8aed3a04 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -216,8 +216,8 @@ void AsmPrinter::emitCallSiteCheriCapability(const MCSymbol *Hi, // this would result in emitCheriCapability() creating a relocation against // section plus offset rather than function + offset. We need the right // bounds and permissions info and need to use a non-preemptible alias. - const MCExpr *Expr = MCSymbolRefExpr::create(CurrentFnBeginLocal, OutContext); - Expr = MCBinaryExpr::createAdd(Expr, DiffToStart, OutContext); + const MCExpr *Expr = + TLOF.lowerCheriCodeReference(CurrentFnBeginLocal, DiffToStart); OutStreamer->emitCheriCapability(Expr, TLOF.getCheriCapabilitySize(TM)); } diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp index 1b8b7069f17c..ffec68384858 100644 --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -501,6 +501,18 @@ const MCExpr *TargetLoweringObjectFile::getDebugThreadLocalSymbol(const MCSymbol return MCSymbolRefExpr::create(Sym, getContext()); } +const MCExpr * +TargetLoweringObjectFile::lowerCheriCodeReference(const MCSymbol *Sym, + const MCExpr *Addend) const { + // Default to a normal expression if the target does not treat these + // specially. + // TODO: Require every CHERI target to implement this? + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext()); + if (Addend != nullptr) + Expr = MCBinaryExpr::createAdd(Expr, Addend, getContext()); + return Expr; +} + void TargetLoweringObjectFile::getNameWithPrefix( SmallVectorImpl &OutName, const GlobalValue *GV, const TargetMachine &TM) const { From f0660e1281059f64069d54b6a91b1d628b12c053 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 02:39:59 +0100 Subject: [PATCH 3/7] [BinaryFormat][RISCV] Reserve R_RISCV_CHERI_CAPABILITY_CODE For non-c18n runtimes this is the same as R_RISCV_CHERI_CAPABILITY, but for c18n runtimes this marks capabilities that must not be wrapped in a trampoline as they must point directly to the code in question. --- .../llvm/BinaryFormat/ELFRelocs/RISCV.def | 4 ++-- llvm/test/MC/RISCV/rv32-relaxation-xqci.s | 12 +++++------ llvm/test/MC/RISCV/xqcibi-linker-relaxation.s | 2 +- llvm/test/MC/RISCV/xqcilb-relocations.s | 20 +++++++++---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def index 32a84d6a96c8..cddbeefc2c4a 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def @@ -64,7 +64,7 @@ ELF_RELOC(R_RISCV_VENDOR, 191) // ELF_RELOC(R_RISCV_CUSTOM192, 192) // ELF_RELOC(R_RISCV_CUSTOM193, 193) // ELF_RELOC(R_RISCV_CUSTOM194, 194) -ELF_RELOC(R_RISCV_CUSTOM195, 195) +// ELF_RELOC(R_RISCV_CUSTOM195, 195) // ELF_RELOC(R_RISCV_CUSTOM196, 196) // ELF_RELOC(R_RISCV_CUSTOM197, 197) // ELF_RELOC(R_RISCV_CUSTOM198, 198) @@ -130,7 +130,7 @@ ELF_RELOC(R_RISCV_CUSTOM255, 255) ELF_RELOC(R_RISCV_CHERI_CAPTAB_PCREL_HI20, 192) ELF_RELOC(R_RISCV_CHERI_CAPABILITY, 193) ELF_RELOC(R_RISCV_FUNC_RELATIVE, 194) -// 195 reserved +ELF_RELOC(R_RISCV_CHERI_CAPABILITY_CODE, 195) ELF_RELOC(R_RISCV_CHERI_TPREL_CINCOFFSET, 196) // Deprecated ELF_RELOC(R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20, 197) // Deprecated ELF_RELOC(R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20, 198) // Deprecated diff --git a/llvm/test/MC/RISCV/rv32-relaxation-xqci.s b/llvm/test/MC/RISCV/rv32-relaxation-xqci.s index b38aa373c90f..fd1a60803f9d 100644 --- a/llvm/test/MC/RISCV/rv32-relaxation-xqci.s +++ b/llvm/test/MC/RISCV/rv32-relaxation-xqci.s @@ -40,7 +40,7 @@ start: # CHECK: qc.e.j {{0x[0-9a-f]+}} c.j undef # CHECK: qc.e.j {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef c.jal NEAR # CHECK: c.jal {{0x[0-9a-f]+}} @@ -56,7 +56,7 @@ start: # CHECK: qc.e.jal {{0x[0-9a-f]+}} c.jal undef # CHECK: qc.e.jal {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef jal zero, NEAR # CHECK: c.j {{0x[0-9a-f]+}} @@ -72,7 +72,7 @@ start: # CHECK: qc.e.j {{0x[0-9a-f]+}} jal zero, undef # CHECK: qc.e.j {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef jal ra, NEAR # CHECK: c.jal {{0x[0-9a-f]+}} @@ -88,7 +88,7 @@ start: # CHECK: qc.e.jal {{0x[0-9a-f]+}} jal ra, undef # CHECK: qc.e.jal {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef qc.e.j NEAR # CHECK: c.j {{0x[0-9a-f]+}} @@ -104,7 +104,7 @@ start: # CHECK: qc.e.j {{0x[0-9a-f]+}} qc.e.j undef # CHECK: qc.e.j {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef qc.e.jal NEAR # CHECK: c.jal {{0x[0-9a-f]+}} @@ -120,7 +120,7 @@ start: # CHECK: qc.e.jal {{0x[0-9a-f]+}} qc.e.jal undef # CHECK: qc.e.jal {{0x[0-9a-f]+}} -# CHECK: R_RISCV_CUSTOM195 undef +# CHECK: R_RISCV_CHERI_CAPABILITY_CODE undef diff --git a/llvm/test/MC/RISCV/xqcibi-linker-relaxation.s b/llvm/test/MC/RISCV/xqcibi-linker-relaxation.s index 098e31c93bc4..c5cc2698685b 100644 --- a/llvm/test/MC/RISCV/xqcibi-linker-relaxation.s +++ b/llvm/test/MC/RISCV/xqcibi-linker-relaxation.s @@ -15,7 +15,7 @@ branch_over_relaxable: jal x1, foo # CHECK: qc.e.jal 0x0 # CHECK-NEXT: R_RISCV_VENDOR QUALCOMM -# CHECK-NEXT: R_RISCV_CUSTOM195 foo +# CHECK-NEXT: R_RISCV_CHERI_CAPABILITY_CODE foo # CHECK-NEXT: R_RISCV_RELAX *ABS* bne a0, a1, branch_over_relaxable # CHECK-NEXT: bne a0, a1, 0x6 diff --git a/llvm/test/MC/RISCV/xqcilb-relocations.s b/llvm/test/MC/RISCV/xqcilb-relocations.s index 48c8c6931c8a..77fc2bc50c7d 100644 --- a/llvm/test/MC/RISCV/xqcilb-relocations.s +++ b/llvm/test/MC/RISCV/xqcilb-relocations.s @@ -21,13 +21,13 @@ this_section: # ASM: qc.e.j undef # OBJ: qc.e.j 0x0 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE undef{{$}} qc.e.j undef # ASM: qc.e.jal undef # OBJ-NEXT: qc.e.jal 0x6 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE undef{{$}} qc.e.jal undef @@ -42,26 +42,26 @@ qc.e.jal same_section # ASM: qc.e.j same_section_extern # OBJ-NEXT: qc.e.j 0x18 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 same_section_extern{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE same_section_extern{{$}} qc.e.j same_section_extern # ASM: qc.e.jal same_section_extern # OBJ-NEXT: qc.e.jal 0x1e # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 same_section_extern{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE same_section_extern{{$}} qc.e.jal same_section_extern # ASM: qc.e.j other_section # OBJ-NEXT: qc.e.j 0x24 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE other_section{{$}} qc.e.j other_section # ASM: qc.e.jal other_section # OBJ-NEXT: qc.e.jal 0x2a # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 other_section{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE other_section{{$}} qc.e.jal other_section @@ -81,14 +81,14 @@ same_section_extern: # ASM: qc.e.j same_section # OBJ: qc.e.j 0x38 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 same_section{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE same_section{{$}} # OBJ-NEXT: R_RISCV_RELAX qc.e.j same_section # ASM: qc.e.jal same_section # OBJ-NEXT: qc.e.jal 0x3e # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 same_section{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE same_section{{$}} # OBJ-NEXT: R_RISCV_RELAX qc.e.jal same_section @@ -99,14 +99,14 @@ qc.e.j undef # ASM: j undef # OBJ: qc.e.j 0x44 # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE undef{{$}} # OBJ-NEXT: R_RISCV_RELAX qc.e.jal undef # ASM: jal undef # OBJ: qc.e.jal 0x4a # OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} -# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_CHERI_CAPABILITY_CODE undef{{$}} # OBJ-NEXT: R_RISCV_RELAX .section .text.other, "ax", @progbits From b283b87c60c5e4e3a8f8fe6a8192c31bf945afc4 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 02:56:39 +0100 Subject: [PATCH 4/7] [RISCV] Add MC support for .chericap %code(expr) --- llvm/lib/MC/MCParser/AsmParser.cpp | 2 +- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp | 2 ++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index a7aea843aa3e..9b20e355bc22 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -5844,7 +5844,7 @@ bool AsmParser::parseDirectiveCheriCap(SMLoc DirectiveLoc) { if (!getTargetParser().isCheri()) return Error(DirectiveLoc, "'.chericap' requires CHERI"); - if (parseExpression(Expr)) + if (getTargetParser().parseDataExpr(Expr)) return true; int64_t Value; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index a6a1d3293bca..21b8bb37f588 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -166,6 +166,8 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, } goto CheriCapability; CheriCapability: + if (Fixup.getValue()->getKind() == ELF::R_RISCV_CHERI_CAPABILITY_CODE) + return ELF::R_RISCV_CHERI_CAPABILITY_CODE; return ELF::R_RISCV_CHERI_CAPABILITY; case RISCV::fixup_riscv_cheriot_compartment_hi: return ELF::R_RISCV_CHERIOT_COMPARTMENT_HI; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index 9ab1976a99e4..f62e8ae98330 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -50,6 +50,7 @@ RISCV::Specifier RISCV::parseSpecifierName(StringRef name) { .Case("cheriot_compartment_lo_i", RISCV::S_CHERIOT_COMPARTMENT_LO_I) .Case("cheriot_compartment_lo_s", RISCV::S_CHERIOT_COMPARTMENT_LO_S) .Case("cheriot_compartment_size", RISCV::S_CHERIOT_COMPARTMENT_SIZE) + .Case("code", ELF::R_RISCV_CHERI_CAPABILITY_CODE) .Default(0); } @@ -105,6 +106,8 @@ StringRef RISCV::getSpecifierName(Specifier S) { return "pltpcrel"; case RISCV::S_QC_ABS20: return "qc.abs20"; + case ELF::R_RISCV_CHERI_CAPABILITY_CODE: + return "code"; } llvm_unreachable("Invalid ELF symbol kind"); } From 95857a481161e1f0c885a233c00e73207f0f0577 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 22:16:51 +0100 Subject: [PATCH 5/7] [ELF][RISCV] Support R_RISCV_CHERI_CAPABILITY_CODE and R_RISCV_FUNC_RELATIVE Note that we only use R_RISCV_FUNC_RELATIVE for CheriABI binaries as it's redundant for plain RISC-V and we would not be able to produce binaries that work with existing upstream RISC-V runtimes. --- lld/ELF/Arch/Cheri.cpp | 22 ++++++-- lld/ELF/Arch/Cheri.h | 17 +++++-- lld/ELF/Arch/RISCV.cpp | 50 ++++++++++--------- lld/ELF/Relocations.cpp | 22 ++++++-- lld/ELF/SyntheticSections.cpp | 10 ++-- lld/ELF/Target.h | 2 + lld/test/ELF/cheri/exception-table.ll | 6 +-- lld/test/ELF/cheri/riscv/code-func-reloc.s | 30 +++++++++++ lld/test/ELF/cheri/riscv/code-reloc-data.s | 15 ++++++ .../ELF/cheri/riscv/code-reloc-preemptible.s | 20 ++++++++ lld/test/ELF/cheri/riscv/plt.s | 8 +-- .../MCTargetDesc/RISCVELFObjectWriter.cpp | 2 +- 12 files changed, 156 insertions(+), 48 deletions(-) create mode 100644 lld/test/ELF/cheri/riscv/code-func-reloc.s create mode 100644 lld/test/ELF/cheri/riscv/code-reloc-data.s create mode 100644 lld/test/ELF/cheri/riscv/code-reloc-preemptible.s diff --git a/lld/ELF/Arch/Cheri.cpp b/lld/ELF/Arch/Cheri.cpp index 434005bdffac..63f8febd1dc2 100644 --- a/lld/ELF/Arch/Cheri.cpp +++ b/lld/ELF/Arch/Cheri.cpp @@ -180,7 +180,7 @@ std::string CheriCapRelocLocation::toString(Ctx &ctx) const { return SymbolAndOffset(section, offset).verboseToString(ctx); } -void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc, +void CheriCapRelocsSection::addCapReloc(bool isCode, CheriCapRelocLocation loc, const SymbolAndOffset &target, int64_t capabilityOffset, Symbol *sourceSymbol) { @@ -215,7 +215,7 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc, return; } - addEntry(loc, {target, capabilityOffset}); + addEntry(loc, {isCode, target, capabilityOffset}); } static uint64_t getTargetSize(Ctx &ctx, const CheriCapRelocLocation &location, @@ -321,6 +321,7 @@ template struct CapRelocPermission { static const uint64_t function = permissionBit(1); static const uint64_t readOnly = permissionBit(2); static const uint64_t indirect = permissionBit(3); + static const uint64_t code = permissionBit(4); // clang-format on }; @@ -353,7 +354,7 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) { // The target VA is the base address of the capability, so symbol + 0 uint64_t targetVA; - bool isFunc, isGnuIFunc, isTls; + bool isFunc, isGnuIFunc, isTls, isCode = reloc.isCode; OutputSection *os; if (Symbol *s = dyn_cast(realTarget.symOrSec)) { targetVA = realTarget.sym()->getVA(ctx, 0); @@ -369,6 +370,15 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) { isTls = isec->type == STT_TLS; os = isec->getOutputSection(); } + if (isCode && !isFunc) { + auto msg = "code relocation against non-function symbol " + + realTarget.verboseToString(ctx) + "\n>>> referenced by " + + location.toString(ctx); + if (ctx.arg.noinhibitExec) + warn(msg); + else + error(msg); + } uint64_t targetSize = getTargetSize(ctx, location, realTarget); uint64_t targetOffset = reloc.capabilityOffset + realTarget.offset; uint64_t permissions = 0; @@ -377,6 +387,8 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) { permissions |= CapRelocPermission::function; if (isGnuIFunc) permissions |= CapRelocPermission::indirect; + if (isCode) + permissions |= CapRelocPermission::code; } else if (os) { assert(!isTls); // if ((OS->getPhdrFlags() & PF_W) == 0) { @@ -960,10 +972,12 @@ void addRelativeCapabilityRelocation( type); return; } + bool isCode = type == ctx.target->symbolicCodeCapRel; assert(!sym || !sym->isPreemptible); assert(!ctx.arg.useRelativeElfCheriRelocs && "relative ELF capability relocations not currently implemented"); - ctx.in.capRelocs->addCapReloc({&isec, offsetInSec}, {symOrSec, 0u}, addend); + ctx.in.capRelocs->addCapReloc(isCode, {&isec, offsetInSec}, {symOrSec, 0u}, + addend); } } // namespace elf diff --git a/lld/ELF/Arch/Cheri.h b/lld/ELF/Arch/Cheri.h index ef2297724b1e..d055bd5bd2b5 100644 --- a/lld/ELF/Arch/Cheri.h +++ b/lld/ELF/Arch/Cheri.h @@ -60,12 +60,18 @@ struct CheriCapRelocLocation { }; struct CheriCapReloc { + // Indicates this is a relocation where the symbol is a function symbol but + // we do not want any interposition, as this reference is for a specific + // instruction within the function. Normal references to functions should not + // set this. + bool isCode; // We can't use a plain Symbol* here as capabilities to string constants // will be e.g. `.rodata.str + 0x90` -> need to store offset as well SymbolAndOffset target; int64_t capabilityOffset; bool operator==(const CheriCapReloc &other) const { - return target == other.target && capabilityOffset == other.capabilityOffset; + return isCode == other.isCode && target == other.target && + capabilityOffset == other.capabilityOffset; } }; @@ -75,8 +81,9 @@ class CheriCapRelocsSection : public SyntheticSection { bool isNeeded() const override { return !relocsMap.empty(); } size_t getSize() const override { return relocsMap.size() * entsize; } void writeTo(uint8_t *buf) override; - void addCapReloc(CheriCapRelocLocation loc, const SymbolAndOffset &target, - int64_t capabilityOffset, Symbol *sourceSymbol = nullptr); + void addCapReloc(bool isCode, CheriCapRelocLocation loc, + const SymbolAndOffset &target, int64_t capabilityOffset, + Symbol *sourceSymbol = nullptr); private: template void writeToImpl(uint8_t *); @@ -88,8 +95,10 @@ class CheriCapRelocsSection : public SyntheticSection { " does not match existing one:\n> Existing: " + it.first->second.target.verboseToString(ctx) + ", cap offset=" + Twine(it.first->second.capabilityOffset) + + ", is code=" + Twine(it.first->second.isCode) + "\n> New: " + relocation.target.verboseToString(ctx) + - ", cap offset=" + Twine(relocation.capabilityOffset)); + ", cap offset=" + Twine(relocation.capabilityOffset) + + ", is code=" + Twine(relocation.isCode)); } return it.second; } diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 92a22fb6bb9d..7b1686825fdf 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -126,8 +126,11 @@ RISCV::RISCV(Ctx &ctx) : TargetInfo(ctx) { copyRel = R_RISCV_COPY; pltRel = R_RISCV_JUMP_SLOT; relativeRel = R_RISCV_RELATIVE; + if (ctx.arg.isCheriAbi) + relativeFuncRel = R_RISCV_FUNC_RELATIVE; iRelativeRel = R_RISCV_IRELATIVE; symbolicCapRel = R_RISCV_CHERI_CAPABILITY; + symbolicCodeCapRel = R_RISCV_CHERI_CAPABILITY_CODE; if (ctx.arg.is64) { symbolicRel = R_RISCV_64; tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64; @@ -382,29 +385,29 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, case R_RISCV_SET_ULEB128: case R_RISCV_SUB_ULEB128: return RE_RISCV_LEB128; - case R_RISCV_CHERI_CAPABILITY: - return R_ABS_CAP; - // TODO: Deprecate and eventually remove these - case R_RISCV_CHERI_CAPTAB_PCREL_HI20: - return R_GOT_PC; - case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20: - return R_GOT_PC; - case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20: - return R_TLSGD_PC; - case R_RISCV_CHERIOT_COMPARTMENT_HI: - return isPCCRelative(ctx, loc, &s) ? R_PC - : R_CHERIOT_COMPARTMENT_CGPREL_HI; - case R_RISCV_CHERIOT_COMPARTMENT_LO_I: - return R_CHERIOT_COMPARTMENT_CGPREL_LO_I; - case R_RISCV_CHERIOT_COMPARTMENT_LO_S: - return R_CHERIOT_COMPARTMENT_CGPREL_LO_S; - case R_RISCV_CHERIOT_COMPARTMENT_SIZE: - return R_CHERIOT_COMPARTMENT_SIZE; - default: - Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v - << ") against symbol " << &s; - return R_NONE; - } + case R_RISCV_CHERI_CAPABILITY: + case R_RISCV_CHERI_CAPABILITY_CODE: + return R_ABS_CAP; + // TODO: Deprecate and eventually remove these + case R_RISCV_CHERI_CAPTAB_PCREL_HI20: + return R_GOT_PC; + case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20: + return R_GOT_PC; + case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20: + return R_TLSGD_PC; + case R_RISCV_CHERIOT_COMPARTMENT_HI: + return isPCCRelative(ctx, loc, &s) ? R_PC : R_CHERIOT_COMPARTMENT_CGPREL_HI; + case R_RISCV_CHERIOT_COMPARTMENT_LO_I: + return R_CHERIOT_COMPARTMENT_CGPREL_LO_I; + case R_RISCV_CHERIOT_COMPARTMENT_LO_S: + return R_CHERIOT_COMPARTMENT_CGPREL_LO_S; + case R_RISCV_CHERIOT_COMPARTMENT_SIZE: + return R_CHERIOT_COMPARTMENT_SIZE; + default: + Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v + << ") against symbol " << &s; + return R_NONE; + } } void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { @@ -681,6 +684,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { } case R_RISCV_CHERI_CAPABILITY: + case R_RISCV_CHERI_CAPABILITY_CODE: // Write a word within the capability if (ctx.arg.is64) write64le(loc, val); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 447bc25fdf20..ee9ce1af1743 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -936,8 +936,11 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec, part.relrDyn->relocs.push_back({&isec, isec.relocs().size() - 1}); return; } - part.relaDyn->addRelativeReloc(ctx.target->relativeRel, isec, - offsetInSec, sym, addend, type, expr); + RelType relativeType = ctx.target->relativeRel; + if (ctx.target->relativeFuncRel && sym.isFunc()) + relativeType = *ctx.target->relativeFuncRel; + part.relaDyn->addRelativeReloc(relativeType, isec, offsetInSec, sym, + addend, type, expr); } template @@ -955,7 +958,8 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt, } addRelativeCapabilityRelocation(ctx, gotPlt, sym.getGotPltOffset(ctx), &plt, - 0, R_ABS_CAP, *ctx.target->symbolicCapRel); + 0, R_ABS_CAP, + *ctx.target->symbolicCodeCapRel); } rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), @@ -1246,8 +1250,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, if (canWrite) { RelType rel = ctx.target->getDynRel(type); if (oneof(expr) || - ((rel == ctx.target->symbolicRel || - rel == ctx.target->symbolicCapRel) && + ((rel == ctx.target->symbolicRel || rel == ctx.target->symbolicCapRel || + type == ctx.target->symbolicCodeCapRel) && !sym.isPreemptible)) { addRelativeReloc(ctx, *sec, offset, sym, addend, expr, type); return; @@ -1298,6 +1302,14 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, if (ctx.arg.emachine == EM_MIPS && expr != R_ABS_CAP) ctx.in.mipsGot->addEntry(*sec->file, sym, addend, expr); return; + } else if (type == ctx.target->symbolicCodeCapRel) { + auto diag = (ctx.arg.noinhibitExec) ? Warn(ctx) : Err(ctx); + diag << "relocation " + toStr(ctx, type) + << " cannot be used against preemptible symbol '" << toStr(ctx, sym) + << "'"; + printLocation(diag, *sec, sym, offset); + + return; } } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index d6d8eec622f1..009d44a339ed 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1798,10 +1798,12 @@ void RelocationBaseSection::partitionRels() { if (!combreloc) return; const RelType relativeRel = ctx.target->relativeRel; - numRelativeRelocs = - std::stable_partition(relocs.begin(), relocs.end(), - [=](auto &r) { return r.type == relativeRel; }) - - relocs.begin(); + const std::optional relativeFuncRel = ctx.target->relativeFuncRel; + const auto *firstNonRelativeReloc = + std::stable_partition(relocs.begin(), relocs.end(), [=](auto &r) { + return r.type == relativeRel || r.type == relativeFuncRel; + }); + numRelativeRelocs = firstNonRelativeReloc - relocs.begin(); } void RelocationBaseSection::finalizeContents() { diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 329811326945..b3ccf2c04e60 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -130,6 +130,7 @@ class TargetInfo { RelType gotRel = 0; RelType pltRel = 0; RelType relativeRel = 0; + std::optional relativeFuncRel; RelType iRelativeRel = 0; RelType symbolicRel = 0; RelType tlsDescRel = 0; @@ -140,6 +141,7 @@ class TargetInfo { std::optional sizeRel; std::optional symbolicCapRel; std::optional symbolicCapCallRel; + std::optional symbolicCodeCapRel; unsigned gotEntrySize = ctx.arg.wordsize; unsigned pltEntrySize = 0; unsigned pltHeaderSize = 0; diff --git a/lld/test/ELF/cheri/exception-table.ll b/lld/test/ELF/cheri/exception-table.ll index a50e55125656..e7e3227fd37f 100644 --- a/lld/test/ELF/cheri/exception-table.ll +++ b/lld/test/ELF/cheri/exception-table.ll @@ -99,9 +99,9 @@ ; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST2_ADDR]] (.L_Z5test2ll$local+68) Length: 124 Perms: Function ; Next one references the local symbol, and uses that length rather than the override: ; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_WEAK_ADDR]] (.L_Z9test_weakll$local+28) Length: 52 Perms: Function -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR:]] (+0) Length: 80 Perms: Function -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Function -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Function +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR:]] (+0) Length: 80 Perms: Code +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Code +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Code ; RV64-RELOCS-NEXT: ] ; IR was generated from the following code: diff --git a/lld/test/ELF/cheri/riscv/code-func-reloc.s b/lld/test/ELF/cheri/riscv/code-func-reloc.s new file mode 100644 index 000000000000..b5defe3cd76a --- /dev/null +++ b/lld/test/ELF/cheri/riscv/code-func-reloc.s @@ -0,0 +1,30 @@ +# REQUIRES: riscv + +# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o +# RUN: ld.lld -shared -z separate-code %t.o -o %t.so +# RUN: llvm-readobj -r --cap-relocs %t.so | FileCheck %s + +# CHECK: .rela.dyn { +# CHECK-NEXT: 0x3100 R_RISCV_FUNC_RELATIVE - 0x1000 +# CHECK-NEXT: 0x3108 R_RISCV_RELATIVE - 0x30D0 +# CHECK-NEXT: } +# CHECK: CHERI __cap_relocs [ +# CHECK-NEXT: 0x0030d0 (data) Base: 0x1000 (func+0) Length: 4 Perms: Function +# CHECK-NEXT: 0x0030e0 Base: 0x1000 (func+0) Length: 4 Perms: Code +# CHECK-NEXT: 0x0030f0 Base: 0x30d0 (data+0) Length: 64 Perms: Object +# CHECK-NEXT: ] + + .type func, @function +func: + cret + .size func, . - func + + .data + .type data, @object +data: + .chericap func + .chericap %code(func) + .chericap data + .quad func + .quad data + .size data, . - data diff --git a/lld/test/ELF/cheri/riscv/code-reloc-data.s b/lld/test/ELF/cheri/riscv/code-reloc-data.s new file mode 100644 index 000000000000..95d4ddd1808d --- /dev/null +++ b/lld/test/ELF/cheri/riscv/code-reloc-data.s @@ -0,0 +1,15 @@ +# REQUIRES: riscv + +# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: code relocation against non-function symbol local object data +# CHECK-NEXT: >>> defined in ({{.*}}/code-reloc-data.s.tmp.o:(object data: .data+0x0)) +# CHECK-NEXT: >>> referenced by local object data +# CHECK-NEXT: >>> defined in ({{.*}}/code-reloc-data.s.tmp.o:(object data: .data+0x0)) + + .data + .type data, @object +data: + .chericap %code(data) + .size data, . - data diff --git a/lld/test/ELF/cheri/riscv/code-reloc-preemptible.s b/lld/test/ELF/cheri/riscv/code-reloc-preemptible.s new file mode 100644 index 000000000000..01b7e0a7551b --- /dev/null +++ b/lld/test/ELF/cheri/riscv/code-reloc-preemptible.s @@ -0,0 +1,20 @@ +# REQUIRES: riscv + +# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: relocation R_RISCV_CHERI_CAPABILITY_CODE cannot be used against preemptible symbol 'func' +# CHECK-NEXT: >>> defined in {{.*}}/code-reloc-preemptible.s.tmp.o +# CHECK-NEXT: >>> referenced by {{.*}}/code-reloc-preemptible.s.tmp.o:(data) + + .global func + .type func, @function +func: + cret + .size func, . - func + + .data + .type data, @object +data: + .chericap %code(func) + .size data, . - data diff --git a/lld/test/ELF/cheri/riscv/plt.s b/lld/test/ELF/cheri/riscv/plt.s index f9ab1d3fd5ff..4bcc20ba52de 100644 --- a/lld/test/ELF/cheri/riscv/plt.s +++ b/lld/test/ELF/cheri/riscv/plt.s @@ -31,8 +31,8 @@ # RELOC32-NEXT: 0x13090 R_RISCV_JUMP_SLOT weak 0x0 # RELOC32-NEXT: } # RELOC32: CHERI __cap_relocs [ -# RELOC32-NEXT: 0x013088 Base: 0x11030 (+0) Length: 64 Perms: Function -# RELOC32-NEXT: 0x013090 Base: 0x11030 (+0) Length: 64 Perms: Function +# RELOC32-NEXT: 0x013088 Base: 0x11030 (+0) Length: 64 Perms: Code +# RELOC32-NEXT: 0x013090 Base: 0x11030 (+0) Length: 64 Perms: Code # RELOC32-NEXT: ] # GOTPLT32: section '.got.plt' # GOTPLT32-NEXT: 0x00013078 00000000 00000000 00000000 00000000 @@ -43,8 +43,8 @@ # RELOC64-NEXT: 0x13120 R_RISCV_JUMP_SLOT weak 0x0 # RELOC64-NEXT: } # RELOC64: CHERI __cap_relocs [ -# RELOC64-NEXT: 0x013110 Base: 0x11030 (+0) Length: 64 Perms: Function -# RELOC64-NEXT: 0x013120 Base: 0x11030 (+0) Length: 64 Perms: Function +# RELOC64-NEXT: 0x013110 Base: 0x11030 (+0) Length: 64 Perms: Code +# RELOC64-NEXT: 0x013120 Base: 0x11030 (+0) Length: 64 Perms: Code # RELOC64-NEXT: ] # GOTPLT64: section '.got.plt' # GOTPLT64-NEXT: 0x000130f0 00000000 00000000 00000000 00000000 diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 21b8bb37f588..c3c61967d2b8 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -166,7 +166,7 @@ unsigned RISCVELFObjectWriter::getRelocType(const MCFixup &Fixup, } goto CheriCapability; CheriCapability: - if (Fixup.getValue()->getKind() == ELF::R_RISCV_CHERI_CAPABILITY_CODE) + if (Spec == ELF::R_RISCV_CHERI_CAPABILITY_CODE) return ELF::R_RISCV_CHERI_CAPABILITY_CODE; return ELF::R_RISCV_CHERI_CAPABILITY; case RISCV::fixup_riscv_cheriot_compartment_hi: From 4403a98a1b5d044b398415a0e24e5fcb03026b27 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Wed, 20 Aug 2025 03:23:40 +0100 Subject: [PATCH 6/7] [RISCV] Use new %code(expr) for lowerCheriCodeReference --- lld/test/ELF/cheri/exception-table.ll | 16 ++++++++-------- .../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 1 + llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp | 11 +++++++++++ llvm/lib/Target/RISCV/RISCVTargetObjectFile.h | 3 +++ .../Inputs/landingpad-non-preemptible.ll | 5 +++-- .../RISCV32/landingpad-non-preemptible.ll | 4 ++-- .../RISCV64/landingpad-non-preemptible.ll | 4 ++-- .../RISCV/cheri/function-start-directives.ll | 4 ++-- 8 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lld/test/ELF/cheri/exception-table.ll b/lld/test/ELF/cheri/exception-table.ll index e7e3227fd37f..bc1056ecd35c 100644 --- a/lld/test/ELF/cheri/exception-table.ll +++ b/lld/test/ELF/cheri/exception-table.ll @@ -15,12 +15,12 @@ ; MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z9test_weakll$local 0x34 ; MIPS-OBJ-RELOCS-NEXT: } ; RV64-OBJ-RELOCS: Section ({{.+}}) .rela.gcc_except_table { -; RV64-OBJ-RELOCS-NEXT: 0x20 R_RISCV_CHERI_CAPABILITY .L_Z4testll$local 0x5C -; RV64-OBJ-RELOCS-NEXT: 0x40 R_RISCV_CHERI_CAPABILITY .L_Z4testll$local 0x48 -; RV64-OBJ-RELOCS-NEXT: 0x80 R_RISCV_CHERI_CAPABILITY .L_Z5test2ll$local 0x44 +; RV64-OBJ-RELOCS-NEXT: 0x20 R_RISCV_CHERI_CAPABILITY_CODE .L_Z4testll$local 0x5C +; RV64-OBJ-RELOCS-NEXT: 0x40 R_RISCV_CHERI_CAPABILITY_CODE .L_Z4testll$local 0x48 +; RV64-OBJ-RELOCS-NEXT: 0x80 R_RISCV_CHERI_CAPABILITY_CODE .L_Z5test2ll$local 0x44 ; RV64-OBJ-RELOCS-NEXT: 0xA4 R_RISCV_ADD32 .L_ZTIl.DW.stub 0x0 ; RV64-OBJ-RELOCS-NEXT: 0xA4 R_RISCV_SUB32 .L0 0x0 -; RV64-OBJ-RELOCS-NEXT: 0xC0 R_RISCV_CHERI_CAPABILITY .L_Z9test_weakll$local 0x1C +; RV64-OBJ-RELOCS-NEXT: 0xC0 R_RISCV_CHERI_CAPABILITY_CODE .L_Z9test_weakll$local 0x1C ; RV64-OBJ-RELOCS-NEXT: } ;; This should work with both -z text and -z notext @@ -94,11 +94,11 @@ ; RV64-RELOCS-OVERRIDE: [[#%.16x,TEST_WEAK_OVERRIDE_ADDR:]] 8 FUNC GLOBAL DEFAULT 9 _Z9test_weakll{{$}} ; RV64-RELOCS: CHERI __cap_relocs [ -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_ADDR]] (.L_Z4testll$local+92) Length: 116 Perms: Function -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_ADDR]] (.L_Z4testll$local+72) Length: 116 Perms: Function -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST2_ADDR]] (.L_Z5test2ll$local+68) Length: 124 Perms: Function +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_ADDR]] (.L_Z4testll$local+92) Length: 116 Perms: Code +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_ADDR]] (.L_Z4testll$local+72) Length: 116 Perms: Code +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST2_ADDR]] (.L_Z5test2ll$local+68) Length: 124 Perms: Code ; Next one references the local symbol, and uses that length rather than the override: -; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_WEAK_ADDR]] (.L_Z9test_weakll$local+28) Length: 52 Perms: Function +; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_WEAK_ADDR]] (.L_Z9test_weakll$local+28) Length: 52 Perms: Code ; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR:]] (+0) Length: 80 Perms: Code ; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Code ; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (+0) Length: 80 Perms: Code diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index f62e8ae98330..b74ca177700e 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -17,6 +17,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp index 0959ed0b8250..3ec131eb576b 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp @@ -210,3 +210,14 @@ int RISCVELFTargetObjectFile::getCheriCapabilitySize( const RISCVTargetMachine &RTM = static_cast(TM); return RTM.IsRV64() ? 16 : 8; } + +const MCExpr * +RISCVELFTargetObjectFile::lowerCheriCodeReference(const MCSymbol *Sym, + const MCExpr *Addend) const { + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext()); + if (Addend != nullptr) + Expr = MCBinaryExpr::createAdd(Expr, Addend, getContext()); + Expr = MCSpecifierExpr::create(Expr, ELF::R_RISCV_CHERI_CAPABILITY_CODE, + getContext()); + return Expr; +} diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h index 67c41e494176..f0d82d7d9135 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h +++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h @@ -62,6 +62,9 @@ class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF { const TargetMachine &TM) const override; int getCheriCapabilitySize(const TargetMachine &TM) const override; + + const MCExpr *lowerCheriCodeReference(const MCSymbol *Sym, + const MCExpr *Addend) const override; }; } // end namespace llvm diff --git a/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll index 26cbab202ce5..eae304312b3c 100644 --- a/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll @@ -75,7 +75,8 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) -; CHECK-NEXT: .chericap .Llpad0 # jumps to .Llpad0 +@IF-MIPS@; CHECK-NEXT: .chericap .Llpad0 # jumps to .Llpad0 +@IF-RISCV@; CHECK-NEXT: .chericap %code(.L_Z8do_catchv$local+(.Ltmp2-.Lfunc_begin0)) # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -104,7 +105,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-LABEL: Section ({{.+}}) .rela.gcc_except_table { @IF-MIPS@; RELOCS-NEXT: 0x10 R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .Llpad0 0x0{{$}} @IF-MIPS@; RELOCS-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE .L_ZTIi.DW.stub 0x0 -@IF-RISCV@; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .Llpad0 0x0{{$}} +@IF-RISCV@; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY_CODE .Llpad0 0x0{{$}} @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_SUB32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 .L_ZTIi.DW.stub 0x0 diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll index d2c4eb73ad50..a75b458ea45e 100644 --- a/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll @@ -111,7 +111,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) -; CHECK-NEXT: .chericap .L_Z8do_catchv$local+(.Ltmp2-.Lfunc_begin0) # jumps to .Ltmp2 +; CHECK-NEXT: .chericap %code(.L_Z8do_catchv$local+(.Ltmp2-.Lfunc_begin0)) # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -138,7 +138,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-LABEL: Relocations [ ; RELOCS-LABEL: Section ({{.+}}) .rela.gcc_except_table { -; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$local 0x24 +; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY_CODE .L_Z8do_catchv$local 0x24 ; RELOCS-NEXT: R_RISCV_ADD32 .L_ZTIi.DW.stub 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 .L0 0x0 ; RELOCS-NEXT: } diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll index 37f8522c5a0e..874e1b30bea5 100644 --- a/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll @@ -111,7 +111,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) -; CHECK-NEXT: .chericap .L_Z8do_catchv$local+(.Ltmp2-.Lfunc_begin0) # jumps to .Ltmp2 +; CHECK-NEXT: .chericap %code(.L_Z8do_catchv$local+(.Ltmp2-.Lfunc_begin0)) # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -138,7 +138,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-LABEL: Relocations [ ; RELOCS-LABEL: Section ({{.+}}) .rela.gcc_except_table { -; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$local 0x24 +; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY_CODE .L_Z8do_catchv$local 0x24 ; RELOCS-NEXT: R_RISCV_ADD32 .L_ZTIi.DW.stub 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 .L0 0x0 ; RELOCS-NEXT: } diff --git a/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll b/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll index 1d1a20145f18..34e3cbf51826 100644 --- a/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll +++ b/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll @@ -64,11 +64,11 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; CHECK: .section .gcc_except_table ; CHECK: .word 12 # (landing pad is a capability) -; CHECK-NEXT: .chericap .L_Z4testv$local+(.Ltmp2-.Lfunc_begin0) # jumps to .Ltmp2 +; CHECK-NEXT: .chericap %code(.L_Z4testv$local+(.Ltmp2-.Lfunc_begin0)) # jumps to .Ltmp2 ; OBJ-LABEL: Relocation section '.rela.gcc_except_table' at offset ; OBJ: Offset Info Type Symbol's Value Symbol's Name + Addend -; OBJ: 0000000000000020 0000000{{.}}000000c1 R_RISCV_CHERI_CAPABILITY +; OBJ: 0000000000000020 0000000{{.}}000000c3 R_RISCV_CHERI_CAPABILITY_CODE ; OBJ-LABEL: Symbol table '.symtab' contains ; OBJ: Value Size Type Bind Vis Ndx Name From 151d7790330a558b06e7d9572023509a5c9994c7 Mon Sep 17 00:00:00 2001 From: Dapeng Gao Date: Wed, 27 Aug 2025 17:48:07 +0100 Subject: [PATCH 7/7] [ELF][RISCV] Handle R_RISCV_FUNC_RELATIVE in getImplicitAddend Otherwise linking with --apply-dynamic-relocs (as is done by U-Boot, or due to -z rel which we don't support) when --check-dynamic-relocs is enabled (which is the default in assertions builds) will give an internal linker error when such a relocation is emitted. Fixes: 2d52aa89a7be ("[ELF][RISCV] Support R_RISCV_CHERI_CAPABILITY_CODE and R_RISCV_FUNC_RELATIVE") --- lld/ELF/Arch/RISCV.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 7b1686825fdf..e1b38ce6de79 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -225,6 +225,7 @@ int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const { return read64le(buf); case R_RISCV_RELATIVE: case R_RISCV_IRELATIVE: + case R_RISCV_FUNC_RELATIVE: return ctx.arg.is64 ? read64le(buf) : read32le(buf); case R_RISCV_NONE: case R_RISCV_JUMP_SLOT: