From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28920 invoked by alias); 17 Aug 2013 00:31:20 -0000 Mailing-List: contact libc-ports-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: libc-ports-owner@sourceware.org Received: (qmail 28905 invoked by uid 89); 17 Aug 2013 00:31:20 -0000 X-Spam-SWARE-Status: No, score=-3.0 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD autolearn=ham version=3.3.2 Received: from multi.imgtec.com (HELO multi.imgtec.com) (194.200.65.239) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Sat, 17 Aug 2013 00:31:18 +0000 From: Jack Carter To: "libc-ports@sourceware.org" Subject: [RFC][PATCH] MIPS ifunc for glibc Date: Sat, 17 Aug 2013 00:31:00 -0000 Message-ID: <4CEFBC1BE64A8048869F799EF2D2EEEE01AAE1FA@BADAG02.ba.imgtec.org> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-SEF-Processed: 7_3_0_01192__2013_08_17_01_31_06 X-SW-Source: 2013-08/txt/msg00007.txt.bz2 This is the initial MIPS ifunc patch for glibc. This patch should be applied in conjunction with the binutils patch. Note: This patch is for initial code review and has no test cases included. They will be forth coming with submission for commit. This is targeting o32. Patches for 64 bit, n32, MicroMips, Mips16, and possibly vxworks will follow this patch. I have also not yet implemented ifunc with local, hidden, or protected symbol status. Relocations using R_MIPS_IRELATIVE or referencting a symbol of type STT_GNU_IFUNC have their affective address produced by executing the function pointed by either the R_MIPS_IRELATIVE target or the STT_GNU_IFUNC target. The resultant address is the final function effective address that= =20 will be used for the duration of the program execution. *************************************** ./ChangeLog 2013-08-16 Jack Carter * elf/elf.h: Define for R_MIPS_IRELATIVE and bump R_MIPS_NUM up to 129. ports/ChangeLog 2013-08-16 Jack Carter * sysdeps/mips/dl-irel.h: New file. (elf_ifunc_invoke): Do the indirect reference. (elf_irel): Call elf_ifunc_invoke() for acceptable relocations. * sysdeps/mips/dl-machine.h:=20 Include new dl-irel.h. (ELF_MACHINE_BEFORE_RTLD_RELOC): Add check for STT_GNU_IFUNC. (elf_machine_reloc): Add skip_ifunc to parameter. Add case for R_MIPS_IRELATIVE. (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. * sysdeps/mips/dl-trampoline.c:=20 (__dl_runtime_resolve): Add check for STT_GNU_IFUNC. diff --git a/elf/elf.h b/elf/elf.h index f372271..78c347b 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1625,8 +1625,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 =20 /* Legal values for p_type field of Elf32_Phdr. */ =20 diff --git a/ports/sysdeps/mips/dl-irel.h b/ports/sysdeps/mips/dl-irel.h new file mode 100644 index 0000000..10acca8 --- /dev/null +++ b/ports/sysdeps/mips/dl-irel.h @@ -0,0 +1,62 @@ +/* Machine-dependent ELF indirect relocation inline functions. + MIPS version. + Copyright (C) 2009-2013 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 + . */ + +#ifndef _DL_IREL_H +#define _DL_IREL_H + +#include +#include +#include +#include +#include +#include + +#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 =3D + ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap)); + GLRO(dl_debug_printf) ("In elf_ifunc_invoke(0x%x), return(0x%x)\n", + addr,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 Elf32_Rel *reloc) +{ + ElfW(Addr) *const reloc_addr =3D (void *) reloc->r_offset; + const unsigned long int r_type =3D ELFW(R_TYPE) (reloc->r_info); + + if (__builtin_expect (r_type =3D=3D R_MIPS_IRELATIVE, 1)) + *reloc_addr =3D elf_ifunc_invoke (*reloc_addr); + else if (r_type) + __libc_fatal ("unexpected reloc type in static binary\n"); +} + +#endif /* dl-irel.h */ diff --git a/ports/sysdeps/mips/dl-machine.h b/ports/sysdeps/mips/dl-machin= e.h index dae938f..9293eb3 100644 --- a/ports/sysdeps/mips/dl-machine.h +++ b/ports/sysdeps/mips/dl-machine.h @@ -32,6 +32,7 @@ #include #include #include +#include =20 /* The offset of gp from GOT might be system-dependent. It's set by ld. The same value is also */ @@ -190,6 +191,8 @@ do { \ else if (ELFW(ST_TYPE) (sym->st_info) =3D=3D STT_FUNC \ && *got !=3D sym->st_value) \ *got +=3D map->l_addr; \ + else if (ELFW(ST_TYPE) (sym->st_info) =3D=3D STT_GNU_IFUNC) \ + *got =3D elf_ifunc_invoke(sym->st_value); \ else if (ELFW(ST_TYPE) (sym->st_info) =3D=3D STT_SECTION) \ { \ if (sym->st_other =3D=3D 0) \ @@ -437,7 +440,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 =3D ELFW(R_TYPE) (r_info); ElfW(Addr) *addr_field =3D (ElfW(Addr) *) reloc_addr; @@ -642,6 +646,21 @@ elf_machine_reloc (struct link_map *map, ElfW(Addr) r_= info, break; } =20 + case R_MIPS_IRELATIVE: + { + ElfW(Addr) value; + + /* The address for the got entry storing the address for the */ + /* ifunc routine is in this relocation. To get the address of */ + /* the function to use on this machine the ifunc routine is run */ + /* and its return value is the address which is then put back */ + /* into the got entry. */ + value =3D map->l_addr + *addr_field; + value =3D ((ElfW(Addr) (*) (void)) value) (); + *addr_field =3D value; + break; + } + #if _MIPS_SIM =3D=3D _ABI64 case R_MIPS_64: /* For full compliance with the ELF64 ABI, one must precede the @@ -671,7 +690,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,=20 + skip_ifunc); } =20 auto inline void @@ -712,7 +732,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); } =20 auto inline void @@ -739,8 +759,15 @@ elf_machine_got_rel (struct link_map *map, int lazy) const struct r_found_version *version __attribute__ ((unused)) \ =3D vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL; \ struct link_map *sym_map; \ + ElfW(Addr) value; \ sym_map =3D RESOLVE_MAP (&ref, version, reloc); \ - ref ? sym_map->l_addr + ref->st_value : 0; \ + if (ref) \ + { \ + value =3D sym_map->l_addr + ref->st_value; \ + if (ELFW(ST_TYPE) (ref->st_info) =3D=3D STT_GNU_IFUNC) \ + value =3D ((ElfW(Addr) (*) (void)) value) (); \ + } \ + ref ? value : 0; \ }) =20 if (map->l_info[VERSYMIDX (DT_VERSYM)] !=3D NULL) @@ -810,6 +837,13 @@ elf_machine_got_rel (struct link_map *map, int lazy) if (sym->st_other =3D=3D 0) *got +=3D map->l_addr; } + else if (ELFW(ST_TYPE) (sym->st_info) =3D=3D STT_GNU_IFUNC) + { + ElfW(Addr) value; + value =3D map->l_addr + *got; + value =3D ((ElfW(Addr) (*) (void)) value) (); + *got =3D value; + } else *got =3D RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32); =20 diff --git a/ports/sysdeps/mips/dl-trampoline.c b/ports/sysdeps/mips/dl-tra= mpoline.c index 605e44e..661dfc4 100644 --- a/ports/sysdeps/mips/dl-trampoline.c +++ b/ports/sysdeps/mips/dl-trampoline.c @@ -193,6 +193,9 @@ __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 =3D (sym ? sym_map->l_addr + sym->st_value : 0); + if (sym !=3D NULL + && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) =3D=3D STT_GNU= _IFUNC, 0)) + value =3D elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value)); } else /* We already found the symbol. The module (and therefore its load