summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2006-11-04 20:14:10 +0000
committerEric Andersen <andersen@codepoet.org>2006-11-04 20:14:10 +0000
commitbcd949c7f80ccf66c8ef869367a9b33dbb51a261 (patch)
tree981e52a9924916366df69688e042f3ad427a22c4
parent980871f06dc4b2359b589fd9d720ed3fc8c3a925 (diff)
mips64 patch from Atsushi Nemoto:
64bit MIPS ELF format tweaks. (from glibc) Elf32/ElfW convertions. asm code adjustments.
-rw-r--r--ldso/ldso/mips/dl-startup.h70
-rw-r--r--ldso/ldso/mips/dl-sysdep.h102
-rw-r--r--ldso/ldso/mips/elfinterp.c32
-rw-r--r--ldso/ldso/mips/resolve.S47
4 files changed, 224 insertions, 27 deletions
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 <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; \
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 <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? */
}
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 <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