Browse Source

mips64 patch from Atsushi Nemoto:
64bit MIPS ELF format tweaks. (from glibc)
Elf32/ElfW convertions.
asm code adjustments.

Eric Andersen 18 years ago
parent
commit
bcd949c7f8
4 changed files with 224 additions and 27 deletions
  1. 61 9
      ldso/ldso/mips/dl-startup.h
  2. 98 4
      ldso/ldso/mips/dl-sysdep.h
  3. 18 14
      ldso/ldso/mips/elfinterp.c
  4. 47 0
      ldso/ldso/mips/resolve.S

+ 61 - 9
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;					\

+ 98 - 4
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? */
 }

+ 18 - 14
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;
 			}

+ 47 - 0
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