Skip to content

Commit dc9f06f

Browse files
jrtc27resistor
authored andcommitted
[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 37fb5f4 commit dc9f06f

File tree

2 files changed

+69
-44
lines changed

2 files changed

+69
-44
lines changed

lld/ELF/Arch/Cheri.cpp

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
333333
auto sourceMsg = [&]() -> std::string {
334334
return sourceSymbol ? verboseToString(ctx, sourceSymbol) : loc.toString(ctx);
335335
};
336-
if (target.sym()->isUndefined() && !target.sym()->isUndefWeak()) {
336+
if (isa<Symbol *>(target.symOrSec) && target.sym()->isUndefined() &&
337+
!target.sym()->isUndefWeak()) {
337338
auto diag = (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError)
338339
? Err(ctx)
339340
: (errorHandler().fatalWarnings) ? Msg(ctx)
@@ -362,6 +363,7 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
362363
return; // Maybe happens with vtables?
363364
}
364365
if (targetNeedsDynReloc) {
366+
assert(isa<Symbol *>(target.symOrSec));
365367
bool relativeToLoadAddress = false;
366368
// The addend is not used as the offset into the capability here, as we
367369
// have the offset field in the __cap_relocs for that. The Addend
@@ -398,6 +400,9 @@ void CheriCapRelocsSection::addCapReloc(CheriCapRelocLocation loc,
398400
template <typename ELFT>
399401
static uint64_t getTargetSize(Ctx &ctx, const CheriCapRelocLocation &location,
400402
const SymbolAndOffset &target) {
403+
if (InputSectionBase *isec = dyn_cast<InputSectionBase *>(target.symOrSec))
404+
return isec->getSize();
405+
401406
uint64_t targetSize = target.sym()->getSize(ctx);
402407
if (targetSize > INT_MAX) {
403408
error("Insanely large symbol size for " + target.verboseToString(ctx) +
@@ -523,9 +528,24 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
523528
location.section->getOutputSection()->addr + outSecOffset;
524529

525530
// The target VA is the base address of the capability, so symbol + 0
526-
uint64_t targetVA = realTarget.sym()->getVA(ctx, 0);
527-
bool preemptibleDynReloc =
528-
reloc.needsDynReloc && realTarget.sym()->isPreemptible;
531+
uint64_t targetVA;
532+
bool isPreemptible, isFunc, isTls;
533+
OutputSection *os;
534+
if (Symbol *s = dyn_cast<Symbol *>(realTarget.symOrSec)) {
535+
targetVA = realTarget.sym()->getVA(ctx, 0);
536+
isPreemptible = reloc.needsDynReloc && realTarget.sym()->isPreemptible;
537+
isFunc = s->isFunc();
538+
isTls = s->isTls();
539+
os = s->getOutputSection();
540+
} else {
541+
InputSectionBase *isec = cast<InputSectionBase *>(realTarget.symOrSec);
542+
targetVA = isec->getVA(0);
543+
isPreemptible = false;
544+
isFunc = (isec->flags & SHF_EXECINSTR) != 0;
545+
isTls = isec->type == STT_TLS;
546+
os = isec->getOutputSection();
547+
}
548+
bool preemptibleDynReloc = reloc.needsDynReloc && isPreemptible;
529549
uint64_t targetSize = 0;
530550
if (preemptibleDynReloc) {
531551
// If we have a relocation against a preemptible symbol (even in the
@@ -543,10 +563,10 @@ void CheriCapRelocsSection::writeToImpl(uint8_t *buf) {
543563
uint64_t targetOffset = reloc.capabilityOffset + realTarget.offset;
544564
uint64_t permissions = 0;
545565
// Fow now Function implies ReadOnly so don't add the flag
546-
if (realTarget.sym()->isFunc()) {
566+
if (isFunc) {
547567
permissions |= CaptablePermissions<ELFT>::function;
548-
} else if (auto os = realTarget.sym()->getOutputSection()) {
549-
assert(!realTarget.sym()->isTls());
568+
} else if (os) {
569+
assert(!isTls);
550570
// if ((OS->getPhdrFlags() & PF_W) == 0) {
551571
if (((os->flags & SHF_WRITE) == 0) || isRelroSection(ctx, os)) {
552572
permissions |= CaptablePermissions<ELFT>::readOnly;
@@ -1080,15 +1100,16 @@ static bool isSymIncludedInDynsym(Ctx &ctx, const Symbol &sym) {
10801100
(ctx.arg.exportDynamic && (sym.isUsedInRegularObj || !sym.ltoCanOmit));
10811101
}
10821102

1083-
10841103
template <typename ELFT>
1085-
void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
1086-
InputSectionBase *sec, uint64_t offset,
1087-
RelExpr expr, int64_t addend, bool isCallExpr,
1088-
llvm::function_ref<std::string()> referencedBy,
1089-
RelocationBaseSection *dynRelSec) {
1104+
void addCapabilityRelocation(
1105+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *> symOrSec,
1106+
RelType type, InputSectionBase *sec, uint64_t offset, RelExpr expr,
1107+
int64_t addend, bool isCallExpr,
1108+
llvm::function_ref<std::string()> referencedBy,
1109+
RelocationBaseSection *dynRelSec) {
1110+
Symbol *sym = dyn_cast<Symbol *>(symOrSec);
10901111
assert(expr == R_CHERI_CAPABILITY);
1091-
if (sec->name == ".gcc_except_table" && sym->isPreemptible) {
1112+
if (sec->name == ".gcc_except_table" && sym && sym->isPreemptible) {
10921113
// We previously had an ugly workaround here to create a hidden alias for
10931114
// relocations in the exception table, but this has since been fixed in
10941115
// the compiler. Add an explicit error here in case someone tries to
@@ -1102,14 +1123,15 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
11021123
// Emit either the legacy __cap_relocs section or a R_CHERI_CAPABILITY reloc
11031124
// For local symbols we can also emit the untagged capability bits and
11041125
// instruct csu/rtld to run CBuildCap
1105-
CapRelocsMode capRelocMode = sym->isPreemptible
1126+
CapRelocsMode capRelocMode = sym && sym->isPreemptible
11061127
? ctx.arg.preemptibleCapRelocsMode
11071128
: ctx.arg.localCapRelocsMode;
11081129
bool needTrampoline = false;
11091130
// In the PLT ABI (and fndesc?) we have to use an elf relocation for function
11101131
// pointers to ensure that the runtime linker adds the required trampolines
11111132
// that sets $cgp:
1112-
if (!isCallExpr && ctx.arg.emachine == llvm::ELF::EM_MIPS && sym->isFunc()) {
1133+
if (!isCallExpr && ctx.arg.emachine == llvm::ELF::EM_MIPS && sym &&
1134+
sym->isFunc()) {
11131135
if (!lld::elf::hasDynamicLinker(ctx)) {
11141136
// In static binaries we do not need PLT stubs for function pointers since
11151137
// all functions share the same $cgp
@@ -1118,26 +1140,26 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
11181140
if (ctx.arg.verboseCapRelocs)
11191141
Msg(ctx) << "Do not need function pointer trampoline for "
11201142
<< toStr(ctx, *sym) << " in static binary";
1121-
needTrampoline = false;
11221143
} else if (ctx.in.mipsAbiFlags) {
11231144
auto abi = static_cast<MipsAbiFlagsSection<ELFT> &>(*ctx.in.mipsAbiFlags)
11241145
.getCheriAbiVariant();
11251146
if (abi && (*abi == llvm::ELF::DF_MIPS_CHERI_ABI_PLT ||
11261147
*abi == llvm::ELF::DF_MIPS_CHERI_ABI_FNDESC))
11271148
needTrampoline = true;
11281149
}
1129-
}
11301150

1131-
if (needTrampoline) {
1132-
capRelocMode = CapRelocsMode::ElfReloc;
1133-
assert(capRelocMode == ctx.arg.preemptibleCapRelocsMode);
1134-
if (ctx.arg.verboseCapRelocs)
1135-
message("Using trampoline for function pointer against " +
1136-
verboseToString(ctx, sym));
1151+
if (needTrampoline) {
1152+
capRelocMode = CapRelocsMode::ElfReloc;
1153+
assert(capRelocMode == ctx.arg.preemptibleCapRelocsMode);
1154+
if (ctx.arg.verboseCapRelocs)
1155+
message("Using trampoline for function pointer against " +
1156+
verboseToString(ctx, sym));
1157+
}
11371158
}
11381159

11391160
// local cap relocs don't need a Elf relocation with a full symbol lookup:
11401161
if (capRelocMode == CapRelocsMode::ElfReloc) {
1162+
assert(sym && "ELF relocs should not be used against sections");
11411163
assert((sym->isPreemptible || needTrampoline) &&
11421164
"ELF relocs should not be used for non-preemptible symbols");
11431165
assert((!sym->isLocal() || needTrampoline) &&
@@ -1195,10 +1217,10 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
11951217

11961218
} else if (capRelocMode == CapRelocsMode::Legacy) {
11971219
if (ctx.arg.relativeCapRelocsOnly) {
1198-
assert(!sym->isPreemptible);
1220+
assert(!sym || !sym->isPreemptible);
11991221
}
1200-
ctx.in.capRelocs->addCapReloc<ELFT>({sec, offset}, {sym, 0u},
1201-
sym->isPreemptible, addend);
1222+
ctx.in.capRelocs->addCapReloc<ELFT>({sec, offset}, {symOrSec, 0u},
1223+
sym && sym->isPreemptible, addend);
12021224
} else {
12031225
assert(ctx.arg.localCapRelocsMode == CapRelocsMode::CBuildCap);
12041226
error("CBuildCap method not implemented yet!");
@@ -1209,14 +1231,18 @@ void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
12091231
} // namespace lld
12101232

12111233
template void lld::elf::addCapabilityRelocation<ELF32LE>(
1212-
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
1213-
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
1234+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1235+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1236+
llvm::function_ref<std::string()>, RelocationBaseSection *);
12141237
template void lld::elf::addCapabilityRelocation<ELF32BE>(
1215-
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
1216-
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
1238+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1239+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1240+
llvm::function_ref<std::string()>, RelocationBaseSection *);
12171241
template void lld::elf::addCapabilityRelocation<ELF64LE>(
1218-
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
1219-
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
1242+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1243+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1244+
llvm::function_ref<std::string()>, RelocationBaseSection *);
12201245
template void lld::elf::addCapabilityRelocation<ELF64BE>(
1221-
Ctx &ctx, Symbol *, RelType, InputSectionBase *, uint64_t, RelExpr, int64_t,
1222-
bool, llvm::function_ref<std::string()>, RelocationBaseSection *);
1246+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *>, RelType,
1247+
InputSectionBase *, uint64_t, RelExpr, int64_t, bool,
1248+
llvm::function_ref<std::string()>, RelocationBaseSection *);

lld/ELF/Arch/Cheri.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ namespace elf {
1616

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

@@ -364,11 +362,12 @@ inline uint64_t getBiasedCGPOffsetLo12(Ctx &ctx, const Symbol &sym)
364362
}
365363

366364
template <typename ELFT>
367-
void addCapabilityRelocation(Ctx &ctx, Symbol *sym, RelType type,
368-
InputSectionBase *sec, uint64_t offset,
369-
RelExpr expr, int64_t addend, bool isCallExpr,
370-
llvm::function_ref<std::string()> referencedBy,
371-
RelocationBaseSection *dynRelSec = nullptr);
365+
void addCapabilityRelocation(
366+
Ctx &ctx, llvm::PointerUnion<Symbol *, InputSectionBase *> target,
367+
RelType type, InputSectionBase *sec, uint64_t offset, RelExpr expr,
368+
int64_t addend, bool isCallExpr,
369+
llvm::function_ref<std::string()> referencedBy,
370+
RelocationBaseSection *dynRelSec = nullptr);
372371
} // namespace elf
373372
} // namespace lld
374373

0 commit comments

Comments
 (0)