[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