[lld] 4bbcd63 - [ELF] Add -z start-stop-gc to let __start_/__stop_ not retain C identifier name sections

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 25 15:46:44 PST 2021


Author: Fangrui Song
Date: 2021-02-25T15:46:37-08:00
New Revision: 4bbcd63eea4950c38e29f9e29b1d11b7d7894469

URL: https://github.com/llvm/llvm-project/commit/4bbcd63eea4950c38e29f9e29b1d11b7d7894469
DIFF: https://github.com/llvm/llvm-project/commit/4bbcd63eea4950c38e29f9e29b1d11b7d7894469.diff

LOG: [ELF] Add -z start-stop-gc to let __start_/__stop_ not retain C identifier name sections

For one metadata section usage, each text section references a metadata section.
The metadata sections have a C identifier name to allow the runtime to collect them via `__start_/__stop_` symbols.

Since `__start_`/`__stop_` references are always present from live sections, the
C identifier name sections appear like GC roots, which means they cannot be
discarded by `ld --gc-sections`.

To make such sections GCable, either SHF_LINK_ORDER or a section group is needed.

SHF_LINK_ORDER is not suitable for the references can be inlined into other functions
(See D97430:
Function A (in the section .text.A) references its `__sancov_guard` section.
Function B inlines A (so now .text.B references `__sancov_guard` - this is invalid with the semantics of SHF_LINK_ORDER).

In the linking stage,
if `.text.A` gets discarded, and `__sancov_guard` is retained via the reference from `.text.B`,
the output will be invalid because `__sancov_guard` references the discarded `.text.A`.
LLD errors "sh_link points to discarded section".
)

A section group have size overhead, and is cumbersome when there is just one metadata section.

Add `-z start-stop-gc` to drop the "__start_/__stop_ references retain
non-SHF_LINK_ORDER non-SHF_GROUP C identifier name sections" rule.
We reserve the rights to switch the default in the future.

Reviewed By: phosek, jrtc27

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

Added: 
    

Modified: 
    lld/ELF/Config.h
    lld/ELF/Driver.cpp
    lld/ELF/MarkLive.cpp
    lld/docs/ld.lld.1
    lld/test/ELF/gc-sections-metadata-startstop.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f80c6fbe4d5e..966bfd3bfad8 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -239,6 +239,7 @@ struct Configuration {
   bool zRelro;
   bool zRodynamic;
   bool zShstk;
+  bool zStartStopGC;
   uint8_t zStartStopVisibility;
   bool zText;
   bool zRetpolineplt;

diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index dbc173187092..f9ff5d6a8c52 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -451,10 +451,11 @@ static bool isKnownZFlag(StringRef s) {
          s == "initfirst" || s == "interpose" ||
          s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" ||
          s == "separate-code" || s == "separate-loadable-segments" ||
-         s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
-         s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
-         s == "nognustack" || s == "nokeep-text-section-prefix" ||
-         s == "norelro" || s == "noseparate-code" || s == "notext" ||
+         s == "start-stop-gc" || s == "nocombreloc" || s == "nocopyreloc" ||
+         s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" ||
+         s == "noexecstack" || s == "nognustack" ||
+         s == "nokeep-text-section-prefix" || s == "norelro" ||
+         s == "noseparate-code" || s == "nostart-stop-gc" || s == "notext" ||
          s == "now" || s == "origin" || s == "pac-plt" || s == "rel" ||
          s == "rela" || s == "relro" || s == "retpolineplt" ||
          s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" ||
@@ -1119,6 +1120,8 @@ static void readConfigs(opt::InputArgList &args) {
   config->zSeparate = getZSeparate(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);
   config->zStartStopVisibility = getZStartStopVisibility(args);
   config->zText = getZFlag(args, "text", "notext", true);
   config->zWxneeded = hasZOption(args, "wxneeded");

diff  --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 92b968d665be..a384a4250b27 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -270,7 +270,8 @@ template <class ELFT> void MarkLive<ELFT>::run() {
 
     if (isReserved(sec) || script->shouldKeep(sec)) {
       enqueue(sec, 0);
-    } else if (isValidCIdentifier(sec->name) && !sec->nextInSectionGroup) {
+    } else if (!config->zStartStopGC && 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/docs/ld.lld.1 b/lld/docs/ld.lld.1
index cd9052e678cc..42525df76ada 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -802,6 +802,8 @@ The stack size is recorded as the size of the
 .Dv PT_GNU_STACK
 program segment.
 .Pp
+.It Cm start-stop-gc
+Don't let __start_/__stop_ references retain non-SHF_LINK_ORDER non-SHF_GROUP C identifier name sections.
 .It Cm text
 Do not allow relocations against read-only segments.
 This is the default.

diff  --git a/lld/test/ELF/gc-sections-metadata-startstop.s b/lld/test/ELF/gc-sections-metadata-startstop.s
index 51324261cc8d..4f6553365c1d 100644
--- a/lld/test/ELF/gc-sections-metadata-startstop.s
+++ b/lld/test/ELF/gc-sections-metadata-startstop.s
@@ -4,6 +4,13 @@
 # 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
+## sections are not retained by __start_/__stop_ references.
+# RUN: ld.lld --gc-sections -z start-stop-gc %t.o -o %t1
+# RUN: llvm-readelf -S -s %t1 | FileCheck %s --check-prefix=GC
 
 # CHECK: Sections:
 # CHECK-NOT: yy
@@ -14,6 +21,13 @@
 # CHECK:   xx    0000000000000000 .protected __start_xx
 # CHECK: w *UND* 0000000000000000 __start_yy
 
+# GC:     Section Headers:
+# GC-NOT:   xx
+# GC-NOT:   yy
+
+# GC:       WEAK DEFAULT UND __start_xx
+# GC:       WEAK DEFAULT UND __start_yy
+
 .weak __start_xx
 .weak __start_yy
 


        


More information about the llvm-commits mailing list