From bcd949c7f80ccf66c8ef869367a9b33dbb51a261 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Sat, 4 Nov 2006 20:14:10 +0000 Subject: mips64 patch from Atsushi Nemoto: 64bit MIPS ELF format tweaks. (from glibc) Elf32/ElfW convertions. asm code adjustments. --- ldso/ldso/mips/dl-startup.h | 70 ++++++++++++++++++++++++++---- ldso/ldso/mips/dl-sysdep.h | 102 ++++++++++++++++++++++++++++++++++++++++++-- ldso/ldso/mips/elfinterp.c | 32 ++++++++------ ldso/ldso/mips/resolve.S | 47 ++++++++++++++++++++ 4 files changed, 224 insertions(+), 27 deletions(-) (limited to 'ldso') diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h index bf461d3b8..4e3fcafb8 100644 --- a/ldso/ldso/mips/dl-startup.h +++ b/ldso/ldso/mips/dl-startup.h @@ -6,6 +6,7 @@ */ +#include 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_indexdynamic_info[DT_MIPS_GOTSYM_IDX])\ *REL += SYMBOL; \ diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h index 5f4dfadc3..19f6812a1 100644 --- a/ldso/ldso/mips/dl-sysdep.h +++ b/ldso/ldso/mips/dl-sysdep.h @@ -8,6 +8,89 @@ /* Define this if the system uses RELOCA. */ #undef ELF_USES_RELOCA #include + +#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 #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? */ } diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index d7aae353d..1b03d9412 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -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; } diff --git a/ldso/ldso/mips/resolve.S b/ldso/ldso/mips/resolve.S index 6dc89643e..f7b286252 100644 --- a/ldso/ldso/mips/resolve.S +++ b/ldso/ldso/mips/resolve.S @@ -12,12 +12,14 @@ * */ +#include .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 -- cgit v1.2.3