Skip to content
Snippets Groups Projects
start.rs 2.51 KiB
Newer Older
use alloc::vec::Vec;
Jeremy Soller's avatar
Jeremy Soller committed
use core::ptr;

Jeremy Soller's avatar
Jeremy Soller committed
use header::{stdio, stdlib};
Jeremy Soller's avatar
Jeremy Soller committed
use platform::types::*;

#[repr(C)]
pub struct Stack {
    argc: isize,
    argv0: *const c_char,
}

impl Stack {
    fn argc(&self) -> isize {
        self.argc
    }

    fn argv(&self) -> *const *const c_char {
        &self.argv0 as *const _
    }

    fn envp(&self) -> *const *const c_char {
        unsafe { self.argv().offset(self.argc() + 1) }
    }
}

Jeremy Soller's avatar
Jeremy Soller committed
unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char> {
    let mut vec = Vec::with_capacity(len + 1);
    for i in 0..len {
        let mut item = *array.add(i);
        let mut len = 0;
        while *item.add(len) != 0 {
            len += 1;
        }

        let buf = platform::alloc(len + 1) as *mut c_char;
        for i in 0..=len {
            *buf.add(i) = *item.add(i);
        }
        vec.push(buf);
    }
    vec.push(ptr::null_mut());
    vec
}

Jeremy Soller's avatar
Jeremy Soller committed
#[inline(never)]
#[no_mangle]
pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
Jeremy Soller's avatar
Jeremy Soller committed
    extern "C" {
        static __preinit_array_start: extern "C" fn();
Jeremy Soller's avatar
Jeremy Soller committed
        static __preinit_array_end: extern "C" fn();
        static __init_array_start: extern "C" fn();
        static __init_array_end: extern "C" fn();
Jeremy Soller's avatar
Jeremy Soller committed
        fn _init();
Jeremy Soller's avatar
Jeremy Soller committed
        fn main(argc: isize, argv: *mut *mut c_char, envp: *mut *mut c_char) -> c_int;
Jeremy Soller's avatar
Jeremy Soller committed
    }

    let argc = sp.argc();
    let argv = sp.argv();

Jeremy Soller's avatar
Jeremy Soller committed
    platform::inner_argv = copy_string_array(argv, argc as usize);
    platform::argv = platform::inner_argv.as_mut_ptr();

Jeremy Soller's avatar
Jeremy Soller committed
    let envp = sp.envp();
    let mut len = 0;
Jeremy Soller's avatar
Jeremy Soller committed
    while ! (*envp.add(len)).is_null() {
Jeremy Soller's avatar
Jeremy Soller committed
        len += 1;
    }
Jeremy Soller's avatar
Jeremy Soller committed
    platform::inner_environ = copy_string_array(envp, len);
Jeremy Soller's avatar
Jeremy Soller committed
    platform::environ = platform::inner_environ.as_mut_ptr();

    // Initialize stdin/stdout/stderr, see https://github.com/rust-lang/rust/issues/51718
    stdio::stdin = stdio::default_stdin.get();
    stdio::stdout = stdio::default_stdout.get();
    stdio::stderr = stdio::default_stderr.get();

Jeremy Soller's avatar
Jeremy Soller committed
    _init();

    // Look for the neighbor functions in memory until the end
    let mut f = &__preinit_array_start as *const _;
    while f < &__preinit_array_end {
        (*f)();
        f = f.offset(1);
    }
    f = &__init_array_start as *const _;
    while f < &__init_array_end {
        (*f)();
        f = f.offset(1);
    }

Jeremy Soller's avatar
Jeremy Soller committed
    // not argv or envp, because programs like bash try to modify this *const* pointer :|
Jeremy Soller's avatar
Jeremy Soller committed
    stdlib::exit(main(
Jeremy Soller's avatar
Jeremy Soller committed
        argc,
Jeremy Soller's avatar
Jeremy Soller committed
        platform::argv,
        platform::environ,
Jeremy Soller's avatar
Jeremy Soller committed
    ));
Jeremy Soller's avatar
Jeremy Soller committed

    unreachable!();
Jeremy Soller's avatar
Jeremy Soller committed
}