ABI - Use Rust code from C

Page content

I just followed “The Rust Reference: 17. Application Binary Interface (ABI)” and “The Embedded Rust Book: 10.2 A little Rust with your C

After then, I tried to expose Rust program to C as ABI.

Test the code in the first reference

foo.rs:

// This is kept because of `#[used]`:
#[used]
static FOO: u32 = 123;

// This is removable because it is unused:
#[allow(dead_code)]
static BAR: u32 = 0;

// This is kept because it is publicly reachable:
pub static BAZ: u32 = 0;

// This is kept because it is referenced by a public, reachable function:
static QUUX: u32 = 0;

pub fn quux() -> &'static u32 {
    &QUUX
}

// This is removable because it is referenced by a private, unused (dead) function:
static CORGE: u32 = 0;

#[allow(dead_code)]
fn corge() -> &'static u32 {
    &CORGE
}

used attribute

The attribute can only be applied to static item. This attribute tells compiler to keep this variable, even the variable isn’t used and is room for optimization in case of shared object output.

no_mangle attribute

Name mangling is also calledd name decoration (by Wikipedia). Name mangling append the variable/function name in the output. The Rust compiler mangles symbol names differently than native code linkers expect, and this is why we need no_mangle.

The attribute specifies the section of the object file that a function or static’s content will be placed into.

#[no_mangle]
#[link_section = ".example_section"]
pub static VAR1: u32 = 1;

export_name attribute

This attribute specifies the name of the symbol that will be exported on a function or static.

#[export_name = "exported_symbol_name"]
pub fn name_in_rust() { }

First, just follow Official document

$ rustc -O --emit=obj --crate-type=rlib foo.rs

$ nm -C foo.o
0000000000000000 R foo::BAZ
0000000000000000 r foo::FOO
0000000000000000 R foo::QUUX
0000000000000000 T foo::quux

Another file type: staticlib

Tried with another --crate-type:

rustc -O --emit=obj --crate-type=staticlib foo.rs

The result:

➜ nm -C foo.o 
0000000000000000 r foo::FOO

➜ objdump -D -C --demangle foo.o 

foo.o:     file format elf64-x86-64


Disassembly of section .rodata._ZN3foo3FOO17hbcfcd8524a307ff1E:

0000000000000000 <foo::FOO>:
   0:	7b 00                	jnp    2 <foo::FOO+0x2>
	...

Hex 7b is 123.

Export Rust function to C

Now, I tried the second reference.

https://docs.rust-embedded.org/book/interoperability/rust-with-c.html

AS of Jan. 2022, C++ has no stable ABI for the Rust compiler to target, so we try C.

lib.rs:

static FOO: usize = 123;

#[no_mangle]
#[export_name = "mylib"]
pub extern "C" fn rust_adder(a: &usize, b: &usize) -> usize {
    *a + *b + FOO
}

test.c:

#include <stdio.h>

int mylib(int *a, int *b);

int main() {
  int i = 1000;
  int j = 10000;
  int result = mylib(&i, &j);
  printf("Result: %d", result);
}

Compile, link, and execute!!:

rustc -O --emit=obj --crate-type=staticlib lib.rs
gcc -o rust_with_c test.c lib.o
./rust_with_c
Result: 11123