diff --git a/main.cc b/main.cc index 1ab7659e..f49165fb 100644 --- a/main.cc +++ b/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 *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 *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. diff --git a/mold.h b/mold.h index 7176abde..51b578da 100644 --- a/mold.h +++ b/mold.h @@ -930,7 +930,6 @@ public: void convert_undefined_weak_symbols(Context &ctx); void resolve_comdat_groups(); void eliminate_duplicate_comdat_groups(); - void ignore_unresolved_symbols(Context &ctx); void claim_unresolved_symbols(Context &ctx); void scan_relocations(Context &ctx); void convert_common_symbols(Context &ctx); @@ -1331,7 +1330,7 @@ template void sort_init_fini(Context &); template std::vector *> collect_output_sections(Context &); template void compute_section_sizes(Context &); -template void convert_undefined_weak_symbols(Context &); +template void claim_unresolved_symbols(Context &); template void scan_rels(Context &); template void apply_version_script(Context &); template void parse_symbol_version(Context &); diff --git a/object_file.cc b/object_file.cc index 9c1cee95..cb652ae5 100644 --- a/object_file.cc +++ b/object_file.cc @@ -883,36 +883,6 @@ void ObjectFile::resolve_common_symbols(Context &ctx) { } } -template -void ObjectFile::convert_undefined_weak_symbols(Context &ctx) { - for (i64 i = first_global; i < this->symbols.size(); i++) { - const ElfSym &esym = elf_syms[i]; - if (!esym.is_undef() || !esym.is_weak()) - continue; - - Symbol &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 void ObjectFile::resolve_comdat_groups() { for (auto &pair : comdat_groups) { @@ -938,59 +908,55 @@ void ObjectFile::eliminate_duplicate_comdat_groups() { } } -template -void ObjectFile::ignore_unresolved_symbols(Context &ctx) { - if (!this->is_alive) - return; - - for (i64 i = first_global; i < this->symbols.size(); i++) { - const ElfSym &esym = elf_syms[i]; - Symbol &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 void ObjectFile::claim_unresolved_symbols(Context &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 &esym = elf_syms[i]; Symbol &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.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 = true; - sym.is_exported = false; + (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; + sym.sym_idx = i; + sym.ver_idx = ctx.arg.default_version; + sym.is_lazy = false; + sym.is_weak = false; + 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::convert_common_symbols(Context &ctx) { Symbol *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; } diff --git a/passes.cc b/passes.cc index a5cfde8a..d058b9a2 100644 --- a/passes.cc +++ b/passes.cc @@ -392,11 +392,10 @@ void compute_section_sizes(Context &ctx) { } template -void convert_undefined_weak_symbols(Context &ctx) { - Timer t(ctx, "undef_weak"); - +void claim_unresolved_symbols(Context &ctx) { + Timer t(ctx, "claim_unresolved_symbols"); tbb::parallel_for_each(ctx.objs, [&](ObjectFile *file) { - file->convert_undefined_weak_symbols(ctx); + file->claim_unresolved_symbols(ctx); }); } @@ -444,6 +443,20 @@ void scan_rels(Context &ctx) { // Assign offsets in additional tables for each dynamic symbol. for (Symbol *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 &ctx) { template std::vector *> \ collect_output_sections(Context &ctx); \ template void compute_section_sizes(Context &ctx); \ - template void convert_undefined_weak_symbols(Context &ctx); \ + template void claim_unresolved_symbols(Context &ctx); \ template void scan_rels(Context &ctx); \ template void apply_version_script(Context &ctx); \ template void parse_symbol_version(Context &ctx); \ diff --git a/test/weak-export.sh b/test/weak-export.sh index 4e6abe64..9f83c178 100755 --- a/test/weak-export.sh +++ b/test/weak-export.sh @@ -5,15 +5,32 @@ echo -n "Testing $(basename -s .sh $0) ... " t=$(pwd)/tmp/$(basename -s .sh $0) mkdir -p $t -cat < $t/a.c +#include + +__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 <