Skip to content
Open
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
2 changes: 1 addition & 1 deletion lld/ELF/Arch/Cheri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ static uint64_t getTargetSize(const CheriCapRelocLocation &location,
if (InputSectionBase *isec = dyn_cast<InputSectionBase *>(target.symOrSec))
return isec->getSize();

uint64_t targetSize = target.sym()->getSize();
uint64_t targetSize = target.sym()->getSize(/*forCheriCap=*/true);
if (targetSize > INT_MAX) {
error("Insanely large symbol size for " + target.verboseToString() +
"for cap_reloc at" + location.toString());
Expand Down
6 changes: 6 additions & 0 deletions lld/ELF/LinkerScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "Arch/Cheri.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -230,6 +231,11 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) {
Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, value.type,
symValue, 0, sec);

if (value.sec && value.val == 0 && isSectionStartSymbol(cmd->name)) {
log("Treating " + cmd->name + " as a section start symbol");
newSym.isSectionStartSymbol = true;
}

Symbol *sym = symtab.insert(cmd->name);
sym->mergeProperties(newSym);
newSym.overwrite(*sym);
Expand Down
10 changes: 6 additions & 4 deletions lld/ELF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ uint64_t Symbol::getMipsCheriCapTableOffset(const InputSectionBase *isec,
in.mipsCheriCapTable->getIndex(*this, isec, offset);
}

uint64_t Defined::getSize() const {
if (LLVM_UNLIKELY(config->isCheriAbi && isSectionStartSymbol)) {
uint64_t Defined::getSize(bool forCheriCap) const {
if (LLVM_UNLIKELY((config->isCheriAbi || forCheriCap) && isSectionStartSymbol)) {
assert(value == 0 && "Bad section start symbol?");
if (!section)
return 0; // Section is not included in the output
Expand All @@ -288,9 +288,9 @@ uint64_t Defined::getSize() const {
return size;
}

uint64_t Symbol::getSize() const {
uint64_t Symbol::getSize(bool forCheriCap) const {
if (const auto *dr = dyn_cast<Defined>(this)) {
return dr->getSize();
return dr->getSize(forCheriCap);
}
// FIXME: assuming it is always shared broke this
if (isa<Undefined>(this))
Expand Down Expand Up @@ -482,6 +482,8 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
void Symbol::mergeProperties(const Symbol &other) {
if (other.exportDynamic)
exportDynamic = true;
if (other.isSectionStartSymbol)
isSectionStartSymbol = true;

// DSO symbols do not affect visibility in the output.
if (!other.isShared() && other.visibility() != STV_DEFAULT) {
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ class Symbol {
uint64_t offset) const;
uint64_t getMipsCheriCapTableOffset(const InputSectionBase *isec,
uint64_t offset) const;
uint64_t getSize() const;
uint64_t getSize(bool forCheriCap = false) const;
OutputSection *getOutputSection() const;

// The following two functions are used for symbol resolution.
Expand Down Expand Up @@ -370,7 +370,7 @@ class Defined : public Symbol {
}

static bool classof(const Symbol *s) { return s->isDefined(); }
uint64_t getSize() const;
uint64_t getSize(bool forCheriCap = false) const;
void setSize(uint64_t newSize) {
assert(!isSectionStartSymbol);
size = newSize;
Expand Down
168 changes: 168 additions & 0 deletions lld/test/ELF/cheri/start-stop-symbols.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// REQUIRES: riscv
/// Check that we correctly set (or don't set) st_size for section start symbols
/// and that the capability relocation has the correct size.
/// In hybrid mode we don't want to change the symbol table st_size value, but
/// the __cap_relocs should still have the correct size value.

// RUN: rm -rf %t && split-file %s %t && cd %t
// RUN: %riscv64_cheri_llvm-mc -filetype=obj test.s -o test-hybrid.o
// RUN: %riscv64_cheri_purecap_llvm-mc -filetype=obj test.s -o test-purecap.o

/// First check the default logic (no linker script)
// RUN: ld.lld --verbose test-hybrid.o -o test-hybrid.exe 2>&1 | FileCheck %s --check-prefix=LOG
// RUN: ld.lld --verbose test-purecap.o -o test-purecap.exe 2>&1 | FileCheck %s --check-prefix=LOG
// LOG-DAG: lld: Treating __start_mysection as a section start symbol
// LOG-DAG: lld: Treating __preinit_array_start as a section start symbol
// LOG-DAG: lld: Treating __init_array_start as a section start symbol
// LOG-DAG: lld: Treating __fini_array_start as a section start symbol
// RUN: llvm-readelf --cap-relocs --expand-relocs --symbols test-hybrid.exe | FileCheck %s --check-prefixes=CHECK,NOSCRIPT,HYBRID
// RUN: llvm-readelf --cap-relocs --expand-relocs --symbols test-purecap.exe | FileCheck %s --check-prefixes=CHECK,NOSCRIPT,PURECAP

/// And also using a custom linker script that provides the start/stop symbols
// RUN: ld.lld --verbose test-hybrid.o -o test-hybrid.exe --script test.script 2>&1 | FileCheck %s --check-prefix=LOG
// RUN: ld.lld --verbose test-purecap.o -o test-purecap.exe --script test.script 2>&1 | FileCheck %s --check-prefix=LOG
// RUN: llvm-readelf --cap-relocs --expand-relocs --symbols test-hybrid.exe | FileCheck %s --check-prefixes=CHECK,SCRIPT,HYBRID
// RUN: llvm-readelf --cap-relocs --expand-relocs --symbols test-purecap.exe | FileCheck %s --check-prefixes=CHECK,SCRIPT,PURECAP


//--- test.script
SECTIONS {
.text 0x210000: { *(.text) }
mysection : {
PROVIDE_HIDDEN(__start_mysection = .);
*(mysection);
PROVIDE_HIDDEN(__stop_mysection = .);
}
.preinit_array : {
PROVIDE_HIDDEN(__preinit_array_start = .);
*(.preinit_array);
PROVIDE_HIDDEN(__preinit_array_end = .);
}
.init_array : {
PROVIDE_HIDDEN(__init_array_start = .);
*(.init_array);
PROVIDE_HIDDEN(__init_array_end = .);
}
.fini_array : {
PROVIDE_HIDDEN(__fini_array_start = .);
*(.fini_array);
PROVIDE_HIDDEN(__fini_array_end = .);
}
.data.rel.ro : {
*(.data.rel.ro);
}
__cap_relocs : {
*(__cap_relocs);
}
}

//--- test.s

.section .preinit_array, "a", @preinit_array
.balign 1024
.8byte 0

.section .init_array, "a", @init_array
.balign 1024
.8byte 0

.section .fini_array, "a", @fini_array
.balign 1024
.8byte 0

.section mysection, "a", @progbits
.balign 1024
.8byte 0

.text
.balign 1024

.globl _start
.type _start, @function
_start: ret

.data.rel.ro

.chericap __preinit_array_start
.chericap __preinit_array_end

.chericap __init_array_start
.chericap __init_array_end

.chericap __fini_array_start
.chericap __fini_array_end

.chericap __start_mysection

.chericap __stop_mysection

/// In purecap mode, the start symbols should have size 8, in hybrid mode
/// all symbols should have a zero st_size for backwards compatibility.
// PURECAP: [[#%.16x,PREINIT_START:]] [[#START_SYM_SIZE:8]] NOTYPE LOCAL HIDDEN [[#]] __preinit_array_start
// HYBRID: [[#%.16x,PREINIT_START:]] [[#START_SYM_SIZE:0]] NOTYPE LOCAL HIDDEN [[#]] __preinit_array_start
// CHECK-DAG: [[#%.16x,PREINIT_START+8]] 0 NOTYPE LOCAL HIDDEN [[#]] __preinit_array_end
// CHECK-DAG: [[#%.16x,INIT_START:]] [[#START_SYM_SIZE]] NOTYPE LOCAL HIDDEN [[#]] __init_array_start
// CHECK-DAG: [[#%.16x,INIT_START+8]] 0 NOTYPE LOCAL HIDDEN [[#]] __init_array_end
// CHECK-DAG: [[#%.16x,FINI_START:]] [[#START_SYM_SIZE]] NOTYPE LOCAL HIDDEN [[#]] __fini_array_start
// CHECK-DAG: [[#%.16x,FINI_START+8]] 0 NOTYPE LOCAL HIDDEN [[#]] __fini_array_end
/// Without a linker script C-compatible sections names get a proected global symbol instead of local hidden
// NOSCRIPT-DAG: [[#%.16x,MY_START:]] [[#START_SYM_SIZE]] NOTYPE GLOBAL PROTECTED [[#]] __start_mysection
// NOSCRIPT-DAG: [[#%.16x,MY_START+8]] 0 NOTYPE GLOBAL PROTECTED [[#]] __stop_mysection
// SCRIPT-DAG: [[#%.16x,MY_START:]] [[#START_SYM_SIZE]] NOTYPE LOCAL HIDDEN [[#]] __start_mysection
// SCRIPT-DAG: [[#%.16x,MY_START+8]] 0 NOTYPE LOCAL HIDDEN [[#]] __stop_mysection
// CHECK: CHERI __cap_relocs [
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC:]]
// CHECK-NEXT: Base: __preinit_array_start ([[#%#X,PREINIT_START]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 8
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x10]]
// CHECK-NEXT: Base: __preinit_array_end ([[#%#X,PREINIT_START+8]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 0
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x20]]
// CHECK-NEXT: Base: __init_array_start ([[#%#X,INIT_START]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 8
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x30]]
// CHECK-NEXT: Base: __init_array_end ([[#%#X,INIT_START+8]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 0
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x40]]
// CHECK-NEXT: Base: __fini_array_start ([[#%#X,FINI_START]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 8
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x50]]
// CHECK-NEXT: Base: __fini_array_end ([[#%#X,FINI_START+8]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 0
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x60]]
// CHECK-NEXT: Base: __start_mysection ([[#%#X,MY_START]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 8
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
// CHECK-NEXT: Location: [[#%#X,FIRST_RELOC+0x70]]
// CHECK-NEXT: Base: __stop_mysection ([[#%#X,MY_START+8]])
// CHECK-NEXT: Offset: 0
// CHECK-NEXT: Length: 0
// CHECK-NEXT: Permissions: Constant (0x4000000000000000)