Skip to content

Commit 69048e3

Browse files
committed
[LLD][ELF] Add -z execute-only-report that checks PURECODE flags
`-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 b356a30 commit 69048e3

File tree

6 files changed

+140
-4
lines changed

6 files changed

+140
-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: 34 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,38 @@ 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.emachine != EM_AARCH64 && ctx.arg.emachine != EM_ARM) ||
2185+
ctx.arg.zExecuteOnlyReport == "none")
2186+
return;
2187+
2188+
auto reportUnless = [&](bool cond) -> ELFSyncStream {
2189+
if (cond)
2190+
return {ctx, DiagLevel::None};
2191+
if (ctx.arg.zExecuteOnlyReport == "error")
2192+
return {ctx, DiagLevel::Err};
2193+
if (ctx.arg.zExecuteOnlyReport == "warning")
2194+
return {ctx, DiagLevel::Warn};
2195+
return {ctx, DiagLevel::None};
2196+
};
2197+
2198+
uint64_t purecodeFlag =
2199+
ctx.arg.emachine == EM_AARCH64 ? SHF_AARCH64_PURECODE : SHF_ARM_PURECODE;
2200+
StringRef purecodeFlagName = ctx.arg.emachine == EM_AARCH64
2201+
? "SHF_AARCH64_PURECODE"
2202+
: "SHF_ARM_PURECODE";
2203+
SmallVector<InputSection *, 0> storage;
2204+
for (OutputSection *osec : ctx.outputSections)
2205+
if (osec->getPhdrFlags() == (PF_R | PF_X))
2206+
for (InputSection *sec : getInputSections(*osec, storage))
2207+
if (sec->file && sec->file->getName() != "<internal>")
2208+
reportUnless(sec->flags & purecodeFlag)
2209+
<< "-z execute-only-report: " << sec << " does not have "
2210+
<< purecodeFlagName << " flag set";
2211+
}
2212+
21792213
// The linker is expected to define SECNAME_start and SECNAME_end
21802214
// symbols for a few sections. This function defines them.
21812215
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: llvm-mc --triple=aarch64 --filetype=obj -o %t.o %s
4+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings %t.o -o /dev/null
5+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
6+
// RUN: | FileCheck --check-prefix=WARNING %s
7+
// RUN: ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
8+
// RUN: | FileCheck --check-prefix=WARNING %s
9+
// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error %t.o -o /dev/null 2>&1 \
10+
// RUN: | FileCheck --check-prefix=ERROR %s
11+
// RUN: not ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=error %t.o -o /dev/null 2>&1 \
12+
// RUN: | FileCheck --check-prefix=ERROR %s
13+
14+
// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_AARCH64_PURECODE flag set
15+
// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
16+
// WARNING: warning: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
17+
// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_PURECODE flag set
18+
19+
// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_AARCH64_PURECODE flag set
20+
// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
21+
// ERROR: error: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_AARCH64_PURECODE flag set
22+
// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_AARCH64_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+
ret
31+
32+
.section .text.foo,"axy",@progbits,unique,0
33+
.globl foo
34+
foo:
35+
ret
36+
37+
.section .text.bar,"ax",@progbits,unique,0
38+
.globl bar
39+
bar:
40+
ret
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// REQUIRES: arm
2+
3+
// RUN: llvm-mc --triple=armv7 --filetype=obj -o %t.o %s
4+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings %t.o -o /dev/null
5+
// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
6+
// RUN: | FileCheck --check-prefix=WARNING %s
7+
// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error %t.o -o /dev/null 2>&1 \
8+
// RUN: | FileCheck --check-prefix=ERROR %s
9+
10+
// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_ARM_PURECODE flag set
11+
// WARNING-NOT: warning: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
12+
// WARNING: warning: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
13+
// WARNING-NOT: warning: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
14+
15+
// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text) does not have SHF_ARM_PURECODE flag set
16+
// ERROR-NOT: error: -z execute-only-report: {{.*}}.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
17+
// ERROR: error: -z execute-only-report: {{.*}}.o:(.text.bar) does not have SHF_ARM_PURECODE flag set
18+
// ERROR-NOT: error: -z execute-only-report: <internal>:({{.*}}) does not have SHF_ARM_PURECODE flag set
19+
20+
.section .text,"axy",%progbits,unique,0
21+
.globl _start
22+
_start:
23+
bl foo
24+
bl bar
25+
bl absolute
26+
bx lr
27+
28+
.section .text.foo,"axy",%progbits,unique,0
29+
.globl foo
30+
foo:
31+
bx lr
32+
33+
.section .text.bar,"ax",%progbits,unique,0
34+
.globl bar
35+
bar:
36+
bx lr
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// REQUIRES: x86
2+
3+
// RUN: llvm-mc --triple=x86_64 --filetype=obj -o %t.o %s
4+
// RUN: not ld.lld -z execute-only-report=warning %t.o -o /dev/null 2>&1 \
5+
// RUN: | FileCheck %s
6+
// RUN: not ld.lld -z execute-only-report=error %t.o -o /dev/null 2>&1 \
7+
// RUN: | FileCheck %s
8+
9+
// CHECK: error: -z execute-only-report only supported on AArch64 and ARM
10+
11+
// RUN: not ld.lld -z execute-only-report=foo %t.o -o /dev/null 2>&1 \
12+
// RUN: | FileCheck --check-prefix=INVALID %s
13+
14+
// INVALID: error: -z execute-only-report= parameter foo is not recognized
15+
16+
.globl _start
17+
_start:
18+
ret

0 commit comments

Comments
 (0)