From 0612ea41f1a4dad4439e898b1d2a675bfd1e85a2 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sun, 15 Sep 2024 15:09:35 +0900 Subject: [PATCH] Lower the priority of DSO symbols than in-archive symbols Assume both `foo.a` and `bar.so` define the same symbol `baz`. If `baz`'s symbol visibility is hidden, it needs to be resolved within the output file, i.e., from `foo.a`. However, previously, such symbol was resolved to the one in `bar.so`. To fix the problem, we'll lower the symbol priority for DSOs. Fixes https://github.com/rui314/mold/issues/1342 --- src/input-files.cc | 15 ++++++++++----- test/gnu-property.sh | 0 test/hidden-archive.sh | 21 +++++++++++++++++++++ test/link-order.sh | 2 +- 4 files changed, 32 insertions(+), 6 deletions(-) mode change 100644 => 100755 test/gnu-property.sh create mode 100755 test/hidden-archive.sh diff --git a/src/input-files.cc b/src/input-files.cc index c61ed5a85e..a00dcdd12a 100644 --- a/src/input-files.cc +++ b/src/input-files.cc @@ -857,22 +857,27 @@ void ObjectFile::parse(Context &ctx) { // // 1. Strong defined symbol // 2. Weak defined symbol -// 3. Strong defined symbol in a DSO/archive -// 4. Weak Defined symbol in a DSO/archive +// 3. Strong defined symbol in an archive +// 4. Weak Defined symbol in an archive // 5. Common symbol // 6. Common symbol in an archive -// 7. Unclaimed (nonexistent) symbol +// 7. Strong defined symbol in a DSO +// 8. Weak Defined symbol in a DSO +// 9. Unclaimed (nonexistent) symbol // // Ties are broken by file priority. template static u64 get_rank(InputFile *file, const ElfSym &esym, bool is_in_archive) { auto get_sym_rank = [&] { + if (file->is_dso) + return (esym.st_bind == STB_WEAK) ? 8 : 7; + if (esym.is_common()) { assert(!file->is_dso); return is_in_archive ? 6 : 5; } - if (file->is_dso || is_in_archive) + if (is_in_archive) return (esym.st_bind == STB_WEAK) ? 4 : 3; if (esym.st_bind == STB_WEAK) @@ -886,7 +891,7 @@ static u64 get_rank(InputFile *file, const ElfSym &esym, bool is_in_archiv template static u64 get_rank(const Symbol &sym) { if (!sym.file) - return 7 << 24; + return 9 << 24; return get_rank(sym.file, sym.esym(), !sym.file->is_alive); } diff --git a/test/gnu-property.sh b/test/gnu-property.sh old mode 100644 new mode 100755 diff --git a/test/hidden-archive.sh b/test/hidden-archive.sh new file mode 100755 index 0000000000..9364e19898 --- /dev/null +++ b/test/hidden-archive.sh @@ -0,0 +1,21 @@ +#!/bin/bash +. $(dirname $0)/common.inc + +cat <