Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -61,6 +61,9 @@ // For tracking ARM Float Argument PCS enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; +// For -z *stack +enum class GnuStackKind { None, Exec, NoExec }; + struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; @@ -189,7 +192,6 @@ bool WriteAddends; bool ZCombreloc; bool ZCopyreloc; - bool ZExecstack; bool ZGlobal; bool ZHazardplt; bool ZInitfirst; @@ -205,6 +207,7 @@ bool ZText; bool ZRetpolineplt; bool ZWxneeded; + GnuStackKind ZGnustack; DiscardPolicy Discard; ICFLevel ICF; OrphanHandlingPolicy OrphanHandling; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -344,6 +344,20 @@ return Default; } +static GnuStackKind getZGnuStack(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered_reverse(OPT_z)) { + if (StringRef("execstack") == Arg->getValue()) + return GnuStackKind::Exec; + if (StringRef("noexecstack") == Arg->getValue()) + return GnuStackKind::NoExec; + if (StringRef("nognustack") == Arg->getValue()) + return GnuStackKind::None; + } + + // default + return GnuStackKind::NoExec; +} + static bool isKnownZFlag(StringRef S) { return S == "combreloc" || S == "copyreloc" || S == "defs" || S == "execstack" || S == "global" || S == "hazardplt" || @@ -351,10 +365,11 @@ S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" || S == "nodelete" || S == "nodlopen" || S == "noexecstack" || - S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || - S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || - S == "rodynamic" || S == "text" || S == "wxneeded" || - S.startswith("max-page-size=") || S.startswith("stack-size="); + S == "nognustack" || S == "nokeep-text-section-prefix" || + S == "norelro" || S == "notext" || S == "now" || S == "origin" || + S == "relro" || S == "retpolineplt" || S == "rodynamic" || + S == "text" || S == "wxneeded" || S.startswith("max-page-size=") || + S.startswith("stack-size="); } // Report an error for an unknown -z option. @@ -873,8 +888,8 @@ Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); - Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); Config->ZGlobal = hasZOption(Args, "global"); + Config->ZGnustack = getZGnuStack(Args); Config->ZHazardplt = hasZOption(Args, "hazardplt"); Config->ZInitfirst = hasZOption(Args, "initfirst"); Config->ZInterpose = hasZOption(Args, "interpose"); Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -2019,14 +2019,16 @@ if (OutputSection *Cmd = findSection(".openbsd.randomdata")) AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); - // PT_GNU_STACK is a special section to tell the loader to make the - // pages for the stack non-executable. If you really want an executable - // stack, you can pass -z execstack, but that's not recommended for - // security reasons. - unsigned Perm = PF_R | PF_W; - if (Config->ZExecstack) - Perm |= PF_X; - AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; + if (Config->ZGnustack != GnuStackKind::None) { + // PT_GNU_STACK is a special section to tell the loader to make the + // pages for the stack non-executable. If you really want an executable + // stack, you can pass -z execstack, but that's not recommended for + // security reasons. + unsigned Perm = PF_R | PF_W; + if (Config->ZGnustack == GnuStackKind::Exec) + Perm |= PF_X; + AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; + } // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable // is expected to perform W^X violations, such as calling mprotect(2) or Index: lld/docs/ld.lld.1 =================================================================== --- lld/docs/ld.lld.1 +++ lld/docs/ld.lld.1 @@ -578,6 +578,10 @@ .Dv DF_1_NOOPEN flag to indicate that the object may not be opened by .Xr dlopen 3 . +.It Cm nognustack +Do not emit the +.Dv PT_GNU_STACK +segment. .It Cm norelro Do not indicate that portions of the object shold be mapped read-only after initial relocation processing. Index: lld/test/ELF/gnustack.s =================================================================== --- lld/test/ELF/gnustack.s +++ lld/test/ELF/gnustack.s @@ -10,6 +10,9 @@ # RUN: ld.lld %t1 -o %t -z noexecstack # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s +# RUN: ld.lld %t1 -o %t -z nognustack +# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=NOGNUSTACK %s + # RW: Type: PT_GNU_STACK # RW-NEXT: Offset: 0x0 # RW-NEXT: VirtualAddress: 0x0 @@ -35,5 +38,7 @@ # RWX-NEXT: ] # RWX-NEXT: Alignment: 0 +# NOGNUSTACK-NOT: Type: PT_GNU_STACK + .globl _start _start: