% cat a.s .globl _start, bbb _start: .section .mytext.bbb,"axG",@progbits,bbb,comdat bbb: .byte 0 .section .init_array.bbb,"awG",@init_array,bbb,comdat .byte 0 % cc -c a.s && ld.bfd --gc-sections --print-gc-sections a.o (no output) If I rename .init_array.bbb to .myinit_array.bbb, the group can be GCed % cc -c a.s && ld.bfd --gc-sections --print-gc-sections a.o ld.bfd: removing unused section '.group' in file 'a.o' ld.bfd: removing unused section '.mytext.bbb[bbb]' in file 'a.o' ld.bfd: removing unused section '.myinit_array.bbb[bbb]' in file 'a.o' It seems favorable to make all special sections GCable if in a section group. This makes the rule more consistent. An SHF_ALLOC SHT_NOTE appears to be a GC root outside of a group. --- Before 13.0, clang -fsanitize-coverage=... abuses .init_array.2 (SHT_INIT_ARRAY) in a section group to make the group a GC root, e.g. % clang -fsanitize-coverage=trace-pc-guard -c -xc++ =(printf 'int main(){}') -ffunction-sections -fdata-sections -c -o a.o % readelf -Wg a.o group section [ 3] `.group' [main] contains 3 sections: [Index] Name [ 4] .text.main [ 5] .rela.text.main [ 9] __sancov_guards COMDAT group section [ 6] `.group' [sancov.module_ctor_trace_pc_guard] contains 4 sections: [Index] Name [ 7] .text.sancov.module_ctor_trace_pc_guard [ 8] .rela.text.sancov.module_ctor_trace_pc_guard [ 10] .init_array.2 [ 11] .rela.init_array.2 The intention is that .text.sancov.module_ctor_trace_pc_guard will be retained. I changed 13.0.0 to use SHF_GNU_RETAIN to express the GC root intention explicitly. You may consider work around it, but I think not working around it is also fine.
For SHF_LINK_ORDER: % cat a.s .globl _start; _start: nop .section .text.a,"ax",@progbits; ret .section .init_array.a,"awo",@init_array,.text.a; ret % gcc -fuse-ld=bfd a.s -nostdlib -Wl,--gc-sections /usr/bin/ld.bfd: a.out: sh_link of section `.init_array' points to discarded section `.text.a' of `/tmp/cceqfqVM.o' /usr/bin/ld.bfd: final link failed: bad value collect2: error: ld returned 1 exit status (Trunk GNU ld is the same.) If we allow GCable .init_array, we should discard .init_array.a and this should link without an error.
It isn't that SHT_INIT_ARRAY sections are treated specially (although they are for ld -r). The reason why .init_array.bbb and .init_array.a is kept is the KEEP in the default linker script: .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); } The pattern .init_array.* is there to match .init_array.65530 or similar with a numeric suffix. (In fact, it's probably wrong to match other named .init_array sections there, but that's a side issue.) KEEP operates on the named sections regardless of whether they are part of a group or not. We'd need to change the behaviour of KEEP (or invent a new keyword) if .init_array inside a group was to be gc'ed.