diff --git a/elf/object-file.cc b/elf/object-file.cc index e12a0de0..072398c8 100644 --- a/elf/object-file.cc +++ b/elf/object-file.cc @@ -992,6 +992,22 @@ void ObjectFile::claim_unresolved_symbols(Context &ctx) { std::lock_guard lock(sym.mu); + if (sym.file && + (!sym.esym().is_undef() || sym.file->priority <= this->priority)) + continue; + + // If a symbol name is in the form of "foo@version", search for + // symbol "foo" and check if the symbol has version "version". + std::string_view key = symbol_strtab.data() + esym.st_name; + if (i64 pos = key.find('@'); pos != key.npos) { + Symbol *sym2 = intern(ctx, key.substr(0, pos)); + if (sym2->file && sym2->file->is_dso && + sym2->get_version() == key.substr(pos + 1)) { + this->symbols[i] = sym2; + continue; + } + } + auto claim = [&]() { sym.file = this; sym.input_section = nullptr; @@ -1002,23 +1018,11 @@ void ObjectFile::claim_unresolved_symbols(Context &ctx) { sym.is_exported = false; }; - if (!sym.file || - (sym.esym().is_undef() && this->priority < sym.file->priority)) { - std::string_view key = symbol_strtab.data() + esym.st_name; + if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN) + Warn(ctx) << "undefined symbol: " << *this << ": " << sym; - // If a symbol name is in the form of "foo@version", search for - // symbol "foo" and check if the symbol has version "version". - if (i64 pos = key.find('@'); pos != key.npos) { - Symbol *sym2 = intern(ctx, key.substr(0, pos)); - if (sym2->file && sym2->file->is_dso && - sym2->get_version() == key.substr(pos + 1)) { - this->symbols[i] = sym2; - continue; - } - } - - // Convert remaining undefined symbols to dynamic symbols. - // + // Convert remaining undefined symbols to dynamic symbols. + if (ctx.arg.shared) { // Traditionally, remaining undefined symbols cause a link failure // only when we are creating an executable. Undefined symbols in // shared objects are promoted to dynamic symbols, so that they'll @@ -1029,10 +1033,11 @@ void ObjectFile::claim_unresolved_symbols(Context &ctx) { // promoted to dynamic symbols for compatibility with other linkers. // Some major programs, notably Firefox, depend on the behavior // (they use this loophole to export symbols from libxul.so). - if (ctx.arg.shared && (!ctx.arg.z_defs || esym.is_undef_weak())) { + if (!ctx.arg.z_defs || esym.is_undef_weak() || + ctx.arg.unresolved_symbols != UnresolvedKind::ERROR) { claim(); sym.ver_idx = 0; - sym.is_imported = !ctx.arg.is_static; + sym.is_imported = true; if (sym.traced) SyncOut(ctx) << "trace-symbol: " << *this << ": unresolved" @@ -1040,17 +1045,14 @@ void ObjectFile::claim_unresolved_symbols(Context &ctx) { << " symbol " << sym; continue; } + } - // Convert remaining undefined symbols to absolute symbols with value 0. - if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR || - esym.is_undef_weak()) { - claim(); - sym.ver_idx = ctx.arg.default_version; - sym.is_imported = false; - - if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN) - Warn(ctx) << "undefined symbol: " << *this << ": " << sym; - } + // Convert remaining undefined symbols to absolute symbols with value 0. + if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR || + esym.is_undef_weak()) { + claim(); + sym.ver_idx = ctx.arg.default_version; + sym.is_imported = false; } } } diff --git a/test/elf/defs.sh b/test/elf/z-defs.sh similarity index 63% rename from test/elf/defs.sh rename to test/elf/z-defs.sh index 7e3cf788..db8b3251 100755 --- a/test/elf/defs.sh +++ b/test/elf/z-defs.sh @@ -15,10 +15,17 @@ EOF clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,nodefs -! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,defs 2> $t/log || false +! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,defs \ + 2> $t/log || false grep -q 'undefined symbol:.* foo' $t/log -! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-no-undefined 2> $t/log || false +! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-no-undefined \ + 2> $t/log || false grep -q 'undefined symbol:.* foo' $t/log +clang -fuse-ld=$mold -shared -o $t/c.so $t/a.o -Wl,-z,defs \ + -Wl,--warn-unresolved-symbols 2> $t/log +grep -q 'undefined symbol: .* foo$' $t/log +readelf --dyn-syms $t/c.so | grep -q ' foo$' + echo OK