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)");
+    }
+}