将 Rust staticlib 与 C 链接后出现分段错误

Segmentation fault after linking Rust staticlib with C

我正在尝试 link 静态地针对用 Rust 编写的库:

#![crate_type = "staticlib"]

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

在 C 中使用以下代码:

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

使用 rustc 编译 lib:

rustc foo.rs

用库编译二进制文件和link:

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

运行 内部调试器:

(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)

它与 dylib 完全兼容。我做错了什么?

这里的问题是具有析构函数的线程局部变量只能用于位置无关的可执行文件(由于 a bug)。修复:将 -pie 标志传递给 gcc,或者等待一两天。

这是由标准库中的std::io::stdio::_print and std::io::stdio::LOCAL_STDOUT引起的:

/// 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);
    }
}

LOCAL_STDOUT 中的 Box 在这种情况下具有析构函数,因此当线程局部变量被触及时可执行文件崩溃。我已经提交了 #24445, and Alex Crichton has diagnosed and fixed the underlying cause

打印不需要初始化线程或任何东西;如果 LOCAL_STDOUT 包含 None(这是默认设置),则可以回退到 stdout()。只需传递 -pie 就足以说服可执行文件打印 bork! 而不是崩溃。