diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -239,6 +239,7 @@ 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 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -451,10 +451,11 @@ 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 @@ 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 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -270,7 +270,8 @@ 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 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -802,6 +802,8 @@ .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 --- 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