edef1c / libfringe

a Rust library implementing safe, lightweight context switches, without relying on kernel services
https://edef1c.github.io/libfringe
Apache License 2.0
512 stars 31 forks source link

fPIC troubles? relocation R_X86_64_PC32 against symbol #59

Closed MarkSwanson closed 8 years ago

MarkSwanson commented 8 years ago

Edit: a quicker/easier way to test is to paste this into libfringe/cargo.toml:

[lib]
name = "libfringe"
path = "src/lib.rs"
crate-type = ["dylib"]

Hello,

I'm unable to use libfringe with my DSO. Small test case pasted below.

  = note: /usr/bin/ld: /home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: relocation R_X86_64_PC32 against symbol `_ZN6fringe4arch3imp4swap10trampoline17h9a2ce236cc1b16f6E' can not be used when making a shared object; recompile with -fPIC

I maintain that my little test is compiled as PIC. Evidence: libfringefpic.0.o (pic) and also:

$ file libfringefpic.0.o 
/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: ELF 64-bit LSB  relocatable, x86-64, version 1 (SYSV), not stripped

I'm quite fascinated with libfringe. I hope it's possible to use with DSOs.

Any suggestions / help would be appreciated!

[dependencies.fringe] no-default-features = true git = "https://github.com/nathan7/libfringe.git"

[lib] name = "libfringefpic" path = "src/lib.rs" crate-type = ["dylib"]

- .cargo/config
```toml
[build]
# rustflags = ["-C", "prefer-dynamic", "-Z", "incremental=/tmp/rustc_incremental", "-Z", "incremental-info"]

rustflags = ["-C", "prefer-dynamic", "-C", "link-args=-fPIC"]
# rustflags = ["-C", "relocation-model=pic", "-C", "link-args=-fPIC"]
# :-)

use fringe::{OsStack, Generator};

pub fn x() { let stack = OsStack::new(1 << 16).unwrap(); let mut gen = Generator::new(stack, move |yielder, mut index| { let values = [1, 2, 3]; loop { index = yielder.suspend(values[index]) } });

println!("{:?}", gen.resume(5)); }

 Running `rustc src/lib.rs --crate-name libfringefpic --crate-type dylib -g -C metadata=63492654b52cf958 --out-dir /home/maswanso/src/external/rust/libfringefpic/target/debug/deps --emit=dep-info,link -L dependency=/home/maswanso/src/external/rust/libfringefpic/target/debug/deps --extern fringe=/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringe-88227e5bfb249863.rlib -C prefer-dynamic -C link-args=-fPIC`

error: linking with cc failed: exit code: 1 | = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o" "-o" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/liblibfringefpic.so" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.metadata.o" "-nodefaultlibs" "-L" "/home/maswanso/src/external/rust/libfringefpic/target/debug/deps" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/libfringe-88227e5bfb249863.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/libvalgrind_request-c9df0ba26d15ec95.rlib" "-Wl,--no-whole-archive" "-Wl,--whole-archive" "/tmp/rustc.5dtQdVsxlbYQ/liblibc-ad32fde1bd850538.rlib" "-Wl,--no-whole-archive" "-L" "/home/maswanso/.multirust/toolchains/nightly-2016-09-09-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-l" "std-411f48d3" "-l" "util" "-l" "dl" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-l" "util" "-shared" "-fPIC" "-l" "compiler-rt" = note: /usr/bin/ld: /home/maswanso/src/external/rust/libfringefpic/target/debug/deps/libfringefpic.0.o: relocation R_X86_64_PC32 against symbol `_ZN6fringe4arch3imp4swap10trampoline17h9a2ce236cc1b16f6E' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Bad value

MarkSwanson commented 8 years ago

Ok, I see that when creating a shared library the linker is smart enough to know that you can't use 32-bit relative offsets in a 64-bit system.

I tried to force R_X86_64_64 by using -C code-model=large. That didn't quite work.

rustflags = ["-C", "prefer-dynamic", "-C", "relocation-model=pic", "-C", "code-model=large", "-C", "link-args=-fPIC", "-C", "save-temps"]

I seem to be completely blocked.

Any suggestions / thoughts would be appreciated.

Thanks!

MarkSwanson commented 8 years ago

Ok, I simply upgraded to a newer nightly and the problem was resolved.

MarkSwanson commented 8 years ago

While the newer Rust compiler got me further when I circled back to my project it failed again. I've created a github repo that contains a tiny example on how to reproduce.

Please help me build a DSO that uses libfringe.

https://github.com/MarkSwanson/libfringetest

MarkSwanson commented 8 years ago

I submitted a pull request that works around the problem (with inline). The benchmarks seem to be exactly the same, so I don't think we've lost any performance.

Ericson2314 commented 8 years ago

You should probably file a bug with rustc, seeing that something seems to have broken on its end.

MarkSwanson commented 8 years ago

Done: https://github.com/rust-lang/rust/issues/37457

Amanieu commented 8 years ago

This can be fixed by appending @plt after the call instruction operand:

callq ${2:c}@plt
MarkSwanson commented 8 years ago

Amanieu - thank you. It seems you also are suggesting a change from "call" to "callq"?

Fyi I used callq ${2:c}@plt and put the #[inline(always)] back and:

I'll submit a new pull request shortly. Amanieu - do you have any words of wisdom that I could add to the pull request to convince Nathan that your change doesn't have any bad side effects? Thanks!

Amanieu commented 8 years ago

Actually that change is superseded by #62 which inlines the trampoline and eliminates the call entirely. I believe that approach is superior since it also improves performance.

Regarding the change to callq, that was unintentional. It actually does not make any difference since call and callq are identical in this case.