Skip to content

Commit ad5a6b1

Browse files
MaskRaytstellar
authored andcommitted
[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 b06426d)
1 parent 6b2e4c5 commit ad5a6b1

File tree

8 files changed

+73
-20
lines changed

8 files changed

+73
-20
lines changed

lld/ELF/Config.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ enum ELFKind {
3838
ELF64BEKind
3939
};
4040

41+
// For -Bno-symbolic, -Bsymbolic-non-weak-functions, -Bsymbolic-functions,
42+
// -Bsymbolic.
43+
enum class BsymbolicKind { None, NonWeakFunctions, Functions, All };
44+
4145
// For --build-id.
4246
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
4347

@@ -144,8 +148,7 @@ struct Configuration {
144148
bool armHasMovtMovw = false;
145149
bool armJ1J2BranchEncoding = false;
146150
bool asNeeded = false;
147-
bool bsymbolic = false;
148-
bool bsymbolicFunctions = false;
151+
BsymbolicKind bsymbolic = BsymbolicKind::None;
149152
bool callGraphProfileSort;
150153
bool checkSections;
151154
bool checkDynamicRelocs;

lld/ELF/Driver.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,12 +1006,15 @@ static void readConfigs(opt::InputArgList &args) {
10061006
OPT_no_allow_multiple_definition, false) ||
10071007
hasZOption(args, "muldefs");
10081008
config->auxiliaryList = args::getStrings(args, OPT_auxiliary);
1009-
if (opt::Arg *arg = args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_functions,
1010-
OPT_Bsymbolic)) {
1011-
if (arg->getOption().matches(OPT_Bsymbolic_functions))
1012-
config->bsymbolicFunctions = true;
1009+
if (opt::Arg *arg =
1010+
args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions,
1011+
OPT_Bsymbolic_functions, OPT_Bsymbolic)) {
1012+
if (arg->getOption().matches(OPT_Bsymbolic_non_weak_functions))
1013+
config->bsymbolic = BsymbolicKind::NonWeakFunctions;
1014+
else if (arg->getOption().matches(OPT_Bsymbolic_functions))
1015+
config->bsymbolic = BsymbolicKind::Functions;
10131016
else if (arg->getOption().matches(OPT_Bsymbolic))
1014-
config->bsymbolic = true;
1017+
config->bsymbolic = BsymbolicKind::All;
10151018
}
10161019
config->checkSections =
10171020
args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
@@ -1374,7 +1377,8 @@ static void readConfigs(opt::InputArgList &args) {
13741377
// When producing an executable, --dynamic-list specifies non-local defined
13751378
// symbols which are required to be exported. When producing a shared object,
13761379
// symbols not specified by --dynamic-list are non-preemptible.
1377-
config->symbolic = config->bsymbolic || args.hasArg(OPT_dynamic_list);
1380+
config->symbolic =
1381+
config->bsymbolic == BsymbolicKind::All || args.hasArg(OPT_dynamic_list);
13781382
for (auto *arg : args.filtered(OPT_dynamic_list))
13791383
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
13801384
readDynamicList(*buffer);

lld/ELF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind default visibility defined symbols
4343
def Bsymbolic_functions: F<"Bsymbolic-functions">,
4444
HelpText<"Bind default visibility defined function symbols locally for -shared">;
4545

46+
def Bsymbolic_non_weak_functions: F<"Bsymbolic-non-weak-functions">,
47+
HelpText<"Bind default visibility defined STB_GLOBAL function symbols locally for -shared">;
48+
4649
def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
4750

4851
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;

lld/ELF/Symbols.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,12 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
368368

369369
// If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is
370370
// specified and the symbol is STT_FUNC, the symbol is preemptible iff it is
371-
// in the dynamic list.
372-
if (config->symbolic || (config->bsymbolicFunctions && sym.isFunc()))
371+
// in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of
372+
// -Bsymbolic-functions.
373+
if (config->symbolic ||
374+
(config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) ||
375+
(config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() &&
376+
sym.binding != STB_WEAK))
373377
return sym.inDynamicList;
374378
return true;
375379
}

lld/ELF/SyntheticSections.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
13561356
// Set DT_FLAGS and DT_FLAGS_1.
13571357
uint32_t dtFlags = 0;
13581358
uint32_t dtFlags1 = 0;
1359-
if (config->bsymbolic)
1359+
if (config->bsymbolic == BsymbolicKind::All)
13601360
dtFlags |= DF_SYMBOLIC;
13611361
if (config->zGlobal)
13621362
dtFlags1 |= DF_1_GLOBAL;

lld/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ ELF Improvements
3030
(`D102461 <https://reviews.llvm.org/D102461>`_)
3131
* A new linker script command ``OVERWRITE_SECTIONS`` has been added.
3232
(`D103303 <https://reviews.llvm.org/D103303>`_)
33+
* ``-Bsymbolic-non-weak-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``.
34+
(`D102570 <https://reviews.llvm.org/D102570>`_)
3335

3436
Breaking changes
3537
----------------

lld/docs/ld.lld.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ flag.
8585
.It Fl Bsymbolic-functions
8686
Bind default visibility defined function symbols locally for
8787
.Fl shared.
88+
.It Fl Bsymbolic-non-weak-functions
89+
Bind default visibility defined STB_GLOBAL function symbols locally for
90+
.Fl shared.
8891
.It Fl -build-id Ns = Ns Ar value
8992
Generate a build ID note.
9093
.Ar value

lld/test/ELF/bsymbolic.s

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@
66
# RUN: llvm-readobj -r %t0.so | FileCheck %s --check-prefix=REL_DEF
77
# RUN: llvm-objdump -d %t0.so | FileCheck %s --check-prefix=ASM_DEF
88

9+
## -Bsymbolic-functions makes all STB_GLOBAL STT_FUNC definitions non-preemptible.
10+
# RUN: ld.lld -shared -Bsymbolic-non-weak-functions %t/a.o %t/b.o -o %t1.so
11+
# RUN: llvm-readobj -r %t1.so | FileCheck %s --check-prefix=REL_GFUN
12+
# RUN: llvm-objdump -d %t1.so | FileCheck %s --check-prefix=ASM_GFUN
13+
914
## -Bsymbolic-functions makes all STT_FUNC definitions non-preemptible.
10-
# RUN: ld.lld -shared -Bsymbolic-functions %t/a.o %t/b.o -o %t1.so
11-
# RUN: llvm-readobj -r %t1.so | FileCheck %s --check-prefix=REL_FUN
12-
# RUN: llvm-objdump -d %t1.so | FileCheck %s --check-prefix=ASM_FUN
15+
# RUN: ld.lld -shared -Bsymbolic-functions %t/a.o %t/b.o -o %t2.so
16+
# RUN: llvm-readobj -r %t2.so | FileCheck %s --check-prefix=REL_FUN
17+
# RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=ASM_FUN
1318

1419
## -Bsymbolic makes all definitions non-preemptible.
15-
# RUN: ld.lld -shared -Bsymbolic %t/a.o %t/b.o -o %t2.so
16-
# RUN: llvm-readobj -r %t2.so | FileCheck %s --check-prefix=REL_ALL
17-
# RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=ASM_ALL
20+
# RUN: ld.lld -shared -Bsymbolic %t/a.o %t/b.o -o %t3.so
21+
# RUN: llvm-readobj -r %t3.so | FileCheck %s --check-prefix=REL_ALL
22+
# RUN: llvm-objdump -d %t3.so | FileCheck %s --check-prefix=ASM_ALL
1823

1924
# RUN: ld.lld -shared -Bsymbolic-functions -Bsymbolic %t/a.o %t/b.o -o %t.so
20-
# RUN: cmp %t.so %t2.so
25+
# RUN: cmp %t.so %t3.so
2126
# RUN: ld.lld -shared -Bsymbolic -Bsymbolic-functions %t/a.o %t/b.o -o %t.so
22-
# RUN: cmp %t.so %t1.so
23-
# RUN: ld.lld -shared -Bno-symbolic -Bsymbolic %t/a.o %t/b.o -o %t.so
2427
# RUN: cmp %t.so %t2.so
28+
# RUN: ld.lld -shared -Bno-symbolic -Bsymbolic %t/a.o %t/b.o -o %t.so
29+
# RUN: cmp %t.so %t3.so
2530

2631
## -Bno-symbolic can cancel previously specified -Bsymbolic and -Bsymbolic-functions.
2732
# RUN: ld.lld -shared -Bsymbolic -Bno-symbolic %t/a.o %t/b.o -o %t.so
@@ -36,6 +41,7 @@
3641
# REL_DEF-NEXT: }
3742
# REL_DEF-NEXT: .rela.plt {
3843
# REL_DEF-NEXT: R_X86_64_JUMP_SLOT default
44+
# REL_DEF-NEXT: R_X86_64_JUMP_SLOT weak_default
3945
# REL_DEF-NEXT: R_X86_64_JUMP_SLOT ext_default
4046
# REL_DEF-NEXT: R_X86_64_JUMP_SLOT notype_default
4147
# REL_DEF-NEXT: R_X86_64_JUMP_SLOT undef
@@ -45,10 +51,31 @@
4551
# ASM_DEF-NEXT: callq {{.*}} <default@plt>
4652
# ASM_DEF-NEXT: callq {{.*}} <protected>
4753
# ASM_DEF-NEXT: callq {{.*}} <hidden>
54+
# ASM_DEF-NEXT: callq {{.*}} <weak_default@plt>
4855
# ASM_DEF-NEXT: callq {{.*}} <ext_default@plt>
4956
# ASM_DEF-NEXT: callq {{.*}} <notype_default@plt>
5057
# ASM_DEF-NEXT: callq {{.*}} <undef@plt>
5158

59+
# REL_GFUN: .rela.dyn {
60+
# REL_GFUN-NEXT: R_X86_64_RELATIVE -
61+
# REL_GFUN-NEXT: R_X86_64_RELATIVE -
62+
# REL_GFUN-NEXT: R_X86_64_64 data_default
63+
# REL_GFUN-NEXT: }
64+
# REL_GFUN-NEXT: .rela.plt {
65+
# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT weak_default
66+
# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT notype_default
67+
# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT undef
68+
# REL_GFUN-NEXT: }
69+
70+
# ASM_GFUN: <_start>:
71+
# ASM_GFUN-NEXT: callq {{.*}} <default>
72+
# ASM_GFUN-NEXT: callq {{.*}} <protected>
73+
# ASM_GFUN-NEXT: callq {{.*}} <hidden>
74+
# ASM_GFUN-NEXT: callq {{.*}} <weak_default@plt>
75+
# ASM_GFUN-NEXT: callq {{.*}} <ext_default>
76+
# ASM_GFUN-NEXT: callq {{.*}} <notype_default@plt>
77+
# ASM_GFUN-NEXT: callq {{.*}} <undef@plt>
78+
5279
# REL_FUN: .rela.dyn {
5380
# REL_FUN-NEXT: R_X86_64_RELATIVE -
5481
# REL_FUN-NEXT: R_X86_64_RELATIVE -
@@ -63,6 +90,7 @@
6390
# ASM_FUN-NEXT: callq {{.*}} <default>
6491
# ASM_FUN-NEXT: callq {{.*}} <protected>
6592
# ASM_FUN-NEXT: callq {{.*}} <hidden>
93+
# ASM_FUN-NEXT: callq {{.*}} <weak_default>
6694
# ASM_FUN-NEXT: callq {{.*}} <ext_default>
6795
# ASM_FUN-NEXT: callq {{.*}} <notype_default@plt>
6896
# ASM_FUN-NEXT: callq {{.*}} <undef@plt>
@@ -80,20 +108,24 @@
80108
# ASM_ALL-NEXT: callq {{.*}} <default>
81109
# ASM_ALL-NEXT: callq {{.*}} <protected>
82110
# ASM_ALL-NEXT: callq {{.*}} <hidden>
111+
# ASM_ALL-NEXT: callq {{.*}} <weak_default>
83112
# ASM_ALL-NEXT: callq {{.*}} <ext_default>
84113
# ASM_ALL-NEXT: callq {{.*}} <notype_default>
85114
# ASM_ALL-NEXT: callq {{.*}} <undef@plt>
86115

87116
#--- a.s
88117
.globl default, protected, hidden, notype_default
118+
.weak weak_default
89119
.protected protected
90120
.hidden hidden
91121
.type default, @function
92122
.type protected, @function
93123
.type hidden, @function
124+
.type weak_default, @function
94125
default: nop
95126
protected: nop
96127
hidden: nop
128+
weak_default: nop
97129
notype_default: nop
98130

99131
.globl _start
@@ -102,6 +134,8 @@ _start:
102134
callq protected@PLT
103135
callq hidden@PLT
104136

137+
callq weak_default@PLT
138+
105139
callq ext_default@PLT
106140

107141
callq notype_default@PLT

0 commit comments

Comments
 (0)