Fix linker crashes during unknown symbol lookup

Integration of kernel VDSO into internal bionic data structures using
common functions.
Fix for dl_iterate_phdr function: the function provides incorrect
address of object in case of nonzero virtual and base addresses.
Location in address space of a particular program header should be
calculated using the formula:  addr = base_addr + virtual_addr.

Signed-off-by: Sergey Melnikov <sergey.melnikov@intel.com>
Change-Id: Ie2ab4257fd456242aab8afed0bd5bd6b29e81d6d
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 6bf18ac..fe4d6c4 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -73,6 +73,7 @@
  */
 
 static bool soinfo_link_image(soinfo* si);
+static Elf_Addr get_elf_exec_load_bias(const Elf_Ehdr* elf);
 
 // We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
 // maps, each a single page in size. The pages are broken up into as many struct soinfo
@@ -186,7 +187,7 @@
 static void insert_soinfo_into_debug_map(soinfo * info) {
     // Copy the necessary fields into the debug structure.
     link_map_t* map = &(info->link_map);
-    map->l_addr = info->base;
+    map->l_addr = info->load_bias;
     map->l_name = (char*) info->name;
     map->l_ld = (uintptr_t)info->dynamic;
 
@@ -1751,15 +1752,16 @@
     Elf_Ehdr* ehdr_vdso = reinterpret_cast<Elf_Ehdr*>(args.getauxval(AT_SYSINFO_EHDR));
 
     soinfo* si = soinfo_alloc("[vdso]");
+
     si->phdr = reinterpret_cast<Elf_Phdr*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
     si->phnum = ehdr_vdso->e_phnum;
-    si->link_map.l_name = si->name;
-    for (size_t i = 0; i < si->phnum; ++i) {
-        if (si->phdr[i].p_type == PT_LOAD) {
-            si->link_map.l_addr = reinterpret_cast<Elf_Addr>(ehdr_vdso) - si->phdr[i].p_vaddr;
-            break;
-        }
-    }
+    si->base = reinterpret_cast<Elf_Addr>(ehdr_vdso);
+    si->size = phdr_table_get_load_size(si->phdr, si->phnum);
+    si->flags = 0;
+    si->load_bias = get_elf_exec_load_bias(ehdr_vdso);
+
+    soinfo_link_image(si);
+    insert_soinfo_into_debug_map(si);
 #endif
 }
 
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 938b8a5..6ba8e66 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -222,3 +222,15 @@
   ASSERT_TRUE(handle != NULL);
   ASSERT_SUBSTR(NULL, dlerror());
 }
+
+TEST(dlfcn, rtld_default_unknown_symbol) {
+  void* self = RTLD_DEFAULT;
+  void* addr = dlsym(self, "ANY_UNKNOWN_SYMBOL_NAME");
+  ASSERT_TRUE(addr == NULL);
+}
+
+TEST(dlfcn, rtld_default_known_symbol) {
+  void* self = RTLD_DEFAULT;
+  void* addr = dlsym(self, "fopen");
+  ASSERT_TRUE(addr != NULL);
+}