File-scope `.symver` is ignored, so generated bindings call the default symbol version

Open
#3,460 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
c, linux, rust

Research direction

Start with the input.h, lib.c, and vers.map reproduction, then trace bindgen's handling of declaration-level asm and file-scope .symver; the issue notes that no symver handling exists in the sources. Done means bindings preserve api@VERS_1 or diagnose unsupported versioning, so C and Rust callers no longer select different symbols.

Written by the indexing model from the issue text.

Description

Input C/C++ Header
int api(int x);
__asm__(".symver api,api@VERS_1");

The shared object that implements api exports two versions (this is not the bindgen input):

int api_v1(int x) { return 101; }
int api_v2(int x) { return 202; }
__asm__(".symver api_v1,api@VERS_1");
__asm__(".symver api_v2,api@@VERS_2");
VERS_1 { global: api; local: *; };
VERS_2 { global: api; } VERS_1;
Bindgen Invocation
$ clang -O0 -fPIC -shared -o libapi.so lib.c -Wl,--version-script=vers.map
$ bindgen input.h --rust-target 1.77 --no-rustfmt-bindings -o bindings.rs
Actual Results

A C TU that includes the header compiles a relocation to the non-default version api@VERS_1. bindgen emits an unversioned api:

extern "C" {
    pub fn api(x: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
}

On the same libapi.so (nm shows api@VERS_1 and default api@@VERS_2):

C caller including input.h:     v=101
Rust caller using bindings.rs:  v=202

Control: the same shared object, but a header that is only int api(int x); (no .symver). Then both C and Rust print v=202.

bindgen 0.70.1, 0.73.1, and current main (77cbc723) all emit the unversioned pub fn api. There is no symver handling in the bindgen sources.

Declaration-level __asm__("other_name") and #pragma redefine_extname already become #[link_name]. File-scope .symver does not.

This is ELF-only (GNU symbol versioning). Layout tests are not involved.

Expected Results

The generated binding should call the same symbol a C TU that includes the header calls, for example by emitting a versioned link_name for api@VERS_1, or by diagnosing that the header selects a non-default version.

Silently emitting an unversioned api makes a Rust caller bind the default api@@VERS_2 while C callers of that header use api@VERS_1.

Environment
bindgen current main: 77cbc723
bindgen crate:        0.70.1
clang:                Ubuntu clang 15.0.7
rustc:                1.86.0
target:               x86_64-unknown-linux-gnu
Dominant language
Rust
Stars
5.3k
Forks
846
Avg merge
2d 6h
Merged PRs (30d)
11

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rust-lang/rust-bindgen

All issues in rust-lang/rust-bindgen

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.