Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 11 additions & 4 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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('=');
Expand Down
33 changes: 33 additions & 0 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -323,6 +324,7 @@ template <class ELFT> void Writer<ELFT>::run() {
// finalizeSections does that.
finalizeSections();
checkExecuteOnly();
checkExecuteOnlyReport();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move into checkExecuteOnly

Copy link
Contributor Author

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.


// If --compressed-debug-sections is specified, compress .debug_* sections.
// Do it right now because it changes the size of output sections.
Expand Down Expand Up @@ -2176,6 +2178,37 @@ 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.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 (!isa<SyntheticSection>(sec))
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() {
Expand Down
44 changes: 44 additions & 0 deletions lld/test/ELF/aarch64-execute-only-report.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// REQUIRES: aarch64

// RUN: rm -rf %t && mkdir %t && cd %t
// RUN: llvm-mc --triple=aarch64 --filetype=obj %s -o a.o

// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings a.o

// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning a.o 2>&1 | \
// RUN: FileCheck --check-prefix=WARNING %s
// RUN: ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=warning a.o 2>&1 | \
// RUN: FileCheck --check-prefix=WARNING %s

// WARNING-NOT: warning: -z execute-only-report: a.o:(.text) does not have SHF_AARCH64_PURECODE flag set
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
// WARNING: warning: -z execute-only-report: a.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

// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error a.o 2>&1 | \
// RUN: FileCheck --check-prefix=ERROR %s
// RUN: not ld.lld --defsym absolute=0xf0000000 --execute-only -z execute-only-report=error a.o 2>&1 | \
// RUN: FileCheck --check-prefix=ERROR %s

// ERROR-NOT: error: -z execute-only-report: a.o:(.text) does not have SHF_AARCH64_PURECODE flag set
// ERROR-NOT: error: -z execute-only-report: a.o:(.text.foo) does not have SHF_AARCH64_PURECODE flag set
// ERROR: error: -z execute-only-report: a.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
40 changes: 40 additions & 0 deletions lld/test/ELF/arm-execute-only-report.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// REQUIRES: arm

// RUN: rm -rf %t && mkdir %t && cd %t
// RUN: llvm-mc --triple=armv7 --filetype=obj %s -o a.o

// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=none --fatal-warnings a.o

// RUN: ld.lld --defsym absolute=0xf0000000 -z execute-only-report=warning a.o 2>&1 | \
// RUN: FileCheck --check-prefix=WARNING %s

// WARNING-NOT: warning: -z execute-only-report: a.o:(.text) does not have SHF_ARM_PURECODE flag set
// WARNING-NOT: warning: -z execute-only-report: a.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
// WARNING: warning: -z execute-only-report: a.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

// RUN: not ld.lld --defsym absolute=0xf0000000 -z execute-only-report=error a.o 2>&1 | \
// RUN: FileCheck --check-prefix=ERROR %s

// ERROR-NOT: error: -z execute-only-report: a.o:(.text) does not have SHF_ARM_PURECODE flag set
// ERROR-NOT: error: -z execute-only-report: a.o:(.text.foo) does not have SHF_ARM_PURECODE flag set
// ERROR: error: -z execute-only-report: a.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
10 changes: 10 additions & 0 deletions lld/test/ELF/target-specific-options.s
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,15 @@
# RUN: not ld.lld %t --toc-optimize -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TOC
# ERR-TOC: error: --toc-optimize is only supported on PowerPC64 targets

# RUN: not ld.lld %t -z execute-only-report=warning -o /dev/null 2>&1 | \
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY
# RUN: not ld.lld %t -z execute-only-report=error -o /dev/null 2>&1 | \
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY
# ERR-EXECUTE-ONLY: error: -z execute-only-report only supported on AArch64 and ARM

# RUN: not ld.lld %t -z execute-only-report=foo -o /dev/null 2>&1 | \
# RUN: FileCheck %s --check-prefix=ERR-EXECUTE-ONLY-INVALID
# ERR-EXECUTE-ONLY-INVALID: error: unknown -z execute-only-report= value: foo

.globl _start
_start:
Loading