diff options
-rw-r--r-- | lld/ELF/InputFiles.cpp | 9 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 10 | ||||
-rw-r--r-- | lld/test/ELF/merge-reloc.s | 92 |
3 files changed, 110 insertions, 1 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index cd29311ccdc..35626092349 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -177,6 +177,15 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { if (Config->Optimize == 0) return false; + // Do not merge sections if generating a relocatable object. It makes + // the code simpler because we do not need to update relocation addends + // to reflect changes introduced by merging. Instead of that we write + // such "merge" sections into separate OutputSections and keep SHF_MERGE + // / SHF_STRINGS flags and sh_entsize value to be able to perform merging + // later during a final linking. + if (Config->Relocatable) + 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/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 0cbee53bd9b..0a6c8732f15 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -894,6 +894,10 @@ void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { Sections.push_back(S); S->OutSec = this; this->updateAlignment(S->Alignment); + // Keep sh_entsize value of the input section to be able to perform merging + // later during a final linking using the generated relocatable object. + if (Config->Relocatable && (S->getSectionHdr()->sh_flags & SHF_MERGE)) + this->Header.sh_entsize = S->getSectionHdr()->sh_entsize; } // This function is called after we sort input sections @@ -1836,8 +1840,12 @@ static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *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 // 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)) + if (isa<MergeInputSection<ELFT>>(C) || + (Config->Relocatable && (H->sh_flags & SHF_MERGE))) Alignment = std::max(H->sh_addralign, H->sh_entsize); uint32_t Type = H->sh_type; diff --git a/lld/test/ELF/merge-reloc.s b/lld/test/ELF/merge-reloc.s new file mode 100644 index 00000000000..2447e3e9444 --- /dev/null +++ b/lld/test/ELF/merge-reloc.s @@ -0,0 +1,92 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -r -o %t-rel +# RUN: llvm-readobj -s -section-data %t-rel | FileCheck %s + +# When linker generates a relocatable object it should keep "merge" +# sections as-is: do not merge content, do not join regular and +# "merge" sections, do not joint "merge" sections with different +# entry size. + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 12 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 4 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 42000000 42000000 42000000 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 8 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 42000000 42000000 42000000 42000000 +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 42000000 42000000 42000000 42000000 +# CHECK-NEXT: ) +# CHECK-NEXT: } + + .section .data.1,"aM",@progbits,4 + .align 4 + .global foo +foo: + .long 0x42 + .long 0x42 + .long 0x42 + + .section .data.2,"aM",@progbits,8 + .align 8 + .global bar +bar: + .long 0x42 + .long 0x42 + .long 0x42 + .long 0x42 + + .data + .global gar +zed: + .long 0x42 + .long 0x42 + .long 0x42 + .long 0x42 |