Skip to content
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

#![no_std] results in linker errors for debug builds that use Drop due to _rust_eh_personality #47442

Closed
mjbshaw opened this issue Jan 15, 2018 · 10 comments
Labels
C-bug Category: This is a bug.

Comments

@mjbshaw
Copy link
Contributor

mjbshaw commented Jan 15, 2018

The following simple program fails to compile with Rust because the Drop trait introduces an incompatibility that causes a linker error. If you comment out the impl block, then it will work just fine. Additionally, if you compile with optimizations turned on, it will work just fine. But if you compile the following without optimizations, it will fail.

t.rs:

#![feature(lang_items, start)]
#![no_std]

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

struct Foo {}

impl core::ops::Drop for Foo {
    fn drop(&mut self) {
    }
}

#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
    let _foo = Foo {};
    return 0;
}

The error: (part of the paths have been redacted; <RUSTUP> is the installation directory for rustup)

$ rustc t.rs -l c
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-m64" "-L" "<RUSTUP>/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "t.t0.rcgu.o" "t.t1.rcgu.o" "-o" "t" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "<RUSTUP>/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "-l" "c" "<RUSTUP>/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-6ee4b7a50e610a70.rlib"
  = note: Undefined symbols for architecture x86_64:
            "_rust_eh_personality", referenced from:
                Dwarf Exception Unwind Info (__eh_frame) in t.t0.rcgu.o
          ld: symbol(s) not found for architecture x86_64
          clang: error: linker command failed with exit code 1 (use -v to see invocation)


error: aborting due to previous error

Rust version:

$ rustc --version
rustc 1.25.0-nightly (3f92e8d89 2018-01-14)

Note: Building with optimizations on works, presumably because the optimizer is able to optimize away the call to core::ptr::drop_in_place (which is tagged with .cfi_personality 155, _rust_eh_personality in the generated debug assembly, which I presume is the source of the problem):

$ rustc t.rs -O -l c
$ ./t

My system: macOS 10.13.2. rustc is installed from rustup.

@mjbshaw
Copy link
Contributor Author

mjbshaw commented Jan 15, 2018

It looks like this was introduced between 2017-12-02 (f9b0897) and 2017-12-03 (1956d55):

$ rustup default nightly-2017-12-03
info: using existing install for 'nightly-2017-12-03-x86_64-apple-darwin'
info: default toolchain set to 'nightly-2017-12-03-x86_64-apple-darwin'

  nightly-2017-12-03-x86_64-apple-darwin unchanged - rustc 1.24.0-nightly (f9b0897c5 2017-12-02)

$ rustc t.rs -l c
$ ./t
$ rustup default nightly-2017-12-04
info: using existing install for 'nightly-2017-12-04-x86_64-apple-darwin'
info: default toolchain set to 'nightly-2017-12-04-x86_64-apple-darwin'

  nightly-2017-12-04-x86_64-apple-darwin unchanged - rustc 1.24.0-nightly (1956d5535 2017-12-03)

$ rustc t.rs -l c
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-m64" "-L" "<RUSTUP>/toolchains/nightly-2017-12-04-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "t.t0.rcgu.o" "t.t1.rcgu.o" "-o" "t" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "<RUSTUP>/toolchains/nightly-2017-12-04-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "-l" "c" "<RUSTUP>/toolchains/nightly-2017-12-04-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-23bf36c939af2dde.rlib"
  = note: Undefined symbols for architecture x86_64:
            "_rust_eh_personality", referenced from:
                Dwarf Exception Unwind Info (__eh_frame) in t.t1.rcgu.o
          ld: symbol(s) not found for architecture x86_64
          clang: error: linker command failed with exit code 1 (use -v to see invocation)


error: aborting due to previous error

@mjbshaw
Copy link
Contributor Author

mjbshaw commented Jan 15, 2018

git bisect shows that this bug was introduced in commit 9dc3967:

9dc396747b31a7c3918d44bd30be115360712f9f is the first bad commit
commit 9dc396747b31a7c3918d44bd30be115360712f9f
Author: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date:   Tue Nov 28 01:45:16 2017 +0200

    funnel all unwind paths through a single Resume block

    This simplifies analysis and borrow-checking because liveness at the
    resume point can always be simply propagated.

    Later on, the "dead" Resumes are removed.

:040000 040000 6d09d3a9b31b20377395eaee88ec98fb0c55b604 b2a7650815c8a9b4dc844778da015e3f71a059a0 M	src

cc @arielb1

Unfortunately I don't know how to fix this. I'm not familiar enough with the compiler internals to be of much help other than this initial triage.

@arielb1 arielb1 added the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Jan 15, 2018
@arielb1
Copy link
Contributor

arielb1 commented Jan 15, 2018

I don't think this way of avoiding linking against the exception handling code is officially supported (compiler_rt does something like this, but compiler_rt is magic).

Nevertheless, we only emit resume in this path due to an oversight which I'll fix.

@arielb1
Copy link
Contributor

arielb1 commented Jan 15, 2018

For example, if a tuple is used like in this code, then a landing pad is created in all modern versions of rustc - that is needed to handle the case where drop panics (rustc does not do cross-function noexcept propagation).

#![feature(lang_items, start)]
#![no_std]

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

struct Foo {}

impl core::ops::Drop for Foo {
    fn drop(&mut self) {
    }
}

#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
    let _foo = (Foo {}, Foo {}); // note change here
    return 0;
}

@hanna-kruppe
Copy link
Contributor

I don't think this way of avoiding linking against the exception handling code is officially supported

Compiling everything (including libcore) with panic=abort should be reliable, right?

@arielb1 arielb1 removed the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Jan 15, 2018
@arielb1
Copy link
Contributor

arielb1 commented Jan 15, 2018

@rkruppe

Sure that should work. Even just compiling the problem .rs file with -C panic=abort should make things work in a supported way.

I just remembered the tiptoing around exceptions in the context of compiler-rt which does not want panic=abort (note: compiler-rt is magic. do not attempt to emulate it).

@arielb1
Copy link
Contributor

arielb1 commented Jan 15, 2018

@mjbshaw

So, as @rkruppe said, you want to add -C panic=abort to your rustc flags. That should have the same level of "official support" as all nightly features.

This should work:

$ rustc t.rs -l c -C panic=abort

arielb1 added a commit to arielb1/rust that referenced this issue Jan 15, 2018
These are already removed in the normal optimization pipeline - so this
should slightly improve codegen performance, as these cleanup blocks are
known to hurt LLVM.

This un-regresses and is therefore a fix for rust-lang#47442. However, the
reporter of that issue should try using `-C panic=abort` instead of
carefully avoiding panics.
@hanna-kruppe
Copy link
Contributor

@mjbshaw Note that if you do that, you need to use Xargo to recompile libcore with panic=abort as well. Otherwise, parts of libcore will have unwinding code that will lead to the same linking error if you pull them in (not in your simple example above, but likely in bigger programs).

@mjbshaw
Copy link
Contributor Author

mjbshaw commented Jan 16, 2018

Thanks for looking into this so quickly! Using -C panic=abort indeed works and it's compatible with my needs; thanks for the tip.

kennytm added a commit to kennytm/rust that referenced this issue Jan 17, 2018
remove noop landing pads in cleanup shims

No-op landing pads are already removed in the normal optimization pipeline - so also removing them on the shim pipeline should slightly improve codegen performance, as these cleanup blocks are known to hurt LLVM.

This un-regresses and is therefore a fix for rust-lang#47442. However, the reporter of that issue should try using `-C panic=abort` instead of carefully avoiding panics.

r? @eddyb
kennytm added a commit to kennytm/rust that referenced this issue Jan 17, 2018
remove noop landing pads in cleanup shims

No-op landing pads are already removed in the normal optimization pipeline - so also removing them on the shim pipeline should slightly improve codegen performance, as these cleanup blocks are known to hurt LLVM.

This un-regresses and is therefore a fix for rust-lang#47442. However, the reporter of that issue should try using `-C panic=abort` instead of carefully avoiding panics.

r? @eddyb
@pietroalbini pietroalbini added the C-bug Category: This is a bug. label Jan 23, 2018
@mjbshaw
Copy link
Contributor Author

mjbshaw commented Jan 13, 2019

This is no longer an issue.

@mjbshaw mjbshaw closed this as completed Jan 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants