Skip to content

Sudden failure to link statically on Arch Linux #43647

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

Closed
sanmai-NL opened this issue Aug 4, 2017 · 20 comments
Closed

Sudden failure to link statically on Arch Linux #43647

sanmai-NL opened this issue Aug 4, 2017 · 20 comments
Assignees
Labels
A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. P-high High priority regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Milestone

Comments

@sanmai-NL
Copy link

It's always worked before. Turning back to compiling Rust after some period of other activities, and found out my binaries don't work anymore.

cargo new --bin bla

     Created binary (application) `bla` project

cd /tmp/bla/

env RUSTFLAGS="-C target-feature=+crt-static" cargo build --target x86_64-unknown-linux-musl

   Compiling bla v0.1.0 (file:///tmp/bla)
    Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs

Actual

file ./target/x86_64-unknown-linux-musl/debug/bla

./target/x86_64-unknown-linux-musl/debug/bla: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8c6e0c77c39c031c76d95379bfe2593165b13a70, with debug_info, not stripped

Expected

A description of an executable statically linked to musl libc.

Meta

rustc 1.21.0-nightly (1d2a6df38 2017-08-03)

OS

Arch Linux with musl package version 1.1.16-2.

@sanmai-NL
Copy link
Author

Downgrading musl package to version 1.1.16-1 does not help. Any other options for testing?

@aidanhs
Copy link
Member

aidanhs commented Aug 4, 2017

Can you paste the output of ldd on the binary as well?

@sanmai-NL
Copy link
Author

env -u LD_PRELOAD ldd -v ./target/x86_64-unknown-linux-musl/debug/bla
        statically linked

That seems fine then. The file output is normally correct, however, see e.g. to the bottom of this blog post.

My issue came up when I was trying to run the statically linked executables under Alpine Linux, as before. See this weird situation:

sudo env UNIFIED_CGROUP_HIERARCHY=no \
    rkt run --insecure-options=image docker://alpine:3.5 \
        --volume=bla,kind=host,source=/tmp/bla/target/x86_64-unknown-linux-musl/debug/ \
        --mount volume=bla,target=/bla/ \
        --exec=/bin/sh -- -c 'ldd -- /bla/bla; stat /bla/bla; /bla/bla; stat /lib64/ld-linux-x86-64.so.2'
[114845.186083] alpine[5]:      /lib64/ld-linux-x86-64.so.2 (0x55a8e0d15000)
[114845.186864] alpine[5]:   File: /bla/bla
[114845.187294] alpine[5]:   Size: 3912560      Blocks: 7648       IO Block: 4096   regular file
[114845.187433] alpine[5]: Device: 26h/38d      Inode: 3618974     Links: 2
[114845.187514] alpine[5]: Access: (0755/-rwxr-xr-x)  Uid: ( 1000/ UNKNOWN)   Gid: ( 1000/ UNKNOWN)
[114845.187583] alpine[5]: Access: 2017-08-04 20:28:41.000000000
[114845.187651] alpine[5]: Modify: 2017-08-04 18:23:00.000000000
[114845.187721] alpine[5]: Change: 2017-08-04 20:19:38.000000000
[114845.187793] alpine[5]: /bin/sh: /bla/bla: not found
[114845.187963] alpine[5]: stat: can't stat '/lib64/ld-linux-x86-64.so.2': No such file or directory

Seems the interpreter path isn't correct.

@aidanhs
Copy link
Member

aidanhs commented Aug 5, 2017

I've just tried to follow your steps on the latest nightly and I can't reproduce this - file reports the binary as statically linked. I have a vague recollection that Arch does some custom packaging of rust - can you confirm whether you're using the binary from rustup, or from arch itself?

Your choice of the version of musl package shouldn't make a difference (unless it's related to the custom packaging I mention) because Rust bundles the musl libc.a with the musl target.

@sanmai-NL
Copy link
Author

sanmai-NL commented Aug 5, 2017

Heh, it appears I had rustup installed as an Arch Linux package and via the common installer. Also, cargo now is included in the rustup Arch Linux package. I rectified the situation to only use the Arch Linux packaged rustup. I definitely use the x86_64-unknown-linux-musl target with the nightly-x86_64-unknown-linux-gnu toolchain. Nevertheless, the statically linked binaries still aren't being produced properly.

@sfackler
Copy link
Member

sfackler commented Aug 5, 2017

I can reproduce this as well with rustup-managed 1.19 on Arch, but not on Debian Jessie, where the file type is

target/x86_64-unknown-linux-musl/debug/foo: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, not stripped

It seems like it'd probably have to do with the way Arch's musl toolchain is configured?

@sfackler
Copy link
Member

sfackler commented Aug 5, 2017

Though it looks like you haven't told rustc to use musl-gcc as the linker, since that makes the resulting binary use /lib/ld-musl-x86_64.so.1 as its interpreter rather than /lib64/ld-linux-x86-64.so.2.

@aidanhs
Copy link
Member

aidanhs commented Aug 5, 2017

@sfackler unless I've misunderstood the intent, linking a static binary with the musl target should not require a custom linker unless this is an oddity of arch. In fact, the host musl toolchain should be totally unused (unless depending on a crate that invokes musl-gcc as part of a build script).

@sfackler
Copy link
Member

sfackler commented Aug 5, 2017

Ah! There is a difference between Debian and Arch's musl-gcc wrappers - Debian's pulls in spec files that disable PIE in addition to the normal MUSL one.

This custom linker setup produces fully static binaries on Arch:

test-gcc

#!/bin/sh                                                                                                                                                                                                                                              
exec "${REALGCC:-gcc}" "$@" -specs "$HOME/no-pie-compile.specs" -specs "$HOME/no-pie-link.specs"

no-pie-link.specs

*self_spec:                                                                                                                                                                                                                                            
+ %{!shared:%{!r:%{!fPIE:%{!pie:-fno-PIE -no-pie}}}}
*self_spec:                                                                                                                                                                                                                                            
+ %{!r:%{!fpie:%{!fPIE:%{!fpic:%{!fPIC:%{!fno-pic:-fno-PIE}}}}}}

It looks like we may want to disable PIE for MUSL targets.

@sfackler
Copy link
Member

sfackler commented Aug 5, 2017

We already appear to not enable PIE for MUSL targets, but it looks like we should actually explicitly be disabling PIE rather than relying on the linker default.

base.position_independent_executables = false;

sfackler added a commit to sfackler/rust that referenced this issue Aug 7, 2017
Some linkers (e.g. Debian and Arch's) that are configured to make PIEs
by default will make dynamically linked executables that don't actually
dynamically link to anything. Fix that by explicitly passing -no-pie in
those cases.

Closes rust-lang#43647
@sfackler
Copy link
Member

sfackler commented Aug 7, 2017

It seems like #40113 may resolve this.

@Mark-Simulacrum Mark-Simulacrum added A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 10, 2017
@Mark-Simulacrum
Copy link
Member

Nominating for prioritization, though it looks like this is potentially already fixed? Confirmation would be good.

@michaelwoerister michaelwoerister added P-high High priority and removed I-nominated labels Aug 10, 2017
@michaelwoerister
Copy link
Member

Discussed in the compiler team meeting. P-high, we want to keep an eye on this.

@alexcrichton
Copy link
Member

#40113 seems close to landing, just a final bug or two to iron out.

@sfackler I'm curious though shouldn't we land #43693 regardless? It seems like a "more correct" patch regardless of what happens to the musl target? We may just stop exercising it once #40113 lands.

@sfackler
Copy link
Member

I haven't been following #40113 super closely, but it seemed like it'd end up generating statically linked PIE executables, which seems better than statically linked non-PIE executables, right?

@alexcrichton
Copy link
Member

Looking at this again, this is tagged as a regression but we don't know what caused it. @sanmai-NL do you have a way for me to reproduce locally? Failing that, do you know when this stopped working? If so, you wouldn't happen to know the relevant change, would you?

@sfackler oh sure yeah I don't even remember at this point why musl is non-PIE. If we have future targets that are not PIE (for whatever reason) though it seems like they could benefit from #43693

@sanmai-NL
Copy link
Author

@alexcrichton:
This shell code is supposed to reproduce it ... but doesn't, so far! Any regression is probably because of Arch Linux changes.

mkdir /tmp/bla/ || rm -fr /tmp/bla/ &&
sudo env UNIFIED_CGROUP_HIERARCHY=no \
    rkt run --insecure-options=image 'docker://stephank/archlinux:makepkg' \
        --net=host \
        --dns=host \
        --user=0 \
        --working-dir='/bla/' \
        --volume=bla,kind=host,source=/tmp/bla/ \
        --mount volume=bla,target=/bla/ \
        --exec=/bin/sh -- -c '
        set -x
        yes | pacman -Sy rustup musl pax-utils &&
        rustup install nightly-x86_64-unknown-linux-gnu &&
        rustup default nightly-x86_64-unknown-linux-gnu &&
        rustup target add x86_64-unknown-linux-musl &&
        cargo init --bin --name bla --vcs none . &&
        env RUSTFLAGS="-C target-feature=+crt-static" \
            cargo build --target x86_64-unknown-linux-musl &&
        file target/x86_64-unknown-linux-musl/debug/bla
        scanelf -ain target/x86_64-unknown-linux-musl/debug/bla
        target/x86_64-unknown-linux-musl/debug/bla'
        
sudo env UNIFIED_CGROUP_HIERARCHY=no \
    rkt run --insecure-options=image 'docker://alpine' \
        --working-dir='/bla/' \
        --net=host \
        --dns=host \
        --volume=bla,kind=host,source=/tmp/bla/ \
        --mount volume=bla,target=/bla/ \
        --exec=/bin/sh -- -c '
        set -x
        apk add --update file
        target/x86_64-unknown-linux-musl/debug/bla
        ldd target/x86_64-unknown-linux-musl/debug/bla
        file target/x86_64-unknown-linux-musl/debug/bla'

On my own system the issue is still present though. Apparently the regression is between the age of the Docker image and the date of this GitHub issue. Apparently that is two months.

@alexcrichton
Copy link
Member

@sfackler due to my most recent comment I believe we will end up needing #43693 regardless.

@alexcrichton alexcrichton modified the milestone: 1.21 Aug 23, 2017
@alexcrichton
Copy link
Member

@sfackler now that #40113 has landed would you be interested in trying to re-land #43693?

sfackler added a commit to sfackler/rust that referenced this issue Aug 24, 2017
Some linkers (e.g. Debian and Arch's) that are configured to make PIEs
by default will make dynamically linked executables that don't actually
dynamically link to anything. Fix that by explicitly passing -no-pie in
those cases.

Closes rust-lang#43647
@aidanhs
Copy link
Member

aidanhs commented Aug 25, 2017

#44070 didn't land in the latest nightly, but I compiled it myself.

on my host ubuntu:16.04:

# echo 'fn main() {}' > x.rs
# ./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --target x86_64-unknown-linux-musl x.rs
# file x
x: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=45654470ff0026421c064536a65c073dbfceb840, not stripped
# ldd x
        not a dynamic executable

i.e. still works fine

then continuing in the same terminal with arch:

# docker run -it --rm -v $(pwd):/myrust -w /myrust base/archlinux bash
[root@6aa90f62adb2 myrust]# pacman -Sy curl file gcc
[...]
[root@6aa90f62adb2 myrust]# curl https://sh.rustup.rs -sSf | sh
[...]
[root@6aa90f62adb2 myrust]# source $HOME/.cargo/env
[root@6aa90f62adb2 myrust]# rustup target add x86_64-unknown-linux-musl
[...]
[root@6aa90f62adb2 myrust]# rustc --target x86_64-unknown-linux-musl x.rs
[root@6aa90f62adb2 myrust]# file x
x: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5992690cf70188d0192de6841a4c9399b37d5cc7, with debug_info, not stripped
[root@6aa90f62adb2 myrust]# ldd x
        statically linked
[root@6aa90f62adb2 myrust]# ./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --target x86_64-unknown-linux-musl x.rs
[root@6aa90f62adb2 myrust]# file x
x: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=633f517e0c5a4fea53cf0033446edf1af079d64c, with debug_info, not stripped
[root@6aa90f62adb2 myrust]# ldd x
        not a dynamic executable

i.e. I verified I could reproduce with stable rust, but the recompiled rust fixes the issue.

I'm going to close this since all the pieces are are in place and you should be able to take advantage in the next nightly. Ping me or open an issue if you have any other issues - thanks for reporting!

@aidanhs aidanhs closed this as completed Aug 25, 2017
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. P-high High priority regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants