-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability from the top-level of the compilation not to mark #[no_mangle] items exported from shared library #73958
Comments
Ran into this today again, because I defined my own malloc-like allocator function and added For now, I can try to prefix it with something reasonably unique, but I'd really rather have private functions stay private and not have to worry about mangling their names manually. |
|
@bjorn3 Right, the situation is a bit different from this issue / my original comment it refers to, but the point is still the same in that |
Mangling is the way to achieve privacy. While ELF and other object formats technically have different visibility modes, those are less useful for Rust than for C. Rust splits up a single crate into multiple codegen units, so any function used in a different codegen unit from the one defining it has to have an external linkage, making it available to all object files used in the linker invocation, thus your |
This is all I want (as well as what @hsivonen describes). I want to be able to expose functions to the C library that is statically linked in as part of |
This problem extends to overriding it for both Rust code and statically linked C code without also overriding it for dynamically linked C code like libc. |
To speak to what we did in C/C++ for Firefox, we used the #pragma GCC visibility push(hidden)
#include_next <real_header>
#pragma GCC visibility pop To @hsivonen's point—the Rust code in Firefox needs to provide a C API to the C/C++ code for FFI purposes, and |
I think this is basically what |
It seems like a useful path forward would be to split Something similar can be done with But also I think there should be a codegen flag for this. |
Isn't By the way why are you using |
|
For this rustc can't do anything as it doesn't control the linker invocation. If it links a cdylib itself it passes a list of all symbols to export to the linker. You did have to emulate this in firefox.
I did recommend putting the part of the library that exports the C api that wraps the rust api in a different crate from the one exporting the rust api. If you don't want the C api to be exported you can then simply depend only on the crate with the rust api. |
This doesn't solve the problem that this issue is about: hiding symbols in the resulting shared library formed by linking a static lib generated by Rust compilation with some other object code. E.g. encoding_rs and encoding_c are a Rust crate and its C API crate. Since Firefox needs the C API, it builds encoding_c as part of its omnibus Rust artifact. Once that's linked with C++ object code to form libxul, having the C API be visible from outside libxul is unwanted. |
The only way to hide those symbols when linking a rust staticlib into a dylib is to pass the linker a list of symbols to hide. This is not something rustc has any control over. If rustc were to do the linking it does this for you, but in the case of libxul rustc doesn't do the linking and as such the build system that invokes the linker is responsible for making sure the symbols are hidden. |
My previous comment here explained the Firefox solution for C/C++, where we encountered similar issues with third-party code. |
Right, hidden visibility doesn't work for rust as we don't yet know in advance if a crate ends up in a rust dylib or cdylib. In the former case hidden visibility is incorrect as a downstream crate may use a function marked with hidden visibility (for example because another function got inlined), while for a cdylib this is not the case. Having a global compiler flag that disables linking as rust dylib only solves part of the issue as the standard library will still not get hidden visibility and libstd is compiled as rust dylib too, so trying to use it with |
The other issue, as raised in #104130, is that we don't want to decide on which symbols to actually link in the cdylib until link time. The alternative is to remove unused APIs via |
Rustc passes the list of symbol to link to the linker and this works just fine despite using default visibility. Rustc basically says make everything hidden except this specific list of symbols. rust/compiler/rustc_codegen_ssa/src/back/linker.rs Lines 694 to 709 in 0aaad9e
|
I can't speak for |
@bjorn3 This does not work fine, see #104130, where it's necessary to be able to configure that. I feel like this issue has had sufficient people with different real-world use cases justifying the need for this, can we move past questioning the need? A lot of these use cases come from complex projects with complex properties, and one thing I've noticed from my years of working on large codebases is that almost always when a large codebase wants feature X, people will suggest a laundry list of things to try instead, and they either won't work or suffer from "I bet that almost works" syndrome I think the stdlib point is a good one and I suspect #104130 paired with a solution here is a good way to fix that. |
That is a wasm specific bug where we fail to hide symbols that are not in the rustc generated list of symbols to be exported. On Windows, macOS and any ELF based system the rustc can pass a specific list and the linker respects this without linking anything else AFAIK.
That is a different use case from the firefox one. In #104130 rustc is invoking the linker and proving an option when compiling the cdylib to only export specified symbols is realistic, albeit requiring a wasm-ld change to allow rustc to hide all symbols except those passed in through The firefox use case is not something rustc can fix as it doesn't control the linker.
I don't question the need, but I think that rustc can't provide the solution for the staticlib crate type, only for the cdylib crate type. For the staticlib crate type I think the only one that can provide a full solution is the thing that invokes the linker by specifying an explicit list of symbols to export. Sure rustc could provide a partial solution using hidden visibility for user crates, but if I understand the post you linked correctly, that is an "I Bet That Almost Works" solution. |
Yes, I understand, I'm highlighting that there are different use cases for the same feature from varied backgrounds. |
Thanks! Do you have ideas as to what is the best path forward here? @sffc can correct me if I'm wrong on this, but we can either have:
It seems like you're leaning towards option 3? |
I think wasm-ld should get a flag that makes it default to hiding all symbols and rustc should use this unconditionally even if none of the suggested flags about controlling In addition we should get a way to allow the user to control the list of symbols exported from a cdylib that works on any platform. I'm not sure if it should be in the form of an allowlist, in the form of a denylist or if both should be supported. I think implementing it in the form of an allowlist would be best as it avoids accidentally exporting symbols you didn't mean to even as you update dependencies, but you probably know better what works than me. |
I guess the wasm-ld stuff occurs upstream, right? |
Indeed. It is part of LLVM. |
I found some new info:
rustc is passing
If I manually remove the Related: ed56145 |
Hmm, ideally that flag would be manually set via link-args but given that it's automatically set perhaps we need another flag to turn it off? |
If rustc changed such that I could turn off both the |
You're probably referring to #104130 not to this issue, as it wouldn't be resolved by Wasm fix alone. |
Indeed. |
It would seem that any FFI bindings tool is going to end up putting all its FFI functions into the exported symbol list due to this conflated use of #[no_mangle] causing export. We're using CXX in Chromium, and it does the following:
We don't want to export all FFI functions from our chrome.dll, or our Mac framework. We can technically use an export list to keep them from being exported on Mac, but Windows linker does not provide the same affordance, so things are much more complicated there. So we really need FFI functions to not be part of the chrome.dll export list. Right now it looks like this, but with many many more.
For clarity, there is a separate issue on Linux/Mac of all Rust symbols ending up in the DLL export list, but these are not #[no_mangle] so I think that should be tracked elsewhere (#37530 ?). Chromium bug for this, which blocks Windows: https://bugs.chromium.org/p/chromium/issues/detail?id=1462356 |
Hi all, I found that this is a big issue when attempting to build the For the time being, I'm relying on manually |
Chromium does something similar for C++. And after https://crrev.com/c/5966273 Chromium gives Rust similar treatment by using So it seems that this issue will be fixed if we can agree on and implement |
For the standard library we have |
Firefox currently builds all its Rust code into a static artifact called
gkrust
which is then statically linked, with cross-language LTO, with C++ artifacts to form the shippablelibxul.so/dylib/dll
.Upon examining the exported symbols of
libxul
, the FFI functions that are meant for internal glue between Rust and C++ show up.This is a problem for two reasons:
libxul
in unsupported ways.Since there's a variety of third-party crates that go into
libxul
, it wouldn't be practical to reannotate each FFI function. Therefore, please add a way from the top level of the Rust compilation to turn off the shared library export metadata generation for#[no_mangle]
items.The text was updated successfully, but these errors were encountered: