Rust和C将问题与最小程序和no_std

时间:2016-06-20 18:15:00

标签: c linker rust

我试图在C中使用GCC 6.1.0和#![no_std]在C中构建一个调用Rust函数的最小程序,最好用rustc 1.11.0-nightly (bb4a79b08 2016-06-15) x86_64-pc-windows-gnu编译。这是我先试过的:

的main.c

#include <stdio.h>

int sum(int, int);

int main()
{
    printf("Sum is %d.\n", sum(2, 3));
    return 0;
}

sum.rs

#![no_std]
#![feature(libc)]
extern crate libc;

#[no_mangle]
pub extern "C" fn sum(x: libc::c_int, y: libc::c_int) -> libc::c_int
{
    x + y
}

然后我试着跑:

rustc --crate-type=staticlib --emit=obj sum.rs

但得到了:

error: language item required, but not found: `panic_fmt`
error: language item required, but not found: `eh_personality`
error: language item required, but not found: `eh_unwind_resume`
error: aborting due to 3 previous errors

好的,所以其中一些错误与恐慌解除有关。我发现了一个Rust编译器设置来删除展开支持-C panic=abort。使用它,eh_personalityeh_unwind_resume的错误消失了,但Rust仍然需要panic_fmt函数。所以我在the Rust docs找到了它的签名,然后我将其添加到文件中:

sum.rs

#![no_std]
#![feature(lang_items, libc)]
extern crate libc;

#[lang = "panic_fmt"]
pub fn panic_fmt(_fmt: core::fmt::Arguments, _file_line: &(&'static str, u32)) -> !
    { loop { } }

#[no_mangle]
pub extern "C" fn sum(x: libc::c_int, y: libc::c_int) -> libc::c_int
{
    x + y
}

然后,我尝试再次构建整个程序:

rustc --crate-type=staticlib --emit=obj -C panic=abort sum.rs
gcc -c main.c
gcc sum.o main.o -o program.exe

但得到了:

sum.o:(.text+0x3e): undefined reference to `core::panicking::panic::h907815f47e914305'
collect2.exe: error: ld returned 1 exit status

恐慌功能参考可能来自sum()处的添加中的溢出检查。这一切都很好,也很可取。根据{{​​3}},我需要定义自己的恐慌函数来使用libcore。但我找不到如何操作的说明:我应该提供定义的函数在文档中称为panic_impl,但是链接器抱怨panic::h907815f47e914305,无论如何那应该是。

使用objdump,我找到了缺少的函数的名称,并将其攻击到C:

的main.c

#include <stdio.h>
#include <stdlib.h>

int sum(int, int);

void _ZN4core9panicking5panic17h907815f47e914305E()
{
    printf("Panic!\n");
    abort();
}

int main()
{
    printf("Sum is %d.\n", sum(2, 3));
    return 0;
}

现在,整个程序成功编译和链接,甚至可以正常工作。

如果我在Rust中尝试使用数组,则会生成另一种恐慌函数(用于边界检查),所以我也需要为它提供一个定义。每当我在Rust中尝试更复杂的东西时,就会出现新的错误。顺便说一下,panic_fmt似乎永远不会被召唤,即使恐慌确实发生了。

无论如何,这一切似乎都非常不可靠,并且与我在此事上可以通过谷歌找到的所有信息相矛盾。有this page,但我试图按照说明无效。

这似乎是一件非常简单和基本的事情,但我无法让它以正确的方式运作。也许它是一个Rust夜间的虫子?但我需要libclang_items。如何在不展开或恐慌支持的情况下生成Rust对象文件/静态库?它可能只是在它想要恐慌时执行非法处理器指令,或者调用我可以在C中安全定义的恐慌函数。

3 个答案:

答案 0 :(得分:6)

你不应该使用--emit=obj;只有rustc --crate-type=staticlib -C panic=abort sum.rs才能做正确的事。 (这修复了_ZN4core9panicking5panic17h907815f47e914305E链接错误。)

要解决另一个链接错误,您需要正确编写panic_fmt(注意使用extern):

#[lang="panic_fmt"]
extern fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32) -> ! {
    loop {}
}

通过这些改变,一切似乎都按照预期的方式发挥作用。

你需要panic_fmt所以你可以决定在发生恐慌时要做什么:如果你使用#![no_std],rustc假设没有标准的库/ libc /内核,所以它不能只调用abort()或者期望非法指令做任何有用的事情。它应该以某种方式暴露在稳定的Rust中,但我不知道是否有人正在努力稳定它。

您无需使用#![feature(libc)]来获取libc;您应该使用crates.io上发布的版本(或者您可以手动声明所需的功能)。

答案 1 :(得分:3)

因此,从接受的答案中得出的解决方案是:

<强>的main.c

#include <stdio.h>
#include <stdlib.h>

int sum(int, int);

void panic(const char* filename_unterminated, int filename_size, int line_num)
{
    printf("Panic! At line %d, file ", line_num);

    for (int i = 0; i < filename_size; i++)
        printf("%c", filename_unterminated[i]);

    abort();
}

int main()
{
    // Sum as u8 will overflow to test panicking.
    printf("Sum is %d.\n", sum(0xff, 3));
    return 0;
}

<强> sum.rs

#![no_std]
#![feature(lang_items, libc)]
extern crate libc;

extern "C"
{
    fn panic(
        filename_unterminated: *const libc::c_char,
        filename_size: libc::c_int,
        line_num: libc::c_int) -> !;
}

#[lang="panic_fmt"]
extern fn panic_fmt(_: ::core::fmt::Arguments, filename: &'static str, line_num: u32) -> !
{
    unsafe { panic(filename.as_ptr() as _, filename.len() as _, line_num as _); }
}

#[no_mangle]
pub extern "C" fn sum(x: libc::c_int, y: libc::c_int) -> libc::c_int
{
    // Convert to u8 to test overflow panicking.
    ((x as u8) + (y as u8)) as _
}

编译:

rustc --crate-type=staticlib -C panic=abort sum.rs
gcc -c main.c
gcc main.o -L . -l sum -o program.exe

现在一切正常,我在C中有一个恐慌处理程序,显示错误发生的位置!

答案 2 :(得分:0)

rustc --crate-type=staticlib -C panic=abort src/sum.rs
error[E0658]: language items are subject to change
  --> src/sum.rs:13:1
   |
13 | #[lang="panic_fmt"]
   | ^^^^^^^^^^^^^^^^^^^

error[E0522]: definition of an unknown language item: `panic_fmt`
  --> src/sum.rs:13:1
   |
13 | #[lang="panic_fmt"]
   | ^^^^^^^^^^^^^^^^^^^ definition of unknown language item `panic_fmt`

error: `#[panic_handler]` function required, but not found

这是为了 HLorenzi 反馈,您的代码不起作用,但我无法向您发送评论