Merge "Make __get_thread inlined."
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 150dd14..b91f5bf 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -174,9 +174,9 @@
 int __fadvise64:fadvise64(int, off64_t, off64_t, int) arm64,mips,mips64,x86_64
 
 int __fstatfs64:fstatfs64(int, size_t, struct statfs*)  arm,mips,x86
-int fstatfs64|fstatfs:fstatfs(int, struct statfs*)  arm64,mips64,x86_64
+int __fstatfs:fstatfs(int, struct statfs*)  arm64,mips64,x86_64
 int __statfs64:statfs64(const char*, size_t, struct statfs*)  arm,mips,x86
-int statfs64|statfs:statfs(const char*, struct statfs*)  arm64,mips64,x86_64
+int __statfs:statfs(const char*, struct statfs*)  arm64,mips64,x86_64
 
 int     fstat64|fstat:fstat64(int, struct stat*)    arm,mips,x86
 int     fstat64|fstat:fstat(int, struct stat*)    arm64,x86_64
diff --git a/libc/arch-arm64/syscalls/fstatfs64.S b/libc/arch-arm64/syscalls/__fstatfs.S
similarity index 73%
rename from libc/arch-arm64/syscalls/fstatfs64.S
rename to libc/arch-arm64/syscalls/__fstatfs.S
index 2ca2dcd..7e350d6 100644
--- a/libc/arch-arm64/syscalls/fstatfs64.S
+++ b/libc/arch-arm64/syscalls/__fstatfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fstatfs64)
+ENTRY(__fstatfs)
     mov     x8, __NR_fstatfs
     svc     #0
 
@@ -11,7 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(fstatfs64)
-
-    .globl fstatfs
-    .equ fstatfs, fstatfs64
+END(__fstatfs)
+.hidden __fstatfs
diff --git a/libc/arch-arm64/syscalls/statfs64.S b/libc/arch-arm64/syscalls/__statfs.S
similarity index 74%
rename from libc/arch-arm64/syscalls/statfs64.S
rename to libc/arch-arm64/syscalls/__statfs.S
index ec8c588..962c590 100644
--- a/libc/arch-arm64/syscalls/statfs64.S
+++ b/libc/arch-arm64/syscalls/__statfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(statfs64)
+ENTRY(__statfs)
     mov     x8, __NR_statfs
     svc     #0
 
@@ -11,7 +11,5 @@
     b.hi    __set_errno_internal
 
     ret
-END(statfs64)
-
-    .globl statfs
-    .equ statfs, statfs64
+END(__statfs)
+.hidden __statfs
diff --git a/libc/arch-mips64/syscalls/fstatfs64.S b/libc/arch-mips64/syscalls/__fstatfs.S
similarity index 81%
rename from libc/arch-mips64/syscalls/fstatfs64.S
rename to libc/arch-mips64/syscalls/__fstatfs.S
index 12e885c..8766e22 100644
--- a/libc/arch-mips64/syscalls/fstatfs64.S
+++ b/libc/arch-mips64/syscalls/__fstatfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fstatfs64)
+ENTRY(__fstatfs)
     .set push
     .set noreorder
     li v0, __NR_fstatfs
@@ -22,7 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(fstatfs64)
-
-    .globl fstatfs
-    .equ fstatfs, fstatfs64
+END(__fstatfs)
+.hidden __fstatfs
diff --git a/libc/arch-mips64/syscalls/statfs64.S b/libc/arch-mips64/syscalls/__statfs.S
similarity index 82%
rename from libc/arch-mips64/syscalls/statfs64.S
rename to libc/arch-mips64/syscalls/__statfs.S
index 74351f7..52db4e2 100644
--- a/libc/arch-mips64/syscalls/statfs64.S
+++ b/libc/arch-mips64/syscalls/__statfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(statfs64)
+ENTRY(__statfs)
     .set push
     .set noreorder
     li v0, __NR_statfs
@@ -22,7 +22,5 @@
     j t9
     move ra, t0
     .set pop
-END(statfs64)
-
-    .globl statfs
-    .equ statfs, statfs64
+END(__statfs)
+.hidden __statfs
diff --git a/libc/arch-x86_64/syscalls/fstatfs64.S b/libc/arch-x86_64/syscalls/__fstatfs.S
similarity index 75%
rename from libc/arch-x86_64/syscalls/fstatfs64.S
rename to libc/arch-x86_64/syscalls/__fstatfs.S
index f727350..b50e355 100644
--- a/libc/arch-x86_64/syscalls/fstatfs64.S
+++ b/libc/arch-x86_64/syscalls/__fstatfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(fstatfs64)
+ENTRY(__fstatfs)
     movl    $__NR_fstatfs, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
@@ -12,7 +12,5 @@
     call    __set_errno_internal
 1:
     ret
-END(fstatfs64)
-
-    .globl fstatfs
-    .equ fstatfs, fstatfs64
+END(__fstatfs)
+.hidden __fstatfs
diff --git a/libc/arch-x86_64/syscalls/statfs64.S b/libc/arch-x86_64/syscalls/__statfs.S
similarity index 77%
rename from libc/arch-x86_64/syscalls/statfs64.S
rename to libc/arch-x86_64/syscalls/__statfs.S
index 16f6bdd..607a809 100644
--- a/libc/arch-x86_64/syscalls/statfs64.S
+++ b/libc/arch-x86_64/syscalls/__statfs.S
@@ -2,7 +2,7 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(statfs64)
+ENTRY(__statfs)
     movl    $__NR_statfs, %eax
     syscall
     cmpq    $-MAX_ERRNO, %rax
@@ -12,7 +12,5 @@
     call    __set_errno_internal
 1:
     ret
-END(statfs64)
-
-    .globl statfs
-    .equ statfs, statfs64
+END(__statfs)
+.hidden __statfs
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 73f77be..50e4643 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -40,9 +40,7 @@
 
 // System calls we need.
 extern "C" int __fcntl64(int, int, void*);
-extern "C" int __fstatfs64(int, size_t, struct statfs*);
 extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int);
-extern "C" int __statfs64(const char*, size_t, struct statfs*);
 
 // For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
 int fcntl(int fd, int cmd, ...) {
@@ -55,18 +53,6 @@
   return __fcntl64(fd, cmd, arg);
 }
 
-// For fstatfs we need to add the extra argument giving the kernel the size of the buffer.
-int fstatfs(int fd, struct statfs* stat) {
-  return __fstatfs64(fd, sizeof(*stat), stat);
-}
-__strong_alias(fstatfs64, fstatfs);
-
-// For statfs we need to add the extra argument giving the kernel the size of the buffer.
-int statfs(const char* path, struct statfs* stat) {
-  return __statfs64(path, sizeof(*stat), stat);
-}
-__strong_alias(statfs64, statfs);
-
 // For lseek64 we need to use the llseek system call which splits the off64_t in two and
 // returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results.
 off64_t lseek64(int fd, off64_t off, int whence) {
diff --git a/libc/bionic/statvfs.cpp b/libc/bionic/statvfs.cpp
index f1e2833..39ffb64 100644
--- a/libc/bionic/statvfs.cpp
+++ b/libc/bionic/statvfs.cpp
@@ -21,13 +21,17 @@
 // Paper over the fact that 32-bit kernels use fstatfs64/statfs64 with an extra argument,
 // but 64-bit kernels don't have the "64" bit suffix or the extra size_t argument.
 #if __LP64__
-#  define __fstatfs64(fd,size,buf) fstatfs(fd,buf)
-#  define __statfs64(path,size,buf) statfs(path,buf)
+extern "C" int __fstatfs(int, struct statfs*);
+extern "C" int __statfs(const char*, struct statfs*);
+#  define __fstatfs64(fd,size,buf) __fstatfs(fd,buf)
+#  define __statfs64(path,size,buf) __statfs(path,buf)
 #else
 extern "C" int __fstatfs64(int, size_t, struct statfs*);
 extern "C" int __statfs64(const char*, size_t, struct statfs*);
 #endif
 
+// The kernel sets a private ST_VALID flag to signal to the C library whether the
+// f_flags field is valid. This flag should not be exposed to users of the C library.
 #define ST_VALID 0x0020
 
 static void __statfs_to_statvfs(const struct statfs& in, struct statvfs* out) {
@@ -40,13 +44,33 @@
   out->f_ffree = in.f_ffree;
   out->f_favail = in.f_ffree;
   out->f_fsid = in.f_fsid.__val[0] | (static_cast<uint64_t>(in.f_fsid.__val[1]) << 32);
-  out->f_flag = in.f_flags & ~ST_VALID;
+  out->f_flag = in.f_flags;
   out->f_namemax = in.f_namelen;
 }
 
+int fstatfs(int fd, struct statfs* result) {
+  int rc = __fstatfs64(fd, sizeof(*result), result);
+  if (rc != 0) {
+    return rc;
+  }
+  result->f_flags &= ~ST_VALID;
+  return 0;
+}
+__strong_alias(fstatfs64, fstatfs);
+
+int statfs(const char* path, struct statfs* result) {
+  int rc = __statfs64(path, sizeof(*result), result);
+  if (rc != 0) {
+    return rc;
+  }
+  result->f_flags &= ~ST_VALID;
+  return 0;
+}
+__strong_alias(statfs64, statfs);
+
 int statvfs(const char* path, struct statvfs* result) {
   struct statfs tmp;
-  int rc = __statfs64(path, sizeof(tmp), &tmp);
+  int rc = statfs(path, &tmp);
   if (rc != 0) {
     return rc;
   }
@@ -57,7 +81,7 @@
 
 int fstatvfs(int fd, struct statvfs* result) {
   struct statfs tmp;
-  int rc = __fstatfs64(fd, sizeof(tmp), &tmp);
+  int rc = fstatfs(fd, &tmp);
   if (rc != 0) {
     return rc;
   }
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 9a8dbc9..64df7a5 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -248,6 +248,7 @@
     __libdl_info.ref_count_ = 1;
     __libdl_info.strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
     __libdl_info.local_group_root_ = &__libdl_info;
+    __libdl_info.soname_ = "libdl.so";
   }
 
   return &__libdl_info;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 15ea423..44ae4d4 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -78,19 +78,6 @@
 #undef ELF_ST_TYPE
 #define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 
-#if defined(__LP64__)
-#define SEARCH_NAME(x) x
-#else
-// Nvidia drivers are relying on the bug:
-// http://code.google.com/p/android/issues/detail?id=6670
-// so we continue to use base-name lookup for lp32
-static const char* get_base_name(const char* name) {
-  const char* bname = strrchr(name, '/');
-  return bname ? bname + 1 : name;
-}
-#define SEARCH_NAME(x) get_base_name(x)
-#endif
-
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
 static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
@@ -942,12 +929,8 @@
     int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
     if (fd != -1) {
       *file_offset = 0;
-      return fd;
     }
-    // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
-#if defined(__LP64__)
-    return -1;
-#endif
+    return fd;
   }
 
   // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
@@ -1033,7 +1016,7 @@
     return nullptr;
   }
 
-  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags);
+  soinfo* si = soinfo_alloc(name, &file_stat, file_offset, rtld_flags);
   if (si == nullptr) {
     return nullptr;
   }
@@ -1055,10 +1038,15 @@
   return si;
 }
 
-static soinfo *find_loaded_library_by_name(const char* name) {
-  const char* search_name = SEARCH_NAME(name);
+static soinfo *find_loaded_library_by_soname(const char* name) {
+  // Ignore filename with path.
+  if (strchr(name, '/') != nullptr) {
+    return nullptr;
+  }
+
   for (soinfo* si = solist; si != nullptr; si = si->next) {
-    if (!strcmp(search_name, si->name)) {
+    const char* soname = si->get_soname();
+    if (soname != nullptr && (strcmp(name, soname) == 0)) {
       return si;
     }
   }
@@ -1066,13 +1054,12 @@
 }
 
 static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
-
-  soinfo* si = find_loaded_library_by_name(name);
+  soinfo* si = find_loaded_library_by_soname(name);
 
   // Library might still be loaded, the accurate detection
   // of this fact is done by load_library.
   if (si == nullptr) {
-    TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
+    TRACE("[ '%s' has not been found by soname.  Trying harder...]", name);
     si = load_library(load_tasks, name, rtld_flags, extinfo);
   }
 
@@ -1836,6 +1823,7 @@
 
   return 0;
 }
+
 void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
   if (has_min_version(1)) {
     if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
@@ -1850,6 +1838,14 @@
   }
 }
 
+const char* soinfo::get_soname() {
+  if (has_min_version(2)) {
+    return soname_;
+  } else {
+    return name;
+  }
+}
+
 // This is a return on get_children()/get_parents() if
 // 'this->flags' does not have FLAG_NEW_SOINFO set.
 static soinfo::soinfo_list_t g_empty_list;
@@ -2016,14 +2012,17 @@
 #endif
 
   // Extract useful information from dynamic section.
+  // Note that: "Except for the DT_NULL element at the end of the array,
+  // and the relative order of DT_NEEDED elements, entries may appear in any order."
+  //
+  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
   uint32_t needed_count = 0;
   for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
     DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
           d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
     switch (d->d_tag) {
       case DT_SONAME:
-        // TODO: glibc dynamic linker uses this name for
-        // initial library lookup; consider doing the same here.
+        // this is parsed after we have strtab initialized (see below).
         break;
 
       case DT_HASH:
@@ -2346,6 +2345,14 @@
     }
   }
 
+  // second pass - parse entries relying on strtab
+  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
+    if (d->d_tag == DT_SONAME) {
+      soname_ = get_string(d->d_un.d_val);
+      break;
+    }
+  }
+
   DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
         reinterpret_cast<void*>(base), strtab_, symtab_);
 
diff --git a/linker/linker.h b/linker/linker.h
index e4681eb..04acda4 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -92,7 +92,7 @@
 
 #define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
 
-#define SOINFO_VERSION 1
+#define SOINFO_VERSION 2
 
 #define SOINFO_NAME_LEN 128
 
@@ -278,6 +278,8 @@
 
   soinfo* get_local_group_root() const;
 
+  const char* get_soname();
+
  private:
   ElfW(Sym)* elf_lookup(SymbolName& symbol_name);
   ElfW(Sym)* elf_addr_lookup(const void* addr);
@@ -322,6 +324,8 @@
   uint8_t* android_relocs_;
   size_t android_relocs_size_;
 
+  const char* soname_;
+
   friend soinfo* get_libdl_info();
 };
 
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index ef4ff20..2bd9476 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -97,6 +97,32 @@
   ASSERT_EQ(0, dlclose(handle2));
 }
 
+TEST(dlfcn, dlopen_by_soname) {
+  static const char* soname = "libdlext_test_soname.so";
+  static const char* filename = "libdlext_test_different_soname.so";
+  // 1. Make sure there is no library with soname in default search path
+  void* handle = dlopen(soname, RTLD_NOW);
+  ASSERT_TRUE(handle == nullptr);
+
+  // 2. Load a library using filename
+  handle = dlopen(filename, RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  // 3. Find library by soname
+  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
+  ASSERT_EQ(handle, handle_soname);
+
+  // 4. RTLD_NOLOAD should still work with filename
+  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
+  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
+  ASSERT_EQ(handle, handle_filename);
+
+  dlclose(handle_filename);
+  dlclose(handle_soname);
+  dlclose(handle);
+}
+
 // ifuncs are only supported on intel and arm64 for now
 #if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
 TEST(dlfcn, ifunc) {
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index 7ca856c..665ce0c 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -117,6 +117,17 @@
 build_target := SHARED_LIBRARY
 include $(TEST_PATH)/Android.build.mk
 
+# ----------------------------------------------------------------------------
+# Library with soname which does not match filename
+# ----------------------------------------------------------------------------
+libdlext_test_different_soname_src_files := \
+    dlext_test_library.cpp \
+
+module := libdlext_test_different_soname
+module_tag := optional
+libdlext_test_different_soname_ldflags := -Wl,-soname=libdlext_test_soname.so
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
 # -----------------------------------------------------------------------------
 # Library used by dlext tests - zipped and aligned
 # -----------------------------------------------------------------------------
diff --git a/tests/sys_statvfs_test.cpp b/tests/sys_statvfs_test.cpp
index 6b19e13..bff9e20 100644
--- a/tests/sys_statvfs_test.cpp
+++ b/tests/sys_statvfs_test.cpp
@@ -30,6 +30,11 @@
   EXPECT_EQ(0U, sb.f_ffree);
   EXPECT_EQ(0U, sb.f_fsid);
   EXPECT_EQ(255U, sb.f_namemax);
+
+  // The kernel sets a private bit to indicate that f_flags is valid.
+  // This flag is not supposed to be exposed to libc clients.
+  static const uint32_t ST_VALID = 0x0020;
+  EXPECT_TRUE((sb.f_flag & ST_VALID) == 0) << sb.f_flag;
 }
 
 TEST(sys_statvfs, statvfs) {
@@ -51,6 +56,7 @@
   close(fd);
   Check(sb);
 }
+
 TEST(sys_statvfs, fstatvfs64) {
   struct statvfs64 sb;
   int fd = open("/proc", O_RDONLY);
diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp
index 4b05660..a521967 100644
--- a/tests/sys_vfs_test.cpp
+++ b/tests/sys_vfs_test.cpp
@@ -31,6 +31,11 @@
   EXPECT_EQ(0, sb.f_fsid.__val[0]);
   EXPECT_EQ(0, sb.f_fsid.__val[1]);
   EXPECT_EQ(255, static_cast<int>(sb.f_namelen));
+
+  // The kernel sets a private bit to indicate that f_flags is valid.
+  // This flag is not supposed to be exposed to libc clients.
+  static const uint32_t ST_VALID = 0x0020;
+  EXPECT_TRUE((sb.f_flags & ST_VALID) == 0) << sb.f_flags;
 }
 
 TEST(sys_vfs, statfs) {
@@ -52,6 +57,7 @@
   close(fd);
   Check(sb);
 }
+
 TEST(sys_vfs, fstatfs64) {
   struct statfs64 sb;
   int fd = open("/proc", O_RDONLY);