Rust and C linking problems with minimal program and no_std

HLorenzi

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.

Eli Friedman

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.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Rust minimal compiled program size

From Dev

Rust minimal compiled program size

From Dev

Rust cdylib crate, linking dll to C program in Windows

From Dev

Linking SDL in a C program

From Dev

Linking a C++ program with SpiderMonkey?

From Dev

Undefined reference to "main" in minimal C program

From Dev

Linking Rust with C: undefined reference to '__aeabi' functions

From Dev

Segmentation fault after linking Rust staticlib with C

From Dev

Problems when linking a PETSc program when using CMake

From Dev

Problems with Linking my Project C++

From Dev

Problems Linking Matlab generated C++ Library

From Dev

Linking C program to C++ Shared Library

From Dev

c++ linking error in example program

From Dev

Error linking fortran subroutine into c++ program

From Dev

linking, compiling and running a c program with a static library

From Dev

Embedding Rust tasks in a C program?

From Dev

Calling a C# DLL from C; linking problems

From Dev

How do the inner workings of the Rust link attribute compare to linking in C?

From Dev

Linking C compiled static library to C++ Program

From Dev

Linking curl library problems

From Dev

Linking problems with jsoncpp

From Dev

glew problems (linking, crashing)

From Dev

OpenGL Linking problems

From Dev

Problems with linking static libraries

From Dev

Problems with linking GSL / CBLAS

From Dev

some SDL linking problems

From Dev

Linking Problems with css and html

From Dev

Intel Compilers: linking a fortran compiled library to main program of C

From Dev

Intel Compilers: linking a fortran compiled library to main program of C