Merge changes I800fc26a,Ie85b45ad
* changes:
pvmfw: heap: Implement malloc() and free()
vmbase: Support Bionic errno, abort(), FORTIFY_SOURCE
diff --git a/pvmfw/src/heap.rs b/pvmfw/src/heap.rs
index bfa8320..eab3bc4 100644
--- a/pvmfw/src/heap.rs
+++ b/pvmfw/src/heap.rs
@@ -14,6 +14,14 @@
//! Heap implementation.
+use core::alloc::GlobalAlloc as _;
+use core::alloc::Layout;
+use core::ffi::c_void;
+use core::mem;
+use core::num::NonZeroUsize;
+use core::ptr;
+use core::ptr::NonNull;
+
use buddy_system_allocator::LockedHeap;
#[global_allocator]
@@ -24,3 +32,32 @@
pub unsafe fn init() {
HEAP_ALLOCATOR.lock().init(HEAP.as_mut_ptr() as usize, HEAP.len());
}
+
+#[no_mangle]
+unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
+ malloc_(size).map_or(ptr::null_mut(), |p| p.cast::<c_void>().as_ptr())
+}
+
+#[no_mangle]
+unsafe extern "C" fn free(ptr: *mut c_void) {
+ if let Some(ptr) = NonNull::new(ptr).map(|p| p.cast::<usize>().as_ptr().offset(-1)) {
+ if let Some(size) = NonZeroUsize::new(*ptr) {
+ if let Some(layout) = malloc_layout(size) {
+ HEAP_ALLOCATOR.dealloc(ptr as *mut u8, layout);
+ }
+ }
+ }
+}
+
+unsafe fn malloc_(size: usize) -> Option<NonNull<usize>> {
+ let size = NonZeroUsize::new(size)?.checked_add(mem::size_of::<usize>())?;
+ let ptr = HEAP_ALLOCATOR.alloc(malloc_layout(size)?);
+ let ptr = NonNull::new(ptr)?.cast::<usize>().as_ptr();
+ *ptr = size.get();
+ NonNull::new(ptr.offset(1))
+}
+
+fn malloc_layout(size: NonZeroUsize) -> Option<Layout> {
+ const ALIGN: usize = mem::size_of::<u64>();
+ Layout::from_size_align(size.get(), ALIGN).ok()
+}
diff --git a/vmbase/src/bionic.rs b/vmbase/src/bionic.rs
index 8b3a076..b4a2f7b 100644
--- a/vmbase/src/bionic.rs
+++ b/vmbase/src/bionic.rs
@@ -14,6 +14,11 @@
//! Low-level compatibility layer between baremetal Rust and Bionic C functions.
+use core::ffi::c_char;
+use core::ffi::c_int;
+use core::ffi::CStr;
+
+use crate::eprintln;
use crate::linker;
/// Reference to __stack_chk_guard.
@@ -23,3 +28,37 @@
extern "C" fn __stack_chk_fail() -> ! {
panic!("stack guard check failed");
}
+
+/// Called from C to cause abnormal program termination.
+#[no_mangle]
+extern "C" fn abort() -> ! {
+ panic!("C code called abort()")
+}
+
+/// Error number set and read by C functions.
+pub static mut ERRNO: c_int = 0;
+
+#[no_mangle]
+unsafe extern "C" fn __errno() -> *mut c_int {
+ &mut ERRNO as *mut _
+}
+
+/// Reports a fatal error detected by Bionic.
+///
+/// # Safety
+///
+/// Input strings `prefix` and `format` must be properly NULL-terminated.
+///
+/// # Note
+///
+/// This Rust functions is missing the last argument of its C/C++ counterpart, a va_list.
+#[no_mangle]
+unsafe extern "C" fn async_safe_fatal_va_list(prefix: *const c_char, format: *const c_char) {
+ let prefix = CStr::from_ptr(prefix);
+ let format = CStr::from_ptr(format);
+
+ if let (Ok(prefix), Ok(format)) = (prefix.to_str(), format.to_str()) {
+ // We don't bother with printf formatting.
+ eprintln!("FATAL BIONIC ERROR: {prefix}: \"{format}\" (unformatted)");
+ }
+}