Skip to content

Commit b1da8fd

Browse files
committed
Auto merge of #155535 - cezarbbb:cstyle-export-symbols, r=<try>
export symbols: support macos/windows(32/64) try-job: aarch64-*
2 parents d12e1e1 + bf58b58 commit b1da8fd

2 files changed

Lines changed: 84 additions & 16 deletions

File tree

  • compiler/rustc_codegen_ssa/src/back
  • tests/run-make/cdylib-export-c-library-symbols

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc_session::{Session, filesearch};
4747
use rustc_span::Symbol;
4848
use rustc_target::spec::crt_objects::CrtObjects;
4949
use rustc_target::spec::{
50-
BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents,
50+
Arch, BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents,
5151
LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel,
5252
RelroLevel, SanitizerSet, SplitDebuginfo,
5353
};
@@ -2290,6 +2290,57 @@ fn add_rpath_args(
22902290
}
22912291
}
22922292

2293+
fn undecorate_c_symbol(name: &str, sess: &Session, kind: SymbolExportKind) -> String {
2294+
if sess.target.is_like_darwin {
2295+
// Mach-O: strip the leading underscore that all C symbols have.
2296+
// The Darwin linker's export_symbols will add it back.
2297+
name.strip_prefix('_').map(|s| s.to_string()).unwrap_or(name.to_string())
2298+
} else if sess.target.is_like_windows {
2299+
match sess.target.arch {
2300+
Arch::X86 => {
2301+
// COFF 32-bit: strip calling-convention decorations.
2302+
if let Some(rest) = name.strip_prefix('@') {
2303+
// fastcall: @foo@N -> foo
2304+
rest.split_once('@')
2305+
.map(|(base, _)| base.to_string())
2306+
.unwrap_or(name.to_string())
2307+
} else if let Some(stripped) = name.strip_prefix('_') {
2308+
if let Some((base, suffix)) = stripped.split_once('@') {
2309+
// stdcall: _foo@N -> foo
2310+
if suffix.parse::<u32>().is_ok() {
2311+
base.to_string()
2312+
} else {
2313+
stripped.to_string()
2314+
}
2315+
} else {
2316+
// cdecl: _foo -> foo
2317+
stripped.to_string()
2318+
}
2319+
} else {
2320+
// vectorcall: foo@@N -> foo
2321+
name.split_once("@@")
2322+
.map(|(base, suffix)| {
2323+
if suffix.parse::<u32>().is_ok() {
2324+
base.to_string()
2325+
} else {
2326+
name.to_string()
2327+
}
2328+
})
2329+
.unwrap_or(name.to_string())
2330+
}
2331+
}
2332+
Arch::Arm64EC if kind == SymbolExportKind::Text => {
2333+
// Arm64EC: only text symbols have '#' prefix decoration
2334+
name.strip_prefix('#').map(|s| s.to_string()).unwrap_or(name.to_string())
2335+
}
2336+
_ => name.to_string(),
2337+
}
2338+
} else {
2339+
// ELF, COFF x86_64: no decoration
2340+
name.to_string()
2341+
}
2342+
}
2343+
22932344
fn add_c_staticlib_symbols(
22942345
sess: &Session,
22952346
lib: &NativeLib,
@@ -2331,7 +2382,13 @@ fn add_c_staticlib_symbols(
23312382
}
23322383

23332384
for symbol in object.symbols() {
2334-
if symbol.scope() != object::SymbolScope::Dynamic {
2385+
// The `object` crate returns `Dynamic` for ELF/Mach-O global symbols,
2386+
// but always returns `Linkage` for COFF external symbols.
2387+
// Accept both on Windows.
2388+
let scope = symbol.scope();
2389+
if scope != object::SymbolScope::Dynamic
2390+
&& !(sess.target.is_like_windows && scope == object::SymbolScope::Linkage)
2391+
{
23352392
continue;
23362393
}
23372394

@@ -2346,9 +2403,8 @@ fn add_c_staticlib_symbols(
23462403
_ => continue,
23472404
};
23482405

2349-
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
2350-
// Need to be resolved.
2351-
out.push((name.to_string(), export_kind));
2406+
let undecorated = undecorate_c_symbol(name, sess, export_kind);
2407+
out.push((undecorated, export_kind));
23522408
}
23532409
}
23542410

tests/run-make/cdylib-export-c-library-symbols/rmake.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,46 @@
11
//@ ignore-nvptx64
22
//@ ignore-wasm
33
//@ ignore-cross-compile
4-
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
5-
// Need to be resolved.
6-
//@ ignore-windows
7-
//@ ignore-apple
84
// Reason: the compiled binary is executed
95

10-
use run_make_support::{build_native_static_lib, cc, dynamic_lib_name, is_darwin, llvm_nm, rustc};
6+
use run_make_support::{
7+
build_native_static_lib, cc, dynamic_lib_name, is_darwin, is_windows, llvm_nm, llvm_readobj,
8+
rustc,
9+
};
1110

1211
fn main() {
1312
cc().input("foo.c").arg("-c").out_exe("foo.o").run();
1413
build_native_static_lib("foo");
1514

1615
rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run();
1716

18-
let out = llvm_nm()
19-
.input(dynamic_lib_name("foo"))
20-
.run()
21-
.assert_stdout_not_contains_regex("T *my_function");
17+
if is_darwin() {
18+
llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T _my_function");
19+
} else if is_windows() {
20+
llvm_readobj()
21+
.arg("--coff-exports")
22+
.input(dynamic_lib_name("foo"))
23+
.run()
24+
.assert_stdout_not_contains("my_function");
25+
} else {
26+
llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T my_function");
27+
}
2228

2329
rustc().input("foo_export.rs").arg("-lstatic:+export-symbols=foo").crate_type("cdylib").run();
2430

2531
if is_darwin() {
26-
let out = llvm_nm()
32+
llvm_nm()
2733
.input(dynamic_lib_name("foo_export"))
2834
.run()
2935
.assert_stdout_contains("T _my_function");
36+
} else if is_windows() {
37+
llvm_readobj()
38+
.arg("--coff-exports")
39+
.input(dynamic_lib_name("foo_export"))
40+
.run()
41+
.assert_stdout_contains("my_function");
3042
} else {
31-
let out = llvm_nm()
43+
llvm_nm()
3244
.input(dynamic_lib_name("foo_export"))
3345
.run()
3446
.assert_stdout_contains("T my_function");

0 commit comments

Comments
 (0)