diff --git a/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test b/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test --- a/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test +++ b/llvm/test/tools/llvm-objcopy/ELF/group-reorder.test @@ -61,4 +61,5 @@ Section: .bar - Name: bar Type: STT_FUNC + Binding: STB_GLOBAL Section: .foo diff --git a/llvm/test/tools/llvm-objcopy/ELF/group.test b/llvm/test/tools/llvm-objcopy/ELF/group.test --- a/llvm/test/tools/llvm-objcopy/ELF/group.test +++ b/llvm/test/tools/llvm-objcopy/ELF/group.test @@ -78,3 +78,52 @@ ## sh_info fields. # RUN: llvm-objcopy --allow-broken-links -R .symtab %t3 %t4 # RUN: cmp %t3 %t4 + +## The signature symbol becomes local. Assume the intention is to localize the group. +## Drop GRP_COMDAT so that the linker will suppress deduplication. +# RUN: llvm-objcopy --keep-global-symbol=bar %t %t5 +# RUN: llvm-readelf -s --section-groups %t5 | FileCheck %s --check-prefix=LOCAL-SIG + +# LOCAL-SIG: LOCAL DEFAULT [[#]] foo +# LOCAL-SIG: (unknown) group section [ 1] `.group' [foo] contains 1 sections: + +## The signature symbol remains non-local. Keep GRP_COMDAT. +# RUN: llvm-readelf -s --section-groups %t1 | FileCheck %s --check-prefix=WEAK-SIG + +# WEAK-SIG: WEAK DEFAULT [[#]] foo +# WEAK-SIG: COMDAT group section [ 1] `.group' [foo] contains 1 sections: + +# RUN: llvm-objcopy --globalize-symbol=foo %t %t6 +# RUN: llvm-readelf -s --section-groups %t6 | FileCheck %s --check-prefix=GLOBAL-SIG + +# GLOBAL-SIG: GLOBAL DEFAULT [[#]] foo +# GLOBAL-SIG: COMDAT group section [ 1] `.group' [foo] contains 1 sections: + +## If the signature is initially local and no operation has been performed to +## specifically localize it, it isn't clear whether we should drop GRP_COMDAT. +## The current convention is that compilers should not produce such input, so +## our choice does not matter. +# RUN: yaml2obj --docnum=2 %s -o %t.localsig +# RUN: llvm-objcopy %t.localsig %t.localsig.out +# RUN: llvm-readelf -s --section-groups %t.localsig.out | FileCheck %s --check-prefix=LOCAL-SIG + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .group + Type: SHT_GROUP + Info: foo + Members: + - SectionOrType: GRP_COMDAT + - SectionOrType: .text.foo + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_GROUP ] +Symbols: + - Name: foo + Type: STT_FUNC + Section: .text.foo diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test --- a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test @@ -34,3 +34,4 @@ Symbols: - Name: foo_bar_grp Section: .group + Binding: STB_GLOBAL diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test b/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test --- a/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-dwo-groups.test @@ -75,9 +75,11 @@ Symbols: - Name: debug_before Section: .debug_before.dwo + - Name: debug_after + Section: .debug_after.dwo - Name: group2 Section: .text.group2 + Binding: STB_WEAK - Name: group1 Section: .text.group1 - - Name: debug_after - Section: .debug_after.dwo + Binding: STB_WEAK diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -1069,6 +1069,12 @@ void GroupSection::finalize() { this->Info = Sym ? Sym->Index : 0; this->Link = SymTab ? SymTab->Index : 0; + // Linker deduplication for GRP_COMDAT is based on Sym->Name. The local/global + // status is not part of the equation. If Sym is localized, the intention is + // likely to make the group fully localized. Drop GRP_COMDAT to suppress + // deduplication. See https://groups.google.com/g/generic-abi/c/2X6mR-s2zoc + if ((FlagWord & GRP_COMDAT) && Sym && Sym->Binding == STB_LOCAL) + this->FlagWord &= ~GRP_COMDAT; } Error GroupSection::removeSectionReferences(