1 use alloc::{boxed::Box, vec::Vec}; 2 use core::{fmt::Debug, intrinsics, ptr}; 3 4 use crate::{ 5 header::{libgen, stdio, stdlib}, 6 ld_so::{self, linker::Linker,init}, 7 platform::{self, get_auxvs, new_mspace, types::*, Pal, Sys}, 8 sync::mutex::Mutex, 9 ALLOCATOR, 10 alloc, 11 }; 12 13 #[repr(C)] 14 pub struct Stack { 15 pub argc: isize, 16 pub argv0: *const c_char, 17 } 18 19 impl Stack { 20 pub fn argv(&self) -> *const *const c_char { 21 &self.argv0 as *const _ 22 } 23 24 pub fn envp(&self) -> *const *const c_char { 25 unsafe { self.argv().offset(self.argc + 1) } 26 } 27 28 pub fn auxv(&self) -> *const (usize, usize) { 29 unsafe { 30 let mut envp = self.envp(); 31 while !(*envp).is_null() { 32 envp = envp.add(1); 33 } 34 envp.add(1) as *const (usize, usize) 35 } 36 } 37 } 38 39 impl Debug for Stack { 40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 41 f.debug_struct("Stack") 42 .field("argc", &self.argc) 43 .field("argv0", &self.argv0) 44 .finish() 45 } 46 } 47 48 unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char> { 49 // println!("copy_string_array: array: {:p}, len: {}", array, len); 50 51 let mut vec = Vec::with_capacity(len + 1); 52 53 for i in 0..len { 54 let item = *array.add(i); 55 let mut len = 0; 56 while *item.add(len) != 0 { 57 len += 1; 58 } 59 60 let buf = platform::alloc(len + 1) as *mut c_char; 61 for i in 0..=len { 62 *buf.add(i) = *item.add(i); 63 } 64 vec.push(buf); 65 } 66 vec.push(ptr::null_mut()); 67 vec 68 } 69 70 // Since Redox and Linux are so similar, it is easy to accidentally run a binary from one on the 71 // other. This will test that the current system is compatible with the current binary 72 #[no_mangle] 73 pub unsafe fn relibc_verify_host() { 74 if !Sys::verify() { 75 intrinsics::abort(); 76 } 77 } 78 #[link_section = ".init_array"] 79 #[used] 80 static INIT_ARRAY: [extern "C" fn(); 1] = [init_array]; 81 82 static mut init_complete: bool = false; 83 84 #[used] 85 #[no_mangle] 86 static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut(); 87 88 fn alloc_init() { 89 unsafe { 90 if init_complete { 91 return; 92 } 93 } 94 unsafe { 95 // dbg!("in alloc init"); 96 if let Some(tcb) = ld_so::tcb::Tcb::current() { 97 // println!("tcb.mspace {}",tcb.mspace); 98 if tcb.mspace != 0 { 99 ALLOCATOR.set_book_keeper(tcb.mspace); 100 } else if ALLOCATOR.get_book_keeper() == 0 { 101 ALLOCATOR.set_book_keeper(new_mspace()); 102 } 103 } else if ALLOCATOR.get_book_keeper() == 0 { 104 // dbg!("TRY"); 105 ALLOCATOR.set_book_keeper(new_mspace()); 106 // dbg!("ALLOCATOR OWARI DAWA"); 107 } 108 } 109 } 110 111 extern "C" fn init_array() { 112 // The thing is that we cannot guarantee if 113 // init_array runs first or if relibc_start runs first 114 // Still whoever gets to run first must initialize rust 115 // memory allocator before doing anything else. 116 117 unsafe { 118 if init_complete { 119 return; 120 } 121 } 122 123 alloc_init(); 124 io_init(); 125 126 unsafe { 127 if platform::environ.is_null() { 128 platform::environ = __relibc_init_environ; 129 } 130 } 131 132 // extern "C" { 133 // fn pthread_init(); 134 // } 135 // unsafe { 136 // pthread_init(); 137 // init_complete = true 138 // } 139 } 140 141 fn io_init() { 142 unsafe { 143 // Initialize stdin/stdout/stderr, 144 // see https://github.com/rust-lang/rust/issues/51718 145 stdio::stdin = stdio::default_stdin.get(); 146 stdio::stdout = stdio::default_stdout.get(); 147 stdio::stderr = stdio::default_stderr.get(); 148 } 149 } 150 151 #[cfg(target_os = "redox")] 152 fn setup_sigstack() { 153 use syscall::{Map, MapFlags}; 154 const SIGSTACK_SIZE: usize = 1024 * 256; 155 let sigstack = unsafe { 156 syscall::fmap( 157 !0, 158 &Map { 159 address: 0, 160 offset: 0, 161 flags: MapFlags::MAP_PRIVATE | MapFlags::PROT_READ | MapFlags::PROT_WRITE, 162 size: SIGSTACK_SIZE, 163 }, 164 ) 165 } 166 .expect("failed to allocate sigstack") 167 + SIGSTACK_SIZE; 168 169 let fd = syscall::open( 170 "thisproc:current/sigstack", 171 syscall::O_WRONLY | syscall::O_CLOEXEC, 172 ) 173 .expect("failed to open thisproc:current/sigstack"); 174 syscall::write(fd, &usize::to_ne_bytes(sigstack)) 175 .expect("failed to write to thisproc:current/sigstack"); 176 let _ = syscall::close(fd); 177 } 178 179 #[inline(never)] 180 #[no_mangle] 181 pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { 182 extern "C" { 183 static __preinit_array_start: extern "C" fn(); 184 static __preinit_array_end: extern "C" fn(); 185 static __init_array_start: extern "C" fn(); 186 static __init_array_end: extern "C" fn(); 187 188 fn _init(); 189 fn main(); 190 } 191 192 // Ensure correct host system before executing more system calls 193 relibc_verify_host(); 194 use core::arch::asm; 195 196 // Initialize TLS, if necessary 197 ld_so::init(sp); 198 199 // println!("alloc init"); 200 201 // Set up the right allocator... 202 // if any memory rust based memory allocation happen before this step .. we are doomed. 203 alloc_init(); 204 205 // println!("alloc init ok"); 206 207 if let Some(tcb) = ld_so::tcb::Tcb::current() { 208 // Update TCB mspace 209 tcb.mspace = ALLOCATOR.get_book_keeper(); 210 211 // Set linker pointer if necessary 212 if tcb.linker_ptr.is_null() { 213 //TODO: get ld path 214 let linker = Linker::new(None); 215 //TODO: load root object 216 tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); 217 } 218 } 219 220 // println!("to copy args"); 221 // Set up argc and argv 222 let argc = sp.argc; 223 let argv = sp.argv(); 224 225 platform::inner_argv = copy_string_array(argv, argc as usize); 226 227 // println!("copy args ok"); 228 platform::argv = platform::inner_argv.as_mut_ptr(); 229 // Special code for program_invocation_name and program_invocation_short_name 230 if let Some(arg) = platform::inner_argv.get(0) { 231 platform::program_invocation_name = *arg; 232 platform::program_invocation_short_name = libgen::basename(*arg); 233 } 234 // println!("to check environ"); 235 236 // We check for NULL here since ld.so might already have initialized it for us, and we don't 237 // want to overwrite it if constructors in .init_array of dependency libraries have called 238 // setenv. 239 if platform::environ.is_null() { 240 // Set up envp 241 let envp = sp.envp(); 242 let mut len = 0; 243 while !(*envp.add(len)).is_null() { 244 len += 1; 245 } 246 platform::OUR_ENVIRON = copy_string_array(envp, len); 247 platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); 248 } 249 // println!("to get auxvs"); 250 let auxvs = get_auxvs(sp.auxv().cast()); 251 // println!("to init platform"); 252 crate::platform::init(auxvs); 253 254 // Setup signal stack, otherwise we cannot handle any signals besides SIG_IGN/SIG_DFL behavior. 255 #[cfg(target_os = "redox")] 256 setup_sigstack(); 257 // println!("before init_array()"); 258 init_array(); 259 // println!("init_array() ok"); 260 261 // Run preinit array 262 { 263 let mut f = &__preinit_array_start as *const _; 264 #[allow(clippy::op_ref)] 265 while f < &__preinit_array_end { 266 (*f)(); 267 f = f.offset(1); 268 } 269 } 270 271 // println!("before _init()"); 272 // Call init section 273 _init(); 274 // println!("after _init()"); 275 // Run init array 276 { 277 let mut f = &__init_array_start as *const _; 278 #[allow(clippy::op_ref)] 279 while f < &__init_array_end { 280 (*f)(); 281 f = f.offset(1); 282 } 283 } 284 285 // println!("to run main()"); 286 main(); 287 // not argv or envp, because programs like bash try to modify this *const* pointer :| 288 stdlib::exit(0); 289 290 unreachable!(); 291 } 292