Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -177,6 +177,15 @@ if (Config->Optimize == 0) return false; + // Do not merge sections if generate a relocatable object. It makes the code + // simpler because we do not need to update relocations addend to reflect + // changes introduced by merging. Instead of that we write such "merge" + // sections into separate output ones 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. Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -894,6 +894,10 @@ 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 @@ -1842,8 +1846,12 @@ // 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>(C)) + if (isa>(C) || + (Config->Relocatable && (H->sh_flags & SHF_MERGE))) Alignment = std::max(H->sh_addralign, H->sh_entsize); uint32_t Type = H->sh_type; Index: test/ELF/merge-reloc.s =================================================================== --- /dev/null +++ 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