STD Support for Bare metal

Hi Team,

I was trying to compile a rust code for bare metal A32 and A64 toolchains which involves box pointers for accessing heap. But I saw that std support is not available for BareMetal. Can you please let me know why std support is missing for BareMetal targets in rust.

Thanks,
Santhosh

std is operating system dependent and bare metal targets are characterised by not having an operating system, so they can only support no_std. With no_std you instead have access to the core crate, which contains the operating system independent parts of std. If you can provide a memory allocator, then you can additionally use the alloc crate, which contains collections and things like Box that depend on memory allocation but not other parts of an operating system.

10 Likes

Hi Jameseb7,

Thanks for your reply.

I have few follow up questions to the above one. Rust provides memory safety features and Concurrency, using entities like box pointers, vectors, rc, thread, sync::mpsc, std::sync::Mutex (which are provided by std) if it is executed on an os like linux.

  1. If I have to leverage these memory safety and concurrency features of rust on baremetal environment like A32 and A64 is it possible to achieve it? as std support is missing for baremetal.
  2. If I want to call few rust functions from c code in BareMetal environment do I get rust memory safety and concurrency features.

Thanks,
Santhosh

If you declare a global allocator with #[global_allocator] you'll be able to use Box, Vec and Rc (from those on that list). In case you cannot declare a global allocator there are crates that are no_std compatible that provide containers with a fixed maximum size (e.g. arrayvec and heapless), so you can use them without losing Rust's memory safety guarantees.

Threads as a OS feature, so they won't be available. Mpsc and Mutex also depend on OS features so you won't be able to use them. In case you're using some library/framework that implements threads on top of the baremetal features you'll still be able to use the Send and Sync traits to make a safe interface for them.

As long as the C side respects the Rust invariants (e.g. no aliasing references, references are valid etc etc) then yes.

5 Likes

Hi SkiFire13,

Thanks for your reply. I was actually trying to implement your suggestion of using global_allocator for custom memory allocation on armv7 baremetal target. Below is my code.

Example code:

#![no_std]
#![feature(lang_items)]
use core::alloc::{GlobalAlloc, Layout};

use core::ptr;
extern crate alloc;

struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
unsafe fn alloc(&self,layout:Layout)-> *mut u8 { todo!() }
unsafe fn dealloc(&self, _: *mut u8, _: Layout) { todo!() }
}

#[global_allocator]
static GLOBAL_ALLOCATOR: MyAllocator = MyAllocator;

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[lang = "eh_personality"]
fn eh_personality() {}

#[no_mangle]
pub extern "C" fn allocate_memory(size: usize) -> i32 {
use alloc::boxed::Box;
let mut x = Box::new(10);
let ptr:*mut i32=&mut *x;
ptr
}

I am trying to call "allocate_memory" function from c file so that rust can allocate and deallocate the memory. Since [feature] is required for global allocator I am using nightly version of rust rather than stable as with stable build was failing at [feature] line. with nightly I am seeing below error.

Error:

error[E0463]: can't find crate for core
|
= note: the armv7a-none-eabi target may not be installed
= help: consider downloading the target with rustup target add armv7a-none-eabi
= help: consider building the standard library from source with cargo build -Zbuild-std

I have armv7a toolchain already installed.

Command used for compiling is "rustc + nightly --crate-type=lib --target armv7a-none-eabi"

Let me know if I am doing any mistake with my approach.

Thanks,
Santhosh

Have you done rustup target add armv7a-none-eabi --toolchain nightly? Without --toolchain nightly it may have been installed for the wrong toolchain.

Hi bjorn3,

Yes, I have installed armv7a toolchain with nightly and even with this I am shown with that error.

Thanks
Santhosh

Hi,

I was trying to use box pointer without std for a baremetal arm v7 target by defining custom allocator. However, I am seeing " error: in function rust_alloc': (.text.rust_alloc+0x54): undefined reference to alloc::raw_vec::handle_error' "

Please find my code below
C:
extern void* rust_alloc(size_t size);
extern void rust_free(void* ptr);
extern int __rust_no_alloc_shim_is_unstable = 0;

void * __rust_alloc(size_t len, size_t _align) {
// todo: proper align the pointer
return malloc(len);
}

void *__rust_alloc_zeroed(size_t len, size_t _align) {
return malloc(len);
}

void __rust_dealloc(void *ptr, size_t _size, size_t _align) {
free(ptr);
}

void __rust_alloc_error_handler(size_t size, size_t align) {
abort();
}

static int prioritythreads(int argc, const console_cmd_args *argv) {

size_t size = 16 * sizeof(int);
int* int_ptr = (int*)rust_alloc(size);

if (int_ptr != NULL) {
    // Fill the allocated memory with some values
    for (int i = 0; i < 16; i++) {
        int_ptr[i] = i;
    }

    // Print the values
    for (int i = 0; i < 16; i++) {
        printf("Value %d: %d\n", i, int_ptr[i]);
    }

    // Free the allocated memory
    rust_free(int_ptr);
} else {
    printf("Failed to allocate memory.\n");
}

return 0;

}

Rust code:
#![no_std]
#![feature(lang_items)]
#![feature(default_alloc_error_handler)]

extern crate alloc;
use alloc::boxed::Box;
use alloc::vec;
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
use core::panic::PanicInfo;

pub struct Dummy;

unsafe impl GlobalAlloc for Dummy {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}

unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
    panic!("dealloc should be never called")
}

}

#[no_mangle]
pub extern "C" fn rust_alloc(size: usize) -> *mut i32 {
let mut vec=Box::new(vec![0;size]);
let ptr =vec.as_mut_ptr();
core::mem::forget(vec);
ptr
}

#[no_mangle]
pub extern "C" fn rust_free(ptr:*mut i32, size:usize) {
if !ptr.is_null(){
unsafe {let _ = Box::from_raw(core::slice::from_raw_parts_mut(ptr,size));};
}
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

I am not sure how to fix this error. Can anybody please provide insights on this.

Thanks
Santhosh

Instead of manually defining functions like __rust_alloc and globals like __rust_no_alloc_shim_is_unstable you should use #[global_allocator] static ALLOC: MyGlobalAlloc = MyGlobalAlloc; where MyGlobalAlloc is the type for which you implemented the GlobalAlloc trait. This will define all those functions and globals for you and doesn't depend on unstable implementation details.

Also your rust_alloc and rust_free methods are incorrect. You are creating a Box<Vec<u8>> but then freeing a Box<[u8]>. You probably want to use the alloc::alloc::alloc and alloc::alloc::dealloc methods directly.

Hi Bjorn3,

I have implemented global allocator with static and removed all the functions related to alloc_shim etc but still I see
"n function alloc::alloc::exchange_malloc': TestRust.23a4d893b5ab48ca-cgu.0:(.text._ZN5alloc5alloc15exchange_malloc17h4da6d21f615b0a75E+0x0): undefined reference to __rust_no_alloc_shim_is_unstable'
arm-none-eabi-ld: TestRust.23a4d893b5ab48ca-cgu.0:(.text._ZN5alloc5alloc15exchange_malloc17h4da6d21f615b0a75E+0x8): undefined reference to __rust_no_alloc_shim_is_unstable' arm-none-eabi-ld: TestRust.23a4d893b5ab48ca-cgu.0:(.text._ZN5alloc5alloc15exchange_malloc17h4da6d21f615b0a75E+0x14): undefined reference to alloc::alloc::handle_alloc_error'
arm-none-eabi-ld: ./build-qemu-virt-arm32-test/app/prioritythreads.mod.o: in function rust_free': (.text.rust_free+0x20): undefined reference to core::panicking::panic'"

C code:
extern void* rust_alloc(size_t size);
extern void rust_free(void* ptr);

static int prioritythreads(int argc, const console_cmd_args *argv) {

size_t size = 16 * sizeof(int);
int* int_ptr = (int*)rust_alloc(size);

if (int_ptr != NULL) {
// Fill the allocated memory with some values
for (int i = 0; i < 16; i++) {
int_ptr[i] = i;
}

// Print the values
for (int i = 0; i < 16; i++) {
    printf("Value %d: %d\n", i, int_ptr[i]);
}

// Free the allocated memory
rust_free(int_ptr);

} else {
printf("Failed to allocate memory.\n");
}

return 0;
}

rust code:
#![no_std]
#![feature(lang_items)]
#![feature(default_alloc_error_handler)]

extern crate alloc;
use alloc::boxed::Box;
use alloc::alloc::{GlobalAlloc, Layout};
use core::ptr::null_mut;
use core::panic::PanicInfo;

pub struct Dummy;

unsafe impl GlobalAlloc for Dummy {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}

unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
    panic!("dealloc should be never called")
}

}

#[global_allocator]
static GLOBAL_ALLOCATOR: Dummy = Dummy;

#[no_mangle]
pub extern "C" fn rust_alloc(size: usize) -> *mut i32 {
let mut data=Box::new(42);
let ptr:*mut i32 =&mut *data;
core::mem::forget(data);
ptr
}

#[no_mangle]
pub extern "C" fn rust_free(ptr:*mut i32, size:usize) {
if !ptr.is_null(){
unsafe {
let _ = Box::from_raw(core::slice::from_raw_parts_mut(ptr,size));};
}
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

Can you let me know how to get rid of those errors

Thanks
Santhosh

How are you linking the rust code? Are you building it as staticlib and then linking the output .a? Or are you doing something else?