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
172 changes: 99 additions & 73 deletions lld/ELF/Arch/Cheri.cpp

Large diffs are not rendered by default.

28 changes: 13 additions & 15 deletions lld/ELF/Arch/Cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,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 @@ -186,9 +184,9 @@ class CheriCapRelocsSection : public SyntheticSection {
// +---------------------------------------+
// TODO: TLS caps also need to be per file/function

class CheriCapTableSection : public SyntheticSection {
class MipsCheriCapTableSection : public SyntheticSection {
public:
CheriCapTableSection();
MipsCheriCapTableSection();
// InputFile and Offset is needed in order to implement per-file/per-function
// tables
void addEntry(Symbol &sym, RelExpr expr, InputSectionBase *isec,
Expand Down Expand Up @@ -266,7 +264,7 @@ class CheriCapTableSection : public SyntheticSection {
CaptableMap dynTlsEntries;
CaptableMap tlsEntries;
bool valuesAssigned = false;
friend class CheriCapTableMappingSection;
friend class MipsCheriCapTableMappingSection;
};

// TODO: could shrink these to reduce size overhead but this is experimental
Expand All @@ -280,13 +278,13 @@ struct CaptableMappingEntry {

// Map from symbol vaddr -> captable subset so that RTLD can setup the correct
// trampolines to initialize $cgp to the correct subset
class CheriCapTableMappingSection : public SyntheticSection {
class MipsCheriCapTableMappingSection : public SyntheticSection {
public:
CheriCapTableMappingSection();
MipsCheriCapTableMappingSection();
bool isNeeded() const override {
if (config->capTableScope == CapTableScopePolicy::All)
return false;
return in.cheriCapTable && in.cheriCapTable->isNeeded();
return in.mipsCheriCapTable && in.mipsCheriCapTable->isNeeded();
}
void writeTo(uint8_t *buf) override;
size_t getSize() const override;
Expand Down Expand Up @@ -320,11 +318,11 @@ inline void readOnlyCapRelocsError(Symbol &sym, const Twine &sourceMsg) {
}

template <typename ELFT>
void addCapabilityRelocation(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(
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
10 changes: 5 additions & 5 deletions lld/ELF/Arch/Mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
case R_MICROMIPS_GPREL7_S2:
return R_MIPS_GOTREL;
case R_MIPS_CHERI_CAPTABLEREL16:
return R_CHERI_CAPABILITY_TABLE_REL;
return R_MIPS_CHERI_CAPTAB_REL;
case R_MIPS_26:
case R_MICROMIPS_26_S1:
return R_PLT;
Expand Down Expand Up @@ -212,16 +212,16 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
return R_CHERI_CAPABILITY;
case R_MIPS_CHERI_CAPTAB_LO16:
case R_MIPS_CHERI_CAPTAB_HI16:
return R_CHERI_CAPABILITY_TABLE_INDEX;
return R_MIPS_CHERI_CAPTAB_INDEX;
case R_MIPS_CHERI_CAPCALL_LO16:
case R_MIPS_CHERI_CAPCALL_HI16:
return R_CHERI_CAPABILITY_TABLE_INDEX_CALL;
return R_MIPS_CHERI_CAPTAB_INDEX_CALL;
case R_MIPS_CHERI_CAPTAB_CLC11:
case R_MIPS_CHERI_CAPTAB20:
return R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE;
return R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE;
case R_MIPS_CHERI_CAPCALL_CLC11:
case R_MIPS_CHERI_CAPCALL20:
return R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE;
return R_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;
Expand Down
37 changes: 17 additions & 20 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ enum Op {
CIncOffsetImm = 0x105b,
CLC_64 = 0x3003,
CLC_128 = 0x200f,
CSub = 0x2800005b,
};

enum Reg {
Expand Down Expand Up @@ -112,10 +111,7 @@ RISCV::RISCV() {
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 (config->is64) {
symbolicRel = R_RISCV_64;
tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
Expand All @@ -127,7 +123,10 @@ RISCV::RISCV() {
tlsOffsetRel = R_RISCV_TLS_DTPREL32;
tlsGotRel = R_RISCV_TLS_TPREL32;
}
gotRel = symbolicRel;
if (config->isCheriAbi)
gotRel = *cheriCapRel;
else
gotRel = symbolicRel;
absPointerRel = symbolicRel;

// .got[0] = _DYNAMIC
Expand Down Expand Up @@ -222,6 +221,10 @@ void RISCV::writeGotHeader(uint8_t *buf) const {
}

void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const {
// Initialised by __cap_relocs for CHERI
if (config->isCheriAbi)
return;

if (config->is64)
write64le(buf, in.plt->getVA());
else
Expand All @@ -238,14 +241,7 @@ void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
}

void RISCV::writePltHeader(uint8_t *buf) const {
// TODO: Remove once we have a CHERI .got.plt and R_RISCV_CHERI_JUMP_SLOT.
// Without those there can be no lazy binding support (though the former
// requirement can be relaxed provided .captable[0] is _dl_runtime_resolve,
// at least when the PLT is non-empty), so for now we emit a header full of
// trapping instructions to ensure we don't accidentally end up trying to use
// it. Ideally we would have a header size of 0, but isCheriAbi isn't known
// in the constructor.
if (config->isCheriAbi) {
if (config->isCheriAbi && !config->zCheriRiscvJumpSlot) {
memset(buf, 0, pltHeaderSize);
return;
}
Expand All @@ -259,7 +255,6 @@ void RISCV::writePltHeader(uint8_t *buf) const {
// (c)jr (c)t3
// (if shift == 0): nop
uint32_t offset = in.gotPlt->getVA() - in.plt->getVA();
uint32_t ptrsub = config->isCheriAbi ? CSub : SUB;
uint32_t ptrload = config->isCheriAbi ? config->is64 ? CLC_128 : CLC_64
: config->is64 ? LD : LW;
uint32_t ptraddi = config->isCheriAbi ? CIncOffsetImm : ADDI;
Expand All @@ -268,7 +263,7 @@ void RISCV::writePltHeader(uint8_t *buf) const {
uint32_t ptrsize = config->isCheriAbi ? config->capabilitySize
: config->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, -target->pltHeaderSize - 12));
write32le(buf + 16, itype(ptraddi, X_T0, X_T2, lo12(offset)));
Expand All @@ -288,8 +283,9 @@ void RISCV::writePlt(uint8_t *buf, const Symbol &sym,
// nop
uint32_t ptrload = config->isCheriAbi ? config->is64 ? CLC_128 : CLC_64
: config->is64 ? LD : LW;
uint32_t entryva = config->isCheriAbi ? sym.getCapTableVA(in.plt.get(), 0)
: sym.getGotPltVA();
uint32_t entryva = config->isCheriAbi && !config->zCheriRiscvJumpSlot
? sym.getGotVA()
: sym.getGotPltVA();
uint32_t offset = entryva - pltEntryAddr;
write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
write32le(buf + 4, itype(ptrload, X_T3, X_T3, lo12(offset)));
Expand Down Expand Up @@ -363,12 +359,13 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
return config->relax ? R_RELAX_HINT : R_NONE;
case R_RISCV_CHERI_CAPABILITY:
return R_CHERI_CAPABILITY;
// TODO: Deprecate and eventually remove these
case R_RISCV_CHERI_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_ENTRY_PC;
return R_GOT_PC;
case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC;
return R_GOT_PC;
case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC;
return R_TLSGD_PC;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ struct Config {
// -z captabledebug: add additional symbols $captable_load_<symbols> before
// each captable clc instruction that indicates which symbol should be loaded
bool zCapTableDebug;
bool zCheriRiscvJumpSlot;
bool zCombreloc;
bool zCopyreloc;
bool zForceBti;
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ static uint8_t getZStartStopVisibility(opt::InputArgList &args) {

constexpr const char *knownZFlags[] = {
"captabledebug",
"cheri-riscv-jump-slot",
"combreloc",
"copyreloc",
"defs",
Expand Down Expand Up @@ -1433,6 +1434,7 @@ static void readConfigs(opt::InputArgList &args) {
args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
config->whyExtract = args.getLastArgValue(OPT_why_extract);
config->zCapTableDebug = getZFlag(args, "captabledebug", "nocaptabledebug", false);
config->zCheriRiscvJumpSlot = hasZOption(args, "cheri-riscv-jump-slot");
config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true);
config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
config->zForceBti = hasZOption(args, "force-bti");
Expand Down
38 changes: 11 additions & 27 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,44 +863,28 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
return in.got->getTlsIndexVA() + a - p;
case R_CHERI_CAPABILITY:
llvm_unreachable("R_CHERI_CAPABILITY should not be handled here!");
case R_CHERI_CAPABILITY_TABLE_INDEX:
case R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE:
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL:
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE:
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:
assert(a == 0 && "capability table index relocs should not have addends");
return sym.getCapTableOffset(isec, offset);
case R_CHERI_CAPABILITY_TABLE_ENTRY_PC: {
assert(a == 0 && "capability table entry relocs should not have addends");
return sym.getCapTableVA(isec, offset) - p;
}
case R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC: {
assert(a == 0 && "capability table index relocs should not have addends");
uint64_t capTableOffset =
in.cheriCapTable->getDynTlsOffset(sym);
return ElfSym::cheriCapabilityTable->getVA() + capTableOffset - p;
}
case R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC: {
assert(a == 0 && "capability table index relocs should not have addends");
uint64_t capTableOffset =
in.cheriCapTable->getTlsOffset(sym);
return ElfSym::cheriCapabilityTable->getVA() + capTableOffset - p;
}
case R_CHERI_CAPABILITY_TABLE_REL:
if (!ElfSym::cheriCapabilityTable) {
return sym.getMipsCheriCapTableOffset(isec, offset);
case R_MIPS_CHERI_CAPTAB_REL:
if (!ElfSym::mipsCheriCapabilityTable) {
error("cannot compute difference between non-existent "
"CheriCapabilityTable and symbol " + toString(sym));
return sym.getVA(a);
}
return sym.getVA(a) - ElfSym::cheriCapabilityTable->getVA();
return sym.getVA(a) - ElfSym::mipsCheriCapabilityTable->getVA();
case R_MIPS_CHERI_CAPTAB_TLSGD:
assert(a == 0 && "capability table index relocs should not have addends");
return in.cheriCapTable->getDynTlsOffset(sym);
return in.mipsCheriCapTable->getDynTlsOffset(sym);
case R_MIPS_CHERI_CAPTAB_TLSLD:
assert(a == 0 && "capability table index relocs should not have addends");
return in.cheriCapTable->getTlsIndexOffset();
return in.mipsCheriCapTable->getTlsIndexOffset();
case R_MIPS_CHERI_CAPTAB_TPREL:
assert(a == 0 && "capability table index relocs should not have addends");
return in.cheriCapTable->getTlsOffset(sym);
return in.mipsCheriCapTable->getTlsOffset(sym);
default:
llvm_unreachable("invalid expression");
}
Expand Down
Loading