Execute .preinit_array before any shared object initialization functions.

This change makes linker handling of .preinit_array compliant with the
System V ABI:

"These [pre-initialization] functions are executed after the dynamic linker has
built the process image and performed relocations but before any shared object
initialization functions."
http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini

Change-Id: Iebfee22bb1ebe1d7c7e69cb4686e4ebae0dfc4bb
diff --git a/linker/README.TXT b/linker/README.TXT
index a8efe35..f920b97 100644
--- a/linker/README.TXT
+++ b/linker/README.TXT
@@ -87,6 +87,7 @@
       present in executables, not shared libraries, which contains
       a list of functions that need to be called before any other
       initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY)
+      in the executable or any of its libraries.
 
       Note: this is generally stored in a .preinit_array section
 
diff --git a/linker/dlfcn.c b/linker/dlfcn.c
index 7161455..62dde2f 100644
--- a/linker/dlfcn.c
+++ b/linker/dlfcn.c
@@ -60,6 +60,7 @@
     if (unlikely(ret == NULL)) {
         set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
     } else {
+        call_constructors_recursive(ret);
         ret->refcount++;
     }
     pthread_mutex_unlock(&dl_lock);
diff --git a/linker/linker.c b/linker/linker.c
index e4618e3..a692d62 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -1617,8 +1617,11 @@
     }
 }
 
-static void call_constructors(soinfo *si)
+void call_constructors_recursive(soinfo *si)
 {
+    if (si->constructors_called)
+        return;
+
     if (si->flags & FLAG_EXE) {
         TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
               pid, (unsigned)si->preinit_array, si->preinit_array_count,
@@ -1633,6 +1636,21 @@
         }
     }
 
+    if (si->dynamic) {
+        unsigned *d;
+        for(d = si->dynamic; *d; d += 2) {
+            if(d[0] == DT_NEEDED){
+                soinfo* lsi = (soinfo *)d[1];
+                if (!validate_soinfo(lsi)) {
+                    DL_ERR("%5d bad DT_NEEDED pointer in %s",
+                           pid, si->name);
+                } else {
+                    call_constructors_recursive(lsi);
+                }
+            }
+        }
+    }
+
     if (si->init_func) {
         TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
               (unsigned)si->init_func, si->name);
@@ -1646,8 +1664,9 @@
         call_array(si->init_array, si->init_array_count, 0);
         TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
     }
-}
 
+    si->constructors_called = 1;
+}
 
 static void call_destructors(soinfo *si)
 {
@@ -2046,7 +2065,6 @@
     if (program_is_setuid)
         nullify_closed_stdio ();
     notify_gdb_of_load(si);
-    call_constructors(si);
     return 0;
 
 fail:
@@ -2251,6 +2269,8 @@
         exit(-1);
     }
 
+    call_constructors_recursive(si);
+
 #if ALLOW_SYMBOLS_FROM_MAIN
     /* Set somain after we've loaded all the libraries in order to prevent
      * linking of symbols back to the main image, which is not set up at that
diff --git a/linker/linker.h b/linker/linker.h
index aa1e5e7..c9e0309 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -149,6 +149,8 @@
 
     unsigned refcount;
     struct link_map linkmap;
+
+    int constructors_called;
 };
 
 
@@ -217,6 +219,7 @@
 soinfo *find_containing_library(const void *addr);
 Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si);
 const char *linker_get_error(void);
+void call_constructors_recursive(soinfo *si);
 
 #ifdef ANDROID_ARM_LINKER 
 typedef long unsigned int *_Unwind_Ptr;