Run constructors before resolving ifunc functions

Bug: 17177284
Change-Id: I5714b9bc2d1ca8f8711806bfb68da3d524213e99
diff --git a/tests/Android.mk b/tests/Android.mk
index ef33afc..bdfd2ef 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -355,6 +355,22 @@
 		$(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS)
 endif
 
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64))
+# add target to run lp32 tests
+bionic-unit-tests-run-on-host32: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh
+	if [ ! -d /system -o ! -d /system/bin ]; then \
+	  echo "Attempting to create /system/bin"; \
+	  sudo mkdir -p -m 0777 /system/bin; \
+	fi
+	mkdir -p $(TARGET_OUT_DATA)/local/tmp
+	cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin
+	cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+	ANDROID_DATA=$(TARGET_OUT_DATA) \
+	ANDROID_ROOT=$(TARGET_OUT) \
+	LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \
+		$(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS)
+endif
+
 endif # linux-x86
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index fc788ac..a731748 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -90,32 +90,42 @@
 // ifuncs are only supported on intel for now
 #if defined(__i386__) || defined(__x86_64__)
 TEST(dlfcn, ifunc) {
-  const char* (*foo_ptr)();
-  const char* (*foo_library_ptr)();
+  typedef const char* (*fn_ptr)();
 
   // ifunc's choice depends on whether IFUNC_CHOICE has a value
   // first check the set case
   setenv("IFUNC_CHOICE", "set", 1);
   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
   ASSERT_TRUE(handle != NULL);
-  *(void **)(&foo_ptr) = dlsym(handle, "foo");
-  *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+  fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+  fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
   ASSERT_TRUE(foo_ptr != NULL);
   ASSERT_TRUE(foo_library_ptr != NULL);
-  ASSERT_EQ(strncmp("set", (*foo_ptr)(), 3), 0);
-  ASSERT_EQ(strncmp("set", (*foo_library_ptr)(), 3), 0);
+  ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
+  ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
   dlclose(handle);
 
   // then check the unset case
   unsetenv("IFUNC_CHOICE");
   handle = dlopen("libtest_ifunc.so", RTLD_NOW);
   ASSERT_TRUE(handle != NULL);
-  *(void **)(&foo_ptr) = dlsym(handle, "foo");
-  *(void **)(&foo_library_ptr) = dlsym(handle, "foo_library");
+  foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
+  foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
   ASSERT_TRUE(foo_ptr != NULL);
   ASSERT_TRUE(foo_library_ptr != NULL);
-  ASSERT_EQ(strncmp("unset", (*foo_ptr)(), 5), 0);
-  ASSERT_EQ(strncmp("unset", (*foo_library_ptr)(), 3), 0);
+  ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
+  ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
+  dlclose(handle);
+}
+
+TEST(dlfcn, ifunc_ctor_call) {
+  typedef const char* (*fn_ptr)();
+
+  void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
+  ASSERT_TRUE(handle != NULL) << dlerror();
+  fn_ptr is_ctor_called =  reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called"));
+  ASSERT_TRUE(is_ctor_called != NULL) << dlerror();
+  ASSERT_STREQ("true", is_ctor_called());
   dlclose(handle);
 }
 #endif
diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c
index 1c4bafa..4874841 100644
--- a/tests/libs/dlopen_testlib_ifunc.c
+++ b/tests/libs/dlopen_testlib_ifunc.c
@@ -17,7 +17,22 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+static int g_flag = 0;
+
+static void __attribute__((constructor)) init_flag() {
+  g_flag = 1;
+}
+
 const char* foo() __attribute__ ((ifunc ("foo_ifunc")));
+const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun")));
+
+const char* return_true() {
+  return "true";
+}
+
+const char* return_false() {
+  return "false";
+}
 
 const char* f1() {
   return "unset";
@@ -27,6 +42,10 @@
   return "set";
 }
 
+void* is_ctor_called_ifun() {
+  return g_flag == 0 ? return_false : return_true;
+}
+
 void* foo_ifunc() {
    char* choice = getenv("IFUNC_CHOICE");
    return choice == NULL ? f1 : f2;
@@ -34,4 +53,4 @@
 
 const char* foo_library() {
    return foo();
-}
\ No newline at end of file
+}