-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
When linking statically, native libraries should go inside --start-group/--end-group for robustness #76992
Comments
https://sourceware.org/binutils/docs/ld/Options.html Circular dependencies are not a common case, and it's better to pass the libraries with circular dependencies multiple times like |
I guess this issue is motivated by linking libc and libgcc or something. |
@petrochenkov The issue is that most crates don't account for static linking at all, and while I've tested linking with and without Based on that, I think it'd be reasonable to do this by default, to make static linking more user-friendly and less fiddly. And to be clear, I'm only suggesting emitting this when linking statically. (It's possible to make |
It could have been "significant performance cost" 2 decades ago. List of the libraries
I'm wondering if this is observable slowdown. |
I guess someone needs to check the perf impact of wrapping everything into a group with BFD linkers (for both ELF and COFF) in common scenarios like "no cyclic dependencies" or "one cyclic dependency between libc and libgcc at the end of a long library list". Functionally this should be ok in practice since LLD is always doing this implicitly and reports no issues. |
Also, I have no idea about grouping in macOS linkers. (Other linkers that we support are wasm-ld which is lld, and PTX linker which is a Rust project.) |
The issue with LLD approach is visible when you are using 32-bit LLD binary on Windows. It has hard time linking huge projects like LLVM. On Linux we should test BFD and GOLD and on Windows just BFD. |
I ran My results:
This was the ideal case, all libs were in the proper order. Apparently there is no overhead of I think we would need huge project with few dozen libs in |
@mati865 Thanks for getting numbers on this. That sounds like a pretty compelling argument that there's no longer any measurable performance loss. I think it'd be a good idea to make this change, to simplify static linking. |
This came up tangentially in the Cargo team meeting today and I wanted to leave a comment here with my thoughts. If Basically AFAIK this is just a weird artifact of behavior from GNU LD which doesn't really make much sense in the modern era and is purely just a pain to work around. If that's actually the case it'd be cool if we could just always pass these options! |
Still it was very small "hello world" example. IMO we would also have to prove there is no big difference for projects with dozens of libraries. Who knows, maybe the slowdown will be exponential for BFD? |
I've tested projects with a dozen libraries and gotten similar results. |
I recently ran into a new issue that would have been fixed by this. On aarch64, the LSE outline-atomics symbols recently added to compiler-builtins have a dependency on the
Moving the link of the compiler_builtins rlib to inside the start-group/end-group fixes this error. Given that, I think we should switch to using start-group/end-group by default. |
I still have it on my long TODO but it's rather low so I won't mind somebody beating it to me. |
Currently giving this a shot in #85805 |
FWIW, I'm still running into getauxval issues on aarch64 as noted above. #89626 (comment) contains my investigation. |
When rustc links rlib libraries, it puts all the libraries inside a
--start-group
/--end-group
pair, causing the linker to resolve backreferences from a library later in the command line to one earlier in the command line.However, when rustc links native libraries, it puts libraries on the command line in whatever order it encountered them in code.
With shared linking, that works fine. But with static linking, the order has a crucial semantic significance: symbols in a library will get thrown away unless a library listed previously on the command line has a corresponding unresolved symbol.
Rust
#[link]
directives don't account for this, and crates in general don't worry about link order, precisely because dynamic linking is the default. When linking statically to multiple libraries, where one depends on another, this is very likely to result in symbol resolution failures at link time. In addition, if libraries have circular references (such as between glibc and libgcc), there is no order that will allow the libraries to link without duplicating at least one library, which seems like something#[link]
directives should not need to account for.I would propose that when linking statically, Rust should always put all libraries, both rlibs and native libraries, inside one large
--start-group
/--end-group
pair, which will allow the linker to handle symbol references both backwards and forwards, as well as circular symbol dependencies.The text was updated successfully, but these errors were encountered: