Skip to content

Commit 9b7b7d6

Browse files
authored
[LLD][ELF] Add -z execute-only-report that checks PURECODE section flags (#128883)
`-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.
1 parent b65e094 commit 9b7b7d6

File tree

6 files changed

+143
-4
lines changed

6 files changed

+143
-4
lines changed

lld/ELF/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ struct Config {
229229
StringRef zCetReport = "none";
230230
StringRef zPauthReport = "none";
231231
StringRef zGcsReport = "none";
232+
StringRef zExecuteOnlyReport = "none";
232233
bool ltoBBAddrMap;
233234
llvm::StringRef ltoBasicBlockSections;
234235
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;

lld/ELF/Driver.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ static void checkOptions(Ctx &ctx) {
406406
ErrAlways(ctx) << "-z gcs only supported on AArch64";
407407
}
408408

409+
if (ctx.arg.emachine != EM_AARCH64 && ctx.arg.emachine != EM_ARM &&
410+
ctx.arg.zExecuteOnlyReport != "none")
411+
ErrAlways(ctx)
412+
<< "-z execute-only-report only supported on AArch64 and ARM";
413+
409414
if (ctx.arg.emachine != EM_PPC64) {
410415
if (ctx.arg.tocOptimize)
411416
ErrAlways(ctx) << "--toc-optimize is only supported on PowerPC64 targets";
@@ -1620,10 +1625,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
16201625
ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
16211626
}
16221627

1623-
auto reports = {std::make_pair("bti-report", &ctx.arg.zBtiReport),
1624-
std::make_pair("cet-report", &ctx.arg.zCetReport),
1625-
std::make_pair("gcs-report", &ctx.arg.zGcsReport),
1626-
std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
1628+
auto reports = {
1629+
std::make_pair("bti-report", &ctx.arg.zBtiReport),
1630+
std::make_pair("cet-report", &ctx.arg.zCetReport),
1631+
std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
1632+
std::make_pair("gcs-report", &ctx.arg.zGcsReport),
1633+
std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
16271634
for (opt::Arg *arg : args.filtered(OPT_z)) {
16281635
std::pair<StringRef, StringRef> option =
16291636
StringRef(arg->getValue()).split('=');

lld/ELF/Writer.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ template <class ELFT> class Writer {
6464
void sortOrphanSections();
6565
void finalizeSections();
6666
void checkExecuteOnly();
67+
void checkExecuteOnlyReport();
6768
void setReservedSymbolSections();
6869

6970
SmallVector<std::unique_ptr<PhdrEntry>, 0> createPhdrs(Partition &part);
@@ -323,6 +324,7 @@ template <class ELFT> void Writer<ELFT>::run() {
323324
// finalizeSections does that.
324325
finalizeSections();
325326
checkExecuteOnly();
327+
checkExecuteOnlyReport();
326328

327329
// If --compressed-debug-sections is specified, compress .debug_* sections.
328330
// Do it right now because it changes the size of output sections.
@@ -2176,6 +2178,41 @@ template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
21762178
"data and code";
21772179
}
21782180

2181+
// Check which input sections of RX output sections don't have the
2182+
// SHF_AARCH64_PURECODE or SHF_ARM_PURECODE flag set.
2183+
template <class ELFT> void Writer<ELFT>::checkExecuteOnlyReport() {
2184+
if (ctx.arg.zExecuteOnlyReport == "none")
2185+
return;
2186+
2187+
auto reportUnless = [&](bool cond) -> ELFSyncStream {
2188+
if (cond)
2189+
return {ctx, DiagLevel::None};
2190+
if (ctx.arg.zExecuteOnlyReport == "error")
2191+
return {ctx, DiagLevel::Err};
2192+
if (ctx.arg.zExecuteOnlyReport == "warning")
2193+
return {ctx, DiagLevel::Warn};
2194+
return {ctx, DiagLevel::None};
2195+
};
2196+
2197+
uint64_t purecodeFlag =
2198+
ctx.arg.emachine == EM_AARCH64 ? SHF_AARCH64_PURECODE : SHF_ARM_PURECODE;
2199+
StringRef purecodeFlagName = ctx.arg.emachine == EM_AARCH64
2200+
? "SHF_AARCH64_PURECODE"
2201+
: "SHF_ARM_PURECODE";
2202+
SmallVector<InputSection *, 0> storage;
2203+
for (OutputSection *osec : ctx.outputSections) {
2204+
if (osec->getPhdrFlags() != (PF_R | PF_X))
2205+
continue;
2206+
for (InputSection *sec : getInputSections(*osec, storage)) {
2207+
if (isa<SyntheticSection>(sec))
2208+
continue;
2209+
reportUnless(sec->flags & purecodeFlag)
2210+
<< "-z execute-only-report: " << sec << " does not have "
2211+
<< purecodeFlagName << " flag set";
2212+
}
2213+
}
2214+
}
2215+
21792216
// The linker is expected to define SECNAME_start and SECNAME_end
21802217
// symbols for a few sections. This function defines them.
21812218
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: rm -rf %t && mkdir %t && cd %t
4+
// RUN: llvm-mc --triple=aarch64 --filetype=obj %s -o a.o
5+
6+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings a.o
7+
8+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning a.o 2>&1 | \
9+
// RUN: FileCheck --check-prefix=WARNING %s
10+
// RUN: ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=warning a.o 2>&1 | \
11+
// RUN: FileCheck --check-prefix=WARNING %s
12+
13+
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text) does not have SHF_AARCH64_PURECODE flag set
14+
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
15+
// WARNING: warning: -z execute-only-report: a.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
16+
// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_PURECODE flag set
17+
18+
// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error a.o 2>&1 | \
19+
// RUN: FileCheck --check-prefix=ERROR %s
20+
// RUN: not ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=error a.o 2>&1 | \
21+
// RUN: FileCheck --check-prefix=ERROR %s
22+
23+
// ERROR-NOT: error: -z execute-only-report: a.o:(.text) does not have SHF_AARCH64_PURECODE flag set
24+
// ERROR-NOT: error: -z execute-only-report: a.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
25+
// ERROR: error: -z execute-only-report: a.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
26+
// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_PURECODE flag set
27+
28+
.section .text,"axy",@progbits,unique,0
29+
.globl _start
30+
_start:
31+
bl foo
32+
bl bar
33+
bl absolute
34+
ret
35+
36+
.section .text.foo,"axy",@progbits,unique,0
37+
.globl foo
38+
foo:
39+
ret
40+
41+
.section .text.bar,"ax",@progbits,unique,0
42+
.globl bar
43+
bar:
44+
ret
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// REQUIRES: arm
2+
3+
// RUN: rm -rf %t && mkdir %t && cd %t
4+
// RUN: llvm-mc --triple=armv7 --filetype=obj %s -o a.o
5+
6+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings a.o
7+
8+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning a.o 2>&1 | \
9+
// RUN: FileCheck --check-prefix=WARNING %s
10+
11+
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text) does not have SHF_ARM_PURECODE flag set
12+
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
13+
// WARNING: warning: -z execute-only-report: a.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
14+
// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
15+
16+
// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error a.o 2>&1 | \
17+
// RUN: FileCheck --check-prefix=ERROR %s
18+
19+
// ERROR-NOT: error: -z execute-only-report: a.o:(.text) does not have SHF_ARM_PURECODE flag set
20+
// ERROR-NOT: error: -z execute-only-report: a.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
21+
// ERROR: error: -z execute-only-report: a.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
22+
// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
23+
24+
.section .text,"axy",%progbits,unique,0
25+
.globl _start
26+
_start:
27+
bl foo
28+
bl bar
29+
bl absolute
30+
bx lr
31+
32+
.section .text.foo,"axy",%progbits,unique,0
33+
.globl foo
34+
foo:
35+
bx lr
36+
37+
.section .text.bar,"ax",%progbits,unique,0
38+
.globl bar
39+
bar:
40+
bx lr

lld/test/ELF/target-specific-options.s

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,15 @@
1313
# RUN: not ld.lld %t --toc-optimize -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TOC
1414
# ERR-TOC: error: --toc-optimize is only supported on PowerPC64 targets
1515

16+
# RUN: not ld.lld %t -z execute-only-report=warning -o /dev/null 2>&1 | \
17+
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY
18+
# RUN: not ld.lld %t -z execute-only-report=error -o /dev/null 2>&1 | \
19+
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY
20+
# ERR-EXECUTE-ONLY: error: -z execute-only-report only supported on AArch64 and ARM
21+
22+
# RUN: not ld.lld %t -z execute-only-report=foo -o /dev/null 2>&1 | \
23+
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY-INVALID
24+
# ERR-EXECUTE-ONLY-INVALID: error: unknown -z execute-only-report= value: foo
25+
1626
.globl _start
1727
_start:

0 commit comments

Comments
 (0)