Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -288,12 +288,6 @@ 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. - 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/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -411,7 +411,8 @@ } if (Config->IsRela) { - P->r_addend += Sym.getVA() - Section->getOutputSection()->Addr; + int64_t Addend = getAddend(Rel); + P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr; } else if (Config->Relocatable) { const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -466,9 +466,10 @@ return Out->RelocationSection; } - // When control reaches here, mergeable sections have already been - // merged except the -r case. If that's the case, we do not combine them - // and let final link to handle this optimization. + // When control reaches here, mergeable sections have already been merged. + // For relocatable case each input mergeable section contains data grouped by + // sh_entsize and we want to allow final link to perform the last merging + // optimization, so we emit unique output section for each input. if (Config->Relocatable && (IS->Flags & SHF_MERGE)) return createSection(IS, OutsecName); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -2505,8 +2505,15 @@ uint32_t Alignment = std::max(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { - return Sec->Name == OutsecName && Sec->Flags == MS->Flags && - Sec->Alignment == Alignment; + if (Sec->Name != OutsecName || Sec->Flags != MS->Flags) + return false; + // For -r we produce output section for each synthetic mergeable section, + // because we want to let final link to do final merging optimization. + // Thus we want MergeSyntheticSection to contain mergeable sections + // with the same entry sizes only. + if (Config->Relocatable && Sec->Entsize != MS->Entsize) + return false; + return Sec->Alignment == Alignment; }); if (I == MergeSections.end()) { MergeSyntheticSection *Syn = @@ -2514,6 +2521,11 @@ MergeSections.push_back(Syn); I = std::prev(MergeSections.end()); S = Syn; + + // For relocatable output we need to set sh_entsize field, + // which will be the same for all mergeable input sections. + if (Config->Relocatable) + Syn->Entsize = MS->Entsize; } else { S = nullptr; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -487,8 +487,13 @@ if (I == Sec->SectionCommands.end()) continue; InputSection *IS = cast(*I)->Sections[0]; - if (isa(IS) || IS->Type == SHT_REL || - IS->Type == SHT_RELA) + + // We do not create symbol for synthetic sections because do not have + // relocations that might use it, but SHF_MERGE sections is an exception + // which is used for -r. + if (isa(IS) && !(IS->Flags & SHF_MERGE)) + continue; + if (IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; auto *Sym = make("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, Index: test/ELF/emit-relocs.s =================================================================== --- test/ELF/emit-relocs.s +++ test/ELF/emit-relocs.s @@ -64,6 +64,15 @@ # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: Section +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .comment +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { # CHECK-NEXT: Name: fn # CHECK-NEXT: Value: 0x201000 # CHECK-NEXT: Size: 0 Index: test/ELF/merge-reloc.s =================================================================== --- test/ELF/merge-reloc.s +++ test/ELF/merge-reloc.s @@ -3,14 +3,13 @@ # 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. +# When linker generates a relocatable object it do string merging in the same +# way as for regular link. It should keep SHF_MERGE flag and set proper sh_entsize +# value so that final link can perform the final merging optimization. # CHECK: Section { # CHECK: Index: -# CHECK: Name: .rodata +# CHECK: Name: .rodata.1 # CHECK-NEXT: Type: SHT_PROGBITS # CHECK-NEXT: Flags [ # CHECK-NEXT: SHF_ALLOC @@ -18,18 +17,18 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: # CHECK-NEXT: Offset: -# CHECK-NEXT: Size: 12 +# CHECK-NEXT: Size: 4 # 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: 0000: 42000000 # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK: Section { # CHECK: Index: -# CHECK: Name: .rodata +# CHECK: Name: .rodata.2 # CHECK-NEXT: Type: SHT_PROGBITS # CHECK-NEXT: Flags [ # CHECK-NEXT: SHF_ALLOC @@ -37,13 +36,13 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: # CHECK-NEXT: Offset: -# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Size: 8 # 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: 0000: 42000000 42000000 # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK: Section { Index: test/ELF/relocatable-mergeable-relocs.s =================================================================== --- test/ELF/relocatable-mergeable-relocs.s +++ test/ELF/relocatable-mergeable-relocs.s @@ -0,0 +1,54 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld %t1 -o %t2 -r +# RUN: llvm-readobj -sections -section-data -r %t2 | FileCheck %s + +## Check we still produce proper relocations for relocatable +## output when merging sections. + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .strings +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 12 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 41414100 43434300 42424200 |AAA.CCC.BBB.| +# CHECK-NEXT: ) +# CHECK-NEXT: } + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.foo { +# CHECK-NEXT: 0x0 R_X86_64_64 .strings 0x0 +# CHECK-NEXT: 0x8 R_X86_64_64 .strings 0x8 +# CHECK-NEXT: 0x10 R_X86_64_64 .strings 0x8 +# CHECK-NEXT: 0x18 R_X86_64_64 .strings 0x4 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .strings,"MS",@progbits,1,unique,10 +.Linfo_string0: + .asciz "AAA" +.Linfo_string1: + .asciz "BBB" + +.section .strings,"MS",@progbits,1,unique,20 +.Linfo_string2: + .asciz "BBB" +.Linfo_string3: + .asciz "CCC" + +.section .foo,"ax",@progbits +.quad .Linfo_string0 +.quad .Linfo_string1 +.quad .Linfo_string2 +.quad .Linfo_string3 Index: test/ELF/relocatable-mergeable.s =================================================================== --- test/ELF/relocatable-mergeable.s +++ test/ELF/relocatable-mergeable.s @@ -0,0 +1,55 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld %t1 -o %t2 -r +# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s + +## Check we don't merge SHF_MERGE sections with different entries +## size for relocatable output. + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .strings +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 1 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: |foo.| +# CHECK-NEXT: ) +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .strings +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 6 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 2 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: |aabb..| +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section .strings,"MS",@progbits,1,unique,10 +.align 2 +.asciz "foo" + +.section .strings,"MS",@progbits,2,unique,30 +.ascii "aabb" +.word 0