[lld] r281338 - Enable merging of SHF_MERGE sections with linker scripts.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 13 07:23:15 PDT 2016


Author: rafael
Date: Tue Sep 13 09:23:14 2016
New Revision: 281338

URL: http://llvm.org/viewvc/llvm-project?rev=281338&view=rev
Log:
Enable merging of SHF_MERGE sections with linker scripts.

This also fixes the related problem of non SHF_MERGE sections with
different flags not being merged.

Fixes pr30355.

Added:
    lld/trunk/test/ELF/linkerscript/merge-sections.s
    lld/trunk/test/ELF/linkerscript/repsection-symbol.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/test/ELF/linkerscript/repsection-va.s

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=281338&r1=281337&r2=281338&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Tue Sep 13 09:23:14 2016
@@ -166,14 +166,6 @@ bool elf::ObjectFile<ELFT>::shouldMerge(
   if (Config->Optimize == 0)
     return false;
 
-  // We don't merge if linker script has SECTIONS command. When script
-  // do layout it can merge several sections with different attributes
-  // into single output sections. We currently do not support adding
-  // mergeable input sections to regular output ones as well as adding
-  // regular input sections to mergeable output.
-  if (ScriptConfig->HasContents)
-    return false;
-
   // A mergeable section with size 0 is useless because they don't have
   // any data to merge. A mergeable string section with size 0 can be
   // argued as invalid because it doesn't end with a null character.

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=281338&r1=281337&r2=281338&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Tue Sep 13 09:23:14 2016
@@ -215,11 +215,42 @@ template <class ELFT> void LinkerScript<
 }
 
 template <class ELFT>
+static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
+                                            StringRef OutsecName) {
+  // When using linker script the merge rules are different.
+  // Unfortunately, linker scripts are name based. This means that expressions
+  // like *(.foo*) can refer to multiple input sections that would normally be
+  // placed in different output sections. We cannot put them in different
+  // output sections or we would produce wrong results for
+  // start = .; *(.foo.*) end = .; *(.bar)
+  // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to
+  // another. The problem is that there is no way to layout those output
+  // sections such that the .foo sections are the only thing between the
+  // start and end symbols.
+
+  // An extra annoyance is that we cannot simply disable merging of the contents
+  // of SHF_MERGE sections, but our implementation requires one output section
+  // per "kind" (string or not, which size/aligment).
+  // Fortunately, creating symbols in the middle of a merge section is not
+  // supported by bfd or gold, so we can just create multiple section in that
+  // case.
+  const typename ELFT::Shdr *H = C->getSectionHdr();
+  typedef typename ELFT::uint uintX_t;
+  uintX_t Flags = H->sh_flags & (SHF_MERGE | SHF_STRINGS);
+
+  uintX_t Alignment = 0;
+  if (isa<MergeInputSection<ELFT>>(C))
+    Alignment = std::max(H->sh_addralign, H->sh_entsize);
+
+  return SectionKey<ELFT::Is64Bits>{OutsecName, /*Type*/ 0, Flags, Alignment};
+}
+
+template <class ELFT>
 void LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) {
   auto AddSec = [&](InputSectionBase<ELFT> *Sec, StringRef Name) {
     OutputSectionBase<ELFT> *OutSec;
     bool IsNew;
-    std::tie(OutSec, IsNew) = Factory.create(Sec, Name);
+    std::tie(OutSec, IsNew) = Factory.create(createKey(Sec, Name), Sec);
     if (IsNew)
       OutputSections->push_back(OutSec);
     return OutSec;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=281338&r1=281337&r2=281338&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Tue Sep 13 09:23:14 2016
@@ -1831,11 +1831,16 @@ void MipsAbiFlagsOutputSection<ELFT>::ad
 }
 
 template <class ELFT>
+static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
+  return S->getSectionHdr()->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
+}
+
+template <class ELFT>
 static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
                                             StringRef OutsecName) {
   const typename ELFT::Shdr *H = C->getSectionHdr();
   typedef typename ELFT::uint uintX_t;
-  uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
+  uintX_t Flags = getOutFlags(C);
 
   // For SHF_MERGE we create different output sections for each alignment.
   // This makes each output section simple and keeps a single level mapping from
@@ -1853,19 +1858,29 @@ std::pair<OutputSectionBase<ELFT> *, boo
 OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
                                    StringRef OutsecName) {
   SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
+  return create(Key, C);
+}
+
+template <class ELFT>
+std::pair<OutputSectionBase<ELFT> *, bool>
+OutputSectionFactory<ELFT>::create(const SectionKey<ELFT::Is64Bits> &Key,
+                                   InputSectionBase<ELFT> *C) {
+  uintX_t Flags = getOutFlags(C);
   OutputSectionBase<ELFT> *&Sec = Map[Key];
-  if (Sec)
+  if (Sec) {
+    Sec->updateFlags(Flags);
     return {Sec, false};
+  }
 
+  uint32_t Type = C->getSectionHdr()->sh_type;
   switch (C->kind()) {
   case InputSectionBase<ELFT>::Regular:
-    Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+    Sec = new OutputSection<ELFT>(Key.Name, Type, Flags);
     break;
   case InputSectionBase<ELFT>::EHFrame:
     return {Out<ELFT>::EhFrame, false};
   case InputSectionBase<ELFT>::Merge:
-    Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags,
-                                       Key.Alignment);
+    Sec = new MergeOutputSection<ELFT>(Key.Name, Type, Flags, Key.Alignment);
     break;
   case InputSectionBase<ELFT>::MipsReginfo:
     Sec = new MipsReginfoOutputSection<ELFT>();

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=281338&r1=281337&r2=281338&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Tue Sep 13 09:23:14 2016
@@ -93,6 +93,7 @@ public:
   uintX_t getSize() const { return Header.sh_size; }
   void setSize(uintX_t Val) { Header.sh_size = Val; }
   uintX_t getFlags() const { return Header.sh_flags; }
+  void updateFlags(uintX_t Val) { Header.sh_flags |= Val; }
   uint32_t getPhdrFlags() const;
   uintX_t getFileOff() const { return Header.sh_offset; }
   uintX_t getAlignment() const { return Header.sh_addralign; }
@@ -803,6 +804,8 @@ template <class ELFT> class OutputSectio
 public:
   std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
                                                     StringRef OutsecName);
+  std::pair<OutputSectionBase<ELFT> *, bool>
+  create(const SectionKey<ELFT::Is64Bits> &Key, InputSectionBase<ELFT> *C);
 
 private:
   llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;

Added: lld/trunk/test/ELF/linkerscript/merge-sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/merge-sections.s?rev=281338&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/merge-sections.s (added)
+++ lld/trunk/test/ELF/linkerscript/merge-sections.s Tue Sep 13 09:23:14 2016
@@ -0,0 +1,73 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : {*(.foo.*)} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -s -t %t1 | FileCheck %s
+
+# CHECK:        Name: .foo
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:     SHF_STRINGS
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x1C8
+# CHECK-NEXT:   Offset: 0x1C8
+# CHECK-NEXT:   Size: 4
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 1
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .foo
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x1CC
+# CHECK-NEXT:   Offset: 0x1CC
+# CHECK-NEXT:   Size: 1
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 1
+# CHECK-NEXT:   EntrySize: 1
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index:
+# CHECK-NEXT:   Name: .foo
+# CHECK-NEXT:   Type: SHT_PROGBITS
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:     SHF_MERGE
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address: 0x1CE
+# CHECK-NEXT:   Offset: 0x1CE
+# CHECK-NEXT:   Size: 2
+# CHECK-NEXT:   Link: 0
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: 2
+# CHECK-NEXT:   EntrySize: 2
+
+.section        .foo.1a,"aMS", at progbits,1
+.asciz "foo"
+
+.section        .foo.1b,"aMS", at progbits,1
+.asciz "foo"
+
+.section        .foo.2a,"aM", at progbits,1
+.byte 42
+
+.section        .foo.2b,"aM", at progbits,1
+.byte 42
+
+.section        .foo.3a,"aM", at progbits,2
+.align 2
+.short 42
+
+.section        .foo.3b,"aM", at progbits,2
+.align 2
+.short 42

Added: lld/trunk/test/ELF/linkerscript/repsection-symbol.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/repsection-symbol.s?rev=281338&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/repsection-symbol.s (added)
+++ lld/trunk/test/ELF/linkerscript/repsection-symbol.s Tue Sep 13 09:23:14 2016
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "SECTIONS {.foo : {foo1 = .; *(.foo.*) foo2 = .; *(.bar) foo3 = .;} }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t -shared
+# RUN: llvm-readobj -t %t1 | FileCheck %s
+
+# CHECK:      Name: foo1
+# CHECK-NEXT: Value: 0x238
+
+# CHECK:      Name: foo2
+# CHECK-NEXT: Value: 0x240
+
+# CHECK:      Name: foo3
+# CHECK-NEXT: Value: 0x244
+
+.section .foo.1,"a"
+ .long 1
+
+.section .foo.2,"aw"
+ .long 2
+
+ .section .bar,"aw"
+ .long 3

Modified: lld/trunk/test/ELF/linkerscript/repsection-va.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/repsection-va.s?rev=281338&r1=281337&r2=281338&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/repsection-va.s (original)
+++ lld/trunk/test/ELF/linkerscript/repsection-va.s Tue Sep 13 09:23:14 2016
@@ -7,9 +7,8 @@
 # CHECK:      Sections:
 # CHECK-NEXT: Idx Name          Size      Address          Type
 # CHECK-NEXT:   0               00000000 0000000000000000
-# CHECK-NEXT:   1 .foo          00000004 0000000000000158 DATA
-# CHECK-NEXT:   2 .foo          00000004 000000000000015c DATA
-# CHECK-NEXT:   3 .text         00000001 0000000000000160 TEXT DATA
+# CHECK-NEXT:   1 .foo          00000008 0000000000000158 DATA
+# CHECK-NEXT:   2 .text         00000001 0000000000000160 TEXT DATA
 
 .global _start
 _start:




More information about the llvm-commits mailing list