This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Changes with respect to previous patch: - Add IFUNC to mips/libc-abis for ABIVERSION checking - Move global IFUNCs to explicitly relocated GOT region. - Resolve global symbols unconditionally - GENERAL_GOTNO is likely to occur * elf/elf.h (R_MIPS_IRELATIVE): New relocation type. (R_MIPS_NUM): Bump up to 129. (DT_MIPS_GENERAL_GOTNO): New dynamic tags. (DT_MIPS_NUM): Bump to 0x37. * sysdeps/mips/dl-irel.h: New file. (elf_ifunc_invoke): New function. (elf_irel): Likewise. * sysdeps/mips/dl-machine.h Include new dl-irel.h (ELF_MACHINE_BEFORE_RTLD_RELOC): Use DT_MIPS_GENERAL_GOTNO tag, if present, to find the start of the normally relocated GOT. (elf_machine_reloc): Add skip_ifunc to parameter. Add case for R_MIPS_IRELATIVE. Modify REL32 to check for pre-emption if symbol is IFUNC and then perform IFUNC indirection. (elf_machine_rel): Add skip_ifunc to call to elf_machine_reloc(). (elf_machine_rela):Add skip_ifunc to call to elf_machine_reloc(). (RESOLVE_GOTSYM): Add check for STT_GNU_IFUNC. (elf_machine_got_rel): Add check for STT_GNU_IFUNC and IFUNC resolution step. Use DT_MIPS_GENERAL_GOTNO tag, if present, to find the start of the normally relocated GOT. * sysdeps/mips/dl-trampoline.c (__dl_runtime_resolve): Add check for STT_GNU_IFUNC. * sysdeps/unix/sysv/linux/mips/libc-abis (IFUNC): New ABI compatibility level. --- elf/elf.h | 7 ++- sysdeps/mips/dl-irel.h | 63 ++++++++++++++++++++++ sysdeps/mips/dl-machine.h | 93 +++++++++++++++++++++++--------- sysdeps/mips/dl-trampoline.c | 4 ++ sysdeps/unix/sysv/linux/mips/libc-abis | 3 ++ 5 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 sysdeps/mips/dl-irel.h diff --git a/elf/elf.h b/elf/elf.h index fbadda4..960834a 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1653,8 +1653,9 @@ typedef struct #define R_MIPS_GLOB_DAT 51 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 +#define R_MIPS_IRELATIVE 128 /* Keep this the last entry. */ -#define R_MIPS_NUM 128 +#define R_MIPS_NUM 129 /* Legal values for p_type field of Elf32_Phdr. */ @@ -1731,7 +1732,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 + /* Number of explicitly relocated GOT entries */ +#define DT_MIPS_GENERAL_GOTNO 0x70000036 +#define DT_MIPS_NUM 0x37 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ diff --git a/sysdeps/mips/dl-irel.h b/sysdeps/mips/dl-irel.h new file mode 100644 index 0000000..7e1fdc4 --- /dev/null +++ b/sysdeps/mips/dl-irel.h @@ -0,0 +1,63 @@ +/* Machine-dependent ELF indirect relocation inline functions. + MIPS version. + Copyright (C) 2015 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 + <http://www.gnu.org/licenses/>. */ + +#ifndef _DL_IREL_H +#define _DL_IREL_H + +#include <stdio.h> +#include <unistd.h> +#include <sgidefs.h> +#include <link.h> +#include <elf.h> +#include <ldsodefs.h> + +#define ELF_MACHINE_IREL 1 + +static inline ElfW(Addr) +__attribute ((always_inline)) +elf_ifunc_invoke (ElfW(Addr) addr) +{ + /* Print some debugging info if wanted. */ + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0)) + { + ElfW(Addr) t_addr = + ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap)); + GLRO(dl_debug_printf) ("In elf_ifunc_invoke(0x%lx), return(0x%lx)\n", + (unsigned long int)addr, + (unsigned long int)t_addr); + } + + return ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap)); +} + +/* Allow either R_MIPS_RELATIVE or the nop R_MIPS_NONE. */ +static inline void +__attribute ((always_inline)) +elf_irel (const ElfW(Rel) *reloc) +{ + ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset; + const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info); + + if (__builtin_expect (r_type == R_MIPS_IRELATIVE, 1)) + *reloc_addr = elf_ifunc_invoke (*reloc_addr); + else if (r_type) + __libc_fatal ("unexpected reloc type in static binary"); +} + +#endif /* dl-irel.h */ diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h index 8738564..3d2edf1 100644 --- a/sysdeps/mips/dl-machine.h +++ b/sysdeps/mips/dl-machine.h @@ -33,6 +33,7 @@ #include <sysdep.h> #include <sys/asm.h> #include <dl-tls.h> +#include <dl-irel.h> /* The offset of gp from GOT might be system-dependent. It's set by ld. The same value is also */ @@ -200,10 +201,13 @@ do { \ if (__builtin_expect (map->l_addr == 0, 1)) \ break; \ \ - /* 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; \ + if (__glibc_likely (map->l_info[DT_MIPS (GENERAL_GOTNO)] != NULL)) \ + i = map->l_info[DT_MIPS (GENERAL_GOTNO)]->d_un.d_val; \ + else \ + /* 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 displacement to all local got entries. */ \ @@ -493,7 +497,8 @@ auto inline void __attribute__ ((always_inline)) elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info, const ElfW(Sym) *sym, const struct r_found_version *version, - void *reloc_addr, ElfW(Addr) r_addend, int inplace_p) + void *reloc_addr, ElfW(Addr) r_addend, int inplace_p, + int skip_ifunc) { const unsigned long int r_type = ELFW(R_TYPE) (r_info); ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr; @@ -579,21 +584,37 @@ elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info, if ((ElfW(Word))symidx < gotsym) { - /* This wouldn't work for a symbol imported from other - libraries for which there's no GOT entry, but MIPS - requires every symbol referenced in a dynamic - relocation to have a GOT entry in the primary GOT, - so we only get here for locally-defined symbols. - For section symbols, we should *NOT* be adding - sym->st_value (per the definition of the meaning of - S in reloc expressions in the ELF64 MIPS ABI), - since it should have already been added to - reloc_value by the linker, but older versions of - GNU ld didn't add it, and newer versions don't emit - useless relocations to section symbols any more, so - it is safe to keep on adding sym->st_value, even - though it's not ABI compliant. Some day we should - bite the bullet and stop doing this. */ +#ifndef RTLD_BOOTSTRAP + /* Resolve IFUNC symbols with pre-emption. */ + if (sym && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) + == STT_GNU_IFUNC) && !skip_ifunc) + { + struct link_map *rmap = RESOLVE_MAP (&sym, version, r_type); + + if (__glibc_likely (ELFW(ST_TYPE) (sym->st_info) + == STT_GNU_IFUNC)) + reloc_value = elf_ifunc_invoke (sym->st_value + + rmap->l_addr); + else + reloc_value = sym->st_value + rmap->l_addr; + } + else +#endif + /* This wouldn't work for a symbol imported from other + libraries for which there's no GOT entry, but MIPS + requires every symbol referenced in a dynamic + relocation to have a GOT entry in the primary GOT, + so we only get here for locally-defined symbols. + For section symbols, we should *NOT* be adding + sym->st_value (per the definition of the meaning of + S in reloc expressions in the ELF64 MIPS ABI), + since it should have already been added to + reloc_value by the linker, but older versions of + GNU ld didn't add it, and newer versions don't emit + useless relocations to section symbols any more, so + it is safe to keep on adding sym->st_value, even + though it's not ABI compliant. Some day we should + bite the bullet and stop doing this. */ #ifndef RTLD_BOOTSTRAP if (map != &GL(dl_rtld_map)) #endif @@ -698,6 +719,14 @@ elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info, break; } + case R_MIPS_IRELATIVE: + /* The resolver routine is the symbol referenced by this relocation. + To get the address of the function to use at runtime, the resolver + routine is called and its return value is the address of the target + functon which is final relocation value. */ + *addr_field = elf_ifunc_invoke (map->l_addr + *addr_field); + break; + #if _MIPS_SIM == _ABI64 case R_MIPS_64: /* For full compliance with the ELF64 ABI, one must precede the @@ -727,7 +756,8 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc, const ElfW(Sym) *sym, const struct r_found_version *version, void *const reloc_addr, int skip_ifunc) { - elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1); + elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1, + skip_ifunc); } auto inline void @@ -768,7 +798,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, void *const reloc_addr, int skip_ifunc) { elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, - reloc->r_addend, 0); + reloc->r_addend, 0, skip_ifunc); } auto inline void @@ -795,8 +825,16 @@ elf_machine_got_rel (struct link_map *map, int lazy) const struct r_found_version *version __attribute__ ((unused)) \ = vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL; \ struct link_map *sym_map; \ + ElfW(Addr) value = 0; \ sym_map = RESOLVE_MAP (&ref, version, reloc); \ - ref ? sym_map->l_addr + ref->st_value : 0; \ + if (__glibc_likely(ref != NULL)) \ + { \ + value = sym_map->l_addr + ref->st_value; \ + if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) \ + == STT_GNU_IFUNC)) \ + value = elf_ifunc_invoke (value); \ + } \ + value; \ }) if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) @@ -810,9 +848,12 @@ elf_machine_got_rel (struct link_map *map, int lazy) /* The dynamic linker's local got entries have already been relocated. */ if (map != &GL(dl_rtld_map)) { - /* 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; + if (__glibc_likely(map->l_info[DT_MIPS (GENERAL_GOTNO)] != NULL)) + i = map->l_info[DT_MIPS (GENERAL_GOTNO)]->d_un.d_val; + else + /* 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; /* Add the run-time displacement to all local got entries if needed. */ diff --git a/sysdeps/mips/dl-trampoline.c b/sysdeps/mips/dl-trampoline.c index 25b1709..d5f8891 100644 --- a/sysdeps/mips/dl-trampoline.c +++ b/sysdeps/mips/dl-trampoline.c @@ -193,6 +193,10 @@ __dl_runtime_resolve (ElfW(Word) sym_index, /* Currently value contains the base load address of the object that defines sym. Now add in the symbol offset. */ value = (sym ? sym_map->l_addr + sym->st_value : 0); + if (sym != NULL + && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) + == STT_GNU_IFUNC, 0)) + value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value)); } else /* We already found the symbol. The module (and therefore its load diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis index 14ff603..0644720 100644 --- a/sysdeps/unix/sysv/linux/mips/libc-abis +++ b/sysdeps/unix/sysv/linux/mips/libc-abis @@ -14,3 +14,6 @@ UNIQUE # # MIPS O32 FP64 MIPS_O32_FP64 mips*-*-linux* +# +# MIPS IFUNC +IFUNC mips*-*-linux* -- 1.7.9.5
Attachment:
Spec.txt
Description: Text document
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |