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
22 changes: 18 additions & 4 deletions lld/ELF/Arch/Cheri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -321,6 +321,7 @@ template <class ELFT> 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
};

Expand Down Expand Up @@ -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<Symbol *>(realTarget.symOrSec)) {
targetVA = realTarget.sym()->getVA(ctx, 0);
Expand All @@ -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;
Expand All @@ -377,6 +387,8 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
permissions |= CapRelocPermission<ELFT>::function;
if (isGnuIFunc)
permissions |= CapRelocPermission<ELFT>::indirect;
if (isCode)
permissions |= CapRelocPermission<ELFT>::code;
} else if (os) {
assert(!isTls);
// if ((OS->getPhdrFlags() & PF_W) == 0) {
Expand Down Expand Up @@ -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
Expand Down
17 changes: 13 additions & 4 deletions lld/ELF/Arch/Cheri.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};

Expand All @@ -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 <class ELFT> void writeToImpl(uint8_t *);
Expand All @@ -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;
}
Expand Down
51 changes: 28 additions & 23 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -222,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:
Expand Down Expand Up @@ -382,29 +386,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 {
Expand Down Expand Up @@ -681,6 +685,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);
Expand Down
22 changes: 17 additions & 5 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<shard>(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<shard>(relativeType, isec, offsetInSec, sym,
addend, type, expr);
}

template <class PltSection, class GotPltSection>
Expand All @@ -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),
Expand Down Expand Up @@ -1246,8 +1250,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
if (canWrite) {
RelType rel = ctx.target->getDynRel(type);
if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) ||
((rel == ctx.target->symbolicRel ||
rel == ctx.target->symbolicCapRel) &&
((rel == ctx.target->symbolicRel || rel == ctx.target->symbolicCapRel ||
type == ctx.target->symbolicCodeCapRel) &&
!sym.isPreemptible)) {
addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type);
return;
Expand Down Expand Up @@ -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;
}
}

Expand Down
10 changes: 6 additions & 4 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<RelType> 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() {
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class TargetInfo {
RelType gotRel = 0;
RelType pltRel = 0;
RelType relativeRel = 0;
std::optional<RelType> relativeFuncRel;
RelType iRelativeRel = 0;
RelType symbolicRel = 0;
RelType tlsDescRel = 0;
Expand All @@ -140,6 +141,7 @@ class TargetInfo {
std::optional<RelType> sizeRel;
std::optional<RelType> symbolicCapRel;
std::optional<RelType> symbolicCapCallRel;
std::optional<RelType> symbolicCodeCapRel;
unsigned gotEntrySize = ctx.arg.wordsize;
unsigned pltEntrySize = 0;
unsigned pltHeaderSize = 0;
Expand Down
22 changes: 11 additions & 11 deletions lld/test/ELF/cheri/exception-table.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -94,14 +94,14 @@
; 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,PLT0_ADDR:]] (<unknown symbol>+0) Length: 80 Perms: Function
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Function
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 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:]] (<unknown symbol>+0) Length: 80 Perms: Code
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Code
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Code
; RV64-RELOCS-NEXT: ]

; IR was generated from the following code:
Expand Down
30 changes: 30 additions & 0 deletions lld/test/ELF/cheri/riscv/code-func-reloc.s
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions lld/test/ELF/cheri/riscv/code-reloc-data.s
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions lld/test/ELF/cheri/riscv/code-reloc-preemptible.s
Original file line number Diff line number Diff line change
@@ -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
Loading