Merge "Revert "Move __system_property* to LIBC_PRIVATE for lp64 libc""
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index b44c296..0000000
--- a/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/Android.mk b/Android.mk
index 7c39751..9f0f0c3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,4 +16,5 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under,$(LOCAL_PATH)) \
+	$(call all-makefiles-under,$(LOCAL_PATH)/libc)
diff --git a/libc/Android.bp b/libc/Android.bp
index 74fd22b..8df77ce 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -112,11 +112,6 @@
         device_uses_dlmalloc: {
             cflags: ["-DUSE_DLMALLOC"],
         },
-        // To customize dlmalloc's alignment, set BOARD_MALLOC_ALIGNMENT in
-        // the appropriate BoardConfig.mk file.
-        dlmalloc_alignment: {
-            cflags: ["-DMALLOC_ALIGNMENT=%d"],
-        },
     },
     // Clang/llvm has incompatible long double (fp128) for x86_64.
     // https://llvm.org/bugs/show_bug.cgi?id=23897
@@ -142,18 +137,47 @@
 // libc_stack_protector.a - stack protector code
 // ========================================================
 //
-// The stack protector code needs to be compiled
-// with -fno-stack-protector, since it modifies the
-// stack canary.
+// Code that implements the stack protector (or that runs
+// before TLS has been set up) needs to be compiled with
+// -fno-stack-protector, since it accesses the stack canary
+// TLS slot.
 
 cc_library_static {
 
-    srcs: ["bionic/__stack_chk_fail.cpp"],
+    srcs: [
+        "bionic/__libc_init_main_thread.cpp",
+        "bionic/__stack_chk_fail.cpp",
+    ],
+    arch: {
+        arm64: {
+            srcs: ["arch-arm64/bionic/__set_tls.c"],
+        },
+        x86: {
+            srcs: ["arch-arm64/bionic/__set_tls.c"],
+        },
+        x86_64: {
+            srcs: ["arch-x86_64/bionic/__set_tls.c"],
+        },
+    },
+
     defaults: ["libc_defaults"],
     cflags: ["-fno-stack-protector"],
     name: "libc_stack_protector",
 }
 
+// libc_init_static.cpp also needs to be built without stack protector,
+// because it's responsible for setting up TLS for static executables.
+// This isn't the case for dynamic executables because the dynamic linker
+// has already set up the main thread's TLS.
+
+cc_library_static {
+    name: "libc_init_static",
+    defaults: ["libc_defaults"],
+    srcs: ["bionic/libc_init_static.cpp"],
+    cflags: ["-fno-stack-protector"],
+}
+
+
 // ========================================================
 // libc_tzcode.a - upstream 'tzcode' code
 // ========================================================
@@ -1089,7 +1113,6 @@
                 "arch-arm64/bionic/__bionic_clone.S",
                 "arch-arm64/bionic/_exit_with_stack_teardown.S",
                 "arch-arm64/bionic/setjmp.S",
-                "arch-arm64/bionic/__set_tls.c",
                 "arch-arm64/bionic/syscall.S",
                 "arch-arm64/bionic/vfork.S",
 
@@ -1173,7 +1196,6 @@
                 "arch-x86/bionic/libgcc_compat.c",
                 "arch-x86/bionic/__restore.S",
                 "arch-x86/bionic/setjmp.S",
-                "arch-x86/bionic/__set_tls.c",
                 "arch-x86/bionic/syscall.S",
                 "arch-x86/bionic/vfork.S",
 
@@ -1214,7 +1236,9 @@
                     "arch-x86/atom/string/sse2-strlen-atom.S",
                     "arch-x86/atom/string/ssse3-bcopy-atom.S",
                     "arch-x86/atom/string/ssse3-memcmp-atom.S",
+                    "arch-x86/atom/string/ssse3-memcpy-atom.S",
                     "arch-x86/atom/string/ssse3-memmove-atom.S",
+                    "arch-x86/atom/string/ssse3-strcpy-atom.S",
                     "arch-x86/atom/string/ssse3-strncpy-atom.S",
                     "arch-x86/atom/string/ssse3-wmemcmp-atom.S",
                 ],
@@ -1263,7 +1287,6 @@
                 "arch-x86_64/bionic/_exit_with_stack_teardown.S",
                 "arch-x86_64/bionic/__restore_rt.S",
                 "arch-x86_64/bionic/setjmp.S",
-                "arch-x86_64/bionic/__set_tls.c",
                 "arch-x86_64/bionic/syscall.S",
                 "arch-x86_64/bionic/vfork.S",
 
@@ -1348,6 +1371,7 @@
         "bionic/getpid.cpp",
         "bionic/gettid.cpp",
         "bionic/__gnu_basename.cpp",
+        "bionic/ifaddrs.cpp",
         "bionic/inotify_init.cpp",
         "bionic/ioctl.cpp",
         "bionic/lchown.cpp",
@@ -1674,7 +1698,6 @@
     defaults: ["libc_defaults"],
     srcs: [
         "bionic/dl_iterate_phdr_static.cpp",
-        "bionic/libc_init_static.cpp",
     ],
 
     arch: {
@@ -1687,7 +1710,10 @@
 
     name: "libc_nomalloc",
 
-    whole_static_libs: ["libc_common"],
+    whole_static_libs: [
+        "libc_common",
+        "libc_init_static",
+    ],
 }
 
 // ========================================================
@@ -1724,9 +1750,9 @@
     static: {
         srcs: [
             "bionic/dl_iterate_phdr_static.cpp",
-            "bionic/libc_init_static.cpp",
         ],
         cflags: ["-DLIBC_STATIC"],
+        whole_static_libs: ["libc_init_static"],
     },
     shared: {
         srcs: [
@@ -1766,7 +1792,6 @@
 
     nocrt: true,
 
-    // special for arm
     arch: {
         arm: {
             //TODO: This is to work around b/24465209. Remove after root cause is fixed
@@ -1774,6 +1799,11 @@
 
             // Don't re-export new/delete and friends, even if the compiler really wants to.
             version_script: "libc.arm.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.arm.brillo.map",
+                },
+            },
 
             shared: {
                 srcs: ["arch-arm/bionic/exidx_dynamic.c"],
@@ -1781,6 +1811,8 @@
             static: {
                 srcs: ["arch-arm/bionic/exidx_static.c"],
             },
+
+            // special for arm
             cflags: ["-DCRT_LEGACY_WORKAROUND"],
             srcs: [
                 "arch-arm/bionic/atexit_legacy.c",
@@ -1793,6 +1825,11 @@
         mips: {
             // Don't re-export new/delete and friends, even if the compiler really wants to.
             version_script: "libc.mips.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.mips.brillo.map",
+                },
+            },
         },
         mips64: {
             // Don't re-export new/delete and friends, even if the compiler really wants to.
@@ -1804,6 +1841,11 @@
 
             // Don't re-export new/delete and friends, even if the compiler really wants to.
             version_script: "libc.x86.map",
+            product_variables: {
+                brillo: {
+                    version_script: "libc.x86.brillo.map",
+                },
+            },
         },
         x86_64: {
             // Don't re-export new/delete and friends, even if the compiler really wants to.
diff --git a/libc/Android.mk b/libc/Android.mk
index a399b89..39c8c9e 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -149,6 +149,7 @@
     bionic/getpid.cpp \
     bionic/gettid.cpp \
     bionic/__gnu_basename.cpp \
+    bionic/ifaddrs.cpp \
     bionic/inotify_init.cpp \
     bionic/ioctl.cpp \
     bionic/lchown.cpp \
@@ -644,7 +645,7 @@
   libc_common_cflags += -DDEBUG
 endif
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
   libc_common_cflags += -DUSE_DLMALLOC
   libc_malloc_src := bionic/dlmalloc.c
 else
@@ -653,13 +654,6 @@
   libc_common_c_includes += external/jemalloc/include
 endif
 
-# To customize dlmalloc's alignment, set BOARD_MALLOC_ALIGNMENT in
-# the appropriate BoardConfig.mk file.
-#
-ifneq ($(BOARD_MALLOC_ALIGNMENT),)
-  libc_common_cflags += -DMALLOC_ALIGNMENT=$(BOARD_MALLOC_ALIGNMENT)
-endif
-
 # Define some common conlyflags
 libc_common_conlyflags := \
     -std=gnu99
@@ -690,16 +684,21 @@
 # libc_stack_protector.a - stack protector code
 # ========================================================
 #
-# The stack protector code needs to be compiled
-# with -fno-stack-protector, since it modifies the
-# stack canary.
+# Code that implements the stack protector (or that runs
+# before TLS has been set up) needs to be compiled with
+# -fno-stack-protector, since it accesses the stack canary
+# TLS slot.
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := bionic/__stack_chk_fail.cpp
-# On x86, the __set_tls implementation is complex enough that
-# -fstack-protector-strong inserts a check.
+LOCAL_SRC_FILES := \
+    bionic/__libc_init_main_thread.cpp \
+    bionic/__stack_chk_fail.cpp \
+
+LOCAL_SRC_FILES_arm64 := arch-arm64/bionic/__set_tls.c
 LOCAL_SRC_FILES_x86 := arch-x86/bionic/__set_tls.c
+LOCAL_SRC_FILES_x86_64 := arch-x86_64/bionic/__set_tls.c
+
 LOCAL_CFLAGS := $(libc_common_cflags) -fno-stack-protector
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
@@ -716,6 +715,30 @@
 include $(BUILD_STATIC_LIBRARY)
 
 
+# libc_init_static.cpp also needs to be built without stack protector,
+# because it's responsible for setting up TLS for static executables.
+# This isn't the case for dynamic executables because the dynamic linker
+# has already set up the main thread's TLS.
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bionic/libc_init_static.cpp
+LOCAL_CFLAGS := $(libc_common_cflags) -fno-stack-protector
+LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
+LOCAL_CPPFLAGS := $(libc_common_cppflags)
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+LOCAL_MODULE := libc_init_static
+LOCAL_CLANG := $(use_clang)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
+LOCAL_CXX_STL := none
+LOCAL_SYSTEM_SHARED_LIBRARIES :=
+LOCAL_SANITIZE := never
+LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+
+$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
+include $(BUILD_STATIC_LIBRARY)
+
+
 # ========================================================
 # libc_tzcode.a - upstream 'tzcode' code
 # ========================================================
@@ -1205,7 +1228,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES_arm := libc_aeabi
 LOCAL_CXX_STL := none
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
@@ -1277,7 +1300,6 @@
 
 LOCAL_SRC_FILES := \
     $(libc_arch_static_src_files) \
-    bionic/libc_init_static.cpp
 
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 LOCAL_CFLAGS := $(libc_common_cflags) \
@@ -1289,7 +1311,7 @@
 LOCAL_MODULE := libc_nomalloc
 LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common libc_init_static
 LOCAL_CXX_STL := none
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 LOCAL_SANITIZE := never
@@ -1329,7 +1351,6 @@
 LOCAL_SRC_FILES := \
     $(libc_arch_static_src_files) \
     bionic/malloc_debug_common.cpp \
-    bionic/libc_init_static.cpp \
 
 LOCAL_CFLAGS := $(libc_common_cflags) \
     -DLIBC_STATIC \
@@ -1340,9 +1361,9 @@
 LOCAL_MODULE := libc
 LOCAL_CLANG := $(use_clang)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
-LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common libc_init_static
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
@@ -1408,7 +1429,7 @@
 LOCAL_SHARED_LIBRARIES := libdl
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 
-ifneq ($(MALLOC_IMPL),dlmalloc)
+ifneq ($(MALLOC_SVELTE),true)
 LOCAL_WHOLE_STATIC_LIBRARIES += libjemalloc
 endif
 
@@ -1608,6 +1629,3 @@
 LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
 include $(BUILD_STATIC_LIBRARY)
 
-
-# ========================================================
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libc/arch-arm/bionic/__aeabi.c b/libc/arch-arm/bionic/__aeabi.c
index 254c7a6..1620d45 100644
--- a/libc/arch-arm/bionic/__aeabi.c
+++ b/libc/arch-arm/bionic/__aeabi.c
@@ -51,34 +51,62 @@
  */
 
 int __attribute__((weak))
-__aeabi_atexit(void *object, void (*destructor) (void *), void *dso_handle) {
+__aeabi_atexit_impl(void *object, void (*destructor) (void *), void *dso_handle) {
+    return __cxa_atexit(destructor, object, dso_handle);
+}
+
+int __attribute__((weak))
+__aeabi_atexit_impl2(void *object, void (*destructor) (void *), void *dso_handle) {
     return __cxa_atexit(destructor, object, dso_handle);
 }
 
 
-void __attribute__((weak))
-__aeabi_memcpy8(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy8_impl(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memcpy4(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy4_impl(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memcpy(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memcpy_impl(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy8_impl2(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy4_impl2(void *dest, const void *src, size_t n) {
+    memcpy(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memcpy_impl2(void *dest, const void *src, size_t n) {
     memcpy(dest, src, n);
 }
 
 
-void __attribute__((weak)) __aeabi_memmove8(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove8_impl(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memmove4(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove4_impl(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
-void __attribute__((weak)) __aeabi_memmove(void *dest, const void *src, size_t n) {
+void __attribute__((weak)) __aeabi_memmove_impl(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove8_impl2(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove4_impl2(void *dest, const void *src, size_t n) {
+    memmove(dest, src, n);
+}
+
+void __attribute__((weak)) __aeabi_memmove_impl2(void *dest, const void *src, size_t n) {
     memmove(dest, src, n);
 }
 
@@ -87,27 +115,71 @@
  *  This allows __aeabi_memclr to tail-call __aeabi_memset
  */
 
-void __attribute__((weak)) __aeabi_memset8(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset8_impl(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
-void __attribute__((weak)) __aeabi_memset4(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset4_impl(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
-void __attribute__((weak)) __aeabi_memset(void *dest, size_t n, int c) {
+void __attribute__((weak)) __aeabi_memset_impl(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset8_impl2(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset4_impl2(void *dest, size_t n, int c) {
+    memset(dest, c, n);
+}
+
+void __attribute__((weak)) __aeabi_memset_impl2(void *dest, size_t n, int c) {
     memset(dest, c, n);
 }
 
 
-void __attribute__((weak)) __aeabi_memclr8(void *dest, size_t n) {
-    __aeabi_memset8(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr8_impl(void *dest, size_t n) {
+    __aeabi_memset8_impl(dest, n, 0);
 }
 
-void __attribute__((weak)) __aeabi_memclr4(void *dest, size_t n) {
-    __aeabi_memset4(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr4_impl(void *dest, size_t n) {
+    __aeabi_memset4_impl(dest, n, 0);
 }
 
-void __attribute__((weak)) __aeabi_memclr(void *dest, size_t n) {
-    __aeabi_memset(dest, n, 0);
+void __attribute__((weak)) __aeabi_memclr_impl(void *dest, size_t n) {
+    __aeabi_memset_impl(dest, n, 0);
 }
+
+void __attribute__((weak)) __aeabi_memclr8_impl2(void *dest, size_t n) {
+    __aeabi_memset8_impl(dest, n, 0);
+}
+
+void __attribute__((weak)) __aeabi_memclr4_impl2(void *dest, size_t n) {
+    __aeabi_memset4_impl(dest, n, 0);
+}
+
+void __attribute__((weak)) __aeabi_memclr_impl2(void *dest, size_t n) {
+    __aeabi_memset_impl(dest, n, 0);
+}
+
+#define __AEABI_SYMVERS(fn_name) \
+__asm__(".symver " #fn_name "_impl, " #fn_name "@@LIBC_N"); \
+__asm__(".symver " #fn_name "_impl2, " #fn_name "@LIBC_PRIVATE")
+
+__AEABI_SYMVERS(__aeabi_atexit);
+__AEABI_SYMVERS(__aeabi_memcpy8);
+__AEABI_SYMVERS(__aeabi_memcpy4);
+__AEABI_SYMVERS(__aeabi_memcpy);
+__AEABI_SYMVERS(__aeabi_memmove8);
+__AEABI_SYMVERS(__aeabi_memmove4);
+__AEABI_SYMVERS(__aeabi_memmove);
+__AEABI_SYMVERS(__aeabi_memset8);
+__AEABI_SYMVERS(__aeabi_memset4);
+__AEABI_SYMVERS(__aeabi_memset);
+__AEABI_SYMVERS(__aeabi_memclr8);
+__AEABI_SYMVERS(__aeabi_memclr4);
+__AEABI_SYMVERS(__aeabi_memclr);
+
+#undef __AEABI_SYMVERS
diff --git a/libc/arch-arm/bionic/exidx_dynamic.c b/libc/arch-arm/bionic/exidx_dynamic.c
index c7b7156..60ac8af 100644
--- a/libc/arch-arm/bionic/exidx_dynamic.c
+++ b/libc/arch-arm/bionic/exidx_dynamic.c
@@ -37,7 +37,13 @@
  * the expectation that libc will define it and call through to
  * a differently-named function in the dynamic linker.
  */
-_Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount)
-{
+_Unwind_Ptr __gnu_Unwind_Find_exidx_impl(_Unwind_Ptr pc, int *pcount) {
     return dl_unwind_find_exidx(pc, pcount);
 }
+
+_Unwind_Ptr __gnu_Unwind_Find_exidx_impl2(_Unwind_Ptr pc, int *pcount) {
+    return dl_unwind_find_exidx(pc, pcount);
+}
+
+__asm__(".symver __gnu_Unwind_Find_exidx_impl,__gnu_Unwind_Find_exidx@LIBC_PRIVATE");
+__asm__(".symver __gnu_Unwind_Find_exidx_impl2,__gnu_Unwind_Find_exidx@@LIBC_N");
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index 0811c96..9a76072 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -42,7 +42,6 @@
     arch-arm64/bionic/__bionic_clone.S \
     arch-arm64/bionic/_exit_with_stack_teardown.S \
     arch-arm64/bionic/setjmp.S \
-    arch-arm64/bionic/__set_tls.c \
     arch-arm64/bionic/syscall.S \
     arch-arm64/bionic/vfork.S \
 
diff --git a/libc/arch-x86/atom/string/sse2-strrchr-atom.S b/libc/arch-x86/atom/string/sse2-strrchr-atom.S
index da3dc3b..e916bc1 100644
--- a/libc/arch-x86/atom/string/sse2-strrchr-atom.S
+++ b/libc/arch-x86/atom/string/sse2-strrchr-atom.S
@@ -278,7 +278,7 @@
 	jnz	L(FindZeroExit2)
 	test	$0x04, %cl
 	jnz	L(FindZeroExit3)
-	and	$1 << 4 - 1, %eax
+	and	$(1 << 4) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -296,7 +296,7 @@
 	jnz	L(FindZeroExit6)
 	test	$0x40, %cl
 	jnz	L(FindZeroExit7)
-	and	$1 << 8 - 1, %eax
+	and	$(1 << 8) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -317,7 +317,7 @@
 	jnz	L(FindZeroExit10)
 	test	$0x04, %ch
 	jnz	L(FindZeroExit11)
-	and	$1 << 12 - 1, %eax
+	and	$(1 << 12) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -335,7 +335,7 @@
 	jnz	L(FindZeroExit14)
 	test	$0x40, %ch
 	jnz	L(FindZeroExit15)
-	and	$1 << 16 - 1, %eax
+	and	$(1 << 16) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -359,7 +359,7 @@
 
 	.p2align 4
 L(FindZeroExit2):
-	and	$1 << 2 - 1, %eax
+	and	$(1 << 2) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -371,7 +371,7 @@
 
 	.p2align 4
 L(FindZeroExit3):
-	and	$1 << 3 - 1, %eax
+	and	$(1 << 3) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -383,7 +383,7 @@
 
 	.p2align 4
 L(FindZeroExit5):
-	and	$1 << 5 - 1, %eax
+	and	$(1 << 5) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -395,7 +395,7 @@
 
 	.p2align 4
 L(FindZeroExit6):
-	and	$1 << 6 - 1, %eax
+	and	$(1 << 6) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -407,7 +407,7 @@
 
 	.p2align 4
 L(FindZeroExit7):
-	and	$1 << 7 - 1, %eax
+	and	$(1 << 7) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -419,7 +419,7 @@
 
 	.p2align 4
 L(FindZeroExit9):
-	and	$1 << 9 - 1, %eax
+	and	$(1 << 9) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -431,7 +431,7 @@
 
 	.p2align 4
 L(FindZeroExit10):
-	and	$1 << 10 - 1, %eax
+	and	$(1 << 10) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -443,7 +443,7 @@
 
 	.p2align 4
 L(FindZeroExit11):
-	and	$1 << 11 - 1, %eax
+	and	$(1 << 11) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -455,7 +455,7 @@
 
 	.p2align 4
 L(FindZeroExit13):
-	and	$1 << 13 - 1, %eax
+	and	$(1 << 13) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -467,7 +467,7 @@
 
 	.p2align 4
 L(FindZeroExit14):
-	and	$1 << 14 - 1, %eax
+	and	$(1 << 14) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -479,7 +479,7 @@
 
 	.p2align 4
 L(FindZeroExit15):
-	and	$1 << 15 - 1, %eax
+	and	$(1 << 15) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%ebx)
@@ -619,7 +619,7 @@
 	jnz	L(PrologFindZeroExit2)
 	test	$0x04, %cl
 	jnz	L(PrologFindZeroExit3)
-	and	$1 << 4 - 1, %eax
+	and	$(1 << 4) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
@@ -632,7 +632,7 @@
 	jnz	L(PrologFindZeroExit6)
 	test	$0x40, %cl
 	jnz	L(PrologFindZeroExit7)
-	and	$1 << 8 - 1, %eax
+	and	$(1 << 8) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
@@ -648,7 +648,7 @@
 	jnz	L(PrologFindZeroExit10)
 	test	$0x04, %ch
 	jnz	L(PrologFindZeroExit11)
-	and	$1 << 12 - 1, %eax
+	and	$(1 << 12) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
@@ -661,7 +661,7 @@
 	jnz	L(PrologFindZeroExit14)
 	test	$0x40, %ch
 	jnz	L(PrologFindZeroExit15)
-	and	$1 << 16 - 1, %eax
+	and	$(1 << 16) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
@@ -675,77 +675,77 @@
 
 	.p2align 4
 L(PrologFindZeroExit2):
-	and	$1 << 2 - 1, %eax
+	and	$(1 << 2) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit3):
-	and	$1 << 3 - 1, %eax
+	and	$(1 << 3) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit5):
-	and	$1 << 5 - 1, %eax
+	and	$(1 << 5) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit6):
-	and	$1 << 6 - 1, %eax
+	and	$(1 << 6) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit7):
-	and	$1 << 7 - 1, %eax
+	and	$(1 << 7) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit9):
-	and	$1 << 9 - 1, %eax
+	and	$(1 << 9) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit10):
-	and	$1 << 10 - 1, %eax
+	and	$(1 << 10) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit11):
-	and	$1 << 11 - 1, %eax
+	and	$(1 << 11) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit13):
-	and	$1 << 13 - 1, %eax
+	and	$(1 << 13) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit14):
-	and	$1 << 14 - 1, %eax
+	and	$(1 << 14) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
 
 	.p2align 4
 L(PrologFindZeroExit15):
-	and	$1 << 15 - 1, %eax
+	and	$(1 << 15) - 1, %eax
 	jnz	L(match_case1)
 	xor	%eax, %eax
 	RETURN
diff --git a/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S b/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S
index e30779d..1a55df2 100644
--- a/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S
+++ b/libc/arch-x86/atom/string/sse2-wcsrchr-atom.S
@@ -280,7 +280,7 @@
 
 	.p2align 4
 L(find_zero_in_second_wchar):
-	and	$1 << 5 - 1, %eax
+	and	$(1 << 5) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%esi)
@@ -296,7 +296,7 @@
 L(find_zero_in_third_or_fourth_wchar):
 	test	$15, %ch
 	jz	L(find_zero_in_fourth_wchar)
-	and	$1 << 9 - 1, %eax
+	and	$(1 << 9) - 1, %eax
 	jz	L(return_value)
 
 	POP	(%esi)
@@ -368,7 +368,7 @@
 
 	.p2align 4
 L(prolog_find_zero_in_second_wchar):
-	and	$1 << 5 - 1, %eax
+	and	$(1 << 5) - 1, %eax
 	jz	L(return_null)
 
 	test	$15 << 4, %al
@@ -380,7 +380,7 @@
 L(prolog_find_zero_in_third_or_fourth_wchar):
 	test	$15, %ch
 	jz	L(prolog_find_zero_in_fourth_wchar)
-	and	$1 << 9 - 1, %eax
+	and	$(1 << 9) - 1, %eax
 	jz	L(return_null)
 
 	test	%ah, %ah
diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk
index bbf5c8c..ce06217 100644
--- a/libc/arch-x86_64/x86_64.mk
+++ b/libc/arch-x86_64/x86_64.mk
@@ -25,7 +25,6 @@
     arch-x86_64/bionic/_exit_with_stack_teardown.S \
     arch-x86_64/bionic/__restore_rt.S \
     arch-x86_64/bionic/setjmp.S \
-    arch-x86_64/bionic/__set_tls.c \
     arch-x86_64/bionic/syscall.S \
     arch-x86_64/bionic/vfork.S \
 
diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp
index 0e903b9..6284b12 100644
--- a/libc/bionic/__cxa_thread_atexit_impl.cpp
+++ b/libc/bionic/__cxa_thread_atexit_impl.cpp
@@ -17,7 +17,8 @@
 
 #include "pthread_internal.h"
 
-struct thread_local_dtor {
+class thread_local_dtor {
+ public:
   void (*func) (void *);
   void *arg;
   void *dso_handle; // unused...
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
new file mode 100644
index 0000000..e1445cb
--- /dev/null
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libc_init_common.h"
+
+#include "private/bionic_auxv.h"
+#include "private/bionic_globals.h"
+#include "private/KernelArgumentBlock.h"
+#include "pthread_internal.h"
+
+extern "C" int __set_tls(void* ptr);
+extern "C" int __set_tid_address(int* tid_address);
+
+// Setup for the main thread. For dynamic executables, this is called by the
+// linker _before_ libc is mapped in memory. This means that all writes to
+// globals from this function will apply to linker-private copies and will not
+// be visible from libc later on.
+//
+// Note: this function creates a pthread_internal_t for the initial thread and
+// stores the pointer in TLS, but does not add it to pthread's thread list. This
+// has to be done later from libc itself (see __libc_init_common).
+//
+// This is in a file by itself because it needs to be built with
+// -fno-stack-protector because it's responsible for setting up the main
+// thread's TLS (which stack protector relies on).
+
+void __libc_init_main_thread(KernelArgumentBlock& args) {
+  __libc_auxv = args.auxv;
+
+  static pthread_internal_t main_thread;
+
+  // The -fstack-protector implementation uses TLS, so make sure that's
+  // set up before we call any function that might get a stack check inserted.
+  __set_tls(main_thread.tls);
+
+  // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
+  // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
+  main_thread.tid = __set_tid_address(&main_thread.tid);
+  main_thread.set_cached_pid(main_thread.tid);
+
+  // We don't want to free the main thread's stack even when the main thread exits
+  // because things like environment variables with global scope live on it.
+  // We also can't free the pthread_internal_t itself, since that lives on the main
+  // thread's stack rather than on the heap.
+  // The main thread has no mmap allocated space for stack or pthread_internal_t.
+  main_thread.mmap_size = 0;
+  pthread_attr_init(&main_thread.attr);
+  main_thread.attr.guard_size = 0; // The main thread has no guard page.
+  main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked.
+  // TODO: the main thread's sched_policy and sched_priority need to be queried.
+
+  __init_thread(&main_thread);
+  __init_tls(&main_thread);
+
+  // Store a pointer to the kernel argument block in a TLS slot to be
+  // picked up by the libc constructor.
+  main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
+
+  __init_alternate_signal_stack(&main_thread);
+}
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
new file mode 100644
index 0000000..b66883e
--- /dev/null
+++ b/libc/bionic/ifaddrs.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ifaddrs.h>
+
+#include <errno.h>
+#include <linux/if_packet.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// The public ifaddrs struct is full of pointers. Rather than track several
+// different allocations, we use a maximally-sized structure with the public
+// part at offset 0, and pointers into its hidden tail.
+struct ifaddrs_storage {
+  // Must come first, so that `ifaddrs_storage` is-a `ifaddrs`.
+  ifaddrs ifa;
+
+  // The interface index, so we can match RTM_NEWADDR messages with
+  // earlier RTM_NEWLINK messages (to copy the interface flags).
+  int interface_index;
+
+  // Storage for the pointers in `ifa`.
+  sockaddr_storage addr;
+  sockaddr_storage netmask;
+  sockaddr_storage ifa_ifu;
+  char name[IFNAMSIZ + 1];
+
+  ifaddrs_storage(ifaddrs** list) {
+    memset(this, 0, sizeof(*this));
+
+    // push_front onto `list`.
+    ifa.ifa_next = *list;
+    *list = reinterpret_cast<ifaddrs*>(this);
+  }
+
+  // Netlink gives us the address family in the header, and the
+  // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
+  // stitch the two bits together into the sockaddr that's part of
+  // our portable interface.
+  void SetAddress(int family, const void* data, size_t byteCount) {
+      addr.ss_family = family;
+      memcpy(SockaddrBytes(family, &addr), data, byteCount);
+      ifa.ifa_addr = reinterpret_cast<sockaddr*>(&addr);
+  }
+
+  void SetBroadcastAddress(int family, const void* data, size_t byteCount) {
+      ifa_ifu.ss_family = family;
+      memcpy(SockaddrBytes(family, &ifa_ifu), data, byteCount);
+      ifa.ifa_dstaddr = reinterpret_cast<sockaddr*>(&ifa_ifu);
+  }
+
+  // Netlink gives us the prefix length as a bit count. We need to turn
+  // that into a BSD-compatible netmask represented by a sockaddr*.
+  void SetNetmask(int family, size_t prefix_length) {
+      // ...and work out the netmask from the prefix length.
+      netmask.ss_family = family;
+      uint8_t* dst = SockaddrBytes(family, &netmask);
+      memset(dst, 0xff, prefix_length / 8);
+      if ((prefix_length % 8) != 0) {
+        dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8)));
+      }
+      ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask);
+  }
+
+  void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) {
+    sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(&addr);
+    sll->sll_ifindex = ifindex;
+    sll->sll_hatype = hatype;
+    sll->sll_halen = halen;
+  }
+
+ private:
+  // Returns a pointer to the first byte in the address data (which is
+  // stored in network byte order).
+  uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) {
+    if (family == AF_INET) {
+      sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
+      return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
+    } else if (family == AF_INET6) {
+      sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
+      return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
+    } else if (family == AF_PACKET) {
+      sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ss);
+      return reinterpret_cast<uint8_t*>(&sll->sll_addr);
+    }
+    return nullptr;
+  }
+};
+
+#if !defined(__clang__)
+// GCC gets confused by NLMSG_DATA and doesn't realize that the old-style
+// cast is from a system header and should be ignored.
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#endif
+
+static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) {
+  if (hdr->nlmsg_type == RTM_NEWLINK) {
+    ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr));
+
+    // Create a new ifaddr entry, and set the interface index and flags.
+    ifaddrs_storage* new_addr = new ifaddrs_storage(out);
+    new_addr->interface_index = ifi->ifi_index;
+    new_addr->ifa.ifa_flags = ifi->ifi_flags;
+
+    // Go through the various bits of information and find the name.
+    rtattr* rta = IFLA_RTA(ifi);
+    size_t rta_len = IFLA_PAYLOAD(hdr);
+    while (RTA_OK(rta, rta_len)) {
+      if (rta->rta_type == IFLA_ADDRESS) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) {
+            new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
+          }
+      } else if (rta->rta_type == IFLA_BROADCAST) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) {
+            new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
+          }
+      } else if (rta->rta_type == IFLA_IFNAME) {
+          if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
+            memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
+            new_addr->ifa.ifa_name = new_addr->name;
+          }
+      }
+      rta = RTA_NEXT(rta, rta_len);
+    }
+  } else if (hdr->nlmsg_type == RTM_NEWADDR) {
+    ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
+
+    // We should already know about this from an RTM_NEWLINK message.
+    const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out);
+    while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) {
+      addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next);
+    }
+    // If this is an unknown interface, ignore whatever we're being told about it.
+    if (addr == nullptr) return;
+
+    // Create a new ifaddr entry and copy what we already know.
+    ifaddrs_storage* new_addr = new ifaddrs_storage(out);
+    // We can just copy the name rather than look for IFA_LABEL.
+    strcpy(new_addr->name, addr->name);
+    new_addr->ifa.ifa_name = new_addr->name;
+    new_addr->ifa.ifa_flags = addr->ifa.ifa_flags;
+    new_addr->interface_index = addr->interface_index;
+
+    // Go through the various bits of information and find the address
+    // and any broadcast/destination address.
+    rtattr* rta = IFA_RTA(msg);
+    size_t rta_len = IFA_PAYLOAD(hdr);
+    while (RTA_OK(rta, rta_len)) {
+      if (rta->rta_type == IFA_ADDRESS) {
+        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
+          new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+          new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
+        }
+      } else if (rta->rta_type == IFA_BROADCAST) {
+        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
+          new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
+        }
+      }
+      rta = RTA_NEXT(rta, rta_len);
+    }
+  }
+}
+
+static bool __send_netlink_request(int fd, int type) {
+  struct NetlinkMessage {
+    nlmsghdr hdr;
+    rtgenmsg msg;
+  } request;
+  memset(&request, 0, sizeof(request));
+  request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+  request.hdr.nlmsg_type = type;
+  request.hdr.nlmsg_len = sizeof(request);
+  request.msg.rtgen_family = AF_UNSPEC; // All families.
+  return (TEMP_FAILURE_RETRY(send(fd, &request, sizeof(request), 0)) == sizeof(request));
+}
+
+static bool __read_netlink_responses(int fd, ifaddrs** out, char* buf, size_t buf_len) {
+  ssize_t bytes_read;
+  // Read through all the responses, handing interesting ones to __handle_netlink_response.
+  while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd, buf, buf_len, 0))) > 0) {
+    nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buf);
+    for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
+      if (hdr->nlmsg_type == NLMSG_DONE) return true;
+      if (hdr->nlmsg_type == NLMSG_ERROR) return false;
+      __handle_netlink_response(out, hdr);
+    }
+  }
+  // We only get here if recv fails before we see a NLMSG_DONE.
+  return false;
+}
+
+int getifaddrs(ifaddrs** out) {
+  // Make cleanup easy.
+  *out = nullptr;
+
+  // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE),
+  // but that's a bit too large to go on the stack.
+  size_t buf_len = 8192;
+  char* buf = new char[buf_len];
+  if (buf == nullptr) return -1;
+
+  // Open the netlink socket and ask for all the links and addresses.
+  int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
+  bool okay = fd != -1 &&
+      __send_netlink_request(fd, RTM_GETLINK) && __read_netlink_responses(fd, out, buf, buf_len) &&
+      __send_netlink_request(fd, RTM_GETADDR) && __read_netlink_responses(fd, out, buf, buf_len);
+
+  if (!okay) {
+    freeifaddrs(*out);
+    // Ensure that callers crash if they forget to check for success.
+    *out = nullptr;
+  }
+  {
+    int saved_errno = errno;
+    close(fd);
+    delete[] buf;
+    errno = saved_errno;
+  }
+  return okay ? 0 : -1;
+}
+
+void freeifaddrs(ifaddrs* list) {
+  while (list != nullptr) {
+    ifaddrs* current = list;
+    list = list->ifa_next;
+    free(current);
+  }
+}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index b0c62d6..532dab9 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -52,8 +52,6 @@
 
 extern "C" abort_msg_t** __abort_message_ptr;
 extern "C" int __system_properties_init(void);
-extern "C" int __set_tls(void* ptr);
-extern "C" int __set_tid_address(int* tid_address);
 
 __LIBC_HIDDEN__ WriteProtected<libc_globals> __libc_globals;
 
@@ -66,49 +64,6 @@
 // Declared in "private/bionic_ssp.h".
 uintptr_t __stack_chk_guard = 0;
 
-// Setup for the main thread. For dynamic executables, this is called by the
-// linker _before_ libc is mapped in memory. This means that all writes to
-// globals from this function will apply to linker-private copies and will not
-// be visible from libc later on.
-//
-// Note: this function creates a pthread_internal_t for the initial thread and
-// stores the pointer in TLS, but does not add it to pthread's thread list. This
-// has to be done later from libc itself (see __libc_init_common).
-void __libc_init_main_thread(KernelArgumentBlock& args) {
-  __libc_auxv = args.auxv;
-
-  static pthread_internal_t main_thread;
-
-  // The x86 -fstack-protector implementation uses TLS, so make sure that's
-  // set up before we call any function that might get a stack check inserted.
-  __set_tls(main_thread.tls);
-
-  // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
-  // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
-  main_thread.tid = __set_tid_address(&main_thread.tid);
-  main_thread.set_cached_pid(main_thread.tid);
-
-  // We don't want to free the main thread's stack even when the main thread exits
-  // because things like environment variables with global scope live on it.
-  // We also can't free the pthread_internal_t itself, since that lives on the main
-  // thread's stack rather than on the heap.
-  // The main thread has no mmap allocated space for stack or pthread_internal_t.
-  main_thread.mmap_size = 0;
-  pthread_attr_init(&main_thread.attr);
-  main_thread.attr.guard_size = 0; // The main thread has no guard page.
-  main_thread.attr.stack_size = 0; // User code should never see this; we'll compute it when asked.
-  // TODO: the main thread's sched_policy and sched_priority need to be queried.
-
-  __init_thread(&main_thread);
-  __init_tls(&main_thread);
-
-  // Store a pointer to the kernel argument block in a TLS slot to be
-  // picked up by the libc constructor.
-  main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
-
-  __init_alternate_signal_stack(&main_thread);
-}
-
 void __libc_init_globals(KernelArgumentBlock& args) {
   // Initialize libc globals that are needed in both the linker and in libc.
   // In dynamic binaries, this is run at least twice for different copies of the
@@ -336,7 +291,7 @@
 
   if (getauxval(AT_SECURE)) {
     // If this is a setuid/setgid program, close the security hole described in
-    // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
+    // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc
     __nullify_closed_stdio();
 
     __sanitize_environment_variables(args.envp);
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index edf6a44..97d9e39 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 /*
  * libc_init_dynamic.c
  *
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 2fe86d0..3cda1a2 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -25,17 +25,6 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/*
- * libc_init_static.c
- *
- * The program startup function __libc_init() defined here is
- * used for static executables only (i.e. those that don't depend
- * on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S
- * which is directly invoked by the kernel when the program is launched.
- *
- * The 'structors' parameter contains pointers to various initializer
- * arrays that must be run before the program's 'main' routine is launched.
- */
 
 #include <elf.h>
 #include <errno.h>
@@ -79,12 +68,19 @@
   }
 }
 
+// The program startup function __libc_init() defined here is
+// used for static executables only (i.e. those that don't depend
+// on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S
+// which is directly invoked by the kernel when the program is launched.
+//
+// The 'structors' parameter contains pointers to various initializer
+// arrays that must be run before the program's 'main' routine is launched.
+
 __noreturn void __libc_init(void* raw_args,
                             void (*onexit)(void) __unused,
                             int (*slingshot)(int, char**, char**),
                             structors_array_t const * const structors) {
   KernelArgumentBlock args(raw_args);
-
   __libc_init_main_thread(args);
 
   // Initializing the globals requires TLS to be available for errno.
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 4bbb2c1..dfd0e68 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -340,10 +340,17 @@
 }
 
 // In L we added a public pthread_gettid_np, but some apps were using the private API.
-pid_t __pthread_gettid(pthread_t t) {
+pid_t __pthread_gettid_libc(pthread_t t) {
   return pthread_gettid_np(t);
 }
 
+pid_t __pthread_gettid_libc_private(pthread_t t) {
+  return pthread_gettid_np(t);
+}
+
+__asm__(".symver __pthread_gettid_libc,__pthread_gettid@LIBC");
+__asm__(".symver __pthread_gettid_libc_private,__pthread_gettid@@LIBC_PRIVATE");
+
 // Older versions of apportable used dlmalloc directly instead of malloc,
 // so export this compatibility shim that simply calls malloc.
 void* dlmalloc(size_t size) {
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index f96e9d2..e8be4ae 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -40,7 +40,8 @@
 /* Has the thread been joined by another thread? */
 #define PTHREAD_ATTR_FLAG_JOINED 0x00000002
 
-struct pthread_key_data_t {
+class pthread_key_data_t {
+ public:
   uintptr_t seq; // Use uintptr_t just for alignment, as we use pointer below.
   void* data;
 };
@@ -52,11 +53,12 @@
   THREAD_DETACHED
 };
 
-struct thread_local_dtor;
+class thread_local_dtor;
 
-struct pthread_internal_t {
-  struct pthread_internal_t* next;
-  struct pthread_internal_t* prev;
+class pthread_internal_t {
+ public:
+  class pthread_internal_t* next;
+  class pthread_internal_t* prev;
 
   pid_t tid;
 
diff --git a/libc/private/bionic_time.h b/libc/include/ifaddrs.h
similarity index 70%
rename from libc/private/bionic_time.h
rename to libc/include/ifaddrs.h
index 030dcfd..54a5a2c 100644
--- a/libc/private/bionic_time.h
+++ b/libc/include/ifaddrs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,35 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _BIONIC_TIME_H
-#define _BIONIC_TIME_H
 
-#include <time.h>
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
 #include <sys/cdefs.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 
 __BEGIN_DECLS
 
-// We can't remove this (and this file) until we fix MtpUtils.cpp.
-time_t mktime_tz(struct tm* const, char const*);
+struct ifaddrs {
+  struct ifaddrs* ifa_next;
+  char* ifa_name;
+  unsigned int ifa_flags;
+  struct sockaddr* ifa_addr;
+  struct sockaddr* ifa_netmask;
+  union {
+    struct sockaddr* ifu_broadaddr;
+    struct sockaddr* ifu_dstaddr;
+  } ifa_ifu;
+  void* ifa_data;
+};
+
+#define ifa_broadaddr ifa_ifu.ifu_broadaddr
+#define ifa_dstaddr ifa_ifu.ifu_dstaddr
+
+void freeifaddrs(struct ifaddrs*);
+int getifaddrs(struct ifaddrs**);
 
 __END_DECLS
 
-#endif /* _BIONIC_TIME_H */
+#endif
diff --git a/libc/include/sys/sysmacros.h b/libc/include/sys/sysmacros.h
index 6f053a8..54e43dd 100644
--- a/libc/include/sys/sysmacros.h
+++ b/libc/include/sys/sysmacros.h
@@ -25,28 +25,20 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SYS_SYSMACROS_H_
 #define _SYS_SYSMACROS_H_
 
-/* some rogue code includes this file directly :-( */
-#ifndef _SYS_TYPES_H_
-# include <sys/types.h>
-#endif
+#define makedev(__major, __minor) \
+  ( \
+    (((__major) & 0xfffff000ULL) << 32) | (((__major) & 0xfffULL) << 8) | \
+    (((__minor) & 0xffffff00ULL) << 12) | (((__minor) & 0xffULL)) \
+  )
 
-static __inline__ int major(dev_t _dev)
-{
-  return (_dev >> 8) & 0xfff;
-}
+#define major(__dev) \
+  ((unsigned) ((((unsigned long long) (__dev) >> 32) & 0xfffff000) | (((__dev) >> 8) & 0xfff)))
 
-static __inline__ int minor(dev_t _dev)
-{
-  return (_dev & 0xff) | ((_dev >> 12) & 0xfff00);
-}
-
-static __inline__ dev_t makedev(int __ma, int __mi)
-{
-  return ((__ma & 0xfff) << 8) | (__mi & 0xff) | ((__mi & 0xfff00) << 12);
-}
+#define minor(__dev) \
+  ((unsigned) ((((__dev) >> 12) & 0xffffff00) | ((__dev) & 0xff)))
 
 #endif /* _SYS_SYSMACROS_H_ */
-
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
index a6b0fd8..217fd60 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -139,19 +139,18 @@
 typedef unsigned int        uint_t;
 typedef unsigned int        uint;
 
-/* for some applications */
+#ifdef __BSD_VISIBLE
 #include <sys/sysmacros.h>
 
-#ifdef __BSD_VISIBLE
-typedef	unsigned char	u_char;
-typedef	unsigned short	u_short;
-typedef	unsigned int	u_int;
-typedef	unsigned long	u_long;
+typedef unsigned char  u_char;
+typedef unsigned short u_short;
+typedef unsigned int   u_int;
+typedef unsigned long  u_long;
 
-typedef uint32_t       u_int32_t;
-typedef uint16_t       u_int16_t;
-typedef uint8_t        u_int8_t;
-typedef uint64_t       u_int64_t;
+typedef uint32_t u_int32_t;
+typedef uint16_t u_int16_t;
+typedef uint8_t  u_int8_t;
+typedef uint64_t u_int64_t;
 #endif
 
 #endif
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index 8cbff2b..c51b7e1 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -260,7 +260,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -675,7 +674,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1213,15 +1211,31 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
     __fread_chk;
     __fwrite_chk;
     __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
     __pwrite_chk;
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1388,7 +1402,7 @@
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
     __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
+    __udivdi3; # arm mips
     __udivsi3; # arm
     __unorddf2; # arm
     __unordsf2; # arm
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index bb42c0f..6297fd1 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -122,6 +122,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -260,7 +261,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -675,7 +675,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1213,15 +1212,31 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
     __fread_chk;
     __fwrite_chk;
     __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
     __pwrite_chk;
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1399,7 +1414,7 @@
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
     __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
+    __udivdi3; # arm mips
     __udivsi3; # arm
     __unorddf2; # arm
     __unordsf2; # arm
@@ -1424,6 +1439,7 @@
     arc4random_stir; # arm x86 mips nobrillo
     atexit; # arm
     bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
     bsd_signal; # arm x86 mips nobrillo
     dlmalloc; # arm x86 mips nobrillo
     dlmalloc_inspect_all; # arm x86 mips nobrillo
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index e54bef6..fea1759 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -596,7 +596,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1154,8 +1153,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     pthread_barrierattr_destroy;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c80c19f..258ff48 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -123,6 +123,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -209,6 +210,7 @@
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
+    __udivdi3; # x86
     __umask_chk;
     __vsnprintf_chk;
     __vsprintf_chk;
@@ -263,7 +265,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -678,7 +679,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1239,15 +1239,31 @@
 
 LIBC_N {
   global:
+    __aeabi_atexit; # arm
+    __aeabi_memclr; # arm
+    __aeabi_memclr4; # arm
+    __aeabi_memclr8; # arm
+    __aeabi_memcpy; # arm
+    __aeabi_memcpy4; # arm
+    __aeabi_memcpy8; # arm
+    __aeabi_memmove; # arm
+    __aeabi_memmove4; # arm
+    __aeabi_memmove8; # arm
+    __aeabi_memset; # arm
+    __aeabi_memset4; # arm
+    __aeabi_memset8; # arm
     __fread_chk;
     __fwrite_chk;
     __getcwd_chk;
+    __gnu_Unwind_Find_exidx; # arm
     __pwrite_chk;
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1425,7 +1441,7 @@
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
     __truncdfsf2; # arm
-    __udivdi3; # arm x86 mips
+    __udivdi3; # arm mips
     __udivsi3; # arm
     __umoddi3; # x86 mips
     __unorddf2; # arm
@@ -1451,6 +1467,7 @@
     arc4random_stir; # arm x86 mips nobrillo
     atexit; # arm
     bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
     bsd_signal; # arm x86 mips nobrillo
     dlmalloc; # arm x86 mips nobrillo
     dlmalloc_inspect_all; # arm x86 mips nobrillo
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 709ffd9..67e1c05 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -259,7 +259,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -674,7 +673,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1219,8 +1217,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1263,7 +1263,7 @@
     __swbuf; # arm x86 mips
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
-    __udivdi3; # arm x86 mips
+    __udivdi3; # arm mips
     __umoddi3; # x86 mips
     _fwalk; # arm x86 mips
     free_malloc_leak_info;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index cb068ef..b82ef0f 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -120,6 +120,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -259,7 +260,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     cacheflush; # arm mips
@@ -674,7 +674,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1219,8 +1218,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1274,13 +1275,14 @@
     __swbuf; # arm x86 mips
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
-    __udivdi3; # arm x86 mips
+    __udivdi3; # arm mips
     __umoddi3; # x86 mips
     __wait4; # arm x86 mips nobrillo
     _fwalk; # arm x86 mips
     arc4random_addrandom; # arm x86 mips nobrillo
     arc4random_stir; # arm x86 mips nobrillo
     bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
     bsd_signal; # arm x86 mips nobrillo
     dlmalloc; # arm x86 mips nobrillo
     dlmalloc_inspect_all; # arm x86 mips nobrillo
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index e54bef6..fea1759 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -596,7 +596,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1154,8 +1153,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     pthread_barrierattr_destroy;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index 82df4a4..71390b7 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -205,6 +205,7 @@
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
+    __udivdi3; # x86
     __umask_chk;
     __vsnprintf_chk;
     __vsprintf_chk;
@@ -258,7 +259,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     calloc;
@@ -672,7 +672,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1217,8 +1216,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1262,7 +1263,6 @@
     __swbuf; # arm x86 mips
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
-    __udivdi3; # arm x86 mips
     __umoddi3; # x86 mips
     _fwalk; # arm x86 mips
     free_malloc_leak_info;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 94e4b80..6905ff8 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -120,6 +120,7 @@
     __pselect6; # arm x86 mips
     __pthread_cleanup_pop;
     __pthread_cleanup_push;
+    __pthread_gettid; # arm x86 mips nobrillo
     __ptrace; # arm x86 mips
     __putlong;
     __putshort;
@@ -205,6 +206,7 @@
     __timer_getoverrun; # arm x86 mips
     __timer_gettime; # arm x86 mips
     __timer_settime; # arm x86 mips
+    __udivdi3; # x86
     __umask_chk;
     __vsnprintf_chk;
     __vsprintf_chk;
@@ -258,7 +260,6 @@
     brk;
     bsearch;
     btowc;
-    bzero; # arm x86 mips
     c16rtomb;
     c32rtomb;
     calloc;
@@ -672,7 +673,6 @@
     mktemp;
     mktime;
     mktime64; # arm x86 mips
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1217,8 +1217,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     prlimit; # arm mips x86
@@ -1273,13 +1275,13 @@
     __swbuf; # arm x86 mips
     __swrite; # arm x86 mips
     __swsetup; # arm x86 mips
-    __udivdi3; # arm x86 mips
     __umoddi3; # x86 mips
     __wait4; # arm x86 mips nobrillo
     _fwalk; # arm x86 mips
     arc4random_addrandom; # arm x86 mips nobrillo
     arc4random_stir; # arm x86 mips nobrillo
     bcopy; # arm x86 mips nobrillo
+    bzero; # arm x86 mips nobrillo
     bsd_signal; # arm x86 mips nobrillo
     dlmalloc; # arm x86 mips nobrillo
     dlmalloc_inspect_all; # arm x86 mips nobrillo
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index e54bef6..fea1759 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -596,7 +596,6 @@
     mkstemps64;
     mktemp;
     mktime;
-    mktime_tz;
     mlock;
     mlockall;
     mmap;
@@ -1154,8 +1153,10 @@
     __pwrite64_chk;
     __write_chk;
     fileno_unlocked;
+    freeifaddrs;
     getgrgid_r;
     getgrnam_r;
+    getifaddrs;
     preadv;
     preadv64;
     pthread_barrierattr_destroy;
diff --git a/libc/private/KernelArgumentBlock.h b/libc/private/KernelArgumentBlock.h
index c8ea497..68d4999 100644
--- a/libc/private/KernelArgumentBlock.h
+++ b/libc/private/KernelArgumentBlock.h
@@ -38,32 +38,25 @@
     argv = reinterpret_cast<char**>(args + 1);
     envp = argv + argc + 1;
 
-    // Skip over all environment variable definitions to find aux vector.
-    // The end of the environment block is marked by two NULL pointers.
+    // Skip over all environment variable definitions to find the aux vector.
+    // The end of the environment block is marked by a NULL pointer.
     char** p = envp;
     while (*p != NULL) {
       ++p;
     }
-    ++p; // Skip second NULL;
+    ++p; // Skip the NULL itself.
 
     auxv = reinterpret_cast<ElfW(auxv_t)*>(p);
   }
 
   // Similar to ::getauxval but doesn't require the libc global variables to be set up,
-  // so it's safe to call this really early on. This function also lets you distinguish
-  // between the inability to find the given type and its value just happening to be 0.
-  unsigned long getauxval(unsigned long type, bool* found_match = NULL) {
+  // so it's safe to call this really early on.
+  unsigned long getauxval(unsigned long type) {
     for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) {
       if (v->a_type == type) {
-        if (found_match != NULL) {
-            *found_match = true;
-        }
         return v->a_un.a_val;
       }
     }
-    if (found_match != NULL) {
-      *found_match = false;
-    }
     return 0;
   }
 
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 2ca7728..9d3f4c5 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -121,7 +121,7 @@
 
 #if defined(__cplusplus)
 class KernelArgumentBlock;
-extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock& args);
+extern __LIBC_HIDDEN__ void __libc_init_main_thread(KernelArgumentBlock&);
 #endif
 
 #endif /* __BIONIC_PRIVATE_BIONIC_TLS_H_ */
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index b1ebb24..f370e87 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -2462,50 +2462,4 @@
   return fd;
 }
 
-// Caches the most recent timezone (http://b/8270865).
-static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
-  lock();
-
-  // Our single-item cache.
-  static char* g_cached_time_zone_name;
-  static struct state g_cached_time_zone;
-
-  // Do we already have this timezone cached?
-  if (g_cached_time_zone_name != NULL && strcmp(name, g_cached_time_zone_name) == 0) {
-    *sp = g_cached_time_zone;
-    unlock();
-    return 0;
-  }
-
-  // Can we load it?
-  int rc = tzload(name, sp, doextend);
-  if (rc == 0) {
-    // Update the cache.
-    free(g_cached_time_zone_name);
-    g_cached_time_zone_name = strdup(name);
-    g_cached_time_zone = *sp;
-  }
-
-  unlock();
-  return rc;
-}
-
-// Non-standard API: mktime(3) but with an explicit timezone parameter.
-// This can't actually be hidden/removed until we fix MtpUtils.cpp
-__attribute__((visibility("default"))) time_t mktime_tz(struct tm* const tmp, const char* tz) {
-  struct state* st = malloc(sizeof(*st));
-  time_t return_value;
-
-  if (st == NULL)
-    return 0;
-  if (__bionic_tzload_cached(tz, st, true) != 0) {
-    // TODO: not sure what's best here, but for now, we fall back to gmt.
-    gmtload(st);
-  }
-
-  return_value = time1(tmp, localsub, st, 0L);
-  free(st);
-  return return_value;
-}
-
 // END android-added
diff --git a/linker/linker.cpp b/linker/linker.cpp
index eb938c7..70c2ca5 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -3267,7 +3267,7 @@
   /* We can't log anything until the linker is relocated */
   bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
   if (!relocating_linker) {
-    INFO("[ linking %s ]", get_realpath());
+    INFO("[ Linking '%s' ]", get_realpath());
     DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
   }
 
@@ -3954,17 +3954,27 @@
     g_ld_debug_verbosity = atoi(LD_DEBUG);
   }
 
+#if defined(__LP64__)
+  INFO("[ Android dynamic linker (64-bit) ]");
+#else
+  INFO("[ Android dynamic linker (32-bit) ]");
+#endif
+
   // These should have been sanitized by __libc_init_AT_SECURE, but the test
   // doesn't cost us anything.
   const char* ldpath_env = nullptr;
   const char* ldpreload_env = nullptr;
   if (!getauxval(AT_SECURE)) {
     ldpath_env = getenv("LD_LIBRARY_PATH");
+    if (ldpath_env != nullptr) {
+      INFO("[ LD_LIBRARY_PATH set to '%s' ]", ldpath_env);
+    }
     ldpreload_env = getenv("LD_PRELOAD");
+    if (ldpreload_env != nullptr) {
+      INFO("[ LD_PRELOAD set to '%s' ]", ldpreload_env);
+    }
   }
 
-  INFO("[ android linker & debugger ]");
-
   soinfo* si = soinfo_alloc(&g_default_namespace, args.argv[0], nullptr, 0, RTLD_GLOBAL);
   if (si == nullptr) {
     exit(EXIT_FAILURE);
@@ -4144,6 +4154,7 @@
   return 0;
 }
 
+extern "C" int __set_tls(void*);
 extern "C" void _start();
 
 /*
@@ -4158,6 +4169,9 @@
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   KernelArgumentBlock args(raw_args);
 
+  void* tls[BIONIC_TLS_SLOTS];
+  __set_tls(tls);
+
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
   ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
@@ -4213,7 +4227,7 @@
   args.abort_message_ptr = &g_abort_message;
   ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
 
-  INFO("[ jumping to _start ]");
+  INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
 
   // Return the address that the calling assembly stub should jump to.
   return start_address;
diff --git a/tests/Android.mk b/tests/Android.mk
index 520892b..3a0d6ee 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -40,7 +40,7 @@
 
 test_cflags += -D__STDC_LIMIT_MACROS  # For glibc.
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
 test_cflags += -DUSE_DLMALLOC
 else
 test_cflags += -DUSE_JEMALLOC
@@ -62,6 +62,7 @@
     ftw_test.cpp \
     getauxval_test.cpp \
     getcwd_test.cpp \
+    ifaddrs_test.cpp \
     inttypes_test.cpp \
     libc_logging_test.cpp \
     libgen_basename_test.cpp \
@@ -70,6 +71,7 @@
     malloc_test.cpp \
     math_test.cpp \
     mntent_test.cpp \
+    net_if_test.cpp \
     netdb_test.cpp \
     netinet_udp_test.cpp \
     pthread_test.cpp \
@@ -105,6 +107,7 @@
     sys_statvfs_test.cpp \
     sys_syscall_test.cpp \
     sys_sysinfo_test.cpp \
+    sys_sysmacros_test.cpp \
     sys_time_test.cpp \
     sys_types_test.cpp \
     sys_uio_test.cpp \
@@ -121,7 +124,7 @@
 libBionicStandardTests_cflags := \
     $(test_cflags) \
 
-ifeq ($(MALLOC_IMPL),dlmalloc)
+ifeq ($(MALLOC_SVELTE),true)
   libBionicStandardTests_cflags += -DUSE_DLMALLOC
 else
   libBionicStandardTests_cflags += -DUSE_JEMALLOC
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
new file mode 100644
index 0000000..8159710
--- /dev/null
+++ b/tests/ifaddrs_test.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+
+#include <ifaddrs.h>
+
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+TEST(ifaddrs, freeifaddrs_null) {
+  freeifaddrs(nullptr);
+}
+
+TEST(ifaddrs, getifaddrs_smoke) {
+  ifaddrs* addrs = nullptr;
+
+  ASSERT_EQ(0, getifaddrs(&addrs));
+  ASSERT_TRUE(addrs != nullptr);
+
+  // We can't say much about what network interfaces are available, but we can be pretty
+  // sure there's a loopback interface, and that it has IPv4, IPv6, and AF_PACKET entries.
+  ifaddrs* lo_inet4 = nullptr;
+  ifaddrs* lo_inet6 = nullptr;
+  ifaddrs* lo_packet = nullptr;
+  for (ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next) {
+    if (addr->ifa_name && strcmp(addr->ifa_name, "lo") == 0) {
+      if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET) lo_inet4 = addr;
+      else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET6) lo_inet6 = addr;
+      else if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_PACKET) lo_packet = addr;
+    }
+  }
+
+  // Does the IPv4 entry look right?
+  ASSERT_TRUE(lo_inet4 != nullptr);
+  const sockaddr_in* sa_inet4 = reinterpret_cast<const sockaddr_in*>(lo_inet4->ifa_addr);
+  ASSERT_TRUE(ntohl(sa_inet4->sin_addr.s_addr) == INADDR_LOOPBACK);
+
+  // Does the IPv6 entry look right?
+  ASSERT_TRUE(lo_inet6 != nullptr);
+  const sockaddr_in6* sa_inet6 = reinterpret_cast<const sockaddr_in6*>(lo_inet6->ifa_addr);
+  ASSERT_TRUE(IN6_IS_ADDR_LOOPBACK(&sa_inet6->sin6_addr));
+
+  // Does the AF_PACKET entry look right?
+  ASSERT_TRUE(lo_packet != nullptr);
+  const sockaddr_ll* sa_ll = reinterpret_cast<const sockaddr_ll*>(lo_packet->ifa_addr);
+  ASSERT_EQ(6, sa_ll->sll_halen);
+
+  freeifaddrs(addrs);
+}
+
+static void print_sockaddr_ll(const char* what, const sockaddr* p) {
+  const sockaddr_ll* s = reinterpret_cast<const sockaddr_ll*>(p);
+  printf("\t%s\t", what);
+  for (int i = 0; i < s->sll_halen; ++i) {
+    if (i > 0) printf(":");
+    printf("%02X", s->sll_addr[i]);
+  }
+  printf(" (%d bytes)\n", s->sll_halen);
+}
+
+static void print_sockaddr_inet(const char* what, const sockaddr* addr) {
+  char host[NI_MAXHOST];
+  int family = addr->sa_family;
+  int error = getnameinfo(addr,
+                          (family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6),
+                          host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
+  if (error != 0) {
+    printf("%d getnameinfo() failed: %s\n", family, gai_strerror(error));
+    strcpy(host, "???");
+  }
+  printf("\t%s: <%s>\n", what, host);
+}
+
+static const char* family_to_name(int family) {
+  if (family == AF_INET) return "AF_INET";
+  if (family == AF_INET6) return "AF_INET6";
+  if (family == AF_PACKET) return "AF_PACKET";
+  if (family == AF_UNSPEC) return "AF_UNSPEC";
+  return "?";
+}
+
+// Not really a test, but a useful debugging tool.
+TEST(ifaddrs, dump) {
+  ifaddrs* addrs;
+  ASSERT_EQ(0, getifaddrs(&addrs));
+
+  for (ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) {
+    int family = ifa->ifa_addr ? ifa->ifa_addr->sa_family :
+                                 ifa->ifa_broadaddr ? ifa->ifa_broadaddr->sa_family : AF_UNSPEC;
+
+    printf("%s\n\t%s (%d) flags=%#x\n",
+           ifa->ifa_name, family_to_name(family), family, ifa->ifa_flags);
+
+    if (family == AF_PACKET) {
+      if (ifa->ifa_addr) print_sockaddr_ll("hwaddr", ifa->ifa_addr);
+      if (ifa->ifa_broadaddr) print_sockaddr_ll("hwbroad", ifa->ifa_addr);
+    } else if (family == AF_INET || family == AF_INET6) {
+      if (ifa->ifa_addr) print_sockaddr_inet("address", ifa->ifa_addr);
+      if (ifa->ifa_broadaddr && (ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) != 0) {
+        print_sockaddr_inet((ifa->ifa_flags & IFF_BROADCAST) ? "broadcast" : "destination",
+                            ifa->ifa_broadaddr);
+      }
+    }
+
+    fflush(stdout);
+  }
+
+  freeifaddrs(addrs);
+}
diff --git a/tests/net_if_test.cpp b/tests/net_if_test.cpp
new file mode 100644
index 0000000..9f38411
--- /dev/null
+++ b/tests/net_if_test.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 <net/if.h>
+
+#include <errno.h>
+
+#include <gtest/gtest.h>
+
+TEST(net_if, if_nametoindex_if_indextoname) {
+  unsigned index;
+  index = if_nametoindex("lo");
+  ASSERT_NE(index, 0U);
+
+  char buf[IF_NAMESIZE] = {};
+  char* name = if_indextoname(index, buf);
+  ASSERT_STREQ("lo", name);
+}
+
+TEST(net_if, if_nametoindex_fail) {
+  unsigned index = if_nametoindex("this-interface-does-not-exist");
+  ASSERT_EQ(0U, index);
+}
diff --git a/tests/sys_sysmacros_test.cpp b/tests/sys_sysmacros_test.cpp
new file mode 100644
index 0000000..f17fac5
--- /dev/null
+++ b/tests/sys_sysmacros_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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 <sys/sysmacros.h>
+
+#include <gtest/gtest.h>
+
+TEST(sys_sysmacros, makedev) {
+  ASSERT_EQ(0x12345aabbcc678ddULL, makedev(0x12345678, 0xaabbccdd));
+}
+
+TEST(sys_sysmacros, major) {
+  ASSERT_EQ(0x12345678UL, major(0x12345aabbcc678dd));
+}
+
+TEST(sys_sysmacros, minor) {
+  ASSERT_EQ(0xaabbccddUL, minor(0x12345aabbcc678dd));
+}