diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -230,6 +230,7 @@ bool zRelro; bool zRodynamic; bool zShstk; + uint8_t zStartStopVisibility; bool zText; bool zRetpolineplt; bool zWxneeded; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -411,6 +411,24 @@ return GnuStackKind::NoExec; } +static uint8_t getZStartStopVisibility(opt::InputArgList &args) { + for (auto *arg : args.filtered_reverse(OPT_z)) { + std::pair kv = StringRef(arg->getValue()).split('='); + if (kv.first == "start-stop-visibility") { + if (kv.second == "default") + return STV_DEFAULT; + else if (kv.second == "internal") + return STV_INTERNAL; + else if (kv.second == "hidden") + return STV_HIDDEN; + else if (kv.second == "protected") + return STV_PROTECTED; + error("unknown -z start-stop-visibility= value: " + StringRef(kv.second)); + } + } + return STV_PROTECTED; +} + static bool isKnownZFlag(StringRef s) { return s == "combreloc" || s == "copyreloc" || s == "defs" || s == "execstack" || s == "force-bti" || s == "force-ibt" || @@ -426,7 +444,8 @@ s == "rela" || s == "relro" || s == "retpolineplt" || s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" || s == "wxneeded" || s.startswith("common-page-size=") || - s.startswith("max-page-size=") || s.startswith("stack-size="); + s.startswith("max-page-size=") || s.startswith("stack-size=") || + s.startswith("start-stop-visibility="); } // Report an error for an unknown -z option. @@ -1046,6 +1065,7 @@ config->zSeparate = getZSeparate(args); config->zShstk = hasZOption(args, "shstk"); config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); + config->zStartStopVisibility = getZStartStopVisibility(args); config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2229,8 +2229,10 @@ StringRef s = sec->name; if (!isValidCIdentifier(s)) return; - addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED); - addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED); + addOptionalRegular(saver.save("__start_" + s), sec, 0, + config->zStartStopVisibility); + addOptionalRegular(saver.save("__stop_" + s), sec, -1, + config->zStartStopVisibility); } static bool needsPtLoad(OutputSection *sec) { diff --git a/lld/test/ELF/startstop-visibility.s b/lld/test/ELF/startstop-visibility.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/startstop-visibility.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -s %t | FileCheck %s + +# CHECK: 0 NOTYPE GLOBAL PROTECTED 2 __start_aaa +# CHECK: 0 NOTYPE GLOBAL PROTECTED 2 __stop_aaa + +# RUN: ld.lld -z start-stop-visibility=default %t.o -o %t1 +# RUN: llvm-readelf -s %t1 | FileCheck --check-prefix=CHECK-DEFAULT %s + +# CHECK-DEFAULT: 0 NOTYPE GLOBAL DEFAULT 2 __start_aaa +# CHECK-DEFAULT: 0 NOTYPE GLOBAL DEFAULT 2 __stop_aaa + +# RUN: ld.lld -z start-stop-visibility=internal %t.o -o %t2 +# RUN: llvm-readelf -s %t2 | FileCheck --check-prefix=CHECK-INTERNAL %s + +# CHECK-INTERNAL: 0 NOTYPE LOCAL INTERNAL 2 __start_aaa +# CHECK-INTERNAL: 0 NOTYPE LOCAL INTERNAL 2 __stop_aaa + +# RUN: ld.lld -z start-stop-visibility=hidden %t.o -o %t3 +# RUN: llvm-readelf -s %t3 | FileCheck --check-prefix=CHECK-HIDDEN %s + +# CHECK-HIDDEN: 0 NOTYPE LOCAL HIDDEN 2 __start_aaa +# CHECK-HIDDEN: 0 NOTYPE LOCAL HIDDEN 2 __stop_aaa + +# RUN: ld.lld -z start-stop-visibility=protected %t.o -o %t4 +# RUN: llvm-readelf -s %t4 | FileCheck --check-prefix=CHECK-PROTECTED %s + +# CHECK-PROTECTED: 0 NOTYPE GLOBAL PROTECTED 2 __start_aaa +# CHECK-PROTECTED: 0 NOTYPE GLOBAL PROTECTED 2 __stop_aaa + +# RUN: not ld.lld -z start-stop-visibility=aaa %t.o -o /dev/null +# CHECK-ERROR: error: unknown -z start-stop-visibility= value: aaa + +.quad __start_aaa +.quad __stop_aaa +.section aaa,"ax" + +.global _start +.text +_start: + nop