From a932cd409b861582902211690b497cafc774bee6 Mon Sep 17 00:00:00 2001 From: David Bolvansky Date: Mon, 30 Jul 2018 17:02:46 +0000 Subject: [PATCH] [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 --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 10 ++++++++++ lld/ELF/Options.td | 4 ++++ lld/ELF/Writer.cpp | 11 +++++++++++ lld/test/ELF/execute-only-mixed-data.s | 26 ++++++++++++++++++++++++++ lld/test/ELF/execute-only.s | 10 ++++++++++ 6 files changed, 62 insertions(+) create mode 100644 lld/test/ELF/execute-only-mixed-data.s create mode 100644 lld/test/ELF/execute-only.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index ec804c5296bc9..997fade64777a 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -133,6 +133,7 @@ struct Configuration { bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; + bool ExecuteOnly; bool ExportDynamic; bool FixCortexA53Errata843419; bool GcSections; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 1fc552f011b64..7794abce85e92 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -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); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 73457db8332f8..492b42d90bf78 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -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)">; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 91741f6eaf5b9..d3b4116da98b7 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1608,6 +1608,15 @@ template void Writer::finalizeSections() { if (auto *Sec = dyn_cast(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; diff --git a/lld/test/ELF/execute-only-mixed-data.s b/lld/test/ELF/execute-only-mixed-data.s new file mode 100644 index 0000000000000..6ef62368123f7 --- /dev/null +++ b/lld/test/ELF/execute-only-mixed-data.s @@ -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 diff --git a/lld/test/ELF/execute-only.s b/lld/test/ELF/execute-only.s new file mode 100644 index 0000000000000..7a825cb7a1883 --- /dev/null +++ b/lld/test/ELF/execute-only.s @@ -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