Skip to content

Commit 30a3280

Browse files
committed
[ELF][CHERI] Support creating new capability relocations against sections
This will be needed to initialise .got.plt entries to refer to .plt[0]. The infrastructure is already mostly there, we just need to expose it via the addCapabilityRelocation interface and remove some assumptions.
1 parent a6d0f43 commit 30a3280

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

lld/ELF/Arch/Cheri.cpp

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
322322
auto sourceMsg = [&]() -> std::string {
323323
return sourceSymbol ? verboseToString(sourceSymbol) : loc.toString();
324324
};
325-
if (target.sym()->isUndefined() && !target.sym()->isUndefWeak()) {
325+
if (isa<Symbol *>(target.symOrSec) && target.sym()->isUndefined() &&
326+
!target.sym()->isUndefWeak()) {
326327
std::string msg =
327328
"cap_reloc against undefined symbol: " + toString(*target.sym()) +
328329
"\n>>> referenced by " + sourceMsg();
@@ -348,6 +349,7 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
348349
return; // Maybe happens with vtables?
349350
}
350351
if (targetNeedsDynReloc) {
352+
assert(isa<Symbol *>(target.symOrSec));
351353
bool relativeToLoadAddress = false;
352354
// The addend is not used as the offset into the capability here, as we
353355
// have the offset field in the __cap_relocs for that. The Addend
@@ -384,6 +386,9 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
384386
template <typename ELFT>
385387
static uint64_t getTargetSize(const CheriCapRelocLocation &location,
386388
const SymbolAndOffset &target) {
389+
if (InputSectionBase *isec = dyn_cast<InputSectionBase *>(target.symOrSec))
390+
return isec->getSize();
391+
387392
uint64_t targetSize = target.sym()->getSize();
388393
if (targetSize > INT_MAX) {
389394
error("Insanely large symbol size for " + target.verboseToString() +
@@ -510,9 +515,24 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
510515
location.section->getOutputSection()->addr + outSecOffset;
511516

512517
// The target VA is the base address of the capability, so symbol + 0
513-
uint64_t targetVA = realTarget.sym()->getVA(0);
514-
bool preemptibleDynReloc =
515-
reloc.needsDynReloc && realTarget.sym()->isPreemptible;
518+
uint64_t targetVA;
519+
bool isPreemptible, isFunc, isTls;
520+
OutputSection *os;
521+
if (Symbol *s = dyn_cast<Symbol *>(realTarget.symOrSec)) {
522+
targetVA = realTarget.sym()->getVA(0);
523+
isPreemptible = reloc.needsDynReloc && realTarget.sym()->isPreemptible;
524+
isFunc = s->isFunc();
525+
isTls = s->isTls();
526+
os = s->getOutputSection();
527+
} else {
528+
InputSectionBase *isec = cast<InputSectionBase *>(realTarget.symOrSec);
529+
targetVA = isec->getVA(0);
530+
isPreemptible = false;
531+
isFunc = (isec->flags & SHF_EXECINSTR) != 0;
532+
isTls = isec->type == STT_TLS;
533+
os = isec->getOutputSection();
534+
}
535+
bool preemptibleDynReloc = reloc.needsDynReloc && isPreemptible;
516536
uint64_t targetSize = 0;
517537
if (preemptibleDynReloc) {
518538
// If we have a relocation against a preemptible symbol (even in the
@@ -529,10 +549,10 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
529549
uint64_t targetOffset = reloc.capabilityOffset + realTarget.offset;
530550
uint64_t permissions = 0;
531551
// Fow now Function implies ReadOnly so don't add the flag
532-
if (realTarget.sym()->isFunc()) {
552+
if (isFunc) {
533553
permissions |= CaptablePermissions<ELFT>::function;
534-
} else if (auto os = realTarget.sym()->getOutputSection()) {
535-
assert(!realTarget.sym()->isTls());
554+
} else if (os) {
555+
assert(!isTls);
536556
// if ((OS->getPhdrFlags() & PF_W) == 0) {
537557
if (((os->flags & SHF_WRITE) == 0) || isRelroSection(os)) {
538558
permissions |= CaptablePermissions<ELFT>::readOnly;
@@ -1047,13 +1067,14 @@ void MipsCheriCapTableMappingSection::writeTo(uint8_t *buf) {
10471067
}
10481068

10491069
template <typename ELFT>
1050-
void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
1051-
uint64_t offset, RelExpr expr, int64_t addend,
1052-
bool isCallExpr,
1053-
llvm::function_ref<std::string()> referencedBy,
1054-
RelocationBaseSection *dynRelSec) {
1070+
void addCapabilityRelocation(
1071+
llvm::PointerUnion<Symbol *, InputSectionBase *> symOrSec, RelType type,
1072+
InputSectionBase *sec, uint64_t offset, RelExpr expr, int64_t addend,
1073+
bool isCallExpr, llvm::function_ref<std::string()> referencedBy,
1074+
RelocationBaseSection *dynRelSec) {
1075+
Symbol *sym = dyn_cast<Symbol *>(symOrSec);
10551076
assert(expr == R_CHERI_CAPABILITY);
1056-
if (sec->name == ".gcc_except_table" && sym->isPreemptible) {
1077+
if (sec->name == ".gcc_except_table" && sym && sym->isPreemptible) {
10571078
// We previously had an ugly workaround here to create a hidden alias for
10581079
// relocations in the exception table, but this has since been fixed in
10591080
// the compiler. Add an explicit error here in case someone tries to
@@ -1067,14 +1088,15 @@ void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
10671088
// Emit either the legacy __cap_relocs section or a R_CHERI_CAPABILITY reloc
10681089
// For local symbols we can also emit the untagged capability bits and
10691090
// instruct csu/rtld to run CBuildCap
1070-
CapRelocsMode capRelocMode = sym->isPreemptible
1091+
CapRelocsMode capRelocMode = sym && sym->isPreemptible
10711092
? config->preemptibleCapRelocsMode
10721093
: config->localCapRelocsMode;
10731094
bool needTrampoline = false;
10741095
// In the PLT ABI (and fndesc?) we have to use an elf relocation for function
10751096
// pointers to ensure that the runtime linker adds the required trampolines
10761097
// that sets $cgp:
1077-
if (!isCallExpr && config->emachine == llvm::ELF::EM_MIPS && sym->isFunc()) {
1098+
if (!isCallExpr && config->emachine == llvm::ELF::EM_MIPS && sym &&
1099+
sym->isFunc()) {
10781100
if (!lld::elf::hasDynamicLinker()) {
10791101
// In static binaries we do not need PLT stubs for function pointers since
10801102
// all functions share the same $cgp
@@ -1083,26 +1105,26 @@ void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
10831105
if (config->verboseCapRelocs)
10841106
message("Do not need function pointer trampoline for " +
10851107
toString(*sym) + " in static binary");
1086-
needTrampoline = false;
10871108
} else if (in.mipsAbiFlags) {
10881109
auto abi = static_cast<MipsAbiFlagsSection<ELFT> &>(*in.mipsAbiFlags)
10891110
.getCheriAbiVariant();
10901111
if (abi && (*abi == llvm::ELF::DF_MIPS_CHERI_ABI_PLT ||
10911112
*abi == llvm::ELF::DF_MIPS_CHERI_ABI_FNDESC))
10921113
needTrampoline = true;
10931114
}
1094-
}
10951115

1096-
if (needTrampoline) {
1097-
capRelocMode = CapRelocsMode::ElfReloc;
1098-
assert(capRelocMode == config->preemptibleCapRelocsMode);
1099-
if (config->verboseCapRelocs)
1100-
message("Using trampoline for function pointer against " +
1101-
verboseToString(sym));
1116+
if (needTrampoline) {
1117+
capRelocMode = CapRelocsMode::ElfReloc;
1118+
assert(capRelocMode == config->preemptibleCapRelocsMode);
1119+
if (config->verboseCapRelocs)
1120+
message("Using trampoline for function pointer against " +
1121+
verboseToString(sym));
1122+
}
11021123
}
11031124

11041125
// local cap relocs don't need a Elf relocation with a full symbol lookup:
11051126
if (capRelocMode == CapRelocsMode::ElfReloc) {
1127+
assert(sym && "ELF relocs should not be used against sections");
11061128
assert((sym->isPreemptible || needTrampoline) &&
11071129
"ELF relocs should not be used for non-preemptible symbols");
11081130
assert((!sym->isLocal() || needTrampoline) &&
@@ -1157,10 +1179,10 @@ void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
11571179

11581180
} else if (capRelocMode == CapRelocsMode::Legacy) {
11591181
if (config->relativeCapRelocsOnly) {
1160-
assert(!sym->isPreemptible);
1182+
assert(!sym || !sym->isPreemptible);
11611183
}
1162-
in.capRelocs->addCapReloc<ELFT>({sec, offset}, {sym, 0u},
1163-
sym->isPreemptible, addend);
1184+
in.capRelocs->addCapReloc<ELFT>({sec, offset}, {symOrSec, 0u},
1185+
sym && sym->isPreemptible, addend);
11641186
} else {
11651187
assert(config->localCapRelocsMode == CapRelocsMode::CBuildCap);
11661188
error("CBuildCap method not implemented yet!");
@@ -1171,14 +1193,18 @@ void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
11711193
} // namespace lld
11721194

11731195
template void lld::elf::addCapabilityRelocation<ELF32LE>(
1174-
Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1196+
llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1197+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
11751198
llvm::function_ref<std::string()>, RelocationBaseSection *);
11761199
template void lld::elf::addCapabilityRelocation<ELF32BE>(
1177-
Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1200+
llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1201+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
11781202
llvm::function_ref<std::string()>, RelocationBaseSection *);
11791203
template void lld::elf::addCapabilityRelocation<ELF64LE>(
1180-
Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1204+
llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1205+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
11811206
llvm::function_ref<std::string()>, RelocationBaseSection *);
11821207
template void lld::elf::addCapabilityRelocation<ELF64BE>(
1183-
Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1208+
llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1209+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
11841210
llvm::function_ref<std::string()>, RelocationBaseSection *);

lld/ELF/Arch/Cheri.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ namespace elf {
1515

1616
struct SymbolAndOffset {
1717
public:
18-
SymbolAndOffset(Symbol *s, int64_t o) : symOrSec(s), offset(o) {
18+
SymbolAndOffset(llvm::PointerUnion<Symbol *, InputSectionBase *> s, int64_t o)
19+
: symOrSec(s), offset(o) {
1920
assert(s && "Should not be null");
2021
}
21-
SymbolAndOffset(InputSectionBase *isec, int64_t o) : symOrSec(isec), offset(o) {
22-
assert(isec && "Should not be null");
23-
}
2422
SymbolAndOffset(const SymbolAndOffset &) = default;
2523
SymbolAndOffset &operator=(const SymbolAndOffset &) = default;
2624

@@ -320,11 +318,11 @@ inline void readOnlyCapRelocsError(Symbol &sym, const Twine &sourceMsg) {
320318
}
321319

322320
template <typename ELFT>
323-
void addCapabilityRelocation(Symbol *sym, RelType type, InputSectionBase *sec,
324-
uint64_t offset, RelExpr expr, int64_t addend,
325-
bool isCallExpr,
326-
llvm::function_ref<std::string()> referencedBy,
327-
RelocationBaseSection *dynRelSec = nullptr);
321+
void addCapabilityRelocation(
322+
llvm::PointerUnion<Symbol *, InputSectionBase *> target, RelType type,
323+
InputSectionBase *sec, uint64_t offset, RelExpr expr, int64_t addend,
324+
bool isCallExpr, llvm::function_ref<std::string()> referencedBy,
325+
RelocationBaseSection *dynRelSec = nullptr);
328326
} // namespace elf
329327
} // namespace lld
330328

0 commit comments

Comments
 (0)