|
@@ -1,103 +1,157 @@
|
|
|
// Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs
|
|
|
|
|
|
-use alloc::boxed::Box;
|
|
|
-
|
|
|
-use crate::{c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex};
|
|
|
-
|
|
|
-use super::linker::Linker;
|
|
|
-use super::tcb::Tcb;
|
|
|
-
|
|
|
-#[no_mangle]
|
|
|
-pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
|
|
|
- if sp.argc < 2 {
|
|
|
- eprintln!("ld.so [executable] [arguments...]");
|
|
|
- unistd::_exit(1);
|
|
|
- loop {}
|
|
|
- }
|
|
|
-
|
|
|
- // Some variables that will be overridden by environment and auxiliary vectors
|
|
|
- let mut library_path = "/lib";
|
|
|
- //let mut page_size = 4096;
|
|
|
-
|
|
|
- // Pop the first argument (path to ld_so), and get the path of the program
|
|
|
- let path_c = unsafe {
|
|
|
- let mut argv = sp.argv() as *mut usize;
|
|
|
-
|
|
|
- // Move arguments
|
|
|
- loop {
|
|
|
- let next_argv = argv.add(1);
|
|
|
- let arg = *next_argv;
|
|
|
- *argv = arg;
|
|
|
- argv = next_argv;
|
|
|
- if arg == 0 {
|
|
|
- break;
|
|
|
+use alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, string::String, vec::Vec};
|
|
|
+
|
|
|
+use crate::{
|
|
|
+ c_str::CStr, header::unistd, platform::types::c_char, start::Stack, sync::mutex::Mutex,
|
|
|
+};
|
|
|
+
|
|
|
+use super::{linker::Linker, tcb::Tcb};
|
|
|
+use crate::header::sys_auxv::AT_ENTRY;
|
|
|
+
|
|
|
+unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
|
|
|
+ //traverse the stack and collect argument vector
|
|
|
+ let mut argv = Vec::new();
|
|
|
+ while *ptr != 0 {
|
|
|
+ let arg = *ptr;
|
|
|
+ match CStr::from_ptr(arg as *const c_char).to_str() {
|
|
|
+ Ok(arg_str) => argv.push(arg_str.to_owned()),
|
|
|
+ _ => {
|
|
|
+ eprintln!("ld.so: failed to parse argv[{}]", argv.len());
|
|
|
+ unistd::_exit(1);
|
|
|
+ loop {}
|
|
|
}
|
|
|
+ }
|
|
|
+ ptr = ptr.add(1);
|
|
|
+ }
|
|
|
+ return (argv, ptr);
|
|
|
+}
|
|
|
|
|
|
- if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
|
|
- println!(" arg: '{}'", arg_str);
|
|
|
+unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const usize) {
|
|
|
+ //traverse the stack and collect argument environment variables
|
|
|
+ let mut envs = BTreeMap::new();
|
|
|
+ while *ptr != 0 {
|
|
|
+ let env = *ptr;
|
|
|
+ if let Ok(arg_str) = CStr::from_ptr(env as *const c_char).to_str() {
|
|
|
+ let mut parts = arg_str.splitn(2, '=');
|
|
|
+ if let Some(key) = parts.next() {
|
|
|
+ if let Some(value) = parts.next() {
|
|
|
+ envs.insert(key.to_owned(), value.to_owned());
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ ptr = ptr.add(1);
|
|
|
+ }
|
|
|
+ return (envs, ptr);
|
|
|
+}
|
|
|
|
|
|
- // Move environment
|
|
|
- loop {
|
|
|
- let next_argv = argv.add(1);
|
|
|
- let arg = *next_argv;
|
|
|
- *argv = arg;
|
|
|
- argv = next_argv;
|
|
|
- if arg == 0 {
|
|
|
- break;
|
|
|
- }
|
|
|
+unsafe fn get_auxv(mut ptr: *const usize) -> BTreeMap<usize, usize> {
|
|
|
+ //traverse the stack and collect argument environment variables
|
|
|
+ let mut auxv = BTreeMap::new();
|
|
|
+ while *ptr != 0 {
|
|
|
+ let kind = *ptr;
|
|
|
+ ptr = ptr.add(1);
|
|
|
+ let value = *ptr;
|
|
|
+ ptr = ptr.add(1);
|
|
|
+ auxv.insert(kind, value);
|
|
|
+ }
|
|
|
+ return auxv;
|
|
|
+}
|
|
|
|
|
|
- if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
|
|
- println!(" env: '{}'", arg_str);
|
|
|
+unsafe fn adjust_stack(sp: &'static mut Stack) {
|
|
|
+ let mut argv = sp.argv() as *mut usize;
|
|
|
+
|
|
|
+ // Move arguments
|
|
|
+ loop {
|
|
|
+ let next_argv = argv.add(1);
|
|
|
+ let arg = *next_argv;
|
|
|
+ *argv = arg;
|
|
|
+ argv = next_argv;
|
|
|
+ if arg == 0 {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- let mut parts = arg_str.splitn(2, '=');
|
|
|
- if let Some(key) = parts.next() {
|
|
|
- if let Some(value) = parts.next() {
|
|
|
- if let "LD_LIBRARY_PATH" = key {
|
|
|
- library_path = value
|
|
|
- }
|
|
|
+ // Move environment
|
|
|
+ loop {
|
|
|
+ let next_argv = argv.add(1);
|
|
|
+ let arg = *next_argv;
|
|
|
+ *argv = arg;
|
|
|
+ argv = next_argv;
|
|
|
+ if arg == 0 {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if let Ok(arg_str) = CStr::from_ptr(arg as *const c_char).to_str() {
|
|
|
+ let mut parts = arg_str.splitn(2, '=');
|
|
|
+ if let Some(key) = parts.next() {
|
|
|
+ if let Some(value) = parts.next() {
|
|
|
+ if let "LD_LIBRARY_PATH" = key {
|
|
|
+ //library_path = value
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // Move auxiliary vectors
|
|
|
- loop {
|
|
|
- let next_argv = argv.add(1);
|
|
|
- let kind = *next_argv;
|
|
|
- *argv = kind;
|
|
|
- argv = next_argv;
|
|
|
+ // Move auxiliary vectors
|
|
|
+ loop {
|
|
|
+ let next_argv = argv.add(1);
|
|
|
+ let kind = *next_argv;
|
|
|
+ *argv = kind;
|
|
|
+ argv = next_argv;
|
|
|
+ let next_argv = argv.add(1);
|
|
|
+ let value = *next_argv;
|
|
|
+ *argv = value;
|
|
|
+ argv = next_argv;
|
|
|
+ if kind == 0 {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- let next_argv = argv.add(1);
|
|
|
- let value = *next_argv;
|
|
|
- *argv = value;
|
|
|
- argv = next_argv;
|
|
|
+ sp.argc -= 1;
|
|
|
+}
|
|
|
+#[no_mangle]
|
|
|
+pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize {
|
|
|
+ // first we get the arguments, the environment, and the auxilary vector
|
|
|
+ let (argv, envs, auxv) = unsafe {
|
|
|
+ let argv_start = sp.argv() as *mut usize;
|
|
|
+ let (argv, argv_end) = get_argv(argv_start);
|
|
|
+ let (envs, envs_end) = get_env(argv_end.add(1));
|
|
|
+ let auxv = get_auxv(envs_end.add(1));
|
|
|
+ (argv, envs, auxv)
|
|
|
+ };
|
|
|
|
|
|
- if kind == 0 {
|
|
|
- break;
|
|
|
- }
|
|
|
+ let img_entry = *auxv.get(&AT_ENTRY).unwrap_or_else(|| {
|
|
|
+ eprintln!("failed to find AT_ENTRY");
|
|
|
+ unistd::_exit(1);
|
|
|
+ loop {}
|
|
|
+ });
|
|
|
|
|
|
- println!(" aux: {}={:#x}", kind, value);
|
|
|
- //match kind {
|
|
|
- // 6 => page_size = value,
|
|
|
- // _ => (),
|
|
|
- //}
|
|
|
- }
|
|
|
+ // Some variables that will be overridden by environment and auxiliary vectors
|
|
|
+ let library_path = match envs.get("LD_LIBRARY_PATH") {
|
|
|
+ Some(lib_path) => lib_path,
|
|
|
+ None => "/lib",
|
|
|
+ };
|
|
|
|
|
|
- sp.argc -= 1;
|
|
|
+ let path;
|
|
|
|
|
|
- CStr::from_ptr(sp.argv0)
|
|
|
- };
|
|
|
+ let is_manual = img_entry == ld_entry;
|
|
|
+ if is_manual {
|
|
|
+ // ld.so is run directly by user and not via execve() or similar systemcall
|
|
|
+ println!("argv: {:#?}", argv);
|
|
|
+ println!("envs: {:#?}", envs);
|
|
|
+ println!("auxv: {:#x?}", auxv);
|
|
|
|
|
|
- let path = match path_c.to_str() {
|
|
|
- Ok(ok) => ok,
|
|
|
- Err(err) => {
|
|
|
- eprintln!("ld.so: failed to parse path: {}", err);
|
|
|
+ if sp.argc < 2 {
|
|
|
+ eprintln!("ld.so [executable] [arguments...]");
|
|
|
unistd::_exit(1);
|
|
|
loop {}
|
|
|
}
|
|
|
- };
|
|
|
+ unsafe { adjust_stack(sp) };
|
|
|
+ path = &argv[1];
|
|
|
+ } else {
|
|
|
+ path = &argv[0];
|
|
|
+ }
|
|
|
|
|
|
let mut linker = Linker::new(library_path);
|
|
|
match linker.load(&path, &path) {
|