Bare-metal Rust linking with C static library

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Bare-metal Rust linking with C static library

Eric Stutzenberger
I'm working on building out a Rust interface to the nRF51x series parts.  I have a bare metal system working quite well.  The nRF51x has a bluetooth stack (called Softdevice).  This stack requires the use of supervisor calls to request the stack to perform certain functions.  My plan is to write a C library wrapper around these service calls, compile with arm-none-wabi-gcc and then link this to my Bare-metal rust system.  A large chunk of the work I have done thus far is based off of STM32 example work done by Jorge Aparicio (https://github.com/japaric).

Since I have the basics up and running, I am working on trying to get a C static library built with arm-none-eabi-gcc and archived with arm-none-eabi-ar to properly link in with my Rust code.

I have the following (very basic) .c file:
uint32_t sum(uint32_t a, uint32_t b)
{
return a + b;
}

I am compiling and linking with the following commands:

arm-none-eabi-gcc -Wall -mcpu=cortex-m0 -mthumb -fPIC --specs=nosys.specs -shared test.c -o test.o

arm-none-eabi-ar -rs libtest.a test.o


In my rust file:

[link(name="test", kind="static")]

extern {

pub fn sum(a: u32, b: u32) -> u32;

}


I then invoke it as a test:

pub fn main() {

        let test_sum = unsafe { sum(2, 3) };

}


I am using a Makefile to execute the rust compiler for some specific arguments, such as my specific target:

# rustc target

TARGET = thumbv6m-none-eabi


# toolchain prefix

TRIPLE = arm-none-eabi


APP_DIR = src/app

OUT_DIR = target/$(TARGET)/release


DEPS_DIR = $(OUT_DIR)/deps


BINS = $(OUT_DIR)/%.hex

HEXS = $(OUT_DIR)/%.hex

ELFS = $(OUT_DIR)/%.elf

OBJECTS = $(OUT_DIR)/intermediate/%.o

SOURCES = $(APP_DIR)/%.rs


APPS = $(patsubst $(SOURCES),$(BINS),$(wildcard $(APP_DIR)/*.rs))


RUSTC_FLAGS := -C lto -g $(RUSTC_FLAGS)


# don't delete my elf files!

.SECONDARY:


all: rlibs  $(APPS)


clean:

cargo clean


# TODO $(APPS) should get recompiled when the `rlibs` change


$(OBJECTS): $(SOURCES)

mkdir -p $(dir $@)

rustc \

$(RUSTC_FLAGS) \

--crate-type staticlib \

--emit obj \

--target $(TARGET) \

-L $(DEPS_DIR) \

-L ../sd110_lib \

--verbose \

-o $@ \

-ltest \

$<


$(ELFS): $(OBJECTS)

$(TRIPLE)-ld \

--gc-sections \

-T layout.ld \

-o $@ \

$<

#size $@


$(BINS): $(ELFS)

$(TRIPLE)-objcopy \

-O ihex \

$< \

$@


rlibs:

cargo build --target $(TARGET) --verbose --release


The cargo.toml is as follows:

[package]

name = "bmd200eval"

version = "0.1.0"

authors = ["Eric Stutzenberger <[hidden email]>"]


[dependencies.nrf51822]

path = "../nrf51822.rs"


When I run make, I get the following output:

.

.

.

mkdir -p target/thumbv6m-none-eabi/release/intermediate/

rustc \

-C lto -g  \

--crate-type staticlib \

--emit obj \

--target thumbv6m-none-eabi \

-L target/thumbv6m-none-eabi/release/deps \

-L ../sd110_lib \

--verbose \

-o target/thumbv6m-none-eabi/release/intermediate/blink.o \

-ltest \

src/app/blink.rs

src/app/blink.rs:42:9: 42:17 warning: unused variable: `test_sum`, #[warn(unused_variables)] on by default

src/app/blink.rs:42     let test_sum = unsafe { sum(2, 3) };

                            ^~~~~~~~

arm-none-eabi-ld \

--gc-sections \

-T layout.ld \

-o target/thumbv6m-none-eabi/release/blink.elf \

target/thumbv6m-none-eabi/release/intermediate/blink.o

target/thumbv6m-none-eabi/release/intermediate/blink.o: In function `blink::main':

git/rust-nrf/bmd200eval.rs/src/app/blink.rs:42: undefined reference to `sum' 


I have found numerous different references to linking Rust with C and calling C from Rust but I haven't found a specific answer as to why this will not link.  As you can see in the Makefile, I have tried to force rustc's hand in finding and linking against the library, but this doesn't seem to make a difference.


Is there an issue with how I am building a library?

Since rustc is generating a staticlib in this case, is there some different method that needs to be used?


Note that I am avoiding the Clang compiler for the moment due to the following:

https://devzone.nordicsemi.com/question/29628/using-clang-and-the-s110-issues-with-supervisor-calls-to-the-softdevice/


Essentially, the gist of the above is that Clang is not quite producing the correct supervisor assembly code for calling in to the bluetooth stack, especially when optimizations are enabled.


Cheers,

Eric


_______________________________________________
Rust-dev mailing list
[hidden email]
https://mail.mozilla.org/listinfo/rust-dev
Reply | Threaded
Open this post in threaded view
|

Re: Bare-metal Rust linking with C static library

Matthieu Monrocq
Hello Eric,

Please note that the rust-dev list is (for better or worse) abandonned.

You may ask questions on either IRC (https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust), the users forum (https://users.rust-lang.org/) or StackOverflow.

You may also ask on Reddit (https://reddit.com/r/rust), however it's more used for announcements than questions in general.

Note that all the community links I gave are accessible directly from http://www.rust-lang.org/

Good luck with your project!


On Sat, May 30, 2015 at 8:49 PM, Eric Stutzenberger <[hidden email]> wrote:
I'm working on building out a Rust interface to the nRF51x series parts.  I have a bare metal system working quite well.  The nRF51x has a bluetooth stack (called Softdevice).  This stack requires the use of supervisor calls to request the stack to perform certain functions.  My plan is to write a C library wrapper around these service calls, compile with arm-none-wabi-gcc and then link this to my Bare-metal rust system.  A large chunk of the work I have done thus far is based off of STM32 example work done by Jorge Aparicio (https://github.com/japaric).

Since I have the basics up and running, I am working on trying to get a C static library built with arm-none-eabi-gcc and archived with arm-none-eabi-ar to properly link in with my Rust code.

I have the following (very basic) .c file:
uint32_t sum(uint32_t a, uint32_t b)
{
return a + b;
}

I am compiling and linking with the following commands:

arm-none-eabi-gcc -Wall -mcpu=cortex-m0 -mthumb -fPIC --specs=nosys.specs -shared test.c -o test.o

arm-none-eabi-ar -rs libtest.a test.o


In my rust file:

[link(name="test", kind="static")]

extern {

pub fn sum(a: u32, b: u32) -> u32;

}


I then invoke it as a test:

pub fn main() {

        let test_sum = unsafe { sum(2, 3) };

}


I am using a Makefile to execute the rust compiler for some specific arguments, such as my specific target:

# rustc target

TARGET = thumbv6m-none-eabi


# toolchain prefix

TRIPLE = arm-none-eabi


APP_DIR = src/app

OUT_DIR = target/$(TARGET)/release


DEPS_DIR = $(OUT_DIR)/deps


BINS = $(OUT_DIR)/%.hex

HEXS = $(OUT_DIR)/%.hex

ELFS = $(OUT_DIR)/%.elf

OBJECTS = $(OUT_DIR)/intermediate/%.o

SOURCES = $(APP_DIR)/%.rs


APPS = $(patsubst $(SOURCES),$(BINS),$(wildcard $(APP_DIR)/*.rs))


RUSTC_FLAGS := -C lto -g $(RUSTC_FLAGS)


# don't delete my elf files!

.SECONDARY:


all: rlibs  $(APPS)


clean:

cargo clean


# TODO $(APPS) should get recompiled when the `rlibs` change


$(OBJECTS): $(SOURCES)

mkdir -p $(dir $@)

rustc \

$(RUSTC_FLAGS) \

--crate-type staticlib \

--emit obj \

--target $(TARGET) \

-L $(DEPS_DIR) \

-L ../sd110_lib \

--verbose \

-o $@ \

-ltest \

$<


$(ELFS): $(OBJECTS)

$(TRIPLE)-ld \

--gc-sections \

-T layout.ld \

-o $@ \

$<

#size $@


$(BINS): $(ELFS)

$(TRIPLE)-objcopy \

-O ihex \

$< \

$@


rlibs:

cargo build --target $(TARGET) --verbose --release


The cargo.toml is as follows:

[package]

name = "bmd200eval"

version = "0.1.0"

authors = ["Eric Stutzenberger <[hidden email]>"]


[dependencies.nrf51822]

path = "../nrf51822.rs"


When I run make, I get the following output:

.

.

.

mkdir -p target/thumbv6m-none-eabi/release/intermediate/

rustc \

-C lto -g  \

--crate-type staticlib \

--emit obj \

--target thumbv6m-none-eabi \

-L target/thumbv6m-none-eabi/release/deps \

-L ../sd110_lib \

--verbose \

-o target/thumbv6m-none-eabi/release/intermediate/blink.o \

-ltest \

src/app/blink.rs

src/app/blink.rs:42:9: 42:17 warning: unused variable: `test_sum`, #[warn(unused_variables)] on by default

src/app/blink.rs:42     let test_sum = unsafe { sum(2, 3) };

                            ^~~~~~~~

arm-none-eabi-ld \

--gc-sections \

-T layout.ld \

-o target/thumbv6m-none-eabi/release/blink.elf \

target/thumbv6m-none-eabi/release/intermediate/blink.o

target/thumbv6m-none-eabi/release/intermediate/blink.o: In function `blink::main':

git/rust-nrf/bmd200eval.rs/src/app/blink.rs:42: undefined reference to `sum' 


I have found numerous different references to linking Rust with C and calling C from Rust but I haven't found a specific answer as to why this will not link.  As you can see in the Makefile, I have tried to force rustc's hand in finding and linking against the library, but this doesn't seem to make a difference.


Is there an issue with how I am building a library?

Since rustc is generating a staticlib in this case, is there some different method that needs to be used?


Note that I am avoiding the Clang compiler for the moment due to the following:

https://devzone.nordicsemi.com/question/29628/using-clang-and-the-s110-issues-with-supervisor-calls-to-the-softdevice/


Essentially, the gist of the above is that Clang is not quite producing the correct supervisor assembly code for calling in to the bluetooth stack, especially when optimizations are enabled.


Cheers,

Eric


_______________________________________________
Rust-dev mailing list
[hidden email]
https://mail.mozilla.org/listinfo/rust-dev



_______________________________________________
Rust-dev mailing list
[hidden email]
https://mail.mozilla.org/listinfo/rust-dev