mirror of
https://github.com/rui314/mold.git
synced 2024-11-13 09:39:13 +03:00
[ELF] Support extern "C++"
in dynamic lists
Fixes https://github.com/rui314/mold/issues/149
This commit is contained in:
parent
7b3c640472
commit
7aa5c393e4
@ -463,7 +463,8 @@ void parse_nonpositional_args(Context<E> &ctx,
|
||||
} else if (read_arg(ctx, args, arg, "sysroot")) {
|
||||
ctx.arg.sysroot = arg;
|
||||
} else if (read_arg(ctx, args, arg, "unique")) {
|
||||
ctx.arg.unique.reset(new std::regex(glob_to_regex(arg)));
|
||||
auto flags = std::regex_constants::extended | std::regex_constants::optimize;
|
||||
ctx.arg.unique.reset(new std::regex(glob_to_regex(arg), flags));
|
||||
} else if (read_arg(ctx, args, arg, "unresolved-symbols")) {
|
||||
if (arg == "report-all" || arg == "ignore-in-shared-libs")
|
||||
ctx.arg.unresolved_symbols = UnresolvedKind::ERROR;
|
||||
|
@ -266,7 +266,7 @@ static bool read_label(std::span<std::string_view> &tok,
|
||||
template <typename E>
|
||||
static void
|
||||
read_version_script_commands(Context<E> &ctx, std::span<std::string_view> &tok,
|
||||
VersionPattern &pat, bool is_extern_cpp) {
|
||||
VersionPattern &pat, bool is_cpp) {
|
||||
bool is_global = true;
|
||||
|
||||
while (!tok.empty() && tok[0] != "}") {
|
||||
@ -283,17 +283,16 @@ read_version_script_commands(Context<E> &ctx, std::span<std::string_view> &tok,
|
||||
if (tok[0] == "extern") {
|
||||
tok = tok.subspan(1);
|
||||
|
||||
bool is_cpp;
|
||||
if (!tok.empty() && tok[0] == "\"C\"") {
|
||||
tok = tok.subspan(1);
|
||||
is_cpp = false;
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_version_script_commands(ctx, tok, pat, false);
|
||||
} else {
|
||||
tok = skip(ctx, tok, "\"C++\"");
|
||||
is_cpp = true;
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_version_script_commands(ctx, tok, pat, true);
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_version_script_commands(ctx, tok, pat, is_cpp);
|
||||
tok = skip(ctx, tok, "}");
|
||||
tok = skip(ctx, tok, ";");
|
||||
continue;
|
||||
@ -301,10 +300,10 @@ read_version_script_commands(Context<E> &ctx, std::span<std::string_view> &tok,
|
||||
|
||||
if (tok[0] == "*")
|
||||
ctx.arg.default_version = (is_global ? pat.ver_idx : VER_NDX_LOCAL);
|
||||
else if (is_extern_cpp)
|
||||
pat.cpp_patterns.push_back(tok[0]);
|
||||
else if (is_cpp)
|
||||
pat.cpp_patterns.push_back(unquote(tok[0]));
|
||||
else
|
||||
pat.patterns.push_back(tok[0]);
|
||||
pat.patterns.push_back(unquote(tok[0]));
|
||||
|
||||
tok = tok.subspan(1);
|
||||
|
||||
@ -351,6 +350,41 @@ void parse_version_script(Context<E> &ctx, std::string path) {
|
||||
SyntaxError(ctx, tok[0]) << "trailing garbage token";
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void read_dynamic_list_commands(Context<E> &ctx,
|
||||
std::span<std::string_view> &tok,
|
||||
VersionPattern &pat,
|
||||
bool is_cpp) {
|
||||
while (!tok.empty() && tok[0] != "}") {
|
||||
if (tok[0] == "extern") {
|
||||
tok = tok.subspan(1);
|
||||
|
||||
if (!tok.empty() && tok[0] == "\"C\"") {
|
||||
tok = tok.subspan(1);
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_dynamic_list_commands(ctx, tok, pat, false);
|
||||
} else {
|
||||
tok = skip(ctx, tok, "\"C++\"");
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_dynamic_list_commands(ctx, tok, pat, true);
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok, "}");
|
||||
tok = skip(ctx, tok, ";");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok[0] == "*")
|
||||
ctx.arg.default_version = VER_NDX_GLOBAL;
|
||||
else if (is_cpp)
|
||||
pat.cpp_patterns.push_back(unquote(tok[0]));
|
||||
else
|
||||
pat.patterns.push_back(unquote(tok[0]));
|
||||
|
||||
tok = skip(ctx, tok.subspan(1), ";");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void parse_dynamic_list(Context<E> &ctx, std::string path) {
|
||||
current_file<E> = MappedFile<Context<E>>::must_open(ctx, path);
|
||||
@ -360,18 +394,10 @@ void parse_dynamic_list(Context<E> &ctx, std::string path) {
|
||||
std::span<std::string_view> tok = vec;
|
||||
tok = skip(ctx, tok, "{");
|
||||
|
||||
while (!tok.empty() && tok[0] != "}") {
|
||||
if (tok[0] == "*") {
|
||||
ctx.arg.default_version = VER_NDX_GLOBAL;
|
||||
} else {
|
||||
VersionPattern pat;
|
||||
pat.ver_idx = VER_NDX_GLOBAL;
|
||||
pat.patterns.push_back(tok[0]);
|
||||
ctx.arg.version_patterns.push_back(pat);
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok.subspan(1), ";");
|
||||
}
|
||||
VersionPattern pat;
|
||||
pat.ver_idx = VER_NDX_GLOBAL;
|
||||
read_dynamic_list_commands(ctx, tok, pat, false);
|
||||
ctx.arg.version_patterns.push_back(pat);
|
||||
|
||||
tok = skip(ctx, tok, "}");
|
||||
tok = skip(ctx, tok, ";");
|
||||
|
17
elf/main.cc
17
elf/main.cc
@ -18,11 +18,20 @@ namespace mold::elf {
|
||||
|
||||
std::string glob_to_regex(std::string_view pattern) {
|
||||
std::stringstream ss;
|
||||
for (u8 c : pattern) {
|
||||
if (c == '*')
|
||||
for (char c : pattern) {
|
||||
switch (c) {
|
||||
case '.': case '[': case ']': case '^':
|
||||
case '$': case '\\': case '(': case ')':
|
||||
case '+': case '?': case '|':
|
||||
ss << "\\" << c;
|
||||
break;
|
||||
case '*':
|
||||
ss << ".*";
|
||||
else
|
||||
ss << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (int)c;
|
||||
break;
|
||||
default:
|
||||
ss << c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -622,7 +622,8 @@ void apply_version_script(Context<E> &ctx) {
|
||||
if (vec.empty() && elem.cpp_patterns.empty())
|
||||
continue;
|
||||
|
||||
auto flags = std::regex_constants::optimize | std::regex_constants::nosubs;
|
||||
auto flags = std::regex_constants::extended | std::regex_constants::optimize |
|
||||
std::regex_constants::nosubs;
|
||||
std::regex re(to_regex(vec), flags);
|
||||
std::regex cpp_re(to_regex(elem.cpp_patterns), flags);
|
||||
|
||||
|
37
test/elf/dynamic-list2.sh
Executable file
37
test/elf/dynamic-list2.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
export LANG=
|
||||
set -e
|
||||
cd $(dirname $0)
|
||||
mold=`pwd`/../../mold
|
||||
echo -n "Testing $(basename -s .sh $0) ... "
|
||||
t=$(pwd)/../../out/test/elf/$(basename -s .sh $0)
|
||||
mkdir -p $t
|
||||
|
||||
cat <<EOF | cc -o $t/a.o -c -xc -
|
||||
void foo(int x) {}
|
||||
void bar(int x) {}
|
||||
EOF
|
||||
|
||||
cat <<EOF | c++ -o $t/b.o -c -xc++ -
|
||||
void baz(int x) {}
|
||||
int main() {}
|
||||
EOF
|
||||
|
||||
clang++ -fuse-ld=$mold -o $t/exe $t/a.o $t/b.o
|
||||
|
||||
readelf --dyn-syms $t/exe > $t/log
|
||||
! grep -q ' foo$' $t/log || false
|
||||
! grep -q ' bar$' $t/log || false
|
||||
|
||||
cat <<EOF > $t/dyn
|
||||
{ foo; extern "C++" { "baz(int)"; }; };
|
||||
EOF
|
||||
|
||||
clang -fuse-ld=$mold -o $t/exe $t/a.o $t/b.o -Wl,-dynamic-list=$t/dyn
|
||||
|
||||
readelf --dyn-syms $t/exe > $t/log
|
||||
grep -q ' foo$' $t/log
|
||||
! grep -q ' bar$' $t/log || false
|
||||
grep -q ' _Z3bazi$' $t/log
|
||||
|
||||
echo OK
|
Loading…
Reference in New Issue
Block a user