diff --git a/elf/cmdline.cc b/elf/cmdline.cc index e5f2a4ceed..bc0182dd52 100644 --- a/elf/cmdline.cc +++ b/elf/cmdline.cc @@ -522,7 +522,9 @@ std::vector parse_nonpositional_args(Context &ctx) { bool version_shown = false; bool warn_shared_textrel = false; + bool error_unresolved_symbols = true; std::optional z_separate_code; + std::optional report_undefined; std::optional z_relro; std::optional shuffle_sections_seed; std::unordered_set rpaths; @@ -781,9 +783,9 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.unique = std::move(*pat); } else if (read_arg("unresolved-symbols")) { if (arg == "report-all" || arg == "ignore-in-shared-libs") - ctx.arg.unresolved_symbols = UNRESOLVED_ERROR; + report_undefined = true; else if (arg == "ignore-all" || arg == "ignore-in-object-files") - ctx.arg.unresolved_symbols = UNRESOLVED_IGNORE; + report_undefined = false; else Fatal(ctx) << "unknown --unresolved-symbols argument: " << arg; } else if (read_arg("undefined") || read_arg("u")) { @@ -963,10 +965,10 @@ std::vector parse_nonpositional_args(Context &ctx) { z_relro = true; } else if (read_z_flag("norelro")) { z_relro = false; - } else if (read_z_flag("defs")) { - ctx.arg.z_defs = true; + } else if (read_z_flag("defs") || read_flag("no-undefined")) { + report_undefined = true; } else if (read_z_flag("undefs")) { - ctx.arg.z_defs = false; + report_undefined = false; } else if (read_z_flag("nodlopen")) { ctx.arg.z_dlopen = false; } else if (read_z_flag("nodelete")) { @@ -1018,8 +1020,6 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.z_rewrite_endbr = true; } else if (read_z_flag("rodynamic")) { ctx.arg.z_rodynamic = true; - } else if (read_flag("no-undefined")) { - ctx.arg.z_defs = true; } else if (read_flag("nmagic")) { ctx.arg.nmagic = true; } else if (read_flag("no-nmagic")) { @@ -1149,9 +1149,9 @@ std::vector parse_nonpositional_args(Context &ctx) { } else if (read_flag("strip-debug") || read_flag("S")) { ctx.arg.strip_debug = true; } else if (read_flag("warn-unresolved-symbols")) { - ctx.arg.unresolved_symbols = UNRESOLVED_WARN; + error_unresolved_symbols = false; } else if (read_flag("error-unresolved-symbols")) { - ctx.arg.unresolved_symbols = UNRESOLVED_ERROR; + error_unresolved_symbols = true; } else if (read_arg("rpath")) { add_rpath(arg); } else if (read_arg("R")) { @@ -1310,6 +1310,18 @@ std::vector parse_nonpositional_args(Context &ctx) { if (ctx.arg.pic) ctx.arg.image_base = 0; + if (!report_undefined) + report_undefined = !ctx.arg.shared; + + if (*report_undefined) { + if (error_unresolved_symbols) + ctx.arg.unresolved_symbols = UNRESOLVED_ERROR; + else + ctx.arg.unresolved_symbols = UNRESOLVED_WARN; + } else { + ctx.arg.unresolved_symbols = UNRESOLVED_IGNORE; + } + if (ctx.arg.retain_symbols_file) { ctx.arg.strip_all = false; ctx.arg.discard_all = false; diff --git a/elf/input-sections.cc b/elf/input-sections.cc index 72703f2f47..8383a7fd44 100644 --- a/elf/input-sections.cc +++ b/elf/input-sections.cc @@ -523,16 +523,22 @@ bool InputSection::record_undef_error(Context &ctx, const ElfRel &rel) acc->second.push_back(ss.str()); }; - // A non-weak undefined symbol must be promoted to an imported - // symbol or resolved to an defined symbol. Otherwise, it's an - // undefined symbol error. + // A non-weak undefined symbol must be promoted to an imported symbol + // or resolved to an defined symbol. Otherwise, we need to report an + // error or warn on it. // // Every ELF file has an absolute local symbol as its first symbol. // Referring to that symbol is always valid. bool is_undef = esym.is_undef() && !esym.is_weak() && sym.sym_idx; - if (!sym.is_imported && is_undef && sym.esym().is_undef()) { - record(); - return true; + if (is_undef && sym.esym().is_undef()) { + if (ctx.arg.unresolved_symbols == UNRESOLVED_ERROR && !sym.is_imported) { + record(); + return true; + } + if (ctx.arg.unresolved_symbols == UNRESOLVED_WARN) { + record(); + return false; + } } // If a protected/hidden undefined symbol is resolved to other .so, diff --git a/elf/mold.h b/elf/mold.h index 3f826ac264..79946c6035 100644 --- a/elf/mold.h +++ b/elf/mold.h @@ -1690,7 +1690,7 @@ struct Context { Symbol *entry = nullptr; Symbol *fini = nullptr; Symbol *init = nullptr; - UnresolvedKind unresolved_symbols = UNRESOLVED_ERROR; + UnresolvedKind unresolved_symbols = UNRESOLVED_IGNORE; BsymbolicKind Bsymbolic = BSYMBOLIC_NONE; bool allow_multiple_definition = false; bool apply_dynamic_relocs = true; @@ -1745,7 +1745,6 @@ struct Context { bool warn_once = false; bool warn_textrel = false; bool z_copyreloc = true; - bool z_defs = false; bool z_delete = true; bool z_dlopen = true; bool z_dump = true; diff --git a/elf/passes.cc b/elf/passes.cc index a35904c79f..49fa569fd5 100644 --- a/elf/passes.cc +++ b/elf/passes.cc @@ -1432,9 +1432,11 @@ void compute_section_sizes(Context &ctx) { } // Find all unresolved symbols and attach them to the most appropriate files. -// Note that even a symbol that will be reported as an undefined symbol will -// get an owner file in this function. Such symbol will be reported by -// ObjectFile::scan_relocations(). +// +// Note that even a symbol that will be reported as an undefined symbol +// will get an owner file in this function. Such symbol will be reported +// by ObjectFile::scan_relocations(). This is because we want to report +// errors only on symbols that are actually referenced. template void claim_unresolved_symbols(Context &ctx) { Timer t(ctx, "claim_unresolved_symbols"); @@ -1512,7 +1514,8 @@ void 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 && sym.visibility != STV_HIDDEN && !ctx.arg.z_defs) { + if (ctx.arg.shared && sym.visibility != STV_HIDDEN && + ctx.arg.unresolved_symbols != UNRESOLVED_ERROR) { claim(true); continue; } diff --git a/test/elf/copyrel-norelro.sh b/test/elf/copyrel-norelro.sh old mode 100644 new mode 100755 diff --git a/test/elf/linker-script6.sh b/test/elf/linker-script6.sh old mode 100644 new mode 100755 diff --git a/test/elf/riscv64_global-pointer-dso.sh b/test/elf/riscv64_global-pointer-dso.sh old mode 100644 new mode 100755 diff --git a/test/elf/unresolved-symbols2.sh b/test/elf/unresolved-symbols2.sh new file mode 100755 index 0000000000..566f50653e --- /dev/null +++ b/test/elf/unresolved-symbols2.sh @@ -0,0 +1,10 @@ +#!/bin/bash +. $(dirname $0)/common.inc + +cat <