Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -67,6 +67,10 @@ // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; + // Pointer to relocation section. Used for --emit-relocs, where we about to + // merge relocation sections if their target sections were merged. + OutputSection *RelocationSection = nullptr; + // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -333,6 +333,21 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { + + // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have + // relocation sections .rela.foo and .rela.bar for example. Most tools do + // not allow multiple REL[A] sections for output section. Hence we + // should combine these relocation sections into single output. + // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any + // other REL[A] sections created by linker itself. + if (!isa(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + InputSection *Sec = cast(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); + addInputSec(IS, OutsecName, Out->RelocationSection); + return; + } + SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; return addInputSec(IS, OutsecName, Sec); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -96,18 +96,6 @@ if (Config->Relocatable) return Name; - // If -emit-relocs is given (which is rare), we need to copy - // relocation sections to the output. If input section .foo is - // output as .bar, we want to rename .rel.foo .rel.bar as well. - if (Config->EmitRelocs) { - for (StringRef V : {".rel.", ".rela."}) { - if (Name.startswith(V)) { - StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); - return Saver.save(V.drop_back() + Inner); - } - } - } - for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", Index: test/ELF/emit-relocs-merge.s =================================================================== --- test/ELF/emit-relocs-merge.s +++ test/ELF/emit-relocs-merge.s @@ -8,7 +8,7 @@ # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } -# CHECK-NEXT: Section ({{.*}}) .rela.data { +# CHECK-NEXT: Section ({{.*}}) .rela.data.foo { # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } Index: test/ELF/emit-relocs-merge.test =================================================================== --- test/ELF/emit-relocs-merge.test +++ test/ELF/emit-relocs-merge.test @@ -0,0 +1,47 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: ld.lld %t.o -o %t --emit-relocs +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .reloc.text.foo { +# CHECK-NEXT: 0x2000E8 R_X86_64_64 _start 0x0 +# CHECK-NEXT: 0x2000F0 R_X86_64_64 _start 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: '0000000000000000' + - Name: .reloc.text.foo + Type: SHT_RELA + Link: .symtab + Info: .text.foo + Relocations: + - Offset: 0x0000000000000000 + Symbol: _start + Type: R_X86_64_64 + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: '0000000000000000' + - Name: .reloc.text.bar + Type: SHT_RELA + Link: .symtab + Info: .text.bar + Relocations: + - Offset: 0x0000000000000000 + Symbol: _start + Type: R_X86_64_64 +Symbols: + Global: + - Name: _start + Section: .text.foo +...