diff --git a/src/header/sys_auxv/mod.rs b/src/header/sys_auxv/mod.rs index 3e191883f92d8955b245a538c8db6700b21578fa..184eba1a76cbd1662c16a55e392b5c8363532275 100644 --- a/src/header/sys_auxv/mod.rs +++ b/src/header/sys_auxv/mod.rs @@ -2,7 +2,33 @@ use crate::platform::types::*; -pub const AT_HWCAP: usize = 16; +pub const AT_NULL: usize = 0; /* End of vector */ +pub const AT_IGNORE: usize = 1; /* Entry should be ignored */ +pub const AT_EXECFD: usize = 2; /* File descriptor of program */ +pub const AT_PHDR: usize = 3; /* Program headers for program */ +pub const AT_PHENT: usize = 4; /* Size of program header entry */ +pub const AT_PHNUM: usize = 5; /* Number of program headers */ +pub const AT_PAGESZ: usize = 6; /* System page size */ +pub const AT_BASE: usize = 7; /* Base address of interpreter */ +pub const AT_FLAGS: usize = 8; /* Flags */ +pub const AT_ENTRY: usize = 9; /* Entry point of program */ +pub const AT_NOTELF: usize = 10; /* Program is not ELF */ +pub const AT_UID: usize = 11; /* Real uid */ +pub const AT_EUID: usize = 12; /* Effective uid */ +pub const AT_GID: usize = 13; /* Real gid */ +pub const AT_EGID: usize = 14; /* Effective gid */ +pub const AT_CLKTCK: usize = 17; /* Frequency of times() */ +pub const AT_PLATFORM: usize = 15; /* String identifying platform. */ +pub const AT_HWCAP: usize = 16; /* Machine-dependent hints about */ +pub const AT_FPUCW: usize = 18; /* Used FPU control word. */ +pub const AT_DCACHEBSIZE: usize = 19; /* Data cache block size. */ +pub const AT_ICACHEBSIZE: usize = 20; /* Instruction cache block size. */ +pub const AT_UCACHEBSIZE: usize = 21; /* Unified cache block size. */ +pub const AT_IGNOREPPC: usize = 22; /* Entry should be ignored. */ +pub const AT_BASE_PLATFORM: usize = 24; /* String identifying real platforms.*/ +pub const AT_RANDOM: usize = 25; /* Address of 16 random bytes. */ +pub const AT_HWCAP2: usize = 26; /* More machine-dependent hints about*/ +pub const AT_EXECFN: usize = 31; /* Filename of executable. */ #[no_mangle] pub extern "C" fn getauxval(_t: c_ulong) -> c_ulong { diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index af78829ffbf58a05c0fd2c94d4a8cef63164380b..1512a7f6fd192846225a47d9a5c04558c25828d0 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -41,21 +41,24 @@ pub struct Linker { pub globals: BTreeMap<String, usize>, /// Loaded library in-memory data mmaps: BTreeMap<String, &'static mut [u8]>, + verbose: bool } impl Linker { - pub fn new(library_path: &str) -> Self { + pub fn new(library_path: &str, verbose: bool) -> Self { Self { library_path: library_path.to_string(), objects: BTreeMap::new(), globals: BTreeMap::new(), mmaps: BTreeMap::new(), + verbose: verbose } } pub fn load(&mut self, name: &str, path: &str) -> Result<()> { - println!("load {}: {}", name, path); - + if self.verbose { + println!("load {}: {}", name, path); + } let mut data = Vec::new(); let path_c = CString::new(path) @@ -102,9 +105,9 @@ impl Linker { } else { format!("{}/{}", part, name) }; - - println!("check {}", path); - + if self.verbose { + println!("check {}", path); + } let access = unsafe { let path_c = CString::new(path.as_bytes()).map_err(|err| { Error::Malformed(format!("invalid path '{}': {}", path, err)) @@ -140,8 +143,9 @@ impl Linker { let mut tls_primary = 0; let mut tls_size = 0; for (elf_name, elf) in elfs.iter() { - println!("map {}", elf_name); - + if self.verbose { + println!("map {}", elf_name); + } let object = match self.objects.get(*elf_name) { Some(some) => some, None => continue, @@ -158,8 +162,9 @@ impl Linker { match ph.p_type { program_header::PT_LOAD => { - println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph); - + if self.verbose { + println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph); + } if let Some(ref mut bounds) = bounds_opt { if vaddr < bounds.0 { bounds.0 = vaddr; @@ -172,7 +177,9 @@ impl Linker { } } program_header::PT_TLS => { - println!(" load tls {:#x}: {:x?}", vsize, ph); + if self.verbose{ + println!(" load tls {:#x}: {:x?}", vsize, ph); + } tls_size += vsize; if Some(*elf_name) == primary_opt { tls_primary += vsize; @@ -186,8 +193,9 @@ impl Linker { None => continue, } }; - println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1); - + if self.verbose { + println!(" bounds {:#x}, {:#x}", bounds.0, bounds.1); + } // Allocate memory let mmap = unsafe { let size = bounds.1 /* - bounds.0 */; @@ -208,8 +216,9 @@ impl Linker { ptr::write_bytes(ptr as *mut u8, 0, size); slice::from_raw_parts_mut(ptr as *mut u8, size) }; - println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); - + if self.verbose { + println!(" mmap {:p}, {:#x}", mmap.as_mut_ptr(), mmap.len()); + } // Locate all globals for sym in elf.dynsyms.iter() { if sym.st_bind() == sym::STB_GLOBAL && sym.st_value != 0 { @@ -231,8 +240,9 @@ impl Linker { } else { None }; - println!("tcb {:x?}", tcb_opt); - + if self.verbose{ + println!("tcb {:x?}", tcb_opt); + } // Copy data let mut tls_offset = tls_primary; let mut tcb_masters = Vec::new(); @@ -253,9 +263,9 @@ impl Linker { Some(some) => some, None => continue, }; - - println!("load {}", elf_name); - + if self.verbose { + println!("load {}", elf_name); + } // Copy data for ph in elf.program_headers.iter() { let voff = ph.p_vaddr as usize % PAGE_SIZE; @@ -289,15 +299,15 @@ impl Linker { } } }; - - println!( - " copy {:#x}, {:#x}: {:#x}, {:#x}", - vaddr, - vsize, - voff, - obj_data.len() - ); - + if self.verbose { + println!( + " copy {:#x}, {:#x}: {:#x}, {:#x}", + vaddr, + vsize, + voff, + obj_data.len() + ); + } mmap_data.copy_from_slice(obj_data); } program_header::PT_TLS => { @@ -312,12 +322,12 @@ impl Linker { len: ph.p_filesz as usize, offset: tls_size - valign, }; - - println!( - " tls master {:p}, {:#x}: {:#x}, {:#x}", - tcb_master.ptr, tcb_master.len, tcb_master.offset, valign, - ); - + if self.verbose { + println!( + " tls master {:p}, {:#x}: {:#x}, {:#x}", + tcb_master.ptr, tcb_master.len, tcb_master.offset, valign, + ); + } if Some(*elf_name) == primary_opt { tls_ranges.insert(elf_name.to_string(), (0, tcb_master.range())); tcb_masters[0] = tcb_master; @@ -350,9 +360,9 @@ impl Linker { Some(some) => some, None => continue, }; - - println!("link {}", elf_name); - + if self.verbose { + println!("link {}", elf_name); + } // Relocate for rel in elf .dynrelas @@ -461,8 +471,9 @@ impl Linker { let res = unsafe { let ptr = mmap.as_mut_ptr().add(vaddr); - println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot); - + if self.verbose { + println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot); + } sys_mman::mprotect(ptr as *mut c_void, vsize, prot) }; @@ -487,9 +498,9 @@ impl Linker { Some(some) => some, None => continue, }; - - println!("entry {}", elf_name); - + if self.verbose { + println!("entry {}", elf_name); + } if Some(*elf_name) == primary_opt { entry_opt = Some(mmap.as_mut_ptr() as usize + elf.header.e_entry as usize); } @@ -550,8 +561,9 @@ impl Linker { let res = unsafe { let ptr = mmap.as_mut_ptr().add(vaddr); - println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot); - + if self.verbose { + println!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot); + } sys_mman::mprotect(ptr as *mut c_void, vsize, prot) }; diff --git a/src/ld_so/src/lib.rs b/src/ld_so/src/lib.rs index e64534ccb10e52fbc3c2a13fce8eb6c317af7ee1..f26bc0af6403e4a5989dad63a747c9754248c45b 100644 --- a/src/ld_so/src/lib.rs +++ b/src/ld_so/src/lib.rs @@ -8,12 +8,17 @@ pub unsafe extern "C" fn _start() { #[cfg(target_arch = "x86_64")] asm!(" + # rsi = _start + 5 + call next +next: pop rsi + # Save original stack and align stack to 16 bytes mov rbp, rsp and rsp, 0xFFFFFFFFFFFFFFF0 - # Call ld_so_start(stack) + # Call ld_so_start(stack, entry) mov rdi, rbp + sub rsi, 5 call relibc_ld_so_start # Restore original stack, clear registers, and jump to new start function diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 56501aad6d275cb3b1e323efc2c1563d90f4932d..a55abdac2f5f8dd4f30c91970a5e1e634f4ba76c 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -1,105 +1,159 @@ // 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); + let mut linker = Linker::new(library_path, is_manual); match linker.load(&path, &path) { Ok(()) => (), Err(err) => { @@ -128,7 +182,8 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize { if let Some(tcb) = unsafe { Tcb::current() } { tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); } - - eprintln!("ld.so: entry '{}': {:#x}", path, entry); + if is_manual { + eprintln!("ld.so: entry '{}': {:#x}", path, entry); + } entry }