我试图在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_personality
和eh_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夜间的虫子?但我需要libc
和lang_items
。如何在不展开或恐慌支持的情况下生成Rust对象文件/静态库?它可能只是在它想要恐慌时执行非法处理器指令,或者调用我可以在C中安全定义的恐慌函数。
答案 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 反馈,您的代码不起作用,但我无法向您发送评论