Repository: rust
Issue: Incompatibility between musl and crates linking to shared libraries
Labels: A-diagnostics,T-compiler,O-musl,C-bug,WG-diagnostics

I'm trying to rewrite [kmscube](https://gitlab.freedesktop.org/mesa/kmscube/) in rust, targetting an environment with musl as libc implementation.
kmscube's goal is to demonstrate the use of opengl without any compositor. It relies on mesa3d's libgbm, which is present as a shared library in my musl environment, at `/usr/lib/libgbm.so`. There is a rust crate wrapping libgbm : [gbm.rs](https://github.com/Smithay/gbm.rs). I'm using the crate as follows:
```rust
extern crate gbm;

use gbm::Device as GBMDevice;
use std::fs::OpenOptions;

fn main() {
	let card = {
		let mut options = OpenOptions::new();
		options.read(true);
		options.write(true);
		options.open("/dev/dri/card0").unwrap()
	};

	println!("pre-gbm");
	let _card = GBMDevice::new(card).unwrap();
	println!("post-gbm");
}
```

Using the gnu (non-musl) target, this happens:
```
cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/azimuth`
pre-gbm
post-gbm
```

Using the musl target, this happens:
```
cargo run --target=x86_64-unknown-linux-musl
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/azimuth`
pre-gbm
Segmentation fault (core dumped)
```
And this SIGSEGV is my problem.

## Analysis

`readelf` reveals the dynamic section of each file:

GNU
```
 0x0000000000000001 (NEEDED)             Shared library: [libEGL.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
[numeric entries]
 0x000000006ffffffb (FLAGS_1)            Flags: NOW PIE
[numeric entries]
```

MUSL
```
 0x0000000000000001 (NEEDED)             Shared library: [libgbm.so.1]
[numeric entries]
 0x000000006ffffffb (FLAGS_1)            Flags: NOW PIE
[numeric entries]
```

As well as the program headers:

GNU
```
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x0000000000000310 0x0000000000000310  R      0x8
  INTERP         0x0000000000000350 0x0000000000000350 0x0000000000000350
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000040e0 0x00000000000040e0  R      0x1000
  LOAD           0x0000000000005000 0x0000000000005000 0x0000000000005000
                 0x00000000000265a5 0x00000000000265a5  R E    0x1000
  LOAD           0x000000000002c000 0x000000000002c000 0x000000000002c000
                 0x0000000000009d58 0x0000000000009d58  R      0x1000
  LOAD           0x0000000000036320 0x0000000000037320 0x0000000000037320
                 0x0000000000001d18 0x0000000000001e98  RW     0x1000
  DYNAMIC        0x00000000000377a8 0x00000000000387a8 0x00000000000387a8
                 0x0000000000000240 0x0000000000000240  RW     0x8
  NOTE           0x0000000000000370 0x0000000000000370 0x0000000000000370
                 0x0000000000000020 0x0000000000000020  R      0x8
  NOTE           0x0000000000000390 0x0000000000000390 0x0000000000000390
                 0x0000000000000044 0x0000000000000044  R      0x4
  TLS            0x0000000000036320 0x0000000000037320 0x0000000000037320
                 0x0000000000000000 0x0000000000000098  R      0x20
  GNU_PROPERTY   0x0000000000000370 0x0000000000000370 0x0000000000000370
                 0x0000000000000020 0x0000000000000020  R      0x8
  GNU_EH_FRAME   0x0000000000030158 0x0000000000030158 0x0000000000030158
                 0x0000000000000b9c 0x0000000000000b9c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000036320 0x0000000000037320 0x0000000000037320
                 0x0000000000001ce0 0x0000000000001ce0  R      0x1
```

MUSL
```
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000006e10 0x0000000000006e10  R      0x1000
  LOAD           0x0000000000007000 0x0000000000007000 0x0000000000007000
                 0x00000000000420eb 0x00000000000420eb  R E    0x1000
  LOAD           0x000000000004a000 0x000000000004a000 0x000000000004a000
                 0x000000000000fda4 0x000000000000fda4  R      0x1000
  LOAD           0x000000000005a060 0x000000000005b060 0x000000000005b060
                 0x0000000000002100 0x0000000000003d08  RW     0x1000
  DYNAMIC        0x000000000005b788 0x000000000005c788 0x000000000005c788
                 0x0000000000000140 0x0000000000000140  RW     0x8
  NOTE           0x0000000000000270 0x0000000000000270 0x0000000000000270
                 0x0000000000000024 0x0000000000000024  R      0x4
  TLS            0x000000000005a060 0x000000000005b060 0x000000000005b060
                 0x0000000000000000 0x00000000000000d8  R      0x20
  GNU_EH_FRAME   0x0000000000051e24 0x0000000000051e24 0x0000000000051e24
                 0x000000000000125c 0x000000000000125c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x000000000005a060 0x000000000005b060 0x000000000005b060
                 0x0000000000001fa0 0x0000000000001fa0  R      0x1
```

Using `strace`, I was able to see that the musl binary never tries to reach for libgbm.
The function call at line 15 results in the use of the symbol `gbm_create_device`, which was never resolved and points to NULL.
→ segmentation fault.

## Interpretation

Upon inspection of the musl target specification in [rust-lang/rust](https://github.com/rust-lang/rust/blob/master/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs), I understand that the musl target systematically produces static binaries. [Further in the targets code](https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/back/linker.rs#L291), the `static_position_independent_executables` target option is converted to a command line argument for gcc: `-static`.

From the GCC manual:
```
-static: On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries.
```
I think GCC achieves this by simply removing the code relocating imported symbols, leaving them unresolved. If we try to use them, we get a segfault.

Does this mean that the musl target is incompatible with any crate that links with shared library at runtime ?
My motivation for using musl is not getting fully static binaries, I just like that it's lightweight and simple. If this incompatibility exists, I'd be happier if I could disable the `static_position_independent_executables` as a feature, so I could use all crates with musl.

**I'm reporting this as a bug because rustc does not warn the developer that using crates linking to a shlib will lead to segfaults.**

## Meta

`rustc --version --verbose`:
```
rustc 1.50.0 (cb75ad5db 2021-02-10)
binary: rustc
commit-hash: cb75ad5db02783e8b0222fee363c5f63f7e2cf5b
commit-date: 2021-02-10
host: x86_64-unknown-linux-gnu
release: 1.50.0
```