Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -67,6 +67,11 @@ // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; + // Pointer to a relocation section for this section. Usually nullptr because + // we consume relocations, but if --emit-relocs is specified (which is rare), + // it may have a non-null value. + OutputSection *RelocationSection = nullptr; + // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -283,6 +283,20 @@ return; } + // 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)) { + auto *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: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -101,18 +101,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: lld/trunk/test/ELF/emit-relocs-merge.s =================================================================== --- lld/trunk/test/ELF/emit-relocs-merge.s +++ lld/trunk/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: lld/trunk/test/ELF/linkerscript/emit-relocs-multiple.s =================================================================== --- lld/trunk/test/ELF/linkerscript/emit-relocs-multiple.s +++ lld/trunk/test/ELF/linkerscript/emit-relocs-multiple.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .zed : { *(.foo) *(.bar) } }" > %t.script +# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1 +# RUN: llvm-readobj -r %t1 | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.foo { +# CHECK-NEXT: 0x1 R_X86_64_32 .zed 0x0 +# CHECK-NEXT: 0x6 R_X86_64_32 .zed 0x5 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .foo,"ax",@progbits +aaa: + movl $aaa, %edx + +.section .bar,"ax",@progbits +bbb: + movl $bbb, %edx