libc_shared_globals: add a constexpr ctor

Having a constexpr constructor should guarantee that the static
`globals` variable in __libc_shared_globals is initialized statically
(as opposed to dynamically), which is important because
__libc_shared_globals is called very early (before the linker has
relocated itself). With the constructor, though, the fields can safely
have in-line default initializers.

Bug: none
Test: bionic unit tests
Change-Id: Icde821557369625734a4d85d7ff55428bad5c247
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 289b4a3..b2f8bbf 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -152,8 +152,6 @@
 }
 
 __LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals() {
-  static libc_shared_globals globals = {
-    .abort_msg_lock = PTHREAD_MUTEX_INITIALIZER,
-  };
+  static libc_shared_globals globals;
   return &globals;
 }
diff --git a/libc/private/bionic_fdsan.h b/libc/private/bionic_fdsan.h
index de14cf8..f403d08 100644
--- a/libc/private/bionic_fdsan.h
+++ b/libc/private/bionic_fdsan.h
@@ -39,21 +39,23 @@
 #include <sys/user.h>
 
 struct FdEntry {
-  _Atomic(uint64_t) close_tag;
+  _Atomic(uint64_t) close_tag = 0;
 };
 
 struct FdTableOverflow {
-  size_t len;
+  size_t len = 0;
   FdEntry entries[0];
 };
 
 template <size_t inline_fds>
 struct FdTableImpl {
-  uint32_t version;  // currently 0, and hopefully it'll stay that way.
-  _Atomic(android_fdsan_error_level) error_level;
+  constexpr FdTableImpl() {}
+
+  uint32_t version = 0;  // currently 0, and hopefully it'll stay that way.
+  _Atomic(android_fdsan_error_level) error_level = ANDROID_FDSAN_ERROR_LEVEL_DISABLED;
 
   FdEntry entries[inline_fds];
-  _Atomic(FdTableOverflow*) overflow;
+  _Atomic(FdTableOverflow*) overflow = nullptr;
 
   FdEntry* at(size_t idx);
 };
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index ba510b1..ceda38a 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -50,21 +50,26 @@
 
 // Globals shared between the dynamic linker and libc.so.
 struct libc_shared_globals {
+  // Construct the shared globals using a constexpr constructor to ensure that
+  // the object doesn't need dynamic initialization. The object is accessed
+  // before the dynamic linker has relocated itself.
+  constexpr libc_shared_globals() {}
+
   FdTable fd_table;
 
   // When the linker is invoked on a binary (e.g. `linker64 /system/bin/date`),
   // record the number of arguments passed to the linker itself rather than to
   // the program it's loading. Typically 0, sometimes 1.
-  int initial_linker_arg_count;
+  int initial_linker_arg_count = 0;
 
-  ElfW(auxv_t)* auxv;
+  ElfW(auxv_t)* auxv = nullptr;
 
-  pthread_mutex_t abort_msg_lock;
-  abort_msg_t* abort_msg;
+  pthread_mutex_t abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
+  abort_msg_t* abort_msg = nullptr;
 
   // Values passed from the linker to libc.so.
-  const char* init_progname;
-  char** init_environ;
+  const char* init_progname = nullptr;
+  char** init_environ = nullptr;
 };
 
 __LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();