[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