Exporting Dynamic Symbols from Executable


#1

I’m trying to create a Rust executable which embeds the Lua run-time and exports the LUA_API and LUALIB_API functions so that I can load Lua libraries (essentially shared objects which link against API functions in the run-time) but I cannot figure out how to specify which symbols should provide dynamic linkage in the executable.

For a C program I use __attribute__((visibility("default"))) on the function declaration/definition, and then -fvisibility=hidden for the compile step and -rdynamic for the link step (equivalent to -Wl,--export-dynamic).

The only solution I’ve been able to work out so far for Rust is to create a symbol file dynsyms.txt containing { lua_*; luaL_* }; and then calling cargo rustc -- -C link-args='-Wl,--dynamic-list=dynsyms.txt' to compile the program, but this feels clumsy.

If I define a public Rust function with the attribute #[no_mangle] then it (magically?) appears in the dynamic symbol list, but I cannot figure out how to do this for extern functions or use functions. Note that for Rust functions neither pub or no_mangle is sufficient on its own, both must be present.


#2

Have you tried just passing --export-dynamic as a link argument (rather than --dynamic-list)? I’m pretty sure Rust does the equivalent of -fvisibility=hidden by default, and it would be the Lua static library itself that determines the visibility of its symbols, not Rust. I don’t think there even is any way for object files to “re-export” hidden symbols from other object files as non-hidden, in GNU land. Of course Rust could try to be smart and automatically pass those linker flags based on some property of declarations, but it currently doesn’t.

It’s also possible to specify link_args in a source file, but that feature is currently unstable.


#3

--export-dynamic does sort of work. I end up with around 12,000 symbols in my program, but focusing just on the Lua component which I have compiled to a static library and then linked into my executable the symbols appear with the correct visibility that I defined in the original static library, so this is good. There is the small issue that any libraries that I use that don’t correctly define visibility will be exported, but this isn’t Rust’s problem, that rests with those libraries so OK.

The bigger issue that leads to the 12,000 symbols is that every rust symbol which is public anywhere (including dependencies) seems to be being exported as dynamic but with type a and address 00000000. I cannot find very much information about these symbols but that they are local absolute symbols according to the OpenGroup specification (they don’t actually appear in the Gnu nm manpage). This may be a bug since I cannot understand how a local symbol being dynamic is in any way helpful. These symbols appear in both release and debug targets.

I suppose then that if these type a symbols can be dealt with and the --export-dynamic flag somehow integrated into Cargo then this would be a good solution to the problem I am having.

Actually, given that Rust does a reasonable job of hiding its symbols properly, then --export-dynamic could actually be set as the default option and the symbol exports I need would be automatic based on the options I set in the original C library. That would be nice.