【问题标题】:Rust and C linking problems with minimal program and no_stdRust 和 C 链接问题与最小程序和 no_std
【发布时间】:2016-06-20 18:15:00
【问题描述】:

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

ma​​in.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

panic 函数引用可能来自sum() 中添加的溢出检查。这一切都很好,也很可取。根据this page,我需要定义自己的恐慌函数来使用libcore。但是我找不到有关如何执行此操作的说明:我应该为其提供定义的函数在文档中称为panic_impl,但是链接器抱怨panic::h907815f47e914305,无论它应该是什么。

使用objdump,我能够找到丢失的函数的名称,并将其破解到 C:

ma​​in.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 似乎永远不会被调用,即使确实发生了恐慌。

无论如何,这一切似乎都非常不可靠,并且与我可以通过 Google 找到的关于此事的所有信息相矛盾。有this,但我尝试按照说明操作无济于事。

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

【问题讨论】:

  • 请不要编辑您的问题以包含答案。 Stack Overflow 明确鼓励您在下面添加自己的答案。

标签: c linker rust


【解决方案1】:

你不应该使用--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/kernel,因此它不能只调用 abort() 或期望做任何有用的事情的非法指令。它应该以某种方式暴露在稳定的 Rust 中,但我不知道是否有人正在努力稳定它。

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

【讨论】:

  • 错误[E0433]:无法解决:可能是缺少板条箱core? --> lib.rs:13:26 | 13 | extern fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32) -> ! | ^^^^ 可能是丢失的箱子core? [...] 一些错误有详细解释:E0433、E0522、E0658。
【解决方案2】:

因此,从接受的答案来看,解决方案是:

ma​​in.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 语言中有一个恐慌处理程序,可以显示错误发生的位置!

【讨论】:

    【解决方案3】:
    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 反馈的,你的代码不起作用,但我不能给你发评论

    【讨论】:

      猜你喜欢
      • 2021-03-17
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多