From 34bd8611868e269365a09ff3bea7a8ff078082fc Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 21:56:28 -0600 Subject: [PATCH 1/6] [CHERI] Rename target-specific RelExpr entries to match upstream naming convention. --- lld/ELF/Arch/Cheri.cpp | 8 +++---- lld/ELF/Arch/Mips.cpp | 16 +++++++------- lld/ELF/Arch/RISCV.cpp | 9 ++++---- lld/ELF/InputSection.cpp | 26 +++++++++++----------- lld/ELF/Relocations.cpp | 47 ++++++++++++++++++++-------------------- lld/ELF/Relocations.h | 24 ++++++++++---------- 6 files changed, 66 insertions(+), 64 deletions(-) diff --git a/lld/ELF/Arch/Cheri.cpp b/lld/ELF/Arch/Cheri.cpp index 63f8febd1dc2..c7a4bba84805 100644 --- a/lld/ELF/Arch/Cheri.cpp +++ b/lld/ELF/Arch/Cheri.cpp @@ -496,8 +496,8 @@ void MipsCheriCapTableSection::addEntry(Symbol &sym, RelExpr expr, idx.firstUse = SymbolAndOffset(isec, offset); assert(!idx.firstUse->symOrSec.isNull()); switch (expr) { - case R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE: - case R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: + case RE_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE: + case RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: idx.needsSmallImm = true; break; default: @@ -509,8 +509,8 @@ void MipsCheriCapTableSection::addEntry(Symbol &sym, RelExpr expr, // not used as a function pointer and therefore does not need a unique // address (plt stub) across all DSOs. switch (expr) { - case R_MIPS_CHERI_CAPTAB_INDEX_CALL: - case R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: + case RE_MIPS_CHERI_CAPTAB_INDEX_CALL: + case RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: if (!sym.isFunc() && !sym.isUndefWeak()) { CheriCapRelocLocation loc{isec, offset}; std::string msg = "call relocation against non-function symbol " + diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index c12f98e3c75f..d8a173a81edd 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -121,7 +121,7 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, case R_MICROMIPS_GPREL7_S2: return RE_MIPS_GOTREL; case R_MIPS_CHERI_CAPTABLEREL16: - return R_MIPS_CHERI_CAPTAB_REL; + return RE_MIPS_CHERI_CAPTAB_REL; case R_MIPS_26: case R_MICROMIPS_26_S1: return R_PLT; @@ -210,25 +210,25 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, return R_ABS_CAP; case R_MIPS_CHERI_CAPTAB_LO16: case R_MIPS_CHERI_CAPTAB_HI16: - return R_MIPS_CHERI_CAPTAB_INDEX; + return RE_MIPS_CHERI_CAPTAB_INDEX; case R_MIPS_CHERI_CAPCALL_LO16: case R_MIPS_CHERI_CAPCALL_HI16: - return R_MIPS_CHERI_CAPTAB_INDEX_CALL; + return RE_MIPS_CHERI_CAPTAB_INDEX_CALL; case R_MIPS_CHERI_CAPTAB_CLC11: case R_MIPS_CHERI_CAPTAB20: - return R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE; + return RE_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE; case R_MIPS_CHERI_CAPCALL_CLC11: case R_MIPS_CHERI_CAPCALL20: - return R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE; + return RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE; case R_MIPS_CHERI_CAPTAB_TLS_GD_LO16: case R_MIPS_CHERI_CAPTAB_TLS_GD_HI16: - return R_MIPS_CHERI_CAPTAB_TLSGD; + return RE_MIPS_CHERI_CAPTAB_TLSGD; case R_MIPS_CHERI_CAPTAB_TLS_LDM_LO16: case R_MIPS_CHERI_CAPTAB_TLS_LDM_HI16: - return R_MIPS_CHERI_CAPTAB_TLSLD; + return RE_MIPS_CHERI_CAPTAB_TLSLD; case R_MIPS_CHERI_CAPTAB_TLS_TPREL_LO16: case R_MIPS_CHERI_CAPTAB_TLS_TPREL_HI16: - return R_MIPS_CHERI_CAPTAB_TPREL; + return RE_MIPS_CHERI_CAPTAB_TPREL; default: Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v << ") against symbol " << &s; diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index c329965f56a4..0504ec7e191a 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -397,13 +397,14 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, 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; + return isPCCRelative(ctx, loc, &s) ? R_PC + : RE_CHERIOT_COMPARTMENT_CGPREL_HI; case R_RISCV_CHERIOT_COMPARTMENT_LO_I: - return R_CHERIOT_COMPARTMENT_CGPREL_LO_I; + return RE_CHERIOT_COMPARTMENT_CGPREL_LO_I; case R_RISCV_CHERIOT_COMPARTMENT_LO_S: - return R_CHERIOT_COMPARTMENT_CGPREL_LO_S; + return RE_CHERIOT_COMPARTMENT_CGPREL_LO_S; case R_RISCV_CHERIOT_COMPARTMENT_SIZE: - return R_CHERIOT_COMPARTMENT_SIZE; + return RE_CHERIOT_COMPARTMENT_SIZE; default: Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v << ") against symbol " << &s; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 56abc35abaa0..6b11c907c37e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1020,39 +1020,39 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, assert(r.sym->isUndefined() && "cannot encode non-null derived capability yet"); return 0; - case R_MIPS_CHERI_CAPTAB_INDEX: - case R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE: - case R_MIPS_CHERI_CAPTAB_INDEX_CALL: - case R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: + case RE_MIPS_CHERI_CAPTAB_INDEX: + case RE_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE: + case RE_MIPS_CHERI_CAPTAB_INDEX_CALL: + case RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE: assert(a == 0 && "capability table index relocs should not have addends"); return r.sym->getMipsCheriCapTableOffset(ctx, this, r.offset); - case R_MIPS_CHERI_CAPTAB_REL: + case RE_MIPS_CHERI_CAPTAB_REL: if (!ctx.sym.mipsCheriCapabilityTable) { error("cannot compute difference between non-existent " "CheriCapabilityTable and symbol " + toStr(ctx, *r.sym)); return r.sym->getVA(ctx, a); } return r.sym->getVA(ctx, a) - ctx.sym.mipsCheriCapabilityTable->getVA(ctx); - case R_MIPS_CHERI_CAPTAB_TLSGD: + case RE_MIPS_CHERI_CAPTAB_TLSGD: assert(a == 0 && "capability table index relocs should not have addends"); return ctx.in.mipsCheriCapTable->getDynTlsOffset(*r.sym); - case R_MIPS_CHERI_CAPTAB_TLSLD: + case RE_MIPS_CHERI_CAPTAB_TLSLD: assert(a == 0 && "capability table index relocs should not have addends"); return ctx.in.mipsCheriCapTable->getTlsIndexOffset(); - case R_MIPS_CHERI_CAPTAB_TPREL: + case RE_MIPS_CHERI_CAPTAB_TPREL: assert(a == 0 && "capability table index relocs should not have addends"); return ctx.in.mipsCheriCapTable->getTlsOffset(*r.sym); // LO_I is used for both PCC and CGP-relative addresses. For backwards // compatibility, the symbol may be a CGP-relative symbol. In newer code, it // will always be the symbol containing the accompanying HI relocation. - case R_CHERIOT_COMPARTMENT_CGPREL_LO_I: { + case RE_CHERIOT_COMPARTMENT_CGPREL_LO_I: { if (isPCCRelative(ctx, nullptr, r.sym)) { if (const Relocation *hiRel = getRISCVPCRelHi20(ctx, this, r)) { if (isPCCRelative(ctx, nullptr, hiRel->sym)) return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx)); return getBiasedCGPOffsetLo12(ctx, *hiRel->sym); } - fatal("R_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation points to " + + fatal("RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation points to " + r.sym->getName() + " without an associated R_RISCV_PCREL_HI20 relocation"); } @@ -1060,13 +1060,13 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, } // Reached only for CGP-relative relocations. PCC-relative addresses are // calculated with the R_PC and R_PC_INDIRECT cases. - case R_CHERIOT_COMPARTMENT_CGPREL_LO_S: + case RE_CHERIOT_COMPARTMENT_CGPREL_LO_S: return getBiasedCGPOffsetLo12(ctx, *r.sym); - case R_CHERIOT_COMPARTMENT_CGPREL_HI: + case RE_CHERIOT_COMPARTMENT_CGPREL_HI: return (getBiasedCGPOffset(ctx, *r.sym) - getBiasedCGPOffsetLo12(ctx, *r.sym)) >> 11; - case R_CHERIOT_COMPARTMENT_SIZE: + case RE_CHERIOT_COMPARTMENT_SIZE: return r.sym->getSize(ctx); default: llvm_unreachable("invalid expression"); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index ee9ce1af1743..f5ecd4145df7 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -215,10 +215,10 @@ bool lld::elf::needsGot(RelExpr expr) { // returns false for TLS variables even though then need a captable entry, // because TLS variables use the captable differently than regular variables. static bool needsMipsCheriCapTable(RelExpr expr) { - return oneof(expr); + return oneof(expr); } // True if this expression is of the form Sym - X, where X is a position in the @@ -227,7 +227,7 @@ static bool isRelExpr(RelExpr expr) { return oneof(expr); + RE_LOONGARCH_PAGE_PC, RE_MIPS_CHERI_CAPTAB_REL>(expr); } static RelExpr toPlt(RelExpr expr) { @@ -1060,21 +1060,22 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, uint64_t relOff) const { // These expressions always compute a constant - if (oneof< - R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE, - RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, RE_MIPS_GOT_GP_PC, - RE_AARCH64_GOT_PAGE_PC, RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, - R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, - R_GOTPLT_GOTREL, R_GOTPLT_PC, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT, - RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE, - RE_AARCH64_AUTH_GOT, RE_AARCH64_AUTH_GOT_PC, RE_LOONGARCH_PLT_PAGE_PC, - RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC, R_MIPS_CHERI_CAPTAB_INDEX, - R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE, - R_MIPS_CHERI_CAPTAB_INDEX_CALL, - R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE, - R_MIPS_CHERI_CAPTAB_REL, R_CHERIOT_COMPARTMENT_CGPREL_HI, - R_CHERIOT_COMPARTMENT_CGPREL_LO_I, R_CHERIOT_COMPARTMENT_CGPREL_LO_S, - R_CHERIOT_COMPARTMENT_SIZE>(e)) + if (oneof(e)) return true; // Cheri capability relocations are never static link time constants since @@ -1418,17 +1419,17 @@ static unsigned handleMipsTlsRelocation(Ctx &ctx, RelType type, Symbol &sym, c.addReloc(ctx, {expr, type, offset, addend, &sym}); return 1; } - if (expr == R_MIPS_CHERI_CAPTAB_TLSLD) { + if (expr == RE_MIPS_CHERI_CAPTAB_TLSLD) { ctx.in.mipsCheriCapTable->addTlsIndex(); c.addReloc(ctx, {expr, type, offset, addend, &sym}); return 1; } - if (expr == R_MIPS_CHERI_CAPTAB_TLSGD) { + if (expr == RE_MIPS_CHERI_CAPTAB_TLSGD) { ctx.in.mipsCheriCapTable->addDynTlsEntry(sym); c.addReloc(ctx, {expr, type, offset, addend, &sym}); return 1; } - if (expr == R_MIPS_CHERI_CAPTAB_TPREL) { + if (expr == RE_MIPS_CHERI_CAPTAB_TPREL) { ctx.in.mipsCheriCapTable->addTlsEntry(sym); c.addReloc(ctx, {expr, type, offset, addend, &sym}); return 1; diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index bd53846d354b..774496dabc40 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -125,18 +125,18 @@ enum RelExpr { RE_RISCV_ADD, RE_RISCV_LEB128, RE_RISCV_PC_INDIRECT, - R_MIPS_CHERI_CAPTAB_INDEX, - R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE, - R_MIPS_CHERI_CAPTAB_INDEX_CALL, - R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE, - R_MIPS_CHERI_CAPTAB_REL, // relative offset to _CHERI_CAPABILITY_TABLE_ - R_MIPS_CHERI_CAPTAB_TLSGD, - R_MIPS_CHERI_CAPTAB_TLSLD, - R_MIPS_CHERI_CAPTAB_TPREL, - R_CHERIOT_COMPARTMENT_CGPREL_HI, - R_CHERIOT_COMPARTMENT_CGPREL_LO_S, - R_CHERIOT_COMPARTMENT_CGPREL_LO_I, - R_CHERIOT_COMPARTMENT_SIZE, + RE_MIPS_CHERI_CAPTAB_INDEX, + RE_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE, + RE_MIPS_CHERI_CAPTAB_INDEX_CALL, + RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE, + RE_MIPS_CHERI_CAPTAB_REL, // relative offset to _CHERI_CAPABILITY_TABLE_ + RE_MIPS_CHERI_CAPTAB_TLSGD, + RE_MIPS_CHERI_CAPTAB_TLSLD, + RE_MIPS_CHERI_CAPTAB_TPREL, + RE_CHERIOT_COMPARTMENT_CGPREL_HI, + RE_CHERIOT_COMPARTMENT_CGPREL_LO_S, + RE_CHERIOT_COMPARTMENT_CGPREL_LO_I, + RE_CHERIOT_COMPARTMENT_SIZE, // Same as R_PC but with page-aligned semantics. RE_LOONGARCH_PAGE_PC, // Same as R_PLT_PC but with page-aligned semantics. From 460197824898f36fc820dc561d25b2e79d209e5a Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 22:25:09 -0600 Subject: [PATCH 2/6] [CHERIoT] Introduce INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I to simplify the control flow surrounding the relocation of AUIPCC sequences. --- lld/ELF/Arch/RISCV.cpp | 110 ++++++++++++++++++++++----------------- lld/ELF/InputSection.cpp | 7 ++- 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 0504ec7e191a..d6a8805294e4 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -62,6 +62,8 @@ class RISCV final : public TargetInfo { #define INTERNAL_R_RISCV_X0REL_I 258 #define INTERNAL_R_RISCV_X0REL_S 259 +#define INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I 270 + const uint64_t dtpOffset = 0x800; namespace { @@ -401,6 +403,8 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, : RE_CHERIOT_COMPARTMENT_CGPREL_HI; case R_RISCV_CHERIOT_COMPARTMENT_LO_I: return RE_CHERIOT_COMPARTMENT_CGPREL_LO_I; + case INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I: + return RE_RISCV_PC_INDIRECT; case R_RISCV_CHERIOT_COMPARTMENT_LO_S: return RE_CHERIOT_COMPARTMENT_CGPREL_LO_S; case R_RISCV_CHERIOT_COMPARTMENT_SIZE: @@ -504,8 +508,9 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { val); relocate(loc + 4, Relocation{R_NONE, - ctx.arg.isCheriot ? R_RISCV_CHERIOT_COMPARTMENT_LO_I - : R_RISCV_PCREL_LO12_I, + ctx.arg.isCheriot + ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I + : R_RISCV_PCREL_LO12_I, 0, 0, rel.sym}, val); } @@ -641,15 +646,18 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { write32le(loc + 4, val); break; case R_RISCV_CHERIOT_COMPARTMENT_LO_I: { - if (isPCCRelative(ctx, loc, rel.sym)) { - // Attach a negative sign bit to LO12 if the offset is negative. - // However, if HI20 alone is enough to reach the target, then this should - // not be done and LO14 should just be 0 regardless. - if (int64_t(val) >= 0 || (val & 0x7ff) == 0) - val &= 0x7ff; - else - val = (uint64_t(-1) & ~0x7ff) | (val & 0x7ff); - } + checkInt(ctx, loc, val, 12, rel); + write32le(loc, (read32le(loc) & 0x000fffff) | (val << 20)); + break; + } + case INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I: { + // Attach a negative sign bit to LO12 if the offset is negative. + // However, if HI20 alone is enough to reach the target, then this should + // not be done and LO14 should just be 0 regardless. + if (int64_t(val) >= 0 || (val & 0x7ff) == 0) + val &= 0x7ff; + else + val = (uint64_t(-1) & ~0x7ff) | (val & 0x7ff); checkInt(ctx, loc, val, 12, rel); write32le(loc, (read32le(loc) & 0x000fffff) | (val << 20)); break; @@ -1058,49 +1066,53 @@ static void relaxCGP(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, */ static bool rewriteCheriotLowRelocs(Ctx &ctx, InputSection &sec) { bool modified = false; - for (auto it : llvm::enumerate(sec.relocations)) { - Relocation &r = it.value(); + for (auto &r : sec.relocations) { if (r.type == R_RISCV_CHERIOT_COMPARTMENT_LO_I) { // If this is PCC-relative, then the relocation points to the auicgp / // auipcc instruction and we need to look there to find the real target. - if (isPCCRelative(ctx, nullptr, r.sym)) { - const Defined *d = cast(r.sym); - if (!d->section) - error("R_RISCV_CHERIOT_COMPARTMENT_LO_I relocation points to an " - "absolute symbol: " + - r.sym->getName()); - InputSection *isec = cast(d->section); - - // Relocations are sorted by offset, so we can use std::equal_range to - // do binary search. - Relocation targetReloc; - targetReloc.offset = d->value; - auto range = std::equal_range( - isec->relocations.begin(), isec->relocations.end(), targetReloc, - [](const Relocation &lhs, const Relocation &rhs) { - return lhs.offset < rhs.offset; - }); - - const Relocation *target = nullptr; - for (auto it = range.first; it != range.second; ++it) - if (it->type == R_RISCV_CHERIOT_COMPARTMENT_HI) { - target = &*it; - break; - } - if (!target) { - error( - "Could not find R_RISCV_CHERIOT_COMPARTMENT_HI relocation for " + - toStr(ctx, *r.sym)); + if (!isPCCRelative(ctx, nullptr, r.sym)) + fatal("R_RISCV_CHERIOT_COMPARTMENT_LO_I must point to " + "R_RISCV_COMPARTMENT_HI"); + + const Defined *d = cast(r.sym); + if (!d->section) + error("R_RISCV_CHERIOT_COMPARTMENT_LO_I relocation points to an " + "absolute symbol: " + + r.sym->getName()); + InputSection *isec = cast(d->section); + + // Relocations are sorted by offset, so we can use std::equal_range to + // do binary search. + Relocation targetReloc; + targetReloc.offset = d->value; + auto range = std::equal_range( + isec->relocations.begin(), isec->relocations.end(), targetReloc, + [](const Relocation &lhs, const Relocation &rhs) { + return lhs.offset < rhs.offset; + }); + + const Relocation *target = nullptr; + for (auto it = range.first; it != range.second; ++it) + if (it->type == R_RISCV_CHERIOT_COMPARTMENT_HI) { + target = &*it; + break; } - // If the target is PCC-relative then the auipcc can't be erased and so - // skip the rewriting. - if (isPCCRelative(ctx, nullptr, target->sym)) - continue; - // Update our relocation to point to the target thing. - r.sym = target->sym; - r.addend = target->addend; - modified = true; + if (!target) { + error("Could not find R_RISCV_CHERIOT_COMPARTMENT_HI relocation for " + + toStr(ctx, *r.sym)); + } + modified = true; + // If the target is PCC-relative then the auipcc can't be erased and so + // skip the rewriting. + if (isPCCRelative(ctx, nullptr, target->sym)) { + r.type = INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I; + r.expr = RE_RISCV_PC_INDIRECT; + continue; } + // Update our relocation to point to the target thing. + r.sym = target->sym; + r.addend = target->addend; + modified = true; } } return modified; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 6b11c907c37e..0b8ecff7e06e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -34,6 +34,10 @@ using namespace llvm::sys; using namespace lld; using namespace lld::elf; +#define INTERNAL_R_RISCV_COMPARTMENT_AUICGP_LO_I 272 +#define INTERNAL_R_RISCV_COMPARTMENT_CGPREL_LO_I 273 +#define INTERNAL_R_RISCV_COMPARTMENT_AUIPCC_LO_I 274 + // Returns a string to construct an error message. std::string elf::toStr(Ctx &ctx, const InputSectionBase *sec) { return (toStr(ctx, sec->file) + ":(" + sec->name + ")").str(); @@ -1049,7 +1053,8 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, if (isPCCRelative(ctx, nullptr, r.sym)) { if (const Relocation *hiRel = getRISCVPCRelHi20(ctx, this, r)) { if (isPCCRelative(ctx, nullptr, hiRel->sym)) - return getRelocTargetVA(ctx, *hiRel, r.sym->getVA(ctx)); + fatal("RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation used for " + "PCC-relative access!"); return getBiasedCGPOffsetLo12(ctx, *hiRel->sym); } fatal("RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation points to " + From 0b792dc59096752122f5690b5fb1789fec43c5b3 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 23:16:33 -0600 Subject: [PATCH 3/6] [CHERIoT] Remove legacy handling of R_RISCV_CHERIOT_COMPARTMENT_LO_I without paired reloc. This further simplifies control flow around CHERIoT relocation handling, and allows us to collapse the CGPREL_LO_I and CGPREL_LO_S RelExpr's together. --- lld/ELF/Arch/RISCV.cpp | 5 ++--- lld/ELF/InputSection.cpp | 21 +++------------------ lld/ELF/Relocations.cpp | 3 +-- lld/ELF/Relocations.h | 3 +-- 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index d6a8805294e4..fa0a938a6393 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -402,11 +402,10 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, return isPCCRelative(ctx, loc, &s) ? R_PC : RE_CHERIOT_COMPARTMENT_CGPREL_HI; case R_RISCV_CHERIOT_COMPARTMENT_LO_I: - return RE_CHERIOT_COMPARTMENT_CGPREL_LO_I; + case R_RISCV_CHERIOT_COMPARTMENT_LO_S: + return RE_CHERIOT_COMPARTMENT_CGPREL_LO; case INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I: return RE_RISCV_PC_INDIRECT; - case R_RISCV_CHERIOT_COMPARTMENT_LO_S: - return RE_CHERIOT_COMPARTMENT_CGPREL_LO_S; case R_RISCV_CHERIOT_COMPARTMENT_SIZE: return RE_CHERIOT_COMPARTMENT_SIZE; default: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 0b8ecff7e06e..f53f29f55295 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1046,26 +1046,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, case RE_MIPS_CHERI_CAPTAB_TPREL: assert(a == 0 && "capability table index relocs should not have addends"); return ctx.in.mipsCheriCapTable->getTlsOffset(*r.sym); - // LO_I is used for both PCC and CGP-relative addresses. For backwards - // compatibility, the symbol may be a CGP-relative symbol. In newer code, it - // will always be the symbol containing the accompanying HI relocation. - case RE_CHERIOT_COMPARTMENT_CGPREL_LO_I: { - if (isPCCRelative(ctx, nullptr, r.sym)) { - if (const Relocation *hiRel = getRISCVPCRelHi20(ctx, this, r)) { - if (isPCCRelative(ctx, nullptr, hiRel->sym)) - fatal("RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation used for " - "PCC-relative access!"); - return getBiasedCGPOffsetLo12(ctx, *hiRel->sym); - } - fatal("RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation points to " + - r.sym->getName() + - " without an associated R_RISCV_PCREL_HI20 relocation"); - } - return getBiasedCGPOffsetLo12(ctx, *r.sym); - } // Reached only for CGP-relative relocations. PCC-relative addresses are // calculated with the R_PC and R_PC_INDIRECT cases. - case RE_CHERIOT_COMPARTMENT_CGPREL_LO_S: + case RE_CHERIOT_COMPARTMENT_CGPREL_LO: + if (isPCCRelative(ctx, nullptr, r.sym)) + fatal("Malformed RE_CHERIOT_COMPARTMENT_CGPREL_LO_I relocation!"); return getBiasedCGPOffsetLo12(ctx, *r.sym); case RE_CHERIOT_COMPARTMENT_CGPREL_HI: return (getBiasedCGPOffset(ctx, *r.sym) - diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index f5ecd4145df7..c2c53c5c5f1c 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1074,8 +1074,7 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type, RE_MIPS_CHERI_CAPTAB_INDEX_CALL, RE_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE, RE_MIPS_CHERI_CAPTAB_REL, RE_CHERIOT_COMPARTMENT_CGPREL_HI, - RE_CHERIOT_COMPARTMENT_CGPREL_LO_I, - RE_CHERIOT_COMPARTMENT_CGPREL_LO_S, RE_CHERIOT_COMPARTMENT_SIZE>(e)) + RE_CHERIOT_COMPARTMENT_CGPREL_LO, RE_CHERIOT_COMPARTMENT_SIZE>(e)) return true; // Cheri capability relocations are never static link time constants since diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 774496dabc40..21f13b1de9a2 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -134,8 +134,7 @@ enum RelExpr { RE_MIPS_CHERI_CAPTAB_TLSLD, RE_MIPS_CHERI_CAPTAB_TPREL, RE_CHERIOT_COMPARTMENT_CGPREL_HI, - RE_CHERIOT_COMPARTMENT_CGPREL_LO_S, - RE_CHERIOT_COMPARTMENT_CGPREL_LO_I, + RE_CHERIOT_COMPARTMENT_CGPREL_LO, RE_CHERIOT_COMPARTMENT_SIZE, // Same as R_PC but with page-aligned semantics. RE_LOONGARCH_PAGE_PC, From 5c0b2b0d7c5d71d32793734f7d3b20615b4c8308 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 23:28:30 -0600 Subject: [PATCH 4/6] [CHERIoT] Introduce INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI to simplify handling of PCC-relative R_RISCV_CHERIOT_COMPARTMENT_HI relocs. --- lld/ELF/Arch/RISCV.cpp | 45 +++++++++++++++++++++++++++++----------- lld/ELF/InputSection.cpp | 5 ++--- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index fa0a938a6393..7fdc30725392 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -63,6 +63,7 @@ class RISCV final : public TargetInfo { #define INTERNAL_R_RISCV_X0REL_S 259 #define INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I 270 +#define INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI 271 const uint64_t dtpOffset = 0x800; @@ -398,9 +399,10 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, return R_GOT_PC; case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20: return R_TLSGD_PC; + case INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI: + return R_PC; case R_RISCV_CHERIOT_COMPARTMENT_HI: - return isPCCRelative(ctx, loc, &s) ? R_PC - : RE_CHERIOT_COMPARTMENT_CGPREL_HI; + return RE_CHERIOT_COMPARTMENT_CGPREL_HI; case R_RISCV_CHERIOT_COMPARTMENT_LO_I: case R_RISCV_CHERIOT_COMPARTMENT_LO_S: return RE_CHERIOT_COMPARTMENT_CGPREL_LO; @@ -501,8 +503,9 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { if (isInt<20>(hi)) { relocate(loc, Relocation{R_NONE, - ctx.arg.isCheriot ? R_RISCV_CHERIOT_COMPARTMENT_HI - : R_RISCV_PCREL_HI20, + ctx.arg.isCheriot + ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI + : R_RISCV_PCREL_HI20, 0, 0, rel.sym}, val); relocate(loc + 4, @@ -677,12 +680,24 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { case R_RISCV_CHERIOT_COMPARTMENT_HI: { // AUICGP uint32_t opcode = AUICGP; - if (isPCCRelative(ctx, loc, rel.sym)) { - opcode = AUIPCC; - if (int64_t(val) < 0) - val = (val + 0x7ff) & ~0x7ff; - val = int64_t(val) >> 11; - } + uint32_t existingOpcode = read32le(loc) & 0x7f; + if ((existingOpcode != AUIPCC) && (existingOpcode != AUICGP)) + warn("R_RISCV_CHERIOT_COMPARTMENT_HI relocation applied to instruction " + "with unexpected opcode " + + Twine(existingOpcode)); + checkInt(ctx, loc, SignExtend64(val + 0x800, bits) >> 12, 20, rel); + // Preserve the target register. We will rewrite the opcode (source + // register) to either AUICGP or AUIPCC and set the immediate field. + uint32_t insn = read32le(loc) & 0x00000f80; + write32le(loc, insn | (val << 12) | opcode); + break; + } + case INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI: { + // AUIPCC + uint32_t opcode = AUIPCC; + if (int64_t(val) < 0) + val = (val + 0x7ff) & ~0x7ff; + val = int64_t(val) >> 11; uint32_t existingOpcode = read32le(loc) & 0x7f; if ((existingOpcode != AUIPCC) && (existingOpcode != AUICGP)) warn("R_RISCV_CHERIOT_COMPARTMENT_HI relocation applied to instruction " @@ -1066,7 +1081,12 @@ static void relaxCGP(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, static bool rewriteCheriotLowRelocs(Ctx &ctx, InputSection &sec) { bool modified = false; for (auto &r : sec.relocations) { - if (r.type == R_RISCV_CHERIOT_COMPARTMENT_LO_I) { + if (r.type == R_RISCV_CHERIOT_COMPARTMENT_HI && + isPCCRelative(ctx, nullptr, r.sym)) { + modified = true; + r.type = INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI; + r.expr = R_PC; + } else if (r.type == R_RISCV_CHERIOT_COMPARTMENT_LO_I) { // If this is PCC-relative, then the relocation points to the auicgp / // auipcc instruction and we need to look there to find the real target. if (!isPCCRelative(ctx, nullptr, r.sym)) @@ -1092,7 +1112,8 @@ static bool rewriteCheriotLowRelocs(Ctx &ctx, InputSection &sec) { const Relocation *target = nullptr; for (auto it = range.first; it != range.second; ++it) - if (it->type == R_RISCV_CHERIOT_COMPARTMENT_HI) { + if (it->type == R_RISCV_CHERIOT_COMPARTMENT_HI || + it->type == INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI) { target = &*it; break; } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index f53f29f55295..a62b25589c52 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -34,9 +34,7 @@ using namespace llvm::sys; using namespace lld; using namespace lld::elf; -#define INTERNAL_R_RISCV_COMPARTMENT_AUICGP_LO_I 272 -#define INTERNAL_R_RISCV_COMPARTMENT_CGPREL_LO_I 273 -#define INTERNAL_R_RISCV_COMPARTMENT_AUIPCC_LO_I 274 +#define INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI 271 // Returns a string to construct an error message. std::string elf::toStr(Ctx &ctx, const InputSectionBase *sec) { @@ -712,6 +710,7 @@ static Relocation *getRISCVPCRelHi20(Ctx &ctx, const InputSectionBase *loSec, if (it->type == R_RISCV_PCREL_HI20 || it->type == R_RISCV_GOT_HI20 || it->type == R_RISCV_TLS_GD_HI20 || it->type == R_RISCV_TLS_GOT_HI20 || it->type == R_RISCV_CHERIOT_COMPARTMENT_HI || + it->type == INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI || it->type == R_RISCV_CHERI_CAPTAB_PCREL_HI20 || it->type == R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20 || it->type == R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20) From 7b96464e9c6307e23ae7a0082e66c4793ddcf9e0 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 23:31:55 -0600 Subject: [PATCH 5/6] [CHERIoT] Restore upstream use of relocateNoSym for call reloc resolution. This is possible now that isPCCRelative is no longer called in relocate(). --- lld/ELF/Arch/RISCV.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 7fdc30725392..b8d0f4c93466 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -501,20 +501,16 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { int64_t hi = SignExtend64(val + 0x800, bits) >> 12; checkInt(ctx, loc, hi, 20, rel); if (isInt<20>(hi)) { - relocate(loc, - Relocation{R_NONE, - ctx.arg.isCheriot - ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI - : R_RISCV_PCREL_HI20, - 0, 0, rel.sym}, - val); - relocate(loc + 4, - Relocation{R_NONE, - ctx.arg.isCheriot - ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I - : R_RISCV_PCREL_LO12_I, - 0, 0, rel.sym}, - val); + relocateNoSym(loc, + ctx.arg.isCheriot + ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI + : R_RISCV_PCREL_HI20, + val); + relocateNoSym(loc + 4, + ctx.arg.isCheriot + ? INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I + : R_RISCV_PCREL_LO12_I, + val); } return; } From 28aef8022ae60581683f2e2a0568bbff54c0a60c Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 21 Nov 2025 23:44:52 -0600 Subject: [PATCH 6/6] [CHERIoT] Update comments regarding the CHERIoT relocation pre-pass. --- lld/ELF/Arch/RISCV.cpp | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index b8d0f4c93466..01c49f9ad4a0 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -1056,23 +1056,29 @@ static void relaxCGP(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc, } /** - * Find all R_RISCV_CHERIOT_COMPARTMENT_LO_I relocations that are CGP-relative - * and rewrite them to be relative to the target of the current relocation. - * These relocations mirror the HI20/LO12 PC-relative relocations and are - * written as pairs where the first has the real relocation target as its - * symbol and the second has the location of the first as its target. This is - * necessary for PC-relative relocations because the final address depends on - * the location of the first instruction. For CHERIoT, both PCC and - * CGP-relative relocations use the same relocation types and we don't know - * whether it is relative to PCC or CGP until we know the target. That would - * be fine, except that relaxation can delete the AUICGP, which means that we - * then can't find the target. We void this by doing a pass to find these - * relocation targets and attaching them to the - * R_RISCV_CHERIOT_COMPARTMENT_LO_I relocations for the cases where the target - * is CGP-relative. + * Perform a substantial pre-pass of Cheriot relocations ahead of relaxation + * and relocation. This pre-pass has two goals: + * - Separate PCC-relative and CGP-relative relocations. This reduces + * complexity in relaxation and relocation by making the decision once + * upfront. + * - Resolve the target address for the second in a pair of relocations. This + * is required because relaxation may eliminate the first in a pair of + * relocations, which would leave the second one unable to be relocated. * - * Note: If we ever get direct PC[C]-relative loads in RISC-V then other - * relocations will want to reuse this path. + * The specific post-conditions are: + * - All PCC-relative CHERIOT_COMPARTMENT_HI relocations are represented as + * INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_HI. + * - All CGP-relative CHERIOT_COMPARTMENT_HI relocations are represented as + * R_RISCV_CHERIOT_COMPARTMENT_HI. + * - All PCC-relative CHERIOT_COMPARTMENT_LO_I relocations are represented as + * INTERNAL_R_RISCV_CHERIOT_COMPARTMENT_PCCREL_LO_I. + * - All CGP-relative CHERIOT_COMPARTMENT_LO_I relocations are represented as + * R_RISCV_CHERIOT_COMPARTMENT_LO_I. + * - The targets of all CHERIOT_COMPARTMENT_LO_I relocations are resolved to + * the target of their paired CHERIOT_COMPARTMENT_HI relocation. + * - PCC-relative CHERIOT_COMPARTMENT_LO_S relocations do not exist. + * - All CGP-relative CHERIOT_COMPARTMENT_LO_S relocations are represented as + * R_RISCV_CHERIOT_COMPARTMENT_LO_S. */ static bool rewriteCheriotLowRelocs(Ctx &ctx, InputSection &sec) { bool modified = false; @@ -1144,6 +1150,8 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) { bool tlsdescRelax = false, toLeShortForm = false; // On the first pass, do a scan of LO_I CHERIoT relocations + // FIXME: One the relocation scan loop is under target control, this should be + // applied outside of relaxation. if (pass == 0) changed |= rewriteCheriotLowRelocs(ctx, sec);