[lld] [LLD][ELF] Add `-z execute-only-report` that checks PURECODE section flags (PR #128883)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 26 06:50:05 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
Author: Csanád Hajdú (Il-Capitano)
<details>
<summary>Changes</summary>
`-z execute-only-report` checks that all executable sections have either the SHF_AARCH64_PURECODE or SHF_ARM_PURECODE section flag set on AArch64 and ARM respectively.
---
Full diff: https://github.com/llvm/llvm-project/pull/128883.diff
6 Files Affected:
- (modified) lld/ELF/Config.h (+1)
- (modified) lld/ELF/Driver.cpp (+11-4)
- (modified) lld/ELF/Writer.cpp (+34)
- (added) lld/test/ELF/aarch64-execute-only-report.s (+40)
- (added) lld/test/ELF/arm-execute-only-report.s (+36)
- (added) lld/test/ELF/execute-only-report-error.s (+18)
``````````diff
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f132b11b20c63..b5872b85efd3a 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -229,6 +229,7 @@ struct Config {
StringRef zCetReport = "none";
StringRef zPauthReport = "none";
StringRef zGcsReport = "none";
+ StringRef zExecuteOnlyReport = "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 70a293875f27b..8cf588ef27b09 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -406,6 +406,11 @@ static void checkOptions(Ctx &ctx) {
ErrAlways(ctx) << "-z gcs only supported on AArch64";
}
+ if (ctx.arg.emachine != EM_AARCH64 && ctx.arg.emachine != EM_ARM &&
+ ctx.arg.zExecuteOnlyReport != "none")
+ ErrAlways(ctx)
+ << "-z execute-only-report only supported on AArch64 and ARM";
+
if (ctx.arg.emachine != EM_PPC64) {
if (ctx.arg.tocOptimize)
ErrAlways(ctx) << "--toc-optimize is only supported on PowerPC64 targets";
@@ -1620,10 +1625,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
}
- auto reports = {std::make_pair("bti-report", &ctx.arg.zBtiReport),
- std::make_pair("cet-report", &ctx.arg.zCetReport),
- std::make_pair("gcs-report", &ctx.arg.zGcsReport),
- std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
+ auto reports = {
+ std::make_pair("bti-report", &ctx.arg.zBtiReport),
+ std::make_pair("cet-report", &ctx.arg.zCetReport),
+ std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
+ std::make_pair("gcs-report", &ctx.arg.zGcsReport),
+ std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a2c49343e5c8d..c747a5b5e1239 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -64,6 +64,7 @@ template <class ELFT> class Writer {
void sortOrphanSections();
void finalizeSections();
void checkExecuteOnly();
+ void checkExecuteOnlyReport();
void setReservedSymbolSections();
SmallVector<std::unique_ptr<PhdrEntry>, 0> createPhdrs(Partition &part);
@@ -323,6 +324,7 @@ template <class ELFT> void Writer<ELFT>::run() {
// finalizeSections does that.
finalizeSections();
checkExecuteOnly();
+ checkExecuteOnlyReport();
// If --compressed-debug-sections is specified, compress .debug_* sections.
// Do it right now because it changes the size of output sections.
@@ -2177,6 +2179,38 @@ template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
"data and code";
}
+// Check which input sections of RX output sections don't have the
+// SHF_AARCH64_PURECODE or SHF_ARM_PURECODE flag set.
+template <class ELFT> void Writer<ELFT>::checkExecuteOnlyReport() {
+ if ((ctx.arg.emachine != EM_AARCH64 && ctx.arg.emachine != EM_ARM) ||
+ ctx.arg.zExecuteOnlyReport == "none")
+ return;
+
+ auto reportUnless = [&](bool cond) -> ELFSyncStream {
+ if (cond)
+ return {ctx, DiagLevel::None};
+ if (ctx.arg.zExecuteOnlyReport == "error")
+ return {ctx, DiagLevel::Err};
+ if (ctx.arg.zExecuteOnlyReport == "warning")
+ return {ctx, DiagLevel::Warn};
+ return {ctx, DiagLevel::None};
+ };
+
+ uint64_t purecodeFlag =
+ ctx.arg.emachine == EM_AARCH64 ? SHF_AARCH64_PURECODE : SHF_ARM_PURECODE;
+ StringRef purecodeFlagName = ctx.arg.emachine == EM_AARCH64
+ ? "SHF_AARCH64_PURECODE"
+ : "SHF_ARM_PURECODE";
+ SmallVector<InputSection *, 0> storage;
+ for (OutputSection *osec : ctx.outputSections)
+ if (osec->getPhdrFlags() == (PF_R | PF_X))
+ for (InputSection *sec : getInputSections(*osec, storage))
+ if (sec->file && sec->file->getName() != "<internal>")
+ reportUnless(sec->flags & purecodeFlag)
+ << "-z execute-only-report: " << sec << " does not have "
+ << purecodeFlagName << " flag set";
+}
+
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
diff --git a/lld/test/ELF/aarch64-execute-only-report.s b/lld/test/ELF/aarch64-execute-only-report.s
new file mode 100644
index 0000000000000..e56eed819d12b
--- /dev/null
+++ b/lld/test/ELF/aarch64-execute-only-report.s
@@ -0,0 +1,40 @@
+// REQUIRES: aarch64
+
+// RUN: llvm-mc --triple=aarch64 --filetype=obj -o %t.o %s
+// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings %t.o -o /dev/null
+// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=WARNING %s
+// RUN: ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=WARNING %s
+// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=ERROR %s
+// RUN: not ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=error %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=ERROR %s
+
+// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_AARCH64_PURECODE flag set
+// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
+// WARNING: warning: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
+// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_PURECODE flag set
+
+// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_AARCH64_PURECODE flag set
+// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
+// ERROR: error: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
+// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_PURECODE flag set
+
+.section .text,"axy", at progbits,unique,0
+.globl _start
+_start:
+ bl foo
+ bl bar
+ bl absolute
+ ret
+
+.section .text.foo,"axy", at progbits,unique,0
+.globl foo
+foo:
+ ret
+
+.section .text.bar,"ax", at progbits,unique,0
+.globl bar
+bar:
+ ret
diff --git a/lld/test/ELF/arm-execute-only-report.s b/lld/test/ELF/arm-execute-only-report.s
new file mode 100644
index 0000000000000..1676a8f654552
--- /dev/null
+++ b/lld/test/ELF/arm-execute-only-report.s
@@ -0,0 +1,36 @@
+// REQUIRES: arm
+
+// RUN: llvm-mc --triple=armv7 --filetype=obj -o %t.o %s
+// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings %t.o -o /dev/null
+// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=WARNING %s
+// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=ERROR %s
+
+// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_ARM_PURECODE flag set
+// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
+// WARNING: warning: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
+// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
+
+// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_ARM_PURECODE flag set
+// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
+// ERROR: error: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
+// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
+
+.section .text,"axy",%progbits,unique,0
+.globl _start
+_start:
+ bl foo
+ bl bar
+ bl absolute
+ bx lr
+
+.section .text.foo,"axy",%progbits,unique,0
+.globl foo
+foo:
+ bx lr
+
+.section .text.bar,"ax",%progbits,unique,0
+.globl bar
+bar:
+ bx lr
diff --git a/lld/test/ELF/execute-only-report-error.s b/lld/test/ELF/execute-only-report-error.s
new file mode 100644
index 0000000000000..91afd4edfc0d2
--- /dev/null
+++ b/lld/test/ELF/execute-only-report-error.s
@@ -0,0 +1,18 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc --triple=x86_64 --filetype=obj -o %t.o %s
+// RUN: not ld.lld -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck %s
+// RUN: not ld.lld -z execute-only-report=error %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck %s
+
+// CHECK: error: -z execute-only-report only supported on AArch64 and ARM
+
+// RUN: not ld.lld -z execute-only-report=foo %t.o -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix=INVALID %s
+
+// INVALID: error: -z execute-only-report= parameter foo is not recognized
+
+.globl _start
+_start:
+ ret
``````````
</details>
https://github.com/llvm/llvm-project/pull/128883
More information about the llvm-commits
mailing list