-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
Consider this toy example:
#[no_mangle]
pub fn hello() {
println!("hello world")
}
extern "C" {
void hello();
}
void
really_hello()
{
hello();
}
Compile and link:
$ rustc --crate-type staticlib --emit link=sl.a sl.rs
$ g++ -o hello.so -fPIC -shared driver.cpp sl.a
With rust 1.8.0, we have:
$ ls -l hello.so
-rwxr-xr-x 1 froydnj froydnj 2141544 Apr 26 11:02 hello.so
which is quite large (2MB!) for such a simple program. Despite all of std
being compiled with the moral equivalent of -ffunction-sections
, adding -Wl,--gc-sections
does very little to slim down the binary:
$ g++ -o hello.so -fPIC -shared driver.cpp sl.a -Wl,--gc-sections
$ ls -l hello.so
-rwxr-xr-x 1 froydnj froydnj 2141544 Apr 26 11:02 hello.so
That's only about 400 bytes eliminated, which seems suboptimal.
The problem is that all of the public functions in libstd.rlib
are marked as global symbols. When sl.a
is linked into a shared library, all of those global symbols from libstd.rlib
are now treated as symbols that the newly-created shared library should export as publically visible symbols. Which creates bloat in terms of a large PLT the shared library must tote around as well as rendering -Wl,--gc-sections
ineffective, as virtually everything is transitively reachable from these public functions from libstd.rlib
. hello.so
has ~5000 visible functions, when it should really only have a handful. hello.so
contains code for parsing floating-point numbers, even though it really shouldn't, according to the functions shown above.
This example is admittedly contrived, but Firefox's use of Rust is not terribly dissimilar from this: we compile all the crates we use into rlibs, link all of the rlibs together into a staticlib, and then link the staticlib into our enormous shared library, libxul. We're pretty careful with symbol visibility; we have hundreds of thousands of symbols in libxul, but fewer than 500 exported symbols. We would very much like it if:
- libxul didn't suddenly grow thousands of newly-exported symbols overnight.
- libxul didn't contain Rust code from
std
(or otherwise) that it doesn't use.
We didn't think terribly hard about this when we enabled Rust on our desktop platforms (though we should have), but our Android team cares quite a bit about binary size, and Rust support taking up this much space would be a hard blocker on our ability to ship Rust on Android. It would be somewhat less than the above because we'd be compiling for ARM, but it'd still be significant. (I assume the situation is similar on Mac and Windows, though I haven't checked.)