Linker version scripts no longer appear to be working in the current version of rust. This appears to be due to Rust providing its own version script which conflicts with the one I want to use.
Example
src/lib.rs
pub unsafe extern "system" fn foo() {}
Cargo.toml
[package]
name = "version_script_test"
version = "0.1.0"
edition = "2018"
[lib]
name = "testing"
crate-type = ["cdylib"]
[dependencies]
mapfile
testing1.0 {
global:
foo;
};
Building
$ rustc --version
rustc 1.54.0 (a178d0322 2021-07-26)
$ cargo rustc -- -C link-args=-Wl,--version-script=mapfile
Compiling version_script_test v0.1.0 (/mnt/c/Users/Jasper/CLionProjects/version_script_test)
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-Wl,--version-script=/tmp/rustcrti1pz/list" [truncated] "-Wl,--version-script=mapfile"
= note: /usr/bin/ld: anonymous version tag cannot be combined with other version tags
collect2: error: ld returned 1 exit status
error: aborting due to previous error
error: could not compile `version_script_test`
To learn more, run the command again with --verbose.
fn main() -> Result<(), std::io::Error> {
let cur_dir = std::env::current_dir()?;
// Use a versionscript to limit symbol visibility.
println!(
"cargo:rustc-cdylib-link-arg=-Wl,--version-script={}/versionscript.txt",
cur_dir.to_string_lossy()
);
}
This helped resolve the error from the compiler, however when I check it using objdump -TC target/debug/libtesting.so it did not attach the version node to foo. I can tell the version script is being used though, since I can remove rust_eh_personality by making it local.
$ objdump -TC target/debug/lib
testing.so
target/debug/libtesting.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 Base __gmon_start__
0000000000000000 w D *UND* 0000000000000000 Base _ITM_deregisterTMCloneTable
0000000000000000 w D *UND* 0000000000000000 Base _ITM_registerTMCloneTable
0000000000000000 w DF *UND* 0000000000000000 Base __cxa_finalize
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_GetDataRelBase
0000000000000000 DF *UND* 0000000000000000 GCC_4.2.0 _Unwind_GetIPInfo
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_GetLanguageSpecificData
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_GetRegionStart
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_GetTextRelBase
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_SetGR
0000000000000000 DF *UND* 0000000000000000 GCC_3.0 _Unwind_SetIP
0000000000003a40 g DF .text 0000000000000001 Base foo
0000000000003c50 g DF .text 00000000000002e5 Base rust_eh_personality
In the objdump output, I would expect it to say testing1.0 instead of Base for foo.
I suspect the anonymous version script generated by Rust is taking precedence. Do you know how I might be able to fix this?
Maybe give the Rust function and the exported symbols different names? You can add a thing to your build.rs to add new names to symbols. So in Rust you e.g. expose foo_impl, and then in build.rs: