mirror of
https://github.com/rui314/mold.git
synced 2024-09-11 21:17:28 +03:00
[ELF] Fix precedence with C++ version script rules.
Earlier entries in a version scripts always get the precedence. Don't let a non-C++ symbol rule override a preceding C++ symbol rule. MultiGlob is modified to return the necessary rule index information to the caller. Since the rule index might not always be contiguous within a MultiGlob instance (e.g. interleaving ordinary/C++ rules), the meaning of MultiGlob's `val` is changed so that the minimum `val` itself is returned, instead of the `val` with minimum index (the earliest added one). MultiGlob is also used for the macOS backend, but since it does not care about order yet the code is left as-is. Signed-off-by: Tatsuyuki Ishi <ishitatsuyuki@gmail.com>
This commit is contained in:
parent
c9ff2a21c5
commit
9875150677
@ -1227,12 +1227,13 @@ void apply_version_script(Context<E> &ctx) {
|
||||
MultiGlob matcher;
|
||||
MultiGlob cpp_matcher;
|
||||
|
||||
for (VersionPattern &v : ctx.version_patterns) {
|
||||
for (i64 i = 0; i < ctx.version_patterns.size(); i++) {
|
||||
VersionPattern &v = ctx.version_patterns[i];
|
||||
if (v.is_cpp) {
|
||||
if (!cpp_matcher.add(v.pattern, v.ver_idx))
|
||||
if (!cpp_matcher.add(v.pattern, i))
|
||||
Fatal(ctx) << "invalid version pattern: " << v.pattern;
|
||||
} else {
|
||||
if (!matcher.add(v.pattern, v.ver_idx))
|
||||
if (!matcher.add(v.pattern, i))
|
||||
Fatal(ctx) << "invalid version pattern: " << v.pattern;
|
||||
}
|
||||
}
|
||||
@ -1244,17 +1245,26 @@ void apply_version_script(Context<E> &ctx) {
|
||||
|
||||
std::string_view name = sym->name();
|
||||
|
||||
if (std::optional<u16> ver = matcher.find(name)) {
|
||||
sym->ver_idx = *ver;
|
||||
continue;
|
||||
}
|
||||
std::optional<u32> best_match = std::nullopt;
|
||||
auto update_match = [&](u32 match) {
|
||||
if (!best_match || match < *best_match)
|
||||
best_match = match;
|
||||
};
|
||||
|
||||
if (std::optional<u32> rule_idx = matcher.find(name))
|
||||
update_match(*rule_idx);
|
||||
|
||||
// Match non-mangled symbols against the C++ pattern as well.
|
||||
// Weird, but required to match other linkers' behavior.
|
||||
if (!cpp_matcher.empty()) {
|
||||
if (std::optional<std::string_view> s = cpp_demangle(name))
|
||||
name = *s;
|
||||
if (std::optional<u16> ver = cpp_matcher.find(name))
|
||||
sym->ver_idx = *ver;
|
||||
if (std::optional<u32> rule_idx = cpp_matcher.find(name))
|
||||
update_match(*rule_idx);
|
||||
}
|
||||
|
||||
if (best_match)
|
||||
sym->ver_idx = ctx.version_patterns[*best_match].ver_idx;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
1
mold.h
1
mold.h
@ -567,7 +567,6 @@ private:
|
||||
std::vector<std::string> strings;
|
||||
std::unique_ptr<TrieNode> root;
|
||||
std::vector<std::pair<Glob, u32>> globs;
|
||||
std::vector<u32> values;
|
||||
std::once_flag once;
|
||||
bool is_compiled = false;
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ namespace mold {
|
||||
|
||||
std::optional<u32> MultiGlob::find(std::string_view str) {
|
||||
std::call_once(once, [&] { compile(); });
|
||||
u32 idx = UINT32_MAX;
|
||||
u32 val = UINT32_MAX;
|
||||
|
||||
if (root) {
|
||||
// Match against simple glob patterns
|
||||
@ -36,7 +36,7 @@ std::optional<u32> MultiGlob::find(std::string_view str) {
|
||||
for (;;) {
|
||||
if (node->children[c]) {
|
||||
node = node->children[c].get();
|
||||
idx = std::min(idx, node->value);
|
||||
val = std::min(val, node->value);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -55,11 +55,11 @@ std::optional<u32> MultiGlob::find(std::string_view str) {
|
||||
// Match against complex glob patterns
|
||||
for (std::pair<Glob, u32> &glob : globs)
|
||||
if (glob.first.match(str))
|
||||
idx = std::min(idx, glob.second);
|
||||
val = std::min(val, glob.second);
|
||||
|
||||
if (idx == UINT32_MAX)
|
||||
if (val == UINT32_MAX)
|
||||
return {};
|
||||
return values[idx];
|
||||
return val;
|
||||
}
|
||||
|
||||
static bool is_simple_pattern(std::string_view pat) {
|
||||
@ -86,14 +86,12 @@ bool MultiGlob::add(std::string_view pat, u32 val) {
|
||||
assert(!is_compiled);
|
||||
assert(!pat.empty());
|
||||
|
||||
u32 idx = strings.size();
|
||||
strings.push_back(std::string(pat));
|
||||
values.push_back(val);
|
||||
|
||||
// Complex glob pattern
|
||||
if (!is_simple_pattern(pat)) {
|
||||
if (std::optional<Glob> glob = Glob::compile(pat)) {
|
||||
globs.push_back({std::move(*glob), idx});
|
||||
globs.push_back({std::move(*glob), val});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -110,7 +108,7 @@ bool MultiGlob::add(std::string_view pat, u32 val) {
|
||||
node = node->children[c].get();
|
||||
}
|
||||
|
||||
node->value = std::min(node->value, idx);
|
||||
node->value = std::min(node->value, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
23
test/elf/version-script18.sh
Executable file
23
test/elf/version-script18.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
# Test version script precedence.
|
||||
|
||||
cat <<'EOF' > $t/a.ver
|
||||
{ global: extern "C++" { *libalpha::*; }; local: *libbeta*; };
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -fPIC -c -o $t/b.o -xc++ -
|
||||
namespace libbeta {
|
||||
struct Bar;
|
||||
}
|
||||
namespace libalpha {
|
||||
template <typename T>
|
||||
void foo() {}
|
||||
template void foo<libbeta::Bar>();
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -B. -shared -Wl,--version-script=$t/a.ver -o $t/c.so $t/b.o
|
||||
readelf --wide --dyn-syms $t/c.so | grep libalpha | grep -q Bar
|
||||
|
Loading…
Reference in New Issue
Block a user