diff --git a/elf/input-files.cc b/elf/input-files.cc index 0226931e9b..276b233da7 100644 --- a/elf/input-files.cc +++ b/elf/input-files.cc @@ -1434,7 +1434,7 @@ void SharedFile::resolve_symbols(Context &ctx) { sym.value = esym.st_value; sym.sym_idx = i; sym.ver_idx = versyms[i]; - sym.is_weak = false; + sym.is_weak = true; } } } diff --git a/elf/main.cc b/elf/main.cc index ce8d369b4a..e3d07833e5 100644 --- a/elf/main.cc +++ b/elf/main.cc @@ -546,6 +546,9 @@ int elf_main(int argc, char **argv) { // .got.plt, .dynsym, .dynstr, etc. scan_relocations(ctx); + // Compute the is_weak bit for each imported symbol. + compute_imported_symbol_weakness(ctx); + // Compute sizes of output sections while assigning offsets // within an output section to input sections. compute_section_sizes(ctx); diff --git a/elf/mold.h b/elf/mold.h index fc7266f5ee..93cd55c983 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1392,6 +1392,7 @@ template void compute_section_sizes(Context &); template void sort_output_sections(Context &); template void claim_unresolved_symbols(Context &); template void scan_relocations(Context &); +template void compute_imported_symbol_weakness(Context &); template void construct_relr(Context &); template void create_output_symtab(Context &); template void report_undef_errors(Context &); diff --git a/elf/passes.cc b/elf/passes.cc index 04d4205352..3fa8136d98 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -1513,6 +1513,27 @@ void scan_relocations(Context &ctx) { Warn(ctx) << "creating a DT_TEXTREL in an output file"; } +// Compute the is_weak bit for each imported symbol. +// +// If all references to a shared symbol is weak, the symbol is marked +// as weak in .dynsym. +template +void compute_imported_symbol_weakness(Context &ctx) { + Timer t(ctx, "compute_imported_symbol_weakness"); + + tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) { + for (i64 i = file->first_global; i < file->elf_syms.size(); i++) { + const ElfSym &esym = file->elf_syms[i]; + Symbol &sym = *file->symbols[i]; + + if (esym.is_undef() && !esym.is_weak() && sym.file && sym.file->is_dso) { + std::scoped_lock lock(sym.mu); + sym.is_weak = false; + } + } + }); +} + // Report all undefined symbols, grouped by symbol. template void report_undef_errors(Context &ctx) { @@ -2977,6 +2998,7 @@ template void shuffle_sections(Context &); template void compute_section_sizes(Context &); template void sort_output_sections(Context &); template void claim_unresolved_symbols(Context &); +template void compute_imported_symbol_weakness(Context &); template void scan_relocations(Context &); template void report_undef_errors(Context &); template void create_reloc_sections(Context &); diff --git a/test/elf/weak-export-dso2.sh b/test/elf/weak-export-dso2.sh new file mode 100755 index 0000000000..3c24b68bdd --- /dev/null +++ b/test/elf/weak-export-dso2.sh @@ -0,0 +1,21 @@ +#!/bin/bash +. $(dirname $0)/common.inc + +cat < + +__attribute__((weak)) int foo(); + +int main() { + printf("%d\n", foo ? foo() : 3); +} +EOF + +$CC -B. -o $t/d.so $t/c.o $t/b.so -shared +readelf -W --dyn-syms $t/d.so | grep -q 'WEAK DEFAULT UND foo'