[lld] 1728405 - [LLD][ELF][RISCV][Zicfilp] Handle .note.gnu.property sections for Zicfilp/Zicfiss features (#127193)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 5 19:32:21 PDT 2025
Author: Ming-Yi Lai
Date: 2025-06-06T10:32:17+08:00
New Revision: 1728405b13781f2e2696ed2679c9d05101116fa2
URL: https://github.com/llvm/llvm-project/commit/1728405b13781f2e2696ed2679c9d05101116fa2
DIFF: https://github.com/llvm/llvm-project/commit/1728405b13781f2e2696ed2679c9d05101116fa2.diff
LOG: [LLD][ELF][RISCV][Zicfilp] Handle .note.gnu.property sections for Zicfilp/Zicfiss features (#127193)
+ When all relocatable files contain a `.note.gnu.property` section
(with `NT_GNU_PROPERTY_TYPE_0` notes) which contains a
`GNU_PROPERTY_RISCV_FEATURE_1_AND` property in which the
`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED`/`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG`/`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SS`
bit is set:
+ The output file will contain a `.note.gnu.property` section with the
bit set
+ A `PT_GNU_PROPERTY` program header is created to encompass the
`.note.gnu.property` section
+ If `-z zicfilp-unlabeled-report=[warning|error]`/`-z
zicfilp-func-sig-report=[warning|error]`/`-z
zicfiss-report=[warning|error]` is specified, the linker will report a
warning or error for any relocatable file lacking the feature bit
RISC-V Zicfilp/Zicfiss features indicate their adoptions as bits in the
`.note.gnu.property` section of ELF files. This patch enables LLD to
process the information correctly by parsing, checking and merging the
bits from all input ELF files and writing the merged result to the
output ELF file.
These feature bits are encoded as a mask in each input ELF files and
intended to be "and"-ed together to check that all input files support a
particular feature.
For RISC-V Zicfilp features, there are 2 conflicting bits allocated:
`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED` and
`GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG`. They represent the
adoption of the forward edge protection of control-flow integrity with
the "unlabeled" or "func-sig" policy. Since these 2 policies conflicts
with each other, these 2 bits also conflict with each other. This patch
adds the `-z zicfilp-unlabeled-report=[none|warning|error]` and `-z
zicfilp-func-sig-report=[none|warning|error]` commandline options to
make LLD report files that do not have the expected bits toggled on.
For RISC-V Zicfiss feature, there's only one bit allocated:
`GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS`. This bit indicates that the ELF
file supports Zicfiss-based shadow stack. This patch adds the `-z
zicfiss-report=[none|warning|error]` commandline option to make LLD
report files that do not have the expected bit toggled on.
The adoption of the `.note.gnu.property` section for RISC-V targets can
be found in the psABI PR
<https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/417>
(`CFI_LP_UNLABELED` and `CFI_SS`) and PR
<https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/434>
(`CFI_LP_FUNC_SIG`).
Added:
lld/test/ELF/riscv-feature-zicfilp-func-sig.s
lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
lld/test/ELF/riscv-feature-zicfiss.s
Modified:
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/InputFiles.cpp
lld/ELF/SyntheticSections.cpp
Removed:
################################################################################
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f0e9592d85dd6..0a52dfe6901bd 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -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;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6150fe072156f..12dac82c614a7 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -419,8 +419,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)
@@ -1635,7 +1645,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 =
@@ -2829,9 +2843,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;
@@ -2883,6 +2900,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)
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 12a77736aba7f..44e77bf57183f 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -968,7 +968,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>
@@ -977,6 +977,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);
@@ -997,10 +1013,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();
@@ -1064,9 +1076,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
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index c21fce0ce15ec..785a56cdb349e 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -322,15 +322,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
diff --git a/lld/test/ELF/riscv-feature-zicfilp-func-sig.s b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
new file mode 100644
index 0000000000000..f68fbddfa6026
--- /dev/null
+++ b/lld/test/ELF/riscv-feature-zicfilp-func-sig.s
@@ -0,0 +1,193 @@
+# 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, at 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, at 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, at function
+f2:
+ .globl f3
+ .type f3, @function
+ call f3
+ ret
+
+#--- f3.s
+.text
+.globl f3
+.type f3, at 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, at 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, at function
+f3:
+ ret
diff --git a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
new file mode 100644
index 0000000000000..0fcd8538d24a1
--- /dev/null
+++ b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
@@ -0,0 +1,221 @@
+# REQUIRES: riscv
+## Test the ZICFILP unlabeled feature.
+## To lift maintenance burden, most tests are conducted only with 64-bit RISC-V
+## Naming convention: *-s.s files enables ZICFILP unlabeled.
+## Naming convention: *-c.s files enables both of the conflicting ZICFILP unlabeled and ZICFILP func-sig features.
+# 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 f1-c.s -o f1-c.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-unlabeled 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-unlabeled
+
+## ZICFILP-unlabeled 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-unlabeled-report should report any input files that don't have the
+## ZICFILP-unlabeled property
+# RUN: ld.lld f1-s.o f2.o f3-s.o -z zicfilp-unlabeled-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: not ld.lld f2-s.o f3.o --shared -z zicfilp-unlabeled-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: ld.lld f1-s.o f2-s.o f3-s.o -z zicfilp-unlabeled-report=warning 2>&1 | count 0
+# REPORT-WARN: warning: f2.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
+# REPORT-ERROR: error: f3.o: -z zicfilp-unlabeled-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property
+
+## An invalid -z zicfilp-unlabeled-report option should give an error
+# RUN: not ld.lld f2-s.o -z zicfilp-unlabeled-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# INVALID: error: unknown -z zicfilp-unlabeled-report= value: x
+
+## ZICFILP-unlabeled and ZICFILP-func-sig should conflict with each other
+# RUN: not ld.lld f1-c.o 2>&1 | FileCheck --check-prefix=CONFLICT %s
+# CONFLICT: error: f1-c.o: file has conflicting properties: GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED and GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG
+
+#--- 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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 8
+ndesc_end:
+
+.text
+.globl _start
+.type f1,%function
+f1:
+ call f2
+ ret
+
+#--- f1-c.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 5 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED | 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, at 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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 4
+ndesc_end:
+
+.text
+.globl f2
+.type f2, at 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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 8
+ndesc_end:
+
+.text
+.globl f2
+.type f2, at function
+f2:
+ .globl f3
+ .type f3, @function
+ call f3
+ ret
+
+#--- f3.s
+.text
+.globl f3
+.type f3, at 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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 4
+ndesc_end:
+
+.text
+.globl f3
+.type f3, at 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 1 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 8
+ndesc_end:
+
+.text
+.globl f3
+.type f3, at function
+f3:
+ ret
diff --git a/lld/test/ELF/riscv-feature-zicfiss.s b/lld/test/ELF/riscv-feature-zicfiss.s
new file mode 100644
index 0000000000000..4623522f5ed79
--- /dev/null
+++ b/lld/test/ELF/riscv-feature-zicfiss.s
@@ -0,0 +1,193 @@
+# REQUIRES: riscv
+## Test the ZICFISS feature.
+## To lift maintenance burden, most tests are conducted only with 64-bit RISC-V
+## Naming convention: *-s.s files enable ZICFISS.
+# 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
+
+## ZICFISS 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=ZICFISS %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=ZICFISS %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=ZICFISS %s
+# ZICFISS: Properties: RISC-V feature: ZICFISS
+
+## ZICFISS 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
+
+## zicfiss-report should report any input files that don't have the zicfiss
+## property
+# RUN: ld.lld f1-s.o f2.o f3-s.o -z zicfiss-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
+# RUN: not ld.lld f2-s.o f3.o --shared -z zicfiss-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
+# RUN: ld.lld f1-s.o f2-s.o f3-s.o -z zicfiss-report=warning 2>&1 | count 0
+# RUN: ld.lld f1-s.o f2-s.o f3-s.o -z zicfiss-report=error 2>&1 | count 0
+# REPORT-WARN: warning: f2.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
+# REPORT-ERROR: error: f3.o: -z zicfiss-report: file does not have GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property
+
+## An invalid -z zicfiss-report option should give an error
+# RUN: not ld.lld f2-s.o f3-s.o -z zicfiss-report=x 2>&1 | FileCheck --check-prefix=INVALID %s
+# INVALID: error: unknown -z zicfiss-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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.balign 8
+ndesc_end:
+
+.text
+.globl _start
+.type f1,%function
+f1:
+ call f2
+ ret
+
+#--- f2.s
+.text
+.globl f2
+.type f2, at 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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.balign 4
+ndesc_end:
+
+.text
+.globl f2
+.type f2, at 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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.balign 8
+ndesc_end:
+
+.text
+.globl f2
+.type f2, at function
+f2:
+ .globl f3
+ .type f3, @function
+ call f3
+ ret
+
+#--- f3.s
+.text
+.globl f3
+.type f3, at 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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.balign 4
+ndesc_end:
+
+.text
+.globl f3
+.type f3, at 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 2 // GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
+.balign 8
+ndesc_end:
+
+.text
+.globl f3
+.type f3, at function
+f3:
+ ret
More information about the llvm-commits
mailing list