I'm trying to build a minimal program in C that calls Rust functions, preferably compiled with #![no_std]
, in Windows, using GCC 6.1.0 and rustc 1.11.0-nightly (bb4a79b08 2016-06-15) x86_64-pc-windows-gnu
. Here's what I tried first:
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
}
Then I tried running:
rustc --crate-type=staticlib --emit=obj sum.rs
But got:
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
OK, so some of those errors are related to panic unwinding. I found out about a Rust compiler setting to remove unwinding support, -C panic=abort
. Using that, the errors about eh_personality
and eh_unwind_resume
disappeared, but Rust still required the panic_fmt
function. So I found its signature at the Rust docs, then I added that to the file:
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
}
Then, I tried building the whole program again:
rustc --crate-type=staticlib --emit=obj -C panic=abort sum.rs
gcc -c main.c
gcc sum.o main.o -o program.exe
But got:
sum.o:(.text+0x3e): undefined reference to `core::panicking::panic::h907815f47e914305'
collect2.exe: error: ld returned 1 exit status
The panic function reference is probably from a overflow check in the addition at sum()
. That's all fine and desirable. According to this page, I need to define my own panic function to work with libcore. But I can't find instructions on how to do so: the function for which I am supposed to provide a definition is called panic_impl
in the docs, however the linker is complaining about panic::h907815f47e914305
, whatever that's supposed to be.
Using objdump
, I was able to find the missing function's name, and hacked that into 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;
}
Now, the whole program compiles and links successfully, and even works correctly.
If I then try using arrays in Rust, another kind of panic function (for bounds checks) is generated, so I need to provide a definition for that too. Whenever I try something more complex in Rust, new errors arise. And, by the way, panic_fmt
seems to never be called, even when a panic does happen.
Anyways, this all seems very unreliable, and contradicts every information I could find via Google on the matter. There's this, but I tried to follow the instructions to no avail.
It seems such a simple and fundamental thing, but I can't get it to work the right way. Perhaps it's a Rust nightly bug? But I need libc
and lang_items
. How can I generate a Rust object file/static library without unwinding or panic support? It should probably just execute an illegal processor instruction when it wants to panic, or call a panic function I can safely define in C.
You shouldn't use --emit=obj
; just rustc --crate-type=staticlib -C panic=abort sum.rs
should do the right thing. (This fixes the _ZN4core9panicking5panic17h907815f47e914305E link error.)
To fix another link error, you need to write panic_fmt correctly (note the use of extern
):
#[lang="panic_fmt"]
extern fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32) -> ! {
loop {}
}
With those changes, everything appears to work the way it's supposed to.
You need panic_fmt so you can decide what to do when a panic happens: if you use #![no_std]
, rustc assumes there is no standard library/libc/kernel, so it can't just call abort() or expect an illegal instruction to do anything useful. It's something which should be exposed in stable Rust somehow, but I don't know if anyone is working on stabilizing it.
You don't need to use #![feature(libc)]
to get libc; you should use the version posted on crates.io instead (or you can declare the functions you need by hand).
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments