Author: Fangrui Song Date: 2021-07-29T19:29:45-07:00 New Revision: ad5a6b15ff04920a17524dd11adb828240c7103e
URL: https://github.com/llvm/llvm-project/commit/ad5a6b15ff04920a17524dd11adb828240c7103e DIFF: https://github.com/llvm/llvm-project/commit/ad5a6b15ff04920a17524dd11adb828240c7103e.diff LOG: [ELF] Add -Bsymbolic-non-weak-functions This option is a subset of -Bsymbolic-functions. It applies to STB_GLOBAL STT_FUNC definitions. The address of a vague linkage function (STB_WEAK STT_FUNC, e.g. an inline function, a template instantiation) seen by a -Bsymbolic-functions linked shared object may be different from the address seen from outside the shared object. Such cases are uncommon. (ELF/Mach-O programs may use `-fvisibility-inlines-hidden` to break such pointer equality. On Windows, correct dllexport and dllimport are needed to make pointer equality work. Windows link.exe enables /OPT:ICF by default so different inline functions may have the same address.) ``` // a.cc -> a.o -> a.so (-Bsymbolic-functions) inline void f() {} void *g() { return (void *)&f; } // b.cc -> b.o -> exe // The address is different! inline void f() {} ``` -Bsymbolic-non-weak-functions is a safer (C++ conforming) subset of -Bsymbolic-functions, which can make such programs work. Implementations usually emit a vague linkage definition in a COMDAT group. We could detect the group (with more code) but I feel that we should just check STB_WEAK for simplicity. A weak definition will thus serve as an escape hatch for rare cases when users want interposition on definitions. GNU ld feature request: https://sourceware.org/bugzilla/show_bug.cgi?id=27871 Longer write-up: https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic If Linux distributions migrate to protected non-vague-linkage external linkage functions by default, the linker option can still be handy because it allows rapid experiment without recompilation. Protected function addresses currently have deep issues in GNU ld. Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D102570 (cherry picked from commit b06426da764a8d0254521b33d667db8f26ae5e2f) Added: Modified: lld/ELF/Config.h lld/ELF/Driver.cpp lld/ELF/Options.td lld/ELF/Symbols.cpp lld/ELF/SyntheticSections.cpp lld/docs/ReleaseNotes.rst lld/docs/ld.lld.1 lld/test/ELF/bsymbolic.s Removed: ################################################################################ diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 9144347045b9..a996a815599a 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -38,6 +38,10 @@ enum ELFKind { ELF64BEKind }; +// For -Bno-symbolic, -Bsymbolic-non-weak-functions, -Bsymbolic-functions, +// -Bsymbolic. +enum class BsymbolicKind { None, NonWeakFunctions, Functions, All }; + // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; @@ -144,8 +148,7 @@ struct Configuration { bool armHasMovtMovw = false; bool armJ1J2BranchEncoding = false; bool asNeeded = false; - bool bsymbolic = false; - bool bsymbolicFunctions = false; + BsymbolicKind bsymbolic = BsymbolicKind::None; bool callGraphProfileSort; bool checkSections; bool checkDynamicRelocs; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index a15959158653..91e7df21a60a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1006,12 +1006,15 @@ static void readConfigs(opt::InputArgList &args) { 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_non_weak_functions, + OPT_Bsymbolic_functions, OPT_Bsymbolic)) { + if (arg->getOption().matches(OPT_Bsymbolic_non_weak_functions)) + config->bsymbolic = BsymbolicKind::NonWeakFunctions; + 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); @@ -1374,7 +1377,8 @@ static void readConfigs(opt::InputArgList &args) { // 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<MemoryBufferRef> buffer = readFile(arg->getValue())) readDynamicList(*buffer); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index bedcf43bbe85..f0e4c11b79eb 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -43,6 +43,9 @@ def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind default visibility defined symbols def Bsymbolic_functions: F<"Bsymbolic-functions">, HelpText<"Bind default visibility defined function symbols locally for -shared">; +def Bsymbolic_non_weak_functions: F<"Bsymbolic-non-weak-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 index 1039be369d9e..496be33dd182 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -368,8 +368,12 @@ bool elf::computeIsPreemptible(const Symbol &sym) { // 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())) + // in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of + // -Bsymbolic-functions. + if (config->symbolic || + (config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) || + (config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() && + sym.binding != STB_WEAK)) return sym.inDynamicList; return true; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 3496df1d2814..187b2ac90c21 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1356,7 +1356,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { // 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 index 40439c995f17..a52ee4348f78 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -30,6 +30,8 @@ ELF Improvements (`D102461 <https://reviews.llvm.org/D102461>`_) * A new linker script command ``OVERWRITE_SECTIONS`` has been added. (`D103303 <https://reviews.llvm.org/D103303>`_) +* ``-Bsymbolic-non-weak-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``. + (`D102570 <https://reviews.llvm.org/D102570>`_) Breaking changes ---------------- diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index ba3b0779e699..bd67e58daa4d 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -85,6 +85,9 @@ flag. .It Fl Bsymbolic-functions Bind default visibility defined function symbols locally for .Fl shared. +.It Fl Bsymbolic-non-weak-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. .Ar value diff --git a/lld/test/ELF/bsymbolic.s b/lld/test/ELF/bsymbolic.s index a083d2cebe88..ff182b110d06 100644 --- 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-non-weak-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: ld.lld -shared -Bno-symbolic -Bsymbolic %t/a.o %t/b.o -o %t.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 %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 {{.*}} <default@plt> # ASM_DEF-NEXT: callq {{.*}} <protected> # ASM_DEF-NEXT: callq {{.*}} <hidden> +# ASM_DEF-NEXT: callq {{.*}} <weak_default@plt> # ASM_DEF-NEXT: callq {{.*}} <ext_default@plt> # ASM_DEF-NEXT: callq {{.*}} <notype_default@plt> # ASM_DEF-NEXT: callq {{.*}} <undef@plt> +# 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 {{.*}} <default> +# ASM_GFUN-NEXT: callq {{.*}} <protected> +# ASM_GFUN-NEXT: callq {{.*}} <hidden> +# ASM_GFUN-NEXT: callq {{.*}} <weak_default@plt> +# ASM_GFUN-NEXT: callq {{.*}} <ext_default> +# ASM_GFUN-NEXT: callq {{.*}} <notype_default@plt> +# ASM_GFUN-NEXT: callq {{.*}} <undef@plt> + # 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 {{.*}} <default> # ASM_FUN-NEXT: callq {{.*}} <protected> # ASM_FUN-NEXT: callq {{.*}} <hidden> +# ASM_FUN-NEXT: callq {{.*}} <weak_default> # ASM_FUN-NEXT: callq {{.*}} <ext_default> # ASM_FUN-NEXT: callq {{.*}} <notype_default@plt> # ASM_FUN-NEXT: callq {{.*}} <undef@plt> @@ -80,20 +108,24 @@ # ASM_ALL-NEXT: callq {{.*}} <default> # ASM_ALL-NEXT: callq {{.*}} <protected> # ASM_ALL-NEXT: callq {{.*}} <hidden> +# ASM_ALL-NEXT: callq {{.*}} <weak_default> # ASM_ALL-NEXT: callq {{.*}} <ext_default> # ASM_ALL-NEXT: callq {{.*}} <notype_default> # ASM_ALL-NEXT: callq {{.*}} <undef@plt> #--- 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 @@ _start: callq protected@PLT callq hidden@PLT + callq weak_default@PLT + callq ext_default@PLT callq notype_default@PLT _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits