diff --git a/lld/ELF/Arch/Cheri.cpp b/lld/ELF/Arch/Cheri.cpp index 45a9342fc1905..319f40137a21a 100644 --- a/lld/ELF/Arch/Cheri.cpp +++ b/lld/ELF/Arch/Cheri.cpp @@ -389,7 +389,7 @@ static uint64_t getTargetSize(const CheriCapRelocLocation &location, if (InputSectionBase *isec = dyn_cast(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()); diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 0550ddd8d4ad5..7a82a44108522 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -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" @@ -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); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index a7539598e51c5..3ed5677350d52 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -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 @@ -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(this)) { - return dr->getSize(); + return dr->getSize(forCheriCap); } // FIXME: assuming it is always shared broke this if (isa(this)) @@ -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) { diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 46c26aa693682..78b2f741439c9 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -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. @@ -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; diff --git a/lld/test/ELF/cheri/start-stop-symbols.s b/lld/test/ELF/cheri/start-stop-symbols.s new file mode 100644 index 0000000000000..adfff79df6129 --- /dev/null +++ b/lld/test/ELF/cheri/start-stop-symbols.s @@ -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)