linux-mips
[Top] [All Lists]

Clean up the mips dynamic linker

To: linux-mips@oss.sgi.com
Subject: Clean up the mips dynamic linker
From: "H . J . Lu" <hjl@lucon.org>
Date: Thu, 12 Jul 2001 18:24:02 -0700
Cc: GNU C Library <libc-alpha@sourceware.cygnus.com>
Sender: owner-linux-mips@oss.sgi.com
User-agent: Mutt/1.2.5i
Here is a patch to cleanup the mips dynamic linker. It fixes 2 things:

1. We have been handling MAP_BASE_ADDR right for a long time. In
the MIPS SVR4 ABI, DT_MIPS_MAP_BASE_ADDR holds the virtual address of
the segment. According to the ABI, it is only used for 

The dynamic linker relocates the global offset table by first adding
the difference between the base where the shared object is loaded
and the value of dyamic tag DT_MIPS_MAP_BASE_ADDR to all local
global offset table entries.

In glibc, this difference is stored in the l_addr field in link_map. We
have adjusted it in elf_machine_got_rel ():

/* Relocate GOT. */
static inline void
elf_machine_got_rel (struct link_map *map, int lazy)
{
  ElfW(Addr) *got;
  ElfW(Sym) *sym;
  int i, n, symidx;

  got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);

  n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
  /* The dynamic linker's local got entries have already been relocated.  */
  if (map != &_dl_rtld_map)
    {
      /* got[0] is reserved. got[1] is also reserved for the dynamic object
         generated by gnu ld. Skip these reserved entries from relocation.  */
      i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;

      /* Add the run-time displacement to all local got entries if
         needed.  */
      if (__builtin_expect (map->l_addr != 0, 0))
        {
          while (i < n)
            got[i++] += map->l_addr;
        }
    }

In fact, DT_MIPS_MAP_BASE_ADDR is the same as the p_addr field of the
first loadable segment in the program header. I think it is included
in the MIPS ABI to give the dynamic linker easy access to it.

I have tested DSOs with none-zero DT_MIPS_MAP_BASE_ADDR. It works
fine. I think it is safe to remove MAP_BASE_ADDR and old binaries
will work with the new glibc. If someone thinks I am wrong, please
send me a testcase to show it.

2. The existing mips dynamic linker resolves GOT at the wrong time. It
does it in elf_machine_got_rel called from elf_machine_runtime_setup.
It doesn't work with Jakub's prelinking work. I think it should be
done in elf_dynamic_do_rel. I introduced a new macro,
ELF_MACHINE_RESOLVE_GOT, to do it.

I also clean up a little bit to follow lazy binding.

Any comments?

Thanks.



H.J.
-----
2001-07-12  H.J. Lu <hjl@gnu.org>

        * elf/do-rel.h (ELF_MACHINE_RESOLVE_GOT): New.
        (elf_dynamic_do_rel): Call ELF_MACHINE_RESOLVE_GOT.

        * sysdeps/mips/dl-machine.h (MAP_BASE_ADDR): Removed.
        (ELF_MACHINE_RESOLVE_GOT): Defined as elf_machine_resolve_got.
        (elf_machine_resolve_got): New fucntion to resolve GOT.
        (elf_machine_got_rel): Only do GOT relocation.

        * sysdeps/mips/rtld-ldscript.in: Removed.
        * sysdeps/mips/rtld-parms: Likewise.
        * sysdeps/mips/mips64/rtld-parms: Likewise.
        * sysdeps/mips/mipsel/rtld-parms: Likewise.

--- libc/elf/do-rel.h.mips      Sat Jul  7 16:44:45 2001
+++ libc/elf/do-rel.h   Thu Jul 12 17:07:47 2001
@@ -30,6 +30,12 @@
 # define VERSYMIDX(sym)        (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX 
(sym))
 #endif
 
+/* Some machine, like mips, needs to resolve GOT. */
+
+#ifndef ELF_MACHINE_RESOLVE_GOT
+#define ELF_MACHINE_RESOLVE_GOT(map,lazy)
+#endif
+
 /* Perform the relocations in MAP on the running program image as specified
    by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
    relocations; they should be set up to call _dl_runtime_resolve, rather
@@ -42,6 +48,8 @@ elf_dynamic_do_rel (struct link_map *map
 {
   const ElfW(Rel) *r = (const void *) reladdr;
   const ElfW(Rel) *end = (const void *) (reladdr + relsize);
+
+  ELF_MACHINE_RESOLVE_GOT (map, lazy);
 
   if (lazy)
     {
--- libc/sysdeps/mips/dl-machine.h.mips Sat Jul  7 16:46:05 2001
+++ libc/sysdeps/mips/dl-machine.h      Thu Jul 12 17:36:11 2001
@@ -61,23 +61,6 @@
    in l_info array.  */
 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
 
-/*
- * MIPS libraries are usually linked to a non-zero base address.  We
- * subtract the base address from the address where we map the object
- * to.  This results in more efficient address space usage.
- *
- * FIXME: By the time when MAP_BASE_ADDR is called we don't have the
- * DYNAMIC section read.  Until this is fixed make the assumption that
- * libraries have their base address at 0x5ffe0000.  This needs to be
- * fixed before we can safely get rid of this MIPSism.
- */
-#if 0
-#define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \
-                         (l)->l_info[DT_MIPS(BASE_ADDRESS)]->d_un.d_ptr : 0)
-#else
-#define MAP_BASE_ADDR(l) 0x5ffe0000
-#endif
-
 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
    with the run-time address of the r_debug structure  */
 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
@@ -557,76 +540,31 @@ elf_machine_lazy_rel (struct link_map *m
   /* Do nothing.  */
 }
 
-/* Relocate GOT. */
+#ifndef RTLD_BOOTSTRAP
+#define ELF_MACHINE_RESOLVE_GOT(map,lazy) \
+  elf_machine_resolve_got ((map), (lazy))
+
+/* Resolve GOT. */
 static inline void
-elf_machine_got_rel (struct link_map *map, int lazy)
+elf_machine_resolve_got (struct link_map *map, int lazy)
 {
   ElfW(Addr) *got;
   ElfW(Sym) *sym;
-  int i, n, symidx;
-  /*  This function is loaded in dl-reloc as a nested function and can
-      therefore access the variables scope and strtab from
-      _dl_relocate_object.  */
-#ifdef RTLD_BOOTSTRAP
-# define RESOLVE_GOTSYM(sym,sym_index) 0
-#else
-# define RESOLVE_GOTSYM(sym,sym_index)                                   \
-    ({                                                                   \
-      const ElfW(Sym) *ref = sym;                                        \
-      ElfW(Addr) value;                                                        
  \
-                                                                         \
-      switch (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)                \
-       {                                                                 \
-       default:                                                          \
-         {                                                               \
-           const ElfW(Half) *vernum =                                    \
-             (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);  \
-           ElfW(Half) ndx = vernum[sym_index];                           \
-           const struct r_found_version *version = &l->l_versions[ndx];  \
-                                                                         \
-           if (version->hash != 0)                                       \
-             {                                                           \
-               value = _dl_lookup_versioned_symbol(strtab + sym->st_name,\
-                                                   map,                  \
-                                                   &ref, scope, version, \
-                                                   R_MIPS_REL32, 0);     \
-               break;                                                    \
-             }                                                           \
-           /* Fall through.  */                                          \
-         }                                                               \
-       case 0:                                                           \
-         value = _dl_lookup_symbol (strtab + sym->st_name, map, &ref,    \
-                                    scope, R_MIPS_REL32, 0);             \
-       }                                                                 \
-                                                                         \
-      (ref)? value + ref->st_value: 0;                                   \
-    })
-#endif /* RTLD_BOOTSTRAP */
+  int i, n;
+  const ElfW(Half) *const version;
 
-  got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
-
-  n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
-  /* The dynamic linker's local got entries have already been relocated.  */
-  if (map != &_dl_rtld_map)
-    {
-      /* got[0] is reserved. got[1] is also reserved for the dynamic object
-        generated by gnu ld. Skip these reserved entries from relocation.  */
-      i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
+  if (map->l_info[VERSYMIDX (DT_VERSYM)])
+    version = (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+  else
+    version = NULL;
 
-      /* Add the run-time displacement to all local got entries if
-         needed.  */
-      if (__builtin_expect (map->l_addr != 0, 0))
-       {
-         while (i < n)
-           got[i++] += map->l_addr;
-       }
-    }
+  got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
 
   /* Handle global got entries. */
-  got += n;
+  got += map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
   /* Keep track of the symbol index.  */
-  symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
-  sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
+  sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB])
+       + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
 
@@ -635,17 +573,25 @@ elf_machine_got_rel (struct link_map *ma
     {
       if (sym->st_shndx == SHN_UNDEF)
        {
-         if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
-             && sym->st_value && lazy)
-           *got = sym->st_value + map->l_addr;
+         if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC)
+           {
+             if (sym->st_value == 0)
+               {
+                 if (!lazy)
+                   *got = RESOLVE (&sym, version, R_MIPS_REL32);
+               }
+             else if (*got == sym->st_value)
+               *got += map->l_addr;
+             else
+               *got = sym->st_value + map->l_addr;
+           }
          else
-           *got = RESOLVE_GOTSYM (sym, symidx);
+           *got = RESOLVE (&sym, version, R_MIPS_REL32);
        }
       else if (sym->st_shndx == SHN_COMMON)
-       *got = RESOLVE_GOTSYM (sym, symidx);
+       *got = RESOLVE (&sym, version, R_MIPS_REL32);
       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
-              && *got != sym->st_value
-              && lazy)
+              && *got != sym->st_value)
        *got += map->l_addr;
       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
        {
@@ -653,17 +599,40 @@ elf_machine_got_rel (struct link_map *ma
            *got += map->l_addr;
        }
       else
-       *got = RESOLVE_GOTSYM (sym, symidx);
+       *got = RESOLVE (&sym, version, R_MIPS_REL32);
 
       ++got;
       ++sym;
-      ++symidx;
     }
+}
 
-#undef RESOLVE_GOTSYM
+/* Relocate GOT. */
+static inline void
+elf_machine_got_rel (struct link_map *map, int lazy)
+{
+  ElfW(Addr) *got;
+  int i, n;
+
+  got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
+
+  n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
+  /* The dynamic linker's local got entries have already been relocated.  */
+  if (map != &_dl_rtld_map)
+    {
+      /* got[0] is reserved. got[1] is also reserved for the dynamic object
+        generated by gnu ld. Skip these reserved entries from relocation.  */
+      i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
 
-  return;
+      /* Add the run-time displacement to all local got entries if
+         needed.  */
+      if (__builtin_expect (map->l_addr != 0, 0))
+       {
+         while (i < n)
+           got[i++] += map->l_addr;
+       }
+    }
 }
+#endif
 
 /* Set up the loaded object described by L so its stub function
    will jump to the on-demand fixup code __dl_runtime_resolve.  */
--- libc/sysdeps/mips/mips64/rtld-parms.mips    Sat Jul 12 16:26:11 1997
+++ libc/sysdeps/mips/mips64/rtld-parms Thu Jul 12 17:49:55 2001
@@ -1,3 +0,0 @@
-ifndef rtld-wordsize
-rtld-wordsize = 64
-endif
--- libc/sysdeps/mips/mipsel/rtld-parms.mips    Sat Jul 12 16:26:15 1997
+++ libc/sysdeps/mips/mipsel/rtld-parms Thu Jul 12 17:49:55 2001
@@ -1,3 +0,0 @@
-ifndef rtld-oformat
-rtld-oformat = elf32-littlemips
-endif
--- libc/sysdeps/mips/rtld-ldscript.in.mips     Sun May 13 20:39:31 2001
+++ libc/sysdeps/mips/rtld-ldscript.in  Thu Jul 12 17:49:55 2001
@@ -1,105 +0,0 @@
-OUTPUT_ARCH(@@rtld-arch@@)
-ENTRY(@@rtld-entry@@)
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = @@rtld-base@@;
-  .reginfo       : { *(.reginfo) }
-  .dynamic       : { *(.dynamic) }
-  .dynstr        : { *(.dynstr)                }
-  .dynsym        : { *(.dynsym)                }
-  .hash          : { *(.hash)          }
-  .rel.text      : { *(.rel.text)              }
-  .rela.text     : { *(.rela.text)     }
-  .rel.data      : { *(.rel.data)              }
-  .rela.data     : { *(.rela.data)     }
-  .rel.rodata    : { *(.rel.rodata)    }
-  .rela.rodata   : { *(.rela.rodata)   }
-  .rel.got       : { *(.rel.got)               }
-  .rela.got      : { *(.rela.got)              }
-  .rel.ctors     : { *(.rel.ctors)     }
-  .rela.ctors    : { *(.rela.ctors)    }
-  .rel.dtors     : { *(.rel.dtors)     }
-  .rela.dtors    : { *(.rela.dtors)    }
-  .rel.init      : { *(.rel.init)      }
-  .rela.init     : { *(.rela.init)     }
-  .rel.fini      : { *(.rel.fini)      }
-  .rela.fini     : { *(.rela.fini)     }
-  .rel.bss       : { *(.rel.bss)               }
-  .rela.bss      : { *(.rela.bss)              }
-  .rel.plt       : { *(.rel.plt)               }
-  .rela.plt      : { *(.rela.plt)              }
-  .rodata    : { *(.rodata)  }
-  .rodata1   : { *(.rodata1) }
-  .init          : { *(.init)  } =0
-  .text      :
-  {
-    *(.text)
-    *(.stub)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  } =0
-  .fini      : { *(.fini)    } =0
-  /* Adjust the address for the data segment.  We want to adjust up to
-     the same address within the page on the next page up.  It would
-     be more correct to do this:
-       . = 0x10000000;
-     The current expression does not correctly handle the case of a
-     text segment ending precisely at the end of a page; it causes the
-     data segment to skip a page.  The above expression does not have
-     this problem, but it will currently (2/95) cause BFD to allocate
-     a single segment, combining both text and data, for this case.
-     This will prevent the text segment from being shared among
-     multiple executions of the program; I think that is more
-     important than losing a page of the virtual address space (note
-     that no actual memory is lost; the page which is skipped can not
-     be referenced).  */
-  . += 0x10000;
-  .data    :
-  {
-    *(.data)
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  .ctors         : { *(.ctors)   }
-  .dtors         : { *(.dtors)   }
-  _gp = ALIGN(16) + 0x7ff0;
-  .got           :
-  {
-    *(.got.plt) *(.got)
-   }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  .lit8 : { *(.lit8) }
-  .lit4 : { *(.lit4) }
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  /* The normal linker scripts created by the binutils doesn't have the
-     symbols end and _end which breaks ld.so's dl-minimal.c.  */
-  _end = . ;
-  PROVIDE (end = .);
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* DWARF debug sections.
-     Symbols in the .debug DWARF section are relative to the beginning of the
-     section so we begin .debug at 0.  It's not clear yet what needs to happen
-     for the others.   */
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
-  /* These must appear regardless of  .  */
-  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
-  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-}
--- libc/sysdeps/mips/rtld-parms.mips   Mon Jul 21 17:04:07 1997
+++ libc/sysdeps/mips/rtld-parms        Thu Jul 12 17:49:55 2001
@@ -1,15 +0,0 @@
-ifndef rtld-wordsize
-rtld-wordsize = 32
-endif
-ifndef rtld-oformat
-rtld-oformat = elf$(rtld-wordsize)-bigmips
-endif
-ifndef rtld-arch
-rtld-arch = mips
-endif
-ifndef rtld-entry
-rtld-entry = __start
-endif
-ifndef rtld-base
-rtld-base = 0x0fb60000 + SIZEOF_HEADERS
-endif

<Prev in Thread] Current Thread [Next in Thread>