diff --git a/test.c b/test.c index ec2f6fba..1db963c1 100644 --- a/test.c +++ b/test.c @@ -1,11 +1,22 @@ #include #include #include +#include + +void will_fail(jmp_buf a) { + printf("FAIL!!!\n"); + longjmp(a, 123); +} int main(int argc, const char **argv) { - double x = round(1234.123); - assert(fabs(x - 1234.000) < 0.00001); - double y = round(1234.5678); - assert(fabs(y - 1235.000) < 0.00001); + jmp_buf a; + int res = setjmp(a); + + printf("setjmp = %d\n", res); + + if (res == 0) { + will_fail(a); + } + return 0; } diff --git a/userspace/dyn-loader/src/relocation.rs b/userspace/dyn-loader/src/relocation.rs index 014d06ee..b604d1a5 100644 --- a/userspace/dyn-loader/src/relocation.rs +++ b/userspace/dyn-loader/src/relocation.rs @@ -78,6 +78,7 @@ impl RelocationExt for Rela { // Direct 64 bit elf::abi::R_X86_64_64 => Ok(Some(RelValue::QWord(base_value + self.r_addend))), elf::abi::R_X86_64_JUMP_SLOT => Ok(Some(RelValue::QWord(base_value))), + elf::abi::R_X86_64_COPY => todo!("{:?}: R_X86_64_COPY", symbol.name), // GLOB_DAT elf::abi::R_X86_64_GLOB_DAT => Ok(Some(RelValue::QWord(base_value))), // Adjust by image base diff --git a/userspace/lib/ygglibc/etc/x86_64-unknown-none.json b/userspace/lib/ygglibc/etc/x86_64-unknown-none.json index d2a2cad0..426bf2a0 100644 --- a/userspace/lib/ygglibc/etc/x86_64-unknown-none.json +++ b/userspace/lib/ygglibc/etc/x86_64-unknown-none.json @@ -22,12 +22,7 @@ "linker": "rust-lld", "linker-flavor": "ld.lld", - "late-link-args-static": { - "ld.lld": [ - "--gc-sections" - ] - }, - "late-link-args-dynamic": { + "pre-link-args": { "ld.lld": [ "--dynamic-linker=/libexec/dyn-loader" ] diff --git a/userspace/lib/ygglibc/include/bits/setjmp.h b/userspace/lib/ygglibc/include/bits/setjmp.h deleted file mode 100644 index 6d6e5c82..00000000 --- a/userspace/lib/ygglibc/include/bits/setjmp.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _YGGDRASIL_SETJMP_H -#define _YGGDRASIL_SETJMP_H 1 - -int setjmp(jmp_buf env); -[[noreturn]] void longjmp(jmp_buf env, int val); - -#endif diff --git a/userspace/lib/ygglibc/include/dlfcn.h b/userspace/lib/ygglibc/include/dlfcn.h new file mode 100644 index 00000000..f30704a6 --- /dev/null +++ b/userspace/lib/ygglibc/include/dlfcn.h @@ -0,0 +1,14 @@ +#ifndef _DLFCN_H +#define _DLFCN_H 1 + +#define RTLD_LAZY (1 << 0) +#define RTLD_NOW (0 << 0) +#define RTLD_GLOBAL (1 << 1) +#define RTLD_LOCAL (0 << 1) + +int dlclose(void *ptr); +char *dlerror(void); +void *dlopen(const char *path, int mode); +void *dlsym(void *handle, const char *sym); + +#endif diff --git a/userspace/lib/ygglibc/src/headers/mod.rs b/userspace/lib/ygglibc/src/headers/mod.rs index a7fb62b4..850b7605 100644 --- a/userspace/lib/ygglibc/src/headers/mod.rs +++ b/userspace/lib/ygglibc/src/headers/mod.rs @@ -18,9 +18,7 @@ // Math // - // - -// - -// - -// - +// + // I/O utilities // ! diff --git a/userspace/lib/ygglibc/src/headers/setjmp/cbindgen.toml b/userspace/lib/ygglibc/src/headers/setjmp/cbindgen.toml index ee66b1b1..b48fda9b 100644 --- a/userspace/lib/ygglibc/src/headers/setjmp/cbindgen.toml +++ b/userspace/lib/ygglibc/src/headers/setjmp/cbindgen.toml @@ -1,7 +1,7 @@ language = "C" style = "Type" -sys_includes = ["stdarg.h", "stddef.h"] +sys_includes = ["stddef.h"] no_includes = true include_guard = "_SETJMP_H" @@ -12,4 +12,11 @@ isize_type = "ssize_t" [export] include = ["jmp_buf"] -exclude = [] +exclude = [ + "setjmp", + "longjmp", + "_setjmp", + "_longjmp", + "__x86_64_setjmp", + "__x86_64_longjmp" +] diff --git a/userspace/lib/ygglibc/src/headers/setjmp/mod.rs b/userspace/lib/ygglibc/src/headers/setjmp/mod.rs index fb510033..395e2d36 100644 --- a/userspace/lib/ygglibc/src/headers/setjmp/mod.rs +++ b/userspace/lib/ygglibc/src/headers/setjmp/mod.rs @@ -1,5 +1,9 @@ -#[cfg(any(target_arch = "x86_64", rust_analyzer))] -mod x86_64; +use core::ffi::c_int; #[cfg(any(target_arch = "x86_64", rust_analyzer))] -pub type jmp_buf = *mut x86_64::__jmp_buf; +pub mod x86_64; + +#[cfg(any(target_arch = "x86_64", rust_analyzer))] +pub use x86_64::__jmp_buf; + +pub type jmp_buf = __jmp_buf; diff --git a/userspace/lib/ygglibc/src/headers/setjmp/x86_64.S b/userspace/lib/ygglibc/src/headers/setjmp/x86_64.S deleted file mode 100644 index 9858bf01..00000000 --- a/userspace/lib/ygglibc/src/headers/setjmp/x86_64.S +++ /dev/null @@ -1,46 +0,0 @@ -.global setjmp -.global longjmp - -.global _setjmp -.global _longjmp - -.section .text -// args: -// %rdi -- __jmp_buf *env -setjmp: -_setjmp: - movq %rbx, 0(%rdi) - movq %rbp, 8(%rdi) - movq %r12, 16(%rdi) - movq %r13, 24(%rdi) - movq %r14, 32(%rdi) - movq %r15, 40(%rdi) - // Calculate return stack and rip - leaq 8(%rsp), %rax - movq %rax, 48(%rdi) - movq (%rsp), %rax - movq %rax, 56(%rdi) - - movq $0, %rax - ret - -// args: -// %rdi -- __jmp_buf *env -// %rsi -- int val -longjmp: -_longjmp: - // Restore registers - movq 0(%rdi), %rbx - movq 8(%rdi), %rbp - movq 16(%rdi), %r12 - movq 24(%rdi), %r13 - movq 32(%rdi), %r14 - movq 40(%rdi), %r15 - movq 48(%rdi), %rsp - movq 56(%rdi), %rax - pushq %rax - - // Setup return value - movq %rsi, %rax - - ret diff --git a/userspace/lib/ygglibc/src/headers/setjmp/x86_64.rs b/userspace/lib/ygglibc/src/headers/setjmp/x86_64.rs index c482d07e..c6e91659 100644 --- a/userspace/lib/ygglibc/src/headers/setjmp/x86_64.rs +++ b/userspace/lib/ygglibc/src/headers/setjmp/x86_64.rs @@ -1,15 +1,53 @@ -use core::arch::global_asm; +use core::{arch::global_asm, ffi::c_int}; -#[repr(C)] -pub struct __jmp_buf { - rip: usize, - rsp: usize, - r15: usize, - r14: usize, - r13: usize, - r12: usize, - rbp: usize, - rbx: usize, +pub type __jmp_buf = [usize; 8]; + +#[no_mangle] +#[naked] +unsafe extern "C" fn setjmp(buf: __jmp_buf) -> c_int { + // %rdi -- jmp_buf pointer + core::arch::naked_asm!( + r#" + // Preserve callee-saved registers + movq %rbx, 0(%rdi) // jmp_buf[0] = %rbx + movq %rbp, 8(%rdi) // jmp_buf[1] = %rbp + movq %r12, 16(%rdi) // jmp_buf[2] = %r12 + movq %r13, 24(%rdi) // jmp_buf[3] = %r13 + movq %r14, 32(%rdi) // jmp_buf[4] = %r14 + movq %r15, 40(%rdi) // jmp_buf[5] = %r15 + // Calculate return stack and rip + leaq 8(%rsp), %rax + movq %rax, 48(%rdi) // jmp_buf[6] = %rsp + 8 (return stack) + movq (%rsp), %rax // jmp_buf[7] = return address + movq %rax, 56(%rdi) + + movq $0, %rax + ret + "#, + options(att_syntax) + ) } -global_asm!(include_str!("x86_64.S"), options(att_syntax)); +#[no_mangle] +#[naked] +unsafe extern "C" fn longjmp(buf: __jmp_buf, val: c_int) -> c_int { + // %rdi -- jmp_buf pointer + // %rsi -- return value + core::arch::naked_asm!(r#" + // Restore the registers + movq 0(%rdi), %rbx + movq 8(%rdi), %rbp + movq 16(%rdi), %r12 + movq 24(%rdi), %r13 + movq 32(%rdi), %r14 + movq 40(%rdi), %r15 + movq 48(%rdi), %rsp + movq 56(%rdi), %rax + pushq %rax // Setup fake return address + + // Setup return value + movq %rsi, %rax + + ret + "#, options(att_syntax)) +} diff --git a/userspace/lib/ygglibc/src/headers/signal/cbindgen.toml b/userspace/lib/ygglibc/src/headers/signal/cbindgen.toml index 6c040ee4..677d0f45 100644 --- a/userspace/lib/ygglibc/src/headers/signal/cbindgen.toml +++ b/userspace/lib/ygglibc/src/headers/signal/cbindgen.toml @@ -1,9 +1,10 @@ language = "C" -style = "Type" +style = "Tag" sys_includes = [ "stddef.h", "stdint.h", + "time.h", "sys/types.h", "bits/signal.h" ] @@ -15,5 +16,5 @@ usize_type = "size_t" isize_type = "ssize_t" [export] -include = ["sig_handler_t", "SIGABRT"] +include = ["sig_handler_t", "sigaction", "sigevent", "SIGABRT"] exclude = [] diff --git a/userspace/lib/ygglibc/src/headers/signal/mod.rs b/userspace/lib/ygglibc/src/headers/signal/mod.rs index 48db559b..44fbab7f 100644 --- a/userspace/lib/ygglibc/src/headers/signal/mod.rs +++ b/userspace/lib/ygglibc/src/headers/signal/mod.rs @@ -1,11 +1,59 @@ -use core::ffi::c_int; +use core::ffi::{c_char, c_int, c_long, c_void}; use yggdrasil_rt::process::Signal; -use super::sys_types::pid_t; +use super::{ + sys_time::__ygg_timespec_t, + sys_types::{pid_t, uid_t}, +}; pub type sig_handler_t = unsafe extern "C" fn(SigNumber); +pub type sigset_t = u64; + +#[repr(C)] +pub struct sigevent { + pub sigev_notify: c_int, + pub sigev_signo: c_int, + pub sigev_value: sigval, + pub sigev_notify_function: unsafe extern "C" fn(sigval), + // TODO pthread_attr_t * + pub sigev_notify_attributes: *mut c_void, +} + +#[repr(C)] +pub struct sigaction { + pub sa_handler: unsafe extern "C" fn(c_int), + pub sa_mask: sigset_t, + pub sa_flags: c_int, + pub sa_sigaction: unsafe extern "C" fn(c_int, *mut siginfo_t, *mut c_void), +} + +#[repr(C)] +pub struct siginfo { + pub si_signo: c_int, + pub si_code: c_int, + pub si_errno: c_int, + pub si_pid: pid_t, + pub si_uid: uid_t, + pub si_addr: *mut c_void, + pub si_status: c_int, + pub si_band: c_long, + pub si_value: sigval, +} + +pub type siginfo_t = siginfo; + +#[repr(C)] +pub union sigval { + pub sival_int: c_int, + pub sival_ptr: *mut c_void, +} + +// TODO sig_atomic_t + +// SIG_DFL, SIG_ERR, SIG_HOLD, SIG_IGN are in + extern "C" { fn __sig_terminate(_: SigNumber); fn __sig_ignore(_: SigNumber); @@ -15,6 +63,10 @@ extern "C" { #[repr(transparent)] pub struct SigNumber(pub c_int); +pub const SIGEV_NONE: c_int = 0; +pub const SIGEV_SIGNAL: c_int = 1; +pub const SIGEV_THREAD: c_int = 2; + // TODO generate these based on the ABI pub const SIGSEGV: SigNumber = SigNumber(1); pub const SIGABRT: SigNumber = SigNumber(2); @@ -77,30 +129,159 @@ impl From for SigNumber { } #[no_mangle] -unsafe extern "C" fn kill(_pid: pid_t, _signum: SigNumber) -> c_int { +unsafe extern "C" fn kill(_pid: pid_t, _signum: c_int) -> c_int { todo!() } #[no_mangle] -unsafe extern "C" fn killpg(_pid: pid_t, _signum: SigNumber) -> c_int { +unsafe extern "C" fn killpg(_pgid: pid_t, _signum: c_int) -> c_int { todo!() } #[no_mangle] -unsafe extern "C" fn raise(_signum: SigNumber) -> c_int { +unsafe extern "C" fn psiginfo(_info: *const siginfo_t, _m: *const c_char) { todo!() } #[no_mangle] -unsafe extern "C" fn signal(_signum: SigNumber, _handler: sig_handler_t) -> sig_handler_t { +unsafe extern "C" fn psignal(_signum: c_int, _m: *const c_char) { + todo!() +} + +// TODO pthread_t +#[no_mangle] +unsafe extern "C" fn pthread_kill(_pt: *mut c_void, _signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn pthread_sigmask( + _a: c_int, + _new: *const sigset_t, + _old: *mut sigset_t, +) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn raise(_signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigaction( + _signum: c_int, + _new: *const sigaction, + _old: *mut sigaction, +) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigaddset(_mask: *mut sigset_t, _signum: c_int) -> c_int { + todo!() +} + +// TODO: stack_t +#[no_mangle] +unsafe extern "C" fn sigaltstack(_new: *const c_void, _old: *const c_void) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigdelset(_mask: *mut sigset_t, _signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigemptyset(_mask: *mut sigset_t) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigfillset(_mask: *mut sigset_t) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sighold(_signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigignore(_signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn siginterrupt(_signum: c_int, _b: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigismember(_mask: *const sigset_t, _signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn signal(_handler: sig_handler_t, _signum: c_int) -> sig_handler_t { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigpause(_signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigpending(_mask: *mut sigset_t) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigprocmask( + _signum: c_int, + _new: *const sigset_t, + _old: *mut sigset_t, +) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigqueue(_pid: pid_t, _signum: c_int, _val: sigval) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigrelse(_signum: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigset(_signum: c_int, _handler: sig_handler_t) -> sig_handler_t { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigsuspend(_mask: *const sigset_t) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigtimedwait( + _mask: *const sigset_t, + _info: *mut siginfo_t, + _time: *const __ygg_timespec_t, +) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigwait(_mask: *const sigset_t, _signum: *mut c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn sigwaitinfo(_mask: *const sigset_t, _info: *mut siginfo_t) -> c_int { todo!() - // // NOTE handler might be NULL, so check that - // let Ok(signal) = Signal::try_from(signum) else { - // // Ignore - // return __sig_terminate; - // }; - // let handler_ptr = handler as usize; - // let handler = (handler_ptr != 0).then_some(handler); - - // signal::set_handler(signal, handler) } diff --git a/userspace/lib/ygglibc/src/headers/stdlib/io.rs b/userspace/lib/ygglibc/src/headers/stdlib/io.rs index 7f6fdffa..7cb54562 100644 --- a/userspace/lib/ygglibc/src/headers/stdlib/io.rs +++ b/userspace/lib/ygglibc/src/headers/stdlib/io.rs @@ -1,8 +1,36 @@ +use core::ffi::{c_char, c_int}; -// int grantpt(int); -// char *mkdtemp(char *); -// int mkstemp(char *); -// int posix_openpt(int); -// char *ptsname(int); -// char *realpath(const char *restrict, char *restrict); -// int unlockpt(int); +#[no_mangle] +unsafe extern "C" fn grantpt(_fd: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn mkdtemp(_template: *mut c_char) -> *mut c_char { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn mkstemp(_template: *mut c_char) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn posix_openpt(_fd: c_int) -> c_int { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn ptsname(_fd: c_int) -> *mut c_char { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn realpath(_path: *const c_char, _resolved: *mut c_char) -> *mut c_char { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn unlockpt(_fd: c_int) -> c_int { + todo!() +} diff --git a/userspace/lib/ygglibc/src/headers/time/mod.rs b/userspace/lib/ygglibc/src/headers/time/mod.rs index 6c74a13f..7ca4bd04 100644 --- a/userspace/lib/ygglibc/src/headers/time/mod.rs +++ b/userspace/lib/ygglibc/src/headers/time/mod.rs @@ -6,7 +6,7 @@ use core::{ use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc}; -use super::{sys_time::__ygg_timespec_t, sys_types::time_t}; +use super::{sys_time::__ygg_timespec_t, sys_types::{clock_t, clockid_t, time_t}}; mod convert; mod string; @@ -36,6 +36,15 @@ pub struct tm { pub type __ygg_tm_t = tm; +pub const CLOCKS_PER_SEC: clock_t = 1000000; + +pub const CLOCK_MONOTONIC: clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; +pub const CLOCK_REALTIME: clockid_t = 3; +pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 4; + +pub const TIMER_ABSTIME: c_int = 1 << 0; + #[no_mangle] pub static mut daylight: c_int = 0; #[no_mangle] diff --git a/userspace/lib/ygglibc/src/headers/time/util.rs b/userspace/lib/ygglibc/src/headers/time/util.rs index 6e0782af..c4cdb9d2 100644 --- a/userspace/lib/ygglibc/src/headers/time/util.rs +++ b/userspace/lib/ygglibc/src/headers/time/util.rs @@ -25,7 +25,7 @@ unsafe extern "C" fn nanosleep( #[no_mangle] unsafe extern "C" fn time(_tp: *mut time_t) -> time_t { - todo!() + time_t(0) } #[no_mangle] diff --git a/userspace/lib/ygglibc/src/lib.rs b/userspace/lib/ygglibc/src/lib.rs index d929dd2e..4c29f6d8 100644 --- a/userspace/lib/ygglibc/src/lib.rs +++ b/userspace/lib/ygglibc/src/lib.rs @@ -8,7 +8,8 @@ maybe_uninit_slice, slice_internals, linkage, - rustc_private + rustc_private, + naked_functions )] #![allow(internal_features)] #![cfg_attr(not(test), no_std)] diff --git a/userspace/lib/ygglibc/src/panic.rs b/userspace/lib/ygglibc/src/panic.rs index aed38e60..df0b5572 100644 --- a/userspace/lib/ygglibc/src/panic.rs +++ b/userspace/lib/ygglibc/src/panic.rs @@ -1,7 +1,88 @@ +use core::{fmt, sync::atomic::AtomicUsize}; + +use crate::io::{managed::{stderr, FILE}, Write}; + +struct PanicPrinter { + buffer: [u8; 1024], + pos: usize, + + print: Option<&'static mut FILE> +} + +impl fmt::Write for PanicPrinter { + fn write_str(&mut self, s: &str) -> fmt::Result { + for ch in s.bytes() { + self.push(ch); + } + Ok(()) + } +} + +impl PanicPrinter { + pub fn new() -> Self { + let print = unsafe { stderr.as_mut() }; + + Self { + buffer: [0; 1024], + pos: 0, + print, + } + } + + fn flush(&mut self) { + let text = &self.buffer[..self.pos]; + if !text.is_empty() { + // Print to debug trace + unsafe { yggdrasil_rt::debug::trace_raw(text) }; + + // Print to stderr + if let Some(print) = self.print.as_mut() { + print.write_all(text).ok(); + print.write_all(b"\n").ok(); + } + } + + self.pos = 0; + } + + pub fn push(&mut self, ch: u8) { + if self.pos >= self.buffer.len() { + return; + } + + if ch == b'\n' { + self.flush(); + } else { + self.buffer[self.pos] = ch; + self.pos += 1; + } + } +} + +static PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); + #[cfg(any(not(test), rust_analyzer))] #[panic_handler] fn panic_handler(pi: &core::panic::PanicInfo) -> ! { - yggdrasil_rt::debug_trace!("PANIC {:?}", &pi); + use core::{fmt::Write, sync::atomic::Ordering}; + + match PANIC_COUNT.fetch_add(1, Ordering::Relaxed) { + 0 => { + let mut printer = PanicPrinter::new(); + + writeln!(printer, "!!! ygglibc panic !!!").ok(); + if let Some(location) = pi.location() { + writeln!(printer, "{}:{}:", location.file(), location.line()).ok(); + } + writeln!(printer, " {}", pi.message()); + + printer.flush(); + } + 1 => unsafe { + yggdrasil_rt::debug_trace!("!!! ygglibc panicked while panicking !!!"); + } + _ => {} + } // Kill myself super::process::abort(); diff --git a/xtask/src/build/userspace.rs b/xtask/src/build/userspace.rs index fe4fd1f4..bdac79bc 100644 --- a/xtask/src/build/userspace.rs +++ b/xtask/src/build/userspace.rs @@ -196,6 +196,11 @@ pub fn build_initrd( build_userspace(env, &mut install_extra, check)?; + install_extra.push(( + "toolchain-c/programs/lua-5.4.7/src/lua".into(), + "lua".into(), + )); + build_rootfs( env, install_extra,