Merge "Revert "Expose more symbols temporarily""
diff --git a/libc/Android.bp b/libc/Android.bp
index e0d0fee..964b64a 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1612,6 +1612,8 @@
         symbol_file: "libc.map.txt",
         versions: ["10000"],
     },
+
+    symbol_ordering_file: "symbol_ordering",
 }
 
 genrule {
diff --git a/libc/arch-arm/bionic/vfork.S b/libc/arch-arm/bionic/vfork.S
index 8329111..0b17d64 100644
--- a/libc/arch-arm/bionic/vfork.S
+++ b/libc/arch-arm/bionic/vfork.S
@@ -27,12 +27,13 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 ENTRY(vfork)
 __BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork)
     // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
     mrc     p15, 0, r3, c13, c0, 3
-    ldr     r3, [r3, #4]
+    ldr     r3, [r3, #(TLS_SLOT_THREAD_ID * 4)]
     mov     r0, #0
     str     r0, [r3, #12]
 
diff --git a/libc/arch-arm64/bionic/vfork.S b/libc/arch-arm64/bionic/vfork.S
index 0a83cc7..6acd64b 100644
--- a/libc/arch-arm64/bionic/vfork.S
+++ b/libc/arch-arm64/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 #include <asm/signal.h>
 #include <linux/sched.h>
 
@@ -34,7 +35,7 @@
 __BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork)
     // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
     mrs     x0, tpidr_el0
-    ldr     x0, [x0, #8]
+    ldr     x0, [x0, #(TLS_SLOT_THREAD_ID * 8)]
     str     wzr, [x0, #20]
 
     mov     x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD)
diff --git a/libc/arch-x86/bionic/vfork.S b/libc/arch-x86/bionic/vfork.S
index 79d7899..24ede3d 100644
--- a/libc/arch-x86/bionic/vfork.S
+++ b/libc/arch-x86/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 // This custom code preserves the return address across the system call.
 
@@ -38,7 +39,7 @@
 
   // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
   movl    %gs:0, %eax
-  movl    4(%eax), %eax
+  movl    (TLS_SLOT_THREAD_ID * 4)(%eax), %eax
   movl    $0, 12(%eax)
 
   movl    $__NR_vfork, %eax
diff --git a/libc/arch-x86_64/bionic/vfork.S b/libc/arch-x86_64/bionic/vfork.S
index ce96a8c..e32b517 100644
--- a/libc/arch-x86_64/bionic/vfork.S
+++ b/libc/arch-x86_64/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 // This custom code preserves the return address across the system call.
 
@@ -36,7 +37,7 @@
 
   // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
   mov    %fs:0, %rax
-  mov    8(%rax), %rax
+  mov    (TLS_SLOT_THREAD_ID * 8)(%rax), %rax
   movl   $0, 20(%rax)
 
   movl    $__NR_vfork, %eax
diff --git a/libc/bionic/bionic_elf_tls.cpp b/libc/bionic/bionic_elf_tls.cpp
index 55c2c31..2d2cbe3 100644
--- a/libc/bionic/bionic_elf_tls.cpp
+++ b/libc/bionic/bionic_elf_tls.cpp
@@ -28,11 +28,43 @@
 
 #include "private/bionic_elf_tls.h"
 
+#include <async_safe/log.h>
 #include <sys/param.h>
+#include <unistd.h>
 
 #include "private/bionic_macros.h"
 #include "private/bionic_tls.h"
 
+// Search for a TLS segment in the given phdr table. Returns true if it has a
+// TLS segment and false otherwise.
+bool __bionic_get_tls_segment(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                              ElfW(Addr) load_bias, const char* mod_name,
+                              TlsSegment* out) {
+  for (size_t i = 0; i < phdr_count; ++i) {
+    const ElfW(Phdr)& phdr = phdr_table[i];
+    if (phdr.p_type == PT_TLS) {
+      // N.B. The size does not need to be a multiple of the alignment. With
+      // ld.bfd (or after using binutils' strip), the TLS segment's size isn't
+      // rounded up.
+      size_t alignment = phdr.p_align;
+      if (alignment == 0 || !powerof2(alignment)) {
+        async_safe_fatal("error: \"%s\": TLS segment alignment is not a power of 2: %zu",
+                         mod_name, alignment);
+      }
+      // Bionic only respects TLS alignment up to one page.
+      alignment = MIN(alignment, PAGE_SIZE);
+      *out = TlsSegment {
+        phdr.p_memsz,
+        alignment,
+        reinterpret_cast<void*>(load_bias + phdr.p_vaddr),
+        phdr.p_filesz,
+      };
+      return true;
+    }
+  }
+  return false;
+}
+
 void StaticTlsLayout::reserve_tcb() {
   offset_bionic_tcb_ = reserve_type<bionic_tcb>();
 }
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index d530fa4..4cc5df9 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -641,42 +641,6 @@
   }
 }
 
-extern "C" void InstallInitHeapprofdHook(int);
-
-// Initializes memory allocation framework once per process.
-static void malloc_init_impl(libc_globals* globals) {
-  struct sigaction action = {};
-  action.sa_handler = InstallInitHeapprofdHook;
-  sigaction(HEAPPROFD_SIGNAL, &action, nullptr);
-
-  const char* prefix;
-  const char* shared_lib;
-  char prop[PROP_VALUE_MAX];
-  char* options = prop;
-  // Prefer malloc debug since it existed first and is a more complete
-  // malloc interceptor than the hooks.
-  if (CheckLoadMallocDebug(&options)) {
-    prefix = "debug";
-    shared_lib = DEBUG_SHARED_LIB;
-  } else if (CheckLoadMallocHooks(&options)) {
-    prefix = "hooks";
-    shared_lib = HOOKS_SHARED_LIB;
-  } else if (CheckLoadHeapprofd()) {
-    prefix = "heapprofd";
-    shared_lib = HEAPPROFD_SHARED_LIB;
-  } else {
-    return;
-  }
-  install_hooks(globals, options, prefix, shared_lib);
-}
-
-// Initializes memory allocation framework.
-// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
-  malloc_init_impl(globals);
-}
-
 // The logic for triggering heapprofd below is as following.
 // 1. HEAPPROFD_SIGNAL is received by the process.
 // 2. If neither InitHeapprofd nor InitHeapprofdHook are currently installed
@@ -704,6 +668,45 @@
 static _Atomic bool g_heapprofd_init_in_progress = false;
 static _Atomic bool g_heapprofd_init_hook_installed = false;
 
+extern "C" void InstallInitHeapprofdHook(int);
+
+// Initializes memory allocation framework once per process.
+static void malloc_init_impl(libc_globals* globals) {
+  struct sigaction action = {};
+  action.sa_handler = InstallInitHeapprofdHook;
+  sigaction(HEAPPROFD_SIGNAL, &action, nullptr);
+
+  const char* prefix;
+  const char* shared_lib;
+  char prop[PROP_VALUE_MAX];
+  char* options = prop;
+  // Prefer malloc debug since it existed first and is a more complete
+  // malloc interceptor than the hooks.
+  if (CheckLoadMallocDebug(&options)) {
+    prefix = "debug";
+    shared_lib = DEBUG_SHARED_LIB;
+  } else if (CheckLoadMallocHooks(&options)) {
+    prefix = "hooks";
+    shared_lib = HOOKS_SHARED_LIB;
+  } else if (CheckLoadHeapprofd()) {
+    prefix = "heapprofd";
+    shared_lib = HEAPPROFD_SHARED_LIB;
+  } else {
+    return;
+  }
+  if (!atomic_exchange(&g_heapprofd_init_in_progress, true)) {
+    install_hooks(globals, options, prefix, shared_lib);
+    atomic_store(&g_heapprofd_init_in_progress, false);
+  }
+}
+
+// Initializes memory allocation framework.
+// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
+  malloc_init_impl(globals);
+}
+
 static void* InitHeapprofd(void*) {
   __libc_globals.mutate([](libc_globals* globals) {
     install_hooks(globals, nullptr, HEAPPROFD_PREFIX, HEAPPROFD_SHARED_LIB);
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 870a526..46fa630 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -35,30 +35,13 @@
 
 #include <async_safe/log.h>
 
+#include "private/ScopedRWLock.h"
 #include "private/bionic_futex.h"
 #include "private/bionic_tls.h"
 
 static pthread_internal_t* g_thread_list = nullptr;
 static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER;
 
-template <bool write> class ScopedRWLock {
- public:
-  explicit ScopedRWLock(pthread_rwlock_t* rwlock) : rwlock_(rwlock) {
-    (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(rwlock_);
-  }
-
-  ~ScopedRWLock() {
-    pthread_rwlock_unlock(rwlock_);
-  }
-
- private:
-  pthread_rwlock_t* rwlock_;
-  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedRWLock);
-};
-
-typedef ScopedRWLock<true> ScopedWriteLock;
-typedef ScopedRWLock<false> ScopedReadLock;
-
 pthread_t __pthread_internal_add(pthread_internal_t* thread) {
   ScopedWriteLock locker(&g_thread_list_lock);
 
diff --git a/libc/private/ScopedRWLock.h b/libc/private/ScopedRWLock.h
new file mode 100644
index 0000000..f034505
--- /dev/null
+++ b/libc/private/ScopedRWLock.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#include "private/bionic_macros.h"
+
+template <bool write> class ScopedRWLock {
+ public:
+  explicit ScopedRWLock(pthread_rwlock_t* rwlock) : rwlock_(rwlock) {
+    (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(rwlock_);
+  }
+
+  ~ScopedRWLock() {
+    pthread_rwlock_unlock(rwlock_);
+  }
+
+ private:
+  pthread_rwlock_t* rwlock_;
+  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedRWLock);
+};
+
+typedef ScopedRWLock<true> ScopedWriteLock;
+typedef ScopedRWLock<false> ScopedReadLock;
diff --git a/libc/private/bionic_asm_tls.h b/libc/private/bionic_asm_tls.h
index 06e3dce..0f0873f 100644
--- a/libc/private/bionic_asm_tls.h
+++ b/libc/private/bionic_asm_tls.h
@@ -87,11 +87,9 @@
 #define TLS_SLOT_STACK_GUARD      5
 #define TLS_SLOT_SANITIZER        6 // was historically used for dlerror
 #define TLS_SLOT_ART_THREAD_SELF  7
-#define TLS_SLOT_TSAN             8 // should be replaced with TLS_SLOT_SANITIZER
 
 // The maximum slot is fixed by the minimum TLS alignment in Bionic executables.
-// It should be changed to 7 once TLS_SLOT_TSAN is removed.
-#define MAX_TLS_SLOT              8
+#define MAX_TLS_SLOT              7
 
 #elif defined(__i386__) || defined(__x86_64__)
 
@@ -109,10 +107,9 @@
 #define TLS_SLOT_STACK_GUARD      5
 #define TLS_SLOT_SANITIZER        6 // was historically used for dlerror
 #define TLS_SLOT_ART_THREAD_SELF  7
-#define TLS_SLOT_TSAN             8 // should be replaced with TLS_SLOT_SANITIZER
-#define TLS_SLOT_DTV              9
-#define TLS_SLOT_BIONIC_TLS       10
-#define MAX_TLS_SLOT              10 // update this value when reserving a slot
+#define TLS_SLOT_DTV              8
+#define TLS_SLOT_BIONIC_TLS       9
+#define MAX_TLS_SLOT              9 // update this value when reserving a slot
 
 #endif
 
diff --git a/libc/private/bionic_elf_tls.h b/libc/private/bionic_elf_tls.h
index e847669..48a4d25 100644
--- a/libc/private/bionic_elf_tls.h
+++ b/libc/private/bionic_elf_tls.h
@@ -28,7 +28,20 @@
 
 #pragma once
 
+#include <link.h>
 #include <stdint.h>
+#include <sys/cdefs.h>
+
+struct TlsSegment {
+  size_t size = 0;
+  size_t alignment = 1;
+  const void* init_ptr = "";    // Field is non-null even when init_size is 0.
+  size_t init_size = 0;
+};
+
+__LIBC_HIDDEN__ bool __bionic_get_tls_segment(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                              ElfW(Addr) load_bias, const char* mod_name,
+                                              TlsSegment* out);
 
 struct StaticTlsLayout {
   constexpr StaticTlsLayout() {}
diff --git a/libc/symbol_ordering b/libc/symbol_ordering
new file mode 100644
index 0000000..5b365f0
--- /dev/null
+++ b/libc/symbol_ordering
@@ -0,0 +1,210 @@
+# This file is generated by sorting symbols in the .bss section in libc.so by
+# their sizes and taking out symbols that are unique to a target.  By sorting
+# symbols by size, we usually have less dirty pages at runtime, because small
+# symbols are grouped together.
+
+je_background_thread_enabled_state
+je_can_enable_background_thread
+_ZZ17__find_icu_symbolPKcE9found_icu
+_ZL28g_heapprofd_init_in_progress
+_ZL31g_heapprofd_init_hook_installed
+je_opt_abort
+je_opt_abort_conf
+je_opt_junk_alloc
+je_opt_junk_free
+je_opt_utrace
+je_opt_xmalloc
+je_opt_zero
+malloc_disabled_tcache
+had_conf_error
+malloc_slow_flags
+je_opt_background_thread
+background_thread_enabled_at_fork
+ctl_initialized
+je_log_init_done
+mmap_flags
+os_overcommits
+je_opt_stats_print
+je_tsd_booted
+global_hashtable_initialized
+gmtcheck.gmt_is_set
+restartloop
+_ZZ12bindresvportE4port
+ru_counter
+ru_a
+ru_x
+ru_b
+ru_seed
+ru_g
+ru_seed2
+ru_msb
+je_narenas_auto
+je_ncpus
+je_init_system_thp_mode
+je_nhbins
+je_tsd_tsd
+optreset
+_rs_forked
+daylight
+_ZL17g_icudata_version
+gMallocLeakZygoteChild
+_ZL18netdClientInitOnce
+je_opt_narenas
+narenas_total
+je_malloc_disable.once_control
+je_opt_metadata_thp
+je_opt_thp
+stack_nelms
+tcaches_past
+ncleanups
+error_message_count
+error_one_per_line
+_ZZ13error_at_lineE9last_line
+_ZL13g_locale_once
+_ZL30g_propservice_protocol_version
+_res_cache_once
+_res_key
+_rs_forkdetect._rs_pid
+ru_pid
+lcl_is_set
+__cxa_finalize.call_depth
+seed48.sseed
+ether_aton.addr
+je_background_thread_info
+je_max_background_threads
+je_n_background_threads
+je_malloc_message
+je_tcache_bin_info
+je_tcache_maxclass
+je_tcaches
+optarg
+suboptarg
+timezone
+_ZGVZ17__find_icu_symbolPKcE9found_icu
+_ZL17g_libicuuc_handle
+__malloc_hook
+__realloc_hook
+__free_hook
+__memalign_hook
+_ZL21g_heapprofd_init_func
+je_malloc_conf
+malloc_initializer
+a0
+je_opt_dirty_decay_ms
+je_opt_muzzy_decay_ms
+dirty_decay_ms_default.0
+muzzy_decay_ms_default.0
+pthread_create_fptr
+b0
+ctl_arenas
+ctl_stats
+je_hooks_arena_new_hook
+os_page
+tcaches_avail
+_ZN9prop_area8pa_size_E
+_ZN9prop_area13pa_data_size_E
+_ZL6g_lock
+_ZL6g_tags
+_ZZ8c16rtombE15__private_state
+_ZZ8c32rtombE15__private_state
+environ
+error_print_progname
+_ZZ13error_at_lineE9last_file
+_ZZ14__icu_charTypejE10u_charType
+_ZGVZ14__icu_charTypejE10u_charType
+_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+__progname
+_ZZ8mbrtoc16E15__private_state
+_ZZ8mbrtoc32E15__private_state
+_ZL14syslog_log_tag
+__system_property_area__
+_ZZ7mbrtowcE15__private_state
+_ZZ10mbsnrtowcsE15__private_state
+_ZZ7wcrtombE15__private_state
+_ZZ10wcsnrtombsE15__private_state
+_ZZ8iswcntrlE10u_charType
+_ZGVZ8iswcntrlE10u_charType
+_ZZ8iswdigitE9u_isdigit
+_ZGVZ8iswdigitE9u_isdigit
+_ZZ8iswpunctE9u_ispunct
+_ZGVZ8iswpunctE9u_ispunct
+_ZZ8towlowerE9u_tolower
+_ZGVZ8towlowerE9u_tolower
+_ZZ8towupperE9u_toupper
+_ZGVZ8towupperE9u_toupper
+global_hashtable
+handlers
+p5s
+ut
+rs
+rsx
+mbrlen.mbs
+mbtowc.mbs
+wctomb.mbs
+ru_reseed
+ru_prf
+tmpnam.tmpcount
+lastenv
+strtok.last
+__stack_chk_guard
+lclptr
+gmtptr
+_ZGVZ14tzset_unlockedE20persist_sys_timezone
+_ZL13g_thread_list
+__atexit
+je_opt_stats_print_opts
+nuls
+precsize_ntoa.retbuf
+__p_secstodate.output
+_ZL13g_atfork_list
+inet_ntoa.b
+ether_ntoa.buf
+__sym_ntos.unname
+__sym_ntop.unname
+__p_type.typebuf
+__p_class.classbuf
+malloc_disabled_lock
+_ZL11g_arc4_lock
+_res_cache_list_lock
+__p_option.nbuf
+__p_time.nbuf
+atexit_mutex
+random_mutex
+__res_randomid.__libc_mutex_random
+locallock
+g_atexit_lock
+_ZL11g_functions
+_ZL13vendor_passwd
+_ZL12vendor_group
+tm
+_ZL18g_thread_list_lock
+buf_asctime
+__dtoa_locks
+freelist
+__loc_ntoa.tmpbuf
+_ZL8g_locale
+je_arenas_lock
+je_background_thread_lock
+init_lock
+ctl_mtx
+tcaches_mtx
+je_tsd_init_head
+_ZZ14tzset_unlockedE20persist_sys_timezone
+arena_binind_div_info
+__hexdig_D2A
+lcl_TZname
+utmp
+inet_nsap_ntoa_tmpbuf
+_ZL17system_properties
+_ZL7key_map
+private_mem
+__libc_globals
+tmpnam.buf
+_res_cache_list
+_nres
+je_extent_mutex_pool
+je_arenas
+je_extents_rtree
diff --git a/linker/Android.bp b/linker/Android.bp
index 38a53f8..e103ade 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -176,6 +176,11 @@
         "-Wextra",
         "-Wunused",
         "-Werror",
+
+        // Define _USING_LIBCXX so <stdatomic.h> defers to the <atomic> header. When a Soong module
+        // uses the platform libc++, Soong automatically passes this macro, but the dynamic linker
+        // links against libc++ manually.
+        "-D_USING_LIBCXX",
     ],
 
     // TODO: split out the asflags.
diff --git a/tests/__aeabi_read_tp_test.cpp b/tests/__aeabi_read_tp_test.cpp
index ab96af9..6974658 100644
--- a/tests/__aeabi_read_tp_test.cpp
+++ b/tests/__aeabi_read_tp_test.cpp
@@ -32,7 +32,12 @@
 
 #if defined(__arm__)
 extern "C" void* __aeabi_read_tp();
-TEST(aeabi, read_tp) {
-  ASSERT_EQ(__aeabi_read_tp(), static_cast<void*>(__get_tls()));
-}
 #endif
+
+TEST(aeabi, read_tp) {
+#if defined(__arm__)
+  ASSERT_EQ(__aeabi_read_tp(), static_cast<void*>(__get_tls()));
+#else
+  GTEST_LOG_(INFO) << "__aeabi_read_tp is only available on arm32.\n";
+#endif
+}