1 // Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs 2 3 use alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, string::String, vec::Vec}; 4 5 use crate::{ 6 c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex, 7 }; 8 9 use super::{ 10 debug::_r_debug, 11 linker::{Linker, DSO}, 12 tcb::Tcb, 13 }; 14 use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR}; 15 16 unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) { 17 //traverse the stack and collect argument vector 18 let mut argv = Vec::new(); 19 while *ptr != 0 { 20 let arg = *ptr; 21 match CStr::from_ptr(arg as *const c_char).to_str() { 22 Ok(arg_str) => argv.push(arg_str.to_owned()), 23 _ => { 24 eprintln!("ld.so: failed to parse argv[{}]", argv.len()); 25 unistd::_exit(1); 26 loop {} 27 } 28 } 29 ptr = ptr.add(1); 30 } 31 return (argv, ptr); 32 } 33 34 unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const usize) { 35 //traverse the stack and collect argument environment variables 36 let mut envs = BTreeMap::new(); 37 while *ptr != 0 { 38 let env = *ptr; 39 if let Ok(arg_str) = CStr::from_ptr(env as *const c_char).to_str() { 40 let mut parts = arg_str.splitn(2, '='); 41 if let Some(key) = parts.next() { 42 if let Some(value) = parts.next() { 43 envs.insert(key.to_owned(), value.to_owned()); 44 } 45 } 46 } 47 ptr = ptr.add(1); 48 } 49 return (envs, ptr); 50 } 51 52 unsafe fn get_auxv(mut ptr: *const usize) -> BTreeMap<usize, usize> { 53 //traverse the stack and collect argument environment variables 54 let mut auxv = BTreeMap::new(); 55 while *ptr != 0 { 56 let kind = *ptr; 57 ptr = ptr.add(1); 58 let value = *ptr; 59 ptr = ptr.add(1); 60 auxv.insert(kind, value); 61 } 62 return auxv; 63 } 64 65 unsafe fn adjust_stack(sp: &'static mut Stack) { 66 let mut argv = sp.argv() as *mut usize; 67 68 // Move arguments 69 loop { 70 let next_argv = argv.add(1); 71 let arg = *next_argv; 72 *argv = arg; 73 argv = next_argv; 74 if arg == 0 { 75 break; 76 } 77 } 78 79 // Move environment 80 loop { 81 let next_argv = argv.add(1); 82 let arg = *next_argv; 83 *argv = arg; 84 argv = next_argv; 85 if arg == 0 { 86 break; 87 } 88 if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() { 89 let mut parts = arg_str.splitn(2, '='); 90 if let Some(key) = parts.next() { 91 if let Some(value) = parts.next() { 92 if let "LD_LIBRARY_PATH" = key { 93 //library_path = value 94 } 95 } 96 } 97 } 98 } 99 100 // Move auxiliary vectors 101 loop { 102 let next_argv = argv.add(1); 103 let kind = *next_argv; 104 *argv = kind; 105 argv = next_argv; 106 let next_argv = argv.add(1); 107 let value = *next_argv; 108 *argv = value; 109 argv = next_argv; 110 if kind == 0 { 111 break; 112 } 113 } 114 115 sp.argc -= 1; 116 } 117 #[no_mangle] 118 pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize { 119 // first we get the arguments, the environment, and the auxilary vector 120 let (argv, envs, auxv) = unsafe { 121 let argv_start = sp.argv() as *mut usize; 122 let (argv, argv_end) = get_argv(argv_start); 123 let (envs, envs_end) = get_env(argv_end.add(1)); 124 let auxv = get_auxv(envs_end.add(1)); 125 (argv, envs, auxv) 126 }; 127 128 let is_manual = if let Some(img_entry) = auxv.get(&AT_ENTRY) { 129 *img_entry == ld_entry 130 } else { 131 true 132 }; 133 134 // we might need global lock for this kind of stuff 135 unsafe { 136 _r_debug.r_ldbase = ld_entry; 137 } 138 139 // Some variables that will be overridden by environment and auxiliary vectors 140 let library_path = match envs.get("LD_LIBRARY_PATH") { 141 Some(lib_path) => lib_path, 142 None => "/lib", 143 }; 144 145 let path = if is_manual { 146 // ld.so is run directly by user and not via execve() or similar systemcall 147 println!("argv: {:#?}", argv); 148 println!("envs: {:#?}", envs); 149 println!("auxv: {:#x?}", auxv); 150 151 if sp.argc < 2 { 152 eprintln!("ld.so [executable] [arguments...]"); 153 unistd::_exit(1); 154 loop {} 155 } 156 unsafe { adjust_stack(sp) }; 157 &argv[1] 158 } else { 159 &argv[0] 160 }; 161 // if we are not running in manual mode, then the main 162 // program is already loaded by the kernel and we want 163 // to use it. 164 let program = { 165 let mut pr = None; 166 if !is_manual { 167 let phdr = *auxv.get(&AT_PHDR).unwrap(); 168 if phdr != 0 { 169 let p = DSO { 170 name: path.to_owned(), 171 entry_point: *auxv.get(&AT_ENTRY).unwrap(), 172 // The 0x40 is the size of Elf header not a good idea for different bit size 173 // compatiablility but it will always work on 64 bit systems, 174 base_addr: phdr - 0x40, 175 }; 176 pr = Some(p); 177 } 178 } 179 pr 180 }; 181 let mut linker = Linker::new(library_path, false); 182 match linker.load(&path, &path) { 183 Ok(()) => (), 184 Err(err) => { 185 eprintln!("ld.so: failed to load '{}': {}", path, err); 186 unistd::_exit(1); 187 loop {} 188 } 189 } 190 191 let entry = match linker.link(Some(&path), program) { 192 Ok(ok) => match ok { 193 Some(some) => some, 194 None => { 195 eprintln!("ld.so: failed to link '{}': missing entry", path); 196 unistd::_exit(1); 197 loop {} 198 } 199 }, 200 Err(err) => { 201 eprintln!("ld.so: failed to link '{}': {}", path, err); 202 unistd::_exit(1); 203 loop {} 204 } 205 }; 206 if let Err(e) = linker.run_init() { 207 eprintln!("ld.so: failed to run .init_array"); 208 unistd::_exit(1); 209 loop {} 210 } 211 if let Some(tcb) = unsafe { Tcb::current() } { 212 tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); 213 } 214 if is_manual { 215 eprintln!("ld.so: entry '{}': {:#x}", path, entry); 216 } 217 entry 218 } 219