This commit is contained in:
nora 2023-09-30 23:52:08 +02:00
parent 9bfadd77d9
commit 84e6db0684
8 changed files with 252 additions and 13 deletions

View file

@ -1,5 +1,4 @@
#include<stdio.h> #include<stdio.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int result = printf("Hello, world!\n"); int result = printf("Hello, world!\n");
if (result != 15) { if (result != 15) {

51
libuwuc/src/error.rs Normal file
View file

@ -0,0 +1,51 @@
use core::{cell::UnsafeCell, ptr::addr_of};
#[thread_local]
static ERRNO: UnsafeCell<i32> = UnsafeCell::new(0);
pub fn errno_location() -> *const i32 {
addr_of!(ERRNO).cast()
}
pub fn errno() -> i32 {
unsafe { *ERRNO.get() }
}
pub fn set_errno(errno: i32) {
unsafe { ERRNO.get().write(errno) }
}
pub const EPERM: i32 = 1; /* Operation not permitted */
pub const ENOENT: i32 = 2; /* No such file or directory */
pub const ESRCH: i32 = 3; /* No such process */
pub const EINTR: i32 = 4; /* Interrupted system call */
pub const EIO: i32 = 5; /* I/O error */
pub const ENXIO: i32 = 6; /* No such device or address */
pub const E2BIG: i32 = 7; /* Argument list too long */
pub const ENOEXEC: i32 = 8; /* Exec format error */
pub const EBADF: i32 = 9; /* Bad file number */
pub const ECHILD: i32 = 10; /* No child processes */
pub const EAGAIN: i32 = 11; /* Try again */
pub const ENOMEM: i32 = 12; /* Out of memory */
pub const EACCES: i32 = 13; /* Permission denied */
pub const EFAULT: i32 = 14; /* Bad address */
pub const ENOTBLK: i32 = 15; /* Block device required */
pub const EBUSY: i32 = 16; /* Device or resource busy */
pub const EEXIST: i32 = 17; /* File exists */
pub const EXDEV: i32 = 18; /* Cross-device link */
pub const ENODEV: i32 = 19; /* No such device */
pub const ENOTDIR: i32 = 20; /* Not a directory */
pub const EISDIR: i32 = 21; /* Is a directory */
pub const EINVAL: i32 = 22; /* Invalid argument */
pub const ENFILE: i32 = 23; /* File table overflow */
pub const EMFILE: i32 = 24; /* Too many open files */
pub const ENOTTY: i32 = 25; /* Not a typewriter */
pub const ETXTBSY: i32 = 26; /* Text file busy */
pub const EFBIG: i32 = 27; /* File too large */
pub const ENOSPC: i32 = 28; /* No space left on device */
pub const ESPIPE: i32 = 29; /* Illegal seek */
pub const EROFS: i32 = 30; /* Read-only file system */
pub const EMLINK: i32 = 31; /* Too many links */
pub const EPIPE: i32 = 32; /* Broken pipe */
pub const EDOM: i32 = 33; /* Math argument out of domain of func */
pub const ERANGE: i32 = 34; /* Math result not representable */

View file

@ -3,9 +3,9 @@ use core::ffi::c_int;
pub mod parse; pub mod parse;
pub mod printf; pub mod printf;
pub fn is_space(c: c_int) -> c_int { pub fn is_space(c: c_int) -> bool {
// todo: is this correct? // todo: is this correct?
char::from_u32(c as _) char::from_u32(c as _)
.map(char::is_whitespace) .map(char::is_whitespace)
.unwrap_or_default() as _ .unwrap_or_default()
} }

View file

@ -1,18 +1,161 @@
use core::ffi::{c_int, c_long}; use core::ffi::{c_int, c_long};
use crate::utils::SharedThinCstr; use crate::{
error::{set_errno, EINVAL},
utils::SharedThinCstr,
};
pub unsafe fn parse_long<'a>( pub fn parse_long<'a>(
str: SharedThinCstr<'a>, str: SharedThinCstr<'a>,
endptr: *mut SharedThinCstr<'a>, endptr: Option<&mut Option<SharedThinCstr<'a>>>,
base: c_int, base: c_int,
) -> c_long { ) -> c_long {
let mut cur = str; if base != 10 {
while cur todo!();
.first() }
.map(|c| super::is_space(c as _) == 1) let mut chars = str.into_iter().enumerate().peekable();
.unwrap_or(false)
{}
0 while chars
.peek()
.map(|&(_, c)| super::is_space(c as _))
.unwrap_or(false)
{
chars.next();
}
let mut negate = false;
let mut acc: i64 = 0;
let write_end = |pos: usize| {
if let Some(endptr) = endptr {
*endptr = Some(unsafe { str.add(pos) });
}
};
let mut last_pos;
let c = chars.peek();
match c {
Some((pos, b'+')) => {
last_pos = *pos;
chars.next();
}
Some((pos, b'-')) => {
last_pos = *pos;
chars.next();
negate = true
}
Some((_, c)) if !c.is_ascii_digit() => {
write_end(0);
set_errno(EINVAL);
return 0;
}
None => {
write_end(0);
set_errno(EINVAL);
return 0;
}
Some((pos, _)) => {
last_pos = *pos;
}
}
loop {
match chars.next() {
Some((pos, c)) if c.is_ascii_digit() => {
last_pos = pos;
let n = c - b'0';
acc *= 10;
if negate {
acc -= n as i64;
} else {
acc += n as i64;
}
}
Some((pos, _)) => {
write_end(pos);
break;
}
None => {
write_end(last_pos + 1);
break;
}
}
}
acc
}
#[cfg(test)]
mod tests {
use crate::{cstr, utils::SharedThinCstr};
fn test_strtol(str: SharedThinCstr<'_>, expected: i64, base: i32, parsed_len: usize) {
let mut end = None;
let result = super::parse_long(str, Some(&mut end), base);
assert_eq!(result, expected);
let end = end.unwrap();
let read = end.as_raw() as usize - str.as_raw() as usize;
assert_eq!(read, parsed_len);
}
#[test]
fn l_zero() {
test_strtol(cstr!("0"), 0, 10, 1);
}
#[test]
fn l_ten() {
test_strtol(cstr!("10"), 10, 10, 2);
}
#[test]
fn l_eleven() {
test_strtol(cstr!("11"), 11, 10, 2);
}
#[test]
fn negative_zero() {
test_strtol(cstr!("-0"), 0, 10, 2);
}
#[test]
fn negative_ten() {
test_strtol(cstr!("-10"), -10, 10, 3);
}
#[test]
fn negative_eleven() {
test_strtol(cstr!("-11"), -11, 10, 3);
}
#[test]
fn l_leading_whitespace() {
test_strtol(cstr!("\t 1"), 1, 10, 3);
}
#[test]
fn l_trailing_garbage_one() {
test_strtol(cstr!("3uwu"), 3, 10, 1);
}
#[test]
fn l_trailing_garbage_two() {
test_strtol(cstr!("32uwu"), 32, 10, 2);
}
#[test]
fn l_trailing_garbage_many() {
test_strtol(cstr!("12345uwu"), 12345, 10, 5);
}
#[test]
fn l_long_max() {
test_strtol(cstr!("9223372036854775807"), i64::MAX, 10, 19);
}
#[test]
fn l_long_min() {
test_strtol(cstr!("-9223372036854775808"), i64::MIN, 10, 20);
}
} }

View file

@ -1,5 +1,7 @@
#![no_std] #![no_std]
#![feature(c_variadic)] #![feature(c_variadic)]
#![feature(thread_local)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
@ -9,6 +11,7 @@ extern crate std;
pub mod alloc; pub mod alloc;
pub mod env; pub mod env;
pub mod error;
pub mod fmt; pub mod fmt;
pub mod io; pub mod io;
pub mod mem; pub mod mem;

View file

@ -12,6 +12,9 @@ macro_rules! syscall {
"syscall", "syscall",
in("rdi") $number, in("rdi") $number,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered https://github.com/torvalds/linux/blob/3b517966c5616ac011081153482a5ba0e91b17ff/tools/include/nolibc/arch-x86_64.h#L19
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -22,6 +25,9 @@ macro_rules! syscall {
in("rax") $number, in("rax") $number,
in("rdi") $arg1, in("rdi") $arg1,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -33,6 +39,9 @@ macro_rules! syscall {
in("rdi") $arg1, in("rdi") $arg1,
in("rsi") $arg2, in("rsi") $arg2,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -45,6 +54,9 @@ macro_rules! syscall {
in("rsi") $arg2, in("rsi") $arg2,
in("rdx") $arg3, in("rdx") $arg3,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -58,6 +70,9 @@ macro_rules! syscall {
in("rdx") $arg3, in("rdx") $arg3,
in("r10") $arg4, in("r10") $arg4,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -72,6 +87,9 @@ macro_rules! syscall {
in("r10") $arg4, in("r10") $arg4,
in("r8") $arg5, in("r8") $arg5,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};
@ -87,6 +105,9 @@ macro_rules! syscall {
in("r8") $arg5, in("r8") $arg5,
in("r9") $arg6, in("r9") $arg6,
lateout("rax") out, lateout("rax") out,
// rcx and r11 are clobbered
out("rcx") _,
out("r11") _,
); );
out out
}}; }};

View file

@ -5,3 +5,8 @@ pub extern "C" fn __stack_chk_fail() -> ! {
libuwuc::start::abort(); libuwuc::start::abort();
} }
} }
#[no_mangle]
pub extern "C" fn __errno_location() -> *const i32 {
libuwuc::error::errno_location()
}

View file

@ -1,3 +1,5 @@
use core::ffi::{c_int, c_long};
use libuwuc::utils::SharedThinCstr; use libuwuc::utils::SharedThinCstr;
#[no_mangle] #[no_mangle]
@ -15,6 +17,21 @@ pub unsafe extern "C" fn exit(code: i32) -> ! {
libuwuc::start::exit(code as i64 as _) libuwuc::start::exit(code as i64 as _)
} }
#[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);
libuwuc::fmt::parse::parse_long(
str,
core::mem::transmute::<*mut *const u8, Option<&mut Option<SharedThinCstr<'_>>>>(endptr),
base,
)
}
#[no_mangle]
pub unsafe extern "C" fn strtoll(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long {
strtol(nptr, endptr, base)
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 { pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 {
libuwuc::env::getenv(SharedThinCstr::from_raw(name)) libuwuc::env::getenv(SharedThinCstr::from_raw(name))