5

I'm trying to link statically against library written in Rust:

#![crate_type = "staticlib"]

#[no_mangle]
pub extern "C" fn foo() {
    println!("bork!");
}

Using following code in C:

void foo();
int main()
{
    foo();
    return 0;
}

Compile lib with rustc:

rustc foo.rs

Compile binary and link with library:

gcc -g bar.c libfoo.a -ldl -lpthread -lrt -lgcc_s -lpthread -lc -lm -o bar

Run inside debugger:

(gdb) run
Starting program: /home/kykc/rusttest/bar 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff72117df in __cxa_thread_atexit_impl (func=<optimized out>, obj=<optimized out>, dso_symbol=0x0) at cxa_thread_atexit_impl.c:67
67  cxa_thread_atexit_impl.c: No such file or directory.

gcc:

gcc-4.8.real (Ubuntu 4.8.2-19ubuntu1) 4.8.2

rustc:

rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)

It works completely fine with dylib. What am I doing wrong?

2
  • Try turning optimizations off Commented Apr 14, 2015 at 17:17
  • rustc -g -C opt_level=0 foo.rs gcc -O0 -g bar.c libfoo.a -ldl -lpthread -lrt -lgcc_s -lpthread -lc -lm -o bar produces same result Commented Apr 14, 2015 at 22:13

1 Answer 1

4

The problem here is that thread-locals with destructors can only be used in position-independent executables (due to a bug) . Fix: pass the -pie flag to gcc, or wait a day or two.

This is caused by std::io::stdio::_print and std::io::stdio::LOCAL_STDOUT in the standard library:

/// Stdout used by print! and println! macros
thread_local! {
    static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = {
        RefCell::new(None)
    }
}

// ...

pub fn _print(args: fmt::Arguments) {
    let result = LOCAL_STDOUT.with(|s| {
        if s.borrow_state() == BorrowState::Unused {
            if let Some(w) = s.borrow_mut().as_mut() {
                return w.write_fmt(args);
            }
        }
        stdout().write_fmt(args)
    });
    if let Err(e) = result {
        panic!("failed printing to stdout: {}", e);
    }
}

The Box in LOCAL_STDOUT has the destructor in that case, so the executable crashes when the thread-local variable is touched. I've filed #24445, and Alex Crichton has diagnosed and fixed the underlying cause already.

Printing doesn't require initialising the threads or anything; there's fallback to stdout() in the case that LOCAL_STDOUT contains None (which is the default). Just passing -pie is enough to convince the executable to print bork! instead of crashing.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.