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 {
 +  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
 index 97902f0..c1874c1 100644
 --- a/LibOS/glibc-2.17/dlfcn/Versions

+ 1 - 20
Pal/src/db_main.c

@@ -27,6 +27,7 @@
 #include "pal_defs.h"
 #include "pal.h"
 #include "pal_internal.h"
+#include "pal_security.h"
 #include "pal_debug.h"
 #include "pal_error.h"
 #include "api.h"
@@ -35,12 +36,6 @@
 #include <elf/elf.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 */
 PAL_NUM allocsize, allocshift, allocmask;
 
@@ -195,25 +190,13 @@ static void * find_heap_base (void)
     return NULL;
 }
 
-void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn, ElfW(Addr) addr);
 void start_execution (int argc, const char ** argv);
 
-#include "dynamic_link.h"
-
 void pal_main (int argc, const char ** argv, const char ** envp)
 {
-    ElfW(Addr) pal_addr;
     char cfgbuf[CONFIG_MAX];
     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.alloc_align = _DkGetAllocationAlignment();
 
@@ -224,8 +207,6 @@ void pal_main (int argc, const char ** argv, const char ** envp)
 
     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
        symbols of loader should be accessible. */
     pal_config.lib_text_start = (void *) &text_start;

+ 36 - 88
Pal/src/db_rtld.c

@@ -39,7 +39,6 @@
 #include <bits/dlfcn.h>
 
 struct link_map * loaded_libraries = NULL;
-struct link_map * rtld_map = NULL;
 struct link_map * exec_map = NULL;
 bool run_preload = false;
 
@@ -99,6 +98,9 @@ static ElfW(Addr) resolve_map (const char **strtab, ElfW(Sym) ** ref)
     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)
 
 #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 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->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.  */
@@ -1016,68 +1026,6 @@ static int relocate_elf_object (struct link_map * l)
     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)
 {
     /* 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 "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.  */
 #define ELF_MACHINE_NO_REL 1
 
@@ -153,13 +97,22 @@ elf_machine_rela (Elf64_Dyn **l_info, Elf64_Addr l_addr,
 #define SYM (sym)
 #else
     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 */
     if (!rel) {

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

@@ -42,18 +42,20 @@
 #include <sysdeps/generic/ldsodefs.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,
    envps and auxvs. Here we store rsp to rdi, so it will not be
    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"
      "  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"
      ".byte 1\r\n"
      ".asciz \"" XSTRINGIFY(GDB_SCRIPT) "\"\r\n"
@@ -239,6 +241,12 @@ bad_shebang:
     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)
 {
     int argc;
@@ -247,6 +255,18 @@ void pal_linux_main (void * args)
     /* parse argc, argv, envp and auxv */
     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 */
     pal_main(argc, argv, envp);
 }

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

@@ -41,6 +41,75 @@
 #include <elf/elf.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
 void setup_vdso_map (ElfW(Addr) addr)
 {
@@ -115,3 +184,10 @@ void setup_vdso_map (ElfW(Addr) addr)
     free(l);
 }
 #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 <elf/elf.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;
     char * l_soname;
     bool l_relocated;
+    bool l_lookup_symbol;
 
     ElfW(Dyn) * l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
                        + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];