Merge "Remove `volatile` from the `__errno` declaration."
diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
index 41306db..aa1e8c9 100644
--- a/benchmarks/string_benchmark.cpp
+++ b/benchmarks/string_benchmark.cpp
@@ -58,19 +58,42 @@
 }
 BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
 
-static void BM_string_memmove(benchmark::State& state) {
+static void BM_string_memmove_non_overlapping(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* buf = new char[nbytes + 64];
-  memset(buf, 'x', nbytes + 64);
+  std::vector<char> src(nbytes, 'x');
+  std::vector<char> dst(nbytes, 'x');
 
   while (state.KeepRunning()) {
-    memmove(buf, buf + 1, nbytes); // Worst-case overlap.
+    memmove(dst.data(), src.data(), nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] buf;
 }
-BENCHMARK(BM_string_memmove)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_non_overlapping)->AT_COMMON_SIZES;
+
+static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
+  const size_t nbytes = state.range(0);
+  std::vector<char> buf(nbytes + 1, 'x');
+
+  while (state.KeepRunning()) {
+    memmove(buf.data(), buf.data() + 1, nbytes); // Worst-case overlap.
+  }
+
+  state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
+}
+BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_COMMON_SIZES;
+
+static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
+  const size_t nbytes = state.range(0);
+  std::vector<char> buf(nbytes + 1, 'x');
+
+  while (state.KeepRunning()) {
+    memmove(buf.data() + 1, buf.data(), nbytes); // Worst-case overlap.
+  }
+
+  state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
+}
+BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_COMMON_SIZES;
 
 static void BM_string_memset(benchmark::State& state) {
   const size_t nbytes = state.range(0);
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 936f3fd..5ff3c64 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -350,7 +350,5 @@
 int     __set_thread_area:set_thread_area(void*) x86
 
 # vdso stuff.
-int clock_gettime(clockid_t, timespec*)                 mips,mips64
-int __clock_gettime:clock_gettime(clockid_t, timespec*) arm,arm64,x86,x86_64
-int gettimeofday(timeval*, timezone*)                   mips,mips64
-int __gettimeofday:gettimeofday(timeval*, timezone*)    arm,arm64,x86,x86_64
+int __clock_gettime:clock_gettime(clockid_t, timespec*) all
+int __gettimeofday:gettimeofday(timeval*, timezone*) all
diff --git a/libc/arch-mips/syscalls/clock_gettime.S b/libc/arch-mips/syscalls/__clock_gettime.S
similarity index 86%
rename from libc/arch-mips/syscalls/clock_gettime.S
rename to libc/arch-mips/syscalls/__clock_gettime.S
index d227a06..6fad7e9 100644
--- a/libc/arch-mips/syscalls/clock_gettime.S
+++ b/libc/arch-mips/syscalls/__clock_gettime.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(clock_gettime)
+ENTRY(__clock_gettime)
     .set noreorder
     .cpload t9
     li v0, __NR_clock_gettime
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(clock_gettime)
+END(__clock_gettime)
diff --git a/libc/arch-mips/syscalls/gettimeofday.S b/libc/arch-mips/syscalls/__gettimeofday.S
similarity index 86%
rename from libc/arch-mips/syscalls/gettimeofday.S
rename to libc/arch-mips/syscalls/__gettimeofday.S
index 672faa3..e8b9d6a 100644
--- a/libc/arch-mips/syscalls/gettimeofday.S
+++ b/libc/arch-mips/syscalls/__gettimeofday.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(gettimeofday)
+ENTRY(__gettimeofday)
     .set noreorder
     .cpload t9
     li v0, __NR_gettimeofday
@@ -16,4 +16,4 @@
     j t9
     nop
     .set reorder
-END(gettimeofday)
+END(__gettimeofday)
diff --git a/libc/arch-mips64/syscalls/clock_gettime.S b/libc/arch-mips64/syscalls/__clock_gettime.S
similarity index 84%
rename from libc/arch-mips64/syscalls/clock_gettime.S
rename to libc/arch-mips64/syscalls/__clock_gettime.S
index 0813560..3407122 100644
--- a/libc/arch-mips64/syscalls/clock_gettime.S
+++ b/libc/arch-mips64/syscalls/__clock_gettime.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(clock_gettime)
+ENTRY(__clock_gettime)
     .set push
     .set noreorder
     li v0, __NR_clock_gettime
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(clock_gettime)
+END(__clock_gettime)
+.hidden __clock_gettime
diff --git a/libc/arch-mips64/syscalls/gettimeofday.S b/libc/arch-mips64/syscalls/__gettimeofday.S
similarity index 84%
rename from libc/arch-mips64/syscalls/gettimeofday.S
rename to libc/arch-mips64/syscalls/__gettimeofday.S
index 3a6d417..2ac5e9b 100644
--- a/libc/arch-mips64/syscalls/gettimeofday.S
+++ b/libc/arch-mips64/syscalls/__gettimeofday.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(gettimeofday)
+ENTRY(__gettimeofday)
     .set push
     .set noreorder
     li v0, __NR_gettimeofday
@@ -22,4 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(gettimeofday)
+END(__gettimeofday)
+.hidden __gettimeofday
diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp
index f3d95ca..dd4c070 100644
--- a/libc/bionic/vdso.cpp
+++ b/libc/bionic/vdso.cpp
@@ -17,8 +17,6 @@
 #include "private/bionic_globals.h"
 #include "private/bionic_vdso.h"
 
-#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || defined(__x86_64__)
-
 #include <limits.h>
 #include <link.h>
 #include <string.h>
@@ -112,10 +110,3 @@
     }
   }
 }
-
-#else
-
-void __libc_init_vdso(libc_globals*, KernelArgumentBlock&) {
-}
-
-#endif
diff --git a/libc/include/android/legacy_signal_inlines.h b/libc/include/android/legacy_signal_inlines.h
index a5d3a6f..09db2a6 100644
--- a/libc/include/android/legacy_signal_inlines.h
+++ b/libc/include/android/legacy_signal_inlines.h
@@ -37,10 +37,10 @@
 
 __BEGIN_DECLS
 
-sighandler_t bsd_signal(int signum, sighandler_t handler) __REMOVED_IN(21);
-
 #if __ANDROID_API__ < __ANDROID_API_L__
 
+sighandler_t bsd_signal(int signum, sighandler_t handler) __REMOVED_IN(21);
+
 /* These weren't introduced until L. */
 int __libc_current_sigrtmax() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
 int __libc_current_sigrtmin() __attribute__((__weak__)) __VERSIONER_NO_GUARD;
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index a3dc95c..9a2ec35 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -43,17 +43,12 @@
 #define MREMAP_MAYMOVE  1
 #define MREMAP_FIXED    2
 
-#define POSIX_MADV_NORMAL     MADV_NORMAL
-#define POSIX_MADV_RANDOM     MADV_RANDOM
-#define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL
-#define POSIX_MADV_WILLNEED   MADV_WILLNEED
-#define POSIX_MADV_DONTNEED   MADV_DONTNEED
-
 #if defined(__USE_FILE_OFFSET64) && __ANDROID_API__ >= __ANDROID_API_L__
 void* mmap(void*, size_t, int, int, int, off_t) __RENAME(mmap64) __INTRODUCED_IN(21);
 #else
 void* mmap(void*, size_t, int, int, int, off_t);
 #endif
+
 void* mmap64(void*, size_t, int, int, int, off64_t) __INTRODUCED_IN(21);
 
 int munmap(void*, size_t);
@@ -63,12 +58,29 @@
 
 int mlockall(int) __INTRODUCED_IN(17);
 int munlockall(void) __INTRODUCED_IN(17);
+
 int mlock(const void*, size_t);
 int munlock(const void*, size_t);
 
 int mincore(void*, size_t, unsigned char*);
 
 int madvise(void*, size_t, int);
+
+#if __ANDROID_API__ >= __ANDROID_API_M__
+/*
+ * Some third-party code uses the existence of POSIX_MADV_NORMAL to detect the
+ * availability of posix_madvise. This is not correct, since having up-to-date
+ * UAPI headers says nothing about the C library, but for the time being we
+ * don't want to harm adoption to the unified headers.
+ *
+ * https://github.com/android-ndk/ndk/issues/395
+ */
+#define POSIX_MADV_NORMAL     MADV_NORMAL
+#define POSIX_MADV_RANDOM     MADV_RANDOM
+#define POSIX_MADV_SEQUENTIAL MADV_SEQUENTIAL
+#define POSIX_MADV_WILLNEED   MADV_WILLNEED
+#define POSIX_MADV_DONTNEED   MADV_DONTNEED
+#endif
 int posix_madvise(void*, size_t, int) __INTRODUCED_IN(23);
 
 __END_DECLS
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index b071b90..06fc426 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -13,7 +13,7 @@
 
     stl: "libc++_static",
 
-    whole_static_libs: ["libasync_safe"],
+    whole_static_libs: ["libasync_safe", "libdemangle"],
 
     include_dirs: ["bionic/libc"],
 
diff --git a/libc/malloc_debug/backtrace.cpp b/libc/malloc_debug/backtrace.cpp
index 907944f..2443ba1 100644
--- a/libc/malloc_debug/backtrace.cpp
+++ b/libc/malloc_debug/backtrace.cpp
@@ -36,6 +36,8 @@
 #include <unistd.h>
 #include <unwind.h>
 
+#include <demangle.h>
+
 #include "backtrace.h"
 #include "debug_log.h"
 #include "MapData.h"
@@ -163,13 +165,9 @@
 
     char buf[1024];
     if (symbol != nullptr) {
-      char* demangled_symbol = __cxa_demangle(symbol, nullptr, nullptr, nullptr);
-      const char* best_name = (demangled_symbol != nullptr) ? demangled_symbol : symbol;
-
       async_safe_format_buffer(
           buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s%s (%s+%" PRIuPTR ")\n", frame_num,
-          rel_pc, soname, offset_buf, best_name, frames[frame_num] - offset);
-      free(demangled_symbol);
+          rel_pc, soname, offset_buf, demangle(symbol).c_str(), frames[frame_num] - offset);
     } else {
       async_safe_format_buffer(
           buf, sizeof(buf), "          #%02zd  pc %" PAD_PTR "  %s%s\n", frame_num, rel_pc, soname,
diff --git a/libc/private/bionic_vdso.h b/libc/private/bionic_vdso.h
index 8fd0743..2d11cd6 100644
--- a/libc/private/bionic_vdso.h
+++ b/libc/private/bionic_vdso.h
@@ -34,7 +34,7 @@
 #if defined(__aarch64__)
 #define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime"
 #define VDSO_GETTIMEOFDAY_SYMBOL  "__kernel_gettimeofday"
-#elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
+#else
 #define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime"
 #define VDSO_GETTIMEOFDAY_SYMBOL  "__vdso_gettimeofday"
 #endif
diff --git a/libc/upstream-freebsd/lib/libc/stdlib/qsort.c b/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
index 93e22cd..1ccc518 100644
--- a/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
+++ b/libc/upstream-freebsd/lib/libc/stdlib/qsort.c
@@ -41,47 +41,53 @@
 typedef int		 cmp_t(const void *, const void *);
 #endif
 static inline char	*med3(char *, char *, char *, cmp_t *, void *);
-static inline void	 swapfunc(char *, char *, int, int);
+static inline void	 swapfunc(char *, char *, size_t, int, int);
 
-#define min(a, b)	(a) < (b) ? a : b
+#define	MIN(a, b)	((a) < (b) ? a : b)
 
 /*
  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
  */
-#define swapcode(TYPE, parmi, parmj, n) { 		\
-	long i = (n) / sizeof (TYPE); 			\
-	TYPE *pi = (TYPE *) (parmi); 		\
-	TYPE *pj = (TYPE *) (parmj); 		\
+#define	swapcode(TYPE, parmi, parmj, n) {		\
+	size_t i = (n) / sizeof (TYPE);			\
+	TYPE *pi = (TYPE *) (parmi);		\
+	TYPE *pj = (TYPE *) (parmj);		\
 	do { 						\
 		TYPE	t = *pi;		\
 		*pi++ = *pj;				\
 		*pj++ = t;				\
-        } while (--i > 0);				\
+	} while (--i > 0);				\
 }
 
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+#define	SWAPINIT(TYPE, a, es) swaptype_ ## TYPE =	\
+	((char *)a - (char *)0) % sizeof(TYPE) ||	\
+	es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
 
 static inline void
-swapfunc(a, b, n, swaptype)
-	char *a, *b;
-	int n, swaptype;
+swapfunc(char *a, char *b, size_t n, int swaptype_long, int swaptype_int)
 {
-	if(swaptype <= 1)
+	if (swaptype_long <= 1)
 		swapcode(long, a, b, n)
+	else if (swaptype_int <= 1)
+		swapcode(int, a, b, n)
 	else
 		swapcode(char, a, b, n)
 }
 
-#define swap(a, b)					\
-	if (swaptype == 0) {				\
+#define	swap(a, b)					\
+	if (swaptype_long == 0) {			\
 		long t = *(long *)(a);			\
 		*(long *)(a) = *(long *)(b);		\
 		*(long *)(b) = t;			\
+	} else if (swaptype_int == 0) {			\
+		int t = *(int *)(a);			\
+		*(int *)(a) = *(int *)(b);		\
+		*(int *)(b) = t;			\
 	} else						\
-		swapfunc(a, b, es, swaptype)
+		swapfunc(a, b, es, swaptype_long, swaptype_int)
 
-#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
+#define	vecswap(a, b, n)				\
+	if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int)
 
 #ifdef I_AM_QSORT_R
 #define	CMP(t, x, y) (cmp((t), (x), (y)))
@@ -98,24 +104,25 @@
 {
 	return CMP(thunk, a, b) < 0 ?
 	       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
-              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+	      :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
 }
 
 #ifdef I_AM_QSORT_R
 void
 qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
 #else
-#define thunk NULL
+#define	thunk NULL
 void
 qsort(void *a, size_t n, size_t es, cmp_t *cmp)
 #endif
 {
 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-	size_t d, r;
+	size_t d1, d2;
 	int cmp_result;
-	int swaptype, swap_cnt;
+	int swaptype_long, swaptype_int, swap_cnt;
 
-loop:	SWAPINIT(a, es);
+loop:	SWAPINIT(long, a, es);
+	SWAPINIT(int, a, es);
 	swap_cnt = 0;
 	if (n < 7) {
 		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
@@ -130,7 +137,8 @@
 		pl = a;
 		pn = (char *)a + (n - 1) * es;
 		if (n > 40) {
-			d = (n / 8) * es;
+			size_t d = (n / 8) * es;
+
 			pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
 			pm = med3(pm - d, pm, pm + d, cmp, thunk);
 			pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
@@ -175,21 +183,43 @@
 	}
 
 	pn = (char *)a + n * es;
-	r = min(pa - (char *)a, pb - pa);
-	vecswap(a, pb - r, r);
-	r = min(pd - pc, pn - pd - es);
-	vecswap(pb, pn - r, r);
-	if ((r = pb - pa) > es)
+	d1 = MIN(pa - (char *)a, pb - pa);
+	vecswap(a, pb - d1, d1);
+	d1 = MIN(pd - pc, pn - pd - es);
+	vecswap(pb, pn - d1, d1);
+
+	d1 = pb - pa;
+	d2 = pd - pc;
+	if (d1 <= d2) {
+		/* Recurse on left partition, then iterate on right partition */
+		if (d1 > es) {
 #ifdef I_AM_QSORT_R
-		qsort_r(a, r / es, es, thunk, cmp);
+			qsort_r(a, d1 / es, es, thunk, cmp);
 #else
-		qsort(a, r / es, es, cmp);
+			qsort(a, d1 / es, es, cmp);
 #endif
-	if ((r = pd - pc) > es) {
-		/* Iterate rather than recurse to save stack space */
-		a = pn - r;
-		n = r / es;
-		goto loop;
+		}
+		if (d2 > es) {
+			/* Iterate rather than recurse to save stack space */
+			/* qsort(pn - d2, d2 / es, es, cmp); */
+			a = pn - d2;
+			n = d2 / es;
+			goto loop;
+		}
+	} else {
+		/* Recurse on right partition, then iterate on left partition */
+		if (d2 > es) {
+#ifdef I_AM_QSORT_R
+			qsort_r(pn - d2, d2 / es, es, thunk, cmp);
+#else
+			qsort(pn - d2, d2 / es, es, cmp);
+#endif
+		}
+		if (d1 > es) {
+			/* Iterate rather than recurse to save stack space */
+			/* qsort(a, d1 / es, es, cmp); */
+			n = d1 / es;
+			goto loop;
+		}
 	}
-/*		qsort(pn - r, r / es, es, cmp);*/
 }
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 6195d40..fde4717 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -322,7 +322,7 @@
 static soinfo* __libdl_info = nullptr;
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
-soinfo* get_libdl_info(const char* linker_path) {
+soinfo* get_libdl_info(const char* linker_path, const link_map& linker_map) {
   if (__libdl_info == nullptr) {
     __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, linker_path, nullptr, 0, 0);
     __libdl_info->flags_ |= FLAG_LINKED;
@@ -338,6 +338,9 @@
     __libdl_info->soname_ = "ld-android.so";
     __libdl_info->target_sdk_version_ = __ANDROID_API__;
     __libdl_info->generate_handle();
+    __libdl_info->link_map_head.l_addr = linker_map.l_addr;
+    __libdl_info->link_map_head.l_name = linker_map.l_name;
+    __libdl_info->link_map_head.l_ld = linker_map.l_ld;
 #if defined(__work_around_b_24465209__)
     strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
 #endif
diff --git a/linker/linker.h b/linker/linker.h
index ae1ae3c..43d345c 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -100,7 +100,7 @@
 
 void count_relocation(RelocationKind kind);
 
-soinfo* get_libdl_info(const char* linker_path);
+soinfo* get_libdl_info(const char* linker_path, const link_map& linker_map);
 
 soinfo* find_containing_library(const void* p);
 
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 3d26e91..5dc215f 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -163,11 +163,11 @@
  * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
  * Note that the linker shouldn't be on the soinfo list.
  */
-static void init_linker_info_for_gdb(ElfW(Addr) linker_base, char* linker_path) {
-  static link_map linker_link_map_for_gdb;
+static link_map linker_link_map;
 
-  linker_link_map_for_gdb.l_addr = linker_base;
-  linker_link_map_for_gdb.l_name = linker_path;
+static void init_linker_info_for_gdb(ElfW(Addr) linker_base, char* linker_path) {
+  linker_link_map.l_addr = linker_base;
+  linker_link_map.l_name = linker_path;
 
   /*
    * Set the dynamic field in the link map otherwise gdb will complain with
@@ -178,9 +178,8 @@
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_base);
   ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_base + elf_hdr->e_phoff);
   phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
-                                 &linker_link_map_for_gdb.l_ld, nullptr);
+                                 &linker_link_map.l_ld, nullptr);
 
-  insert_link_map_into_debug_map(&linker_link_map_for_gdb);
 }
 
 extern "C" int __system_properties_init(void);
@@ -210,7 +209,7 @@
  * fixed it's own GOT. It is safe to make references to externs
  * and other non-local data at this point.
  */
-static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {
+static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) {
   ProtectedDataGuard guard;
 
 #if TIMING
@@ -288,7 +287,7 @@
   map->l_addr = 0;
   map->l_name = const_cast<char*>(executable_path);
   insert_link_map_into_debug_map(map);
-  init_linker_info_for_gdb(linker_base, kLinkerPath);
+  insert_link_map_into_debug_map(&linker_link_map);
 
   // Extract information passed from the kernel.
   si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
@@ -554,16 +553,18 @@
     exit(0);
   }
 
+  init_linker_info_for_gdb(linker_addr, kLinkerPath);
+
   // Initialize static variables. Note that in order to
   // get correct libdl_info we need to call constructors
   // before get_libdl_info().
-  sonext = solist = get_libdl_info(kLinkerPath);
+  sonext = solist = get_libdl_info(kLinkerPath, linker_link_map);
   g_default_namespace.add_soinfo(solist);
 
   // We have successfully fixed our own relocations. It's safe to run
   // the main part of the linker now.
   args.abort_message_ptr = &g_abort_message;
-  ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
+  ElfW(Addr) start_address = __linker_init_post_relocation(args);
 
   INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
 
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 71eb543..29b5c2b 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -337,7 +337,7 @@
   android_namespace_list_t secondary_namespaces_;
   uintptr_t handle_;
 
-  friend soinfo* get_libdl_info(const char* linker_path);
+  friend soinfo* get_libdl_info(const char* linker_path, const link_map& linker_map);
 };
 
 // This function is used by dlvsym() to calculate hash of sym_ver
diff --git a/tests/Android.bp b/tests/Android.bp
index e5a4d2c..2a5b47e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -89,6 +89,7 @@
         "nl_types_test.cpp",
         "pthread_test.cpp",
         "pty_test.cpp",
+        "qsort_test.cpp",
         "regex_test.cpp",
         "resolv_test.cpp",
         "sched_test.cpp",
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 275a5da..1bef0f4 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -277,9 +277,10 @@
 }
 
 /*
- * Kernels less than 4.1 are affected.
- * Devices that fail this test should include change id from Nexus:
- * Commit: 9b431291a1fadbdbcca1485711b5bab145112293
+ * b/28760453:
+ * Kernels older than 4.1 should have ext4 FALLOC_FL_PUNCH_HOLE disabled due to CVE-2015-8839.
+ * Devices that fail this test should cherry-pick the following commit:
+ * https://android.googlesource.com/kernel/msm/+/bdba352e898cbf57c8620ad68c8abf749c784d1f
  */
 TEST(fcntl, falloc_punch) {
   long major = 0, minor = 0;
diff --git a/tests/link_test.cpp b/tests/link_test.cpp
index ac3ccb9..a5430a9 100644
--- a/tests/link_test.cpp
+++ b/tests/link_test.cpp
@@ -46,9 +46,6 @@
     void DoChecks(dl_phdr_info* info, size_t s) {
       ASSERT_EQ(sizeof(dl_phdr_info), s);
 
-      // TODO: why does the entry for the main executable have a null dlpi_addr and no name anyway?
-      if (++count == 1 && info->dlpi_addr == 0) return;
-
       ASSERT_TRUE(info->dlpi_name != nullptr);
 
       // Find the first PT_LOAD program header so we can find the ELF header.
diff --git a/tests/qsort_test.cpp b/tests/qsort_test.cpp
new file mode 100644
index 0000000..95b4789
--- /dev/null
+++ b/tests/qsort_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <gtest/gtest.h>
+
+#include "gtest_globals.h"
+
+#define BUFFER_SIZE 1024
+
+static int cmp_long(const void *l, const void *r)
+{
+
+  return (*(long *)l - *(long *)r);
+}
+
+static int cmp_int(const void *l, const void *r)
+{
+
+  return (*(int *)l - *(int *)r);
+}
+
+#ifndef arc4random_uniform
+static bool seeded;
+
+u_int32_t arc4random_uniform(uint32_t upper_bound)
+{
+  if (!seeded) {
+    srandom((int)time(NULL));
+    seeded = true;
+  }
+
+  return (random() % upper_bound);
+}
+#endif
+
+TEST(qsort_test, long_test) {
+  long buf[BUFFER_SIZE];
+  long i;
+
+  /* Initialize buffer with known numbers */
+  for (i=0; i<BUFFER_SIZE; i++)
+    buf[i] = i;
+
+  /* Stir 1/4 pairs in the buffer */
+  for (i=0; i<BUFFER_SIZE/4; i++) {
+    u_int32_t pos1, pos2;
+    long t;
+
+    pos1 = arc4random_uniform(BUFFER_SIZE);
+    pos2 = arc4random_uniform(BUFFER_SIZE);
+
+    t = buf[pos1];
+    buf[pos1] = buf[pos2];
+    buf[pos2] = t;
+  }
+
+  /* Sort */
+  qsort(buf, BUFFER_SIZE, sizeof(buf[0]), &cmp_long);
+
+  for (i=0; i<BUFFER_SIZE; i++)
+    EXPECT_EQ(i, buf[i]);
+}
+
+TEST(qsort_test, int_test) {
+  int buf[BUFFER_SIZE];
+  int i;
+
+  /* Initialize buffer with known numbers */
+  for (i=0; i<BUFFER_SIZE; i++)
+    buf[i] = i;
+
+  /* Stir 1/4 pairs in the buffer */
+  for (i=0; i<BUFFER_SIZE/4; i++) {
+    u_int32_t pos1, pos2;
+    int t;
+
+    pos1 = arc4random_uniform(BUFFER_SIZE);
+    pos2 = arc4random_uniform(BUFFER_SIZE);
+
+    t = buf[pos1];
+    buf[pos1] = buf[pos2];
+    buf[pos2] = t;
+  }
+
+  /* Sort */
+  qsort(buf, BUFFER_SIZE, sizeof(buf[0]), &cmp_int);
+
+  for (i=0; i<BUFFER_SIZE; i++)
+    EXPECT_EQ(i, buf[i]);
+}