Merge "linker_main: acquire loader lock earlier and release it later" into main
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index e92aada..8a20670 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -44,7 +44,6 @@
 #include "linker_utils.h"
 
 #include "private/KernelArgumentBlock.h"
-#include "private/ScopedPthreadMutexLocker.h"
 #include "private/bionic_call_ifunc_resolver.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
@@ -499,11 +498,6 @@
 
   if (!get_cfi_shadow()->InitialLinkDone(solist)) __linker_cannot_link(g_argv[0]);
 
-  // A constructor could spawn a thread that calls into the loader, so as soon
-  // as we've called a constructor, we need to hold the lock while accessing
-  // global loader state.
-  ScopedPthreadMutexLocker locker(&g_dl_mutex);
-
   si->call_pre_init_constructors();
   si->call_constructors();
 
@@ -696,6 +690,13 @@
  * function, or other GOT reference will generate a segfault.
  */
 extern "C" ElfW(Addr) __linker_init(void* raw_args) {
+  // Unlock the loader mutex immediately before transferring to the executable's
+  // entry point. This must happen after destructors are called in this function
+  // (e.g. ~soinfo), so declare this variable very early.
+  struct DlMutexUnlocker {
+    ~DlMutexUnlocker() { pthread_mutex_unlock(&g_dl_mutex); }
+  } unlocker;
+
   // Initialize TLS early so system calls and errno work.
   KernelArgumentBlock args(raw_args);
   bionic_tcb temp_tcb __attribute__((uninitialized));
@@ -758,6 +759,11 @@
   // Initialize the linker's static libc's globals
   __libc_init_globals();
 
+  // A constructor could spawn a thread that calls into the loader, so as soon
+  // as we've called a constructor, we need to hold the lock until transferring
+  // to the entry point.
+  pthread_mutex_lock(&g_dl_mutex);
+
   // Initialize the linker's own global variables
   tmp_linker_so.call_constructors();