Fix program header propagation.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 14 Nov 2016 15:39:38 +0000 (15:39 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 14 Nov 2016 15:39:38 +0000 (15:39 +0000)
Propagate program headers by walking the commands, not the
sections. This allows us to propagate program headers even from
sections that don't end up in the output.

Fixes pr30997.

llvm-svn: 286837

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/Writer.cpp
lld/test/ELF/linkerscript/Inputs/implicit-program-header.script [new file with mode: 0644]
lld/test/ELF/linkerscript/implicit-program-header.s [new file with mode: 0644]

index 2cf088e..c8ca74a 100644 (file)
@@ -563,6 +563,35 @@ template <class ELFT> void LinkerScript<ELFT>::adjustSectionsBeforeSorting() {
     auto *OutSec = make<OutputSection<ELFT>>(Cmd->Name, Type, Flags);
     OutputSections->push_back(OutSec);
   }
+}
+
+template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
+  placeOrphanSections();
+
+  // If output section command doesn't specify any segments,
+  // and we haven't previously assigned any section to segment,
+  // then we simply assign section to the very first load segment.
+  // Below is an example of such linker script:
+  // PHDRS { seg PT_LOAD; }
+  // SECTIONS { .aaa : { *(.aaa) } }
+  std::vector<StringRef> DefPhdrs;
+  auto FirstPtLoad =
+      std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(),
+                   [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+  if (FirstPtLoad != Opt.PhdrsCommands.end())
+    DefPhdrs.push_back(FirstPtLoad->Name);
+
+  // Walk the commands and propagate the program headers to commands that don't
+  // explicitly specify them.
+  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+    auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+    if (!Cmd)
+      continue;
+    if (Cmd->Phdrs.empty())
+      Cmd->Phdrs = DefPhdrs;
+    else
+      DefPhdrs = Cmd->Phdrs;
+  }
 
   removeEmptyCommands();
 }
@@ -630,8 +659,6 @@ void LinkerScript<ELFT>::placeOrphanSections() {
 
 template <class ELFT>
 void LinkerScript<ELFT>::assignAddresses(std::vector<PhdrEntry<ELFT>> &Phdrs) {
-  placeOrphanSections();
-
   // Assign addresses as instructed by linker script SECTIONS sub-commands.
   Dot = 0;
 
@@ -711,7 +738,6 @@ std::vector<PhdrEntry<ELFT>> LinkerScript<ELFT>::createPhdrs() {
 
   // Process PHDRS and FILEHDR keywords because they are not
   // real output sections and cannot be added in the following loop.
-  std::vector<size_t> DefPhdrIds;
   for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) {
     Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags);
     PhdrEntry<ELFT> &Phdr = Ret.back();
@@ -725,15 +751,6 @@ std::vector<PhdrEntry<ELFT>> LinkerScript<ELFT>::createPhdrs() {
       Phdr.H.p_paddr = Cmd.LMAExpr(0);
       Phdr.HasLMA = true;
     }
-
-    // If output section command doesn't specify any segments,
-    // and we haven't previously assigned any section to segment,
-    // then we simply assign section to the very first load segment.
-    // Below is an example of such linker script:
-    // PHDRS { seg PT_LOAD; }
-    // SECTIONS { .aaa : { *(.aaa) } }
-    if (DefPhdrIds.empty() && Phdr.H.p_type == PT_LOAD)
-      DefPhdrIds.push_back(Ret.size() - 1);
   }
 
   // Add output sections to program headers.
@@ -741,17 +758,12 @@ std::vector<PhdrEntry<ELFT>> LinkerScript<ELFT>::createPhdrs() {
     if (!(Sec->Flags & SHF_ALLOC))
       break;
 
-    std::vector<size_t> PhdrIds = getPhdrIndices(Sec->getName());
-    if (PhdrIds.empty())
-      PhdrIds = std::move(DefPhdrIds);
-
     // Assign headers specified by linker script
-    for (size_t Id : PhdrIds) {
+    for (size_t Id : getPhdrIndices(Sec->getName())) {
       Ret[Id].add(Sec);
       if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
         Ret[Id].H.p_flags |= Sec->getPhdrFlags();
     }
-    DefPhdrIds = std::move(PhdrIds);
   }
   return Ret;
 }
index 6bd02f1..ce64526 100644 (file)
@@ -221,6 +221,7 @@ public:
   void createSections(OutputSectionFactory<ELFT> &Factory);
   void removeEmptyCommands();
   void adjustSectionsBeforeSorting();
+  void adjustSectionsAfterSorting();
 
   std::vector<PhdrEntry<ELFT>> createPhdrs();
   bool ignoreInterpSection();
index 9776f62..2117e47 100644 (file)
@@ -856,6 +856,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
     std::rotate(BestPos, NonScriptI, NonScriptI + 1);
     ++NonScriptI;
   }
+
+  Script<ELFT>::X->adjustSectionsAfterSorting();
 }
 
 // Create output section objects and add them to OutputSections.
diff --git a/lld/test/ELF/linkerscript/Inputs/implicit-program-header.script b/lld/test/ELF/linkerscript/Inputs/implicit-program-header.script
new file mode 100644 (file)
index 0000000..27dbea8
--- /dev/null
@@ -0,0 +1,12 @@
+PHDRS
+{
+       ph_write PT_LOAD FLAGS(2);
+       ph_exec  PT_LOAD FLAGS(1);
+}
+
+SECTIONS
+{
+  .bar : { *(.bar) } : ph_exec
+  .foo : { *(.foo) }
+  .text : { *(.text) } : ph_write
+}
diff --git a/lld/test/ELF/linkerscript/implicit-program-header.s b/lld/test/ELF/linkerscript/implicit-program-header.s
new file mode 100644 (file)
index 0000000..9598a6a
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t1 --script %S/Inputs/implicit-program-header.script  \
+# RUN:   %t.o -shared
+# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s
+
+# CHECK:      Segment Sections...
+# CHECK-NEXT:   00     .text .dynsym .hash .dynstr .dynamic
+# CHECK-NEXT:   01     .foo
+
+.quad 0
+.section .foo,"ax"
+.quad 0