-
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
Improve symbol visibility handling for dynamic libraries. #38117
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me!
Could you also post a small tl;dr; of the high-level changes here? I got lost a bit in the refactorings, but it seemed like it was (a) a tweak to how we call the linker and (b) a tweak to sometimes set symbols to hidden. Clarifications on these two though would be welcome :)
Also, I'm curious about the rlib-into-dylib case as well. Presumably rlibs don't have hidden symbols if they're public exported, right? In that case, if it's linked into a cdylib we're using the "fancy linker argument" to not export the symbols? If it's linked into an executable or goes into a staticlib the symbol will still be exported? (unsure on this last bit)
@@ -0,0 +1,26 @@ | |||
include ../tools.mk | |||
|
|||
all: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This'll probably need a guard or two for only running on Linux (I think).
Either that or it'll need some tweaks to run on OSX/Windows
config::CrateTypeExecutable | | ||
config::CrateTypeStaticlib | | ||
config::CrateTypeCdylib => SymbolExportLevel::C, | ||
config::CrateTypeProcMacro | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can actually switch this to a c export level, it's essentially like an executable where nothing else will ever link to it again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it is more or less like a cdylib, right? Or a Rust dylib?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, more like a cdylib
_ => { | ||
sess.fatal("lto can only be run for executables and \ | ||
if !crate_type_allows_lto(*crate_type) { | ||
sess.fatal("lto can only be run for executables and \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This message does not match the crate_type_allows_lto
function above anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix it.
The main changes in here are:
I'm just thinking, maybe it would be sufficient to just always rely on explicit export lists and don't bother with marking things as hidden in LLVM. I'm not sure though if LLVM can already do some optimizations based on the fact that something is |
More information for the compiler is almost always better. I think the roughly equivalent situation in C/C++ on Linux is using |
Yeah I agree with @froydnj that getting info in the compiler is best. We also want to help out the staticlib case as much as possible where we don't always control the linker invocation. @michaelwoerister do you have thoughts on the "rlib in dylib case" above |
I tried to list the various cases in the test. To summarize:
So this is pretty much what you said, I think. As for static libs: They inherit whatever we mark things as in LLVM, I'm not sure actually if the version script will cause the linker to put things not in there into the local symbol table, even if not building a dynamic library. Ideally we'd only want things in the staticlib's global symbol table that would also be exported from a cdylib, right? |
Yeah in theory a staticlib exported symbol list is precisely the same as a cdylib. Unfortunately though, as you've seen, I don't think we can actually do that. Maybe one day we can emit something that's like "pass these extra args to the linker" but we're not quite there just yet. |
This and what @froydnj mentioned would be good reasons for switching to rlibs that don't contain any machine code. Then we could control all of this at the leaf products by just declaring things as hidden in LLVM. |
This is a conservative policy, but not necessarily optimal, right? e.g. A dylib which was linked with the |
Everything that is publicly reachable, not marked with Rust dylibs are strange things anyway. I'm wondering if we should get rid of them, or at least declare them as unstable, not that we have cdylibs. |
Hey if we get a fast enough code generator I'm all for this, it'd solve quite a few problems. |
For instance, if my library was a |
@cuviper If |
@michaelwoerister There still could be some benefit to a dylib, if there's some part of that fancy algorithm that doesn't depend on the generic type, perhaps only dealing with the length. But OK, the example doesn't have to be generic, so let's try something concrete. Consider I'm not suggesting this needs to block the PR, just that there's further room for improvement. In practice people should favor rlibs anyway, since there's no stable ABI in a dylib. |
@cuviper But how does the compiler know what is related and what isn't? Maybe you included some rlib only because you want to make it's symbols available in your dylib? But I agree that this is not exactly a desirable state of affairs. |
@cuviper note that symbol visibility was a primary reason cdylibs were created. If you want strict control over symbols then dylib isn't the crate type you want (due to the way rustc uses it). A cdylib, however, is intended to be as conservative as possible with symbol exports. |
Could be, but I think that's a niche case. Maybe there could be a
OK, but I'm saying the "uncontrolled" state of symbols is not ideal. I think the default should only export things the crate itself makes directly reachable. I might want Maybe we should move this to its own issue. P-low because dylibs are a bit silly anyway. |
How important is it to allow symbol preemption in dylibs? This feature does not exist on Windows and I can't say I ever missed it. |
Does anybody how that would interact with codegen? If LLVM relies on the symbol not being exported but then the linker exports it anyway, that sounds like a potential problem. |
LLVM will outright remove code for provably unreachable stuff. |
Some platforms have differences in calling convention too -- e.g. IIRC ppc64le can have multiple entry points depending on whether you need to setup the TOC pointer. |
If I am reading this correctly, hidden symbols are still available for static linking, however they are not put into the dynamic symbol table, should that object be linked into a shared lib. Also, internal references to them inside the shared lib will not use indirection via PLT. |
I don't think that
That sounds like a problem. |
btw the only changes wrt this PR itself I see before r+ are:
(just to summarize) |
6077ba8
to
4c675a9
Compare
This should work now for OSX and MSVC. On MINGW I see too many symbols included for cdylibs, so there's still a bug in there somewhere.
This should be fixed by 581c292 now. |
☔ The latest upstream changes (presumably #38055) made this pull request unmergeable. Please resolve the merge conflicts. |
r=me whenever this passes tests, or also feel free to use bors to see if it passes tests :) |
4c675a9
to
2863736
Compare
2863736
to
8ecdc4e
Compare
I disabled tests on MINGW now. The linker there seems to ignore |
@michaelwoerister sounds ok to me, we can always look more into it if it becomes a problem. |
Have you tried You might also try messing with
|
@bors r=alexcrichton Let's give it a try |
📌 Commit 8ecdc4e has been approved by |
Improve symbol visibility handling for dynamic libraries. This will hopefully fix issue #37530 and maybe also #32887. I'm relying on @m4b to post some numbers on how awesome the improvement for cdylibs is `:)` cc @rust-lang/compiler @rust-lang/tools @cuviper @froydnj r? @alexcrichton
rust nightly after Dec-8 will have a problem with crates generating cdylib with cargo clippy (tested with clippy version 0.0.104) - it fails at linking step with - syntax error in version script - error. This is apparantly a bug due to rust-lang/rust#38117. So reverting back to using rust-nightly of 17th Nov 2016 and clippy of v0.0.99.
This will hopefully fix issue #37530 and maybe also #32887.
I'm relying on @m4b to post some numbers on how awesome the improvement for cdylibs is
:)
cc @rust-lang/compiler @rust-lang/tools @cuviper @froydnj
r? @alexcrichton