mirror of
https://github.com/rui314/mold.git
synced 2024-12-26 01:44:29 +03:00
Promote weak undefined symbols to weak dynamic symbols
Previously, if a weak undefined symbol cannot be resolved within an output of the linker, mold turned it into an absolute symbol with value 0. However, other linkers export such symbols as a weak dynamic symbol, so that the symbol gets another chance to be resolved at runtime. This patch implements the behavior. This is needed by Gentoo's dev-libs/nsync-1.20.1 package.
This commit is contained in:
parent
a8ebb63b00
commit
d9ecc2e3e6
21
main.cc
21
main.cc
@ -447,26 +447,13 @@ int do_main(int argc, char **argv) {
|
||||
// Beyond this point, no new files will be added to ctx.objs
|
||||
// or ctx.dsos.
|
||||
|
||||
// Convert weak symbols to absolute symbols with value 0.
|
||||
convert_undefined_weak_symbols(ctx);
|
||||
|
||||
// If we do not handle undefined symbols as errors, such symbols
|
||||
// are converted to absolute symbols with value 0.
|
||||
if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
file->ignore_unresolved_symbols(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
// If we are linking a .so file, remaining undefined symbols does
|
||||
// not cause a linker error. Instead, they are treated as if they
|
||||
// were imported symbols.
|
||||
if (ctx.arg.shared && !ctx.arg.z_defs) {
|
||||
Timer t(ctx, "claim_unresolved_symbols");
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
file->claim_unresolved_symbols(ctx);
|
||||
});
|
||||
}
|
||||
//
|
||||
// If we are linking an executable, weak undefs are converted to
|
||||
// weakly imported symbol so that they'll have another chance to be
|
||||
claim_unresolved_symbols(ctx);
|
||||
|
||||
// Beyond this point, no new symbols will be added to the result.
|
||||
|
||||
|
3
mold.h
3
mold.h
@ -930,7 +930,6 @@ public:
|
||||
void convert_undefined_weak_symbols(Context<E> &ctx);
|
||||
void resolve_comdat_groups();
|
||||
void eliminate_duplicate_comdat_groups();
|
||||
void ignore_unresolved_symbols(Context<E> &ctx);
|
||||
void claim_unresolved_symbols(Context<E> &ctx);
|
||||
void scan_relocations(Context<E> &ctx);
|
||||
void convert_common_symbols(Context<E> &ctx);
|
||||
@ -1331,7 +1330,7 @@ template <typename E> void sort_init_fini(Context<E> &);
|
||||
template <typename E> std::vector<OutputChunk<E> *>
|
||||
collect_output_sections(Context<E> &);
|
||||
template <typename E> void compute_section_sizes(Context<E> &);
|
||||
template <typename E> void convert_undefined_weak_symbols(Context<E> &);
|
||||
template <typename E> void claim_unresolved_symbols(Context<E> &);
|
||||
template <typename E> void scan_rels(Context<E> &);
|
||||
template <typename E> void apply_version_script(Context<E> &);
|
||||
template <typename E> void parse_symbol_version(Context<E> &);
|
||||
|
@ -883,36 +883,6 @@ void ObjectFile<E>::resolve_common_symbols(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjectFile<E>::convert_undefined_weak_symbols(Context<E> &ctx) {
|
||||
for (i64 i = first_global; i < this->symbols.size(); i++) {
|
||||
const ElfSym<E> &esym = elf_syms[i];
|
||||
if (!esym.is_undef() || !esym.is_weak())
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *this->symbols[i];
|
||||
std::lock_guard lock(sym.mu);
|
||||
|
||||
if (!sym.file ||
|
||||
(sym.esym().is_undef_weak() && this->priority < sym.file->priority)) {
|
||||
sym.file = this;
|
||||
sym.input_section = nullptr;
|
||||
sym.value = 0;
|
||||
sym.sym_idx = i;
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.is_lazy = false;
|
||||
sym.is_weak = true;
|
||||
|
||||
if (ctx.arg.shared)
|
||||
sym.is_imported = true;
|
||||
|
||||
if (sym.traced)
|
||||
SyncOut(ctx) << "trace-symbol: " << *this
|
||||
<< ": unresolved weak symbol " << sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjectFile<E>::resolve_comdat_groups() {
|
||||
for (auto &pair : comdat_groups) {
|
||||
@ -938,50 +908,25 @@ void ObjectFile<E>::eliminate_duplicate_comdat_groups() {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjectFile<E>::ignore_unresolved_symbols(Context<E> &ctx) {
|
||||
if (!this->is_alive)
|
||||
return;
|
||||
|
||||
for (i64 i = first_global; i < this->symbols.size(); i++) {
|
||||
const ElfSym<E> &esym = elf_syms[i];
|
||||
Symbol<E> &sym = *this->symbols[i];
|
||||
if (esym.is_defined())
|
||||
continue;
|
||||
|
||||
std::lock_guard lock(sym.mu);
|
||||
if (!sym.file ||
|
||||
(sym.esym().is_undef_strong() && sym.file->priority < this->priority)) {
|
||||
if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN)
|
||||
Warn(ctx) << "undefined symbol: " << *this << ": " << sym;
|
||||
|
||||
sym.file = this;
|
||||
sym.input_section = nullptr;
|
||||
sym.value = esym.st_value;
|
||||
sym.sym_idx = i;
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.is_lazy = false;
|
||||
sym.is_weak = false;
|
||||
sym.is_imported = false;
|
||||
sym.is_exported = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
|
||||
if (!this->is_alive)
|
||||
return;
|
||||
|
||||
bool claim_all = ctx.arg.shared && !ctx.arg.z_defs;
|
||||
|
||||
for (i64 i = first_global; i < this->symbols.size(); i++) {
|
||||
const ElfSym<E> &esym = elf_syms[i];
|
||||
Symbol<E> &sym = *this->symbols[i];
|
||||
if (esym.is_defined())
|
||||
if (!esym.is_undef())
|
||||
continue;
|
||||
|
||||
std::lock_guard lock(sym.mu);
|
||||
|
||||
if (!sym.file ||
|
||||
(sym.esym().is_undef_strong() && sym.file->priority < this->priority)) {
|
||||
(sym.esym().is_undef() && sym.file->priority < this->priority)) {
|
||||
if (claim_all || esym.is_weak()) {
|
||||
// Convert remaining undefined symbols to dynamic symbols.
|
||||
sym.file = this;
|
||||
sym.input_section = nullptr;
|
||||
sym.value = 0;
|
||||
@ -989,8 +934,29 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.is_lazy = false;
|
||||
sym.is_weak = false;
|
||||
sym.is_imported = true;
|
||||
sym.is_imported = !ctx.arg.is_static;
|
||||
sym.is_exported = false;
|
||||
|
||||
if (sym.traced)
|
||||
SyncOut(ctx) << "trace-symbol: " << *this << ": unresolved"
|
||||
<< (esym.is_weak() ? " weak" : "")
|
||||
<< " symbol " << sym;
|
||||
} else if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR) {
|
||||
// Convert remaining undefined symbols to absolute symbols with
|
||||
// value 0.
|
||||
sym.file = this;
|
||||
sym.input_section = nullptr;
|
||||
sym.value = 0;
|
||||
sym.sym_idx = i;
|
||||
sym.ver_idx = ctx.arg.default_version;
|
||||
sym.is_lazy = false;
|
||||
sym.is_weak = false;
|
||||
sym.is_imported = false;
|
||||
sym.is_exported = false;
|
||||
|
||||
if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN)
|
||||
Warn(ctx) << "undefined symbol: " << *this << ": " << sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1034,7 +1000,7 @@ void ObjectFile<E>::convert_common_symbols(Context<E> &ctx) {
|
||||
Symbol<E> *sym = this->symbols[i];
|
||||
if (sym->file != this) {
|
||||
if (ctx.arg.warn_common)
|
||||
Warn(ctx) << *this << ": " << "multiple common symbols: " << *sym;
|
||||
Warn(ctx) << *this << ": multiple common symbols: " << *sym;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
23
passes.cc
23
passes.cc
@ -392,11 +392,10 @@ void compute_section_sizes(Context<E> &ctx) {
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void convert_undefined_weak_symbols(Context<E> &ctx) {
|
||||
Timer t(ctx, "undef_weak");
|
||||
|
||||
void claim_unresolved_symbols(Context<E> &ctx) {
|
||||
Timer t(ctx, "claim_unresolved_symbols");
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
file->convert_undefined_weak_symbols(ctx);
|
||||
file->claim_unresolved_symbols(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
@ -444,6 +443,20 @@ void scan_rels(Context<E> &ctx) {
|
||||
|
||||
// Assign offsets in additional tables for each dynamic symbol.
|
||||
for (Symbol<E> *sym : syms) {
|
||||
if ((sym->flags & NEEDS_COPYREL) && !sym->file->is_dso) {
|
||||
// Weak undefined symbols can be converted to imported symbols, but
|
||||
// we can't create copy relocations against them because we don't
|
||||
// know their symbol sizes. Therefore, if we have to create copyrels
|
||||
// against such symbols, we instead turns the symbols into
|
||||
// non-imported absoute ones with value 0. That means weak symbols
|
||||
// are exported only when compiled with -fPIC, and the same program
|
||||
// can have different meanings depending on the presence or absense
|
||||
// that flag. That's bad, but this is the best we can do.
|
||||
sym->is_imported = false;
|
||||
sym->flags = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sym->flags & NEEDS_DYNSYM)
|
||||
ctx.dynsym->add_symbol(ctx, sym);
|
||||
|
||||
@ -873,7 +886,7 @@ void compress_debug_sections(Context<E> &ctx) {
|
||||
template std::vector<OutputChunk<E> *> \
|
||||
collect_output_sections(Context<E> &ctx); \
|
||||
template void compute_section_sizes(Context<E> &ctx); \
|
||||
template void convert_undefined_weak_symbols(Context<E> &ctx); \
|
||||
template void claim_unresolved_symbols(Context<E> &ctx); \
|
||||
template void scan_rels(Context<E> &ctx); \
|
||||
template void apply_version_script(Context<E> &ctx); \
|
||||
template void parse_symbol_version(Context<E> &ctx); \
|
||||
|
@ -5,15 +5,32 @@ echo -n "Testing $(basename -s .sh $0) ... "
|
||||
t=$(pwd)/tmp/$(basename -s .sh $0)
|
||||
mkdir -p $t
|
||||
|
||||
cat <<EOF | cc -o $t/a.o -c -x assembler -
|
||||
.weak weak_fn
|
||||
.global _start
|
||||
_start:
|
||||
nop
|
||||
cat <<EOF > $t/a.c
|
||||
#include <stdio.h>
|
||||
|
||||
__attribute__((weak)) int foo();
|
||||
__attribute__((weak)) extern int bar;
|
||||
|
||||
int main() {
|
||||
printf("%d %d\n", foo ? foo() : 3, &bar ? bar : 5);
|
||||
}
|
||||
EOF
|
||||
|
||||
cc -fno-PIC -c -o $t/c.o $t/a.c
|
||||
clang -fuse-ld=`pwd`/../mold -o $t/exe $t/c.o
|
||||
! readelf --dyn-syms $t/exe | grep -q 'NOTYPE WEAK DEFAULT UND foo' || false
|
||||
$t/exe | grep -q '3 5'
|
||||
|
||||
../mold -o $t/exe $t/a.o
|
||||
readelf -a $t/exe > /dev/null
|
||||
cc -fPIC -c -o $t/b.o $t/a.c
|
||||
clang -fuse-ld=`pwd`/../mold -o $t/exe $t/b.o
|
||||
readelf --dyn-syms $t/exe | grep -q 'NOTYPE WEAK DEFAULT UND foo'
|
||||
$t/exe | grep -q '3 5'
|
||||
|
||||
cat <<EOF | cc -shared -o $t/d.so -xc -
|
||||
int foo() { return 42; }
|
||||
int bar = 7;
|
||||
EOF
|
||||
|
||||
LD_PRELOAD=$t/d.so $t/exe | grep -q '42 7'
|
||||
|
||||
echo OK
|
||||
|
Loading…
Reference in New Issue
Block a user