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
 }