|
|
b1dca6 |
commit 23c1c256ae7b0f010d0fcaff60682b620887b164
|
|
|
b1dca6 |
Author: Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
|
|
|
b1dca6 |
Date: Thu Aug 29 20:11:42 2019 +0000
|
|
|
b1dca6 |
|
|
|
b1dca6 |
MIPS support for GNU hash
|
|
|
b1dca6 |
|
|
|
b1dca6 |
This patch is a reimplementation of [1], which was submitted back in
|
|
|
b1dca6 |
2015. Copyright issue has been sorted [2] last year. It proposed a new
|
|
|
b1dca6 |
section (.gnu.xhash) and related dynamic tag (GT_GNU_XHASH). The new
|
|
|
b1dca6 |
section would be virtually identical to the existing .gnu.hash except
|
|
|
b1dca6 |
for the translation table (xlat) which would contain correct MIPS
|
|
|
b1dca6 |
.dynsym indexes corresponding to the hashvals in chains. This is because
|
|
|
b1dca6 |
MIPS ABI imposes a different ordering of the dynsyms than the one
|
|
|
b1dca6 |
expected by the .gnu.hash section. Another addition would be a leading
|
|
|
b1dca6 |
word at the beggining of the section, which would contain the number of
|
|
|
b1dca6 |
entries in the translation table.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
In this patch, the new section name and dynamic tag are changed to
|
|
|
b1dca6 |
reflect the fact that the section should be treated as MIPS specific
|
|
|
b1dca6 |
(.MIPS.xhash and DT_MIPS_XHASH).
|
|
|
b1dca6 |
|
|
|
b1dca6 |
This patch addresses the alignment issue reported in [3] which is caused
|
|
|
b1dca6 |
by the leading word of the .MIPS.xhash section. Leading word is now
|
|
|
b1dca6 |
removed in the corresponding binutils patch, and the number of entries
|
|
|
b1dca6 |
in the translation table is computed using DT_MIPS_SYMTABNO dynamic tag.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
Since the MIPS specific dl-lookup.c file was removed following the
|
|
|
b1dca6 |
initial patch submission, I opted for the definition of three new macros
|
|
|
b1dca6 |
in the generic ldsodefs.h. ELF_MACHINE_GNU_HASH_ADDRIDX defines the
|
|
|
b1dca6 |
index of the dynamic tag in the l_info array. ELF_MACHINE_HASH_SYMIDX is
|
|
|
b1dca6 |
used to calculate the index of a symbol in GNU hash. On MIPS, it is
|
|
|
b1dca6 |
defined to look up the symbol index in the translation table.
|
|
|
b1dca6 |
ELF_MACHINE_XHASH_SETUP is defined for MIPS only. It initializes the
|
|
|
b1dca6 |
.MIPS.xhash pointer in the link_map_machine struct.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
The other major change is bumping the highest EI_ABIVERSION value for
|
|
|
b1dca6 |
MIPS to suggest that the dynamic linker now supports GNU hash.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
The patch was tested by running the glibc testsuite for the three MIPS
|
|
|
b1dca6 |
ABIs (o32, n32 and n64) and for x86_64-linux-gnu.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
[1] https://sourceware.org/ml/binutils/2015-10/msg00057.html
|
|
|
b1dca6 |
[2] https://sourceware.org/ml/binutils/2018-03/msg00025.html
|
|
|
b1dca6 |
[3] https://sourceware.org/ml/binutils/2016-01/msg00006.html
|
|
|
b1dca6 |
|
|
|
b1dca6 |
* elf/dl-addr.c (determine_info): Calculate the symbol index
|
|
|
b1dca6 |
using the newly defined ELF_MACHINE_HASH_SYMIDX macro.
|
|
|
b1dca6 |
* elf/dl-lookup.c (do_lookup_x): Ditto.
|
|
|
b1dca6 |
(_dl_setup_hash): Initialize MIPS xhash translation table.
|
|
|
b1dca6 |
* elf/elf.h (SHT_MIPS_XHASH): New define.
|
|
|
b1dca6 |
(DT_MIPS_XHASH): New define.
|
|
|
b1dca6 |
* sysdeps/generic/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New
|
|
|
b1dca6 |
define.
|
|
|
b1dca6 |
(ELF_MACHINE_HASH_SYMIDX): Ditto.
|
|
|
b1dca6 |
(ELF_MACHINE_XHASH_SETUP): Ditto.
|
|
|
b1dca6 |
* sysdeps/mips/ldsodefs.h (ELF_MACHINE_GNU_HASH_ADDRIDX): New
|
|
|
b1dca6 |
define.
|
|
|
b1dca6 |
(ELF_MACHINE_HASH_SYMIDX): Ditto.
|
|
|
b1dca6 |
(ELF_MACHINE_XHASH_SETUP): Ditto.
|
|
|
b1dca6 |
* sysdeps/mips/linkmap.h (struct link_map_machine): New member.
|
|
|
b1dca6 |
* sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increment valid ABI
|
|
|
b1dca6 |
version.
|
|
|
b1dca6 |
* sysdeps/unix/sysv/linux/mips/libc-abis: New ABI version.
|
|
|
b1dca6 |
|
|
|
b1dca6 |
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
|
|
|
b1dca6 |
index e6c7d020945c51d2..b146fed09a46ff76 100644
|
|
|
b1dca6 |
--- a/elf/dl-addr.c
|
|
|
b1dca6 |
+++ b/elf/dl-addr.c
|
|
|
b1dca6 |
@@ -42,7 +42,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
|
|
|
b1dca6 |
ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
const ElfW(Sym) *matchsym = NULL;
|
|
|
b1dca6 |
- if (match->l_info[ADDRIDX (DT_GNU_HASH)] != NULL)
|
|
|
b1dca6 |
+ if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
/* We look at all symbol table entries referenced by the hash
|
|
|
b1dca6 |
table. */
|
|
|
b1dca6 |
@@ -57,6 +57,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
/* The hash table never references local symbols so
|
|
|
b1dca6 |
we can omit that test here. */
|
|
|
b1dca6 |
+ symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr);
|
|
|
b1dca6 |
if ((symtab[symndx].st_shndx != SHN_UNDEF
|
|
|
b1dca6 |
|| symtab[symndx].st_value != 0)
|
|
|
b1dca6 |
&& symtab[symndx].st_shndx != SHN_ABS
|
|
|
b1dca6 |
@@ -65,8 +66,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
|
|
|
b1dca6 |
matchsym, addr)
|
|
|
b1dca6 |
&& symtab[symndx].st_name < strtabsize)
|
|
|
b1dca6 |
matchsym = (ElfW(Sym) *) &symtab[symndx];
|
|
|
b1dca6 |
-
|
|
|
b1dca6 |
- ++symndx;
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
while ((*hasharr++ & 1u) == 0);
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
|
|
b1dca6 |
index 01724a54f8840f9f..42fdaed99296137f 100644
|
|
|
b1dca6 |
--- a/elf/dl-lookup.c
|
|
|
b1dca6 |
+++ b/elf/dl-lookup.c
|
|
|
b1dca6 |
@@ -432,7 +432,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
|
|
|
b1dca6 |
do
|
|
|
b1dca6 |
if (((*hasharr ^ new_hash) >> 1) == 0)
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
- symidx = hasharr - map->l_gnu_chain_zero;
|
|
|
b1dca6 |
+ symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
|
|
|
b1dca6 |
sym = check_match (undef_name, ref, version, flags,
|
|
|
b1dca6 |
type_class, &symtab[symidx], symidx,
|
|
|
b1dca6 |
strtab, map, &versioned_sym,
|
|
|
b1dca6 |
@@ -961,10 +961,10 @@ _dl_setup_hash (struct link_map *map)
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
Elf_Symndx *hash;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
- if (__glibc_likely (map->l_info[ADDRIDX (DT_GNU_HASH)] != NULL))
|
|
|
b1dca6 |
+ if (__glibc_likely (map->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL))
|
|
|
b1dca6 |
{
|
|
|
b1dca6 |
Elf32_Word *hash32
|
|
|
b1dca6 |
- = (void *) D_PTR (map, l_info[ADDRIDX (DT_GNU_HASH)]);
|
|
|
b1dca6 |
+ = (void *) D_PTR (map, l_info[ELF_MACHINE_GNU_HASH_ADDRIDX]);
|
|
|
b1dca6 |
map->l_nbuckets = *hash32++;
|
|
|
b1dca6 |
Elf32_Word symbias = *hash32++;
|
|
|
b1dca6 |
Elf32_Word bitmask_nwords = *hash32++;
|
|
|
b1dca6 |
@@ -979,6 +979,10 @@ _dl_setup_hash (struct link_map *map)
|
|
|
b1dca6 |
map->l_gnu_buckets = hash32;
|
|
|
b1dca6 |
hash32 += map->l_nbuckets;
|
|
|
b1dca6 |
map->l_gnu_chain_zero = hash32 - symbias;
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+ /* Initialize MIPS xhash translation table. */
|
|
|
b1dca6 |
+ ELF_MACHINE_XHASH_SETUP (hash32, symbias, map);
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
return;
|
|
|
b1dca6 |
}
|
|
|
b1dca6 |
|
|
|
b1dca6 |
diff --git a/elf/elf.h b/elf/elf.h
|
|
|
b1dca6 |
index 74f7f479ce817040..d6506ea1c7160dea 100644
|
|
|
b1dca6 |
--- a/elf/elf.h
|
|
|
b1dca6 |
+++ b/elf/elf.h
|
|
|
b1dca6 |
@@ -1698,6 +1698,7 @@ typedef struct
|
|
|
b1dca6 |
#define SHT_MIPS_EH_REGION 0x70000027
|
|
|
b1dca6 |
#define SHT_MIPS_XLATE_OLD 0x70000028
|
|
|
b1dca6 |
#define SHT_MIPS_PDR_EXCEPTION 0x70000029
|
|
|
b1dca6 |
+#define SHT_MIPS_XHASH 0x7000002b
|
|
|
b1dca6 |
|
|
|
b1dca6 |
/* Legal values for sh_flags field of Elf32_Shdr. */
|
|
|
b1dca6 |
|
|
|
b1dca6 |
@@ -1945,7 +1946,9 @@ typedef struct
|
|
|
b1dca6 |
in a PIE as it stores a relative offset from the address of the tag
|
|
|
b1dca6 |
rather than an absolute address. */
|
|
|
b1dca6 |
#define DT_MIPS_RLD_MAP_REL 0x70000035
|
|
|
b1dca6 |
-#define DT_MIPS_NUM 0x36
|
|
|
b1dca6 |
+/* GNU-style hash table with xlat. */
|
|
|
b1dca6 |
+#define DT_MIPS_XHASH 0x70000036
|
|
|
b1dca6 |
+#define DT_MIPS_NUM 0x37
|
|
|
b1dca6 |
|
|
|
b1dca6 |
/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
|
|
|
b1dca6 |
|
|
|
b1dca6 |
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
|
|
b1dca6 |
index f0185ce0d16c0f69..3bdbdd6e67dacc85 100644
|
|
|
b1dca6 |
--- a/sysdeps/generic/ldsodefs.h
|
|
|
b1dca6 |
+++ b/sysdeps/generic/ldsodefs.h
|
|
|
b1dca6 |
@@ -47,6 +47,23 @@ __BEGIN_DECLS
|
|
|
b1dca6 |
#define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
|
|
b1dca6 |
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
|
|
|
b1dca6 |
|
|
|
b1dca6 |
+/* Type of GNU hash which the machine uses. */
|
|
|
b1dca6 |
+#ifndef ELF_MACHINE_GNU_HASH_ADDRIDX
|
|
|
b1dca6 |
+# define ELF_MACHINE_GNU_HASH_ADDRIDX ADDRIDX (DT_GNU_HASH)
|
|
|
b1dca6 |
+#endif
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+/* Calculate the index of a symbol in GNU hash. */
|
|
|
b1dca6 |
+#ifndef ELF_MACHINE_HASH_SYMIDX
|
|
|
b1dca6 |
+# define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
|
|
|
b1dca6 |
+ ((hasharr) - (map)->l_gnu_chain_zero)
|
|
|
b1dca6 |
+#endif
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+/* Setup MIPS xhash. Defined only for MIPS. */
|
|
|
b1dca6 |
+#ifndef ELF_MACHINE_XHASH_SETUP
|
|
|
b1dca6 |
+# define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \
|
|
|
b1dca6 |
+ ((void) (hash32), (void) (symbias), (void) (map))
|
|
|
b1dca6 |
+#endif
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
/* We use this macro to refer to ELF types independent of the native wordsize.
|
|
|
b1dca6 |
`ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
|
|
|
b1dca6 |
#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
|
|
|
b1dca6 |
diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
|
|
|
b1dca6 |
index c6e5ce7e660325c1..35043b7c6d416c50 100644
|
|
|
b1dca6 |
--- a/sysdeps/mips/ldsodefs.h
|
|
|
b1dca6 |
+++ b/sysdeps/mips/ldsodefs.h
|
|
|
b1dca6 |
@@ -26,6 +26,21 @@ struct La_mips_32_retval;
|
|
|
b1dca6 |
struct La_mips_64_regs;
|
|
|
b1dca6 |
struct La_mips_64_retval;
|
|
|
b1dca6 |
|
|
|
b1dca6 |
+#define ELF_MACHINE_GNU_HASH_ADDRIDX (DT_MIPS_XHASH - DT_LOPROC + DT_NUM)
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+/* Calculate the index of a symbol in MIPS xhash. */
|
|
|
b1dca6 |
+#define ELF_MACHINE_HASH_SYMIDX(map, hasharr) \
|
|
|
b1dca6 |
+ ((map)->l_mach.mips_xlat_zero[(hasharr) - (map)->l_gnu_chain_zero])
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
+/* Setup MIPS xhash. */
|
|
|
b1dca6 |
+#define ELF_MACHINE_XHASH_SETUP(hash32, symbias, map) \
|
|
|
b1dca6 |
+ do \
|
|
|
b1dca6 |
+ { \
|
|
|
b1dca6 |
+ (hash32) += (map)->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val - (symbias); \
|
|
|
b1dca6 |
+ (map)->l_mach.mips_xlat_zero = (hash32) - (symbias); \
|
|
|
b1dca6 |
+ } \
|
|
|
b1dca6 |
+ while (0)
|
|
|
b1dca6 |
+
|
|
|
b1dca6 |
#define ARCH_PLTENTER_MEMBERS \
|
|
|
b1dca6 |
Elf32_Addr (*mips_o32_gnu_pltenter) (Elf32_Sym *, unsigned int, \
|
|
|
b1dca6 |
uintptr_t *, uintptr_t *, \
|
|
|
b1dca6 |
diff --git a/sysdeps/mips/linkmap.h b/sysdeps/mips/linkmap.h
|
|
|
b1dca6 |
index 1fb9678a6d1625fd..1e640c3ba9bd18e4 100644
|
|
|
b1dca6 |
--- a/sysdeps/mips/linkmap.h
|
|
|
b1dca6 |
+++ b/sysdeps/mips/linkmap.h
|
|
|
b1dca6 |
@@ -3,4 +3,5 @@ struct link_map_machine
|
|
|
b1dca6 |
ElfW(Addr) plt; /* Address of .plt */
|
|
|
b1dca6 |
ElfW(Word) fpabi; /* FP ABI of the object */
|
|
|
b1dca6 |
unsigned int odd_spreg; /* Does the object require odd_spreg support? */
|
|
|
b1dca6 |
+ const Elf32_Word *mips_xlat_zero; /* .MIPS.xhash */
|
|
|
b1dca6 |
};
|
|
|
b1dca6 |
diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
|
|
|
b1dca6 |
index d2912cadabfd6877..03f3e12f202a0563 100644
|
|
|
b1dca6 |
--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h
|
|
|
b1dca6 |
+++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
|
|
|
b1dca6 |
@@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map);
|
|
|
b1dca6 |
#undef VALID_ELF_ABIVERSION
|
|
|
b1dca6 |
#define VALID_ELF_ABIVERSION(osabi,ver) \
|
|
|
b1dca6 |
(ver == 0 \
|
|
|
b1dca6 |
- || (osabi == ELFOSABI_SYSV && ver < 5) \
|
|
|
b1dca6 |
+ || (osabi == ELFOSABI_SYSV && ver < 6) \
|
|
|
b1dca6 |
|| (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
|
|
|
b1dca6 |
|
|
|
b1dca6 |
#endif /* ldsodefs.h */
|
|
|
b1dca6 |
diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis
|
|
|
b1dca6 |
index eaea558720f42a48..c0b67dae3ece1511 100644
|
|
|
b1dca6 |
--- a/sysdeps/unix/sysv/linux/mips/libc-abis
|
|
|
b1dca6 |
+++ b/sysdeps/unix/sysv/linux/mips/libc-abis
|
|
|
b1dca6 |
@@ -16,3 +16,5 @@ UNIQUE
|
|
|
b1dca6 |
MIPS_O32_FP64 mips*-*-linux*
|
|
|
b1dca6 |
# Absolute (SHN_ABS) symbols working correctly.
|
|
|
b1dca6 |
ABSOLUTE
|
|
|
b1dca6 |
+# GNU-style hash table with translation table.
|
|
|
b1dca6 |
+MIPS_XHASH
|