Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -609,24 +609,17 @@ 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 || + (flag & GRP_COMDAT) == 0 || ignoreComdats || symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) .second; if (isNew) { Index: lld/test/ELF/gc-sections-group.s =================================================================== --- lld/test/ELF/gc-sections-group.s +++ 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.baz is retained because it is not in a group. +# CHECK-DEAD-NOT: Name: .myanote.comdat +# CHECK-DEAD-NOT: Name: .mytext.comdat +# CHECK-DEAD-NOT: Name: .mybss.comdat +# CHECK-DEAD-NOT: Name: .mynote.comdat +# CHECK-DEAD-NOT: Name: .myanote.zero +# CHECK-DEAD-NOT: Name: .mytext.zero +# CHECK-DEAD-NOT: Name: .mybss.zero +# CHECK-DEAD-NOT: Name: .mynote.zero +# CHECK-DEAD: Name: .mynote.baz + +# RUN: ld.lld --gc-sections %t.o -o %t -e anote_comdat +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT-GRP +# RUN: ld.lld --gc-sections %t.o -o %t -e comdat +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT-GRP +# RUN: ld.lld --gc-sections %t.o -o %t -e bss_comdat +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT-GRP + +## note_comdat 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_comdat +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-COMDAT-GRP + +# CHECK-LIVE-COMDAT-GRP: Name: .myanote.comdat +# CHECK-LIVE-COMDAT-GRP: Name: .mytext.comdat +# CHECK-LIVE-COMDAT-GRP: Name: .mybss.comdat +# CHECK-LIVE-COMDAT-GRP: Name: .mynote.comdat +# CHECK-LIVE-COMDAT-GRP-NOT: Name: .myanote.zero +# CHECK-LIVE-COMDAT-GRP-NOT: Name: .mytext.zero +# CHECK-LIVE-COMDAT-GRP-NOT: Name: .mybss.zero +# CHECK-LIVE-COMDAT-GRP-NOT: Name: .mynote.zero +# CHECK-LIVE-COMDAT-GRP: Name: .mynote.baz + +# RUN: ld.lld --gc-sections %t.o -o %t -e anote_zero +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-ZERO-GRP +# RUN: ld.lld --gc-sections %t.o -o %t -e zero +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-ZERO-GRP +# RUN: ld.lld --gc-sections %t.o -o %t -e bss_zero +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-ZERO-GRP + +## 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_foo -# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE +# RUN: ld.lld --gc-sections %t.o -o %t -e note_zero +# RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=CHECK-LIVE-ZERO-GRP + +# CHECK-LIVE-ZERO-GRP-NOT: Name: .myanote.comdat +# CHECK-LIVE-ZERO-GRP-NOT: Name: .mytext.comdat +# CHECK-LIVE-ZERO-GRP-NOT: Name: .mybss.comdat +# CHECK-LIVE-ZERO-GRP-NOT: Name: .mynote.comdat +# CHECK-LIVE-ZERO-GRP: Name: .myanote.zero +# CHECK-LIVE-ZERO-GRP: Name: .mytext.zero +# CHECK-LIVE-ZERO-GRP: Name: .mybss.zero +# CHECK-LIVE-ZERO-GRP: Name: .mynote.zero +# CHECK-LIVE-ZERO-GRP: Name: .mynote.baz + +## These seections are in a COMDAT group `comdat_grp`. +.globl anote_comdat, comdat, bss_comdat, note_comdat -# 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.comdat,"aG",@note,comdat_grp,comdat +anote_comdat: +.byte 0 + +.section .mytext.comdat,"axG",@progbits,comdat_grp,comdat +comdat: +.byte 0 + +.section .mybss.comdat,"awG",@nobits,comdat_grp,comdat +bss_comdat: +.byte 0 + +.section .mynote.comdat,"G",@note,comdat_grp,comdat +note_comdat: +.byte 0 -.globl anote_foo, foo, bss_foo, note_foo +## These sections are in a zero flag group `zero_grp`. +.globl anote_zero, zero, bss_zero, note_zero -.section .myanote.foo,"aG",@note,foo,comdat -anote_foo: +.section .myanote.zero,"aG",@note,zero_grp +anote_zero: .byte 0 -.section .mytext.foo,"axG",@progbits,foo,comdat -foo: +.section .mytext.zero,"axG",@progbits,zero_grp +zero: .byte 0 -.section .mybss.foo,"awG",@nobits,foo,comdat -bss_foo: +.section .mybss.zero,"awG",@nobits,zero_grp +bss_zero: .byte 0 -.section .mynote.foo,"G",@note,foo,comdat -note_foo: +.section .mynote.zero,"G",@note,zero_grp +note_zero: .byte 0 -.section .mynote.bar,"",@note +## This section isn't in any group. +.section .mynote.baz,"",@note .byte 0