Skip to content
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

Linking a staticlib into shared C library or executable with gcc causes considerbly larger binary than linking into a cdylib or executable with rustc #111593

Open
sdroege opened this issue May 15, 2023 · 4 comments · May be fixed by rust-lang/reference#1361
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sdroege
Copy link
Contributor

sdroege commented May 15, 2023

See https://github.com/sdroege/rust-staticlib-bloat-test for the code. This doesn't use cargo to make the actual compiler invocations clear (the same behaviour can be observed with cargo).

With Rust 1.69 and gcc 13.1.1 on Linux x86-64 the following can be observed:

unstripped stripped (--strip-all)
Rust executable (my_test) 4.1MB 315kB
Rust cdylib (libstaticlib.so) 4.0MB 290kB
gcc executable (my_staticlib_test) 5.2MB (+ 27%) 1.1MB (+ 355%)
gcc shared library (libmy_staticlib_test_dylib.so) 5.6MB (+ 40%) 1.5MB (+ 517%)

The actual size comes from the enabled overflow checks (-C debug-assertions=on) , and thus all the panic and string formatting machinery that is included. However, this should be approximately the same code in either case so that doesn't explain the difference. (Disabling the overflow checks gives a more expected result because the function from the library compiles down to a few instructions) Also note that this compiles with -C panic=abort so having the assertion in an extern "C" function is not UB.

The question here now is what exactly the difference between both cases is, and how the staticlib case can be improved. Maybe this requires changes in the compiler, maybe this just requires invoking the linker differently (in which case this would be useful to add to the documentation).

@GuillaumeGomez GuillaumeGomez added A-linkage Area: linking into static, shared libraries and binaries C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. and removed C-enhancement Category: An issue proposing an enhancement or a PR with one. labels May 16, 2023
@bjorn3
Copy link
Member

bjorn3 commented May 16, 2023

For cdylib we use a version script to limit the exported symbols in combination with --gc-sections to remove unused functions. Did you pass --gc-sections when linking yourself?

@sdroege
Copy link
Contributor Author

sdroege commented May 16, 2023

That makes a lot of sense, sorry for missing that. Passing -Wl,--gc-sections solves it for the executable. I guess for the shared library a version script to not re-export random Rust symbols would also fix it (will test later and update this comment it does).

Do you think this would be useful to add to e.g. https://doc.rust-lang.org/reference/linkage.html ?

@bjorn3
Copy link
Member

bjorn3 commented May 16, 2023

I guess for the shared library a version script to not re-export random Rust symbols would also fix it (will test later and update this comment).

You need both. Without the version script the linker needs to export all symbols, but without --gc-sections the linker won't omit unused functions even if the version script says they aren't exported.

Do you think this would be useful to add to e.g. https://doc.rust-lang.org/reference/linkage.html ?

Yeah, could be useful to add a recommendation to pass -Wl,--gc-sections (and -dead_strip on macOS) there.

@sdroege
Copy link
Contributor Author

sdroege commented May 16, 2023

You need both. Without the version script the linker needs to export all symbols, but without --gc-sections the linker won't omit unused functions even if the version script says they aren't exported.

Yeah, with that it's also the same in both cases. Thanks!

I'll prepare a PR for adding a sentence about that to the docs some time later :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
3 participants