summaryrefslogtreecommitdiff
path: root/lld/ELF/LinkerScript.cpp
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2023-11-01 22:35:28 -0700
committerGitHub <noreply@github.com>2023-11-01 22:35:28 -0700
commita40f651a065ef28fee17bc1f22cce08247eff950 (patch)
tree7427f1bb89aa1683211182ff7897f445a37e38ba /lld/ELF/LinkerScript.cpp
parentbd29197fd8448265dbf8e370a8a21a477cd50f5a (diff)
[ELF] adjustOutputSections: don't copy SHF_EXECINSTR when an output does not contain input sections (#70911)
For an output section with no input section, GNU ld eliminates the output section when there are only symbol assignments (e.g. `.foo : { symbol = 42; }`) but not for `.foo : { . += 42; }` (`SHF_ALLOC|SHF_WRITE`). We choose to retain such an output section with a symbol assignment (unless unreferenced `PROVIDE`). We copy the previous section flag (see https://reviews.llvm.org/D37736) to hopefully make the current PT_LOAD segment extend to the current output section: * decrease the number of PT_LOAD segments * If a new PT_LOAD segment is introduced without a page-size alignment as a separator, there may be a run-time crash. However, this `flags` copying behavior is not suitable for `.foo : { . += 42; }` when `flags` contains `SHF_EXECINSTR`. The executable bit is surprising (https://discourse.llvm.org/t/lld-output-section-flag-assignment-behavior/74359). I think we should drop SHF_EXECINSTR when copying `flags`. The risk is a code section followed by `.foo : { symbol = 42; }` will be broken, which I believe is unrelated as such uses are almost always related to data sections. For data-command-only output sections (e.g. `.foo : { QUAD(42) }`), we keep allowing copyable SHF_WRITE. Some tests are updated to drop the SHF_EXECINSTR flag. GNU ld doesn't set SHF_EXECINSTR as well, though it sets SHF_WRITE for some tests while we don't.
Diffstat (limited to 'lld/ELF/LinkerScript.cpp')
-rw-r--r--lld/ELF/LinkerScript.cpp8
1 files changed, 5 insertions, 3 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index df091613dc0a..1b8acbe1c908 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -1167,7 +1167,9 @@ void LinkerScript::adjustOutputSections() {
// * The address assignment.
// The other option is to pick flags that minimize the impact the section
// will have on the rest of the linker. That is why we copy the flags from
- // the previous sections. Only a few flags are needed to keep the impact low.
+ // the previous sections. We copy just SHF_ALLOC and SHF_WRITE to keep the
+ // impact low. We do not propagate SHF_EXECINSTR as in some cases this can
+ // lead to executable writeable section.
uint64_t flags = SHF_ALLOC;
SmallVector<StringRef, 0> defPhdrs;
@@ -1193,8 +1195,8 @@ void LinkerScript::adjustOutputSections() {
// We do not want to keep any special flags for output section
// in case it is empty.
if (isEmpty)
- sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) |
- SHF_WRITE | SHF_EXECINSTR);
+ sec->flags =
+ flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE);
// The code below may remove empty output sections. We should save the
// specified program headers (if exist) and propagate them to subsequent