[lld] r291107 - Change which input sections we concatenate

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 5 06:20:36 PST 2017


Author: rafael
Date: Thu Jan  5 08:20:35 2017
New Revision: 291107

URL: http://llvm.org/viewvc/llvm-project?rev=291107&view=rev
Log:
Change which input sections we concatenate

After Mark's patch I was wondering what was the rationale for the ELF
spec requiring us to merge only sections with matching flags and
types. I tried emailing
https://groups.google.com/forum/#!forum/generic-abi, but looks like my
emails are not being posted (the list is probably moderated). I
emailed Cary Coutant instead.

Cary pointed out that the section was a late addition and didn't got
the scrutiny it deserved. Given that and the problems found by
implementing the letter of the standard, I propose changing lld to
merge all sections with the same name and issue errors if the types or
some critical flags are different.

This should allow an unmodified firefox linked with lld to run.

This also merges some code with the linkerscript path.

Added:
    lld/trunk/test/ELF/incompatible-section-flags.s
    lld/trunk/test/ELF/incompatible-section-types.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/test/ELF/linkerscript/phdrs.s
    lld/trunk/test/ELF/linkerscript/sections.s
    lld/trunk/test/ELF/section-name.s
    lld/trunk/test/ELF/string-table.s

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Jan  5 08:20:35 2017
@@ -264,42 +264,12 @@ LinkerScript<ELFT>::createInputSectionLi
 }
 
 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.
-  typedef typename ELFT::uint uintX_t;
-  uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
-
-  uintX_t Alignment = 0;
-  if (isa<MergeInputSection<ELFT>>(C))
-    Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
-
-  return SectionKey<ELFT::Is64Bits>{OutsecName, /*Type*/ 0, Flags, Alignment};
-}
-
-template <class ELFT>
 void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
                                     InputSectionBase<ELFT> *Sec,
                                     StringRef Name) {
   OutputSectionBase *OutSec;
   bool IsNew;
-  std::tie(OutSec, IsNew) = Factory.create(createKey(Sec, Name), Sec);
+  std::tie(OutSec, IsNew) = Factory.create(Sec, Name);
   if (IsNew)
     OutputSections->push_back(OutSec);
   OutSec->addSection(Sec);

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Jan  5 08:20:35 2017
@@ -537,21 +537,68 @@ static typename ELFT::uint getOutFlags(I
 template <class ELFT>
 static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
                                             StringRef OutsecName) {
+  //  The ELF spec just says
+  // ----------------------------------------------------------------
+  // In the first phase, input sections that match in name, type and
+  // attribute flags should be concatenated into single sections.
+  // ----------------------------------------------------------------
+  //
+  // However, it is clear that at least some flags have to be ignored for
+  // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be
+  // ignored. We should not have two output .text sections just because one was
+  // in a group and another was not for example.
+  //
+  // It also seems that that wording was a late addition and didn't get the
+  // necessary scrutiny.
+  //
+  // Merging sections with different flags is expected by some users. One
+  // reason is that if one file has
+  //
+  // int *const bar __attribute__((section(".foo"))) = (int *)0;
+  //
+  // gcc with -fPIC will produce a read only .foo section. But if another
+  // file has
+  //
+  // int zed;
+  // int *const bar __attribute__((section(".foo"))) = (int *)&zed;
+  //
+  // gcc with -fPIC will produce a read write section.
+  //
+  // Last but not least, when using linker script the merge rules are forced by
+  // the script. Unfortunately, linker scripts are name based. This means that
+  // expressions like *(.foo*) can refer to multiple input sections with
+  // different flags. 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.
+  //
+  // Given the above issues, we instead merge sections by name and error on
+  // incompatible types and flags.
+  //
+  // The exception being SHF_MERGE, where we create different output sections
+  // for each alignment. This makes each output section simple. In case of
+  // relocatable object generation we do not try to perform merging and treat
+  // SHF_MERGE sections as regular ones, but also create different output
+  // sections for them to allow merging at final linking stage.
+  //
+  // Fortunately, creating symbols in the middle of a merge section is not
+  // supported by bfd or gold, so the SHF_MERGE exception should not cause
+  // problems with most linker scripts.
+
   typedef typename ELFT::uint uintX_t;
-  uintX_t Flags = getOutFlags(C);
+  uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
 
-  // For SHF_MERGE we create different output sections for each alignment.
-  // This makes each output section simple and keeps a single level mapping from
-  // input to output.
-  // In case of relocatable object generation we do not try to perform merging
-  // and treat SHF_MERGE sections as regular ones, but also create different
-  // output sections for them to allow merging at final linking stage.
   uintX_t Alignment = 0;
   if (isa<MergeInputSection<ELFT>>(C) ||
       (Config->Relocatable && (C->Flags & SHF_MERGE)))
     Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
 
-  return SectionKey<ELFT::Is64Bits>{OutsecName, C->Type, Flags, Alignment};
+  return SectionKey<ELFT::Is64Bits>{OutsecName, Flags, Alignment};
 }
 
 template <class ELFT>
@@ -562,6 +609,10 @@ OutputSectionFactory<ELFT>::create(Input
   return create(Key, C);
 }
 
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+  return Flags & (SHF_ALLOC | SHF_TLS);
+}
+
 template <class ELFT>
 std::pair<OutputSectionBase *, bool>
 OutputSectionFactory<ELFT>::create(const SectionKey<ELFT::Is64Bits> &Key,
@@ -569,6 +620,12 @@ OutputSectionFactory<ELFT>::create(const
   uintX_t Flags = getOutFlags(C);
   OutputSectionBase *&Sec = Map[Key];
   if (Sec) {
+    if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
+      error("Section has flags incompatible with others with the same name " +
+            toString(C));
+    if (Sec->Type != C->Type)
+      error("Section has different type from others with the same name " +
+            toString(C));
     Sec->Flags |= Flags;
     return {Sec, false};
   }
@@ -591,28 +648,26 @@ OutputSectionFactory<ELFT>::create(const
 template <bool Is64Bits>
 typename lld::elf::SectionKey<Is64Bits>
 DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() {
-  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0};
+  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
 }
 
 template <bool Is64Bits>
 typename lld::elf::SectionKey<Is64Bits>
 DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() {
-  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0,
-                              0};
+  return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0};
 }
 
 template <bool Is64Bits>
 unsigned
 DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) {
-  return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
+  return hash_combine(Val.Name, Val.Flags, Val.Alignment);
 }
 
 template <bool Is64Bits>
 bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS,
                                                            const Key &RHS) {
   return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
-         LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
-         LHS.Alignment == RHS.Alignment;
+         LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
 }
 
 namespace llvm {

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Jan  5 08:20:35 2017
@@ -220,7 +220,6 @@ template <class ELFT> struct Out {
 template <bool Is64Bits> struct SectionKey {
   typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
   StringRef Name;
-  uint32_t Type;
   uintX_t Flags;
   uintX_t Alignment;
 };

Added: lld/trunk/test/ELF/incompatible-section-flags.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/incompatible-section-flags.s?rev=291107&view=auto
==============================================================================
--- lld/trunk/test/ELF/incompatible-section-flags.s (added)
+++ lld/trunk/test/ELF/incompatible-section-flags.s Thu Jan  5 08:20:35 2017
@@ -0,0 +1,18 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s
+
+// CHECK: error:  Section has flags incompatible with others with the same name {{.*}}incompatible-section-flags.s.tmp.o:(.foo)
+// CHECK: error:  Section has flags incompatible with others with the same name {{.*}}incompatible-section-flags.s.tmp.o:(.bar)
+
+.section .foo, "awT", @progbits, unique, 1
+.quad 0
+
+.section .foo, "aw", @progbits, unique, 2
+.quad 0
+
+
+.section .bar, "aw", @progbits, unique, 3
+.quad 0
+
+.section .bar, "awT", @progbits, unique, 4
+.quad 0

Added: lld/trunk/test/ELF/incompatible-section-types.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/incompatible-section-types.s?rev=291107&view=auto
==============================================================================
--- lld/trunk/test/ELF/incompatible-section-types.s (added)
+++ lld/trunk/test/ELF/incompatible-section-types.s Thu Jan  5 08:20:35 2017
@@ -0,0 +1,10 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s
+
+// CHECK: error: Section has different type from others with the same name {{.*}}incompatible-section-types.s.tmp.o:(.foo)
+
+.section .foo, "aw", @progbits, unique, 1
+.quad 0
+
+.section .foo, "aw", @nobits, unique, 2
+.quad 0

Modified: lld/trunk/test/ELF/linkerscript/phdrs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/phdrs.s?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/phdrs.s (original)
+++ lld/trunk/test/ELF/linkerscript/phdrs.s Thu Jan  5 08:20:35 2017
@@ -93,7 +93,7 @@
 
 ## Check the numetic values for PHDRS.
 # RUN: echo "PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; } \
-# RUN:       SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.*) } : text : foo}" > %t1.script
+# RUN:       SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.foo* .text*) } : text : foo}" > %t1.script
 # RUN: ld.lld -o %t2 --script %t1.script %t
 # RUN: llvm-readobj -program-headers %t2 | FileCheck --check-prefix=INT-PHDRS %s
 

Modified: lld/trunk/test/ELF/linkerscript/sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/sections.s?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/sections.s (original)
+++ lld/trunk/test/ELF/linkerscript/sections.s Thu Jan  5 08:20:35 2017
@@ -20,11 +20,10 @@
 # SEC-DEFAULT: 2 .data         00000020 {{[0-9a-f]*}} DATA
 # SEC-DEFAULT: 3 other         00000003 {{[0-9a-f]*}} DATA
 # SEC-DEFAULT: 4 .bss          00000002 {{[0-9a-f]*}} BSS
-# SEC-DEFAULT: 5 .shstrtab     00000002 {{[0-9a-f]*}}
-# SEC-DEFAULT: 6 .comment      00000008 {{[0-9a-f]*}}
-# SEC-DEFAULT: 7 .symtab       00000030 {{[0-9a-f]*}}
-# SEC-DEFAULT: 8 .shstrtab     0000003b {{[0-9a-f]*}}
-# SEC-DEFAULT: 9 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT: 5 .comment      00000008 {{[0-9a-f]*}}
+# SEC-DEFAULT: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-DEFAULT: 7 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-DEFAULT: 8 .strtab       00000008 {{[0-9a-f]*}}
 
 # Sections are put in order specified in linker script, other than alloc
 # sections going first.
@@ -43,12 +42,11 @@
 #           Idx Name          Size
 # SEC-ORDER: 1 .bss          00000002 {{[0-9a-f]*}} BSS
 # SEC-ORDER: 2 other         00000003 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 3 .shstrtab     00000002 {{[0-9a-f]*}}
-# SEC-ORDER: 4 .shstrtab     0000003b {{[0-9a-f]*}}
-# SEC-ORDER: 5 .symtab       00000030 {{[0-9a-f]*}}
-# SEC-ORDER: 6 .strtab       00000008 {{[0-9a-f]*}}
-# SEC-ORDER: 7 .data         00000020 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 8 .text         0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-ORDER: 3 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-ORDER: 4 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 5 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .data         00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 7 .text         0000000e {{[0-9a-f]*}} TEXT DATA
 
 # .text and .data have swapped names but proper sizes and types.
 # RUN: echo "SECTIONS { \
@@ -63,11 +61,10 @@
 # SEC-SWAP-NAMES: 2 .text         00000020 {{[0-9a-f]*}} DATA
 # SEC-SWAP-NAMES: 3 other         00000003 {{[0-9a-f]*}} DATA
 # SEC-SWAP-NAMES: 4 .bss          00000002 {{[0-9a-f]*}} BSS
-# SEC-SWAP-NAMES: 5 .shstrtab     00000002 {{[0-9a-f]*}}
-# SEC-SWAP-NAMES: 6 .comment      00000008 {{[0-9a-f]*}}
-# SEC-SWAP-NAMES: 7 .symtab       00000030 {{[0-9a-f]*}}
-# SEC-SWAP-NAMES: 8 .shstrtab     0000003b {{[0-9a-f]*}}
-# SEC-SWAP-NAMES: 9 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 5 .comment      00000008 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 6 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 7 .shstrtab     0000003b {{[0-9a-f]*}}
+# SEC-SWAP-NAMES: 8 .strtab       00000008 {{[0-9a-f]*}}
 
 # .shstrtab from the input object file is discarded.
 # RUN: echo "SECTIONS { \
@@ -102,11 +99,10 @@
 # SEC-MULTI: 1 .text         0000000e {{[0-9a-f]*}} TEXT DATA
 # SEC-MULTI: 2 .data         00000023 {{[0-9a-f]*}} DATA
 # SEC-MULTI: 3 .bss          00000002 {{[0-9a-f]*}} BSS
-# SEC-MULTI: 4 .shstrtab     00000002 {{[0-9a-f]*}}
-# SEC-MULTI: 5 .comment      00000008 {{[0-9a-f]*}}
-# SEC-MULTI: 6 .symtab       00000030 {{[0-9a-f]*}}
-# SEC-MULTI: 7 .shstrtab     00000035 {{[0-9a-f]*}}
-# SEC-MULTI: 8 .strtab       00000008 {{[0-9a-f]*}}
+# SEC-MULTI: 4 .comment      00000008 {{[0-9a-f]*}}
+# SEC-MULTI: 5 .symtab       00000030 {{[0-9a-f]*}}
+# SEC-MULTI: 6 .shstrtab     00000035 {{[0-9a-f]*}}
+# SEC-MULTI: 7 .strtab       00000008 {{[0-9a-f]*}}
 
 .globl _start
 _start:
@@ -118,7 +114,5 @@ _start:
 .section other,"aw"
 .short 10
 .byte 20
-.section .shstrtab,""
-.short 20
 .section .bss,"", at nobits
 .short 0

Modified: lld/trunk/test/ELF/section-name.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/section-name.s?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/test/ELF/section-name.s (original)
+++ lld/trunk/test/ELF/section-name.s Thu Jan  5 08:20:35 2017
@@ -19,9 +19,9 @@ _start:
 .byte 0
 .section .data,"aw"
 .byte 0
-.section .bss.a,"", at nobits
+.section .bss.a,"aw", at nobits
 .byte 0
-.section .bss,"", at nobits
+.section .bss,"aw", at nobits
 .byte 0
 .section .foo.a,"aw"
 .byte 0
@@ -51,9 +51,8 @@ _start:
 // CHECK:  7 .data         00000002
 // CHECK:  8 .foo.a        00000001
 // CHECK:  9 .foo          00000001
-// CHECK: 10 .bss          00000001
-// CHECK: 11 .bss          00000001
-// CHECK: 12 .comment      00000008
-// CHECK: 13 .symtab       00000060
-// CHECK: 14 .shstrtab     00000075
-// CHECK: 15 .strtab       0000001d
+// CHECK: 10 .bss          00000002
+// CHECK: 11 .comment      00000008
+// CHECK: 12 .symtab       00000060
+// CHECK: 13 .shstrtab     00000075
+// CHECK: 14 .strtab       0000001d

Modified: lld/trunk/test/ELF/string-table.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/string-table.s?rev=291107&r1=291106&r2=291107&view=diff
==============================================================================
--- lld/trunk/test/ELF/string-table.s (original)
+++ lld/trunk/test/ELF/string-table.s Thu Jan  5 08:20:35 2017
@@ -6,10 +6,7 @@
 .global _start
 _start:
 
-.section        foobar,"", at progbits,unique,1
-.section        foobar,"T", at progbits,unique,2
-.section        foobar,"", at nobits,unique,3
-.section        foobar,"", at nobits,unique,4
+.section        foobar,"", at progbits
 
 .section bar, "a"
 
@@ -26,18 +23,5 @@ _start:
 // CHECK-NEXT: Flags [
 // CHECK-NEXT: ]
 // CHECK-NEXT: Address: 0x0
-
-// CHECK:      Name: foobar
-// CHECK-NEXT: Type: SHT_PROGBITS
-// CHECK-NEXT: Flags [
-// CHECK-NEXT:   SHF_TLS
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x0
-
-// CHECK:      Name: foobar
-// CHECK-NEXT: Type: SHT_NOBITS
-// CHECK-NEXT: Flags [
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x0
 
 // CHECK-NOT:  Name: foobar




More information about the llvm-commits mailing list