diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index e8cf6ccf913a143c9836f1f0231126b7c97e76d3..a1a517f789f0588ff7de274f44f69f2f7ffe4347 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -472,7 +472,15 @@ impl Linker { } fn run_init(&self, objects: &Vec<DSO>) { + use crate::platform::{self, types::*}; + for obj in objects.iter().rev() { + if let Some((symbol, true)) = obj.get_sym("__relibc_init_environ") { + unsafe { + symbol.as_ptr().cast::<*mut *mut c_char>().write(platform::environ); + } + } + obj.run_init(); } } diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 25a1f16d0af132ff08a952a0b091c0f98369284d..e07afac109b77d444f46ef02e680e79a4f1f8c7e 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -167,6 +167,22 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> (argv, envs, auxv) }; + unsafe { + crate::platform::OUR_ENVIRON = envs.iter().map(|(k, v)| { + let mut var = Vec::with_capacity(k.len() + v.len() + 2); + var.extend(k.as_bytes()); + var.push(b'='); + var.extend(v.as_bytes()); + var.push(b'\0'); + let mut var = var.into_boxed_slice(); + let ptr = var.as_mut_ptr(); + core::mem::forget(var); + ptr.cast() + }).chain(core::iter::once(core::ptr::null_mut())).collect::<Vec<_>>(); + + crate::platform::environ = crate::platform::OUR_ENVIRON.as_mut_ptr(); + } + let is_manual = if let Some(img_entry) = auxv.get(&AT_ENTRY) { *img_entry == ld_entry } else { diff --git a/src/start.rs b/src/start.rs index cee25f33d96dba8dc5ff942c4a59ba4479ad93c9..9ec0eb76deab941012726530e1937528df3193d3 100644 --- a/src/start.rs +++ b/src/start.rs @@ -67,7 +67,16 @@ static INIT_ARRAY: [extern "C" fn(); 1] = [init_array]; static mut init_complete: bool = false; +#[used] +#[no_mangle] +static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut(); + fn alloc_init() { + unsafe { + if init_complete { + return; + } + } unsafe { if let Some(tcb) = ld_so::tcb::Tcb::current() { if tcb.mspace != 0 { @@ -96,6 +105,10 @@ extern "C" fn init_array() { alloc_init(); io_init(); + unsafe { + platform::environ = __relibc_init_environ; + } + extern "C" { fn pthread_init(); } @@ -155,15 +168,19 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { platform::program_invocation_name = *arg; platform::program_invocation_short_name = libgen::basename(*arg); } - - // Set up envp - let envp = sp.envp(); - let mut len = 0; - while !(*envp.add(len)).is_null() { - len += 1; + // We check for NULL here since ld.so might already have initialized it for us, and we don't + // want to overwrite it if constructors in .init_array of dependency libraries have called + // setenv. + if platform::environ.is_null() { + // Set up envp + let envp = sp.envp(); + let mut len = 0; + while !(*envp.add(len)).is_null() { + len += 1; + } + platform::OUR_ENVIRON = copy_string_array(envp, len); + platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); } - platform::OUR_ENVIRON = copy_string_array(envp, len); - platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); // Setup signal stack, otherwise we cannot handle any signals besides SIG_IGN/SIG_DFL behavior. setup_sigstack();