forked from OSchip/llvm-project
[ELF] Refine --export-dynamic-symbol semantics to be compatible GNU ld 2.35
GNU ld from binutils 2.35 onwards will likely support --export-dynamic-symbol but with different semantics. https://sourceware.org/pipermail/binutils/2020-May/111302.html Differences: 1. -export-dynamic-symbol is not supported 2. --export-dynamic-symbol takes a glob argument 3. --export-dynamic-symbol can suppress binding the references to the definition within the shared object if (-Bsymbolic or -Bsymbolic-functions) 4. --export-dynamic-symbol does not imply -u I don't think the first three points can affect any user. For the fourth point, Not implying -u can lead to some archive members unfetched. Add -u foo to restore the previous behavior. Exact semantics: * -no-pie or -pie: matched non-local defined symbols will be added to the dynamic symbol table. * -shared: matched non-local STV_DEFAULT symbols will not be bound to definitions within the shared object even if they would otherwise be due to -Bsymbolic, -Bsymbolic-functions, or --dynamic-list. Reviewed By: psmith Differential Revision: https://reviews.llvm.org/D80487
This commit is contained in:
parent
26ebe936f3
commit
751f18e7d4
|
@ -161,7 +161,6 @@ struct Configuration {
|
|||
bool gdbIndex;
|
||||
bool gnuHash = false;
|
||||
bool gnuUnique;
|
||||
bool hasDynamicList = false;
|
||||
bool hasDynSymTab;
|
||||
bool ignoreDataAddressEquality;
|
||||
bool ignoreFunctionAddressEquality;
|
||||
|
@ -192,6 +191,7 @@ struct Configuration {
|
|||
llvm::Optional<uint32_t> shuffleSectionSeed;
|
||||
bool singleRoRx;
|
||||
bool shared;
|
||||
bool symbolic;
|
||||
bool isStatic = false;
|
||||
bool sysvHash = false;
|
||||
bool target1Rel;
|
||||
|
|
|
@ -1172,25 +1172,21 @@ static void readConfigs(opt::InputArgList &args) {
|
|||
error(arg->getSpelling() + ": " + toString(pat.takeError()));
|
||||
}
|
||||
|
||||
// Parses -dynamic-list and -export-dynamic-symbol. They make some
|
||||
// symbols private. Note that -export-dynamic takes precedence over them
|
||||
// as it says all symbols should be exported.
|
||||
if (!config->exportDynamic) {
|
||||
for (auto *arg : args.filtered(OPT_dynamic_list))
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
|
||||
readDynamicList(*buffer);
|
||||
// When producing an executable, --dynamic-list specifies non-local defined
|
||||
// symbols whith are required to be exported. When producing a shared object,
|
||||
// symbols not specified by --dynamic-list are non-preemptible.
|
||||
config->symbolic =
|
||||
args.hasArg(OPT_Bsymbolic) || args.hasArg(OPT_dynamic_list);
|
||||
for (auto *arg : args.filtered(OPT_dynamic_list))
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
|
||||
readDynamicList(*buffer);
|
||||
|
||||
for (auto *arg : args.filtered(OPT_export_dynamic_symbol))
|
||||
config->dynamicList.push_back(
|
||||
{arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/false});
|
||||
}
|
||||
|
||||
// If --export-dynamic-symbol=foo is given and symbol foo is defined in
|
||||
// an object file in an archive file, that object file should be pulled
|
||||
// out and linked. (It doesn't have to behave like that from technical
|
||||
// point of view, but this is needed for compatibility with GNU.)
|
||||
// --export-dynamic-symbol specifies additional --dynamic-list symbols if any
|
||||
// other option expresses a symbolic intention: -no-pie, -pie, -Bsymbolic,
|
||||
// -Bsymbolic-functions (if STT_FUNC), --dynamic-list.
|
||||
for (auto *arg : args.filtered(OPT_export_dynamic_symbol))
|
||||
config->undefined.push_back(arg->getValue());
|
||||
config->dynamicList.push_back(
|
||||
{arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/true});
|
||||
|
||||
for (auto *arg : args.filtered(OPT_version_script))
|
||||
if (Optional<std::string> path = searchScript(arg->getValue())) {
|
||||
|
|
|
@ -145,7 +145,12 @@ def discard_none: F<"discard-none">,
|
|||
|
||||
defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
|
||||
|
||||
defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">;
|
||||
defm dynamic_list : Eq<"dynamic-list",
|
||||
"Read a list of dynamic symbols. (executable) Put matched non-local defined"
|
||||
"symbols to the dynamic symbol table. (shared object) References to matched"
|
||||
"non-local STV_DEFAULT symbols shouldn't be bound to definitions within the "
|
||||
"shared object. Implies -Bsymbolic but does not set DF_SYMBOLIC">,
|
||||
MetaVarName<"<file>">;
|
||||
|
||||
defm eh_frame_hdr: B<"eh-frame-hdr",
|
||||
"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
|
||||
|
@ -181,8 +186,12 @@ defm export_dynamic: B<"export-dynamic",
|
|||
"Put symbols in the dynamic symbol table",
|
||||
"Do not put symbols in the dynamic symbol table (default)">;
|
||||
|
||||
defm export_dynamic_symbol:
|
||||
Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
|
||||
defm export_dynamic_symbol : EEq<"export-dynamic-symbol",
|
||||
"(executable) Put matched symbols in the dynamic symbol table. "
|
||||
"(shared object) References to matched non-local STV_DEFAULT symbols "
|
||||
"shouldn't be bound to definitions within the shared object. "
|
||||
"Does not imply -Bsymbolic.">,
|
||||
MetaVarName<"glob">;
|
||||
|
||||
defm fatal_warnings: B<"fatal-warnings",
|
||||
"Treat warnings as errors",
|
||||
|
|
|
@ -175,7 +175,6 @@ static ExprValue bitOr(ExprValue a, ExprValue b) {
|
|||
}
|
||||
|
||||
void ScriptParser::readDynamicList() {
|
||||
config->hasDynamicList = true;
|
||||
expect("{");
|
||||
std::vector<SymbolVersion> locals;
|
||||
std::vector<SymbolVersion> globals;
|
||||
|
|
|
@ -365,13 +365,11 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
|
|||
if (!config->shared)
|
||||
return false;
|
||||
|
||||
// If the dynamic list is present, it specifies preemptable symbols in a DSO.
|
||||
if (config->hasDynamicList)
|
||||
// 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()))
|
||||
return sym.inDynamicList;
|
||||
|
||||
// -Bsymbolic means that definitions are not preempted.
|
||||
if (config->bsymbolic || (config->bsymbolicFunctions && sym.isFunc()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ Breaking changes
|
|||
|
||||
* One-dash form of some long option (``--thinlto-*``, ``--lto-*``, ``--shuffle-sections=``)
|
||||
are no longer supported.
|
||||
* ``--export-dynamic-symbol`` no longer implies ``-u``.
|
||||
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
|
|
@ -157,6 +157,10 @@ This is recorded in an ELF segment of type
|
|||
.It Fl -dynamic-list Ns = Ns Ar file
|
||||
Read a list of dynamic symbols from
|
||||
.Ar file .
|
||||
(executable) Put matched non-local defined symbols to the dynamic symbol table.
|
||||
(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object. Implies
|
||||
.Cm -Bsymbolic
|
||||
but does not set DF_SYMBOLIC
|
||||
.It Fl -eh-frame-hdr
|
||||
Request creation of
|
||||
.Li .eh_frame_hdr
|
||||
|
@ -184,10 +188,14 @@ This option is currently only supported on AArch64.
|
|||
Exclude static libraries from automatic export.
|
||||
.It Fl -export-dynamic , Fl E
|
||||
Put symbols in the dynamic symbol table.
|
||||
.It Fl -export-dynamic-symbol Ns = Ns Ar symbol
|
||||
Include
|
||||
.Ar symbol
|
||||
in the dynamic symbol table.
|
||||
.It Fl -export-dynamic-symbol Ns = Ns Ar glob
|
||||
(executable) Put matched non-local defined symbols to the dynamic symbol table.
|
||||
(shared object) References to matched non-local STV_DEFAULT symbols shouldn't be bound to definitions within the shared object even if they would otherwise be due to
|
||||
.Cm -Bsymbolic
|
||||
,
|
||||
.Cm -Bsymbolic-functions
|
||||
or
|
||||
.Cm --dynamic-list
|
||||
.It Fl -fatal-warnings
|
||||
Treat warnings as errors.
|
||||
.It Fl -filter Ns = Ns Ar value , Fl F Ar value
|
||||
|
|
|
@ -1,18 +1,54 @@
|
|||
# REQUIRES: x86
|
||||
|
||||
# RUN: rm -f %t.a
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t1.o
|
||||
# RUN: llvm-ar rcs %t.a %t1.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
|
||||
|
||||
# RUN: ld.lld -shared -o %t.so --export-dynamic-symbol foo %t.a %t2.o
|
||||
# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s
|
||||
## For an executable, --export-dynamic-symbol exports a symbol if it is non-local and defined.
|
||||
# RUN: ld.lld -pie --export-dynamic-symbol foo %t.o -o %t
|
||||
# RUN: llvm-nm -D -p %t | FileCheck %s
|
||||
|
||||
# RUN: ld.lld -shared -o %t.so --export-dynamic --export-dynamic-symbol foo %t.a %t2.o
|
||||
# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s
|
||||
## --export-dynamic exports all non-local defined symbols.
|
||||
## --export-dynamic-symbol is shadowed.
|
||||
# RUN: ld.lld -pie --export-dynamic --export-dynamic-symbol foo %t.o -o %t.start
|
||||
# RUN: llvm-nm -D -p %t.start | FileCheck --check-prefixes=CHECK,START %s
|
||||
|
||||
# CHECK: foo
|
||||
# CHECK-NOT: .
|
||||
# START: T _start
|
||||
# CHECK: T foo
|
||||
# CHECK-NOT: .
|
||||
|
||||
.global _start
|
||||
## --export-dynamic-symbol does not imply -u: %t1.a(%t1.o) is not fetched.
|
||||
## This is compatible with GNU ld since binutils 2.35 onwards.
|
||||
# RUN: echo '.globl foo, bar; foo: bar:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o
|
||||
# RUN: rm -f %t1.a && llvm-ar rc %t1.a %t1.o
|
||||
# RUN: ld.lld --export-dynamic-symbol bar %t1.a %t.o -o %t.nofetch
|
||||
# RUN: llvm-nm %t.nofetch | FileCheck /dev/null --implicit-check-not=bar
|
||||
|
||||
## --export-dynamic-symbol can make a symbol preemptible even if it would be otherwise
|
||||
## non-preemptible (due to -Bsymbolic, -Bsymbolic-functions or --dynamic-list).
|
||||
# RUN: ld.lld -shared -Bsymbolic --export-dynamic-symbol nomatch %t.o -o %t.nopreempt
|
||||
# RUN: llvm-objdump -d %t.nopreempt | FileCheck --check-prefix=NOPLT %s
|
||||
# RUN: ld.lld -shared -Bsymbolic --export-dynamic-symbol foo %t.o -o %t.preempt
|
||||
# RUN: llvm-objdump -d %t.preempt | FileCheck --check-prefix=PLT %s
|
||||
|
||||
## 'nomatch' does not match any symbol. Don't warn.
|
||||
# RUN: ld.lld --fatal-warnings -shared -Bsymbolic-functions --export-dynamic-symbol nomatch %t.o -o %t.nopreempt2
|
||||
# RUN: llvm-objdump -d %t.nopreempt2 | FileCheck --check-prefix=NOPLT %s
|
||||
# RUN: ld.lld -shared -Bsymbolic-functions --export-dynamic-symbol foo %t.o -o %t.preempt2
|
||||
# RUN: llvm-objdump -d %t.preempt2 | FileCheck --check-prefix=PLT %s
|
||||
|
||||
# RUN: echo '{};' > %t.list
|
||||
# RUN: ld.lld -shared --dynamic-list %t.list --export-dynamic-symbol foo %t.o -o %t.preempt3
|
||||
# RUN: llvm-objdump -d %t.preempt3 | FileCheck --check-prefix=PLT %s
|
||||
|
||||
## The option value is a glob.
|
||||
# RUN: ld.lld -shared -Bsymbolic --export-dynamic-symbol 'f*' %t.o -o %t.preempt4
|
||||
# RUN: llvm-objdump -d %t.preempt4 | FileCheck --check-prefix=PLT %s
|
||||
|
||||
# PLT: <foo@plt>
|
||||
# NOPLT-NOT: <foo@plt>
|
||||
|
||||
.global _start, foo
|
||||
.type foo, @function
|
||||
_start:
|
||||
nop
|
||||
call foo
|
||||
foo:
|
||||
|
|
|
@ -75,8 +75,8 @@
|
|||
## In GNU linkers, -u does not make a backward reference.
|
||||
# RUN: ld.lld --fatal-warnings --warn-backrefs -u foo %t2.a %t1.o -o /dev/null
|
||||
|
||||
## In GNU gold, --export-dynamic-symbol does not make a backward reference.
|
||||
# RUN: ld.lld --fatal-warnings --warn-backrefs --export-dynamic-symbol foo %t2.a %t1.o -o /dev/null
|
||||
## -u does not make a backward reference.
|
||||
# RUN: ld.lld --fatal-warnings --warn-backrefs -u foo %t2.a %t1.o -o /dev/null
|
||||
|
||||
# RUN: not ld.lld --warn-backrefs-exclude='[' 2>&1 | FileCheck --check-prefix=INVALID %s
|
||||
# INVALID: error: --warn-backrefs-exclude: invalid glob pattern: [
|
||||
|
|
Loading…
Reference in New Issue