From 50bdf39ba57e29386de28bd0c303035e626fa29c Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 29 Feb 2024 12:46:21 +0900 Subject: [PATCH] Mark shared symbols as weak if all references are weak Previously, mold marked an imported symbol as a strong one if the symbol came from a DSO and was exported as a strong symbol by the DSO. This logic resulted in a miscomputation of the weakness bit, causing a compatibility issue with other linkers. Now, an imported symbol is marked as strong only when there's at least one strong reference to it. In other words, if all references to an imported symbol are weak, the symbol will be imported as a weak one. Fixes https://github.com/llvm/llvm-project/issues/83080 --- elf/input-files.cc | 2 +- elf/main.cc | 3 +++ elf/mold.h | 1 + elf/passes.cc | 22 ++++++++++++++++++++++ test/elf/weak-export-dso2.sh | 21 +++++++++++++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100755 test/elf/weak-export-dso2.sh 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'