Rust: relocation-model=dynamic-no-pic passes `-pie` to ld

Created on 27 Jul 2016  路  9Comments  路  Source: rust-lang/rust

I'm having trouble linking a Rust program to a non-position-independent C library. When I manually remove the -pie flag from the ld step that rustc runs, everything works correctly. I think that -C relocation-model=dynamic-no-pic should remove the -pie flag for me, but it doesn't.

Here's what I think is going on:

When I run

strace -s 300 -e execve -f rustup run nightly rustc hello.rs -v -C relocation-model=dynamic-no-pic

It runs ld with the -pie flag:

execve("/usr/bin/ld", ["/usr/bin/ld", "-pie"

But when I read the rustc code here, it seems like the intention is that -pie should only be passed to ld when relocation-model=pic. That is, if we're not compiling a position independent executable, then we should not pass the position independent executable -pie flag to ld.

I think what may be happening here is that somehow the defaults from https://github.com/rust-lang/rust/blob/5229e0efb34f924346febcfe158973486dabdf83/src/librustc_back/target/mod.rs#L315 are overriding the command line options I'm setting.

This happens with stable and also the nightly I tried:

rustc 1.12.0-nightly (9316ae515 2016-07-24)
binary: rustc
commit-hash: 9316ae515e2f8f3f497fb4f1559910c1eef2433d
commit-date: 2016-07-24
host: x86_64-unknown-linux-gnu
release: 1.12.0-nightly
A-frontend C-bug

Most helpful comment

I did a bit of reading and here's what I figured out, please correct me if any of this is wrong. Linkers are new to me!

Rust builds position independent executables by default on platforms that support it. These platforms have a relocation model of pic in their target config. The code @jvns linked is what sets that linker option, except if it's disallowed by -static.

The correct solution to this is to add a -C no-pie codegen flag, or something like that. Does this sound right?

All 9 comments

-pie and -pic are two distinct things. -pie is also unrelated to the relocation-model option. Interestingly, I do not remember us having an option to disable PIE; we should have one.

I did a bit of reading and here's what I figured out, please correct me if any of this is wrong. Linkers are new to me!

Rust builds position independent executables by default on platforms that support it. These platforms have a relocation model of pic in their target config. The code @jvns linked is what sets that linker option, except if it's disallowed by -static.

The correct solution to this is to add a -C no-pie codegen flag, or something like that. Does this sound right?

Hi,

I am having the same issue. I am trying to link against non-position-independent C library, build process ends without error but results returned by Rust bindings are different (and incorrect) than those returned from clean C implementation.

In order to overcome that issue currently I am setting RUSTFLAGS="-C relocation-model=dynamic-no-pic -C linker=./linker" where linker is bash script that wraps cc and filter -pie flags:

 #!/bin/bash 

filtered_args=""

for arg; do

    if [ "$arg" != "-pie" ]
    then
        filtered_args="$filtered_args $arg"

    fi

done

command="cc $filtered_args"

echo " $command" > /tmp/linker

eval "$command"

I'm also having this problem. I assumed that passing -C relocation-model=static when doing a --crate-type=bin build would suppress -pie on the linker command line.

(cc: @alexcrichton)

I'm still seeing this issue. Not sure if it's a regression or I'm doing something wrong. I have a "hello world" program in main.rs, and when I run strace -s 300 -e execve -f rustc main.rs -C relocation-model=dynamic-no-pic, the resulting call to ld includes -pie.

I'm using nightly rust on Ubuntu: rustc 1.19.0-nightly (386b0b9d3 2017-05-14).

I'm using nightly rust on Ubuntu

So, the problem here isn't with rust, but with the linker. In Ubuntu 15.10 and later the default GCC toolchain installed has been compiled with --enable-default-pie which causes -fPIE and -fpie to be passed to cc during code generation and -pie to ld during linking. Now, the linking part is what is important here as rust on most platforms uses cc as the linker for most targets. So, though no PIC or PIE code may have been generated by rustc, the linker will still try to link as with PIE in mind, breaking when trying to compile with -static and the like. To work around this rustc will need to see that the linker has been compiled with PIE as the default and pass -no-pie to the linker if using GCC or something similar for other linkers. Code to do this can be seen in this PR for Tarpaulin though it is only meant for Linux in that state and can be improved greatly if in tree.

EDIT: Don't know why Github isn't linking cross-project PRs correctly right now.

Can this issue be resolved by always passing -no-pie, except when compiling with pic?

Can this issue be resolved by always passing -no-pie, except when compiling with pic?

Sadly, no. In testing I have seen that any build of GCC that was not built with --enable-default-pie rejects the option and fails to run. This is why in the PR that I linked the linker was queried to see if it was compiled with --enable-default-pie before tacking on -no-pie.

So it's came out from the discussion on an issue related to this in tarpaulin that passing -no-pie before -shared (and maybe then -static if it exists for static linkages as well) resolves the issue. I'm going to test this tarpaulin side and I can report back but I feel it would be best if this could be solved rustc side as it can affect any user in a similar situation.

Was this page helpful?
0 / 5 - 0 ratings