Skip to content

Commit

Permalink
[ELF] Default to -z start-stop-gc with a glibc "__libc_" special case
Browse files Browse the repository at this point in the history
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
  • Loading branch information
MaskRay authored and arichardson committed Sep 10, 2021
2 parents 41aafc7 + 6d2d3bd commit c127f96
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 14 deletions.
2 changes: 1 addition & 1 deletion lld/ELF/Driver.cpp
Expand Up @@ -1212,7 +1212,7 @@ static void readConfigs(opt::InputArgList &args) {
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");
Expand Down
7 changes: 5 additions & 2 deletions lld/ELF/MarkLive.cpp
Expand Up @@ -270,8 +270,11 @@ template <class ELFT> void MarkLive<ELFT>::run() {

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);
}
Expand Down
7 changes: 3 additions & 4 deletions lld/test/ELF/gc-sections-metadata-startstop.s
Expand Up @@ -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

Expand Down Expand Up @@ -44,4 +44,3 @@ _start:

.section yy,"ao",@progbits,.foo
.quad 0

25 changes: 21 additions & 4 deletions lld/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

Expand All @@ -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
Expand All @@ -45,3 +59,6 @@ f:
.global g
g:
nop

.section __libc_atexit,"a",@progbits
.quad 0
2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript/sections-gc2.s
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/lto/section-name.ll
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/relocatable-gc.s
Expand Up @@ -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
Expand Down

0 comments on commit c127f96

Please sign in to comment.