mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 15:41:46 +00:00
[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 b06426da76
)
This commit is contained in:
parent
6b2e4c5a58
commit
ad5a6b15ff
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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">;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
----------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user