diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/mips/dl-machine.h | 277 |
1 files changed, 147 insertions, 130 deletions
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h index f7a1a6d4c0..d0b20ae655 100644 --- a/sysdeps/mips/dl-machine.h +++ b/sysdeps/mips/dl-machine.h @@ -59,8 +59,13 @@ /* * MIPS libraries are usually linked to a non-zero base address. We - * subtrace the base address from the address where we map the object + * subtract the base address from the address where we map the object * to. This results in more efficient address space usage. + * + * FIXME: By the time when MAP_BASE_ADDR is called we don't have the + * DYNAMIC section read. Until this is fixed make the assumption that + * libraries have their base address at 0x5ffe0000. This needs to be + * fixed before we can safely get rid of this MIPSism. */ #if 0 #define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \ @@ -126,125 +131,8 @@ elf_machine_load_address (void) return addr; } -/* The MSB of got[1] of a gnu object is set to identify gnu objects. */ -#define ELF_MIPS_GNU_GOT1_MASK 0x80000000 - -/* Relocate GOT. */ -static inline void -elf_machine_got_rel (struct link_map *map, int lazy) -{ - ElfW(Addr) *got; - ElfW(Sym) *sym; - int i, n; - const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr; - -#define RESOLVE_GOTSYM(sym) \ - ({ \ - const ElfW(Sym) *ref = sym; \ - ElfW(Addr) sym_loadaddr; \ - sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, &ref, \ - map->l_scope, \ - map->l_name, R_MIPS_REL32);\ - (ref)? sym_loadaddr + ref->st_value: 0; \ - }) - - got = (ElfW(Addr) *) map->l_info[DT_PLTGOT]->d_un.d_ptr; - - /* 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 = (void *) map->l_info[DT_SYMTAB]->d_un.d_ptr; - sym += 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) - { - if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC) - { - if (sym->st_value && lazy) - *got = sym->st_value + map->l_addr; - else - *got = RESOLVE_GOTSYM (sym); - } - else /* if (*got == 0 || *got == QS) */ - *got = RESOLVE_GOTSYM (sym); - } - else if (sym->st_shndx == SHN_COMMON) - *got = RESOLVE_GOTSYM (sym); - else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC - && *got != sym->st_value - && lazy) - *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 = RESOLVE_GOTSYM (sym); - - got++; - sym++; - } - -#undef RESOLVE_GOTSYM - - return; -} - -/* Set up the loaded object described by L so its stub function - will jump to the on-demand fixup code in dl-runtime.c. */ - -static inline int -elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) -{ - ElfW(Addr) *got; - extern void _dl_runtime_resolve (ElfW(Word)); - extern int _dl_mips_gnu_objects; - -#ifdef RTLD_BOOTSTRAP - { - return lazy; - } -#endif - if (lazy) - { - /* The GOT entries for functions have not yet been filled in. - Their initial contents will arrange when called to put an - offset into the .dynsym section in t8, the return address - in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */ - got = (ElfW(Addr) *) l->l_info[DT_PLTGOT]->d_un.d_ptr; - - /* This function will get called to fix up the GOT entry indicated by - the register t8, and then jump to the resolved address. */ - got[0] = (ElfW(Addr)) &_dl_runtime_resolve; - - /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB - of got[1] of a gnu object is set to identify gnu objects. - Where we can store l for non gnu objects? XXX */ - if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0) - got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK); - else - _dl_mips_gnu_objects = 0; - } - - /* Relocate global offset table. */ - elf_machine_got_rel (l, lazy); - - return lazy; -} - -/* Get link_map for this object. */ +/* 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) { @@ -352,9 +240,8 @@ __dl_runtime_resolve (ElfW(Word) sym_index, \ /* Look up the symbol's run-time value. */ \ definer = &symtab[sym_index]; \ \ - loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, \ - l->l_scope, l->l_name, \ - R_MIPS_REL32); \ + loadbase = _dl_lookup_symbol (strtab + definer->st_name, l, &definer, \ + l->l_scope, R_MIPS_REL32); \ \ /* Apply the relocation with that value. */ \ funcaddr = loadbase + definer->st_value; \ @@ -470,19 +357,33 @@ _dl_start_user:\n\ addu $29, $2\n\ # Save back the modified argument count.\n\ sw $4, 0($29)\n\ - # Get _dl_default_scope[2] as argument in _dl_init_next call below.\n\ -1: la $2, _dl_default_scope\n\ - lw $4, 8($2)\n\ +1: subu $29, 16\n\ +2: # Push the searchlist of the main object as argument in\n\ + # the _dl_preinit_next and _dl_init_next calls below.\n\ + lw $4, _dl_main_searchlist\n\ + # First run the pre-initializers.\n\ + # Call _dl_preinit_next to return the address of an initializer\n\ + # function to run.\n\ + jal _dl_preinit_next + move $28, $16\n\ + # Check for zero return, when out of initializers.\n\ + beq $2, $0, 4f\n\ + # Call the pre-initializer.\n\ + move $25, $2\n\ + jalr $25\n\ + move $28, $16\n + # Loop to call _dl_preinit_next for the next initializer.\n\ + b 2b\n +4: lw $4, _dl_main_searchlist\n\ # Call _dl_init_next to return the address of an initializer\n\ # function to run.\n\ - subu $29, 16\n\ jal _dl_init_next\n\ - addiu $29, 16\n\ move $28, $16\n\ # Check for zero return, when out of initializers.\n\ beq $2, $0, 2f\n\ # Call the shared object initializer function.\n\ move $25, $2\n\ + # XXX This looks broken ###.\n\ lw $4, 0($29)\n\ lw $5, 4($29)\n\ lw $6, 8($29)\n\ @@ -490,8 +391,9 @@ _dl_start_user:\n\ jalr $25\n\ move $28, $16\n\ # Loop to call _dl_init_next for the next initializer.\n\ - b 1b\n\ -2: # Clear the startup flag. Assumes 32 bit ints.\n\ + b 4b\n\ +2: addiu $29, 16\n\ + # Clear the startup flag. Assumes 32 bit ints.\n\ sw $0, _dl_starting_up\n\ # Pass our finalizer function to the user in ra.\n\ la $31, _dl_fini\n\ @@ -552,7 +454,7 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc, built-in definitions used while loading those libraries. */ undo = map->l_addr + sym->st_value; #endif - loadbase = RESOLVE (&sym, version, 0); + loadbase = RESOLVE (&sym, version, R_MIPS_REL32); *reloc_addr += (sym ? (loadbase + sym->st_value) : 0) - undo; } break; @@ -571,4 +473,119 @@ elf_machine_lazy_rel (struct link_map *map, /* Do nothing. */ } +/* The MSB of got[1] of a gnu object is set to identify gnu objects. */ +#define ELF_MIPS_GNU_GOT1_MASK 0x80000000 + +/* Relocate GOT. */ +static inline void +elf_machine_got_rel (struct link_map *map, int lazy) +{ + ElfW(Addr) *got; + ElfW(Sym) *sym; + int i, n; + const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr; + +#define RESOLVE_GOTSYM(sym) \ + ({ \ + const ElfW(Sym) *ref = sym; \ + ElfW(Addr) sym_loadaddr; \ + sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, map, \ + &ref, map->l_scope, \ + R_MIPS_REL32); \ + (ref)? sym_loadaddr + ref->st_value: 0; \ + }) + + got = (ElfW(Addr) *) map->l_info[DT_PLTGOT]->d_un.d_ptr; + + /* 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 = (void *) map->l_info[DT_SYMTAB]->d_un.d_ptr; + sym += 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) + { + if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC) + { + if (sym->st_value && lazy) + *got = sym->st_value + map->l_addr; + else + *got = RESOLVE_GOTSYM (sym); + } + else /* if (*got == 0 || *got == QS) */ + *got = RESOLVE_GOTSYM (sym); + } + else if (sym->st_shndx == SHN_COMMON) + *got = RESOLVE_GOTSYM (sym); + else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC + && *got != sym->st_value + && lazy) + *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 = RESOLVE_GOTSYM (sym); + + got++; + sym++; + } + +#undef RESOLVE_GOTSYM + + return; +} + +/* Set up the loaded object described by L so its stub function + will jump to the on-demand fixup code in dl-runtime.c. */ + +static inline int +elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) +{ +# ifndef RTLD_BOOTSTRAP + ElfW(Addr) *got; + extern void _dl_runtime_resolve (ElfW(Word)); + extern int _dl_mips_gnu_objects; + + if (lazy) + { + /* The GOT entries for functions have not yet been filled in. + Their initial contents will arrange when called to put an + offset into the .dynsym section in t8, the return address + in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */ + got = (ElfW(Addr) *) l->l_info[DT_PLTGOT]->d_un.d_ptr; + + /* This function will get called to fix up the GOT entry indicated by + the register t8, and then jump to the resolved address. */ + got[0] = (ElfW(Addr)) &_dl_runtime_resolve; + + /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB + of got[1] of a gnu object is set to identify gnu objects. + Where we can store l for non gnu objects? XXX */ + if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0) + got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK); + else + _dl_mips_gnu_objects = 0; + } + + /* Relocate global offset table. */ + elf_machine_got_rel (l, lazy); + +# endif + return lazy; +} + #endif /* RESOLVE */ |