Skip to content

Commit 37d9cb8

Browse files
jrtc27resistor
authored andcommitted
[ELF][RISCV] Support R_RISCV_CHERI_CAPABILITY_CODE and R_RISCV_FUNC_RELATIVE
Note that we only use R_RISCV_FUNC_RELATIVE for CheriABI binaries as it's redundant for plain RISC-V and we would not be able to produce binaries that work with existing upstream RISC-V runtimes.
1 parent 39c2a73 commit 37d9cb8

File tree

12 files changed

+156
-48
lines changed

12 files changed

+156
-48
lines changed

lld/ELF/Arch/Cheri.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ std::string CheriCapRelocLocation::toString(Ctx &ctx) const {
180180
return SymbolAndOffset(section, offset).verboseToString(ctx);
181181
}
182182

183-
void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
183+
void CheriCapRelocsSection::addCapReloc(bool isCode, CheriCapRelocLocation loc,
184184
const SymbolAndOffset &target,
185185
int64_t capabilityOffset,
186186
Symbol *sourceSymbol) {
@@ -215,7 +215,7 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
215215
return;
216216
}
217217

218-
addEntry(loc, {target, capabilityOffset});
218+
addEntry(loc, {isCode, target, capabilityOffset});
219219
}
220220

221221
static uint64_t getTargetSize(Ctx &ctx, const CheriCapRelocLocation &location,
@@ -321,6 +321,7 @@ template <class ELFT> struct CapRelocPermission {
321321
static const uint64_t function = permissionBit(1);
322322
static const uint64_t readOnly = permissionBit(2);
323323
static const uint64_t indirect = permissionBit(3);
324+
static const uint64_t code = permissionBit(4);
324325
// clang-format on
325326
};
326327

@@ -353,7 +354,7 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
353354

354355
// The target VA is the base address of the capability, so symbol + 0
355356
uint64_t targetVA;
356-
bool isFunc, isGnuIFunc, isTls;
357+
bool isFunc, isGnuIFunc, isTls, isCode = reloc.isCode;
357358
OutputSection *os;
358359
if (Symbol *s = dyn_cast<Symbol *>(realTarget.symOrSec)) {
359360
targetVA = realTarget.sym()->getVA(ctx, 0);
@@ -369,6 +370,15 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
369370
isTls = isec->type == STT_TLS;
370371
os = isec->getOutputSection();
371372
}
373+
if (isCode && !isFunc) {
374+
auto msg = "code relocation against non-function symbol " +
375+
realTarget.verboseToString(ctx) + "\n>>> referenced by " +
376+
location.toString(ctx);
377+
if (ctx.arg.noinhibitExec)
378+
warn(msg);
379+
else
380+
error(msg);
381+
}
372382
uint64_t targetSize = getTargetSize(ctx, location, realTarget);
373383
uint64_t targetOffset = reloc.capabilityOffset + realTarget.offset;
374384
uint64_t permissions = 0;
@@ -377,6 +387,8 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
377387
permissions |= CapRelocPermission<ELFT>::function;
378388
if (isGnuIFunc)
379389
permissions |= CapRelocPermission<ELFT>::indirect;
390+
if (isCode)
391+
permissions |= CapRelocPermission<ELFT>::code;
380392
} else if (os) {
381393
assert(!isTls);
382394
// if ((OS->getPhdrFlags() & PF_W) == 0) {
@@ -960,10 +972,12 @@ void addRelativeCapabilityRelocation(
960972
type);
961973
return;
962974
}
975+
bool isCode = type == ctx.target->symbolicCodeCapRel;
963976
assert(!sym || !sym->isPreemptible);
964977
assert(!ctx.arg.useRelativeElfCheriRelocs &&
965978
"relative ELF capability relocations not currently implemented");
966-
ctx.in.capRelocs->addCapReloc({&isec, offsetInSec}, {symOrSec, 0u}, addend);
979+
ctx.in.capRelocs->addCapReloc(isCode, {&isec, offsetInSec}, {symOrSec, 0u},
980+
addend);
967981
}
968982

969983
} // namespace elf

lld/ELF/Arch/Cheri.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,18 @@ struct CheriCapRelocLocation {
6060
};
6161

6262
struct CheriCapReloc {
63+
// Indicates this is a relocation where the symbol is a function symbol but
64+
// we do not want any interposition, as this reference is for a specific
65+
// instruction within the function. Normal references to functions should not
66+
// set this.
67+
bool isCode;
6368
// We can't use a plain Symbol* here as capabilities to string constants
6469
// will be e.g. `.rodata.str + 0x90` -> need to store offset as well
6570
SymbolAndOffset target;
6671
int64_t capabilityOffset;
6772
bool operator==(const CheriCapReloc &other) const {
68-
return target == other.target && capabilityOffset == other.capabilityOffset;
73+
return isCode == other.isCode && target == other.target &&
74+
capabilityOffset == other.capabilityOffset;
6975
}
7076
};
7177

@@ -75,8 +81,9 @@ class CheriCapRelocsSection : public SyntheticSection {
7581
bool isNeeded() const override { return !relocsMap.empty(); }
7682
size_t getSize() const override { return relocsMap.size() * entsize; }
7783
void writeTo(uint8_t *buf) override;
78-
void addCapReloc(CheriCapRelocLocation loc, const SymbolAndOffset &target,
79-
int64_t capabilityOffset, Symbol *sourceSymbol = nullptr);
84+
void addCapReloc(bool isCode, CheriCapRelocLocation loc,
85+
const SymbolAndOffset &target, int64_t capabilityOffset,
86+
Symbol *sourceSymbol = nullptr);
8087

8188
private:
8289
template <class ELFT> void writeToImpl(uint8_t *);
@@ -88,8 +95,10 @@ class CheriCapRelocsSection : public SyntheticSection {
8895
" does not match existing one:\n> Existing: " +
8996
it.first->second.target.verboseToString(ctx) +
9097
", cap offset=" + Twine(it.first->second.capabilityOffset) +
98+
", is code=" + Twine(it.first->second.isCode) +
9199
"\n> New: " + relocation.target.verboseToString(ctx) +
92-
", cap offset=" + Twine(relocation.capabilityOffset));
100+
", cap offset=" + Twine(relocation.capabilityOffset) +
101+
", is code=" + Twine(relocation.isCode));
93102
}
94103
return it.second;
95104
}

lld/ELF/Arch/RISCV.cpp

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,11 @@ RISCV::RISCV(Ctx &ctx) : TargetInfo(ctx) {
126126
copyRel = R_RISCV_COPY;
127127
pltRel = R_RISCV_JUMP_SLOT;
128128
relativeRel = R_RISCV_RELATIVE;
129+
if (ctx.arg.isCheriAbi)
130+
relativeFuncRel = R_RISCV_FUNC_RELATIVE;
129131
iRelativeRel = R_RISCV_IRELATIVE;
130132
symbolicCapRel = R_RISCV_CHERI_CAPABILITY;
133+
symbolicCodeCapRel = R_RISCV_CHERI_CAPABILITY_CODE;
131134
if (ctx.arg.is64) {
132135
symbolicRel = R_RISCV_64;
133136
tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
@@ -382,29 +385,29 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
382385
case R_RISCV_SET_ULEB128:
383386
case R_RISCV_SUB_ULEB128:
384387
return RE_RISCV_LEB128;
385-
case R_RISCV_CHERI_CAPABILITY:
386-
return R_ABS_CAP;
387-
// TODO: Deprecate and eventually remove these
388-
case R_RISCV_CHERI_CAPTAB_PCREL_HI20:
389-
return R_GOT_PC;
390-
case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20:
391-
return R_GOT_PC;
392-
case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20:
393-
return R_TLSGD_PC;
394-
case R_RISCV_CHERIOT_COMPARTMENT_HI:
395-
return isPCCRelative(ctx, loc, &s) ? R_PC
396-
: R_CHERIOT_COMPARTMENT_CGPREL_HI;
397-
case R_RISCV_CHERIOT_COMPARTMENT_LO_I:
398-
return R_CHERIOT_COMPARTMENT_CGPREL_LO_I;
399-
case R_RISCV_CHERIOT_COMPARTMENT_LO_S:
400-
return R_CHERIOT_COMPARTMENT_CGPREL_LO_S;
401-
case R_RISCV_CHERIOT_COMPARTMENT_SIZE:
402-
return R_CHERIOT_COMPARTMENT_SIZE;
403-
default:
404-
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
405-
<< ") against symbol " << &s;
406-
return R_NONE;
407-
}
388+
case R_RISCV_CHERI_CAPABILITY:
389+
case R_RISCV_CHERI_CAPABILITY_CODE:
390+
return R_ABS_CAP;
391+
// TODO: Deprecate and eventually remove these
392+
case R_RISCV_CHERI_CAPTAB_PCREL_HI20:
393+
return R_GOT_PC;
394+
case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20:
395+
return R_GOT_PC;
396+
case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20:
397+
return R_TLSGD_PC;
398+
case R_RISCV_CHERIOT_COMPARTMENT_HI:
399+
return isPCCRelative(ctx, loc, &s) ? R_PC : R_CHERIOT_COMPARTMENT_CGPREL_HI;
400+
case R_RISCV_CHERIOT_COMPARTMENT_LO_I:
401+
return R_CHERIOT_COMPARTMENT_CGPREL_LO_I;
402+
case R_RISCV_CHERIOT_COMPARTMENT_LO_S:
403+
return R_CHERIOT_COMPARTMENT_CGPREL_LO_S;
404+
case R_RISCV_CHERIOT_COMPARTMENT_SIZE:
405+
return R_CHERIOT_COMPARTMENT_SIZE;
406+
default:
407+
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
408+
<< ") against symbol " << &s;
409+
return R_NONE;
410+
}
408411
}
409412

410413
void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
@@ -681,6 +684,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
681684
}
682685

683686
case R_RISCV_CHERI_CAPABILITY:
687+
case R_RISCV_CHERI_CAPABILITY_CODE:
684688
// Write a word within the capability
685689
if (ctx.arg.is64)
686690
write64le(loc, val);

lld/ELF/Relocations.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -936,8 +936,11 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
936936
part.relrDyn->relocs.push_back({&isec, isec.relocs().size() - 1});
937937
return;
938938
}
939-
part.relaDyn->addRelativeReloc<shard>(ctx.target->relativeRel, isec,
940-
offsetInSec, sym, addend, type, expr);
939+
RelType relativeType = ctx.target->relativeRel;
940+
if (ctx.target->relativeFuncRel && sym.isFunc())
941+
relativeType = *ctx.target->relativeFuncRel;
942+
part.relaDyn->addRelativeReloc<shard>(relativeType, isec, offsetInSec, sym,
943+
addend, type, expr);
941944
}
942945

943946
template <class PltSection, class GotPltSection>
@@ -955,7 +958,8 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt,
955958
}
956959

957960
addRelativeCapabilityRelocation(ctx, gotPlt, sym.getGotPltOffset(ctx), &plt,
958-
0, R_ABS_CAP, *ctx.target->symbolicCapRel);
961+
0, R_ABS_CAP,
962+
*ctx.target->symbolicCodeCapRel);
959963
}
960964

961965
rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx),
@@ -1246,8 +1250,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
12461250
if (canWrite) {
12471251
RelType rel = ctx.target->getDynRel(type);
12481252
if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) ||
1249-
((rel == ctx.target->symbolicRel ||
1250-
rel == ctx.target->symbolicCapRel) &&
1253+
((rel == ctx.target->symbolicRel || rel == ctx.target->symbolicCapRel ||
1254+
type == ctx.target->symbolicCodeCapRel) &&
12511255
!sym.isPreemptible)) {
12521256
addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type);
12531257
return;
@@ -1298,6 +1302,14 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
12981302
if (ctx.arg.emachine == EM_MIPS && expr != R_ABS_CAP)
12991303
ctx.in.mipsGot->addEntry(*sec->file, sym, addend, expr);
13001304
return;
1305+
} else if (type == ctx.target->symbolicCodeCapRel) {
1306+
auto diag = (ctx.arg.noinhibitExec) ? Warn(ctx) : Err(ctx);
1307+
diag << "relocation " + toStr(ctx, type)
1308+
<< " cannot be used against preemptible symbol '" << toStr(ctx, sym)
1309+
<< "'";
1310+
printLocation(diag, *sec, sym, offset);
1311+
1312+
return;
13011313
}
13021314
}
13031315

lld/ELF/SyntheticSections.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,10 +1798,12 @@ void RelocationBaseSection::partitionRels() {
17981798
if (!combreloc)
17991799
return;
18001800
const RelType relativeRel = ctx.target->relativeRel;
1801-
numRelativeRelocs =
1802-
std::stable_partition(relocs.begin(), relocs.end(),
1803-
[=](auto &r) { return r.type == relativeRel; }) -
1804-
relocs.begin();
1801+
const std::optional<RelType> relativeFuncRel = ctx.target->relativeFuncRel;
1802+
const auto *firstNonRelativeReloc =
1803+
std::stable_partition(relocs.begin(), relocs.end(), [=](auto &r) {
1804+
return r.type == relativeRel || r.type == relativeFuncRel;
1805+
});
1806+
numRelativeRelocs = firstNonRelativeReloc - relocs.begin();
18051807
}
18061808

18071809
void RelocationBaseSection::finalizeContents() {

lld/ELF/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class TargetInfo {
130130
RelType gotRel = 0;
131131
RelType pltRel = 0;
132132
RelType relativeRel = 0;
133+
std::optional<RelType> relativeFuncRel;
133134
RelType iRelativeRel = 0;
134135
RelType symbolicRel = 0;
135136
RelType tlsDescRel = 0;
@@ -140,6 +141,7 @@ class TargetInfo {
140141
std::optional<RelType> sizeRel;
141142
std::optional<RelType> symbolicCapRel;
142143
std::optional<RelType> symbolicCapCallRel;
144+
std::optional<RelType> symbolicCodeCapRel;
143145
unsigned gotEntrySize = ctx.arg.wordsize;
144146
unsigned pltEntrySize = 0;
145147
unsigned pltHeaderSize = 0;

lld/test/ELF/cheri/exception-table.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@
9999
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST2_ADDR]] (.L_Z5test2ll$local+68) Length: 124 Perms: Function
100100
; Next one references the local symbol, and uses that length rather than the override:
101101
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,TEST_WEAK_ADDR]] (.L_Z9test_weakll$local+28) Length: 52 Perms: Function
102-
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR:]] (<unknown symbol>+0) Length: 80 Perms: Function
103-
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Function
104-
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Function
102+
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR:]] (<unknown symbol>+0) Length: 80 Perms: Code
103+
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Code
104+
; RV64-RELOCS-NEXT: 0x003{{.+}} Base: 0x[[#%x,PLT0_ADDR]] (<unknown symbol>+0) Length: 80 Perms: Code
105105
; RV64-RELOCS-NEXT: ]
106106

107107
; IR was generated from the following code:
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# REQUIRES: riscv
2+
3+
# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o
4+
# RUN: ld.lld -shared -z separate-code %t.o -o %t.so
5+
# RUN: llvm-readobj -r --cap-relocs %t.so | FileCheck %s
6+
7+
# CHECK: .rela.dyn {
8+
# CHECK-NEXT: 0x3100 R_RISCV_FUNC_RELATIVE - 0x1000
9+
# CHECK-NEXT: 0x3108 R_RISCV_RELATIVE - 0x30D0
10+
# CHECK-NEXT: }
11+
# CHECK: CHERI __cap_relocs [
12+
# CHECK-NEXT: 0x0030d0 (data) Base: 0x1000 (func+0) Length: 4 Perms: Function
13+
# CHECK-NEXT: 0x0030e0 Base: 0x1000 (func+0) Length: 4 Perms: Code
14+
# CHECK-NEXT: 0x0030f0 Base: 0x30d0 (data+0) Length: 64 Perms: Object
15+
# CHECK-NEXT: ]
16+
17+
.type func, @function
18+
func:
19+
cret
20+
.size func, . - func
21+
22+
.data
23+
.type data, @object
24+
data:
25+
.chericap func
26+
.chericap %code(func)
27+
.chericap data
28+
.quad func
29+
.quad data
30+
.size data, . - data
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# REQUIRES: riscv
2+
3+
# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o
4+
# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
5+
6+
# CHECK: error: code relocation against non-function symbol local object data
7+
# CHECK-NEXT: >>> defined in ({{.*}}/code-reloc-data.s.tmp.o:(object data: .data+0x0))
8+
# CHECK-NEXT: >>> referenced by local object data
9+
# CHECK-NEXT: >>> defined in ({{.*}}/code-reloc-data.s.tmp.o:(object data: .data+0x0))
10+
11+
.data
12+
.type data, @object
13+
data:
14+
.chericap %code(data)
15+
.size data, . - data
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# REQUIRES: riscv
2+
3+
# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %s -o %t.o
4+
# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s
5+
6+
# CHECK: error: relocation R_RISCV_CHERI_CAPABILITY_CODE cannot be used against preemptible symbol 'func'
7+
# CHECK-NEXT: >>> defined in {{.*}}/code-reloc-preemptible.s.tmp.o
8+
# CHECK-NEXT: >>> referenced by {{.*}}/code-reloc-preemptible.s.tmp.o:(data)
9+
10+
.global func
11+
.type func, @function
12+
func:
13+
cret
14+
.size func, . - func
15+
16+
.data
17+
.type data, @object
18+
data:
19+
.chericap %code(func)
20+
.size data, . - data

0 commit comments

Comments
 (0)