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();