From 9e2cf38cd55b703b5e775a82dcfc1ec4d4c1f071 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 7 Oct 2023 21:50:57 +0200 Subject: [PATCH] implement more things --- libuwuc/src/alloc.rs | 44 ++++++++++++++++++++++++++++ libuwuc/src/error/errno.rs | 8 ++--- libuwuc/src/error/mod.rs | 7 ++++- libuwuc/src/io/mod.rs | 10 +++++-- libuwuc/src/io/stream/mod.rs | 2 +- libuwuc/src/mem.rs | 57 ++++++++++++++++++++++++++++++++++++ rawc/src/lib.rs | 1 + rawc/src/stdlib.rs | 29 ++++++++++++++++-- rawc/src/string.rs | 14 +++++++++ rawc/src/unistd.rs | 16 ++++++++++ tests/real_world/clone.sh | 1 + 11 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 rawc/src/unistd.rs diff --git a/libuwuc/src/alloc.rs b/libuwuc/src/alloc.rs index 11e33db..162471b 100644 --- a/libuwuc/src/alloc.rs +++ b/libuwuc/src/alloc.rs @@ -97,6 +97,50 @@ pub unsafe fn free(ptr: *mut u8) { ALLOCATOR.dealloc(start, layout); } +fn array_size(nmemb: usize, size: usize) -> Option { + let total = nmemb.checked_mul(size)?; + if total > (isize::MAX as usize) { + return None; + } + Some(total) +} + +pub unsafe fn malloc_zeroed_array(nmemb: usize, size: usize, align: usize) -> *mut u8 { + let Some(total) = nmemb.checked_mul(size) else { + return core::ptr::null_mut(); + }; + if total > (isize::MAX as usize) { + return core::ptr::null_mut(); + } + malloc_zeroed(total, align) +} + +pub unsafe fn realloc(ptr: *mut u8, size: usize, align: usize) -> *mut u8 { + let new = malloc_zeroed(size, align); + if !new.is_null() { + core::ptr::copy_nonoverlapping(ptr, new, size); + } + free(ptr); + new +} + +pub unsafe extern "C" fn reallocarray( + ptr: *mut u8, + nmemb: usize, + size: usize, + align: usize, +) -> *mut u8 { + let new = malloc_zeroed_array(size, size, align); + if !new.is_null() { + let Some(total) = array_size(nmemb, size) else { + return core::ptr::null_mut(); + }; + core::ptr::copy_nonoverlapping(ptr, new, total); + } + free(ptr); + new +} + #[cfg_attr(miri, allow(unused_variables, unreachable_code))] pub unsafe fn sys_mmap( addr: *const u8, diff --git a/libuwuc/src/error/errno.rs b/libuwuc/src/error/errno.rs index 2d08bfe..cd060bb 100644 --- a/libuwuc/src/error/errno.rs +++ b/libuwuc/src/error/errno.rs @@ -273,8 +273,8 @@ impl super::Error { pub const HWPOISON: Self = Self(EHWPOISON); pub const NOTSUP: Self = Self(ENOTSUP); - pub fn simple_str(self) -> &'static str { - match self { + pub fn simple_str(self) -> Option<&'static str> { + Some(match self { Self::PERM => "EPERM", Self::NOENT => "ENOENT", Self::SRCH => "ESRCH", @@ -406,7 +406,7 @@ impl super::Error { Self::NOTRECOVERABLE => "ENOTRECOVERABLE", Self::RFKILL => "ERFKILL", Self::HWPOISON => "EHWPOISON", - _ => "", - } + _ => return None, + }) } } diff --git a/libuwuc/src/error/mod.rs b/libuwuc/src/error/mod.rs index 08cfcc1..e0d5c55 100644 --- a/libuwuc/src/error/mod.rs +++ b/libuwuc/src/error/mod.rs @@ -20,12 +20,17 @@ pub fn set_errno(errno: i32) { unsafe { ERRNO.0.get().write(errno) } } +pub fn strerror(errnum: Error) -> Option<&'static str> { + errnum.simple_str() +} + #[derive(Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] pub struct Error(pub i32); impl Debug for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(self.simple_str()) + f.write_str(self.simple_str().unwrap_or("")) } } diff --git a/libuwuc/src/io/mod.rs b/libuwuc/src/io/mod.rs index c3515ab..d01a653 100644 --- a/libuwuc/src/io/mod.rs +++ b/libuwuc/src/io/mod.rs @@ -39,13 +39,17 @@ pub use println; use self::fd::Fd; -pub unsafe fn sys_write(fd: i32, buf: &[u8]) -> Result { - syscall::syscall!(syscall::SYS_WRITE, fd, buf.as_ptr(), buf.len()).syscall_resultify() +pub unsafe fn sys_read(fd: Fd, buf: &mut [u8]) -> Result { + syscall::syscall!(syscall::SYS_READ, fd.0, buf.as_ptr(), buf.len()).syscall_resultify() +} + +pub unsafe fn sys_write(fd: Fd, buf: &[u8]) -> Result { + syscall::syscall!(syscall::SYS_WRITE, fd.0, buf.as_ptr(), buf.len()).syscall_resultify() } pub unsafe fn write_all(fd: Fd, mut buf: &[u8]) -> Result<(), Error> { while !buf.is_empty() { - let result = sys_write(fd.0, buf)?; + let result = sys_write(fd, buf)?; buf = &buf[result..]; } Ok(()) diff --git a/libuwuc/src/io/stream/mod.rs b/libuwuc/src/io/stream/mod.rs index 32281e3..501cd3c 100644 --- a/libuwuc/src/io/stream/mod.rs +++ b/libuwuc/src/io/stream/mod.rs @@ -27,7 +27,7 @@ impl FileStream { impl IoWrite for &FileStream { fn write(&mut self, buf: &[u8]) -> Result { - unsafe { super::sys_write(self.fd.0, buf) } + unsafe { super::sys_write(self.fd, buf) } } } diff --git a/libuwuc/src/mem.rs b/libuwuc/src/mem.rs index 10f7454..2257cba 100644 --- a/libuwuc/src/mem.rs +++ b/libuwuc/src/mem.rs @@ -16,6 +16,31 @@ pub unsafe fn memcpy(dest: *mut u8, src: *const u8, size: usize) -> *mut u8 { dest } +#[inline] +pub unsafe fn memmove(dest: *mut u8, src: *const u8, size: usize) -> *mut u8 { + if dest as usize > src as usize { + // 1 2 3 4 5 6 7 + // ^---- dest + // ^---- src + // We need to move backwards, first copying the 5 to 6, then 4 to 5 etc. + // Iterating fowards would overwrite 4 with 3 before we can copy 4. + for i in (0..size).rev() { + dest.add(i).write(src.add(i).read()); + } + } else { + // 1 2 3 4 5 6 7 + // ^---- dest + // ^---- src + // We need to move forwards from src. This way we never overwrite values + // before we would need to read them. + for i in 0..size { + dest.add(i).write(src.add(i).read()); + } + } + + dest +} + #[inline] pub unsafe fn memcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { for i in 0..size { @@ -56,6 +81,38 @@ mod tests { assert_eq!(dest, src); } + #[test] + fn memmove_null() { + unsafe { super::memmove(std::ptr::null_mut(), std::ptr::null_mut(), 0) }; + } + + #[test] + fn memmove_one_forwards() { + let mut arr = [1, 2, 3, 4, 5]; + let src = arr.as_mut_ptr(); + let dest = unsafe { src.add(1) }; + unsafe { super::memmove(dest, src, 4) }; + assert_eq!(arr, [1, 1, 2, 3, 4]); + } + + #[test] + fn memmove_one_backwards() { + let mut arr = [1, 2, 3, 4, 5]; + let src = unsafe { arr.as_mut_ptr().add(1) }; + let dest = unsafe { src.sub(1) }; + unsafe { super::memmove(dest, src, 4) }; + assert_eq!(arr, [2, 3, 4, 5, 5]); + } + + #[test] + fn memmove_full_overlap() { + let mut arr = [1, 2, 3, 4, 5]; + let src = arr.as_mut_ptr(); + let dest = src; + unsafe { super::memmove(src, dest, 4) }; + assert_eq!(arr, [1, 2, 3, 4, 5]); + } + #[test] fn memset_null() { unsafe { super::memset(std::ptr::null_mut(), 0, 0) }; diff --git a/rawc/src/lib.rs b/rawc/src/lib.rs index 9528bfd..eca015e 100644 --- a/rawc/src/lib.rs +++ b/rawc/src/lib.rs @@ -8,6 +8,7 @@ mod rt; mod stdio; mod stdlib; mod string; +mod unistd; // libcore seems to require this symbol, even though it's unused. #[no_mangle] diff --git a/rawc/src/stdlib.rs b/rawc/src/stdlib.rs index e5d9874..3bc60d8 100644 --- a/rawc/src/stdlib.rs +++ b/rawc/src/stdlib.rs @@ -2,9 +2,13 @@ use core::ffi::{c_int, c_long}; use libuwuc::{error::IntoOkOrErrno, utils::SharedThinCstr}; +// Allocation functions + +const MAX_ALIGN: usize = 16; + #[no_mangle] pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 { - libuwuc::alloc::malloc_zeroed(size, 16) + libuwuc::alloc::malloc_zeroed(size, MAX_ALIGN) } #[no_mangle] @@ -13,10 +17,22 @@ pub unsafe extern "C" fn free(ptr: *mut u8) { } #[no_mangle] -pub unsafe extern "C" fn exit(code: i32) -> ! { - libuwuc::start::sys_exit(code as i64 as _) +pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut u8 { + libuwuc::alloc::malloc_zeroed_array(nmemb, size, MAX_ALIGN) } +#[no_mangle] +pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 { + libuwuc::alloc::realloc(ptr, size, MAX_ALIGN) +} + +#[no_mangle] +pub unsafe extern "C" fn reallocarray(ptr: *mut u8, nmemb: usize, size: usize) -> *mut u8 { + libuwuc::alloc::reallocarray(ptr, nmemb, size, MAX_ALIGN) +} + +// Integer parsing functions + #[no_mangle] pub unsafe extern "C" fn strtol(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long { let str = SharedThinCstr::from_raw(nptr); @@ -33,9 +49,16 @@ pub unsafe extern "C" fn strtoll(nptr: *const u8, endptr: *mut *const u8, base: strtol(nptr, endptr, base) } +// Other functions + #[no_mangle] pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 { libuwuc::env::getenv(SharedThinCstr::from_raw(name)) .map(SharedThinCstr::as_raw) .unwrap_or(core::ptr::null()) } + +#[no_mangle] +pub unsafe extern "C" fn exit(code: i32) -> ! { + libuwuc::start::sys_exit(code as i64 as _) +} diff --git a/rawc/src/string.rs b/rawc/src/string.rs index 3640aac..9ffd8b4 100644 --- a/rawc/src/string.rs +++ b/rawc/src/string.rs @@ -1,3 +1,5 @@ +use libuwuc::error::Error; + #[no_mangle] pub unsafe extern "C" fn memset(ptr: *mut u8, constant: u8, len: usize) { libuwuc::mem::memset(ptr, constant, len) @@ -8,6 +10,11 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, size: usize) -> * libuwuc::mem::memcpy(dest, src, size) } +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, size: usize) -> *mut u8 { + libuwuc::mem::memmove(dest, src, size) +} + #[no_mangle] pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { libuwuc::mem::memcmp(s1, s2, size) @@ -22,3 +29,10 @@ pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 pub unsafe extern "C" fn strlen(s: *const u8) -> usize { libuwuc::mem::strlen(s) } + +#[no_mangle] +pub unsafe extern "C" fn strerror(errnum: Error) -> *const u8 { + libuwuc::error::strerror(errnum) + .map(str::as_ptr) + .unwrap_or(core::ptr::null()) +} diff --git a/rawc/src/unistd.rs b/rawc/src/unistd.rs new file mode 100644 index 0000000..4cbf673 --- /dev/null +++ b/rawc/src/unistd.rs @@ -0,0 +1,16 @@ +use libuwuc::error::IntoOkOrErrno; +use libuwuc::io::fd::Fd; + +#[no_mangle] +pub unsafe extern "C" fn read(fd: Fd, buf: *mut u8, count: usize) -> isize { + libuwuc::io::sys_read(fd, core::slice::from_raw_parts_mut(buf, count)) + .map(|n| n as isize) + .into_ok_or_errno() +} + +#[no_mangle] +pub unsafe extern "C" fn write(fd: Fd, buf: *const u8, count: usize) -> isize { + libuwuc::io::sys_write(fd, core::slice::from_raw_parts(buf, count)) + .map(|n| n as isize) + .into_ok_or_errno() +} diff --git a/tests/real_world/clone.sh b/tests/real_world/clone.sh index 38ccf00..320f80b 100755 --- a/tests/real_world/clone.sh +++ b/tests/real_world/clone.sh @@ -15,3 +15,4 @@ ensure_cloned() { } ensure_cloned "https://github.com/tsoding/noed.git" "tsoding_noed" "1c2bd182139080a8448a59589e8d457a7019d553" +ensure_cloned "https://github.com/zesterer/tosh.git" "zest_tosh" "fa43ee9ec01a625f6a96cb48662f6c8911d8cc8c"