diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include using namespace llvm; @@ -389,11 +390,16 @@ // The first entry is not a section number but a flag. *to++ = from[0]; - // Adjust section numbers because section numbers in an input object - // files are different in the output. + // Adjust section numbers because section numbers in an input object files are + // different in the output. We also need to handle combined or discarded + // members. ArrayRef sections = file->getSections(); - for (uint32_t idx : from.slice(1)) - *to++ = sections[idx]->getOutputSection()->sectionIndex; + std::unordered_set seen; + for (uint32_t idx : from.slice(1)) { + OutputSection *osec = sections[idx]->getOutputSection(); + if (osec && seen.insert(osec->sectionIndex).second) + *to++ = osec->sectionIndex; + } } InputSectionBase *InputSection::getRelocatedSection() const { diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Parallel.h" #include "llvm/Support/SHA1.h" #include +#include using namespace llvm; using namespace llvm::dwarf; @@ -376,6 +377,15 @@ // provides signature of the section group. ArrayRef symbols = section->file->getSymbols(); os->info = in.symTab->getSymbolIndex(symbols[section->info]); + + // Some group members may be combined or discarded, so we need to compute the + // new size. The content will be rewritten in InputSection::copyShtGroup. + std::unordered_set seen; + ArrayRef sections = section->file->getSections(); + for (const uint32_t &idx : section->getDataAs().slice(1)) + if (OutputSection *osec = sections[read32(&idx)]->getOutputSection()) + seen.insert(osec->sectionIndex); + os->size = (1 + seen.size()) * sizeof(uint32_t); } void OutputSection::finalize() { diff --git a/lld/test/ELF/relocatable-comdat.s b/lld/test/ELF/relocatable-comdat.s --- a/lld/test/ELF/relocatable-comdat.s +++ b/lld/test/ELF/relocatable-comdat.s @@ -1,45 +1,52 @@ # REQUIRES: x86 +## Test that SHT_GROUP sections are retained in relocatable output. The content +## may be rewritten because group members may change their indices. Additionally, +## group member may be combined or discarded (e.g. /DISCARD/ or --gc-sections). + # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld -r %t.o %t.o -o %t -# RUN: llvm-readobj --elf-section-groups --sections %t | FileCheck %s - -# CHECK: Name: .text.bar -# CHECK-NEXT: Type: SHT_PROGBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_EXECINSTR -# CHECK-NEXT: SHF_GROUP -# CHECK-NEXT: ] -# CHECK-NEXT: Address: -# CHECK-NEXT: Offset: -# CHECK-NEXT: Size: 8 -# CHECK: Section { -# CHECK-NEXT: Index: 4 -# CHECK-NEXT: Name: .text.foo -# CHECK-NEXT: Type: SHT_PROGBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_EXECINSTR -# CHECK-NEXT: SHF_GROUP -# CHECK-NEXT: ] -# CHECK-NEXT: Address: -# CHECK-NEXT: Offset: -# CHECK-NEXT: Size: 4 - -# CHECK: Groups { -# CHECK-NEXT: Group { -# CHECK-NEXT: Name: .group -# CHECK-NEXT: Index: 2 -# CHECK-NEXT: Link: 6 -# CHECK-NEXT: Info: 1 -# CHECK-NEXT: Type: COMDAT -# CHECK-NEXT: Signature: abc -# CHECK-NEXT: Section(s) in group [ -# CHECK-NEXT: .text.bar -# CHECK-NEXT: .text.foo -# CHECK-NEXT: ] -# CHECK-NEXT: } -# CHECK-NEXT: } +# RUN: ld.lld -r %t.o %t.o -o %t.ro +# RUN: llvm-readelf -g -S %t.ro | FileCheck %s + +# CHECK: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK: .group GROUP 0000000000000000 {{.*}} 000014 04 {{[1-9]}} 1 4 + +# CHECK: COMDAT group section [{{.*}}] `.group' [abc] contains 4 sections: +# CHECK-NEXT: Name +# CHECK-NEXT: .rodata.bar +# CHECK-NEXT: .rodata.foo +# CHECK-NEXT: .text.bar +# CHECK-NEXT: .text.foo + +## Rewrite SHT_GROUP content if some members are combined. +# RUN: echo 'SECTIONS { .rodata : {*(.rodata.*)} .text : {*(.text.*)} }' > %t1.lds +# RUN: ld.lld -r -T %t1.lds %t.o %t.o -o %t1.ro +# RUN: llvm-readelf -g -S %t1.ro | FileCheck %s --check-prefix=SCRIPT1 + +# SCRIPT1: Name Type Address Off Size ES Flg Lk Inf Al +# SCRIPT1: .group GROUP 0000000000000000 {{.*}} 00000c 04 {{[1-9]}} 1 4 + +# SCRIPT1: COMDAT group section [{{.*}}] `.group' [abc] contains 2 sections: +# SCRIPT1-NEXT: Name +# SCRIPT1-NEXT: .rodata +# SCRIPT1-NEXT: .text + +# RUN: echo 'SECTIONS { /DISCARD/ : {*(.rodata.*)} }' > %t2.lds +# RUN: ld.lld -r -T %t2.lds %t.o %t.o -o %t2.ro +# RUN: llvm-readelf -g -S %t2.ro | FileCheck %s --check-prefix=SCRIPT2 + +## Handle discarded group members. +# SCRIPT2: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# SCRIPT2: [ 2] .group GROUP 0000000000000000 {{.*}} 00000c 04 {{[1-9]}} 1 4 + +# SCRIPT2: COMDAT group section [{{.*}}] `.group' [abc] contains 2 sections: +# SCRIPT2-NEXT: Name +# SCRIPT2-NEXT: .text.bar +# SCRIPT2-NEXT: .text.foo + +.section .rodata.bar,"aG",@progbits,abc,comdat +.byte 42 +.section .rodata.foo,"aG",@progbits,abc,comdat +.byte 42 .section .text.bar,"axG",@progbits,abc,comdat .quad 42