diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index 9d285d7..3f2297a 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -42,7 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
   ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
 
   const ElfW(Sym) *matchsym = NULL;
-  if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
+  if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)
     {
       /* We look at all symbol table entries referenced by the hash
 	 table.  */
@@ -57,6 +57,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
 		{
 		  /* The hash table never references local symbols so
 		     we can omit that test here.  */
+		  symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr);
 		  if ((symtab[symndx].st_shndx != SHN_UNDEF
 		       || symtab[symndx].st_value != 0)
 		      && symtab[symndx].st_shndx != SHN_ABS
@@ -65,8 +66,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
 					    matchsym, addr)
 		      && symtab[symndx].st_name < strtabsize)
 		    matchsym = (ElfW(Sym) *) &symtab[symndx];
-
-		  ++symndx;
 		}
 	      while ((*hasharr++ & 1u) == 0);
 	    }
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index eb23cca..f9d6c36 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -403,7 +403,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 		  do
 		    if (((*hasharr ^ new_hash) >> 1) == 0)
 		      {
-			symidx = hasharr - map->l_gnu_chain_zero;
+			symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
 			sym = check_match (undef_name, ref, version, flags,
 					   type_class, &symtab[symidx], symidx,
 					   strtab, map, &versioned_sym,
@@ -909,10 +909,10 @@ _dl_setup_hash (struct link_map *map)
 {
   Elf_Symndx *hash;
 
-  if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL))
+  if (__glibc_likely (map->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL))
     {
       Elf32_Word *hash32
-	= (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]);
+	= (void *) D_PTR (map, l_info[ELF_MACHINE_GNU_HASH_ADDRIDX]);
       map->l_nbuckets = *hash32++;
       Elf32_Word symbias = *hash32++;
       Elf32_Word bitmask_nwords = *hash32++;
@@ -927,6 +927,10 @@ _dl_setup_hash (struct link_map *map)
       map->l_gnu_buckets = hash32;
       hash32 += map->l_nbuckets;
       map->l_gnu_chain_zero = hash32 - symbias;
+
+      /* Initialize MIPS xhash translation table.  */
+      ELF_MACHINE_XHASH_SETUP (hash32, symbias, map);
+
       return;
     }
 
diff --git a/elf/elf.h b/elf/elf.h
index 7c6d609..5b6ea63 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1715,6 +1715,7 @@ typedef struct
 #define SHT_MIPS_EH_REGION	0x70000027
 #define SHT_MIPS_XLATE_OLD	0x70000028
 #define SHT_MIPS_PDR_EXCEPTION	0x70000029
+#define SHT_MIPS_XHASH		0x7000002b
 
 /* Legal values for sh_flags field of Elf32_Shdr.  */
 
@@ -1962,7 +1963,9 @@ typedef struct
    in a PIE as it stores a relative offset from the address of the tag
    rather than an absolute address.  */
 #define DT_MIPS_RLD_MAP_REL  0x70000035
-#define DT_MIPS_NUM	     0x36
+/* GNU-style hash table with xlat.  */
+#define DT_MIPS_XHASH	     0x70000036
+#define DT_MIPS_NUM	     0x37
 
 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
 
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index b1fc5c3..1e193b0 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -47,6 +47,23 @@ __BEGIN_DECLS
 #define ADDRIDX(tag)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
 			 + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
 
+/* Type of GNU hash which the machine uses.  */
+#ifndef ELF_MACHINE_GNU_HASH_ADDRIDX
+# define ELF_MACHINE_GNU_HASH_ADDRIDX ADDRIDX (DT_GNU_HASH)
+#endif
+
+/* Calculate the index of a symbol in GNU hash.  */
+#ifndef ELF_MACHINE_HASH_SYMIDX
+# define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
+  ((hasharr) - (map)->l_gnu_chain_zero)
+#endif
+
+/* Setup MIPS xhash.  Defined only for MIPS.  */
+#ifndef ELF_MACHINE_XHASH_SETUP
+# define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \
+  ((void) (hash32), (void) (symbias), (void) (map))
+#endif
+
 /* We use this macro to refer to ELF types independent of the native wordsize.
    `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'.  */
 #define ELFW(type)	_ElfW (ELF, __ELF_NATIVE_CLASS, type)
diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
index f0acb02..95cd38e 100644
--- a/sysdeps/mips/ldsodefs.h
+++ b/sysdeps/mips/ldsodefs.h
@@ -26,6 +26,21 @@ struct La_mips_32_retval;
 struct La_mips_64_regs;
 struct La_mips_64_retval;
 
+#define ELF_MACHINE_GNU_HASH_ADDRIDX (DT_MIPS_XHASH - DT_LOPROC + DT_NUM)
+
+/* Calculate the index of a symbol in MIPS xhash.  */
+#define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
+  ((map)->l_mach.mips_xlat_zero[(hasharr) - (map)->l_gnu_chain_zero])
+
+/* Setup MIPS xhash.  */
+#define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map)			    \
+  do									    \
+    {									    \
+      (hash32) += (map)->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - (symbias); \
+      (map)->l_mach.mips_xlat_zero = (hash32) - (symbias);		    \
+    }									    \
+  while (0)
+
 #define ARCH_PLTENTER_MEMBERS						    \
     Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int,	    \
 					 uintptr_t *, uintptr_t *,	    \
diff --git a/sysdeps/mips/linkmap.h b/sysdeps/mips/linkmap.h
index 1fb9678..1e640c3 100644
--- a/sysdeps/mips/linkmap.h
+++ b/sysdeps/mips/linkmap.h
@@ -3,4 +3,5 @@ struct link_map_machine
     ElfW(Addr) plt; /* Address of .plt */
     ElfW(Word) fpabi; /* FP ABI of the object */
     unsigned int odd_spreg; /* Does the object require odd_spreg support? */
+    const Elf32_Word *mips_xlat_zero; /* .MIPS.xhash */
   };
diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
index 28257f8..ce7b2f9 100644
--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h
+++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map);
 #undef VALID_ELF_ABIVERSION
 #define VALID_ELF_ABIVERSION(osabi,ver)			\
   (ver == 0						\
-   || (osabi == ELFOSABI_SYSV && ver < 5)		\
+   || (osabi == ELFOSABI_SYSV && ver < 6)		\
    || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
 
 #endif /* ldsodefs.h */
diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis
index eaea558..83a667b 100644
--- a/sysdeps/unix/sysv/linux/mips/libc-abis
+++ b/sysdeps/unix/sysv/linux/mips/libc-abis
@@ -16,3 +16,6 @@ UNIQUE
 MIPS_O32_FP64   mips*-*-linux*
 # Absolute (SHN_ABS) symbols working correctly.
 ABSOLUTE
+# GNU-style hash table with translation table.
+MIPS_XHASH
+
