Index: glibc-2.16/elf/dynamic-link.h =================================================================== --- glibc-2.16.orig/elf/dynamic-link.h +++ glibc-2.16/elf/dynamic-link.h @@ -172,6 +172,8 @@ elf_get_dynamic_info (struct link_map *l ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM); + ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_XHASH) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM); # undef ADJUST_DYN_INFO assert (cnt <= DL_RO_DYN_TEMP_CNT); } Index: glibc-2.16/elf/elf.h =================================================================== --- glibc-2.16.orig/elf/elf.h +++ glibc-2.16/elf/elf.h @@ -334,6 +334,7 @@ typedef struct #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_XHASH 0x6ffffff4 /* GNU-style hash table with xlat. */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ @@ -720,6 +721,7 @@ typedef struct If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_XHASH 0x6ffffef4 /* GNU-style hash table with xlat. */ #define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ #define DT_TLSDESC_PLT 0x6ffffef6 #define DT_TLSDESC_GOT 0x6ffffef7 @@ -733,7 +735,7 @@ typedef struct #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ -#define DT_ADDRNUM 11 +#define DT_ADDRNUM 12 /* The versioning entry types. The next are defined as part of the GNU extension. */ Index: glibc-2.16/ports/sysdeps/mips/dl-addr.c =================================================================== --- /dev/null +++ glibc-2.16/ports/sysdeps/mips/dl-addr.c @@ -0,0 +1,157 @@ +/* Locate the shared object symbol nearest a given address. + Copyright (C) 1996-2007, 2009, 2011 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + + +static inline void +__attribute ((always_inline)) +determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info, + struct link_map **mapp, const ElfW(Sym) **symbolp) +{ + /* Now we know what object the address lies in. */ + info->dli_fname = match->l_name; + info->dli_fbase = (void *) match->l_map_start; + + /* If this is the main program the information is incomplete. */ + if (__builtin_expect (match->l_name[0], 'a') == '\0' + && match->l_type == lt_executable) + info->dli_fname = _dl_argv[0]; + + const ElfW(Sym) *symtab + = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]); + const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]); + + ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + const ElfW(Sym) *matchsym = NULL; + if (match->l_info[DT_ADDRTAGIDX (DT_GNU_XHASH) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL) + { + const Elf32_Word * const xhash32 + = (void *) D_PTR (match, l_info[DT_ADDRTAGIDX (DT_GNU_XHASH) + DT_NUM + + DT_THISPROCNUM + DT_VERSIONTAGNUM + + DT_EXTRANUM + DT_VALNUM]); + const Elf32_Word ngnusyms = xhash32[0]; + const Elf32_Word symbias = xhash32[2]; + for (Elf32_Word symndx = symbias; symndx < symbias + ngnusyms; ++symndx) + { + /* The hash table never references local symbols so + we can omit that test here. */ + if ((symtab[symndx].st_shndx != SHN_UNDEF + || symtab[symndx].st_value != 0) + && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS + && DL_ADDR_SYM_MATCH (match, &symtab[symndx], + matchsym, addr) + && symtab[symndx].st_name < strtabsize) + matchsym = (ElfW(Sym) *) &symtab[symndx]; + } + } + else + { + const ElfW(Sym) *symtabend; + if (match->l_info[DT_HASH] != NULL) + symtabend = (symtab + + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]); + else + /* There is no direct way to determine the number of symbols in the + dynamic symbol table and no hash table is present. The ELF + binary is ill-formed but what shall we do? Use the beginning of + the string table which generally follows the symbol table. */ + symtabend = (const ElfW(Sym) *) strtab; + + for (; (void *) symtab < (void *) symtabend; ++symtab) + if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL + || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK) + && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS + && (symtab->st_shndx != SHN_UNDEF + || symtab->st_value != 0) + && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr) + && symtab->st_name < strtabsize) + matchsym = (ElfW(Sym) *) symtab; + } + + if (mapp) + *mapp = match; + if (symbolp) + *symbolp = matchsym; + + if (matchsym) + { + /* We found a symbol close by. Fill in its name and exact + address. */ + lookup_t matchl = LOOKUP_VALUE (match); + + info->dli_sname = strtab + matchsym->st_name; + info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym); + } + else + { + /* No symbol matches. We return only the containing object. */ + info->dli_sname = NULL; + info->dli_saddr = NULL; + } +} + + +int +internal_function +_dl_addr (const void *address, Dl_info *info, + struct link_map **mapp, const ElfW(Sym) **symbolp) +{ + const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address); + int result = 0; + + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + /* Find the highest-addressed object that ADDRESS is not below. */ + for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns) + for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l; l = l->l_next) + if (addr >= l->l_map_start && addr < l->l_map_end + && (l->l_contiguous || _dl_addr_inside_object (l, addr))) + { + determine_info (addr, l, info, mapp, symbolp); + result = 1; + goto out; + } + + out: + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + return result; +} +libc_hidden_def (_dl_addr) + +/* Return non-zero if ADDR lies within one of L's segments. */ +int +internal_function +_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) +{ + int n = l->l_phnum; + const ElfW(Addr) reladdr = addr - l->l_addr; + + while (--n >= 0) + if (l->l_phdr[n].p_type == PT_LOAD + && reladdr - l->l_phdr[n].p_vaddr >= 0 + && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz) + return 1; + return 0; +} Index: glibc-2.16/ports/sysdeps/mips/dl-lookup.c =================================================================== --- glibc-2.16.orig/ports/sysdeps/mips/dl-lookup.c +++ glibc-2.16/ports/sysdeps/mips/dl-lookup.c @@ -262,7 +262,9 @@ do_lookup_x (const char *undef_name, uin do if (((*hasharr ^ new_hash) >> 1) == 0) { - symidx = hasharr - map->l_gnu_chain_zero; + symidx = + map->l_mach.gnu_xlat_zero[hasharr - + map->l_gnu_chain_zero]; sym = check_match (&symtab[symidx]); if (sym != NULL) goto found_it; @@ -878,14 +880,15 @@ _dl_setup_hash (struct link_map *map) { Elf_Symndx *hash; - if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_XHASH) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL, 1)) { Elf32_Word *hash32 - = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_XHASH) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM]); + Elf32_Word ngnusyms = *hash32++; map->l_nbuckets = *hash32++; Elf32_Word symbias = *hash32++; Elf32_Word bitmask_nwords = *hash32++; @@ -900,6 +903,8 @@ _dl_setup_hash (struct link_map *map) map->l_gnu_buckets = hash32; hash32 += map->l_nbuckets; map->l_gnu_chain_zero = hash32 - symbias; + hash32 += ngnusyms; + map->l_mach.gnu_xlat_zero = hash32 - symbias; return; } Index: glibc-2.16/ports/sysdeps/mips/bits/linkmap.h =================================================================== --- glibc-2.16.orig/ports/sysdeps/mips/bits/linkmap.h +++ glibc-2.16/ports/sysdeps/mips/bits/linkmap.h @@ -1,4 +1,5 @@ struct link_map_machine { ElfW(Addr) plt; /* Address of .plt */ + const Elf32_Word *gnu_xlat_zero; /* .gnu.xhash */ };