ELF: Make .note.GNU-stack more compatible with traditional linkers.
With this patch, lld creates PT_GNU_STACK segments only when all input
files have .note.GNU-stack sections. This is in line with other linkers
with a minor difference (we don't care about .note.GNU-stack rwx bits as
you can always remove .note.GNU-stack sections instead of setting x bit.)
At least, NetBSD loader does not understand PT_GNU_STACK segments and
reject any executables that have the section. This patch makes lld
compatible with such operating systems.
llvm-svn: 253797
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index e3eeddd..8baf28c 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -63,7 +63,7 @@
bool StripAll;
bool SysvHash = true;
bool Verbose;
- bool ZExecStack;
+ bool ZExecStack = false;
bool ZNodelete;
bool ZNow;
bool ZOrigin;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index f1aaa5b..c76aa86 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -173,7 +173,6 @@
Config->SoName = getString(Args, OPT_soname);
Config->Sysroot = getString(Args, OPT_sysroot);
- Config->ZExecStack = hasZOption(Args, "execstack");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
@@ -277,6 +276,14 @@
for (StringRef S : Config->Undefined)
Symtab.addUndefinedOpt(S);
+ // "-z execstack" value is inferred from input object files (it's false
+ // if all input files have .note.GNU-stack section). Explicit options
+ // override the inferred default value.
+ if (hasZOption(Args, "execstack"))
+ Config->ZExecStack = true;
+ if (hasZOption(Args, "noexecstack"))
+ Config->ZExecStack = false;
+
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index deb5a65..9930f28 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -174,6 +174,7 @@
uint64_t Size = this->ELFObj.getNumSections();
Sections.resize(Size);
unsigned I = -1;
+ bool HasGnuStack = false;
const ELFFile<ELFT> &Obj = this->ELFObj;
for (const Elf_Shdr &Sec : Obj.sections()) {
++I;
@@ -224,21 +225,25 @@
}
break;
}
- default: {
+ default:
ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec);
error(NameOrErr);
- if (*NameOrErr == ".note.GNU-stack")
+ StringRef Name = *NameOrErr;
+ if (Name == ".note.GNU-stack") {
Sections[I] = &InputSection<ELFT>::Discarded;
- else if (*NameOrErr == ".eh_frame")
+ HasGnuStack = true;
+ } else if (Name == ".eh_frame") {
Sections[I] = new (this->Alloc) EHInputSection<ELFT>(this, &Sec);
- else if (shouldMerge<ELFT>(Sec))
+ } else if (shouldMerge<ELFT>(Sec)) {
Sections[I] = new (this->Alloc) MergeInputSection<ELFT>(this, &Sec);
- else
+ } else {
Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
+ }
break;
}
- }
}
+ if (!HasGnuStack)
+ Config->ZExecStack = true;
}
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 98e9f24..a993fc2 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -881,10 +881,13 @@
copyPhdr(PH, Out<ELFT>::Dynamic);
}
- Elf_Phdr *PH = &Phdrs[++PhdrIdx];
- PH->p_type = PT_GNU_STACK;
- PH->p_flags = Config->ZExecStack ? toPhdrFlags(SHF_WRITE | SHF_EXECINSTR)
- : toPhdrFlags(SHF_WRITE);
+ // PT_GNU_STACK is a special section to tell the loader to make the
+ // pages for the stack non-executable.
+ if (!Config->ZExecStack) {
+ Elf_Phdr *PH = &Phdrs[++PhdrIdx];
+ PH->p_type = PT_GNU_STACK;
+ PH->p_flags = PF_R | PF_W;
+ }
// Fix up PT_INTERP as we now know the address of .interp section.
if (Interp) {
@@ -908,11 +911,13 @@
// Returns the number of PHDR entries.
template <class ELFT> int Writer<ELFT>::getPhdrsNum() const {
bool Tls = false;
- int I = 3; // 3 for PT_PHDR, first PT_LOAD and PT_GNU_STACK
+ int I = 2; // 2 for PT_PHDR and first PT_LOAD
if (needsInterpSection())
++I;
if (isOutputDynamic())
++I;
+ if (!Config->ZExecStack)
+ ++I;
uintX_t Last = PF_R;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
if (!needsPhdr<ELFT>(Sec))