diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -37,6 +37,10 @@ ELF64BEKind }; +// For -Bno-symbolic, -Bsymbolic-global-functions, -Bsymbolic-functions, +// -Bsymbolic. +enum class BsymbolicKind { None, GlobalFunctions, Functions, All }; + // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; @@ -143,8 +147,7 @@ bool armHasMovtMovw = false; bool armJ1J2BranchEncoding = false; bool asNeeded = false; - bool bsymbolic = false; - bool bsymbolicFunctions = false; + BsymbolicKind bsymbolic = BsymbolicKind::None; bool callGraphProfileSort; bool checkSections; bool compressDebugSections; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -953,12 +953,15 @@ OPT_no_allow_multiple_definition, false) || hasZOption(args, "muldefs"); config->auxiliaryList = args::getStrings(args, OPT_auxiliary); - if (opt::Arg *arg = args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_functions, - OPT_Bsymbolic)) { - if (arg->getOption().matches(OPT_Bsymbolic_functions)) - config->bsymbolicFunctions = true; + if (opt::Arg *arg = + args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_global_functions, + OPT_Bsymbolic_functions, OPT_Bsymbolic)) { + if (arg->getOption().matches(OPT_Bsymbolic_global_functions)) + config->bsymbolic = BsymbolicKind::GlobalFunctions; + else if (arg->getOption().matches(OPT_Bsymbolic_functions)) + config->bsymbolic = BsymbolicKind::Functions; else if (arg->getOption().matches(OPT_Bsymbolic)) - config->bsymbolic = true; + config->bsymbolic = BsymbolicKind::All; } config->checkSections = args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); @@ -1321,7 +1324,8 @@ // When producing an executable, --dynamic-list specifies non-local defined // symbols which are required to be exported. When producing a shared object, // symbols not specified by --dynamic-list are non-preemptible. - config->symbolic = config->bsymbolic || args.hasArg(OPT_dynamic_list); + config->symbolic = + config->bsymbolic == BsymbolicKind::All || args.hasArg(OPT_dynamic_list); for (auto *arg : args.filtered(OPT_dynamic_list)) if (Optional buffer = readFile(arg->getValue())) readDynamicList(*buffer); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -43,6 +43,9 @@ def Bsymbolic_functions: F<"Bsymbolic-functions">, HelpText<"Bind default visibility defined function symbols locally for -shared">; +def Bsymbolic_global_functions: F<"Bsymbolic-global-functions">, + HelpText<"Bind default visibility defined STB_GLOBAL function symbols locally for -shared">; + def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">; def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -367,7 +367,10 @@ // If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is // specified and the symbol is STT_FUNC, the symbol is preemptible iff it is // in the dynamic list. - if (config->symbolic || (config->bsymbolicFunctions && sym.isFunc())) + if (config->symbolic || + (config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) || + (config->bsymbolic == BsymbolicKind::GlobalFunctions && sym.isFunc() && + sym.binding == STB_GLOBAL)) return sym.inDynamicList; return true; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1349,7 +1349,7 @@ // Set DT_FLAGS and DT_FLAGS_1. uint32_t dtFlags = 0; uint32_t dtFlags1 = 0; - if (config->bsymbolic) + if (config->bsymbolic == BsymbolicKind::All) dtFlags |= DF_SYMBOLIC; if (config->zGlobal) dtFlags1 |= DF_1_GLOBAL; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -28,6 +28,7 @@ (`D102461 `_) * ``-Bno-symbolic`` has been added. (`D102461 `_) +* ``-Bsymbolic-global-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``. Breaking changes ---------------- 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 @@ -84,6 +84,8 @@ flag. .It Fl Bsymbolic-functions Bind default visibility defined function symbols locally for +.It Fl Bsymbolic-global-functions +Bind default visibility defined STB_GLOBAL function symbols locally for .Fl shared. .It Fl -build-id Ns = Ns Ar value Generate a build ID note. diff --git a/lld/test/ELF/bsymbolic.s b/lld/test/ELF/bsymbolic.s --- a/lld/test/ELF/bsymbolic.s +++ b/lld/test/ELF/bsymbolic.s @@ -6,22 +6,27 @@ # RUN: llvm-readobj -r %t0.so | FileCheck %s --check-prefix=REL_DEF # RUN: llvm-objdump -d %t0.so | FileCheck %s --check-prefix=ASM_DEF +## -Bsymbolic-functions makes all STB_GLOBAL STT_FUNC definitions non-preemptible. +# RUN: ld.lld -shared -Bsymbolic-global-functions %t/a.o %t/b.o -o %t1.so +# RUN: llvm-readobj -r %t1.so | FileCheck %s --check-prefix=REL_GFUN +# RUN: llvm-objdump -d %t1.so | FileCheck %s --check-prefix=ASM_GFUN + ## -Bsymbolic-functions makes all STT_FUNC definitions non-preemptible. -# RUN: ld.lld -shared -Bsymbolic-functions %t/a.o %t/b.o -o %t1.so -# RUN: llvm-readobj -r %t1.so | FileCheck %s --check-prefix=REL_FUN -# RUN: llvm-objdump -d %t1.so | FileCheck %s --check-prefix=ASM_FUN +# RUN: ld.lld -shared -Bsymbolic-functions %t/a.o %t/b.o -o %t2.so +# RUN: llvm-readobj -r %t2.so | FileCheck %s --check-prefix=REL_FUN +# RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=ASM_FUN ## -Bsymbolic makes all definitions non-preemptible. -# RUN: ld.lld -shared -Bsymbolic %t/a.o %t/b.o -o %t2.so -# RUN: llvm-readobj -r %t2.so | FileCheck %s --check-prefix=REL_ALL -# RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=ASM_ALL +# RUN: ld.lld -shared -Bsymbolic %t/a.o %t/b.o -o %t3.so +# RUN: llvm-readobj -r %t3.so | FileCheck %s --check-prefix=REL_ALL +# RUN: llvm-objdump -d %t3.so | FileCheck %s --check-prefix=ASM_ALL # RUN: ld.lld -shared -Bsymbolic-functions -Bsymbolic %t/a.o %t/b.o -o %t.so -# RUN: cmp %t.so %t2.so +# RUN: cmp %t.so %t3.so # RUN: ld.lld -shared -Bsymbolic -Bsymbolic-functions %t/a.o %t/b.o -o %t.so -# RUN: cmp %t.so %t1.so +# RUN: cmp %t.so %t2.so # RUN: ld.lld -shared -Bno-symbolic -Bsymbolic %t/a.o %t/b.o -o %t.so -# RUN: cmp %t.so %t2.so +# RUN: cmp %t.so %t3.so ## -Bno-symbolic can cancel previously specified -Bsymbolic and -Bsymbolic-functions. # RUN: ld.lld -shared -Bsymbolic -Bno-symbolic %t/a.o %t/b.o -o %t.so @@ -36,6 +41,7 @@ # REL_DEF-NEXT: } # REL_DEF-NEXT: .rela.plt { # REL_DEF-NEXT: R_X86_64_JUMP_SLOT default +# REL_DEF-NEXT: R_X86_64_JUMP_SLOT weak_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT ext_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT notype_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT undef @@ -45,10 +51,31 @@ # ASM_DEF-NEXT: callq {{.*}} # ASM_DEF-NEXT: callq {{.*}} # ASM_DEF-NEXT: callq {{.*}} +# ASM_DEF-NEXT: callq {{.*}} # ASM_DEF-NEXT: callq {{.*}} # ASM_DEF-NEXT: callq {{.*}} # ASM_DEF-NEXT: callq {{.*}} +# REL_GFUN: .rela.dyn { +# REL_GFUN-NEXT: R_X86_64_RELATIVE - +# REL_GFUN-NEXT: R_X86_64_RELATIVE - +# REL_GFUN-NEXT: R_X86_64_64 data_default +# REL_GFUN-NEXT: } +# REL_GFUN-NEXT: .rela.plt { +# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT weak_default +# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT notype_default +# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT undef +# REL_GFUN-NEXT: } + +# ASM_GFUN: <_start>: +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} +# ASM_GFUN-NEXT: callq {{.*}} + # REL_FUN: .rela.dyn { # REL_FUN-NEXT: R_X86_64_RELATIVE - # REL_FUN-NEXT: R_X86_64_RELATIVE - @@ -63,6 +90,7 @@ # ASM_FUN-NEXT: callq {{.*}} # ASM_FUN-NEXT: callq {{.*}} # ASM_FUN-NEXT: callq {{.*}} +# ASM_FUN-NEXT: callq {{.*}} # ASM_FUN-NEXT: callq {{.*}} # ASM_FUN-NEXT: callq {{.*}} # ASM_FUN-NEXT: callq {{.*}} @@ -80,20 +108,24 @@ # ASM_ALL-NEXT: callq {{.*}} # ASM_ALL-NEXT: callq {{.*}} # ASM_ALL-NEXT: callq {{.*}} +# ASM_ALL-NEXT: callq {{.*}} # ASM_ALL-NEXT: callq {{.*}} # ASM_ALL-NEXT: callq {{.*}} # ASM_ALL-NEXT: callq {{.*}} #--- a.s .globl default, protected, hidden, notype_default +.weak weak_default .protected protected .hidden hidden .type default, @function .type protected, @function .type hidden, @function +.type weak_default, @function default: nop protected: nop hidden: nop +weak_default: nop notype_default: nop .globl _start @@ -102,6 +134,8 @@ callq protected@PLT callq hidden@PLT + callq weak_default@PLT + callq ext_default@PLT callq notype_default@PLT