-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LLD][ELF] Add -z execute-only-report that checks PURECODE section flags
#128883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-lld @llvm/pr-subscribers-lld-elf Author: Csanád Hajdú (Il-Capitano) Changes
Full diff: https://github.com/llvm/llvm-project/pull/128883.diff 6 Files Affected:
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",@progbits,unique,0
+.globl _start
+_start:
+ bl foo
+ bl bar
+ bl absolute
+ ret
+
+.section .text.foo,"axy",@progbits,unique,0
+.globl foo
+foo:
+ ret
+
+.section .text.bar,"ax",@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
|
| // finalizeSections does that. | ||
| finalizeSections(); | ||
| checkExecuteOnly(); | ||
| checkExecuteOnlyReport(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move into checkExecuteOnly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't do this yet, because I think that checkExecuteOnly and checkExecuteOnlyReport aside from the similar naming do different things and they should be separate.
smithp35
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a couple of suggestions over what MaskRay has already mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that the error message is not conventional. It should be
unknown -z execute-only-report= value: foo to match a few other options.
I am updating it. Sorry for making you rebase the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, let me know when it's done and I'll rebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 7e8a06c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rebased and updated the test.
`-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.
38cf844 to
ddaf54d
Compare
-z execute-only-reportchecks that all executable sections have either the SHF_AARCH64_PURECODE or SHF_ARM_PURECODE section flag set on AArch64 and ARM respectively.