Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 9 additions & 6 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ RISCV::RISCV() {
tlsOffsetRel = R_RISCV_TLS_DTPREL32;
tlsGotRel = R_RISCV_TLS_TPREL32;
}
gotRel = symbolicRel;
if (config->isCheriAbi)
gotRel = *cheriCapRel;
else
gotRel = symbolicRel;
absPointerRel = symbolicRel;

// .got[0] = _DYNAMIC
Expand Down Expand Up @@ -288,8 +291,7 @@ void RISCV::writePlt(uint8_t *buf, const Symbol &sym,
// nop
uint32_t ptrload = config->isCheriAbi ? config->is64 ? CLC_128 : CLC_64
: config->is64 ? LD : LW;
uint32_t entryva = config->isCheriAbi ? sym.getCapTableVA(in.plt.get(), 0)
: sym.getGotPltVA();
uint32_t entryva = config->isCheriAbi ? sym.getGotVA() : sym.getGotPltVA();
uint32_t offset = entryva - pltEntryAddr;
write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
write32le(buf + 4, itype(ptrload, X_T3, X_T3, lo12(offset)));
Expand Down Expand Up @@ -363,12 +365,13 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
return config->relax ? R_RELAX_HINT : R_NONE;
case R_RISCV_CHERI_CAPABILITY:
return R_CHERI_CAPABILITY;
// TODO: Deprecate and eventually remove these
case R_RISCV_CHERI_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_ENTRY_PC;
return R_GOT_PC;
case R_RISCV_CHERI_TLS_IE_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC;
return R_GOT_PC;
case R_RISCV_CHERI_TLS_GD_CAPTAB_PCREL_HI20:
return R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC;
return R_TLSGD_PC;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
Expand Down
16 changes: 0 additions & 16 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,22 +869,6 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE:
assert(a == 0 && "capability table index relocs should not have addends");
return sym.getCapTableOffset(isec, offset);
case R_CHERI_CAPABILITY_TABLE_ENTRY_PC: {
assert(a == 0 && "capability table entry relocs should not have addends");
return sym.getCapTableVA(isec, offset) - p;
}
case R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC: {
assert(a == 0 && "capability table index relocs should not have addends");
uint64_t capTableOffset =
in.cheriCapTable->getDynTlsOffset(sym);
return ElfSym::cheriCapabilityTable->getVA() + capTableOffset - p;
}
case R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC: {
assert(a == 0 && "capability table index relocs should not have addends");
uint64_t capTableOffset =
in.cheriCapTable->getTlsOffset(sym);
return ElfSym::cheriCapabilityTable->getVA() + capTableOffset - p;
}
case R_CHERI_CAPABILITY_TABLE_REL:
if (!ElfSym::cheriCapabilityTable) {
error("cannot compute difference between non-existent "
Expand Down
62 changes: 28 additions & 34 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,20 +890,21 @@ template <class PltSection, class GotPltSection>
static void addPltEntry(PltSection &plt, GotPltSection &gotPlt,
RelocationBaseSection &rel, RelType type, Symbol &sym) {
plt.addEntry(sym);
if (config->isCheriAbi) {
// TODO: More normal .got.plt rather than piggy-backing on .captable. We
// pass R_CHERI_CAPABILITY_TABLE_INDEX rather than the more obvious
// R_CHERI_CAPABILITY_TABLE_INDEX_CALL to force dynamic relocations into
// .rela.dyn rather than .rela.plt so no rtld changes are needed, as the
// latter doesn't really achieve anything without lazy binding.
in.cheriCapTable->addEntry(sym, R_CHERI_CAPABILITY_TABLE_INDEX, &plt, 0);
} else {
gotPlt.addEntry(sym);
rel.addReloc({type, &gotPlt, sym.getGotPltOffset(),
sym.isPreemptible ? DynamicReloc::AgainstSymbol
: DynamicReloc::AddendOnlyWithTargetVA,
sym, 0, R_ABS});
}

// For CHERI-RISC-V we mark the symbol NEEDS_GOT so it will end up in .got as
// a function pointer, and uses .rela.dyn rather than .rela.plt, so no rtld
// changes are needed.
//
// TODO: More normal .got.plt with lazy-binding rather than piggy-backing on
// .got once rtld supports it.
if (config->emachine == EM_RISCV && config->isCheriAbi)
return;

gotPlt.addEntry(sym);
rel.addReloc({type, &gotPlt, sym.getGotPltOffset(),
sym.isPreemptible ? DynamicReloc::AgainstSymbol
: DynamicReloc::AddendOnlyWithTargetVA,
sym, 0, R_ABS});
}

static void addGotEntry(Symbol &sym) {
Expand All @@ -918,8 +919,12 @@ static void addGotEntry(Symbol &sym) {
}

// Otherwise, the value is either a link-time constant or the load base
// plus a constant.
if (!config->isPic || isAbsolute(sym))
// plus a constant. For CHERI it always requires run-time initialisation.
if (config->isCheriAbi) {
invokeELFT(addCapabilityRelocation, &sym, *target->cheriCapRel,
in.got.get(), off, R_CHERI_CAPABILITY, 0, false,
[] { return ""; });
} else if (!config->isPic || isAbsolute(sym))
in.got->addConstant({R_ABS, target->symbolicRel, off, 0, &sym});
else
addRelativeReloc(*in.got, off, sym, 0, R_ABS, target->symbolicRel);
Expand Down Expand Up @@ -975,7 +980,6 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_ENTRY_PC,
R_CHERI_CAPABILITY_TABLE_REL,
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
Expand Down Expand Up @@ -1086,8 +1090,7 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
if (oneof<R_CHERI_CAPABILITY_TABLE_INDEX,
R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_ENTRY_PC>(expr)) {
R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE>(expr)) {
std::lock_guard<std::mutex> lock(relocMutex);
in.cheriCapTable->addEntry(sym, expr, sec, offset);
// Write out the index into the instruction
Expand All @@ -1112,6 +1115,9 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
}
} else if (needsPlt(expr)) {
sym.setFlags(NEEDS_PLT);
// See addPltEntry
if (config->emachine == EM_RISCV && config->isCheriAbi)
sym.setFlags(NEEDS_GOT);
} else if (LLVM_UNLIKELY(isIfunc)) {
sym.setFlags(HAS_DIRECT_RELOC);
}
Expand Down Expand Up @@ -1255,6 +1261,9 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
"' cannot be preempted; recompile with -fPIE" +
getLocation(*sec, sym, offset));
sym.setFlags(NEEDS_COPY | NEEDS_PLT);
// See addPltEntry
if (config->emachine == EM_RISCV && config->isCheriAbi)
sym.setFlags(NEEDS_GOT);
sec->addReloc({expr, type, offset, addend, &sym});
return;
}
Expand Down Expand Up @@ -1345,21 +1354,6 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
config->emachine != EM_RISCV &&
!c.file->ppc64DisableTLSRelax;

// No targets currently support TLS relaxation, so we can avoid duplicating
// much of the logic below for the captable.
if (expr == R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC) {
std::lock_guard<std::mutex> lock(relocMutex);
in.cheriCapTable->addDynTlsEntry(sym);
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
if (expr == R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC) {
std::lock_guard<std::mutex> lock(relocMutex);
in.cheriCapTable->addTlsEntry(sym);
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}

// If we are producing an executable and the symbol is non-preemptable, it
// must be defined and the code sequence can be relaxed to use Local-Exec.
//
Expand Down
3 changes: 0 additions & 3 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,6 @@ enum RelExpr {
R_CHERI_CAPABILITY_TABLE_INDEX_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL,
R_CHERI_CAPABILITY_TABLE_INDEX_CALL_SMALL_IMMEDIATE,
R_CHERI_CAPABILITY_TABLE_ENTRY_PC,
R_CHERI_CAPABILITY_TABLE_TLSGD_ENTRY_PC,
R_CHERI_CAPABILITY_TABLE_TLSIE_ENTRY_PC,
R_CHERI_CAPABILITY_TABLE_REL, // relative offset to _CHERI_CAPABILITY_TABLE_
R_MIPS_CHERI_CAPTAB_TLSGD,
R_MIPS_CHERI_CAPTAB_TLSLD,
Expand Down
11 changes: 9 additions & 2 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ GotSection::GotSection()

void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
void GotSection::addEntry(Symbol &sym) {
// TODO: Separate out TLS IE entries for CHERI so we can pack them more
// efficiently rather than consuming a whole capability-sized slot for an
// integer.
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().gotIdx = numEntries++;
}
Expand All @@ -674,8 +677,12 @@ bool GotSection::addTlsDescEntry(Symbol &sym) {
bool GotSection::addDynTlsEntry(Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().tlsGdIdx = numEntries;
// Global Dynamic TLS entries take two GOT slots.
numEntries += 2;
// Global Dynamic TLS entries take two GOT slots, except on CHERI where they
// can be packed into one GOT slot.
if (config->isCheriAbi)
++numEntries;
else
numEntries += 2;
return true;
}

Expand Down
38 changes: 21 additions & 17 deletions lld/test/ELF/cheri/riscv/plt.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# RUN: ld.lld %t.32.o %t1.32.so -z separate-code -o %t.32
# RUN: llvm-readelf -S -s %t.32 | FileCheck --check-prefixes=SEC,NM %s
# RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=RELOC32 %s
# RUN: llvm-readelf -x .captable %t.32 | FileCheck --check-prefix=CAPTAB32 %s
# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=GOT32 %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=DIS,DIS32 %s

# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj %t1.s -o %t1.64.o
Expand All @@ -16,7 +16,7 @@
# RUN: ld.lld %t.64.o %t1.64.so -z separate-code -o %t.64
# RUN: llvm-readelf -S -s %t.64 | FileCheck --check-prefixes=SEC,NM %s
# RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=RELOC64 %s
# RUN: llvm-readelf -x .captable %t.64 | FileCheck --check-prefix=CAPTAB64 %s
# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=GOT64 %s
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=DIS,DIS64 %s

# SEC: .plt PROGBITS {{0*}}00011030
Expand All @@ -27,19 +27,21 @@
# NM: {{0*}}00000000 0 FUNC WEAK DEFAULT UND weak

# RELOC32: .rela.dyn {
# RELOC32-NEXT: 0x12000 R_RISCV_CHERI_CAPABILITY bar 0x0
# RELOC32-NEXT: 0x12008 R_RISCV_CHERI_CAPABILITY weak 0x0
# RELOC32-NEXT: 0x12068 R_RISCV_CHERI_CAPABILITY bar 0x0
# RELOC32-NEXT: 0x12070 R_RISCV_CHERI_CAPABILITY weak 0x0
# RELOC32-NEXT: }
# CAPTAB32: section '.captable'
# CAPTAB32-NEXT: 0x00012000 00000000 00000000 00000000 00000000
# GOT32: section '.got'
# GOT32-NEXT: 0x00012060 00200100 00000000 00000000 00000000
# GOT32-NEXT: 0x00012070 00000000 00000000

# RELOC64: .rela.dyn {
# RELOC64-NEXT: 0x12000 R_RISCV_CHERI_CAPABILITY bar 0x0
# RELOC64-NEXT: 0x12010 R_RISCV_CHERI_CAPABILITY weak 0x0
# RELOC64-NEXT: 0x120D0 R_RISCV_CHERI_CAPABILITY bar 0x0
# RELOC64-NEXT: 0x120E0 R_RISCV_CHERI_CAPABILITY weak 0x0
# RELOC64-NEXT: }
# CAPTAB64: section '.captable'
# CAPTAB64-NEXT: 0x00012000 00000000 00000000 00000000 00000000
# CAPTAB64-NEXT: 0x00012010 00000000 00000000 00000000 00000000
# GOT64: section '.got'
# GOT64-NEXT: 0x000120c0 00200100 00000000 00000000 00000000
# GOT64-NEXT: 0x000120d0 00000000 00000000 00000000 00000000
# GOT64-NEXT: 0x000120e0 00000000 00000000 00000000 00000000

# DIS: <_start>:
## Direct call
Expand All @@ -62,17 +64,19 @@
# DIS: <.plt>:
# DIS-NEXT: ...

## 32-bit: &.captable[bar]-. = 0x12000-0x11050 = 4096*1-80
## 32-bit: &.got[bar]-. = 0x12068-0x11050 = 4096*1+24
## 64-bit: &.got[bar]-. = 0x120d0-0x11050 = 4096*1+128
# DIS: 11050: auipcc ct3, 1
# DIS32-NEXT: lc ct3, -80(ct3)
# DIS64-NEXT: lc ct3, -80(ct3)
# DIS32-NEXT: lc ct3, 24(ct3)
# DIS64-NEXT: lc ct3, 128(ct3)
# DIS-NEXT: jalr ct1, ct3
# DIS-NEXT: nop

## 32-bit: &.captable[weak]-. = 0x12008-0x11060 = 4096*1-88
## 32-bit: &.got[weak]-. = 0x12070-0x11060 = 4096*1+16
## 64-bit: &.got[weak]-. = 0x120e0-0x11060 = 4096*1+128
# DIS: 11060: auipcc ct3, 1
# DIS32-NEXT: lc ct3, -88(ct3)
# DIS64-NEXT: lc ct3, -80(ct3)
# DIS32-NEXT: lc ct3, 16(ct3)
# DIS64-NEXT: lc ct3, 128(ct3)
# DIS-NEXT: jalr ct1, ct3
# DIS-NEXT: nop

Expand Down
77 changes: 77 additions & 0 deletions lld/test/ELF/cheri/riscv/reloc-got.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# REQUIRES: riscv
# RUN: echo '.globl b; b:' | %riscv32_cheri_purecap_llvm-mc -filetype=obj - -o %t1.o
# RUN: ld.lld -shared %t1.o -soname=t1.so -o %t1.so

# RUN: %riscv32_cheri_purecap_llvm-mc -filetype=obj -position-independent %s -o %t.o
# RUN: ld.lld %t.o %t1.so -o %t
# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC32 %s
# RUN: llvm-readobj -r --cap-relocs %t | FileCheck --check-prefix=RELOC32 %s
# RUN: llvm-nm %t | FileCheck --check-prefix=NM32 %s
# RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX32 %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS32 %s

# RUN: echo '.globl b; b:' | %riscv64_cheri_purecap_llvm-mc -filetype=obj - -o %t1.o
# RUN: ld.lld -shared %t1.o -soname=t1.so -o %t1.so

# RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj -position-independent %s -o %t.o
# RUN: ld.lld %t.o %t1.so -o %t
# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC64 %s
# RUN: llvm-readobj -r --cap-relocs %t | FileCheck --check-prefix=RELOC64 %s
# RUN: llvm-nm %t | FileCheck --check-prefix=NM64 %s
# RUN: llvm-readobj -x .got %t | FileCheck --check-prefix=HEX64 %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck --check-prefix=DIS64 %s

# SEC32: .got PROGBITS 00012230 000230 000018
# SEC64: .got PROGBITS 00000000000123a0 0003a0 000030

# RELOC32: .rela.dyn {
# RELOC32-NEXT: 0x12238 R_RISCV_CHERI_CAPABILITY b 0x0
# RELOC32-NEXT: }
# RELOC32: CHERI __cap_relocs [
# RELOC32-NEXT: 0x012240 Base: 0x13248 (a+0) Length: 4 Perms: Object
# RELOC32-NEXT: ]

# RELOC64: .rela.dyn {
# RELOC64-NEXT: 0x123B0 R_RISCV_CHERI_CAPABILITY b 0x0
# RELOC64-NEXT: }
# RELOC64: CHERI __cap_relocs [
# RELOC64-NEXT: 0x0123c0 Base: 0x133d0 (a+0) Length: 4 Perms: Object
# RELOC64-NEXT: ]

# NM32: 00013248 d a
# NM64: 00000000000133d0 d a

## .got[0] = _DYNAMIC
## .got[1] = 0 (relocated by R_RISCV_CHERI_CAPABILITY at run time)
## .got[2] = 0 (relocated by __cap_relocs at run time)
# HEX32: section '.got':
# HEX32: 0x00012230 c0210100 00000000 00000000 00000000
# HEX32: 0x00012240 00000000 00000000

# HEX64: section '.got':
# HEX64: 0x000123a0 c0220100 00000000 00000000 00000000
# HEX64: 0x000123b0 00000000 00000000 00000000 00000000
# HEX64: 0x000123c0 00000000 00000000 00000000 00000000

## &.got[2]-. = 0x12240-0x111b0 = 4096*1+144
# DIS32: 111b0: auipcc ca0, 1
# DIS32-NEXT: lc ca0, 144(ca0)
## &.got[1]-. = 0x12238-0x111b8 = 4096*1+128
# DIS32: 111b8: auipcc ca0, 1
# DIS32-NEXT: lc ca0, 128(ca0)

## &.got[2]-. = 0x123c0-0x112b0 = 4096*1+272
# DIS64: 112b0: auipcc ca0, 1
# DIS64-NEXT: lc ca0, 272(ca0)
## &.got[1]-. = 0x123b0-0x112b8 = 4096*1+248
# DIS64: 112b8: auipcc ca0, 1
# DIS64-NEXT: lc ca0, 248(ca0)

clgc ca0, a
clgc ca0, b

.data
a:
## An undefined reference of _GLOBAL_OFFSET_TABLE_ causes .got[0] to be
## allocated to store _DYNAMIC.
.long _GLOBAL_OFFSET_TABLE_ - .
Loading