Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 61 additions & 35 deletions lld/ELF/Arch/Cheri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
auto sourceMsg = [&]() -> std::string {
return sourceSymbol ? verboseToString(ctx, sourceSymbol) : loc.toString(ctx);
};
if (target.sym()->isUndefined() && !target.sym()->isUndefWeak()) {
if (isa<Symbol *>(target.symOrSec) && target.sym()->isUndefined() &&
!target.sym()->isUndefWeak()) {
auto diag = (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError)
? Err(ctx)
: (errorHandler().fatalWarnings) ? Msg(ctx)
Expand Down Expand Up @@ -362,6 +363,7 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
return; // Maybe happens with vtables?
}
if (targetNeedsDynReloc) {
assert(isa<Symbol *>(target.symOrSec));
bool relativeToLoadAddress = false;
// The addend is not used as the offset into the capability here, as we
// have the offset field in the __cap_relocs for that. The Addend
Expand Down Expand Up @@ -398,6 +400,9 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
template <typename ELFT>
static uint64_t getTargetSize(Ctx &ctx, const CheriCapRelocLocation &location,
const SymbolAndOffset &target) {
if (InputSectionBase *isec = dyn_cast<InputSectionBase *>(target.symOrSec))
return isec->getSize();

uint64_t targetSize = target.sym()->getSize(ctx);
if (targetSize > INT_MAX) {
error("Insanely large symbol size for " + target.verboseToString(ctx) +
Expand Down Expand Up @@ -523,9 +528,24 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
location.section->getOutputSection()->addr + outSecOffset;

// The target VA is the base address of the capability, so symbol + 0
uint64_t targetVA = realTarget.sym()->getVA(ctx, 0);
bool preemptibleDynReloc =
reloc.needsDynReloc && realTarget.sym()->isPreemptible;
uint64_t targetVA;
bool isPreemptible, isFunc, isTls;
OutputSection *os;
if (Symbol *s = dyn_cast<Symbol *>(realTarget.symOrSec)) {
targetVA = realTarget.sym()->getVA(ctx, 0);
isPreemptible = reloc.needsDynReloc && realTarget.sym()->isPreemptible;
isFunc = s->isFunc();
isTls = s->isTls();
os = s->getOutputSection();
} else {
InputSectionBase *isec = cast<InputSectionBase *>(realTarget.symOrSec);
targetVA = isec->getVA(0);
isPreemptible = false;
isFunc = (isec->flags & SHF_EXECINSTR) != 0;
isTls = isec->type == STT_TLS;
os = isec->getOutputSection();
}
bool preemptibleDynReloc = reloc.needsDynReloc && isPreemptible;
uint64_t targetSize = 0;
if (preemptibleDynReloc) {
// If we have a relocation against a preemptible symbol (even in the
Expand All @@ -543,10 +563,10 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
uint64_t targetOffset = reloc.capabilityOffset + realTarget.offset;
uint64_t permissions = 0;
// Fow now Function implies ReadOnly so don't add the flag
if (realTarget.sym()->isFunc()) {
if (isFunc) {
permissions |= CaptablePermissions<ELFT>::function;
} else if (auto os = realTarget.sym()->getOutputSection()) {
assert(!realTarget.sym()->isTls());
} else if (os) {
assert(!isTls);
// if ((OS->getPhdrFlags() & PF_W) == 0) {
if (((os->flags & SHF_WRITE) == 0) || isRelroSection(ctx, os)) {
permissions |= CaptablePermissions<ELFT>::readOnly;
Expand Down Expand Up @@ -1080,15 +1100,16 @@ static bool isSymIncludedInDynsym(Ctx &ctx, const Symbol &sym) {
(ctx.arg.exportDynamic && (sym.isUsedInRegularObj || !sym.ltoCanOmit));
}


template <typename ELFT>
void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
InputSectionBase *sec, uint64_t offset,
RelExpr expr, int64_t addend, bool isCallExpr,
llvm::function_ref<std::string()> referencedBy,
RelocationBaseSection *dynRelSec) {
void addCapabilityRelocation(
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *> symOrSec,
RelType type, InputSectionBase *sec, uint64_t offset, RelExpr expr,
int64_t addend, bool isCallExpr,
llvm::function_ref<std::string()> referencedBy,
RelocationBaseSection *dynRelSec) {
Symbol *sym = dyn_cast<Symbol *>(symOrSec);
assert(expr == R_CHERI_CAPABILITY);
if (sec->name == ".gcc_except_table" && sym->isPreemptible) {
if (sec->name == ".gcc_except_table" && sym && sym->isPreemptible) {
// We previously had an ugly workaround here to create a hidden alias for
// relocations in the exception table, but this has since been fixed in
// the compiler. Add an explicit error here in case someone tries to
Expand All @@ -1102,14 +1123,15 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
// Emit either the legacy __cap_relocs section or a R_CHERI_CAPABILITY reloc
// For local symbols we can also emit the untagged capability bits and
// instruct csu/rtld to run CBuildCap
CapRelocsMode capRelocMode = sym->isPreemptible
CapRelocsMode capRelocMode = sym && sym->isPreemptible
? ctx.arg.preemptibleCapRelocsMode
: ctx.arg.localCapRelocsMode;
bool needTrampoline = false;
// In the PLT ABI (and fndesc?) we have to use an elf relocation for function
// pointers to ensure that the runtime linker adds the required trampolines
// that sets $cgp:
if (!isCallExpr && ctx.arg.emachine == llvm::ELF::EM_MIPS && sym->isFunc()) {
if (!isCallExpr && ctx.arg.emachine == llvm::ELF::EM_MIPS && sym &&
sym->isFunc()) {
if (!lld::elf::hasDynamicLinker(ctx)) {
// In static binaries we do not need PLT stubs for function pointers since
// all functions share the same $cgp
Expand All @@ -1118,26 +1140,26 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
if (ctx.arg.verboseCapRelocs)
Msg(ctx) << "Do not need function pointer trampoline for "
<< toStr(ctx, *sym) << " in static binary";
needTrampoline = false;
} else if (ctx.in.mipsAbiFlags) {
auto abi = static_cast<MipsAbiFlagsSection<ELFT> &>(*ctx.in.mipsAbiFlags)
.getCheriAbiVariant();
if (abi && (*abi == llvm::ELF::DF_MIPS_CHERI_ABI_PLT ||
*abi == llvm::ELF::DF_MIPS_CHERI_ABI_FNDESC))
needTrampoline = true;
}
}

if (needTrampoline) {
capRelocMode = CapRelocsMode::ElfReloc;
assert(capRelocMode == ctx.arg.preemptibleCapRelocsMode);
if (ctx.arg.verboseCapRelocs)
message("Using trampoline for function pointer against " +
verboseToString(ctx, sym));
if (needTrampoline) {
capRelocMode = CapRelocsMode::ElfReloc;
assert(capRelocMode == ctx.arg.preemptibleCapRelocsMode);
if (ctx.arg.verboseCapRelocs)
message("Using trampoline for function pointer against " +
verboseToString(ctx, sym));
}
}

// local cap relocs don't need a Elf relocation with a full symbol lookup:
if (capRelocMode == CapRelocsMode::ElfReloc) {
assert(sym && "ELF relocs should not be used against sections");
assert((sym->isPreemptible || needTrampoline) &&
"ELF relocs should not be used for non-preemptible symbols");
assert((!sym->isLocal() || needTrampoline) &&
Expand Down Expand Up @@ -1195,10 +1217,10 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,

} else if (capRelocMode == CapRelocsMode::Legacy) {
if (ctx.arg.relativeCapRelocsOnly) {
assert(!sym->isPreemptible);
assert(!sym || !sym->isPreemptible);
}
ctx.in.capRelocs->addCapReloc<ELFT>({sec, offset}, {sym, 0u},
sym->isPreemptible, addend);
ctx.in.capRelocs->addCapReloc<ELFT>({sec, offset}, {symOrSec, 0u},
sym && sym->isPreemptible, addend);
} else {
assert(ctx.arg.localCapRelocsMode == CapRelocsMode::CBuildCap);
error("CBuildCap method not implemented yet!");
Expand All @@ -1209,14 +1231,18 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
} // namespace lld

template void lld::elf::addCapabilityRelocation<ELF32LE>(
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
llvm::function_ref<std::string()>, RelocationBaseSection *);
template void lld::elf::addCapabilityRelocation<ELF32BE>(
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
llvm::function_ref<std::string()>, RelocationBaseSection *);
template void lld::elf::addCapabilityRelocation<ELF64LE>(
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
llvm::function_ref<std::string()>, RelocationBaseSection *);
template void lld::elf::addCapabilityRelocation<ELF64BE>(
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
llvm::function_ref<std::string()>, RelocationBaseSection *);
17 changes: 8 additions & 9 deletions lld/ELF/Arch/Cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ namespace elf {

struct SymbolAndOffset {
public:
SymbolAndOffset(Symbol *s, int64_t o) : symOrSec(s), offset(o) {
SymbolAndOffset(llvm::PointerUnion<Symbol *, InputSectionBase *> s, int64_t o)
: symOrSec(s), offset(o) {
assert(s && "Should not be null");
}
SymbolAndOffset(InputSectionBase *isec, int64_t o) : symOrSec(isec), offset(o) {
assert(isec && "Should not be null");
}
SymbolAndOffset(const SymbolAndOffset &) = default;
SymbolAndOffset &operator=(const SymbolAndOffset &) = default;

Expand Down Expand Up @@ -364,11 +362,12 @@ inline uint64_t getBiasedCGPOffsetLo12(Ctx &ctx, const Symbol &sym)
}

template <typename ELFT>
void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
InputSectionBase *sec, uint64_t offset,
RelExpr expr, int64_t addend, bool isCallExpr,
llvm::function_ref<std::string()> referencedBy,
RelocationBaseSection *dynRelSec = nullptr);
void addCapabilityRelocation(
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *> target,
RelType type, InputSectionBase *sec, uint64_t offset, RelExpr expr,
int64_t addend, bool isCallExpr,
llvm::function_ref<std::string()> referencedBy,
RelocationBaseSection *dynRelSec = nullptr);
} // namespace elf
} // namespace lld

Expand Down
53 changes: 17 additions & 36 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ enum Op {
CIncOffsetImm = 0x105b,
CLC_64 = 0x3003,
CLC_128 = 0x200f,
CSub = 0x2800005b,

AUIPCC = 0x17,
AUICGP = 0x7b,
Expand Down Expand Up @@ -128,10 +127,7 @@ RISCV::RISCV(Ctx &ctx) : TargetInfo(ctx) {
pltRel = R_RISCV_JUMP_SLOT;
relativeRel = R_RISCV_RELATIVE;
iRelativeRel = R_RISCV_IRELATIVE;
sizeRel = R_RISCV_CHERI_SIZE;
cheriCapRel = R_RISCV_CHERI_CAPABILITY;
// TODO: R_RISCV_CHERI_JUMP_SLOT in a separate .got.plt / .captable.plt
cheriCapCallRel = R_RISCV_CHERI_CAPABILITY;
if (ctx.arg.is64) {
symbolicRel = R_RISCV_64;
tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
Expand Down Expand Up @@ -275,12 +271,12 @@ void RISCV::writePltHeader(uint8_t *buf) const {
// (c)sub t1, (c)t1, (c)t3
// l[wdc] (c)t3, %pcrel_lo(1b)((c)t2); (c)t3 = _dl_runtime_resolve
// addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0]
// addi t0, t2, %pcrel_lo(1b)
// srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0]
// l[wd] t0, Wordsize(t0); t0 = link_map
// jr t3
// addi/cincoffset (c)t0, (c)t2, %pcrel_lo(1b)
// (if shift != 0): srli t1, t1, shift; t1 = &.got.plt[i] - &.got.plt[0]
// l[wdc] (c)t0, Ptrsize((c)t0); (c)t0 = link_map
// (c)jr (c)t3
// (if shift == 0): nop
uint32_t offset = ctx.in.gotPlt->getVA() - ctx.in.plt->getVA();
uint32_t ptrsub = ctx.arg.isCheriAbi ? CSub : SUB;
uint32_t ptrload = ctx.arg.isCheriAbi ? ctx.arg.is64 ? CLC_128 : CLC_64
: ctx.arg.is64 ? LD
: LW;
Expand All @@ -290,7 +286,7 @@ void RISCV::writePltHeader(uint8_t *buf) const {
uint32_t ptrsize =
ctx.arg.isCheriAbi ? ctx.arg.capabilitySize : ctx.arg.wordsize;
write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset)));
write32le(buf + 4, rtype(ptrsub, X_T1, X_T1, X_T3));
write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3));
write32le(buf + 8, itype(ptrload, X_T3, X_T2, lo12(offset)));
write32le(buf + 12, itype(ADDI, X_T1, X_T1, -ctx.target->pltHeaderSize - 12));
write32le(buf + 16, itype(ptraddi, X_T0, X_T2, lo12(offset)));
Expand Down Expand Up @@ -497,30 +493,19 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
// auipc[c] + [c]jalr pair
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
case R_RISCV_CHERI_CCALL: {
int64_t hi = SignExtend64(val + 0x800, bits) >> 12;
checkInt(ctx, loc, hi, 20, rel);
if (isInt<20>(hi)) {
relocateNoSym(loc, R_RISCV_PCREL_HI20, val);
relocateNoSym(loc + 4, R_RISCV_PCREL_LO12_I, val);
}
return;
}

case R_RISCV_CHERI_CCALL:
case R_RISCV_CHERIOT_CCALL: {
// Cheriot uses an 11-bit shift on AUIPCC, requiring different relocation
// compared to R_RISCV_CHERI_CCALL.
int64_t hi = SignExtend64(val + 0x800, bits) >> 12;
checkInt(ctx, loc, hi, 20, rel);
if (isInt<20>(hi)) {
relocate(loc,
Relocation{rel.expr, R_RISCV_CHERIOT_COMPARTMENT_HI, rel.offset,
rel.addend, rel.sym},
val);
relocate(loc + 4,
Relocation{rel.expr, R_RISCV_CHERIOT_COMPARTMENT_LO_I,
rel.offset, rel.addend, rel.sym},
val);
relocateNoSym(loc,
ctx.arg.isCheriot ? R_RISCV_CHERIOT_COMPARTMENT_HI
: R_RISCV_PCREL_HI20,
val);
relocateNoSym(loc + 4,
ctx.arg.isCheriot ? R_RISCV_CHERIOT_COMPARTMENT_LO_I
: R_RISCV_PCREL_LO12_I,
val);
}
return;
}
Expand Down Expand Up @@ -909,10 +894,6 @@ void elf::initSymbolAnchors(Ctx &ctx) {
// Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal.
static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc,
Relocation &r, uint32_t &remove) {
bool isCCall =
(r.type == R_RISCV_CHERI_CCALL) || (r.type == R_RISCV_CHERIOT_CCALL);
auto jalRVCType = (isCCall) ? R_RISCV_CHERI_RVC_CJUMP : R_RISCV_RVC_JUMP;
auto jalType = (isCCall) ? R_RISCV_CHERI_CJAL : R_RISCV_JAL;
const bool rvc = getEFlags(ctx, sec.file) & EF_RISCV_RVC;
const Symbol &sym = *r.sym;
const uint64_t insnPair = read64le(sec.content().data() + r.offset);
Expand All @@ -924,7 +905,7 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc,
// When the caller specifies the old value of `remove`, disallow its
// increment.
if (remove >= 6 && rvc && isInt<12>(displace) && rd == 0) {
sec.relaxAux->relocTypes[i] = jalRVCType;
sec.relaxAux->relocTypes[i] = R_RISCV_RVC_JUMP;
sec.relaxAux->writes.push_back(0xa001); // c.[c]j
remove = 6;
} else if (remove >= 6 && rvc && isInt<12>(displace) && rd == X_RA &&
Expand All @@ -933,7 +914,7 @@ static void relaxCall(Ctx &ctx, const InputSection &sec, size_t i, uint64_t loc,
sec.relaxAux->writes.push_back(0x2001); // c.jal
remove = 6;
} else if (remove >= 4 && isInt<21>(displace)) {
sec.relaxAux->relocTypes[i] = jalType;
sec.relaxAux->relocTypes[i] = R_RISCV_JAL;
sec.relaxAux->writes.push_back(0x6f | rd << 7); // [c]jal
remove = 4;
} else {
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/cheri/riscv/tls.s
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ _start:

.if PIC == 0
lui a0, %tprel_hi(lvar)
cincoffset a0, tp, a0, %tprel_cincoffset(lvar)
cincoffset a0, tp, a0, %tprel_add(lvar)
cincoffset a0, a0, %tprel_lo(lvar)
.endif

Expand Down
18 changes: 9 additions & 9 deletions llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -129,14 +129,14 @@ ELF_RELOC(R_RISCV_CUSTOM255, 255)
// CHERI relocations
ELF_RELOC(R_RISCV_CHERI_CAPTAB_PCREL_HI20, 192)
ELF_RELOC(R_RISCV_CHERI_CAPABILITY, 193)
// 194 reserved for R_RISCV_CHERI_CAPABILITY_CALL
ELF_RELOC(R_RISCV_CHERI_SIZE, 195)
ELF_RELOC(R_RISCV_CHERI_TPREL_CINCOFFSET, 196)
ELF_RELOC(R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20, 197)
ELF_RELOC(R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20, 198)
ELF_RELOC(R_RISCV_CHERI_CJAL, 199)
ELF_RELOC(R_RISCV_CHERI_CCALL, 200)
ELF_RELOC(R_RISCV_CHERI_RVC_CJUMP, 201)
// 194 reserved
// 195 reserved
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
ELF_RELOC(R_RISCV_CHERI_CJAL, 199) // Deprecated
ELF_RELOC(R_RISCV_CHERI_CCALL, 200) // Deprecated
ELF_RELOC(R_RISCV_CHERI_RVC_CJUMP, 201) // Deprecated

// CHERIoT relocations
ELF_RELOC(R_RISCV_CHERIOT_COMPARTMENT_HI, 220)
Expand Down
Loading