[AArch64] Support execute-only LOAD segments.

Summary:
This adds an LLD flag to mark executable LOAD segments execute-only for AArch64 targets. 

In AArch64 the expectation is that code is execute-only compatible, so this just adds a linker option to enforce this.

Patch by: ivanlozano (Ivan Lozano)

Reviewers: srhines, echristo, peter.smith, eugenis, javed.absar, espindola, ruiu

Reviewed By: ruiu

Subscribers: dokyungs, emaste, arichardson, kristof.beyls, llvm-commits

Differential Revision: https://reviews.llvm.org/D49456

llvm-svn: 338271
This commit is contained in:
David Bolvansky 2018-07-30 17:02:46 +00:00
parent 2fa7fb14ea
commit a932cd409b
6 changed files with 62 additions and 0 deletions

View File

@ -133,6 +133,7 @@ struct Configuration {
bool EhFrameHdr;
bool EmitRelocs;
bool EnableNewDtags;
bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
bool GcSections;

View File

@ -302,6 +302,14 @@ static void checkOptions(opt::InputArgList &Args) {
if (Config->Pie)
error("-r and -pie may not be used together");
}
if (Config->ExecuteOnly) {
if (Config->EMachine != EM_AARCH64)
error("-execute-only is only supported on AArch64 targets");
if (Config->SingleRoRx && !Script->HasSectionsCommand)
error("-execute-only and -no-rosegment cannot be used together");
}
}
static const char *getReproduceOption(opt::InputArgList &Args) {
@ -747,6 +755,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->EnableNewDtags =
Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
Config->ExecuteOnly =
Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
Config->ExportDynamic =
Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
Config->FilterList = args::getStrings(Args, OPT_filter);

View File

@ -131,6 +131,10 @@ def error_unresolved_symbols: F<"error-unresolved-symbols">,
defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm execute_only: B<"execute-only",
"Do not mark executable sections readable",
"Mark executable sections readable (default)">;
defm export_dynamic: B<"export-dynamic",
"Put symbols in the dynamic symbol table",
"Do not put symbols in the dynamic symbol table (default)">;

View File

@ -1608,6 +1608,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
// Ensure data sections are not mixed with executable sections when
// -execute-only is used.
if (Config->ExecuteOnly)
for (OutputSection *OS : OutputSections)
if (OS->Flags & SHF_EXECINSTR)
for (InputSection *IS : getInputSections(OS))
if (!(IS->Flags & SHF_EXECINSTR))
error("-execute-only does not support intermingling data and code");
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
@ -1767,6 +1776,8 @@ static bool needsPtLoad(OutputSection *Sec) {
static uint64_t computeFlags(uint64_t Flags) {
if (Config->Omagic)
return PF_R | PF_W | PF_X;
if (Config->ExecuteOnly && (Flags & PF_X))
return Flags & ~PF_R;
if (Config->SingleRoRx && !(Flags & PF_W))
return Flags | PF_X;
return Flags;

View File

@ -0,0 +1,26 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
// RUN: echo "SECTIONS \
// RUN: { \
// RUN: .text : { *(.text) *(.rodata.foo) } \
// RUN: .rodata : { *(.rodata.bar) } \
// RUN: }" > %t.lds
// RUN: not ld.lld -T%t.lds %t.o -o %t -execute-only 2>&1 | FileCheck %s
// RUN: echo "SECTIONS \
// RUN: { \
// RUN: .text : { *(.text) } \
// RUN: .rodata : { *(.rodata.bar) *(.rodata.foo) } \
// RUN: }" > %t.lds
// RUN: ld.lld -T%t.lds %t.o -o %t -execute-only 2>&1
// CHECK: -execute-only does not support intermingling data and code
br lr
.section .rodata.foo
.word 0x1
.section .rodata.bar
.word 0x2

View File

@ -0,0 +1,10 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
// RUN: ld.lld -Ttext=0xcafe0000 %t.o -o %t.so -shared -execute-only
// RUN: llvm-readelf -l %t.so | FileCheck %s
// CHECK: LOAD {{.*}} 0x00000000cafe0000 0x000004 0x000004 E 0x{{.*}}
// CHECK-NOT: LOAD {{.*}} 0x00000000cafe0000 0x000004 0x000004 R E 0x{{.*}}
br lr