Support symbol versioning

Bug: http://b/20139821
Change-Id: I64122a0fb0960c20b2ce614161b7ab048456b681
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 708e2cd..1023644 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -925,3 +925,63 @@
   GTEST_LOG_(INFO) << "This test is disabled for glibc (glibc segfaults if you try to call dlopen from a constructor).\n";
 #endif
 }
+
+TEST(dlfcn, symbol_versioning_use_v1) {
+  void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(1, fn());
+  dlclose(handle);
+}
+
+TEST(dlfcn, symbol_versioning_use_v2) {
+  void* handle = dlopen("libtest_versioned_uselibv2.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(2, fn());
+  dlclose(handle);
+}
+
+TEST(dlfcn, symbol_versioning_use_other_v2) {
+  void* handle = dlopen("libtest_versioned_uselibv2_other.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(20, fn());
+  dlclose(handle);
+}
+
+TEST(dlfcn, symbol_versioning_use_other_v3) {
+  void* handle = dlopen("libtest_versioned_uselibv3_other.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "get_function_version"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(3, fn());
+  dlclose(handle);
+}
+
+TEST(dlfcn, symbol_versioning_default_via_dlsym) {
+  void* handle = dlopen("libtest_versioned_lib.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+  typedef int (*fn_t)();
+  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "versioned_function"));
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+  ASSERT_EQ(3, fn()); // the default version is 3
+  dlclose(handle);
+}
+
+// This preempts the implementation from libtest_versioned_lib.so
+extern "C" int version_zero_function() {
+  return 0;
+}
+
+// This preempts the implementation from libtest_versioned_uselibv*.so
+extern "C" int version_zero_function2() {
+  return 0;
+}