OSDN Git Service

mips64 patch from Atsushi Nemoto:
authorEric Andersen <andersen@codepoet.org>
Sat, 4 Nov 2006 20:14:10 +0000 (20:14 -0000)
committerEric Andersen <andersen@codepoet.org>
Sat, 4 Nov 2006 20:14:10 +0000 (20:14 -0000)
64bit MIPS ELF format tweaks. (from glibc)
Elf32/ElfW convertions.
asm code adjustments.

ldso/ldso/mips/dl-startup.h
ldso/ldso/mips/dl-sysdep.h
ldso/ldso/mips/elfinterp.c
ldso/ldso/mips/resolve.S

index bf461d3..4e3fcaf 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 
+#include <sgidefs.h>
 asm(""
     "  .text\n"
     "  .globl  _start\n"
@@ -17,23 +18,66 @@ asm(""
     "  bal     0f\n"
     "  nop\n"
     "0:\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI32
     "  .cpload $31\n"
+#else  /* N32 || N64 */
+    "  .cpsetup $31, $2, 0b\n"
+#endif /* N32 || N64 */
     "  move    $31, $25\n"
     "  .set reorder\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+    "  dla     $4, _DYNAMIC\n"
+    "  sd      $4, -0x7ff0($28)\n"
+#else  /* O32 || N32 */
     "  la      $4, _DYNAMIC\n"
     "  sw      $4, -0x7ff0($28)\n"
+#endif /* O32 || N32 */
     "  move    $4, $29\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI32
     "  subu    $29, 16\n"
+#endif
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+    "  dla     $8, .coff\n"
+#else  /* O32 || N32 */
     "  la      $8, .coff\n"
+#endif /* O32 || N32 */
     "  bltzal  $8, .coff\n"
     ".coff:\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+    "  dsubu   $8, $31, $8\n"
+    "  dla     $25, _dl_start\n"
+    "  daddu   $25, $8\n"
+#else  /* O32 || N32 */
     "  subu    $8, $31, $8\n"
     "  la      $25, _dl_start\n"
     "  addu    $25, $8\n"
+#endif /* O32 || N32 */
     "  jalr    $25\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI32
     "  addiu   $29, 16\n"
+#endif
     "  move    $16, $28\n"
     "  move    $17, $2\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+    "  ld      $2, _dl_skip_args\n"
+    "  beq     $2, $0, 1f\n"
+    "  ld      $4, 0($29)\n"
+    "  dsubu   $4, $2\n"
+    "  dsll    $2, 2\n"
+    "  daddu   $29, $2\n"
+    "  sd      $4, 0($29)\n"
+    "1:\n"
+    "  ld      $5, 0($29)\n"
+    "  dla     $6, 8 ($29)\n"
+    "  dsll    $7, $5, 2\n"
+    "  daddu   $7, $7, $6\n"
+    "  daddu   $7, $7, 4\n"
+    "  and     $2, $29, -4 * 4\n"
+    "  sd      $29, -8($2)\n"
+    "  dsubu   $29, $2, 32\n"
+    "  ld      $29, 24($29)\n"
+    "  dla     $2, _dl_fini\n"
+#else  /* O32 || N32 */
     "  lw      $2, _dl_skip_args\n"
     "  beq     $2, $0, 1f\n"
     "  lw      $4, 0($29)\n"
@@ -50,9 +94,12 @@ asm(""
     "  and     $2, $29, -2 * 4\n"
     "  sw      $29, -4($2)\n"
     "  subu    $29, $2, 32\n"
+#if _MIPS_SIM == _MIPS_SIM_ABI32
     "  .cprestore 16\n"
+#endif
     "  lw      $29, 28($29)\n"
     "  la      $2, _dl_fini\n"
+#endif /* O32 || N32 */
     "  move    $25, $17\n"
     "  jr      $25\n"
     ".end      _start\n"
@@ -80,10 +127,10 @@ asm(""
  */
 #define PERFORM_BOOTSTRAP_GOT(tpnt)                                            \
 do {                                                                           \
-       Elf32_Sym *sym;                                                         \
-       Elf32_Addr i;                                                           \
+       ElfW(Sym) *sym;                                                         \
+       ElfW(Addr) i;                                                           \
        register ElfW(Addr) gp __asm__ ("$28");                                 \
-       Elf32_Addr *mipsgot = elf_mips_got_from_gpreg (gp);                     \
+       ElfW(Addr) *mipsgot = elf_mips_got_from_gpreg (gp);                     \
                                                                                \
        /* Add load address displacement to all local GOT entries */            \
        i = 2;                                                                  \
@@ -92,18 +139,18 @@ do {                                                                               \
                                                                                \
        /* Handle global GOT entries */                                         \
        mipsgot += tpnt->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX];                 \
-       sym = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB] +                     \
-                       tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];                 \
+       sym = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB] +                     \
+                       tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];                 \
        i = tpnt->dynamic_info[DT_MIPS_SYMTABNO_IDX] - tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];\
                                                                                \
        while (i--) {                                                           \
                if (sym->st_shndx == SHN_UNDEF ||                               \
                        sym->st_shndx == SHN_COMMON)                            \
                        *mipsgot = tpnt->loadaddr + sym->st_value;              \
-               else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&             \
+               else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&               \
                        *mipsgot != sym->st_value)                              \
                        *mipsgot += tpnt->loadaddr;                             \
-               else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {          \
+               else if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {            \
                        if (sym->st_other == 0)                                 \
                                *mipsgot += tpnt->loadaddr;                     \
                }                                                               \
@@ -119,9 +166,14 @@ do {                                                                               \
  * Here is a macro to perform a relocation.  This is only used when
  * bootstrapping the dynamic loader.
  */
+#if _MIPS_SIM == _MIPS_SIM_ABI64       /* consult with glibc sysdeps/mips/dl-machine.h 1.69 */
+#define R_MIPS_BOOTSTRAP_RELOC ((R_MIPS_64 << 8) | R_MIPS_REL32)
+#else  /* N32 || O32 */
+#define R_MIPS_BOOTSTRAP_RELOC R_MIPS_REL32
+#endif
 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB)                   \
-       switch(ELF32_R_TYPE((RELP)->r_info)) {                                  \
-       case R_MIPS_REL32:                                                      \
+       switch(ELF_R_TYPE((RELP)->r_info)) {                                    \
+       case R_MIPS_BOOTSTRAP_RELOC:                                            \
                if (SYMTAB) {                                                   \
                        if (symtab_index<tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX])\
                                *REL += SYMBOL;                                 \
index 5f4dfad..19f6812 100644 (file)
@@ -8,6 +8,89 @@
 /* Define this if the system uses RELOCA.  */
 #undef ELF_USES_RELOCA
 #include <elf.h>
+
+#ifdef __mips64        /* from glibc sysdeps/mips/elf/ldsodefs.h 1.4 */
+/* The 64-bit MIPS ELF ABI uses an unusual reloc format.  Each
+   relocation entry specifies up to three actual relocations, all at
+   the same address.  The first relocation which required a symbol
+   uses the symbol in the r_sym field.  The second relocation which
+   requires a symbol uses the symbol in the r_ssym field.  If all
+   three relocations require a symbol, the third one uses a zero
+   value.
+
+   We define these structures in internal headers because we're not
+   sure we want to make them part of the ABI yet.  Eventually, some of
+   this may move into elf/elf.h.  */
+
+/* An entry in a 64 bit SHT_REL section.  */
+
+typedef struct
+{
+  Elf32_Word    r_sym;         /* Symbol index */
+  unsigned char r_ssym;                /* Special symbol for 2nd relocation */
+  unsigned char r_type3;       /* 3rd relocation type */
+  unsigned char r_type2;       /* 2nd relocation type */
+  unsigned char r_type1;       /* 1st relocation type */
+} _Elf64_Mips_R_Info;
+
+typedef union
+{
+  Elf64_Xword  r_info_number;
+  _Elf64_Mips_R_Info r_info_fields;
+} _Elf64_Mips_R_Info_union;
+
+typedef struct
+{
+  Elf64_Addr   r_offset;               /* Address */
+  _Elf64_Mips_R_Info_union r_info;     /* Relocation type and symbol index */
+} Elf64_Mips_Rel;
+
+typedef struct
+{
+  Elf64_Addr   r_offset;               /* Address */
+  _Elf64_Mips_R_Info_union r_info;     /* Relocation type and symbol index */
+  Elf64_Sxword r_addend;               /* Addend */
+} Elf64_Mips_Rela;
+
+#define ELF64_MIPS_R_SYM(i) \
+  ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym)
+#define ELF64_MIPS_R_TYPE(i) \
+  (((_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1 \
+   | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \
+                  ).r_info_fields.r_type2 << 8) \
+   | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \
+                  ).r_info_fields.r_type3 << 16) \
+   | ((Elf32_Word)(__extension__ (_Elf64_Mips_R_Info_union)(i) \
+                  ).r_info_fields.r_ssym << 24))
+#define ELF64_MIPS_R_INFO(sym, type) \
+  (__extension__ (_Elf64_Mips_R_Info_union) \
+   (__extension__ (_Elf64_Mips_R_Info) \
+   { (sym), ELF64_MIPS_R_SSYM (type), \
+       ELF64_MIPS_R_TYPE3 (type), \
+       ELF64_MIPS_R_TYPE2 (type), \
+       ELF64_MIPS_R_TYPE1 (type) \
+   }).r_info_number)
+/* These macros decompose the value returned by ELF64_MIPS_R_TYPE, and
+   compose it back into a value that it can be used as an argument to
+   ELF64_MIPS_R_INFO.  */
+#define ELF64_MIPS_R_SSYM(i) (((i) >> 24) & 0xff)
+#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff)
+#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff)
+#define ELF64_MIPS_R_TYPE1(i) ((i) & 0xff)
+#define ELF64_MIPS_R_TYPEENC(type1, type2, type3, ssym) \
+  ((type1) \
+   | ((Elf32_Word)(type2) << 8) \
+   | ((Elf32_Word)(type3) << 16) \
+   | ((Elf32_Word)(ssym) << 24))
+
+#undef ELF64_R_SYM
+#define ELF64_R_SYM(i) ELF64_MIPS_R_SYM (i)
+#undef ELF64_R_TYPE
+#define ELF64_R_TYPE(i) ELF64_MIPS_R_TYPE (i)
+#undef ELF64_R_INFO
+#define ELF64_R_INFO(sym, type) ELF64_MIPS_R_INFO ((sym), (type))
+#endif /* __mips64 */
+
 #include <link.h>
 
 #define ARCH_NUM 3
@@ -24,7 +107,7 @@ else if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) \
 else if (dpnt->d_tag == DT_MIPS_SYMTABNO) \
      dynamic[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; \
 else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \
-     *(Elf32_Addr *)(dpnt->d_un.d_ptr) =  (Elf32_Addr) debug_addr; \
+     *(ElfW(Addr) *)(dpnt->d_un.d_ptr) =  (ElfW(Addr)) debug_addr; \
 } while (0)
 
 /* Initialization sequence for the application/library GOT.  */
@@ -64,9 +147,15 @@ struct elf_resolve;
 void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
 
 /* 4096 bytes alignment */
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+#define PAGE_ALIGN (~0xfffUL)
+#define ADDR_ALIGN 0xfffUL
+#define OFFS_ALIGN (0x10000000000UL-0x1000)
+#else  /* O32 || N32 */
 #define PAGE_ALIGN 0xfffff000
 #define ADDR_ALIGN 0xfff
 #define OFFS_ALIGN 0x7ffff000
+#endif /* O32 || N32 */
 
 #define elf_machine_type_class(type)           ELF_RTYPE_CLASS_PLT
 /* MIPS does not have COPY relocs */
@@ -94,8 +183,13 @@ elf_machine_dynamic (void)
 #define STRINGXP(X) __STRING(X)
 #define STRINGXV(X) STRINGV_(X)
 #define STRINGV_(...) # __VA_ARGS__
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+#define PTR_LA               dla
+#define PTR_SUBU     dsubu
+#else
 #define PTR_LA               la
 #define PTR_SUBU     subu
+#endif
 
 /* Return the run-time load address of the shared object.  */
 static inline ElfW(Addr)
@@ -115,8 +209,8 @@ elf_machine_load_address (void)
 }
 
 static inline void
-elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
-                     Elf32_Word relative_count)
+elf_machine_relative (ElfW(Addr) load_off, const ElfW(Addr) rel_addr,
+                     ElfW(Word) relative_count)
 {
-       /* No REALTIVE relocs in MIPS? */
+       /* No RELATIVE relocs in MIPS? */
 }
index d7aae35..1b03d94 100644 (file)
@@ -38,7 +38,7 @@ unsigned long __dl_runtime_resolve(unsigned long sym_index,
 {
        unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT);
        struct elf_resolve *tpnt = (struct elf_resolve *) got[1];
-       Elf32_Sym *sym;
+       ElfW(Sym) *sym;
        char *strtab;
        unsigned long local_gotno;
        unsigned long gotsym;
@@ -50,7 +50,7 @@ unsigned long __dl_runtime_resolve(unsigned long sym_index,
        gotsym = tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];
        local_gotno = tpnt->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX];
 
-       sym = ((Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB]) + sym_index;
+       sym = ((ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB]) + sym_index;
        strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
        symname = strtab + sym->st_name;
 
@@ -93,8 +93,8 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 int _dl_parse_relocation_information(struct dyn_elf *xpnt,
        unsigned long rel_addr, unsigned long rel_size)
 {
-       Elf32_Sym *symtab;
-       Elf32_Rel *rpnt;
+       ElfW(Sym) *symtab;
+       ElfW(Rel) *rpnt;
        char *strtab;
        unsigned long i;
        unsigned long *got;
@@ -107,18 +107,18 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 #endif
 
        /* Now parse the relocation information */
-       rel_size = rel_size / sizeof(Elf32_Rel);
-       rpnt = (Elf32_Rel *) rel_addr;
+       rel_size = rel_size / sizeof(ElfW(Rel));
+       rpnt = (ElfW(Rel) *) rel_addr;
 
-       symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
+       symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
        strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
        got = (unsigned long *) tpnt->dynamic_info[DT_PLTGOT];
 
        for (i = 0; i < rel_size; i++, rpnt++) {
                reloc_addr = (unsigned long *) (tpnt->loadaddr +
                        (unsigned long) rpnt->r_offset);
-               reloc_type = ELF32_R_TYPE(rpnt->r_info);
-               symtab_index = ELF32_R_SYM(rpnt->r_info);
+               reloc_type = ELF_R_TYPE(rpnt->r_info);
+               symtab_index = ELF_R_SYM(rpnt->r_info);
                symbol_addr = 0;
 
                debug_sym(symtab,strtab,symtab_index);
@@ -129,7 +129,11 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 #endif
 
                switch (reloc_type) {
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+               case (R_MIPS_64 << 8) | R_MIPS_REL32:
+#else  /* O32 || N32 */
                case R_MIPS_REL32:
+#endif /* O32 || N32 */
                        if (symtab_index) {
                                if (symtab_index < tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX])
                                        *reloc_addr +=
@@ -174,7 +178,7 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 /* Relocate the global GOT entries for the object */
 void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)
 {
-       Elf32_Sym *sym;
+       ElfW(Sym) *sym;
        char *strtab;
        unsigned long i, tmp_lazy;
        unsigned long *got_entry;
@@ -188,7 +192,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)
                /* Setup the loop variables */
                got_entry = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT])
                        + tpnt->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX];
-               sym = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB] + tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];
+               sym = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB] + tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];
                strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
                i = tpnt->dynamic_info[DT_MIPS_SYMTABNO_IDX] - tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX];
 
@@ -200,7 +204,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)
                /* Relocate the global GOT entries for the object */
                while (i--) {
                        if (sym->st_shndx == SHN_UNDEF) {
-                               if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value && tmp_lazy) {
+                               if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value && tmp_lazy) {
                                        *got_entry = sym->st_value + (unsigned long) tpnt->loadaddr;
                                }
                                else {
@@ -212,11 +216,11 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)
                                *got_entry = (unsigned long) _dl_find_hash(strtab +
                                        sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
                        }
-                       else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
+                       else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
                                *got_entry != sym->st_value && tmp_lazy) {
                                *got_entry += (unsigned long) tpnt->loadaddr;
                        }
-                       else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {
+                       else if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
                                if (sym->st_other == 0)
                                        *got_entry += (unsigned long) tpnt->loadaddr;
                        }
index 6dc8964..f7b2862 100644 (file)
  *
  */
 
+#include <sgidefs.h>
 .text
 .align 2
 .globl _dl_runtime_resolve
 .type  _dl_runtime_resolve,@function
 .ent   _dl_runtime_resolve
 _dl_runtime_resolve:
+#if _MIPS_SIM == _MIPS_SIM_ABI32
        .frame  $29, 40, $31
        .set noreorder
 
@@ -60,6 +62,51 @@ _dl_runtime_resolve:
 
        # Do a tail call to the original function
        addiu   $29, 40
+#else  /* N32 || N64 */
+       .set noreorder
+
+       # Save GP.
+       move    $3, $28
+
+       # Save arguments and sp value on stack.
+       dsubu   $29, 80
+
+       # Compute GP.
+       .set noreorder
+       .cpsetup        $25, 0, _dl_runtime_resolve
+       .set reorder
+
+       # Store function arguments from registers to stack
+       sd      $15, 72($29)
+       sd      $4, 8($29)
+       sd      $5, 16($29)
+       sd      $6, 24($29)
+       sd      $7, 32($29)
+       sd      $8, 40($29)
+       sd      $9, 48($29)
+       sd      $10, 56($29)
+       sd      $11, 64($29)
+
+       # Setup functions args and call __dl_runtime_resolve
+       move    $4, $24
+       move    $5, $3
+       jal     __dl_runtime_resolve
+
+       # Restore function arguments from stack to registers
+       ld      $31, 72($29)
+       ld      $4, 8($29)
+       ld      $5, 16($29)
+       ld      $6, 24($29)
+       ld      $7, 32($29)
+       ld      $8, 40($29)
+       ld      $9, 48($29)
+       ld      $10, 56($29)
+       ld      $11, 64($29)
+
+       # Do a tail call to the original function
+       .cpreturn
+       daddu   $29, 80
+#endif /* N32 || N64 */
        move    $25, $2
        jr      $25
 .end   _dl_runtime_resolve