Browse Source

patch glibc to fix the "ld-gold version is too old" problem
reorganize platform independent code in PAL

Chia-Che Tsai 9 years ago
parent
commit
d031832cfe

+ 270 - 0
LibOS/glibc-2.17.patch

@@ -77,6 +77,276 @@ index 3c9e0ae..034ab2b 100644
 +liblibos {
 +liblibos {
 +  GLIBC_2.12
 +  GLIBC_2.12
 +}
 +}
+diff --git a/LibOS/glibc-2.17/configure b/LibOS/glibc-2.17/configure
+index 8799b7d..22e4c2c 100755
+--- a/LibOS/glibc-2.17/configure
++++ b/LibOS/glibc-2.17/configure
+@@ -636,7 +636,8 @@ SED
+ MAKEINFO
+ MSGFMT
+ MAKE
+-LD
++LD_GOLD
++LD_BFD
+ AS
+ MIG
+ OBJCOPY
+@@ -4792,17 +4793,22 @@ if test $ac_verc_fail = yes; then
+   AS=: critic_missing="$critic_missing as"
+ fi
+ 
+-for ac_prog in $LD
++LD_BFD=
++LD_GOLD=
++ld_is_gold="`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"
++if test -z "$ld_is_gold"; then
++  LD_BFD=$LD
++  for ac_prog in $LD_BFD
+ do
+   # Extract the first word of "$ac_prog", so it can be a program name with args.
+ set dummy $ac_prog; ac_word=$2
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+ $as_echo_n "checking for $ac_word... " >&6; }
+-if ${ac_cv_prog_LD+:} false; then :
++if ${ac_cv_prog_LD_BFD+:} false; then :
+   $as_echo_n "(cached) " >&6
+ else
+-  if test -n "$LD"; then
+-  ac_cv_prog_LD="$LD" # Let the user override the test.
++  if test -n "$LD_BFD"; then
++  ac_cv_prog_LD_BFD="$LD_BFD" # Let the user override the test.
+ else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+ for as_dir in $PATH
+@@ -4811,7 +4817,7 @@ do
+   test -z "$as_dir" && as_dir=.
+     for ac_exec_ext in '' $ac_executable_extensions; do
+   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+-    ac_cv_prog_LD="$ac_prog"
++    ac_cv_prog_LD_BFD="$ac_prog"
+     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+     break 2
+   fi
+@@ -4821,26 +4827,26 @@ IFS=$as_save_IFS
+ 
+ fi
+ fi
+-LD=$ac_cv_prog_LD
+-if test -n "$LD"; then
+-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+-$as_echo "$LD" >&6; }
++LD_BFD=$ac_cv_prog_LD_BFD
++if test -n "$LD_BFD"; then
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD_BFD" >&5
++$as_echo "$LD_BFD" >&6; }
+ else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ $as_echo "no" >&6; }
+ fi
+ 
+ 
+-  test -n "$LD" && break
++  test -n "$LD_BFD" && break
+ done
+ 
+-if test -z "$LD"; then
++if test -z "$LD_BFD"; then
+   ac_verc_fail=yes
+ else
+   # Found it, now check the version.
+-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
+-$as_echo_n "checking version of $LD... " >&6; }
+-  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
++  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD_BFD" >&5
++$as_echo_n "checking version of $LD_BFD... " >&6; }
++  ac_prog_version=`$LD_BFD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+   case $ac_prog_version in
+     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+     2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*)
+@@ -4852,9 +4858,80 @@ $as_echo_n "checking version of $LD... " >&6; }
+ $as_echo "$ac_prog_version" >&6; }
+ fi
+ if test $ac_verc_fail = yes; then
+-  LD=: critic_missing="$critic_missing ld"
++  LD_BFD=:
+ fi
+ 
++else
++# Accept gold 1.11 or higher.
++  LD_GOLD=$LD
++  for ac_prog in $LD_GOLD
++do
++  # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_LD_GOLD+:} false; then :
++  $as_echo_n "(cached) " >&6
++else
++  if test -n "$LD_GOLD"; then
++  ac_cv_prog_LD_GOLD="$LD_GOLD" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++  IFS=$as_save_IFS
++  test -z "$as_dir" && as_dir=.
++    for ac_exec_ext in '' $ac_executable_extensions; do
++  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
++    ac_cv_prog_LD_GOLD="$ac_prog"
++    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++    break 2
++  fi
++done
++  done
++IFS=$as_save_IFS
++
++fi
++fi
++LD_GOLD=$ac_cv_prog_LD_GOLD
++if test -n "$LD_GOLD"; then
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD_GOLD" >&5
++$as_echo "$LD_GOLD" >&6; }
++else
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++  test -n "$LD_GOLD" && break
++done
++
++if test -z "$LD_GOLD"; then
++  ac_verc_fail=yes
++else
++  # Found it, now check the version.
++  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD_GOLD" >&5
++$as_echo_n "checking version of $LD_GOLD... " >&6; }
++  ac_prog_version=`$LD_GOLD --version 2>&1 | sed -n 's/^.*GNU gold.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
++  case $ac_prog_version in
++    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
++    1.1[1-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*)
++       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
++    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
++
++  esac
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
++$as_echo "$ac_prog_version" >&6; }
++fi
++if test $ac_verc_fail = yes; then
++  LD_GOLD=:
++fi
++
++fi
++# Neither ld nor gold are new enough.
++if test -z "$LD_BFD" && test -z "$LD_GOLD"; then
++  critic_missing="$critic_missing ld"
++fi
+ 
+ # These programs are version sensitive.
+ 
+@@ -6670,6 +6747,16 @@ $as_echo "$libc_cv_use_default_link" >&6; }
+   use_default_link=$libc_cv_use_default_link
+ fi
+ 
++# The gold linker has no builtin default linker script,
++# and the fallback of editing the builtin linker
++# script is not available. Therefore if use_default_link
++# is `no' then we can't use gold. This check is independent
++# of gold's version and is used to sanity check that the
++# linker continues to produce a useful shared link.
++if test "$ld_is_gold" && test "$use_default_link" = "no"; then
++  as_fn_error $? "$LD did not generate a useful shared link. Try using GNU ld.bfd?" "$LINENO" 5
++fi
++
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker output format" >&5
+ $as_echo_n "checking linker output format... " >&6; }
+ if ${libc_cv_output_format+:} false; then :
+@@ -6688,6 +6775,17 @@ fi
+ $as_echo "$libc_cv_output_format" >&6; }
+ 
+ 
++# The gold linker has no builtin default linker script,
++# and the fallback of parsing the builtin linker
++# script to determine the target is not available.
++# Therefore if libc_cv_output_format is `unknown' then
++# we can't use gold. This check is independent of gold's
++# version and is used to sanity check that the linker
++# continues to support --print-output-format.
++if test "$ld_is_gold" && test "$libc_cv_output_format" = "unknown"; then
++  as_fn_error $? "$LD did not support --print-output-format. Try using GNU ld.bfd?" "$LINENO" 5
++fi
++
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fno-toplevel-reorder -fno-section-anchors" >&5
+ $as_echo_n "checking for -fno-toplevel-reorder -fno-section-anchors... " >&6; }
+ if ${libc_cv_fno_toplevel_reorder+:} false; then :
+diff --git a/LibOS/glibc-2.17/configure.in b/LibOS/glibc-2.17/configure.in
+index d369382..38ff3cd 100644
+--- a/LibOS/glibc-2.17/configure.in
++++ b/LibOS/glibc-2.17/configure.in
+@@ -924,9 +924,25 @@ AC_SUBST(MIG)dnl Needed by sysdeps/mach/configure.in
+ AC_CHECK_PROG_VER(AS, $AS, --version,
+ 		  [GNU assembler.* \([0-9]*\.[0-9.]*\)],
+ 		  [2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*], AS=: critic_missing="$critic_missing as")
+-AC_CHECK_PROG_VER(LD, $LD, --version,
++LD_BFD=
++LD_GOLD=
++ld_is_gold="`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"
++if test -z "$ld_is_gold"; then
++  LD_BFD=$LD
++  AC_CHECK_PROG_VER(LD_BFD, $LD_BFD, --version,
+ 		  [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
+-		  [2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*], LD=: critic_missing="$critic_missing ld")
++		  [2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*],LD_BFD=:)
++else
++# Accept gold 1.11 or higher.
++  LD_GOLD=$LD
++  AC_CHECK_PROG_VER(LD_GOLD, $LD_GOLD, --version,
++		  [GNU gold.* \([0-9][0-9]*\.[0-9.]*\)],
++		  [1.1[1-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*],LD_GOLD=:)
++fi
++# Neither ld nor gold are new enough.
++if test -z "$LD_BFD" && test -z "$LD_GOLD"; then
++  critic_missing="$critic_missing ld"
++fi
+ 
+ # These programs are version sensitive.
+ AC_CHECK_TOOL_PREFIX
+@@ -1635,6 +1651,16 @@ $ac_try"
+   use_default_link=$libc_cv_use_default_link
+ fi
+ 
++# The gold linker has no builtin default linker script,
++# and the fallback of editing the builtin linker
++# script is not available. Therefore if use_default_link
++# is `no' then we can't use gold. This check is independent
++# of gold's version and is used to sanity check that the
++# linker continues to produce a useful shared link.
++if test "$ld_is_gold" && test "$use_default_link" = "no"; then
++  AC_MSG_ERROR([$LD did not generate a useful shared link. Try using GNU ld.bfd?])
++fi
++
+ AC_CACHE_CHECK(linker output format, libc_cv_output_format, [dnl
+ if libc_cv_output_format=`
+ ${CC-cc} -nostartfiles -nostdlib -Wl,--print-output-format 2>&AS_MESSAGE_LOG_FD`
+@@ -1646,6 +1672,17 @@ fi
+ test -n "$libc_cv_output_format" || libc_cv_output_format=unknown])
+ AC_SUBST(libc_cv_output_format)
+ 
++# The gold linker has no builtin default linker script,
++# and the fallback of parsing the builtin linker
++# script to determine the target is not available.
++# Therefore if libc_cv_output_format is `unknown' then
++# we can't use gold. This check is independent of gold's
++# version and is used to sanity check that the linker
++# continues to support --print-output-format.
++if test "$ld_is_gold" && test "$libc_cv_output_format" = "unknown"; then
++  AC_MSG_ERROR([$LD did not support --print-output-format. Try using GNU ld.bfd?])
++fi
++
+ AC_CACHE_CHECK(for -fno-toplevel-reorder -fno-section-anchors, libc_cv_fno_toplevel_reorder, [dnl
+ cat > conftest.c <<EOF
+ int foo;
 diff --git a/LibOS/glibc-2.17/dlfcn/Versions b/LibOS/glibc-2.17/dlfcn/Versions
 diff --git a/LibOS/glibc-2.17/dlfcn/Versions b/LibOS/glibc-2.17/dlfcn/Versions
 index 97902f0..c1874c1 100644
 index 97902f0..c1874c1 100644
 --- a/LibOS/glibc-2.17/dlfcn/Versions
 --- a/LibOS/glibc-2.17/dlfcn/Versions

+ 1 - 20
Pal/src/db_main.c

@@ -27,6 +27,7 @@
 #include "pal_defs.h"
 #include "pal_defs.h"
 #include "pal.h"
 #include "pal.h"
 #include "pal_internal.h"
 #include "pal_internal.h"
+#include "pal_security.h"
 #include "pal_debug.h"
 #include "pal_debug.h"
 #include "pal_error.h"
 #include "pal_error.h"
 #include "api.h"
 #include "api.h"
@@ -35,12 +36,6 @@
 #include <elf/elf.h>
 #include <elf/elf.h>
 #include <bits/dlfcn.h>
 #include <bits/dlfcn.h>
 
 
-#define RTLD_BOOTSTRAP
-
-/* pal_start is the entry point of libpal.so, which calls pal_main */
-void pal_start(void);
-#define _ENTRY pal_start
-
 /* allocate memory for page size constants */
 /* allocate memory for page size constants */
 PAL_NUM allocsize, allocshift, allocmask;
 PAL_NUM allocsize, allocshift, allocmask;
 
 
@@ -195,25 +190,13 @@ static void * find_heap_base (void)
     return NULL;
     return NULL;
 }
 }
 
 
-void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn, ElfW(Addr) addr);
 void start_execution (int argc, const char ** argv);
 void start_execution (int argc, const char ** argv);
 
 
-#include "dynamic_link.h"
-
 void pal_main (int argc, const char ** argv, const char ** envp)
 void pal_main (int argc, const char ** argv, const char ** envp)
 {
 {
-    ElfW(Addr) pal_addr;
     char cfgbuf[CONFIG_MAX];
     char cfgbuf[CONFIG_MAX];
     int ret;
     int ret;
 
 
-    pal_addr = elf_machine_load_address();
-    ElfW(Dyn) * pal_dyn[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM +
-                        DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
-    memset(pal_dyn, 0, sizeof(pal_dyn));
-    elf_get_dynamic_info((void *) pal_addr + elf_machine_dynamic(), pal_dyn,
-                         pal_addr);
-    ELF_DYNAMIC_RELOCATE(pal_dyn, pal_addr);
-
     pal_config.pagesize    = _DkGetPagesize();
     pal_config.pagesize    = _DkGetPagesize();
     pal_config.alloc_align = _DkGetAllocationAlignment();
     pal_config.alloc_align = _DkGetAllocationAlignment();
 
 
@@ -224,8 +207,6 @@ void pal_main (int argc, const char ** argv, const char ** envp)
 
 
     init_slab_mgr();
     init_slab_mgr();
 
 
-    setup_pal_map(XSTRINGIFY(SRCDIR) "/" LIBRARY_NAME, pal_dyn, pal_addr);
-
     /* reloaction of loader is done here. starting from this point, the global
     /* reloaction of loader is done here. starting from this point, the global
        symbols of loader should be accessible. */
        symbols of loader should be accessible. */
     pal_config.lib_text_start = (void *) &text_start;
     pal_config.lib_text_start = (void *) &text_start;

+ 36 - 88
Pal/src/db_rtld.c

@@ -39,7 +39,6 @@
 #include <bits/dlfcn.h>
 #include <bits/dlfcn.h>
 
 
 struct link_map * loaded_libraries = NULL;
 struct link_map * loaded_libraries = NULL;
-struct link_map * rtld_map = NULL;
 struct link_map * exec_map = NULL;
 struct link_map * exec_map = NULL;
 bool run_preload = false;
 bool run_preload = false;
 
 
@@ -99,6 +98,9 @@ static ElfW(Addr) resolve_map (const char **strtab, ElfW(Sym) ** ref)
     return 0;
     return 0;
 }
 }
 
 
+extern ElfW(Addr) resolve_map_in_rtld (ElfW(Sym) * ref);
+
+#define RESOLVE_MAP_IN_RTLD(ref) resolve_map_in_rtld(ref)
 #define RESOLVE_MAP(strtab, ref) resolve_map(strtab, ref)
 #define RESOLVE_MAP(strtab, ref) resolve_map(strtab, ref)
 
 
 #include "dynamic_link.h"
 #include "dynamic_link.h"
@@ -868,36 +870,44 @@ static int do_lookup (const char * undef_name, ElfW(Sym) * ref,
 {
 {
     const uint_fast32_t fast_hash = elf_fast_hash(undef_name);
     const uint_fast32_t fast_hash = elf_fast_hash(undef_name);
     const long int hash = elf_hash(undef_name);
     const long int hash = elf_hash(undef_name);
+    ElfW(Sym) * sym;
+    struct link_map * map = loaded_libraries;
 
 
-    assert(rtld_map);
+    while (map) {
+        if (!map->l_lookup_symbol) {
+            map = map->l_next;
+            continue;
+        }
 
 
-    ElfW(Sym) * sym = do_lookup_map (ref, undef_name, fast_hash, hash,
-                                     rtld_map);
+        sym = do_lookup_map (ref, undef_name, fast_hash, hash, map);
 
 
-    if (sym == NULL)
-        return 0;
+        if (sym == NULL)
+            return 0;
 
 
-    switch (__builtin_expect (ELFW(ST_BIND) (sym->st_info), STB_GLOBAL)) {
-        case STB_WEAK:
-            /* Weak definition.  Use this value if we don't find another. */
-            if (!result->s) {
+        switch (__builtin_expect (ELFW(ST_BIND) (sym->st_info), STB_GLOBAL)) {
+            case STB_WEAK:
+                /* Weak definition.  Use this value if we don't find another. */
+                if (!result->s) {
+                    result->s = sym;
+                    result->m = (struct link_map *) map;
+                }
+                break;
+
+                /* FALLTHROUGH */
+            case STB_GLOBAL:
+            case STB_GNU_UNIQUE:
+                /* success: */
+                /* Global definition.  Just what we need.  */
                 result->s = sym;
                 result->s = sym;
-                result->m = (struct link_map *) rtld_map;
-            }
-            break;
-
-            /* FALLTHROUGH */
-        case STB_GLOBAL:
-        case STB_GNU_UNIQUE:
-            /* success: */
-            /* Global definition.  Just what we need.  */
-            result->s = sym;
-            result->m = (struct link_map *) rtld_map;
-            return 1;
-
-        default:
-            /* Local symbols are ignored.  */
-            break;
+                result->m = (struct link_map *) map;
+                return 1;
+
+            default:
+                /* Local symbols are ignored.  */
+                break;
+        }
+
+        map = map->l_next;
     }
     }
 
 
     /* We have not found anything until now.  */
     /* We have not found anything until now.  */
@@ -1016,68 +1026,6 @@ static int relocate_elf_object (struct link_map * l)
     return 0;
     return 0;
 }
 }
 
 
-void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn, ElfW(Addr) addr)
-{
-    assert (loaded_libraries == NULL);
-
-    const ElfW(Ehdr) * header = (void *) addr;
-    struct link_map * l = new_elf_object(realname, OBJECT_RTLD);
-    memcpy(l->l_info, dyn, sizeof(l->l_info));
-    l->l_real_ld = l->l_ld = (void *) elf_machine_dynamic();
-    l->l_addr  = addr;
-    l->l_entry = header->e_entry;
-    l->l_phdr  = (void *) (addr + header->e_phoff);
-    l->l_phnum = header->e_phnum;
-    l->l_relocated = true;
-    l->l_soname = "libpal.so";
-    l->l_text_start = (ElfW(Addr)) &text_start;
-    l->l_text_end   = (ElfW(Addr)) &text_end;
-    l->l_data_start = (ElfW(Addr)) &data_start;
-    l->l_data_end   = (ElfW(Addr)) &data_end;
-    setup_elf_hash(l);
-
-    void * begin_hole = (void *) ALLOC_ALIGNUP(l->l_text_end);
-    void * end_hole = (void *) ALLOC_ALIGNDOWN(l->l_data_start);
-
-    /* Usually the test segment and data segment of a loaded library has
-       a gap between them. Need to fill the hole with a empty area */
-    if (begin_hole < end_hole) {
-        void * addr = begin_hole;
-        _DkVirtualMemoryAlloc(&addr, end_hole - begin_hole,
-                              PAL_ALLOC_RESERVE, PAL_PROT_NONE);
-    }
-
-    /* Set up debugging before the debugger is notified for the first time.  */
-    if (l->l_info[DT_DEBUG] != NULL)
-        l->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) &pal_r_debug;
-
-    l->l_prev = l->l_next = NULL;
-    rtld_map = l;
-    loaded_libraries = l;
-
-    if (!pal_sec_info._r_debug) {
-        pal_r_debug.r_version = 1;
-        pal_r_debug.r_brk = (ElfW(Addr)) &pal_dl_debug_state;
-        pal_r_debug.r_ldbase = addr;
-        pal_r_debug.r_map = loaded_libraries;
-        pal_sec_info._r_debug = &pal_r_debug;
-        pal_sec_info._dl_debug_state = &pal_dl_debug_state;
-    } else {
-        pal_sec_info._r_debug->r_state = RT_ADD;
-        pal_sec_info._dl_debug_state();
-
-        if (pal_sec_info._r_debug->r_map) {
-            l->l_prev = pal_sec_info._r_debug->r_map;
-            pal_sec_info._r_debug->r_map->l_next = l;
-        } else {
-            pal_sec_info._r_debug->r_map = loaded_libraries;
-        }
-
-        pal_sec_info._r_debug->r_state = RT_CONSISTENT;
-        pal_sec_info._dl_debug_state();
-    }
-}
-
 void start_execution (int argc, const char ** argv)
 void start_execution (int argc, const char ** argv)
 {
 {
     /* First we will try to run all the preloaded libraries which come with
     /* First we will try to run all the preloaded libraries which come with

+ 14 - 61
Pal/src/dl-machine-x86_64.h

@@ -35,62 +35,6 @@
 #include <sysdeps/generic/ldsodefs.h>
 #include <sysdeps/generic/ldsodefs.h>
 #include "pal_internal.h"
 #include "pal_internal.h"
 
 
-/* Return nonzero iff ELF header is compatible with the running host.  */
-static inline bool __attribute__ ((unused))
-elf_machine_matches_host (const Elf64_Ehdr *ehdr)
-{
-    return ehdr->e_machine == EM_X86_64;
-}
-
-/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
-   first element of the GOT.  This must be inlined in a function which
-   uses global data.  */
-static inline Elf64_Addr __attribute__ ((unused))
-elf_machine_dynamic (void)
-{
-    Elf64_Addr addr;
-
-    /* This works because we have our GOT address available in the small PIC
-       model.  */
-    addr = (Elf64_Addr) &_DYNAMIC;
-
-    return addr;
-}
-
-#define XSTRINGIFY(x) STRINGIFY(x)
-#define STRINGIFY(x) #x
-
-/* Return the run-time load address of the shared object.  */
-static inline Elf64_Addr __attribute__ ((unused))
-elf_machine_load_address (void)
-{
-    Elf64_Addr addr;
-
-    /* The easy way is just the same as on x86:
-         leaq _dl_start, %0
-         leaq _dl_start(%%rip), %1
-         subq %0, %1
-       but this does not work with binutils since we then have
-       a R_X86_64_32S relocation in a shared lib.
-
-       Instead we store the address of _dl_start in the data section
-       and compare it with the current value that we can get via
-       an RIP relative addressing mode.  Note that this is the address
-       of _dl_start before any relocation performed at runtime.  In case
-       the binary is prelinked the resulting "address" is actually a
-       load offset which is zero if the binary was loaded at the address
-       it is prelinked for.  */
-
-    asm ("leaq " XSTRINGIFY(_ENTRY) "(%%rip), %0\n\t"
-         "subq 1f(%%rip), %0\n\t"
-         ".section\t.data.rel.ro\n"
-         "1:\t.quad " XSTRINGIFY(_ENTRY) "\n\t"
-         ".previous\n\t"
-         : "=r" (addr) : : "cc");
-
-    return addr;
-}
-
 /* The x86-64 never uses Elf64_Rel relocations.  */
 /* The x86-64 never uses Elf64_Rel relocations.  */
 #define ELF_MACHINE_NO_REL 1
 #define ELF_MACHINE_NO_REL 1
 
 
@@ -153,13 +97,22 @@ elf_machine_rela (Elf64_Dyn **l_info, Elf64_Addr l_addr,
 #define SYM (sym)
 #define SYM (sym)
 #else
 #else
     Elf64_Sym *refsym = sym;
     Elf64_Sym *refsym = sym;
-    Elf64_Addr sym_map = RESOLVE_MAP(&strtab, &sym);
-#define SYM (sym ? : refsym)
+    Elf64_Addr value;
+    Elf64_Addr sym_map;
 
 
-    if (!sym_map)
-        sym_map = l_addr;
+    value = RESOLVE_MAP_IN_RTLD(sym);
 
 
-    Elf64_Addr value = sym_map + (sym == NULL ? refsym->st_value : sym->st_value);
+    if (value) {
+        /* We can't handle a IRELEATIVE symbol if it's found in RTLD,
+           they should never exist */
+        if (r_type == R_X86_64_IRELATIVE)
+            return;
+    } else {
+        sym_map = RESOLVE_MAP(&strtab, &sym) ? : l_addr;
+        value = sym_map + (sym ? sym->st_value : refsym->st_value);
+    }
+
+#define SYM (sym ? : refsym)
 
 
     /* We do a very special relocation for loaded libraries */
     /* We do a very special relocation for loaded libraries */
     if (!rel) {
     if (!rel) {

+ 26 - 6
Pal/src/host/Linux/db_main.c

@@ -42,18 +42,20 @@
 #include <sysdeps/generic/ldsodefs.h>
 #include <sysdeps/generic/ldsodefs.h>
 #include <sys/types.h>
 #include <sys/types.h>
 
 
-asm (".global pal_start \n"
-     "  .type pal_start,@function \n"
-     ".global pal_main \n"
-     "  .type pal_main,@function \n");
-
 /* At the begining of entry point, rsp starts at argc, then argvs,
 /* At the begining of entry point, rsp starts at argc, then argvs,
    envps and auxvs. Here we store rsp to rdi, so it will not be
    envps and auxvs. Here we store rsp to rdi, so it will not be
    messed up by function calls */
    messed up by function calls */
-asm ("pal_start: \n"
+asm (".global pal_start \n"
+     "  .type pal_start,@function \n"
+     "pal_start: \n"
      "  movq %rsp, %rdi \n"
      "  movq %rsp, %rdi \n"
      "  call pal_linux_main \n");
      "  call pal_linux_main \n");
 
 
+#define RTLD_BOOTSTRAP
+
+/* pal_start is the entry point of libpal.so, which calls pal_main */
+#define _ENTRY pal_start
+
 asm (".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\r\n"
 asm (".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\r\n"
      ".byte 1\r\n"
      ".byte 1\r\n"
      ".asciz \"" XSTRINGIFY(GDB_SCRIPT) "\"\r\n"
      ".asciz \"" XSTRINGIFY(GDB_SCRIPT) "\"\r\n"
@@ -239,6 +241,12 @@ bad_shebang:
     return 0;
     return 0;
 }
 }
 
 
+#include "elf-x86_64.h"
+#include "dynamic_link.h"
+
+extern void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn,
+                           ElfW(Addr) addr);
+
 void pal_linux_main (void * args)
 void pal_linux_main (void * args)
 {
 {
     int argc;
     int argc;
@@ -247,6 +255,18 @@ void pal_linux_main (void * args)
     /* parse argc, argv, envp and auxv */
     /* parse argc, argv, envp and auxv */
     pal_init_bootstrap(args, &argc, &argv, &envp);
     pal_init_bootstrap(args, &argc, &argv, &envp);
 
 
+    ElfW(Addr) pal_addr = elf_machine_load_address();
+    ElfW(Dyn) * pal_dyn[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM +
+                        DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
+    memset(pal_dyn, 0, sizeof(pal_dyn));
+    elf_get_dynamic_info((void *) pal_addr + elf_machine_dynamic(), pal_dyn,
+                         pal_addr);
+    ELF_DYNAMIC_RELOCATE(pal_dyn, pal_addr);
+
+    init_slab_mgr();
+
+    setup_pal_map(XSTRINGIFY(SRCDIR) "/" LIBRARY_NAME, pal_dyn, pal_addr);
+
     /* jump to main function */
     /* jump to main function */
     pal_main(argc, argv, envp);
     pal_main(argc, argv, envp);
 }
 }

+ 76 - 0
Pal/src/host/Linux/db_rtld.c

@@ -41,6 +41,75 @@
 #include <elf/elf.h>
 #include <elf/elf.h>
 #include <bits/dlfcn.h>
 #include <bits/dlfcn.h>
 
 
+#include "elf-x86_64.h"
+
+struct link_map * rtld_map = NULL;
+
+extern void setup_elf_hash (struct link_map *map);
+
+void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn, ElfW(Addr) addr)
+{
+    assert (loaded_libraries == NULL);
+
+    const ElfW(Ehdr) * header = (void *) addr;
+    struct link_map * l = new_elf_object(realname, OBJECT_RTLD);
+    memcpy(l->l_info, dyn, sizeof(l->l_info));
+    l->l_real_ld = l->l_ld = (void *) elf_machine_dynamic();
+    l->l_addr  = addr;
+    l->l_entry = header->e_entry;
+    l->l_phdr  = (void *) (addr + header->e_phoff);
+    l->l_phnum = header->e_phnum;
+    l->l_relocated = true;
+    l->l_lookup_symbol = true;
+    l->l_soname = "libpal.so";
+    l->l_text_start = (ElfW(Addr)) &text_start;
+    l->l_text_end   = (ElfW(Addr)) &text_end;
+    l->l_data_start = (ElfW(Addr)) &data_start;
+    l->l_data_end   = (ElfW(Addr)) &data_end;
+    setup_elf_hash(l);
+
+    void * begin_hole = (void *) ALLOC_ALIGNUP(l->l_text_end);
+    void * end_hole = (void *) ALLOC_ALIGNDOWN(l->l_data_start);
+
+    /* Usually the test segment and data segment of a loaded library has
+       a gap between them. Need to fill the hole with a empty area */
+    if (begin_hole < end_hole) {
+        void * addr = begin_hole;
+        _DkVirtualMemoryAlloc(&addr, end_hole - begin_hole,
+                              PAL_ALLOC_RESERVE, PAL_PROT_NONE);
+    }
+
+    /* Set up debugging before the debugger is notified for the first time.  */
+    if (l->l_info[DT_DEBUG] != NULL)
+        l->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) &pal_r_debug;
+
+    l->l_prev = l->l_next = NULL;
+    rtld_map = l;
+    loaded_libraries = l;
+
+    if (!pal_sec_info._r_debug) {
+        pal_r_debug.r_version = 1;
+        pal_r_debug.r_brk = (ElfW(Addr)) &pal_dl_debug_state;
+        pal_r_debug.r_ldbase = addr;
+        pal_r_debug.r_map = loaded_libraries;
+        pal_sec_info._r_debug = &pal_r_debug;
+        pal_sec_info._dl_debug_state = &pal_dl_debug_state;
+    } else {
+        pal_sec_info._r_debug->r_state = RT_ADD;
+        pal_sec_info._dl_debug_state();
+
+        if (pal_sec_info._r_debug->r_map) {
+            l->l_prev = pal_sec_info._r_debug->r_map;
+            pal_sec_info._r_debug->r_map->l_next = l;
+        } else {
+            pal_sec_info._r_debug->r_map = loaded_libraries;
+        }
+
+        pal_sec_info._r_debug->r_state = RT_CONSISTENT;
+        pal_sec_info._dl_debug_state();
+    }
+}
+
 #if USE_VDSO_GETTIME == 1
 #if USE_VDSO_GETTIME == 1
 void setup_vdso_map (ElfW(Addr) addr)
 void setup_vdso_map (ElfW(Addr) addr)
 {
 {
@@ -115,3 +184,10 @@ void setup_vdso_map (ElfW(Addr) addr)
     free(l);
     free(l);
 }
 }
 #endif
 #endif
+
+ElfW(Addr) resolve_map_in_rtld (ElfW(Sym) * ref)
+{
+    /* We are not using this, because in Linux we can rely on
+       rtld_map to directly lookup symbols */
+    return 0;
+}

+ 6 - 0
Pal/src/host/Skeleton/db_rtld.c

@@ -38,3 +38,9 @@
 #include <sysdeps/generic/ldsodefs.h>
 #include <sysdeps/generic/ldsodefs.h>
 #include <elf/elf.h>
 #include <elf/elf.h>
 #include <bits/dlfcn.h>
 #include <bits/dlfcn.h>
+
+ElfW(Addr) resolve_map_in_rtld (ElfW(Sym) * ref)
+{
+    /* Not yet implemented */
+    return 0;
+}

+ 1 - 0
Pal/src/pal_rtld.h

@@ -66,6 +66,7 @@ struct link_map {
     ElfW(Dyn) * l_ld;
     ElfW(Dyn) * l_ld;
     char * l_soname;
     char * l_soname;
     bool l_relocated;
     bool l_relocated;
+    bool l_lookup_symbol;
 
 
     ElfW(Dyn) * l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
     ElfW(Dyn) * l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
                        + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
                        + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];