Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ld.elf_so/arch/mips Merge from matt-nb5-mips64:



details:   https://anonhg.NetBSD.org/src/rev/9bfd6083c31b
branches:  trunk
changeset: 749978:9bfd6083c31b
user:      matt <matt%NetBSD.org@localhost>
date:      Mon Dec 14 00:41:18 2009 +0000

description:
Merge from matt-nb5-mips64:
Add N32/N64 support for mips dynamic loader.

diffstat:

 libexec/ld.elf_so/arch/mips/Makefile.inc |   10 +-
 libexec/ld.elf_so/arch/mips/mips_reloc.c |  177 +++++++++++++++++++++---------
 libexec/ld.elf_so/arch/mips/rtld_start.S |  147 +++++++++++++++---------
 3 files changed, 223 insertions(+), 111 deletions(-)

diffs (truncated from 486 to 300 lines):

diff -r b1732b0ab131 -r 9bfd6083c31b libexec/ld.elf_so/arch/mips/Makefile.inc
--- a/libexec/ld.elf_so/arch/mips/Makefile.inc  Mon Dec 14 00:41:03 2009 +0000
+++ b/libexec/ld.elf_so/arch/mips/Makefile.inc  Mon Dec 14 00:41:18 2009 +0000
@@ -1,11 +1,17 @@
-#      $NetBSD: Makefile.inc,v 1.16 2009/11/04 17:02:43 skrll Exp $
+#      $NetBSD: Makefile.inc,v 1.17 2009/12/14 00:41:18 matt Exp $
 
 SRCS+=         rtld_start.S mips_reloc.c
 
 # XXX Should not be in CPPFLAGS!
-CPPFLAGS+=     -mabicalls -G0 -fPIC
+CPUFLAGS+=     -G0
 
+ABI64?= ${CPUFLAGS:M-mabi=64:M-mabi=o64}
+.if !empty(ABI64)
+CPPFLAGS+=     -DELFSIZE=64
+.else
 CPPFLAGS+=     -DELFSIZE=32
+.endif
 CPPFLAGS+=     -DRTLD_INHIBIT_COPY_RELOCS
+AFLAGS+=       -Wa,--fatal-warnings
 
 LDFLAGS+=      -Wl,-e,rtld_start
diff -r b1732b0ab131 -r 9bfd6083c31b libexec/ld.elf_so/arch/mips/mips_reloc.c
--- a/libexec/ld.elf_so/arch/mips/mips_reloc.c  Mon Dec 14 00:41:03 2009 +0000
+++ b/libexec/ld.elf_so/arch/mips/mips_reloc.c  Mon Dec 14 00:41:18 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mips_reloc.c,v 1.55 2009/08/29 13:46:55 jmmv Exp $     */
+/*     $NetBSD: mips_reloc.c,v 1.56 2009/12/14 00:41:18 matt Exp $     */
 
 /*
  * Copyright 1997 Michael L. Hitch <mhitch%montana.edu@localhost>
@@ -30,11 +30,12 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mips_reloc.c,v 1.55 2009/08/29 13:46:55 jmmv Exp $");
+__RCSID("$NetBSD: mips_reloc.c,v 1.56 2009/12/14 00:41:18 matt Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/endian.h>
 
 #include <stdlib.h>
 #include <string.h>
@@ -42,7 +43,9 @@
 #include "debug.h"
 #include "rtld.h"
 
+#ifdef __mips_o32
 #define SUPPORT_OLD_BROKEN_LD
+#endif
 
 void _rtld_bind_start(void);
 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
@@ -52,29 +55,69 @@
  * It is possible for the compiler to emit relocations for unaligned data.
  * We handle this situation with these inlines.
  */
-#define        RELOC_ALIGNED_P(x) \
-       (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
 
-static inline Elf_Addr
-load_ptr(void *where)
+#if ELFSIZE == 64
+/*
+ * ELF64 MIPS encodes the relocs uniquely.  The first 32-bits of info contain
+ * the symbol index.  The top 32-bits contain three relocation types encoded
+ * in big-endian integer with first relocation in LSB.  This means for little
+ * endian we have to byte swap that interger (r_type).
+ */
+#define        Elf_Sxword                      Elf64_Sxword
+#define        ELF_R_NXTTYPE_64_P(r_type)      ((((r_type) >> 8) & 0xff) == R_TYPE(64))
+#if BYTE_ORDER == LITTLE_ENDIAN
+#undef ELF_R_SYM
+#undef ELF_R_TYPE
+#define ELF_R_SYM(r_info)              ((r_info) & 0xffffffff)
+#define ELF_R_TYPE(r_info)             bswap32((r_info) >> 32)
+#endif
+#else
+#define        ELF_R_NXTTYPE_64_P(r_type)      (0)
+#define        Elf_Sxword                      Elf32_Sword
+#endif
+
+static inline Elf_Sxword
+load_ptr(void *where, size_t len)
 {
-       if (__predict_true(RELOC_ALIGNED_P(where)))
-               return *(Elf_Addr *)where;
-       else {
-               Elf_Addr res;
+       Elf_Sxword val;
 
-               (void)memcpy(&res, where, sizeof(res));
-               return res;
+       if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
+#if ELFSIZE == 64
+               if (len == sizeof(Elf_Sxword))
+                       return *(Elf_Sxword *)where;
+#endif
+               return *(Elf_Sword *)where;
        }
+
+       val = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+       (void)memcpy(&val, where, len);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+       (void)memcpy((uint8_t *)((&val)+1) - len, where, len);
+#endif
+       return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val;
 }
 
 static inline void
-store_ptr(void *where, Elf_Addr val)
+store_ptr(void *where, Elf_Sxword val, size_t len)
 {
-       if (__predict_true(RELOC_ALIGNED_P(where)))
-               *(Elf_Addr *)where = val;
-       else
-               (void)memcpy(where, &val, sizeof(val));
+       if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
+#if ELFSIZE == 64
+               if (len == sizeof(Elf_Sxword)) {
+                       *(Elf_Sxword *)where = val;
+                       return;
+               }
+#endif
+               *(Elf_Sword *)where = val;
+               return;
+       }
+#if BYTE_ORDER == LITTLE_ENDIAN
+       (void)memcpy(where, &val, len);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+       (void)memcpy(where, (const uint8_t *)((&val)+1) - len, len);
+#endif
 }
 
 
@@ -94,7 +137,8 @@
        void *where;
        const Elf_Sym *symtab = NULL, *sym;
        Elf_Addr *got = NULL;
-       Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0, i;
+       Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
+       size_t i;
 
        for (; dynp->d_tag != DT_NULL; dynp++) {
                switch (dynp->d_tag) {
@@ -135,20 +179,42 @@
                ++got;
        }
 
-       rellim = (const Elf_Rel *)((const char *)rel + relsz);
+       rellim = (const Elf_Rel *)((uintptr_t)rel + relsz);
        for (; rel < rellim; rel++) {
+               Elf_Word r_symndx, r_type;
+
                where = (void *)(relocbase + rel->r_offset);
 
-               switch (ELF_R_TYPE(rel->r_info)) {
+               r_symndx = ELF_R_SYM(rel->r_info);
+               r_type = ELF_R_TYPE(rel->r_info);
+
+               switch (r_type & 0xff) {
+               case R_TYPE(REL32): {
+                       const size_t rlen =
+                           ELF_R_NXTTYPE_64_P(r_type)
+                               ? sizeof(Elf_Sxword)
+                               : sizeof(Elf_Sword);
+                       Elf_Sxword old = load_ptr(where, rlen);
+                       Elf_Sxword val = old;
+#if ELFSIZE == 64
+                       assert(r_type == R_TYPE(REL32)
+                           || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
+#endif
+                       assert(r_symndx < gotsym);
+                       sym = symtab + r_symndx;
+                       assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
+                       val += relocbase;
+                       store_ptr(where, val, sizeof(Elf_Sword));
+                       rdbg(("REL32/L(%p) %p -> %p in <self>",
+                           where, (void *)old, (void *)val));
+                       store_ptr(where, val, rlen);
+                       break;
+               }
+
+               case R_TYPE(GPREL32):
                case R_TYPE(NONE):
                        break;
 
-               case R_TYPE(REL32):
-                       assert(ELF_R_SYM(rel->r_info) < gotsym);
-                       sym = symtab + ELF_R_SYM(rel->r_info);
-                       assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
-                       store_ptr(where, load_ptr(where) + relocbase);
-                       break;
 
                default:
                        abort();
@@ -185,8 +251,8 @@
        sym = obj->symtab + obj->gotsym;
        /* Now do the global GOT entries */
        for (i = obj->gotsym; i < obj->symtabno; i++) {
-               rdbg((" doing got %d sym %p (%s, %x)", i - obj->gotsym, sym,
-                   sym->st_name + obj->strtab, *got));
+               rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
+                   sym->st_name + obj->strtab, (u_long) *got));
 
 #ifdef SUPPORT_OLD_BROKEN_LD
                if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
@@ -239,37 +305,41 @@
                        *got = def->st_value + (Elf_Addr)defobj->relocbase;
                }
 
-               rdbg(("  --> now %x", *got));
+               rdbg(("  --> now %lx", (u_long) *got));
                ++sym;
                ++got;
        }
 
        got = obj->pltgot;
        for (rel = obj->rel; rel < obj->rellim; rel++) {
+               Elf_Word        r_symndx, r_type;
                void            *where;
-               Elf_Addr         tmp;
-               unsigned long    symnum;
 
                where = obj->relocbase + rel->r_offset;
-               symnum = ELF_R_SYM(rel->r_info);
+               r_symndx = ELF_R_SYM(rel->r_info);
+               r_type = ELF_R_TYPE(rel->r_info);
 
-               switch (ELF_R_TYPE(rel->r_info)) {
+               switch (r_type & 0xff) {
                case R_TYPE(NONE):
                        break;
 
-               case R_TYPE(REL32):
+               case R_TYPE(REL32): {
                        /* 32-bit PC-relative reference */
-                       def = obj->symtab + symnum;
+                       const size_t rlen =
+                           ELF_R_NXTTYPE_64_P(r_type)
+                               ? sizeof(Elf_Sxword)
+                               : sizeof(Elf_Sword);
+                       Elf_Sxword old = load_ptr(where, rlen);
+                       Elf_Sxword val = old;
 
-                       if (symnum >= obj->gotsym) {
-                               tmp = load_ptr(where);
-                               tmp += got[obj->local_gotno + symnum - obj->gotsym];
-                               store_ptr(where, tmp);
+                       def = obj->symtab + r_symndx;
 
-                               rdbg(("REL32/G %s in %s --> %p in %s",
-                                   obj->strtab + def->st_name, obj->path,
-                                   (void *)tmp, obj->path));
-                               break;
+                       if (r_symndx >= obj->gotsym) {
+                               val += got[obj->local_gotno + r_symndx - obj->gotsym];
+                               rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
+                                   where, (void *)old, (void *)val,
+                                   obj->strtab + def->st_name,
+                                   obj->path));
                        } else {
                                /*
                                 * XXX: ABI DIFFERENCE!
@@ -286,7 +356,6 @@
                                 *
                                 * --rkb, Oct 6, 2001
                                 */
-                               tmp = load_ptr(where);
 
                                if (def->st_info ==
                                    ELF_ST_INFO(STB_LOCAL, STT_SECTION)
@@ -294,23 +363,25 @@
                                    && !broken
 #endif
                                    )
-                                       tmp += (Elf_Addr)def->st_value;
+                                       val += (Elf_Addr)def->st_value;
 
-                               tmp += (Elf_Addr)obj->relocbase;
-                               store_ptr(where, tmp);
+                               val += (Elf_Addr)obj->relocbase;
 
-                               rdbg(("REL32/L %s in %s --> %p in %s",
-                                   obj->strtab + def->st_name, obj->path,
-                                   (void *)tmp, obj->path));
+                               rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
+                                   where, (void *)old, (void *)val,
+                                   obj->strtab + def->st_name, obj->path));
                        }
+                       store_ptr(where, val, rlen);
                        break;
+               }
 



Home | Main Index | Thread Index | Old Index