Skip to content

Commit

Permalink
Mark shared symbols as weak if all references are weak
Browse files Browse the repository at this point in the history
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 llvm/llvm-project#83080
  • Loading branch information
rui314 committed Feb 29, 2024
1 parent 1e413d4 commit 50bdf39
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 1 deletion.
2 changes: 1 addition & 1 deletion elf/input-files.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ void SharedFile<E>::resolve_symbols(Context<E> &ctx) {
sym.value = esym.st_value;
sym.sym_idx = i;
sym.ver_idx = versyms[i];
sym.is_weak = false;
sym.is_weak = true;
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions elf/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,7 @@ template <typename E> void compute_section_sizes(Context<E> &);
template <typename E> void sort_output_sections(Context<E> &);
template <typename E> void claim_unresolved_symbols(Context<E> &);
template <typename E> void scan_relocations(Context<E> &);
template <typename E> void compute_imported_symbol_weakness(Context<E> &);
template <typename E> void construct_relr(Context<E> &);
template <typename E> void create_output_symtab(Context<E> &);
template <typename E> void report_undef_errors(Context<E> &);
Expand Down
22 changes: 22 additions & 0 deletions elf/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,27 @@ void scan_relocations(Context<E> &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 <typename E>
void compute_imported_symbol_weakness(Context<E> &ctx) {
Timer t(ctx, "compute_imported_symbol_weakness");

tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
for (i64 i = file->first_global; i < file->elf_syms.size(); i++) {
const ElfSym<E> &esym = file->elf_syms[i];
Symbol<E> &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 <typename E>
void report_undef_errors(Context<E> &ctx) {
Expand Down Expand Up @@ -2977,6 +2998,7 @@ template void shuffle_sections(Context<E> &);
template void compute_section_sizes(Context<E> &);
template void sort_output_sections(Context<E> &);
template void claim_unresolved_symbols(Context<E> &);
template void compute_imported_symbol_weakness(Context<E> &);
template void scan_relocations(Context<E> &);
template void report_undef_errors(Context<E> &);
template void create_reloc_sections(Context<E> &);
Expand Down
21 changes: 21 additions & 0 deletions test/elf/weak-export-dso2.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
. $(dirname $0)/common.inc

cat <<EOF | $CC -fPIC -c -o $t/a.o -xc -
int foo() { return 0; }
EOF

$CC -B. -o $t/b.so $t/a.o -shared

cat <<EOF | $CC -fPIC -c -o $t/c.o -xc -
#include <stdio.h>
__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'

0 comments on commit 50bdf39

Please sign in to comment.