diff --git a/Makefile b/Makefile
index d1381ab4ab0631d2460df7b3965fecff68e1d127..1834aa6d244ba407f79b455255a0e9a44aed4a8b 100644
--- a/Makefile
+++ b/Makefile
@@ -86,6 +86,7 @@ install-libs: libs
 	mkdir -pv "$(DESTDIR)/lib"
 	cp -v "$(BUILD)/release/libc.a" "$(DESTDIR)/lib"
 	cp -v "$(BUILD)/release/libc.so" "$(DESTDIR)/lib"
+	ln -sr "$(DESTDIR)/lib/libc.so" "$(DESTDIR)/lib/libc.so.6"
 	cp -v "$(BUILD)/release/crt0.o" "$(DESTDIR)/lib"
 	cp -v "$(BUILD)/release/crti.o" "$(DESTDIR)/lib"
 	cp -v "$(BUILD)/release/crtn.o" "$(DESTDIR)/lib"
diff --git a/src/ld_so/ld_script b/src/ld_so/ld_script
index 1ea6287d8ce7eab08b47715a93260a8374dee33b..5f05fed75705ce9c24f512afa7a3ca1cab33fdfe 100644
--- a/src/ld_so/ld_script
+++ b/src/ld_so/ld_script
@@ -21,7 +21,7 @@ SEARCH_DIR("/usr/lib");
 SECTIONS
 {
   /* Read-only sections, merged into text segment: */
-  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x12340000)); . = SEGMENT_START("text-segment", 0x1234000) + SIZEOF_HEADERS;
+  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
   .interp         : { *(.interp) }
   .note.gnu.build-id  : { *(.note.gnu.build-id) }
   .hash           : { *(.hash) }
diff --git a/src/ld_so/library.rs b/src/ld_so/library.rs
index 88958e01c8ffd7ab974fda218f1781848eb897d6..19862f7e3d4281b908bf86903a54914b3cb7eb87 100644
--- a/src/ld_so/library.rs
+++ b/src/ld_so/library.rs
@@ -36,6 +36,7 @@ pub struct Library {
     pub dep_tree: DepTree,
     /// A set used to detect circular dependencies in the Linker::load function
     pub cir_dep: BTreeSet<String>,
+    pub runpath: Option<String>,
 }
 impl Library {
     pub fn new() -> Library {
diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs
index 670d38e77612a071d5a66e3ec8af0a519dfbd8b5..3f6b4d4c46b0a67e8d87c563bef38a18aaf3348c 100644
--- a/src/ld_so/linker.rs
+++ b/src/ld_so/linker.rs
@@ -14,7 +14,7 @@ use goblin::{
     elf::{
         header::ET_DYN,
         program_header,
-        r#dyn::{Dyn, DT_DEBUG},
+        r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH},
         reloc, sym, Elf,
     },
     error::{Error, Result},
@@ -63,7 +63,8 @@ impl Symbol {
 pub struct Linker {
     // Used by load
     /// Library path to search when loading library by name
-    library_path: String,
+    default_library_path: String,
+    ld_library_path: Option<String>,
     root: Library,
     verbose: bool,
     tls_index_offset: usize,
@@ -73,9 +74,10 @@ pub struct Linker {
 }
 
 impl Linker {
-    pub fn new(library_path: &str, verbose: bool) -> Self {
+    pub fn new(ld_library_path: Option<String>, verbose: bool) -> Self {
         Self {
-            library_path: library_path.to_string(),
+            default_library_path: "/lib".to_string(),
+            ld_library_path: ld_library_path,
             root: Library::new(),
             verbose,
             tls_index_offset: 0,
@@ -139,13 +141,30 @@ impl Linker {
     ) -> Result<Vec<DepTree>> {
         let elf = Elf::parse(&data)?;
         //println!("{:#?}", elf);
+
+        // search for RUNPATH
+        lib.runpath = if let Some(dynamic) = elf.dynamic {
+            let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH);
+            match entry {
+                Some(entry) => {
+                    let path = elf
+                        .dynstrtab
+                        .get(entry.d_val as usize)
+                        .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??;
+                    Some(path.to_string())
+                }
+                _ => None,
+            }
+        } else {
+            None
+        };
+
         let mut deps = Vec::new();
         for library in elf.libraries.iter() {
             if let Some(dep) = self._load_library(library, lib)? {
                 deps.push(dep);
             }
         }
-        let elf = Elf::parse(&data)?;
         let key = match elf.soname {
             Some(soname) => soname,
             _ => name,
@@ -171,8 +190,15 @@ impl Linker {
         } else if name.contains('/') {
             Ok(Some(self.load_recursive(name, name, lib)?))
         } else {
-            let library_path = self.library_path.clone();
-            for part in library_path.split(PATH_SEP) {
+            let mut paths = Vec::new();
+            if let Some(ld_library_path) = &self.ld_library_path {
+                paths.push(ld_library_path);
+            }
+            if let Some(runpath) = &lib.runpath {
+                paths.push(runpath);
+            }
+            paths.push(&self.default_library_path);
+            for part in paths.iter() {
                 let path = if part.is_empty() {
                     format!("./{}", name)
                 } else {
@@ -647,7 +673,7 @@ impl Linker {
                         } as usize;
 
                         let mut tcb_master = Master {
-                            ptr: unsafe { mmap.as_ptr().add(ph.p_vaddr as usize) },
+                            ptr: unsafe { mmap.as_ptr().add(ph.p_vaddr as usize - base_addr) },
                             len: ph.p_filesz as usize,
                             offset: tls_size - valign,
                         };
diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs
index 153b899265feaf559b12212db64d9454ef9841e3..6a9439d001d6aabc03bd6f6ae9a8879294f80c8d 100644
--- a/src/ld_so/start.rs
+++ b/src/ld_so/start.rs
@@ -183,10 +183,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
     }
 
     // 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.to_owned() + ":/lib",
-        None => "/lib".to_owned(),
-    };
+    let ld_library_path = envs.get("LD_LIBRARY_PATH").map(|s| s.to_owned());
 
     let name_or_path = if is_manual {
         // ld.so is run directly by user and not via execve() or similar systemcall
@@ -234,7 +231,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
         }
         pr
     };
-    let mut linker = Linker::new(&library_path, false);
+    let mut linker = Linker::new(ld_library_path, false);
     match linker.load(&path, &path) {
         Ok(()) => (),
         Err(err) => {
diff --git a/src/start.rs b/src/start.rs
index d001d9dde0aaaa7b74a06512eb29ce3d7c4a2375..2082dc84efa8f3d18c7fdfe7a5a6b5f371595381 100644
--- a/src/start.rs
+++ b/src/start.rs
@@ -86,9 +86,23 @@ extern "C" fn init_array() {
     // init_array runs first or if relibc_start runs first
     // Still whoever gets to run first must initialize rust
     // memory allocator before doing anything else.
+
+    unsafe {
+        if init_complete {
+            return;
+        }
+    }
+
     alloc_init();
     io_init();
-    unsafe { init_complete = true };
+
+    extern "C" {
+        fn pthread_init();
+    }
+    unsafe {
+        pthread_init();
+        init_complete = true
+    }
 }
 fn io_init() {
     unsafe {
@@ -108,7 +122,6 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
         static __init_array_start: extern "C" fn();
         static __init_array_end: extern "C" fn();
 
-        fn pthread_init();
         fn _init();
         fn main(argc: isize, argv: *mut *mut c_char, envp: *mut *mut c_char) -> c_int;
     }
@@ -138,10 +151,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
     platform::inner_environ = copy_string_array(envp, len);
     platform::environ = platform::inner_environ.as_mut_ptr();
 
-    if !init_complete {
-        init_array();
-    }
-    pthread_init();
+    init_array();
 
     // Run preinit array
     {
diff --git a/tests/.gitignore b/tests/.gitignore
index 4764d3daef449032ea949f7f7bec7085a6d21522..748ff9d390dd6f07397b222de5591b2cfc268d4a 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,3 +1,4 @@
-/bins/
+/bins_static/
+/bins_dynamic/
 /gen/
 /*.out
diff --git a/tests/Makefile b/tests/Makefile
index e5de5e3aaec8cd1996820f1c73b2825815f2b017..77113745eb66c3f1adcd5bffa27d23edd3089b95 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -6,43 +6,33 @@ EXPECT_NAMES=\
 	assert \
 	constructor \
 	ctype \
-	destructor \
 	dirent/scandir \
 	errno \
 	error \
 	fcntl/create \
 	fcntl/fcntl \
 	fnmatch \
-	futimens \
 	libgen \
 	locale \
 	math \
 	netdb/getaddrinfo \
-	netdb/netdb \
 	ptrace \
 	regex \
 	select \
 	setjmp \
 	sigaction \
 	signal \
-	stdio/all \
-	stdio/buffer \
-	stdio/fgets \
 	stdio/fputs \
 	stdio/fread \
-	stdio/freopen \
 	stdio/fseek \
 	stdio/fwrite \
-	stdio/getc_unget \
 	stdio/mutex \
 	stdio/popen \
 	stdio/printf \
 	stdio/rename \
 	stdio/scanf \
-	stdio/setvbuf \
 	stdio/sprintf \
 	stdio/printf_space_pad \
-	stdio/ungetc_multiple \
 	stdio/ungetc_ftell \
 	stdio/fscanf_offby1 \
 	stdio/fscanf \
@@ -79,12 +69,10 @@ EXPECT_NAMES=\
 	sys_mman \
 	time/asctime \
 	time/gmtime \
-	time/localtime \
 	time/macros \
 	time/mktime \
 	time/strftime \
 	time/time \
-	tls \
 	unistd/access \
 	unistd/brk \
 	unistd/dup \
@@ -93,8 +81,6 @@ EXPECT_NAMES=\
 	unistd/fork \
 	unistd/fsync \
 	unistd/ftruncate \
-	unistd/getopt \
-	unistd/getopt_long \
 	unistd/pipe \
 	unistd/rmdir \
 	unistd/sleep \
@@ -111,14 +97,37 @@ EXPECT_NAMES=\
 	wchar/wcsrchr \
 	wchar/wcsstr \
 	wchar/wcstod \
-	wchar/wcstok \
 	wchar/wcstol \
 	wchar/wcscasecmp \
 	wchar/wcsncasecmp \
-	wctype/towlower \
-	wctype/towupper
 	# TODO: Fix these
 	# mkfifo
+	# netdb/netdb \
+
+# issues with linking stdin, stdout, stderr
+STATIC_ONLY_NAMES=\
+	futimens \
+	stdio/all \
+	stdio/buffer \
+	stdio/fgets \
+	stdio/freopen \
+	stdio/getc_unget \
+	stdio/setvbuf \
+	stdio/ungetc_multiple \
+	time/localtime \
+	wchar/wcstok \
+	wctype/towlower \
+	wctype/towupper \
+# need to call fini in ld_so's _start
+STATIC_ONLY_NAMES+=\
+	destructor \
+# comparison issue
+STATIC_ONLY_NAMES+=\
+	tls \
+# issues with linking optarg, optind etc.
+STATIC_ONLY_NAMES+=\
+	unistd/getopt \
+	unistd/getopt_long \
 
 # Binaries that may generate varied output
 NAMES=\
@@ -147,8 +156,12 @@ NAMES=\
 #	resource/getrusage
 #	time/times
 
-BINS=$(patsubst %,bins/%,$(NAMES))
-EXPECT_BINS=$(patsubst %,bins/%,$(EXPECT_NAMES))
+BINS=$(patsubst %,bins_static/%,$(NAMES))
+BINS+=$(patsubst %,bins_static/%,$(STATIC_ONLY_NAMES))
+BINS+=$(patsubst %,bins_dynamic/%,$(NAMES))
+EXPECT_BINS=$(patsubst %,bins_static/%,$(EXPECT_NAMES))
+EXPECT_BINS+=$(patsubst %,bins_static/%,$(STATIC_ONLY_NAMES))
+EXPECT_BINS+=$(patsubst %,bins_dynamic/%,$(EXPECT_NAMES))
 
 TEST_RUNNER?=sh --
 
@@ -157,61 +170,76 @@ TEST_RUNNER?=sh --
 all: $(BINS)
 
 clean:
-	rm -rf bins gen *.out
+	rm -rf bins_* gen *.out
 
 run: | $(BINS)
-	for name in $(NAMES); \
+	for bin in $(BINS); \
 	do \
-		echo "# $${name} #"; \
-		"bins/$${name}" test args || exit $$?; \
+		echo "# $${bin} #"; \
+		"$${bin}" test args || exit $$?; \
 	done
 
 expected: | $(EXPECT_BINS)
 	rm -rf expected
 	mkdir -p expected
-	for name in $(EXPECT_NAMES); \
+	for bin in $(EXPECT_BINS); \
 	do \
-		echo "# $${name} #"; \
-		mkdir -p expected/`dirname $${name}`; \
-		"bins/$${name}" test args > "expected/$${name}.stdout" 2> "expected/$${name}.stderr" || exit $$?; \
+		echo "# $${bin} #"; \
+		mkdir -p expected/`dirname $${bin}`; \
+		"$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr" || exit $$?; \
 	done
 
 verify: | $(EXPECT_BINS)
-	$(TEST_RUNNER) ./verify.sh $(EXPECT_NAMES)
+	$(TEST_RUNNER) ./verify.sh $(EXPECT_BINS)
 
-CFLAGS=\
+FLAGS=\
 	-std=c11 \
 	-fno-builtin \
 	-fno-stack-protector \
-	-static \
 	-Wall \
 	-pedantic \
 	-g \
 	-I .
 
-LIBS=
+STATIC_FLAGS=\
+	../sysroot/lib/libc.a \
+	-static
 
 NATIVE_RELIBC?=0
 ifeq ($(NATIVE_RELIBC),0)
-CFLAGS+=\
+FLAGS+=\
 	-nostdinc \
 	-nostdlib \
 	-isystem ../sysroot/include \
 	../sysroot/lib/crt0.o \
-	../sysroot/lib/crti.o
-
-LIBS=\
-	../sysroot/lib/libc.a \
+	../sysroot/lib/crti.o \
 	../sysroot/lib/crtn.o
 
 ../sysroot:
 	$(MAKE) -C .. sysroot
 
-bins/%: %.c ../sysroot
+bins_static/%: %.c ../sysroot
+	mkdir -p "$$(dirname "$@")"
+	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
+
+SYSROOT_LIB=$(shell realpath ../sysroot/lib/)
+
+DYNAMIC_FLAGS=\
+	-Wl,-dynamic-linker=$(SYSROOT_LIB)/ld64.so.1 \
+	-Wl,--enable-new-dtags \
+	-Wl,-rpath=$(SYSROOT_LIB) \
+	-L $(SYSROOT_LIB) \
+	-lc
+
+bins_dynamic/%: %.c ../sysroot
 	mkdir -p "$$(dirname "$@")"
-	$(CC) $(CFLAGS) "$<" $(LIBS) -o "$@"
+	$(CC) "$<" -o "$@" $(FLAGS) $(DYNAMIC_FLAGS)
 else
-bins/%: %.c
+bins_static/%: %.c
+	mkdir -p "$$(dirname "$@")"
+	$(CC) "$<" -o "$@" $(FLAGS) $(STATIC_FLAGS)
+
+bins_dynamic/%: %.c
 	mkdir -p "$$(dirname "$@")"
-	$(CC) $(CFLAGS) "$<" $(LIBS) -o "$@"
+	$(CC) "$<" -o "$@" $(FLAGS)
 endif
diff --git a/tests/expected/args.stdout b/tests/expected/args.stdout
deleted file mode 100644
index 4076ce936a6d1f14e24710d78e2f8f9b8a955c74..0000000000000000000000000000000000000000
--- a/tests/expected/args.stdout
+++ /dev/null
@@ -1 +0,0 @@
-bins/args test args 
diff --git a/tests/expected/args.stderr b/tests/expected/bins_dynamic/args.stderr
similarity index 100%
rename from tests/expected/args.stderr
rename to tests/expected/bins_dynamic/args.stderr
diff --git a/tests/expected/bins_dynamic/args.stdout b/tests/expected/bins_dynamic/args.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..05c95c249b66f952da4509deea112b569de2c576
--- /dev/null
+++ b/tests/expected/bins_dynamic/args.stdout
@@ -0,0 +1 @@
+bins_dynamic/args test args 
diff --git a/tests/expected/errno.stderr b/tests/expected/bins_dynamic/errno.stderr
similarity index 100%
rename from tests/expected/errno.stderr
rename to tests/expected/bins_dynamic/errno.stderr
diff --git a/tests/expected/bins_dynamic/errno.stdout b/tests/expected/bins_dynamic/errno.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..4c4608349b07c566aec56afba6cf755868ec8393
--- /dev/null
+++ b/tests/expected/bins_dynamic/errno.stdout
@@ -0,0 +1,4 @@
+bins_dynamic/errno
+bins_dynamic/errno
+yes, you can change this
+yes, you can change this
diff --git a/tests/expected/bins_static/args.stderr b/tests/expected/bins_static/args.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/bins_static/args.stdout b/tests/expected/bins_static/args.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..3026e24bea00ad56fb0074c123117d1e1683a12e
--- /dev/null
+++ b/tests/expected/bins_static/args.stdout
@@ -0,0 +1 @@
+bins_static/args test args 
diff --git a/tests/expected/bins_static/errno.stderr b/tests/expected/bins_static/errno.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/errno.stdout b/tests/expected/bins_static/errno.stdout
similarity index 58%
rename from tests/expected/errno.stdout
rename to tests/expected/bins_static/errno.stdout
index 62770a791141177b9744b5c96ba106ac2d39be7e..9d4b10bd4fc502a3e5b28adb0e6d09d403a8e098 100644
--- a/tests/expected/errno.stdout
+++ b/tests/expected/bins_static/errno.stdout
@@ -1,4 +1,4 @@
-bins/errno
-bins/errno
+bins_static/errno
+bins_static/errno
 yes, you can change this
 yes, you can change this
diff --git a/tests/verify.sh b/tests/verify.sh
index 2f778e1a64916f82380bf854d103e8f3f79f6753..26ebff0495d58b832ef179d646b7302c5e300320 100755
--- a/tests/verify.sh
+++ b/tests/verify.sh
@@ -3,42 +3,61 @@
 rm -rf gen || exit 1
 mkdir -p gen || exit 1
 
+summary=""
+
 while [ "$#" -gt 0 ]
 do
-    name="$1"
+    bin="$1"
     shift
 
-	echo "# ${name} #"
-	mkdir -p "gen/$(dirname ${name})" || exit 1
+    echo "# ${bin} #"
+    mkdir -p "gen/$(dirname ${bin})" || exit 1
 
-	"bins/${name}" test args > "gen/${name}.stdout" 2> "gen/${name}.stderr"
-    status="$?"
+    "${bin}" test args > "gen/${bin}.stdout" 2> "gen/${bin}.stderr"
+    retcode="$?"
+    status=""
 
     for output in stdout stderr
     do
-        gen="$(sha256sum "gen/${name}.${output}" | cut -d " " -f 1)"
-        expected="$(sha256sum "expected/${name}.${output}" | cut -d " " -f 1)"
+        gen="$(sha256sum "gen/${bin}.${output}" | cut -d " " -f 1)"
+
+        # look for expected output file that is specific to binary type (either static or dynamic)
+        expected_file="expected/${bin}.${output}"
+        if [ ! -e $expected_file ]
+        then
+            # if unable to find above, the expected output file is the same to both static and dynamic binary
+            name=$(echo $bin | cut -d "/" -f2-)
+            expected_file="expected/${name}.${output}"
+        fi
+        expected="$(sha256sum "${expected_file}" | cut -d " " -f 1)"
         if [ "${gen}" != "${expected}" ]
         then
-            echo "# ${name}: ${output}: expected #"
-            cat "expected/${name}.${output}"
+            echo "# ${bin}: ${output}: expected #"
+            cat "${expected_file}"
 
-            echo "# ${name}: ${output}: generated #"
-            cat "gen/${name}.${output}"
+            echo "# ${bin}: ${output}: generated #"
+            cat "gen/${bin}.${output}"
 
             # FIXME: Make diff available on Redox
             if [ $(uname) != "Redox" ]
             then
-                echo "# ${name}: ${output}: diff #"
-                diff --color -u "expected/${name}.${output}" "gen/${name}.${output}"
+                echo "# ${bin}: ${output}: diff #"
+                diff --color -u "${expected_file}" "gen/${bin}.${output}"
             fi
 
-            status="${status}, ${output} mismatch"
+            status="${bin} failed - retcode ${retcode}, ${output} mismatch"
+            summary="${summary}${status}\n"
         fi
     done
 
-    if [ "${status}" != "0" ]
+    if [ -n "${status}" ]
     then
-        echo "# ${name}: failed with status ${status} #"
+        echo "# ${status} #"
     fi
 done
+
+if [ -n "$summary" ]
+then
+    echo -e "$summary"
+    exit 1
+fi