[ELF] Default to -z start-stop-gc with a glibc "__libc_" special case

Change the default to facilitate GC for metadata section usage, so that they
don't need SHF_LINK_ORDER or SHF_GROUP just to drop the unhelpful rule (if they
want to be unconditionally retained, use SHF_GNU_RETAIN
(`__attribute__((retain))`) or linker script `KEEP`).

The dropped SHF_GROUP special case makes the behavior of -z start-stop-gc and -z
nostart-stop-gc closer to GNU ld>=2.37 (https://sourceware.org/PR27451).

However, we default to -z start-stop-gc (which actually matches more closely to
GNU ld before 2015-10 https://sourceware.org/PR19167), which is different from
modern GNU ld (which has the unhelpful rule to work around glibc). As a
compensation, we special case `__libc_` sections as a workaround for glibc<2.34
(https://sourceware.org/PR27492).

Since -z start-stop-gc as the default actually matches the traditional GNU ld
behavior, there isn't much to be aware of. There was a systemd usage which has
been fixed by https://github.com/systemd/systemd/pull/19144

GitOrigin-RevId: 6d2d3bd0a61f5fc7fd9f61f48bc30e9ca77cc619
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 3401c01..2daee21 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -1133,7 +1133,7 @@
   config->zShstk = hasZOption(args, "shstk");
   config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0);
   config->zStartStopGC =
-      getZFlag(args, "start-stop-gc", "nostart-stop-gc", false);
+      getZFlag(args, "start-stop-gc", "nostart-stop-gc", true);
   config->zStartStopVisibility = getZStartStopVisibility(args);
   config->zText = getZFlag(args, "text", "notext", true);
   config->zWxneeded = hasZOption(args, "wxneeded");
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index a384a42..e828429 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -270,8 +270,11 @@
 
     if (isReserved(sec) || script->shouldKeep(sec)) {
       enqueue(sec, 0);
-    } else if (!config->zStartStopGC && isValidCIdentifier(sec->name) &&
-               !sec->nextInSectionGroup) {
+    } else if ((!config->zStartStopGC || sec->name.startswith("__libc_")) &&
+               isValidCIdentifier(sec->name)) {
+      // As a workaround for glibc libc.a before 2.34
+      // (https://sourceware.org/PR27492), retain __libc_atexit and similar
+      // sections regardless of zStartStopGC.
       cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
       cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
     }
diff --git a/test/ELF/gc-sections-metadata-startstop.s b/test/ELF/gc-sections-metadata-startstop.s
index 4f65533..7613452 100644
--- a/test/ELF/gc-sections-metadata-startstop.s
+++ b/test/ELF/gc-sections-metadata-startstop.s
@@ -2,13 +2,13 @@
 # LINK_ORDER cnamed sections are not kept alive by the __start_* reference.
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: ld.lld --gc-sections %t.o -o %t
-# RUN: llvm-objdump --section-headers -t %t | FileCheck  %s
 # RUN: ld.lld --gc-sections -z start-stop-gc -z nostart-stop-gc %t.o -o %t
 # RUN: llvm-objdump --section-headers -t %t | FileCheck  %s
 
-## With -z start-stop-gc, non-SHF_LINK_ORDER non-SHF_GROUP C identifier name
+## With -z start-stop-gc (default), non-SHF_LINK_ORDER C identifier name
 ## sections are not retained by __start_/__stop_ references.
+# RUN: ld.lld --gc-sections %t.o -o %t
+# RUN: llvm-readelf -S -s %t | FileCheck %s --check-prefix=GC
 # RUN: ld.lld --gc-sections -z start-stop-gc %t.o -o %t1
 # RUN: llvm-readelf -S -s %t1 | FileCheck %s --check-prefix=GC
 
@@ -44,4 +44,3 @@
 
 .section yy,"ao",@progbits,.foo
 .quad 0
-
diff --git a/test/ELF/gc-sections-startstop.s b/test/ELF/gc-sections-startstop.s
index 20c244a..569cd3c 100644
--- a/test/ELF/gc-sections-startstop.s
+++ b/test/ELF/gc-sections-startstop.s
@@ -1,6 +1,4 @@
-## Check that group members are retained or discarded as a unit, and
-## sections whose names are C identifiers aren't considered roots if
-## they're members of a group.
+## Check that group members are retained or discarded as a unit.
 
 # REQUIRES: x86
 
@@ -10,24 +8,40 @@
 
 # RUN: echo ".global __start___data; __start___data:" > %t2.s
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
-# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: ld.lld -shared %t2.o --soname=t2 -o %t2.so
 # RUN: ld.lld %t.o --gc-sections -o %t2 %t2.so
 # RUN: llvm-readelf -s %t2 | FileCheck %s
 
+## The referenced __data is retained.
 # CHECK:     [[#%x,ADDR:]] {{.*}} __start___data
 # CHECK:     [[#ADDR + 8]] {{.*}} __stop___data
+## __libc_atexit is retained even if there is no reference, as a workaround for
+## glibc<2.34 (BZ #27492).
+# CHECK:     [[#%x,ADDR:]] {{.*}} __start___libc_atexit
+# CHECK:     [[#ADDR + 8]] {{.*}} __stop___libc_atexit
 # CHECK:     _start
 # CHECK:     f
 # CHECK-NOT: g
 
+## If -z nostart-stop-gc, sections whose names are C identifiers are retained by
+## __start_/__stop_ references.
+# RUN: ld.lld %t.o %t2.so --gc-sections -z nostart-stop-gc -o %t3
+# RUN: llvm-readelf -s %t3 | FileCheck %s --check-prefix=NOGC
+# NOGC:     [[#%x,ADDR:]] {{.*}} __start___data
+# NOGC:     [[#ADDR + 16]] {{.*}} __stop___data
+
 .weak __start___data
 .weak __stop___data
+.weak __start___libc_atexit
+.weak __stop___libc_atexit
 
 .section .text,"ax",@progbits
 .global _start
 _start:
   .quad __start___data - .
   .quad __stop___data - .
+  .quad __start___libc_atexit - .
+  .quad __stop___libc_atexit - .
   call f
 
 .section __data,"axG",@progbits,f
@@ -45,3 +59,6 @@
 .global g
 g:
   nop
+
+.section __libc_atexit,"a",@progbits
+.quad 0
diff --git a/test/ELF/linkerscript/sections-gc2.s b/test/ELF/linkerscript/sections-gc2.s
index 7b1fa8d..76be65f 100644
--- a/test/ELF/linkerscript/sections-gc2.s
+++ b/test/ELF/linkerscript/sections-gc2.s
@@ -5,7 +5,7 @@
 # RUN:         used_in_script : { *(used_in_script) } \
 # RUN:         .text : { *(.text) } \
 # RUN:       }" > %t.script
-# RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections
+# RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections -z nostart-stop-gc
 # RUN: llvm-objdump -h %t.so | FileCheck %s
 
 # CHECK: Idx Name          Size      VMA          Type
diff --git a/test/ELF/lto/section-name.ll b/test/ELF/lto/section-name.ll
index ac74492..626c766 100644
--- a/test/ELF/lto/section-name.ll
+++ b/test/ELF/lto/section-name.ll
@@ -2,7 +2,7 @@
 ; RUN: llvm-as %s -o %t.o
 ; RUN: ld.lld %t.o -o %t.so -shared
 ; RUN: llvm-readelf -S %t.so | FileCheck %s
-; RUN: ld.lld %t.o -o %t.so -shared --gc-sections
+; RUN: ld.lld %t.o -o %t.so -shared --gc-sections -z nostart-stop-gc
 ; RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=GC %s
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/test/ELF/relocatable-gc.s b/test/ELF/relocatable-gc.s
index a59aa10..7d367ba 100644
--- a/test/ELF/relocatable-gc.s
+++ b/test/ELF/relocatable-gc.s
@@ -42,7 +42,7 @@
 ## If .text is retained, its referenced qux and .fred are retained as well.
 ## fred_und is used (by .fred) and thus emitted.
 ## Note, GNU ld does not retain qux.
-# RUN: ld.lld -r --gc-sections -e _start %t.o -o %tstart.ro
+# RUN: ld.lld -r --gc-sections -z nostart-stop-gc -e _start %t.o -o %tstart.ro
 # RUN: llvm-readelf -Ss %tstart.ro | FileCheck %s --check-prefix=KEEP_START
 
 # KEEP_START:      [ 1] .text