summary refs log tree commit diff
path: root/sysdeps/mips/dl-machine.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mips/dl-machine.h')
-rw-r--r--sysdeps/mips/dl-machine.h93
1 files changed, 80 insertions, 13 deletions
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index 0d2bf9d6b6..6d9570542b 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -37,13 +37,17 @@
 #define OFFSET_GP_GOT 0x7ff0
 
 #ifndef _RTLD_PROLOGUE
-# define _RTLD_PROLOGUE(entry) "\n\t.globl " __STRING(entry)	\
-			       "\n\t.ent " __STRING(entry)	\
-			       "\n\t" __STRING(entry) ":\n\t"
+# define _RTLD_PROLOGUE(entry)						\
+	".globl\t" __STRING(entry) "\n\t"				\
+	".ent\t" __STRING(entry) "\n\t"					\
+	".type\t" __STRING(entry) ", @function\n"			\
+	__STRING(entry) ":\n\t"
 #endif
 
 #ifndef _RTLD_EPILOGUE
-# define _RTLD_EPILOGUE(entry) "\t.end " __STRING(entry) "\n"
+# define _RTLD_EPILOGUE(entry)						\
+	".end\t" __STRING(entry) "\n\t"					\
+	".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
 #endif
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
@@ -134,6 +138,60 @@ elf_machine_load_address (void)
 /* The MSB of got[1] of a gnu object is set to identify gnu objects.  */
 #define ELF_MIPS_GNU_GOT1_MASK 0x80000000
 
+/* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
+   fiddles with global data.  */
+#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)			\
+do {									\
+  struct link_map *map = &bootstrap_map;				\
+  ElfW(Sym) *sym;							\
+  ElfW(Addr) *got;							\
+  int i, n;								\
+									\
+  got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);			\
+									\
+									\
+  if (__builtin_expect (map->l_addr == 0, 1))				\
+    goto done;								\
+									\
+  /* got[0] is reserved. got[1] is also reserved for the dynamic object	\
+     generated by gnu ld. Skip these reserved entries from		\
+     relocation.  */							\
+  i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;				\
+  n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;			\
+									\
+  /* Add the run-time display to all local got entries. */		\
+  while (i < n)								\
+    got[i++] += map->l_addr;						\
+									\
+  /* Handle global got entries. */					\
+  got += n;								\
+  sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB])			\
+       + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;			\
+  i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val			\
+       - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);			\
+									\
+  while (i--)								\
+    {									\
+      if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)	\
+	*got = map->l_addr + sym->st_value;				\
+      else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC			\
+	       && *got != sym->st_value)				\
+	*got += map->l_addr;						\
+      else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)		\
+	{								\
+	  if (sym->st_other == 0)					\
+	    *got += map->l_addr;					\
+	}								\
+      else								\
+	*got = map->l_addr + sym->st_value;				\
+									\
+      got++;								\
+      sym++;								\
+    }									\
+done:									\
+} while(0)
+
+
 /* Get link map for callers object containing STUB_PC.  */
 static inline struct link_map *
 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
@@ -354,10 +412,10 @@ _dl_runtime_resolve:\n							      \
    2) That under Linux the entry is named __start
       and not just plain _start.  */
 
-#define RTLD_START asm ("\
-	.text\n"\
-_RTLD_PROLOGUE(ENTRY_POINT)\
-"	.globl _dl_start_user\n\
+#define RTLD_START asm (\
+	".text\n"\
+	_RTLD_PROLOGUE(ENTRY_POINT)\
+	".set noreorder\n\
 	.set noreorder\n\
 	bltzal $0, 0f\n\
 	nop\n\
@@ -371,10 +429,19 @@ _RTLD_PROLOGUE(ENTRY_POINT)\
 	sw $4, -0x7ff0($28)\n\
 	move $4, $29\n\
 	subu $29, 16\n\
-	jal _dl_start\n\
+	\n\
+	la $8, coff\n\
+	bltzal $8, coff\n\
+coff:	subu $8, $31, $8\n\
+	\n\
+	la $25, _dl_start\n\
+	addu $25, $8\n\
+	jalr $25\n\
+	\n\
 	addiu $29, 16\n\
 	# Get the value of label '_dl_start_user' in t9 ($25).\n\
 	la $25, _dl_start_user\n\
+	.globl _dl_start_user\n\
 _dl_start_user:\n\
 	.set noreorder\n\
 	.cpload $25\n\
@@ -410,9 +477,9 @@ _dl_start_user:\n\
 	la $2, _dl_fini\n\
 	# Jump to the user entry point.\n\
 	move $25, $17\n\
-	jr $25\n"\
-_RTLD_EPILOGUE(ENTRY_POINT)\
-	"\n.previous"\
+	jr $25\n\t"\
+	_RTLD_EPILOGUE(ENTRY_POINT)\
+	".previous"\
 );
 
 /* The MIPS never uses Elfxx_Rela relocations.  */
@@ -513,7 +580,7 @@ elf_machine_got_rel (struct link_map *map, int lazy)
 
   /* got[0] is reserved. got[1] is also reserved for the dynamic object
      generated by gnu ld. Skip these reserved entries from relocation.  */
-  i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2: 1;
+  i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
   /* Add the run-time display to all local got entries if needed. */
   if (__builtin_expect (map->l_addr != 0, 0))