Skip to content

Commit 6d2d3bd

Browse files
committed
[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 systemd/systemd#19144
1 parent 5c72975 commit 6d2d3bd

File tree

7 files changed

+33
-14
lines changed

7 files changed

+33
-14
lines changed

lld/ELF/Driver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ static void readConfigs(opt::InputArgList &args) {
11331133
config->zShstk = hasZOption(args, "shstk");
11341134
config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0);
11351135
config->zStartStopGC =
1136-
getZFlag(args, "start-stop-gc", "nostart-stop-gc", false);
1136+
getZFlag(args, "start-stop-gc", "nostart-stop-gc", true);
11371137
config->zStartStopVisibility = getZStartStopVisibility(args);
11381138
config->zText = getZFlag(args, "text", "notext", true);
11391139
config->zWxneeded = hasZOption(args, "wxneeded");

lld/ELF/MarkLive.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,11 @@ template <class ELFT> void MarkLive<ELFT>::run() {
270270

271271
if (isReserved(sec) || script->shouldKeep(sec)) {
272272
enqueue(sec, 0);
273-
} else if (!config->zStartStopGC && isValidCIdentifier(sec->name) &&
274-
!sec->nextInSectionGroup) {
273+
} else if ((!config->zStartStopGC || sec->name.startswith("__libc_")) &&
274+
isValidCIdentifier(sec->name)) {
275+
// As a workaround for glibc libc.a before 2.34
276+
// (https://sourceware.org/PR27492), retain __libc_atexit and similar
277+
// sections regardless of zStartStopGC.
275278
cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
276279
cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
277280
}

lld/test/ELF/gc-sections-metadata-startstop.s

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
# LINK_ORDER cnamed sections are not kept alive by the __start_* reference.
33

44
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
5-
# RUN: ld.lld --gc-sections %t.o -o %t
6-
# RUN: llvm-objdump --section-headers -t %t | FileCheck %s
75
# RUN: ld.lld --gc-sections -z start-stop-gc -z nostart-stop-gc %t.o -o %t
86
# RUN: llvm-objdump --section-headers -t %t | FileCheck %s
97

10-
## With -z start-stop-gc, non-SHF_LINK_ORDER non-SHF_GROUP C identifier name
8+
## With -z start-stop-gc (default), non-SHF_LINK_ORDER C identifier name
119
## sections are not retained by __start_/__stop_ references.
10+
# RUN: ld.lld --gc-sections %t.o -o %t
11+
# RUN: llvm-readelf -S -s %t | FileCheck %s --check-prefix=GC
1212
# RUN: ld.lld --gc-sections -z start-stop-gc %t.o -o %t1
1313
# RUN: llvm-readelf -S -s %t1 | FileCheck %s --check-prefix=GC
1414

@@ -44,4 +44,3 @@ _start:
4444

4545
.section yy,"ao",@progbits,.foo
4646
.quad 0
47-

lld/test/ELF/gc-sections-startstop.s

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
## Check that group members are retained or discarded as a unit, and
2-
## sections whose names are C identifiers aren't considered roots if
3-
## they're members of a group.
1+
## Check that group members are retained or discarded as a unit.
42

53
# REQUIRES: x86
64

@@ -10,24 +8,40 @@
108

119
# RUN: echo ".global __start___data; __start___data:" > %t2.s
1210
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o
13-
# RUN: ld.lld -shared %t2.o -o %t2.so
11+
# RUN: ld.lld -shared %t2.o --soname=t2 -o %t2.so
1412
# RUN: ld.lld %t.o --gc-sections -o %t2 %t2.so
1513
# RUN: llvm-readelf -s %t2 | FileCheck %s
1614

15+
## The referenced __data is retained.
1716
# CHECK: [[#%x,ADDR:]] {{.*}} __start___data
1817
# CHECK: [[#ADDR + 8]] {{.*}} __stop___data
18+
## __libc_atexit is retained even if there is no reference, as a workaround for
19+
## glibc<2.34 (BZ #27492).
20+
# CHECK: [[#%x,ADDR:]] {{.*}} __start___libc_atexit
21+
# CHECK: [[#ADDR + 8]] {{.*}} __stop___libc_atexit
1922
# CHECK: _start
2023
# CHECK: f
2124
# CHECK-NOT: g
2225

26+
## If -z nostart-stop-gc, sections whose names are C identifiers are retained by
27+
## __start_/__stop_ references.
28+
# RUN: ld.lld %t.o %t2.so --gc-sections -z nostart-stop-gc -o %t3
29+
# RUN: llvm-readelf -s %t3 | FileCheck %s --check-prefix=NOGC
30+
# NOGC: [[#%x,ADDR:]] {{.*}} __start___data
31+
# NOGC: [[#ADDR + 16]] {{.*}} __stop___data
32+
2333
.weak __start___data
2434
.weak __stop___data
35+
.weak __start___libc_atexit
36+
.weak __stop___libc_atexit
2537

2638
.section .text,"ax",@progbits
2739
.global _start
2840
_start:
2941
.quad __start___data - .
3042
.quad __stop___data - .
43+
.quad __start___libc_atexit - .
44+
.quad __stop___libc_atexit - .
3145
call f
3246

3347
.section __data,"axG",@progbits,f
@@ -45,3 +59,6 @@ f:
4559
.global g
4660
g:
4761
nop
62+
63+
.section __libc_atexit,"a",@progbits
64+
.quad 0

lld/test/ELF/linkerscript/sections-gc2.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# RUN: used_in_script : { *(used_in_script) } \
66
# RUN: .text : { *(.text) } \
77
# RUN: }" > %t.script
8-
# RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections
8+
# RUN: ld.lld -T %t.script -o %t.so %t.o --gc-sections -z nostart-stop-gc
99
# RUN: llvm-objdump -h %t.so | FileCheck %s
1010

1111
# CHECK: Idx Name Size VMA Type

lld/test/ELF/lto/section-name.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: llvm-as %s -o %t.o
33
; RUN: ld.lld %t.o -o %t.so -shared
44
; RUN: llvm-readelf -S %t.so | FileCheck %s
5-
; RUN: ld.lld %t.o -o %t.so -shared --gc-sections
5+
; RUN: ld.lld %t.o -o %t.so -shared --gc-sections -z nostart-stop-gc
66
; RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=GC %s
77

88
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

lld/test/ELF/relocatable-gc.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
## If .text is retained, its referenced qux and .fred are retained as well.
4343
## fred_und is used (by .fred) and thus emitted.
4444
## Note, GNU ld does not retain qux.
45-
# RUN: ld.lld -r --gc-sections -e _start %t.o -o %tstart.ro
45+
# RUN: ld.lld -r --gc-sections -z nostart-stop-gc -e _start %t.o -o %tstart.ro
4646
# RUN: llvm-readelf -Ss %tstart.ro | FileCheck %s --check-prefix=KEEP_START
4747

4848
# KEEP_START: [ 1] .text

0 commit comments

Comments
 (0)