# How to use linker version scripts in rust 1.54+

**URL:** <https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033>\
**Category:** help\
**Created:** [August 26, 2021, 4:30pm UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033 "2021-08-26T16:30:46Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jmeggitt](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/jmeggitt/32/22486_2.png) [@jmeggitt](https://users.rust-lang.org/u/jmeggitt)\
**Post date:** [August 26, 2021, 4:30pm UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/1 "2021-08-26T16:30:46Z")

</div>

This is essentially the same as the [question](https://users.rust-lang.org/t/linker-version-script/26691) asked by @alexanderlinne back in 2019.

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`

```rust
pub unsafe extern "system" fn foo() {}

```

### `Cargo.toml`

```toml
[package]
name = "version_script_test"
version = "0.1.0"
edition = "2018"

[lib]
name = "testing"
crate-type = ["cdylib"]

[dependencies]

```

### `mapfile`

```rust
testing1.0 {
       global:
                foo;
};

```

### Building

```rust
$ 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.

```

**How can I use my own version script?**

---

<div class="post-metadata">

**Author:** ![itamarst](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/itamarst/32/21395_2.png) [@itamarst](https://users.rust-lang.org/u/itamarst)\
**Post date:** [August 28, 2021, 12:17am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/2 "2021-08-28T00:17:05Z")

</div>

GNU `ld` can't do multiple version scripts... but `lld` can. So:

1. Use `lld`.
2. If you want to hide symbols from rustc's version script, you can mark them as private in yours by setting them as local.

`export RUSTFLAGS="-Clinker=clang -Clink-arg=-fuse-ld=lld"`

The `build.rs`:

```rust
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()
    );
}

```

And the version script:

```rust
{
  global:
    yourlibrary_symbol;
    yourlibrary_symbol2;
  local:
    rust_eh_personality;
    *;
};

```

---

<div class="post-metadata">

**Author:** ![jmeggitt](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/jmeggitt/32/22486_2.png) [@jmeggitt](https://users.rust-lang.org/u/jmeggitt)\
**Post date:** [August 28, 2021, 1:08am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/3 "2021-08-28T01:08:55Z")

</div>

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.

```rust
$ 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?

---

<div class="post-metadata">

**Author:** ![itamarst](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/itamarst/32/21395_2.png) [@itamarst](https://users.rust-lang.org/u/itamarst)\
**Post date:** [August 28, 2021, 1:29am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/4 "2021-08-28T01:29:29Z")

</div>

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`:

```rust
    println!("cargo:rustc-cdylib-link-arg=-Wl,--defsym=foo=foo_impl");

```

---

<div class="post-metadata">

**Author:** ![itamarst](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/itamarst/32/21395_2.png) [@itamarst](https://users.rust-lang.org/u/itamarst)\
**Post date:** [August 28, 2021, 1:29am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/5 "2021-08-28T01:29:57Z")

</div>

And then your version script versions the newly created `foo` that `rustc`'s version script didn't touch.

---

<div class="post-metadata">

**Author:** ![jmeggitt](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/jmeggitt/32/22486_2.png) [@jmeggitt](https://users.rust-lang.org/u/jmeggitt)\
**Post date:** [August 28, 2021, 1:51am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/6 "2021-08-28T01:51:28Z")

</div>

Thanks! `--defsym` with `lld` did the trick to fix the issue.

## Changes

```rust
#[no_mangle]
pub unsafe extern "system" fn foo_impl() {}

```

```rust
testing1.0 {
       global:
                foo;
       local:
                foo_impl;
};

```

## Output

```rust
$ cargo rustc -- -C link-args=-Wl,--defsym=foo=foo_impl,--version-script=mapfile -Clinker=clang -Clink-arg=-fuse-ld=lld
   Compiling version_script_test v0.1.0 (/home/tests/projects/version_script_test)
    Finished dev [unoptimized + debuginfo] target(s) in 15.09s
$ 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 GLIBC_2.2.5 pthread_mutex_lock
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 pthread_mutex_unlock
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
0000000000003c40 g DF .text 00000000000002e1 Base rust_eh_personality
0000000000003a10 g D .text 0000000000000000 testing1.0 foo

```

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [November 26, 2021, 1:52am UTC](https://users.rust-lang.org/t/how-to-use-linker-version-scripts-in-rust-1-54/64033/7 "2021-11-26T01:52:19Z")

</div>

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.
