Merge "Fix bug for recursive/errorcheck mutex on 32-bit devices."
diff --git a/libc/Android.mk b/libc/Android.mk
index 0de0fb2..e632ee7 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -1384,7 +1384,8 @@
 # We'd really like to do this for all architectures, but since this wasn't done
 # before, these symbols must continue to be exported on LP32 for binary
 # compatibility.
-LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
+# TODO: disabled for http://b/20065774.
+#LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
 
 # TODO: This is to work around b/19059885. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index 470a038..6a2f313 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -40,6 +40,8 @@
     arch-arm64/bionic/syscall.S \
     arch-arm64/bionic/vfork.S \
 
+# Work around for http://b/20065774.
+libc_bionic_src_files_arm64 += arch-arm64/bionic/libgcc_compat.c
 
 libc_crt_target_cflags_arm64 := \
     -I$(LOCAL_PATH)/arch-arm64/include
diff --git a/libc/arch-arm64/bionic/libgcc_compat.c b/libc/arch-arm64/bionic/libgcc_compat.c
new file mode 100644
index 0000000..2dae3f5
--- /dev/null
+++ b/libc/arch-arm64/bionic/libgcc_compat.c
@@ -0,0 +1,15 @@
+/* STOPSHIP: remove this once the flounder blobs have been rebuilt (http://b/20065774). */
+
+#if !defined(__clang__)
+
+extern void __clear_cache(char*, char*);
+extern char _Unwind_Backtrace;
+extern char _Unwind_GetIP;
+
+void* __bionic_libgcc_compat_symbols[] = {
+    &__clear_cache,
+    &_Unwind_Backtrace,
+    &_Unwind_GetIP,
+};
+
+#endif
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index 90daf30..f10a8a2 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -59,16 +59,28 @@
   /* If opening a library using library_fd read it starting at library_fd_offset.
    * This flag is only valid when ANDROID_DLEXT_USE_LIBRARY_FD is set.
    */
-
   ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET    = 0x20,
 
+  /* When set, do not check if the library has already been loaded by file stat(2)s.
+   *
+   * This flag allows forced loading of the library in the case when for some
+   * reason multiple ELF files share the same filename (because the already-loaded
+   * library has been removed and overwritten, for example).
+   *
+   * Note that if the library has the same dt_soname as an old one and some other
+   * library has the soname in DT_NEEDED list, the first one will be used to resolve any
+   * dependencies.
+   */
+  ANDROID_DLEXT_FORCE_LOAD = 0x40,
+
   /* Mask of valid bits */
   ANDROID_DLEXT_VALID_FLAG_BITS       = ANDROID_DLEXT_RESERVED_ADDRESS |
                                         ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
                                         ANDROID_DLEXT_WRITE_RELRO |
                                         ANDROID_DLEXT_USE_RELRO |
                                         ANDROID_DLEXT_USE_LIBRARY_FD |
-                                        ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET,
+                                        ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
+                                        ANDROID_DLEXT_FORCE_LOAD,
 };
 
 typedef struct {
diff --git a/libc/version_script.txt b/libc/version_script.txt
index afc5e5c..349a2fc 100644
--- a/libc/version_script.txt
+++ b/libc/version_script.txt
@@ -1,4 +1,9 @@
 LIBC {
+  global:
+    /* Work-around for http://b/20065774. */
+    __clear_cache;
+    _Unwind_Backtrace;
+    _Unwind_GetIP;
   local:
     _ZSt7nothrow;
     _ZdaPv;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 002a4f9..a9c2bc1 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1044,16 +1044,18 @@
   }
 
   // Check for symlink and other situations where
-  // file can have different names.
-  for (soinfo* si = solist; si != nullptr; si = si->next) {
-    if (si->get_st_dev() != 0 &&
-        si->get_st_ino() != 0 &&
-        si->get_st_dev() == file_stat.st_dev &&
-        si->get_st_ino() == file_stat.st_ino &&
-        si->get_file_offset() == file_offset) {
-      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
-          "will return existing soinfo", name, si->name);
-      return si;
+  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
+  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
+    for (soinfo* si = solist; si != nullptr; si = si->next) {
+      if (si->get_st_dev() != 0 &&
+          si->get_st_ino() != 0 &&
+          si->get_st_dev() == file_stat.st_dev &&
+          si->get_st_ino() == file_stat.st_ino &&
+          si->get_file_offset() == file_offset) {
+        TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
+            "will return existing soinfo", name, si->name);
+        return si;
+      }
     }
   }
 
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index ca6a75a..700abff 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -173,6 +173,40 @@
   ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror());
 }
 
+TEST(dlext, android_dlopen_ext_force_load_smoke) {
+  // 1. Open actual file
+  void* handle = dlopen("libdlext_test.so", RTLD_NOW);
+  ASSERT_DL_NOTNULL(handle);
+  // 2. Open link with force_load flag set
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
+  void* handle2 = android_dlopen_ext("libdlext_test_v2.so", RTLD_NOW, &extinfo);
+  ASSERT_DL_NOTNULL(handle2);
+  ASSERT_TRUE(handle != handle2);
+
+  dlclose(handle2);
+  dlclose(handle);
+}
+
+TEST(dlext, android_dlopen_ext_force_load_soname_exception) {
+  // Check if soname lookup still returns already loaded library
+  // when ANDROID_DLEXT_FORCE_LOAD flag is specified.
+  void* handle = dlopen("libdlext_test_v2.so", RTLD_NOW);
+  ASSERT_DL_NOTNULL(handle);
+
+  android_dlextinfo extinfo;
+  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
+
+  // Note that 'libdlext_test.so' is dt_soname for libdlext_test_v2.so
+  void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo);
+
+  ASSERT_DL_NOTNULL(handle2);
+  ASSERT_TRUE(handle == handle2);
+
+  dlclose(handle2);
+  dlclose(handle);
+}
+
 TEST(dlfcn, dlopen_from_zip_absolute_path) {
   const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
 
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index eb0a52a..da3fb1e 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -376,6 +376,7 @@
 libtest_dlsym_from_this_src_files := dlsym_from_this.cpp
 
 module := libtest_dlsym_from_this
+libtest_dlsym_from_this_shared_libraries_target := libdl
 
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
@@ -396,13 +397,9 @@
 
 module := libtest_dlopen_from_ctor
 
-build_target := SHARED_LIBRARY
-build_type := host
-include $(TEST_PATH)/Android.build.mk
+libtest_dlopen_from_ctor_shared_libraries_target := libdl
 
-libtest_dlopen_from_ctor_shared_libraries := libdl
-build_type := target
-include $(TEST_PATH)/Android.build.mk
+include $(LOCAL_PATH)/Android.build.testlib.mk
 
 # -----------------------------------------------------------------------------
 # Library that depends on the library with constructor that calls dlopen() b/7941716