-Zstaticlib-hide-internal-symbols and Zstaticlib-rename-internal-symbols: hide/rename internal symbols in staticlibs#155338
-Zstaticlib-hide-internal-symbols and Zstaticlib-rename-internal-symbols: hide/rename internal symbols in staticlibs#155338cezarbbb wants to merge 10 commits into
-Zstaticlib-hide-internal-symbols and Zstaticlib-rename-internal-symbols: hide/rename internal symbols in staticlibs#155338Conversation
|
rustbot has assigned @petrochenkov. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
|
This would also need to rename symbols to avoid conflicts between two rust staticlibs ending up getting linked together, right? |
Why exactly is that the case? |
ff707ad to
7ac49d1
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
My primary goal right now is to reduce binary size, so I don't have immediate plans to implement symbol renaming. This means that linking multiple Rust staticlibs together can still result in multiple definition errors. Would you like me to address that in this PR as well? It seems feasible to implement — for example, by rehashing symbols and updating their references accordingly. |
I previously assumed this symbol needed to remain externally visible to support scenarios requiring cross-language exception propagation. Do you think we should also set rust_eh_personality as hidden? |
|
If it isn't too hard it would be nice to do symbol renaming too. I think doing in-place modification isn't going to work for that though. Adding a unique suffix would require growing the size of the string table. |
|
Got it. I will first fix the |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
5e1c3a1 to
c7d4e98
Compare
|
@bors delegate=try |
|
✌️ @cezarbbb, you can now perform try builds on this pull request! You can now post |
|
@bors try |
This comment has been minimized.
This comment has been minimized.
`-Zstaticlib-hide-internal-symbols`: Hide non-exported internal symbols from staticlibs
|
@bors try jobs=x86_64-* |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
`-Zstaticlib-hide-internal-symbols` and `Zstaticlib-rename-internal-symbols`: hide/rename internal symbols in staticlibs try-job: dist-x86_64-apple try-job: dist-aarch64-apple try-job: dist-apple-various try-job: aarch64-apple
|
💔 Test for 94c46cf failed: CI. Failed job:
|
This comment has been minimized.
This comment has been minimized.
|
@bors try job=aarch64-apple |
This comment has been minimized.
This comment has been minimized.
`-Zstaticlib-hide-internal-symbols` and `Zstaticlib-rename-internal-symbols`: hide/rename internal symbols in staticlibs try-job: aarch64-apple
|
It looks like the test passed on Apple targets. You can try the current modifications to see if they meet your requirements. @MicroDroid |
|
@cezarbbb Awesome, I think to test it out I just checkout this PR on my computer and build |
|
Correct. Fetch my PR and build |
|
I'll check it out in a sec and report it goes! |
|
Hey @cezarbbb, so I've been trying to get this to work for both Android and iOS, and I'll let you know what happened for each Android (
|
|
Oh my bad, looks like I forgot to set |
|
Ok a new short summary is I tried building with this command for both iOS and Android: And for both targets I got this error: However if I build with just: Then build succeeds. In other words it seems like |
|
It seems that I made a stupid mistake — the flag was using a The fix is to just emit a warning and continue. I'll fix it shortly. |
|
You can try again. |
|
Already in-progress, should report back in a bit :) But one thing I noticed is that now builds emit a warning every dependency crate which is a bit spammy / likely unintended. |
|
Preliminarily speaking, I think it is renaming user-defined symbols, causing undefined symbol errors when the output goes into the linking stage: (I am using cxx.rs btw) Simply toggling the rename flag off fixes this build error. Still investigating. |
|
I think the rename flag indeed modifies public symbols:
When linking against It also seems like the flag breaks mangling somehow as such it could demangle |
|
I see. The |
|
I think I can filter by filename and only process |
|
I have no idea, but let me test that already on my setup |
|
I think I'm like 99% sure renaming works flawlessly now. So my setup was 2 Rust libraries being ported to C++ via cxx.rs and linked independently into a mobile app. There were
For one of the Rust libraries I built it with the That was for Android though, for iOS I'll get that tested very soon too, maybe within the next hour. |
|
Took me long time to test for iOS cause I'm having other unrelated issues with the iOS build, but nonetheless judging by how far I am I think the patch just works on iOS too ✅ |

View all comments
According to issue #104707, when building a staticlib, all Rust internal symbols — mangled symbols,
#[rustc_std_internal_symbol]items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only#[no_mangle]symbols via a linker version script.Two flags are provided, respectively solved the problems of staticlibs exporting many unnecessary Rust internal symbols and multiple staticlibs causing duplicate symbol conflicts:
-Zstaticlib-hide-internal-symbolsdirectly post-processes ELF object files in the archive: parsing theSHT_SYMTABsections and settingSTV_HIDDENvisibility on anyGLOBAL/WEAKdefined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead.-Zstaticlib-rename-internal-symbolstakes a two-pass global approach: first, it collects all definedGLOBAL/WEAKsymbol names that are not in the exported symbol set across all .o files; then it renames those symbols in each .o file by appending a suffix (e.g.__rust_internal_), handling both definitions and undefined references so that cross-object-file references remain consistent. The implementation uses a "move strtab to end" strategy: it builds a newstrtabwith the renamed names, places it at the end of the file, and patches thestrtabsection header and the ELFe_shoff. When combined with-Zstaticlib-hide-internal-symbols, the renamed symbols also receiveSTV_HIDDENvisibility.The two flags for symbol hiding and symbol renaming need to be decoupled, because hiding incurs virtually no overhead, whereas renaming comes with unavoidable costs. Reducing binary size and resolving duplicate symbol conflicts between multiple staticlibs are two distinct requirements. For this reason, I want to let developers choose and trade off between them based on their own needs.
Both flags only affect ELF targets; a warning is emitted for non-ELF targets
The test code are as follows:
1.a std rust staticlib:
1.b downstream c program:
The test results with different compiler flags(which might cause binary size reduction) are as follows:
1.c result with
-Zstaticlib-hide-internal-symbols1.d result with
-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols2.a no_std rust staticlib
2.b downstream c program
The test results with different compiler flags(which might cause binary size reduction) are as follows:
2.c result with
-Zstaticlib-hide-internal-symbols2.d result with
-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbolsTest results show that this compiler option is beneficial for scenarios where LTO cannot be enabled.
r? @bjorn3 @petrochenkov