Support SymbolVersioning in #[export_name]

TDLR: Support "@" character in #[export_name]

I am refering the symbol versioning in SymbolVersioning - GCC Wiki

In C, it's possible to specify symbol version via inline asm, for example

void original_foo() {
}
void new_foo() {
}
__asm__(".symver original_foo,foo@VERS_1.0");
__asm__(".symver new_foo,foo@VERS_2.0");

I currently do not find a way to do this in the stable channel rust I think rust can support this if #[export_name] accepts string which contains "@" For example,

#[export_name = "foo@VERS_1.0"]
pub fn foo() {

}
#[export_name = "foo@VERS_2.0"]
pub fn original_foo() {
}

Currently, the above rust code will fail during linking, because the character "@" is invalid in linker version script.

Can rust handle the "@" character specially in #[export_name] to generate a valid version script and inline asm for ".symver"?

This issue may be of interest here (three digit ID!):

The old issue appears to be talking about symbol versioning in the context of a stable Rust ABI (the thing we'd need in order to ship librust-std.so.1); whereas I understand OP to be asking for the smaller feature of symbol versioning on an exported C-compatible interface.

For LTO to work correctly, the compiler needs to know what the versioning directives mean; they can't just be emitted as opaque inline assembly directives. This means this feature request is going nowhere until LLVM grows support for something equivalent to GCC's __attribute__((symver)) (as far as I can tell LLVM currently doesn't have this, but I could have missed something).

Second, I think it will be more ergonomic to separate the version annotation from the exported-name annotation, and not make the programmer remember how many @ signs they need; perhaps something like

#[export_name = "foo", version = "LIBX_1.0"]
pub fn old_foo () {}

#[export_name = "foo", version = "LIBX_2.0", default_version]
pub fn new_foo () {}

or

#[export_name = ("foo", version = "LIBX_1.0")]
pub fn old_foo () {}

#[export_name = ("foo", version = "LIBX_2.0", default_version)]
pub fn new_foo () {}

And finally, if you need this feature, you are likely to also need to be able to assign multiple exported names (each with its own version) to a single item. This would be easier to accommodate with the syntax with the parentheses:

#[export_name = [
    ("foo", version = "LIBX_1.0"),
    ("foo", version = "LIBX_2.0", default),
    ("foobar", version = "LIBY_0.5")  // an obsolete fork
]]
pub fn i_am_many_foos () {}

(If you're thinking YAGNI, I invite you to review the build process for libxcrypt, particularly the files lib/libcrypt.map.in and lib/libcrypt.minver and how they get turned into crypt-symbol-vers.h.)

1 Like