[lld][ELF] __start_/__stop_ refs don't retain C-ident named group sections
authorPetr Hosek <phosek@google.com>
Tue, 16 Feb 2021 07:41:16 +0000 (23:41 -0800)
committerPetr Hosek <phosek@google.com>
Sun, 21 Feb 2021 06:22:05 +0000 (22:22 -0800)
The special root semantics for identifier-named sections is meant
specifically for the metadata sections. In the context of group
semantics, where group members are always retained or discarded as a
unit, it's natural not to have this semantics apply to a section in a
group, otherwise we would never discard the group defeating the purpose
of using the group in the first place.

This change modifies the GC behavior so that __start_/__stop_ references
don't retain C identifier named sections in section groups which allows
for these groups to be collected. This matches the behavior of BFD ld.

The only kind of existing case that might break is interdependent
metadata sections that are all in a group together, but that group
doesn't contain any other sections referenced by anything except
implicit inclusion in a `__start_` and/or `__stop_`-referenced
identifier-named section, but such cases should be unlikely.

Differential Revision: https://reviews.llvm.org/D96753

lld/ELF/MarkLive.cpp
lld/test/ELF/gc-sections-startstop.s [new file with mode: 0644]
lld/test/ELF/startstop-gccollect.s [deleted file]

index 7d89338..92b968d 100644 (file)
@@ -270,7 +270,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
 
     if (isReserved(sec) || script->shouldKeep(sec)) {
       enqueue(sec, 0);
-    } else if (isValidCIdentifier(sec->name)) {
+    } else if (isValidCIdentifier(sec->name) && !sec->nextInSectionGroup) {
       cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
       cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
     }
diff --git a/lld/test/ELF/gc-sections-startstop.s b/lld/test/ELF/gc-sections-startstop.s
new file mode 100644 (file)
index 0000000..20c244a
--- /dev/null
@@ -0,0 +1,47 @@
+## 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.
+
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o --gc-sections -o %t
+# RUN: llvm-readelf -s %t | FileCheck %s
+
+# 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 %t.o --gc-sections -o %t2 %t2.so
+# RUN: llvm-readelf -s %t2 | FileCheck %s
+
+# CHECK:     [[#%x,ADDR:]] {{.*}} __start___data
+# CHECK:     [[#ADDR + 8]] {{.*}} __stop___data
+# CHECK:     _start
+# CHECK:     f
+# CHECK-NOT: g
+
+.weak __start___data
+.weak __stop___data
+
+.section .text,"ax",@progbits
+.global _start
+_start:
+  .quad __start___data - .
+  .quad __stop___data - .
+  call f
+
+.section __data,"axG",@progbits,f
+.quad 0
+
+.section .text.f,"axG",@progbits,f
+.global f
+f:
+  nop
+
+.section __data,"axG",@progbits,g
+.quad 0
+
+.section .text.g,"axG",@progbits,g
+.global g
+g:
+  nop
diff --git a/lld/test/ELF/startstop-gccollect.s b/lld/test/ELF/startstop-gccollect.s
deleted file mode 100644 (file)
index 8017bca..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-
-## Default run: sections foo and bar exist in output
-# RUN: ld.lld %t -o %tout
-# RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
-
-## Check that foo and bar sections are not garbage collected,
-## we do not want to reclaim sections if they are referred
-## by __start_* and __stop_* symbols.
-# RUN: ld.lld %t --gc-sections -o %tout
-# RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
-
-# RUN: echo ".global __start_foo; __start_foo:" > %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 %t --gc-sections -o %tout %t2.so
-# RUN: llvm-objdump -d %tout | FileCheck --check-prefix=DISASM %s
-
-# DISASM:      <_start>:
-# DISASM-NEXT:   callq   {{.*}} <__start_foo>
-# DISASM-NEXT:   callq   {{.*}} <__stop_bar>
-# DISASM-EMPTY:
-# DISASM-NEXT: Disassembly of section foo:
-# DISASM-EMPTY:
-# DISASM-NEXT: <__start_foo>:
-# DISASM-NEXT:   nop
-# DISASM-EMPTY:
-# DISASM-NEXT: Disassembly of section bar:
-# DISASM-EMPTY:
-# DISASM-NEXT: <bar>:
-# DISASM-NEXT:   nop
-
-.global _start
-.text
-_start:
- callq __start_foo
- callq __stop_bar
-
-.section foo,"ax"
- nop
-
-.section bar,"ax"
- nop