diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -609,27 +609,20 @@ StringRef signature = getShtGroupSignature(objSections, sec); this->sections[i] = &InputSection::discarded; - ArrayRef entries = CHECK(obj.template getSectionContentsAsArray(sec), this); if (entries.empty()) fatal(toString(this) + ": empty SHT_GROUP"); - // The first word of a SHT_GROUP section contains flags. Currently, - // the standard defines only "GRP_COMDAT" flag for the COMDAT group. - // An group with the empty flag doesn't define anything; such sections - // are just skipped. - if (entries[0] == 0) - continue; - - if (entries[0] != GRP_COMDAT) + Elf_Word flag = entries[0]; + if (flag && flag != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); - bool isNew = - ignoreComdats || + bool keepGroup = + (flag & GRP_COMDAT) == 0 || ignoreComdats || symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) .second; - if (isNew) { + if (keepGroup) { if (config->relocatable) this->sections[i] = createInputSection(sec); selectedGroups.push_back(entries); diff --git a/lld/test/ELF/gc-sections-group.s b/lld/test/ELF/gc-sections-group.s --- a/lld/test/ELF/gc-sections-group.s +++ b/lld/test/ELF/gc-sections-group.s @@ -7,48 +7,99 @@ # RUN: ld.lld --gc-sections %t.o -o %t.dead # RUN: llvm-readobj -S %t.dead | FileCheck %s --check-prefix=CHECK-DEAD -## .mynote.bar is retained because it is not in a group. -# CHECK-DEAD-NOT: Name: .myanote.foo -# CHECK-DEAD-NOT: Name: .mytext.foo -# CHECK-DEAD-NOT: Name: .mybss.foo -# CHECK-DEAD-NOT: Name: .mynote.foo -# CHECK-DEAD: Name: .mynote.bar - -# RUN: ld.lld --gc-sections %t.o -o %t -e anote_foo -# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE -# RUN: ld.lld --gc-sections %t.o -o %t -e foo -# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE -# RUN: ld.lld --gc-sections %t.o -o %t -e bss_foo -# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE - -## note_foo as the entry point does not make much sense because it is defined +## .mynote.ccc is retained because it is not in a group. +# CHECK-DEAD-NOT: Name: .myanote.aaa +# CHECK-DEAD-NOT: Name: .mytext.aaa +# CHECK-DEAD-NOT: Name: .mybss.aaa +# CHECK-DEAD-NOT: Name: .mynote.aaa +# CHECK-DEAD-NOT: Name: .myanote.bbb +# CHECK-DEAD-NOT: Name: .mytext.bbb +# CHECK-DEAD-NOT: Name: .mybss.bbb +# CHECK-DEAD-NOT: Name: .mynote.bbb +# CHECK-DEAD: Name: .mynote.ccc + +# RUN: ld.lld --gc-sections %t.o -o %t -e anote_aaa +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-GROUP +# RUN: ld.lld --gc-sections %t.o -o %t -e aaa +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-GROUP +# RUN: ld.lld --gc-sections %t.o -o %t -e bss_aaa +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-GROUP + +## note_zero as the entry point does not make much sense because it is defined +## in a non-SHF_ALLOC section. This is just to demonstrate the behavior. +# RUN: ld.lld --gc-sections %t.o -o %t -e note_aaa +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-GROUP + +# CHECK-LIVE-GROUP: Name: .myanote.aaa +# CHECK-LIVE-GROUP: Name: .mytext.aaa +# CHECK-LIVE-GROUP: Name: .mybss.aaa +# CHECK-LIVE-GROUP: Name: .mynote.aaa +# CHECK-LIVE-GROUP-NOT: Name: .myanote.bbb +# CHECK-LIVE-GROUP-NOT: Name: .mytext.bbb +# CHECK-LIVE-GROUP-NOT: Name: .mybss.bbb +# CHECK-LIVE-GROUP-NOT: Name: .mynote.bbb +# CHECK-LIVE-GROUP: Name: .mynote.ccc + +# RUN: ld.lld --gc-sections %t.o -o %t -e anote_bbb +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT +# RUN: ld.lld --gc-sections %t.o -o %t -e bbb +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT +# RUN: ld.lld --gc-sections %t.o -o %t -e bss_bbb +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT + +## note_bbb as the entry point does not make much sense because it is defined ## in a non-SHF_ALLOC section. This is just to demonstrate the behavior. -# RUN: ld.lld --gc-sections %t.o -o %t -e note_foo -# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE +# RUN: ld.lld --gc-sections %t.o -o %t -e note_bbb +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT + +# CHECK-LIVE-COMDAT-NOT: Name: .myanote.aaa +# CHECK-LIVE-COMDAT-NOT: Name: .mytext.aaa +# CHECK-LIVE-COMDAT-NOT: Name: .mybss.aaa +# CHECK-LIVE-COMDAT-NOT: Name: .mynote.aaa +# CHECK-LIVE-COMDAT: Name: .myanote.bbb +# CHECK-LIVE-COMDAT: Name: .mytext.bbb +# CHECK-LIVE-COMDAT: Name: .mybss.bbb +# CHECK-LIVE-COMDAT: Name: .mynote.bbb +# CHECK-LIVE-COMDAT: Name: .mynote.ccc + +## These sections are in a zero flag group `aaa`. +.globl anote_aaa, aaa, bss_aaa, note_aaa -# CHECK-LIVE: Name: .myanote.foo -# CHECK-LIVE: Name: .mytext.foo -# CHECK-LIVE: Name: .mybss.foo -# CHECK-LIVE: Name: .mynote.foo -# CHECK-LIVE: Name: .mynote.bar +.section .myanote.aaa,"aG",@note,aaa +anote_aaa: +.byte 0 + +.section .mytext.aaa,"axG",@progbits,aaa +aaa: +.byte 0 + +.section .mybss.aaa,"awG",@nobits,aaa +bss_aaa: +.byte 0 + +.section .mynote.aaa,"G",@note,aaa +note_aaa: +.byte 0 -.globl anote_foo, foo, bss_foo, note_foo +## These sections are in a COMDAT group `bbb`. +.globl anote_bbb, bbb, bss_bbb, note_bbb -.section .myanote.foo,"aG",@note,foo,comdat -anote_foo: +.section .myanote.bbb,"aG",@note,bbb,comdat +anote_bbb: .byte 0 -.section .mytext.foo,"axG",@progbits,foo,comdat -foo: +.section .mytext.bbb,"axG",@progbits,bbb,comdat +bbb: .byte 0 -.section .mybss.foo,"awG",@nobits,foo,comdat -bss_foo: +.section .mybss.bbb,"awG",@nobits,bbb,comdat +bss_bbb: .byte 0 -.section .mynote.foo,"G",@note,foo,comdat -note_foo: +.section .mynote.bbb,"G",@note,bbb,comdat +note_bbb: .byte 0 -.section .mynote.bar,"",@note +## This section isn't in any group. +.section .mynote.ccc,"",@note .byte 0