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
12 changes: 9 additions & 3 deletions clang/test/CodeGen/cheri/vaddr-mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ long write_uintcap(__uintcap_t *cap) {
// OFFSET-NEXT: entry:
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
// OFFSET-NEXT: [[AND:%.*]] = and i64 [[TMP0]], 3
// OFFSET-NEXT: ret i64 [[AND]]
// OFFSET-NEXT: [[TMP1:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[AND]])
// OFFSET-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP1]])
// OFFSET-NEXT: ret i64 [[TMP2]]
//
long get_low_bits(__uintcap_t cap) {
return cap & 3;
Expand Down Expand Up @@ -126,7 +128,9 @@ __uintcap_t xor_uintcap(__uintcap_t cap, __uintcap_t cap2) {
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
// OFFSET-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP2:%.*]])
// OFFSET-NEXT: [[XOR:%.*]] = xor i64 [[TMP1]], [[TMP0]]
// OFFSET-NEXT: ret i64 [[XOR]]
// OFFSET-NEXT: [[TMP2:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[XOR]])
// OFFSET-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP2]])
// OFFSET-NEXT: ret i64 [[TMP3]]
//
long xor_uintcap_return_long(__uintcap_t cap, __uintcap_t cap2) {
return cap ^ cap2;
Expand Down Expand Up @@ -160,7 +164,9 @@ __uintcap_t modulo_return_uintcap(__uintcap_t cap) {
// OFFSET-NEXT: entry:
// OFFSET-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[CAP:%.*]])
// OFFSET-NEXT: [[REM:%.*]] = and i64 [[TMP0]], 31
// OFFSET-NEXT: ret i64 [[REM]]
// OFFSET-NEXT: [[TMP1:%.*]] = tail call ptr addrspace(200) @llvm.cheri.cap.offset.set.i64(ptr addrspace(200) [[CAP]], i64 [[REM]])
// OFFSET-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(ptr addrspace(200) [[TMP1]])
// OFFSET-NEXT: ret i64 [[TMP2]]
//
long modulo_return_long(__uintcap_t cap) {
return cap % 32;
Expand Down
144 changes: 77 additions & 67 deletions lld/ELF/Arch/Cheri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ using namespace llvm::ELF;
namespace lld {
namespace elf {

bool isCheriAbi(const InputFile *f) {
switch (f->emachine) {
case EM_MIPS:
return (f->eflags & EF_MIPS_ABI) == EF_MIPS_ABI_CHERIABI;
case EM_RISCV:
return f->eflags & EF_RISCV_CHERIABI;
default:
return false;
}
}

bool hasDynamicLinker(Ctx &ctx) {
return ctx.arg.shared || ctx.arg.pie || !ctx.sharedFiles.empty();
}
Expand All @@ -43,10 +54,10 @@ struct InMemoryCapRelocEntry {
CapRelocUint permissions;
};

CheriCapRelocsSection::CheriCapRelocsSection(Ctx &ctx)
: SyntheticSection(ctx, "__cap_relocs", SHT_PROGBITS,
CheriCapRelocsSection::CheriCapRelocsSection(Ctx &ctx, StringRef name)
: SyntheticSection(ctx, name, SHT_PROGBITS,
(ctx.arg.isPic && !ctx.arg.relativeCapRelocsOnly)
? SHF_ALLOC | SHF_WRITE /* XXX: actually RELRO */
? SHF_ALLOC | SHF_WRITE
: SHF_ALLOC,
ctx.arg.wordsize) {
this->entsize = ctx.arg.wordsize * 5;
Expand Down Expand Up @@ -592,16 +603,14 @@ void CheriCapRelocsSection::writeTo(uint8_t *buf) {
invokeELFT(writeToImpl, buf);
}

CheriCapTableSection::CheriCapTableSection(Ctx &ctx)
: SyntheticSection(
ctx, ".captable", SHT_PROGBITS,
SHF_ALLOC | SHF_WRITE, /* XXX: actually RELRO for BIND_NOW*/
ctx.arg.capabilitySize) {
MipsCheriCapTableSection::MipsCheriCapTableSection(Ctx &ctx)
: SyntheticSection(ctx, ".captable", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE,
ctx.arg.capabilitySize) {
assert(ctx.arg.capabilitySize > 0);
this->entsize = ctx.arg.capabilitySize;
}

void CheriCapTableSection::writeTo(uint8_t *buf) {
void MipsCheriCapTableSection::writeTo(uint8_t *buf) {
// Capability part should be filled with all zeros and crt_init_globals fills
// it in. For the TLS part, assignValuesAndAddCapTableSymbols adds any static
// relocations needed, and should be procesed by relocateAlloc.
Expand All @@ -614,8 +623,8 @@ static Defined *findMatchingFunction(const InputSectionBase *isec,
return isec->getEnclosingFunction(symOffset);
}

CheriCapTableSection::CaptableMap &
CheriCapTableSection::getCaptableMapForFileAndOffset(
MipsCheriCapTableSection::CaptableMap &
MipsCheriCapTableSection::getCaptableMapForFileAndOffset(
const InputSectionBase *isec, uint64_t offset) {
if (LLVM_LIKELY(ctx.arg.capTableScope == CapTableScopePolicy::All))
return globalEntries;
Expand All @@ -637,47 +646,48 @@ CheriCapTableSection::getCaptableMapForFileAndOffset(
return globalEntries;
}

void CheriCapTableSection::addEntry(Symbol &sym, RelExpr expr,
InputSectionBase *isec, uint64_t offset) {
void MipsCheriCapTableSection::addEntry(Symbol &sym, RelExpr expr,
InputSectionBase *isec,
uint64_t offset) {
// FIXME: can this be called from multiple threads?
CapTableIndex idx;
idx.needsSmallImm = false;
idx.usedInCallExpr = false;
idx.firstUse = SymbolAndOffset(isec, offset);
assert(!idx.firstUse->symOrSec.isNull());
switch (expr) {
case R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE:
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE:
idx.needsSmallImm = true;
break;
default:
break;
case R_MIPS_CHERI_CAPTAB_INDEX_SMALL_IMMEDIATE:
case R_MIPS_CHERI_CAPTAB_INDEX_CALL_SMALL_IMMEDIATE:
idx.needsSmallImm = true;
break;
default:
break;
}
// If the symbol is only ever referenced by the captable call relocations we
// can emit a capability call relocation instead of a normal capability
// relocation. This indicates to the runtime linker that the capability is
// not used as a function pointer and therefore does not need a unique
// address (plt stub) across all DSOs.
switch (expr) {
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL:
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE:
if (!sym.isFunc() && !sym.isUndefWeak()) {
CheriCapRelocLocation loc{isec, offset};
std::string msg = "call relocation against non-function symbol " +
verboseToString(ctx, &sym, 0) + "\n>>> referenced by " +
loc.toString(ctx);
if (sym.isUndefined() &&
ctx.arg.unresolvedSymbolsInShlib == UnresolvedPolicy::Ignore) {
// Don't fail the build for shared libraries unless
nonFatalWarning(msg);
} else {
warn(msg);
}
case R_MIPS_CHERI_CAPTAB_INDEX_CALL:
case R_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 " +
verboseToString(ctx, &sym, 0) + "\n>>> referenced by " +
loc.toString(ctx);
if (sym.isUndefined() &&
ctx.arg.unresolvedSymbolsInShlib == UnresolvedPolicy::Ignore) {
// Don't fail the build for shared libraries unless
nonFatalWarning(msg);
} else {
warn(msg);
}
idx.usedInCallExpr = true;
break;
default:
break;
}
idx.usedInCallExpr = true;
break;
default:
break;
}
CaptableMap &entries = getCaptableMapForFileAndOffset(isec, offset);
if (ctx.arg.zCapTableDebug) {
Expand All @@ -700,25 +710,25 @@ void CheriCapTableSection::addEntry(Symbol &sym, RelExpr expr,
}
}

void CheriCapTableSection::addDynTlsEntry(Symbol &sym) {
void MipsCheriCapTableSection::addDynTlsEntry(Symbol &sym) {
dynTlsEntries.map.insert(std::make_pair(&sym, CapTableIndex()));
}

void CheriCapTableSection::addTlsIndex() {
void MipsCheriCapTableSection::addTlsIndex() {
dynTlsEntries.map.insert(std::make_pair(nullptr, CapTableIndex()));
}

void CheriCapTableSection::addTlsEntry(Symbol &sym) {
void MipsCheriCapTableSection::addTlsEntry(Symbol &sym) {
tlsEntries.map.insert(std::make_pair(&sym, CapTableIndex()));
}

uint32_t CheriCapTableSection::getIndex(const Symbol &sym,
const InputSectionBase *isec,
uint64_t offset) const {
uint32_t MipsCheriCapTableSection::getIndex(const Symbol &sym,
const InputSectionBase *isec,
uint64_t offset) const {
assert(valuesAssigned && "getIndex called before index assignment");
const CaptableMap &entries =
const_cast<CheriCapTableSection *>(this)->getCaptableMapForFileAndOffset(
isec, offset);
const_cast<MipsCheriCapTableSection *>(this)
->getCaptableMapForFileAndOffset(isec, offset);
auto it = entries.map.find(const_cast<Symbol *>(&sym));
assert(entries.firstIndex != std::numeric_limits<uint64_t>::max() &&
"First index not set yet?");
Expand All @@ -730,31 +740,31 @@ uint32_t CheriCapTableSection::getIndex(const Symbol &sym,
return *it->second.index - entries.firstIndex;
}

uint32_t CheriCapTableSection::getDynTlsOffset(const Symbol &sym) const {
uint32_t MipsCheriCapTableSection::getDynTlsOffset(const Symbol &sym) const {
assert(valuesAssigned && "getDynTlsOffset called before index assignment");
auto it = dynTlsEntries.map.find(const_cast<Symbol *>(&sym));
assert(it != dynTlsEntries.map.end());
return *it->second.index * ctx.arg.wordsize;
}

uint32_t CheriCapTableSection::getTlsIndexOffset() const {
uint32_t MipsCheriCapTableSection::getTlsIndexOffset() const {
assert(valuesAssigned && "getTlsIndexOffset called before index assignment");
auto it = dynTlsEntries.map.find(nullptr);
assert(it != dynTlsEntries.map.end());
return *it->second.index * ctx.arg.wordsize;
}

uint32_t CheriCapTableSection::getTlsOffset(const Symbol &sym) const {
uint32_t MipsCheriCapTableSection::getTlsOffset(const Symbol &sym) const {
assert(valuesAssigned && "getTlsOffset called before index assignment");
auto it = tlsEntries.map.find(const_cast<Symbol *>(&sym));
assert(it != tlsEntries.map.end());
return *it->second.index * ctx.arg.wordsize;
}

template <class ELFT>
uint64_t CheriCapTableSection::assignIndices(uint64_t startIndex,
CaptableMap &entries,
const Twine &symContext) {
uint64_t MipsCheriCapTableSection::assignIndices(uint64_t startIndex,
CaptableMap &entries,
const Twine &symContext) {
// Usually StartIndex will be zero (one global captable) but if we are
// compiling with per-file/per-function
uint64_t smallEntryCount = 0;
Expand Down Expand Up @@ -864,7 +874,7 @@ uint64_t CheriCapTableSection::assignIndices(uint64_t startIndex,
? ctx.in.relaPlt.get()
: ctx.mainPart->relaDyn.get();
addCapabilityRelocation<ELFT>(
ctx, targetSym, elfCapabilityReloc, ctx.in.cheriCapTable.get(), off,
ctx, targetSym, elfCapabilityReloc, ctx.in.mipsCheriCapTable.get(), off,
R_CHERI_CAPABILITY, 0, it.second.usedInCallExpr,
[&]() {
return ("\n>>> referenced by " + refName + "\n>>> first used in " +
Expand All @@ -878,7 +888,7 @@ uint64_t CheriCapTableSection::assignIndices(uint64_t startIndex,
}

template <class ELFT>
void CheriCapTableSection::assignValuesAndAddCapTableSymbols() {
void MipsCheriCapTableSection::assignValuesAndAddCapTableSymbols() {
// First assign the global indices (which will usually be the only ones)
uint64_t assignedEntries = assignIndices<ELFT>(0, globalEntries, "");
if (LLVM_UNLIKELY(ctx.arg.capTableScope != CapTableScopePolicy::All)) {
Expand Down Expand Up @@ -961,7 +971,6 @@ void CheriCapTableSection::assignValuesAndAddCapTableSymbols() {
this->relocations.push_back(
{R_TPREL, ctx.target->symbolicRel, offset, 0, s});
else
// FIXME: casting to GotSection here is a massive hack!!
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
ctx.target->tlsGotRel, *this, offset, *s, ctx.target->symbolicRel);
}
Expand All @@ -970,22 +979,22 @@ void CheriCapTableSection::assignValuesAndAddCapTableSymbols() {
}

template void
CheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF32LE>();
MipsCheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF32LE>();
template void
CheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF32BE>();
MipsCheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF32BE>();
template void
CheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF64LE>();
MipsCheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF64LE>();
template void
CheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF64BE>();
MipsCheriCapTableSection::assignValuesAndAddCapTableSymbols<ELF64BE>();

CheriCapTableMappingSection::CheriCapTableMappingSection(Ctx &ctx)
MipsCheriCapTableMappingSection::MipsCheriCapTableMappingSection(Ctx &ctx)
: SyntheticSection(ctx, ".captable_mapping", SHT_PROGBITS, SHF_ALLOC, 8) {
assert(ctx.arg.capabilitySize > 0);
this->entsize = sizeof(CaptableMappingEntry);
static_assert(sizeof(CaptableMappingEntry) == 24, "");
}

size_t CheriCapTableMappingSection::getSize() const {
size_t MipsCheriCapTableMappingSection::getSize() const {
assert(ctx.arg.capTableScope != CapTableScopePolicy::All);
if (!isNeeded()) return 0;
size_t count = 0;
Expand All @@ -1000,9 +1009,10 @@ size_t CheriCapTableMappingSection::getSize() const {
return count * sizeof(CaptableMappingEntry);
}

void CheriCapTableMappingSection::writeTo(uint8_t *buf) {
void MipsCheriCapTableMappingSection::writeTo(uint8_t *buf) {
assert(ctx.arg.capTableScope != CapTableScopePolicy::All);
if (!ctx.in.cheriCapTable) return;
if (!ctx.in.mipsCheriCapTable)
return;
if (!ctx.in.symTab) {
error("Cannot write " + this->name + " without .symtab section!");
return;
Expand All @@ -1015,14 +1025,14 @@ void CheriCapTableMappingSection::writeTo(uint8_t *buf) {
for (const SymbolTableEntry &ste : ctx.in.symTab->getSymbols()) {
Symbol *sym = ste.sym;
if (!sym->isDefined() || !sym->isFunc()) continue;
const CheriCapTableSection::CaptableMap *capTableMap = nullptr;
const MipsCheriCapTableSection::CaptableMap *capTableMap = nullptr;
if (ctx.arg.capTableScope == CapTableScopePolicy::Function) {
auto it = ctx.in.cheriCapTable->perFunctionEntries.find(sym);
if (it != ctx.in.cheriCapTable->perFunctionEntries.end())
auto it = ctx.in.mipsCheriCapTable->perFunctionEntries.find(sym);
if (it != ctx.in.mipsCheriCapTable->perFunctionEntries.end())
capTableMap = &it->second;
} else if (ctx.arg.capTableScope == CapTableScopePolicy::File) {
auto it = ctx.in.cheriCapTable->perFileEntries.find(sym->file);
if (it != ctx.in.cheriCapTable->perFileEntries.end())
auto it = ctx.in.mipsCheriCapTable->perFileEntries.find(sym->file);
if (it != ctx.in.mipsCheriCapTable->perFileEntries.end())
capTableMap = &it->second;
} else {
llvm_unreachable("Invalid mode!");
Expand Down
14 changes: 7 additions & 7 deletions lld/ELF/Arch/Cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct CheriCapReloc {
// FIXME: should de-template this class properly
class CheriCapRelocsSection : public SyntheticSection {
public:
CheriCapRelocsSection(Ctx &ctx);
CheriCapRelocsSection(Ctx &ctx, StringRef name);
// Add a __cap_relocs section from in input object file
template <class ELFT>
void addSection(InputSectionBase *s);
Expand Down Expand Up @@ -186,9 +186,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(Ctx &ctx);
MipsCheriCapTableSection(Ctx &ctx);
// 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 +266,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 +280,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(Ctx &ctx);
MipsCheriCapTableMappingSection(Ctx &ctx);
bool isNeeded() const override {
if (ctx.arg.capTableScope == CapTableScopePolicy::All)
return false;
return ctx.in.cheriCapTable && ctx.in.cheriCapTable->isNeeded();
return ctx.in.mipsCheriCapTable && ctx.in.mipsCheriCapTable->isNeeded();
}
void writeTo(uint8_t *buf) override;
size_t getSize() const override;
Expand Down
Loading