From: Rafael Espindola Date: Tue, 13 Sep 2016 14:23:14 +0000 (+0000) Subject: Enable merging of SHF_MERGE sections with linker scripts. X-Git-Tag: llvmorg-4.0.0-rc1~9942 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=10897f1807610802f9b5cdc0f6792adece7bfd3f;p=platform%2Fupstream%2Fllvm.git 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. llvm-svn: 281338 --- diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index e73ac7f..e86b48b 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -166,14 +166,6 @@ bool elf::ObjectFile::shouldMerge(const Elf_Shdr &Sec) { 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. diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index b7f7194..50f2d50 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -215,11 +215,42 @@ template void LinkerScript::createAssignments() { } template +static SectionKey createKey(InputSectionBase *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>(C)) + Alignment = std::max(H->sh_addralign, H->sh_entsize); + + return SectionKey{OutsecName, /*Type*/ 0, Flags, Alignment}; +} + +template void LinkerScript::createSections(OutputSectionFactory &Factory) { auto AddSec = [&](InputSectionBase *Sec, StringRef Name) { OutputSectionBase *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; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index ce5bac9..c984cb1 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1831,11 +1831,16 @@ void MipsAbiFlagsOutputSection::addSection(InputSectionBase *C) { } template +static typename ELFT::uint getOutFlags(InputSectionBase *S) { + return S->getSectionHdr()->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; +} + +template static SectionKey createKey(InputSectionBase *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 *, bool> OutputSectionFactory::create(InputSectionBase *C, StringRef OutsecName) { SectionKey Key = createKey(C, OutsecName); + return create(Key, C); +} + +template +std::pair *, bool> +OutputSectionFactory::create(const SectionKey &Key, + InputSectionBase *C) { + uintX_t Flags = getOutFlags(C); OutputSectionBase *&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::Regular: - Sec = new OutputSection(Key.Name, Key.Type, Key.Flags); + Sec = new OutputSection(Key.Name, Type, Flags); break; case InputSectionBase::EHFrame: return {Out::EhFrame, false}; case InputSectionBase::Merge: - Sec = new MergeOutputSection(Key.Name, Key.Type, Key.Flags, - Key.Alignment); + Sec = new MergeOutputSection(Key.Name, Type, Flags, Key.Alignment); break; case InputSectionBase::MipsReginfo: Sec = new MipsReginfoOutputSection(); diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index cde4aa5..e1634ee 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -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 OutputSectionFactory { public: std::pair *, bool> create(InputSectionBase *C, StringRef OutsecName); + std::pair *, bool> + create(const SectionKey &Key, InputSectionBase *C); private: llvm::SmallDenseMap *> Map; diff --git a/lld/test/ELF/linkerscript/merge-sections.s b/lld/test/ELF/linkerscript/merge-sections.s new file mode 100644 index 0000000..25ddacb --- /dev/null +++ b/lld/test/ELF/linkerscript/merge-sections.s @@ -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",@progbits,1 +.asciz "foo" + +.section .foo.1b,"aMS",@progbits,1 +.asciz "foo" + +.section .foo.2a,"aM",@progbits,1 +.byte 42 + +.section .foo.2b,"aM",@progbits,1 +.byte 42 + +.section .foo.3a,"aM",@progbits,2 +.align 2 +.short 42 + +.section .foo.3b,"aM",@progbits,2 +.align 2 +.short 42 diff --git a/lld/test/ELF/linkerscript/repsection-symbol.s b/lld/test/ELF/linkerscript/repsection-symbol.s new file mode 100644 index 0000000..17512eb --- /dev/null +++ b/lld/test/ELF/linkerscript/repsection-symbol.s @@ -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 diff --git a/lld/test/ELF/linkerscript/repsection-va.s b/lld/test/ELF/linkerscript/repsection-va.s index 4feeaa0..db229df 100644 --- a/lld/test/ELF/linkerscript/repsection-va.s +++ b/lld/test/ELF/linkerscript/repsection-va.s @@ -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: