Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ struct Config {
ReportPolicy zGcsReport = ReportPolicy::None;
ReportPolicy zGcsReportDynamic = ReportPolicy::None;
ReportPolicy zExecuteOnlyReport = ReportPolicy::None;
ReportPolicy zZicfilpUnlabeledReport = ReportPolicy::None;
ReportPolicy zZicfilpFuncSigReport = ReportPolicy::None;
ReportPolicy zZicfissReport = ReportPolicy::None;
bool ltoBBAddrMap;
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
Expand Down
52 changes: 48 additions & 4 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,18 @@ static void checkOptions(Ctx &ctx) {
<< "--pcrel-optimize is only supported on PowerPC64 targets";
}

if (ctx.arg.relaxGP && ctx.arg.emachine != EM_RISCV)
ErrAlways(ctx) << "--relax-gp is only supported on RISC-V targets";
if (ctx.arg.emachine != EM_RISCV) {
if (ctx.arg.relaxGP)
ErrAlways(ctx) << "--relax-gp is only supported on RISC-V targets";
if (ctx.arg.zZicfilpUnlabeledReport != ReportPolicy::None)
ErrAlways(ctx) << "-z zicfilip-unlabeled-report is only supported on "
"RISC-V targets";
if (ctx.arg.zZicfilpFuncSigReport != ReportPolicy::None)
ErrAlways(ctx) << "-z zicfilip-func-sig-report is only supported on "
"RISC-V targets";
if (ctx.arg.zZicfissReport != ReportPolicy::None)
ErrAlways(ctx) << "-z zicfiss-report is only supported on RISC-V targets";
}

if (ctx.arg.emachine != EM_386 && ctx.arg.emachine != EM_X86_64 &&
ctx.arg.zCetReport != ReportPolicy::None)
Expand Down Expand Up @@ -1637,7 +1647,11 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
std::make_pair("gcs-report", &ctx.arg.zGcsReport),
std::make_pair("gcs-report-dynamic", &ctx.arg.zGcsReportDynamic),
std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
std::make_pair("pauth-report", &ctx.arg.zPauthReport),
std::make_pair("zicfilp-unlabeled-report",
&ctx.arg.zZicfilpUnlabeledReport),
std::make_pair("zicfilp-func-sig-report", &ctx.arg.zZicfilpFuncSigReport),
std::make_pair("zicfiss-report", &ctx.arg.zZicfissReport)};
bool hasGcsReportDynamic = false;
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
Expand Down Expand Up @@ -2831,9 +2845,12 @@ static void redirectSymbols(Ctx &ctx, ArrayRef<WrappedSymbol> wrapped) {
// For AArch64 PAuth-enabled object files, the core info of all of them must
// match. Missing info for some object files with matching info for remaining
// ones can be allowed (see -z pauth-report).
//
// RISC-V Zicfilp/Zicfiss extension also use the same mechanism to record
// enabled features in the GNU_PROPERTY_RISCV_FEATURE_1_AND bit mask.
static void readSecurityNotes(Ctx &ctx) {
if (ctx.arg.emachine != EM_386 && ctx.arg.emachine != EM_X86_64 &&
ctx.arg.emachine != EM_AARCH64)
ctx.arg.emachine != EM_AARCH64 && ctx.arg.emachine != EM_RISCV)
return;

ctx.arg.andFeatures = -1;
Expand Down Expand Up @@ -2885,6 +2902,33 @@ static void readSecurityNotes(Ctx &ctx) {
<< ": -z cet-report: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_SHSTK property";

if (ctx.arg.emachine == EM_RISCV) {
reportUnless(ctx.arg.zZicfilpUnlabeledReport,
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
<< f
<< ": -z zicfilp-unlabeled-report: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property";

reportUnless(ctx.arg.zZicfilpFuncSigReport,
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
<< f
<< ": -z zicfilp-func-sig-report: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property";

if ((features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) &&
(features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG))
Err(ctx) << f
<< ": file has conflicting properties: "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED and "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG";

reportUnless(ctx.arg.zZicfissReport,
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
<< f
<< ": -z zicfiss-report: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property";
}

if (ctx.arg.zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
if (ctx.arg.zBtiReport == ReportPolicy::None)
Expand Down
28 changes: 20 additions & 8 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
}
// Read the following info from the .note.gnu.property section and write it to
// the corresponding fields in `ObjFile`:
// - Feature flags (32 bits) representing x86 or AArch64 features for
// - Feature flags (32 bits) representing x86, AArch64 or RISC-V features for
// hardware-assisted call flow control;
// - AArch64 PAuth ABI core info (16 bytes).
template <class ELFT>
Expand All @@ -979,6 +979,22 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
using Elf_Nhdr = typename ELFT::Nhdr;
using Elf_Note = typename ELFT::Note;

uint32_t featureAndType;
switch (ctx.arg.emachine) {
case EM_386:
case EM_X86_64:
featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
break;
case EM_AARCH64:
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
break;
case EM_RISCV:
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
break;
default:
return;
}

ArrayRef<uint8_t> data = sec.content();
auto err = [&](const uint8_t *place) -> ELFSyncStream {
auto diag = Err(ctx);
Expand All @@ -999,10 +1015,6 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
continue;
}

uint32_t featureAndType = ctx.arg.emachine == EM_AARCH64
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
: GNU_PROPERTY_X86_FEATURE_1_AND;

// Read a body of a NOTE record, which consists of type-length-value fields.
ArrayRef<uint8_t> desc = note.getDesc(sec.addralign);
const uint8_t *base = sec.content().data();
Expand Down Expand Up @@ -1066,9 +1078,9 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
}

// Object files that use processor features such as Intel Control-Flow
// Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
// .note.gnu.property section containing a bitfield of feature bits like the
// GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
// Enforcement (CET), AArch64 Branch Target Identification BTI or RISC-V
// Zicfilp/Zicfiss extensions, use a .note.gnu.property section containing
// a bitfield of feature bits like the GNU_PROPERTY_X86_FEATURE_1_IBT flag.
//
// Since we merge bitmaps from multiple object files to create a new
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
Expand Down
21 changes: 17 additions & 4 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,15 +325,28 @@ GnuPropertySection::GnuPropertySection(Ctx &ctx)
ctx.arg.wordsize) {}

void GnuPropertySection::writeTo(uint8_t *buf) {
uint32_t featureAndType;
switch (ctx.arg.emachine) {
case EM_386:
case EM_X86_64:
featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
break;
case EM_AARCH64:
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
break;
case EM_RISCV:
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
break;
default:
llvm_unreachable(
"target machine does not support .note.gnu.property section");
}

write32(ctx, buf, 4); // Name size
write32(ctx, buf + 4, getSize() - 16); // Content size
write32(ctx, buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
memcpy(buf + 12, "GNU", 4); // Name string

uint32_t featureAndType = ctx.arg.emachine == EM_AARCH64
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
: GNU_PROPERTY_X86_FEATURE_1_AND;

unsigned offset = 16;
if (ctx.arg.andFeatures != 0) {
write32(ctx, buf + offset + 0, featureAndType); // Feature type
Expand Down
201 changes: 201 additions & 0 deletions lld/test/ELF/riscv-feature-zicfilp-func-sig.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# REQUIRES: riscv
## Test the ZICFILP func-sig feature.
## To lift maintenance burden, most tests are conducted only with 64-bit RISC-V
## Naming convention: *-s.s files enables ZICFILP func-sig.
# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc --filetype=obj --triple=riscv32 rv32-f1-s.s -o rv32-f1-s.o
# RUN: llvm-mc --filetype=obj --triple=riscv32 rv32-f2-s.s -o rv32-f2-s.o
# RUN: llvm-mc --filetype=obj --triple=riscv32 rv32-f3-s.s -o rv32-f3-s.o

# RUN: llvm-mc --filetype=obj --triple=riscv64 f1-s.s -o f1-s.o
# RUN: llvm-mc --filetype=obj --triple=riscv64 f2.s -o f2.o
# RUN: llvm-mc --filetype=obj --triple=riscv64 f2-s.s -o f2-s.o
# RUN: llvm-mc --filetype=obj --triple=riscv64 f3.s -o f3.o
# RUN: llvm-mc --filetype=obj --triple=riscv64 f3-s.s -o f3-s.o

## ZICFILP-func-sig should be enabled when it's enabled in all inputs
# RUN: ld.lld rv32-f1-s.o rv32-f2-s.o rv32-f3-s.o -o out.rv32 --fatal-warnings
# RUN: llvm-readelf -n out.rv32 | FileCheck --check-prefix=ZICFILP %s
# RUN: ld.lld f1-s.o f2-s.o f3-s.o -o out --fatal-warnings
# RUN: llvm-readelf -n out | FileCheck --check-prefix=ZICFILP %s
# RUN: ld.lld f1-s.o f3-s.o --shared -o out.so --fatal-warnings
# RUN: llvm-readelf -n out.so | FileCheck --check-prefix=ZICFILP %s
# ZICFILP: Properties: RISC-V feature: ZICFILP-func-sig

## ZICFILP-func-sig should not be enabled if it's not enabled in at least one
## input
# RUN: ld.lld f1-s.o f2.o f3-s.o -o out.no --fatal-warnings
# RUN: llvm-readelf -n out.no | count 0
# RUN: ld.lld f2-s.o f3.o --shared -o out.no.so --fatal-warnings
# RUN: llvm-readelf -n out.no.so | count 0

## zicfilp-func-sig-report should report any input files that don't have the
## ZICFILP-func-sig property
# RUN: ld.lld f1-s.o f2.o f3-s.o -z zicfilp-func-sig-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
# RUN: not ld.lld f2-s.o f3.o --shared -z zicfilp-func-sig-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
# RUN: ld.lld f1-s.o f2-s.o f3-s.o -z zicfilp-func-sig-report=warning 2>&1 | count 0
# REPORT-WARN: warning: f2.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property
# REPORT-ERROR: error: f3.o: -z zicfilp-func-sig-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property

## An invalid -z zicfilp-func-sig-report option should give an error
# RUN: not ld.lld f2-s.o -z zicfilp-func-sig-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
# INVALID: error: unknown -z zicfilp-func-sig-report= value: x

#--- rv32-f1-s.s

.section ".note.gnu.property", "a"
.balign 4
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 4
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 4
ndesc_end:

.text
.globl _start
.type f1,%function
f1:
call f2
ret

#--- f1-s.s

.section ".note.gnu.property", "a"
.balign 8
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 8
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 8
ndesc_end:

.text
.globl _start
.type f1,%function
f1:
call f2
ret

#--- f2.s

.text
.globl f2
.type f2,@function
f2:
.globl f3
.type f3, @function
call f3
ret

#--- rv32-f2-s.s

.section ".note.gnu.property", "a"
.balign 4
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 4
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 4
ndesc_end:

.text
.globl f2
.type f2,@function
f2:
.globl f3
.type f3, @function
call f3
ret

#--- f2-s.s

.section ".note.gnu.property", "a"
.balign 8
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 8
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 8
ndesc_end:

.text
.globl f2
.type f2,@function
f2:
.globl f3
.type f3, @function
call f3
ret

#--- f3.s

.text
.globl f3
.type f3,@function
f3:
ret

#--- rv32-f3-s.s

.section ".note.gnu.property", "a"
.balign 4
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 4
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 4
ndesc_end:

.text
.globl f3
.type f3,@function
f3:
ret

#--- f3-s.s

.section ".note.gnu.property", "a"
.balign 8
.4byte 4
.4byte (ndesc_end - ndesc_begin)
.4byte 0x5 // NT_GNU_PROPERTY_TYPE_0
.asciz "GNU"
ndesc_begin:
.balign 8
.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
.4byte 4
.4byte 4 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
.balign 8
ndesc_end:

.text
.globl f3
.type f3,@function
f3:
ret
Loading
Loading