Skip to content

Commit 54dfada

Browse files
committed
[LLD][ELF][RISCV] Handle .note.gnu.property sections for Zicfilp/Zicfiss features
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 conflicts 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.
1 parent 52ed679 commit 54dfada

File tree

7 files changed

+853
-16
lines changed

7 files changed

+853
-16
lines changed

lld/ELF/Config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ struct Config {
235235
ReportPolicy zGcsReport = ReportPolicy::None;
236236
ReportPolicy zGcsReportDynamic = ReportPolicy::None;
237237
ReportPolicy zExecuteOnlyReport = ReportPolicy::None;
238+
ReportPolicy zZicfilpUnlabeledReport = ReportPolicy::None;
239+
ReportPolicy zZicfilpFuncSigReport = ReportPolicy::None;
240+
ReportPolicy zZicfissReport = ReportPolicy::None;
238241
bool ltoBBAddrMap;
239242
llvm::StringRef ltoBasicBlockSections;
240243
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;

lld/ELF/Driver.cpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,18 @@ static void checkOptions(Ctx &ctx) {
421421
<< "--pcrel-optimize is only supported on PowerPC64 targets";
422422
}
423423

424-
if (ctx.arg.relaxGP && ctx.arg.emachine != EM_RISCV)
425-
ErrAlways(ctx) << "--relax-gp is only supported on RISC-V targets";
424+
if (ctx.arg.emachine != EM_RISCV) {
425+
if (ctx.arg.relaxGP)
426+
ErrAlways(ctx) << "--relax-gp is only supported on RISC-V targets";
427+
if (ctx.arg.zZicfilpUnlabeledReport != ReportPolicy::None)
428+
ErrAlways(ctx) << "-z zicfilip-unlabeled-report is only supported on "
429+
"RISC-V targets";
430+
if (ctx.arg.zZicfilpFuncSigReport != ReportPolicy::None)
431+
ErrAlways(ctx) << "-z zicfilip-func-sig-report is only supported on "
432+
"RISC-V targets";
433+
if (ctx.arg.zZicfissReport != ReportPolicy::None)
434+
ErrAlways(ctx) << "-z zicfiss-report is only supported on RISC-V targets";
435+
}
426436

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

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

2905+
if (ctx.arg.emachine == EM_RISCV) {
2906+
reportUnless(ctx.arg.zZicfilpUnlabeledReport,
2907+
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
2908+
<< f
2909+
<< ": -z zicfilp-unlabeled-report: file does not have "
2910+
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED property";
2911+
2912+
reportUnless(ctx.arg.zZicfilpFuncSigReport,
2913+
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG)
2914+
<< f
2915+
<< ": -z zicfilp-func-sig-report: file does not have "
2916+
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG property";
2917+
2918+
if ((features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED) &&
2919+
(features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG))
2920+
Err(ctx) << f
2921+
<< ": file has conflicting properties: "
2922+
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED and "
2923+
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG";
2924+
2925+
reportUnless(ctx.arg.zZicfissReport,
2926+
features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)
2927+
<< f
2928+
<< ": -z zicfiss-report: file does not have "
2929+
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property";
2930+
}
2931+
28882932
if (ctx.arg.zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
28892933
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
28902934
if (ctx.arg.zBtiReport == ReportPolicy::None)

lld/ELF/InputFiles.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
970970
}
971971
// Read the following info from the .note.gnu.property section and write it to
972972
// the corresponding fields in `ObjFile`:
973-
// - Feature flags (32 bits) representing x86 or AArch64 features for
973+
// - Feature flags (32 bits) representing x86, AArch64 or RISC-V features for
974974
// hardware-assisted call flow control;
975975
// - AArch64 PAuth ABI core info (16 bytes).
976976
template <class ELFT>
@@ -979,6 +979,22 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
979979
using Elf_Nhdr = typename ELFT::Nhdr;
980980
using Elf_Note = typename ELFT::Note;
981981

982+
uint32_t featureAndType;
983+
switch (ctx.arg.emachine) {
984+
case EM_386:
985+
case EM_X86_64:
986+
featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
987+
break;
988+
case EM_AARCH64:
989+
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
990+
break;
991+
case EM_RISCV:
992+
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
993+
break;
994+
default:
995+
return;
996+
}
997+
982998
ArrayRef<uint8_t> data = sec.content();
983999
auto err = [&](const uint8_t *place) -> ELFSyncStream {
9841000
auto diag = Err(ctx);
@@ -999,10 +1015,6 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
9991015
continue;
10001016
}
10011017

1002-
uint32_t featureAndType = ctx.arg.emachine == EM_AARCH64
1003-
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
1004-
: GNU_PROPERTY_X86_FEATURE_1_AND;
1005-
10061018
// Read a body of a NOTE record, which consists of type-length-value fields.
10071019
ArrayRef<uint8_t> desc = note.getDesc(sec.addralign);
10081020
const uint8_t *base = sec.content().data();
@@ -1066,9 +1078,9 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
10661078
}
10671079

10681080
// Object files that use processor features such as Intel Control-Flow
1069-
// Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
1070-
// .note.gnu.property section containing a bitfield of feature bits like the
1071-
// GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
1081+
// Enforcement (CET), AArch64 Branch Target Identification BTI or RISC-V
1082+
// Zicfilp/Zicfiss extensions, use a .note.gnu.property section containing
1083+
// a bitfield of feature bits like the GNU_PROPERTY_X86_FEATURE_1_IBT flag.
10721084
//
10731085
// Since we merge bitmaps from multiple object files to create a new
10741086
// .note.gnu.property containing a single AND'ed bitmap, we discard an input

lld/ELF/SyntheticSections.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,15 +325,28 @@ GnuPropertySection::GnuPropertySection(Ctx &ctx)
325325
ctx.arg.wordsize) {}
326326

327327
void GnuPropertySection::writeTo(uint8_t *buf) {
328+
uint32_t featureAndType;
329+
switch (ctx.arg.emachine) {
330+
case EM_386:
331+
case EM_X86_64:
332+
featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
333+
break;
334+
case EM_AARCH64:
335+
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
336+
break;
337+
case EM_RISCV:
338+
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
339+
break;
340+
default:
341+
llvm_unreachable(
342+
"target machine does not support .note.gnu.property section");
343+
}
344+
328345
write32(ctx, buf, 4); // Name size
329346
write32(ctx, buf + 4, getSize() - 16); // Content size
330347
write32(ctx, buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
331348
memcpy(buf + 12, "GNU", 4); // Name string
332349

333-
uint32_t featureAndType = ctx.arg.emachine == EM_AARCH64
334-
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
335-
: GNU_PROPERTY_X86_FEATURE_1_AND;
336-
337350
unsigned offset = 16;
338351
if (ctx.arg.andFeatures != 0) {
339352
write32(ctx, buf + offset + 0, featureAndType); // Feature type

0 commit comments

Comments
 (0)