[lld] [ELF] Add '-z nognustack' opt to suppress emitting PT_GNU_STACK
Add a new '-z nognustack' option that suppresses emitting PT_GNU_STACK segment. This segment is not supported at all on NetBSD (stack is always non-executable), and the option is meant to be used to disable emitting it. Differential Revision: https://reviews.llvm.org/D56554
This commit is contained in:
parent
6a93a12a8d
commit
2a0fcae3d4
|
@ -64,6 +64,9 @@ enum class ARMVFPArgKind { Default, Base, VFP, ToolChain };
|
||||||
// For -z noseparate-code, -z separate-code and -z separate-loadable-segments.
|
// For -z noseparate-code, -z separate-code and -z separate-loadable-segments.
|
||||||
enum class SeparateSegmentKind { None, Code, Loadable };
|
enum class SeparateSegmentKind { None, Code, Loadable };
|
||||||
|
|
||||||
|
// For -z *stack
|
||||||
|
enum class GnuStackKind { None, Exec, NoExec };
|
||||||
|
|
||||||
struct SymbolVersion {
|
struct SymbolVersion {
|
||||||
llvm::StringRef name;
|
llvm::StringRef name;
|
||||||
bool isExternCpp;
|
bool isExternCpp;
|
||||||
|
@ -216,6 +219,7 @@ struct Configuration {
|
||||||
bool zRetpolineplt;
|
bool zRetpolineplt;
|
||||||
bool zWxneeded;
|
bool zWxneeded;
|
||||||
DiscardPolicy discard;
|
DiscardPolicy discard;
|
||||||
|
GnuStackKind zGnustack;
|
||||||
ICFLevel icf;
|
ICFLevel icf;
|
||||||
OrphanHandlingPolicy orphanHandling;
|
OrphanHandlingPolicy orphanHandling;
|
||||||
SortSectionPolicy sortSection;
|
SortSectionPolicy sortSection;
|
||||||
|
|
|
@ -394,6 +394,20 @@ static SeparateSegmentKind getZSeparate(opt::InputArgList &args) {
|
||||||
return SeparateSegmentKind::None;
|
return SeparateSegmentKind::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
static bool isKnownZFlag(StringRef s) {
|
||||||
return s == "combreloc" || s == "copyreloc" || s == "defs" ||
|
return s == "combreloc" || s == "copyreloc" || s == "defs" ||
|
||||||
s == "execstack" || s == "global" || s == "hazardplt" ||
|
s == "execstack" || s == "global" || s == "hazardplt" ||
|
||||||
|
@ -402,6 +416,7 @@ static bool isKnownZFlag(StringRef s) {
|
||||||
s == "separate-code" || s == "separate-loadable-segments" ||
|
s == "separate-code" || s == "separate-loadable-segments" ||
|
||||||
s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
|
s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
|
||||||
s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
|
s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
|
||||||
|
s == "nognustack" ||
|
||||||
s == "nokeep-text-section-prefix" || s == "norelro" ||
|
s == "nokeep-text-section-prefix" || s == "norelro" ||
|
||||||
s == "noseparate-code" || s == "notext" || s == "now" ||
|
s == "noseparate-code" || s == "notext" || s == "now" ||
|
||||||
s == "origin" || s == "relro" || s == "retpolineplt" ||
|
s == "origin" || s == "relro" || s == "retpolineplt" ||
|
||||||
|
@ -951,6 +966,7 @@ static void readConfigs(opt::InputArgList &args) {
|
||||||
config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
|
config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
|
||||||
config->zExecstack = getZFlag(args, "execstack", "noexecstack", false);
|
config->zExecstack = getZFlag(args, "execstack", "noexecstack", false);
|
||||||
config->zGlobal = hasZOption(args, "global");
|
config->zGlobal = hasZOption(args, "global");
|
||||||
|
config->zGnustack = getZGnuStack(args);
|
||||||
config->zHazardplt = hasZOption(args, "hazardplt");
|
config->zHazardplt = hasZOption(args, "hazardplt");
|
||||||
config->zIfuncNoplt = hasZOption(args, "ifunc-noplt");
|
config->zIfuncNoplt = hasZOption(args, "ifunc-noplt");
|
||||||
config->zInitfirst = hasZOption(args, "initfirst");
|
config->zInitfirst = hasZOption(args, "initfirst");
|
||||||
|
|
|
@ -2172,14 +2172,16 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) {
|
||||||
if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo))
|
if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo))
|
||||||
addHdr(PT_OPENBSD_RANDOMIZE, cmd->getPhdrFlags())->add(cmd);
|
addHdr(PT_OPENBSD_RANDOMIZE, cmd->getPhdrFlags())->add(cmd);
|
||||||
|
|
||||||
// PT_GNU_STACK is a special section to tell the loader to make the
|
if (config->zGnustack != GnuStackKind::None) {
|
||||||
// pages for the stack non-executable. If you really want an executable
|
// PT_GNU_STACK is a special section to tell the loader to make the
|
||||||
// stack, you can pass -z execstack, but that's not recommended for
|
// pages for the stack non-executable. If you really want an executable
|
||||||
// security reasons.
|
// stack, you can pass -z execstack, but that's not recommended for
|
||||||
unsigned perm = PF_R | PF_W;
|
// security reasons.
|
||||||
if (config->zExecstack)
|
unsigned perm = PF_R | PF_W;
|
||||||
perm |= PF_X;
|
if (config->zGnustack == GnuStackKind::Exec)
|
||||||
addHdr(PT_GNU_STACK, perm)->p_memsz = config->zStackSize;
|
perm |= PF_X;
|
||||||
|
addHdr(PT_GNU_STACK, perm)->p_memsz = config->zStackSize;
|
||||||
|
}
|
||||||
|
|
||||||
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
|
// 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
|
// is expected to perform W^X violations, such as calling mprotect(2) or
|
||||||
|
|
|
@ -655,6 +655,11 @@ Set the
|
||||||
flag to indicate that the object may not be opened by
|
flag to indicate that the object may not be opened by
|
||||||
.Xr dlopen 3 .
|
.Xr dlopen 3 .
|
||||||
.Pp
|
.Pp
|
||||||
|
.It Cm nognustack
|
||||||
|
Do not emit the
|
||||||
|
.Dv PT_GNU_STACK
|
||||||
|
segment.
|
||||||
|
.Pp
|
||||||
.It Cm norelro
|
.It Cm norelro
|
||||||
Do not indicate that portions of the object shold be mapped read-only
|
Do not indicate that portions of the object shold be mapped read-only
|
||||||
after initial relocation processing.
|
after initial relocation processing.
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
# RUN: ld.lld %t1 -o %t -z noexecstack
|
# RUN: ld.lld %t1 -o %t -z noexecstack
|
||||||
# RUN: llvm-readobj --program-headers -S %t | FileCheck --check-prefix=RW %s
|
# 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: Type: PT_GNU_STACK
|
||||||
# RW-NEXT: Offset: 0x0
|
# RW-NEXT: Offset: 0x0
|
||||||
# RW-NEXT: VirtualAddress: 0x0
|
# RW-NEXT: VirtualAddress: 0x0
|
||||||
|
@ -35,5 +38,7 @@
|
||||||
# RWX-NEXT: ]
|
# RWX-NEXT: ]
|
||||||
# RWX-NEXT: Alignment: 0
|
# RWX-NEXT: Alignment: 0
|
||||||
|
|
||||||
|
# NOGNUSTACK-NOT: Type: PT_GNU_STACK
|
||||||
|
|
||||||
.globl _start
|
.globl _start
|
||||||
_start:
|
_start:
|
||||||
|
|
Loading…
Reference in New Issue