From 5673cf51dbfb7f925d8d0ad5cbbaa55c7c320dd7 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 30 Sep 2023 12:00:05 +0200 Subject: [PATCH] more things --- .cargo/config.toml | 2 - Cargo.lock | 41 +++++++++ example-user/Cargo.lock | 41 +++++++++ hello.c | 3 +- libuwuc/Cargo.toml | 1 + libuwuc/src/alloc.rs | 117 ++++++++++++++++++++++++++ libuwuc/src/env.rs | 1 + libuwuc/src/io/mod.rs | 2 +- libuwuc/src/lib.rs | 5 +- libuwuc/src/start.rs | 9 ++ libuwuc/src/sys/x86_64/syscall/mod.rs | 42 +++++++++ libuwuc/src/utils/mod.rs | 2 +- rawc/build.rs | 4 + rawc/src/lib.rs | 4 + rawc/src/rt.rs | 7 ++ rawc/src/stdlib.rs | 14 +++ rawc/src/string.rs | 4 +- test.sh | 2 +- 18 files changed, 292 insertions(+), 9 deletions(-) delete mode 100644 .cargo/config.toml create mode 100644 libuwuc/src/alloc.rs create mode 100644 rawc/build.rs create mode 100644 rawc/src/rt.rs create mode 100644 rawc/src/stdlib.rs diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 52c9e0e..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.x86_64-unknown-linux-gnu] -rustflags = ["-Clink-arg=-nostartfiles", "-Clink-arg=-nostdlib"] diff --git a/Cargo.lock b/Cargo.lock index bc92513..f4ceb45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "cfg-if" version = "1.0.0" @@ -13,6 +19,26 @@ name = "libuwuc" version = "0.1.0" dependencies = [ "cfg-if", + "linked_list_allocator", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", ] [[package]] @@ -21,3 +47,18 @@ version = "0.1.0" dependencies = [ "libuwuc", ] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] diff --git a/example-user/Cargo.lock b/example-user/Cargo.lock index 6930e5d..b039314 100644 --- a/example-user/Cargo.lock +++ b/example-user/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "cfg-if" version = "1.0.0" @@ -21,6 +27,26 @@ name = "libuwuc" version = "0.1.0" dependencies = [ "cfg-if", + "linked_list_allocator", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", ] [[package]] @@ -29,3 +55,18 @@ version = "0.1.0" dependencies = [ "libuwuc", ] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] diff --git a/hello.c b/hello.c index 0cd9260..d83d70c 100644 --- a/hello.c +++ b/hello.c @@ -1,5 +1,6 @@ #include - +#include int main(int argc, char *argv[]) { + PROT_WRITE; puts("Hello, world!"); } diff --git a/libuwuc/Cargo.toml b/libuwuc/Cargo.toml index 6d73e2e..d07e837 100644 --- a/libuwuc/Cargo.toml +++ b/libuwuc/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] cfg-if = "1.0.0" +linked_list_allocator = "0.10.5" diff --git a/libuwuc/src/alloc.rs b/libuwuc/src/alloc.rs new file mode 100644 index 0000000..cdb7a36 --- /dev/null +++ b/libuwuc/src/alloc.rs @@ -0,0 +1,117 @@ +use core::{ + alloc::{GlobalAlloc, Layout}, + ffi::c_int, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use linked_list_allocator::LockedHeap; + +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +const UNINIT: usize = 0; +const INITIALIZING: usize = 1; +const INIT: usize = 2; + +static INIT_STATE: AtomicUsize = AtomicUsize::new(0); + +fn init() { + let state = + INIT_STATE.compare_exchange(UNINIT, INITIALIZING, Ordering::Relaxed, Ordering::Acquire); + + match state { + Ok(_) => unsafe { + const HEAP_SIZE: usize = 0x100000; + let map_anon = 0x20; + let prot_read = 1; + let prod_write = 2; + + let start = mmap( + core::ptr::null(), + HEAP_SIZE, + prot_read | prod_write, + map_anon, + 0, + 0, + ); + ALLOCATOR.lock().init(start, HEAP_SIZE); + + INIT_STATE.store(INIT, Ordering::Release); + }, + Err(INITIALIZING) => { + while INIT_STATE.load(Ordering::Acquire) != INIT { + core::hint::spin_loop(); + } + } + Err(INIT) => {} + Err(_) => unreachable!(), + } +} + +pub unsafe fn malloc_zeroed(size: usize, align: usize) -> *mut u8 { + /* + |start |align |offset |RETURN VALUE + */ + + init(); + let (layout, offset) = Layout::array::(3) + .unwrap_unchecked() + .extend(Layout::from_size_align_unchecked(size, align)) + .unwrap_unchecked(); + + let ptr = ALLOCATOR.alloc_zeroed(layout); + if ptr.is_null() { + return ptr; + } + ptr.cast::<[usize; 2]>() + .write([layout.size(), layout.align()]); + + let ret_ptr = ptr.add(offset); + ret_ptr.cast::().sub(1).write(offset); + + ret_ptr +} + +pub unsafe fn free(ptr: *mut u8) { + init(); + let offset = ptr.cast::().sub(1).read(); + let start = ptr.sub(offset); + let [size, align] = start.cast::<[usize; 2]>().read(); + let layout = Layout::from_size_align_unchecked(size, align); + ALLOCATOR.dealloc(start, layout); +} + +pub unsafe fn mmap( + addr: *const u8, + size: usize, + prot: c_int, + flags: c_int, + fd: c_int, + offset: u64, +) -> *mut u8 { + #[cfg(miri)] + { + extern crate std; + return std::alloc::System.alloc_zeroed(Layout::from_size_align_unchecked(size, 4096)); + } + crate::sys::syscall::syscall!( + crate::sys::syscall::SYS_MMAP, + addr, + size, + prot, + flags, + fd, + offset + ) as *mut u8 +} + +#[cfg(test)] +mod tests { + #[test] + fn malloc_free() { + unsafe { + let x = super::malloc_zeroed(10, 8); + x.cast::().write(10); + super::free(x); + } + } +} diff --git a/libuwuc/src/env.rs b/libuwuc/src/env.rs index a5e31c7..f49a9d0 100644 --- a/libuwuc/src/env.rs +++ b/libuwuc/src/env.rs @@ -47,6 +47,7 @@ impl Iterator for EnvP { } } +#[allow(unused)] pub(crate) fn debug_env() { println!("start vars"); global::get().for_each(|s| { diff --git a/libuwuc/src/io/mod.rs b/libuwuc/src/io/mod.rs index 0edcb30..8868ff7 100644 --- a/libuwuc/src/io/mod.rs +++ b/libuwuc/src/io/mod.rs @@ -29,7 +29,7 @@ macro_rules! println { pub use println; pub unsafe fn write_all(fd: i32, mut buf: &[u8]) -> Result<(), i64> { - while buf.len() > 0 { + while !buf.is_empty() { let result = syscall::syscall!(syscall::SYS_WRITE, fd, buf.as_ptr(), buf.len()) as i64; if result < 0 { return Err(result); diff --git a/libuwuc/src/lib.rs b/libuwuc/src/lib.rs index efe7d61..cfc5199 100644 --- a/libuwuc/src/lib.rs +++ b/libuwuc/src/lib.rs @@ -1,12 +1,15 @@ #![no_std] #![warn(unreachable_pub)] +#![allow(clippy::missing_safety_doc)] + #[cfg(test)] extern crate std; -pub mod mem; +pub mod alloc; pub mod env; pub mod io; +pub mod mem; pub mod start; mod stubs; mod sys; diff --git a/libuwuc/src/start.rs b/libuwuc/src/start.rs index 31af337..7099d4e 100644 --- a/libuwuc/src/start.rs +++ b/libuwuc/src/start.rs @@ -27,3 +27,12 @@ pub fn exit(code: u64) -> ! { core::hint::unreachable_unchecked() } } + +pub fn abort() -> ! { + // FIXME: we actually need to do signal shenanigans + unsafe { + crate::sys::syscall::syscall!(crate::sys::syscall::SYS_EXIT, 1); + crate::sys::helpers::trap!(); + core::hint::unreachable_unchecked() + } +} diff --git a/libuwuc/src/sys/x86_64/syscall/mod.rs b/libuwuc/src/sys/x86_64/syscall/mod.rs index c9f53fc..f990ca5 100644 --- a/libuwuc/src/sys/x86_64/syscall/mod.rs +++ b/libuwuc/src/sys/x86_64/syscall/mod.rs @@ -48,6 +48,48 @@ macro_rules! syscall { ); out }}; + ($number:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => {{ + let out: u64; + ::core::arch::asm!( + "syscall", + in("rax") $number, + in("rdi") $arg1, + in("rsi") $arg2, + in("rdx") $arg3, + in("r10") $arg4, + lateout("rax") out, + ); + out + }}; + ($number:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {{ + let out: u64; + ::core::arch::asm!( + "syscall", + in("rax") $number, + in("rdi") $arg1, + in("rsi") $arg2, + in("rdx") $arg3, + in("r10") $arg4, + in("r8") $arg5, + lateout("rax") out, + ); + out + }}; + ($number:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr) => {{ + let out: u64; + ::core::arch::asm!( + "syscall", + in("rax") $number, + in("rdi") $arg1, + in("rsi") $arg2, + in("rdx") $arg3, + in("r10") $arg4, + in("r8") $arg5, + in("r9") $arg6, + lateout("rax") out, + ); + out + }}; } pub use syscall; \ No newline at end of file diff --git a/libuwuc/src/utils/mod.rs b/libuwuc/src/utils/mod.rs index 12f23f1..0f83d57 100644 --- a/libuwuc/src/utils/mod.rs +++ b/libuwuc/src/utils/mod.rs @@ -83,7 +83,7 @@ impl From for &CStr { impl PartialEq for SharedThinCstr { fn eq(&self, other: &Self) -> bool { - self.into_iter().eq(other.into_iter()) + self.into_iter().eq(*other) } } diff --git a/rawc/build.rs b/rawc/build.rs new file mode 100644 index 0000000..6438874 --- /dev/null +++ b/rawc/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rustc-link-arg=-nostartfiles"); + println!("cargo:rustc-link-arg=-nostdlib"); +} \ No newline at end of file diff --git a/rawc/src/lib.rs b/rawc/src/lib.rs index a773553..81dd344 100644 --- a/rawc/src/lib.rs +++ b/rawc/src/lib.rs @@ -1,11 +1,15 @@ #![no_std] #![feature(panic_info_message)] +#![deny(clippy::no_mangle_with_rust_abi)] +mod rt; mod stdio; +mod stdlib; mod string; // libcore seems to require this symbol, even though it's unused. #[no_mangle] +#[allow(clippy::no_mangle_with_rust_abi)] fn rust_eh_personality() { unsafe { libuwuc::trap!(); diff --git a/rawc/src/rt.rs b/rawc/src/rt.rs new file mode 100644 index 0000000..964be24 --- /dev/null +++ b/rawc/src/rt.rs @@ -0,0 +1,7 @@ +#[no_mangle] +pub extern "C" fn __stack_chk_fail() -> ! { + unsafe { + let _ = libuwuc::io::write_all(libuwuc::io::STDERR, b"error: stack overflow"); + libuwuc::start::abort(); + } +} diff --git a/rawc/src/stdlib.rs b/rawc/src/stdlib.rs new file mode 100644 index 0000000..7b4cb12 --- /dev/null +++ b/rawc/src/stdlib.rs @@ -0,0 +1,14 @@ +#[no_mangle] +pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 { + libuwuc::alloc::malloc_zeroed(size, 16) +} + +#[no_mangle] +pub unsafe extern "C" fn free(ptr: *mut u8) { + libuwuc::alloc::free(ptr) +} + +#[no_mangle] +pub unsafe extern "C" fn exit(code: i32) -> ! { + libuwuc::start::exit(code as i64 as _) +} diff --git a/rawc/src/string.rs b/rawc/src/string.rs index c98b8b7..ab964ca 100644 --- a/rawc/src/string.rs +++ b/rawc/src/string.rs @@ -9,13 +9,13 @@ pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, size: usize) -> * } #[no_mangle] -pub unsafe fn memcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { +pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { libuwuc::mem::memcmp(s1, s2, size) } #[no_mangle] -pub unsafe fn bcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { +pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 { libuwuc::mem::memcmp(s1, s2, size) } diff --git a/test.sh b/test.sh index 2c97ffd..8ab49fe 100755 --- a/test.sh +++ b/test.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -cargo run --manifest-path example-user/Cargo.toml --target x86_64-unknown-linux-gnu +cargo run --manifest-path example-user/Cargo.toml