rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.84k stars 12.77k forks source link

Isolate llvm's C++ symbols in distibution binaries? #63920

Open jsgf opened 5 years ago

jsgf commented 5 years ago

MIRAI is an abstract interpreter for MIR. It uses the Z3 theorem prover as part of its implementation. Z3 uses C++, and is often used precompiled.

MIRAI also links against rustc. This means that Z3's C++ library conflicts with the libstdc++ linked into rustc (well, libLLVM I think). At best this generates GB of linker errors, at worst something that seems to build but behaves erratically at runtime.

Is there some way to hide all llvm's C++ symbols so that it just becomes an internal implementation details, and a second libstdc++ can coexist in the same address space? Alternatively could it be distributed with a shared libstdc++ so that llvm and Z3 are using a common library?

I can solve this by building everything from source against the same libstdc++, but its a large burden to build rustc from source just to use MIRAI.

cc @hermanventer @alexcrichton

hermanventer commented 5 years ago

To reproduce this, just clone https://github.com/facebookexperimental/MIRAI and try to cargo build on a Linux system (after installing Z3, which you can do using "brew install z3"). If it builds (which it did not, last time I checked), try to run it with cargo test.

alexcrichton commented 5 years ago

We currently ship a compiler with two dynamic libraries that contain C++ code in them. One is LLVM itself, built by LLVM's own build system. I believe the C++ standard library is linked statically into this LLVM dynamic library. The other is librustc_driver.so which contains some C++ shim code compiled so rustc can use bits and pieces of LLVM's C++ interface. (there's a separate issue for removing those shims)

I unfortunately do not know how to instruct LLVM's build system to hide symbols and only expose the ones we want in rustc. I'm not sure it's easily possible either since the C++ APIs that we're using in our shims are probably not super well defined.

jsgf commented 5 years ago

Removing the symbols from rustc_driver will help; then we only need to solve llvm. I wonder if using dlopen(..., RTLD_LOCAL) would help when loading it:

RTLD_LOCAL   Symbols exported from this image (dynamic library or bundle) are generally hidden and only
             availble to dlsym() when directly using the handle returned by this call to dlopen().

I don't know how this applies to transitive dependencies. Maybe statically linking a PIC version libLLVM.a into librustc_codegen_llvm would help in that case? (Or is that already true?)

jsgf commented 5 years ago

@hermanventer BTW, I did a checkout and compile on a current Fedora system using the distro-packaged version of Z3, and it build and ran cleanly without problems.

alexcrichton commented 5 years ago

Oh right! AFAIK we should now be able to use RTLD_LOCAL. Historically we couldn't because some tests relied on the opposite, loading a dynamic library that linked against LLVM and then using that in the compiler. I think nowadays though we dropped support for that (unstable) test so it should be fine to pass in RTLD_LOCAL when we load codegen backends.

jsgf commented 5 years ago

I'll take a look.

bjorn3 commented 1 year ago

The LLVM backend is now linked into librustc_driver.so, so there is nowhere to pass RTLD_LOCAL anymore.