Skip to content

Instantly share code, notes, and snippets.

@japaric

japaric/lib.rs Secret

Last active July 29, 2019 16:50
Show Gist options
  • Save japaric/b5e0a7450d968f6ca29c4d238d34a2d0 to your computer and use it in GitHub Desktop.
Save japaric/b5e0a7450d968f6ca29c4d238d34a2d0 to your computer and use it in GitHub Desktop.
Using newlib's allocator as Rust's allocator
#![feature(allocator_api)]
#![no_std]
extern crate cty;
use core::heap::{Alloc, AllocErr, Layout};
use core::{cmp, ptr};
use cty::c_void;
// C heap allocator
pub struct Heap;
#[link(name = "c_nano")]
extern "C" {
fn free(ptr: *mut c_void);
fn malloc(size: usize) -> *mut c_void;
fn memalign(alignment: usize, size: usize) -> *mut c_void;
fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
}
const MIN_ALIGN: usize = 8;
// FIXME C malloc/free are not thread / interrupt safe. These implementations need a Mutex
unsafe impl<'a> Alloc for &'a Heap {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
malloc(layout.size()) as *mut u8
} else {
aligned_malloc(&layout)
};
if !ptr.is_null() {
Ok(ptr)
} else {
Err(AllocErr::Exhausted { request: layout })
}
}
#[inline]
unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
free(ptr as *mut c_void)
}
#[inline]
unsafe fn realloc(
&mut self,
ptr: *mut u8,
old_layout: Layout,
new_layout: Layout,
) -> Result<*mut u8, AllocErr> {
if old_layout.align() != new_layout.align() {
return Err(AllocErr::Unsupported {
details: "cannot change alignment on `realloc`",
});
}
if new_layout.align() <= MIN_ALIGN && new_layout.align() <= new_layout.size() {
let ptr = realloc(ptr as *mut c_void, new_layout.size());
if !ptr.is_null() {
Ok(ptr as *mut u8)
} else {
Err(AllocErr::Exhausted {
request: new_layout,
})
}
} else {
let res = self.alloc(new_layout.clone());
if let Ok(new_ptr) = res {
let size = cmp::min(old_layout.size(), new_layout.size());
ptr::copy_nonoverlapping(ptr, new_ptr, size);
self.dealloc(ptr, old_layout);
}
res
}
}
}
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
memalign(layout.align(), layout.size()) as *mut u8
}
// Required by malloc
// This implementation is tailored to cortex-m-rt
#[no_mangle]
pub unsafe extern "C" fn _sbrk(nbytes: isize) -> *mut c_void {
extern "C" {
static mut _sheap: u8;
static mut _eheap: u8;
}
static mut HEAP: *mut u8 = unsafe { &_sheap as *const u8 as *mut u8 };
let eheap = &mut _eheap as *mut u8;
let base = HEAP;
let new = base.offset(nbytes);
if new < eheap {
HEAP = new;
base as *mut c_void
} else {
// OOM
0 as *mut c_void
}
}
#![no_std]
// ..
#[global_allocator]
static HEAP: Heap = Heap;
#[inline(never)]
fn main() {
let x = Box::new(0);
unsafe { ptr::read_volatile(&*x) };
}
$ arm-none-eabi-size target/thumbv7m-none-eabi/release/app
   text    data     bss     dec     hex filename
   1900     104      12    2016     7e0 target/thumbv7m-none-eabi/release/app
   
$ # with the Box stuff removed from main
$ arm-none-eabi-size target/thumbv7m-none-eabi/release/app
   text    data     bss     dec     hex filename
   1436       0       0    1436     59c target/thumbv7m-none-eabi/release/app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment