diff options
Diffstat (limited to 'sysdeps/mips/dl-machine.h')
-rw-r--r-- | sysdeps/mips/dl-machine.h | 93 |
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)) |