Skip to content

linking staticlib files into shared libraries exports all of std:: #33221

@froydnj

Description

@froydnj

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:

  1. libxul didn't suddenly grow thousands of newly-exported symbols overnight.
  2. 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.)

cc @alexcrichton @rillian @glandium

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-linkageArea: linking into static, shared libraries and binariesC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions