mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-08 14:20:07 +00:00
Sparc STT_GNU_IFUNC support
This commit is contained in:
parent
57e065ae1e
commit
311927f1bd
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
|||||||
|
2010-02-05 David S. Miller <davem@davemloft.net>
|
||||||
|
|
||||||
|
* elf/elf.h (R_SPARC_JMP_IREL, R_SPARC_IRELATIVE): Define.
|
||||||
|
* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela): Handle new
|
||||||
|
ifunc relocs.
|
||||||
|
(elf_machine_lazy_rel): Likewise.
|
||||||
|
(sparc_fixup_plt): Pull out to...
|
||||||
|
* sysdeps/sparc/sparc32/dl-plt.h: ...here.
|
||||||
|
* sysdeps/sparc/sparc32/dl-irel.h: New file.
|
||||||
|
* sysdeps/sparc/sparc64/dl-machine.h (elf_machine_rela): Handle new
|
||||||
|
ifunc relocs.
|
||||||
|
(elf_machine_lazy_rel): Likewise.
|
||||||
|
(sparc64_fixup_plt): Pull out to...
|
||||||
|
* sysdeps/sparc/sparc64/dl-plt.h: ...here.
|
||||||
|
* sysdeps/sparc/sparc64/dl-irel.h: New file.
|
||||||
|
|
||||||
2010-02-09 Maxim Kuvyrkov <maxim@codesourcery.com>
|
2010-02-09 Maxim Kuvyrkov <maxim@codesourcery.com>
|
||||||
|
|
||||||
* elf/elf.h: Define m68k TLS relocations.
|
* elf/elf.h: Define m68k TLS relocations.
|
||||||
|
@ -1324,6 +1324,8 @@ typedef struct
|
|||||||
#define R_SPARC_H34 85
|
#define R_SPARC_H34 85
|
||||||
#define R_SPARC_SIZE32 86
|
#define R_SPARC_SIZE32 86
|
||||||
#define R_SPARC_SIZE64 87
|
#define R_SPARC_SIZE64 87
|
||||||
|
#define R_SPARC_JMP_IREL 248
|
||||||
|
#define R_SPARC_IRELATIVE 249
|
||||||
#define R_SPARC_GNU_VTINHERIT 250
|
#define R_SPARC_GNU_VTINHERIT 250
|
||||||
#define R_SPARC_GNU_VTENTRY 251
|
#define R_SPARC_GNU_VTENTRY 251
|
||||||
#define R_SPARC_REV32 252
|
#define R_SPARC_REV32 252
|
||||||
|
55
sysdeps/sparc/sparc32/dl-irel.h
Normal file
55
sysdeps/sparc/sparc32/dl-irel.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Machine-dependent ELF indirect relocation inline functions.
|
||||||
|
SPARC 32-bit version.
|
||||||
|
Copyright (C) 2010 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, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _DL_IREL_H
|
||||||
|
#define _DL_IREL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dl-plt.h>
|
||||||
|
|
||||||
|
#define ELF_MACHINE_IRELA 1
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__attribute ((always_inline))
|
||||||
|
elf_irela (const Elf32_Rela *reloc)
|
||||||
|
{
|
||||||
|
unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_SPARC_IRELATIVE, 1))
|
||||||
|
{
|
||||||
|
Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
Elf32_Addr value = ((Elf32_Addr (*) (void)) reloc->r_addend) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
|
else if (__builtin_expect (r_type == R_SPARC_JMP_IREL, 1))
|
||||||
|
{
|
||||||
|
Elf32_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
Elf32_Addr value = ((Elf32_Addr (*) (void)) reloc->r_addend) ();
|
||||||
|
|
||||||
|
sparc_fixup_plt (reloc, reloc_addr, value, 0, 1);
|
||||||
|
}
|
||||||
|
else if (r_type == R_SPARC_NONE)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
__libc_fatal ("unexpected reloc type in static binary");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* dl-irel.h */
|
@ -1,5 +1,5 @@
|
|||||||
/* Machine-dependent ELF dynamic relocation inline functions. SPARC version.
|
/* Machine-dependent ELF dynamic relocation inline functions. SPARC version.
|
||||||
Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
|
Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
@ -27,20 +27,13 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <ldsodefs.h>
|
#include <ldsodefs.h>
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
|
#include <dl-plt.h>
|
||||||
|
|
||||||
#ifndef VALIDX
|
#ifndef VALIDX
|
||||||
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||||
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
|
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Some SPARC opcodes we need to use for self-modifying code. */
|
|
||||||
#define OPCODE_NOP 0x01000000 /* nop */
|
|
||||||
#define OPCODE_CALL 0x40000000 /* call ?; add PC-rel word address */
|
|
||||||
#define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
|
|
||||||
#define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
|
|
||||||
#define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
|
|
||||||
#define OPCODE_BA 0x30800000 /* b,a ?; add PC-rel word address */
|
|
||||||
|
|
||||||
/* Return nonzero iff ELF header is compatible with the running host. */
|
/* Return nonzero iff ELF header is compatible with the running host. */
|
||||||
static inline int
|
static inline int
|
||||||
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
|
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
|
||||||
@ -312,41 +305,6 @@ _dl_start_user:\n\
|
|||||||
.size _dl_start_user, . - _dl_start_user\n\
|
.size _dl_start_user, . - _dl_start_user\n\
|
||||||
.previous");
|
.previous");
|
||||||
|
|
||||||
static inline __attribute__ ((always_inline)) Elf32_Addr
|
|
||||||
sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
|
|
||||||
Elf32_Addr value, int t, int do_flush)
|
|
||||||
{
|
|
||||||
Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
|
|
||||||
|
|
||||||
if (0 && disp >= -0x800000 && disp < 0x800000)
|
|
||||||
{
|
|
||||||
/* Don't need to worry about thread safety. We're writing just one
|
|
||||||
instruction. */
|
|
||||||
|
|
||||||
reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
|
|
||||||
if (do_flush)
|
|
||||||
__asm __volatile ("flush %0" : : "r"(reloc_addr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* For thread safety, write the instructions from the bottom and
|
|
||||||
flush before we overwrite the critical "b,a". This of course
|
|
||||||
need not be done during bootstrapping, since there are no threads.
|
|
||||||
But we also can't tell if we _can_ use flush, so don't. */
|
|
||||||
|
|
||||||
reloc_addr += t;
|
|
||||||
reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
|
|
||||||
if (do_flush)
|
|
||||||
__asm __volatile ("flush %0+4" : : "r"(reloc_addr));
|
|
||||||
|
|
||||||
reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
|
|
||||||
if (do_flush)
|
|
||||||
__asm __volatile ("flush %0" : : "r"(reloc_addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Elf32_Addr
|
static inline Elf32_Addr
|
||||||
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||||
const Elf32_Rela *reloc,
|
const Elf32_Rela *reloc,
|
||||||
@ -433,6 +391,13 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
|||||||
|
|
||||||
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
|
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
|
||||||
|
|
||||||
|
if (sym != NULL
|
||||||
|
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
|
||||||
|
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
|
||||||
|
{
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
}
|
||||||
|
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
|
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
|
||||||
@ -460,6 +425,13 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
|||||||
case R_SPARC_32:
|
case R_SPARC_32:
|
||||||
*reloc_addr = value;
|
*reloc_addr = value;
|
||||||
break;
|
break;
|
||||||
|
case R_SPARC_IRELATIVE:
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
break;
|
||||||
|
case R_SPARC_JMP_IREL:
|
||||||
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
|
/* Fall thru */
|
||||||
case R_SPARC_JMP_SLOT:
|
case R_SPARC_JMP_SLOT:
|
||||||
{
|
{
|
||||||
#if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
|
#if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
|
||||||
@ -578,16 +550,21 @@ __attribute__ ((always_inline))
|
|||||||
elf_machine_lazy_rel (struct link_map *map,
|
elf_machine_lazy_rel (struct link_map *map,
|
||||||
Elf32_Addr l_addr, const Elf32_Rela *reloc)
|
Elf32_Addr l_addr, const Elf32_Rela *reloc)
|
||||||
{
|
{
|
||||||
switch (ELF32_R_TYPE (reloc->r_info))
|
Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
|
||||||
|
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_SPARC_JMP_SLOT, 1))
|
||||||
|
;
|
||||||
|
else if (r_type == R_SPARC_JMP_IREL)
|
||||||
{
|
{
|
||||||
case R_SPARC_NONE:
|
Elf32_Addr value = map->l_addr + reloc->r_addend;
|
||||||
break;
|
value = ((Elf32_Addr (*) (void)) value) ();
|
||||||
case R_SPARC_JMP_SLOT:
|
sparc_fixup_plt (reloc, reloc_addr, value, 0, 1);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (r_type == R_SPARC_NONE)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
_dl_reloc_bad_type (map, r_type, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* RESOLVE_MAP */
|
#endif /* RESOLVE_MAP */
|
||||||
|
62
sysdeps/sparc/sparc32/dl-plt.h
Normal file
62
sysdeps/sparc/sparc32/dl-plt.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* PLT fixups. Sparc 32-bit version.
|
||||||
|
Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
|
||||||
|
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, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
/* Some SPARC opcodes we need to use for self-modifying code. */
|
||||||
|
#define OPCODE_NOP 0x01000000 /* nop */
|
||||||
|
#define OPCODE_CALL 0x40000000 /* call ?; add PC-rel word address */
|
||||||
|
#define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
|
||||||
|
#define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
|
||||||
|
#define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
|
||||||
|
#define OPCODE_BA 0x30800000 /* b,a ?; add PC-rel word address */
|
||||||
|
|
||||||
|
static inline __attribute__ ((always_inline)) Elf32_Addr
|
||||||
|
sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
|
||||||
|
Elf32_Addr value, int t, int do_flush)
|
||||||
|
{
|
||||||
|
Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
|
||||||
|
|
||||||
|
if (0 && disp >= -0x800000 && disp < 0x800000)
|
||||||
|
{
|
||||||
|
/* Don't need to worry about thread safety. We're writing just one
|
||||||
|
instruction. */
|
||||||
|
|
||||||
|
reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
|
||||||
|
if (do_flush)
|
||||||
|
__asm __volatile ("flush %0" : : "r"(reloc_addr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* For thread safety, write the instructions from the bottom and
|
||||||
|
flush before we overwrite the critical "b,a". This of course
|
||||||
|
need not be done during bootstrapping, since there are no threads.
|
||||||
|
But we also can't tell if we _can_ use flush, so don't. */
|
||||||
|
|
||||||
|
reloc_addr += t;
|
||||||
|
reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
|
||||||
|
if (do_flush)
|
||||||
|
__asm __volatile ("flush %0+4" : : "r"(reloc_addr));
|
||||||
|
|
||||||
|
reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
|
||||||
|
if (do_flush)
|
||||||
|
__asm __volatile ("flush %0" : : "r"(reloc_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
58
sysdeps/sparc/sparc64/dl-irel.h
Normal file
58
sysdeps/sparc/sparc64/dl-irel.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* Machine-dependent ELF indirect relocation inline functions.
|
||||||
|
SPARC 64-bit version.
|
||||||
|
Copyright (C) 2010 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, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#ifndef _DL_IREL_H
|
||||||
|
#define _DL_IREL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dl-plt.h>
|
||||||
|
|
||||||
|
#define ELF_MACHINE_IRELA 1
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__attribute ((always_inline))
|
||||||
|
elf_irela (const Elf64_Rela *reloc)
|
||||||
|
{
|
||||||
|
unsigned int r_type = (reloc->r_info & 0xff);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_SPARC_IRELATIVE, 1))
|
||||||
|
{
|
||||||
|
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
}
|
||||||
|
else if (__builtin_expect (r_type == R_SPARC_JMP_IREL, 1))
|
||||||
|
{
|
||||||
|
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
|
Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
|
||||||
|
struct link_map map = { .l_addr = 0 };
|
||||||
|
|
||||||
|
/* 'high' is always zero, for large PLT entries the linker
|
||||||
|
emits an R_SPARC_IRELATIVE. */
|
||||||
|
sparc64_fixup_plt (&map, reloc, reloc_addr, value, 0, 0);
|
||||||
|
}
|
||||||
|
else if (r_type == R_SPARC_NONE)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
__libc_fatal ("unexpected reloc type in static binary");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* dl-irel.h */
|
@ -1,6 +1,6 @@
|
|||||||
/* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version.
|
/* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version.
|
||||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||||
Free Software Foundation, Inc.
|
2010 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -27,6 +27,7 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <ldsodefs.h>
|
#include <ldsodefs.h>
|
||||||
#include <sysdep.h>
|
#include <sysdep.h>
|
||||||
|
#include <dl-plt.h>
|
||||||
|
|
||||||
#ifndef VALIDX
|
#ifndef VALIDX
|
||||||
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||||
@ -89,132 +90,6 @@ elf_machine_load_address (void)
|
|||||||
return (Elf64_Addr) got - *got + (Elf32_Sword) ((pc[2] - pc[3]) * 4) - 4;
|
return (Elf64_Addr) got - *got + (Elf32_Sword) ((pc[2] - pc[3]) * 4) - 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have 4 cases to handle. And we code different code sequences
|
|
||||||
for each one. I love V9 code models... */
|
|
||||||
static inline void __attribute__ ((always_inline))
|
|
||||||
sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc,
|
|
||||||
Elf64_Addr *reloc_addr, Elf64_Addr value,
|
|
||||||
Elf64_Addr high, int t)
|
|
||||||
{
|
|
||||||
unsigned int *insns = (unsigned int *) reloc_addr;
|
|
||||||
Elf64_Addr plt_vaddr = (Elf64_Addr) reloc_addr;
|
|
||||||
Elf64_Sxword disp = value - plt_vaddr;
|
|
||||||
|
|
||||||
/* Now move plt_vaddr up to the call instruction. */
|
|
||||||
plt_vaddr += ((t + 1) * 4);
|
|
||||||
|
|
||||||
/* PLT entries .PLT32768 and above look always the same. */
|
|
||||||
if (__builtin_expect (high, 0) != 0)
|
|
||||||
{
|
|
||||||
*reloc_addr = value - map->l_addr;
|
|
||||||
}
|
|
||||||
/* Near destination. */
|
|
||||||
else if (disp >= -0x800000 && disp < 0x800000)
|
|
||||||
{
|
|
||||||
/* As this is just one instruction, it is thread safe and so
|
|
||||||
we can avoid the unnecessary sethi FOO, %g1.
|
|
||||||
b,a target */
|
|
||||||
insns[0] = 0x30800000 | ((disp >> 2) & 0x3fffff);
|
|
||||||
__asm __volatile ("flush %0" : : "r" (insns));
|
|
||||||
}
|
|
||||||
/* 32-bit Sparc style, the target is in the lower 32-bits of
|
|
||||||
address space. */
|
|
||||||
else if (insns += t, (value >> 32) == 0)
|
|
||||||
{
|
|
||||||
/* sethi %hi(target), %g1
|
|
||||||
jmpl %g1 + %lo(target), %g0 */
|
|
||||||
|
|
||||||
insns[1] = 0x81c06000 | (value & 0x3ff);
|
|
||||||
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[0] = 0x03000000 | ((unsigned int)(value >> 10));
|
|
||||||
__asm __volatile ("flush %0" : : "r" (insns));
|
|
||||||
}
|
|
||||||
/* We can also get somewhat simple sequences if the distance between
|
|
||||||
the target and the PLT entry is within +/- 2GB. */
|
|
||||||
else if ((plt_vaddr > value
|
|
||||||
&& ((plt_vaddr - value) >> 31) == 0)
|
|
||||||
|| (value > plt_vaddr
|
|
||||||
&& ((value - plt_vaddr) >> 31) == 0))
|
|
||||||
{
|
|
||||||
unsigned int displacement;
|
|
||||||
|
|
||||||
if (plt_vaddr > value)
|
|
||||||
displacement = (0 - (plt_vaddr - value));
|
|
||||||
else
|
|
||||||
displacement = value - plt_vaddr;
|
|
||||||
|
|
||||||
/* mov %o7, %g1
|
|
||||||
call displacement
|
|
||||||
mov %g1, %o7 */
|
|
||||||
|
|
||||||
insns[2] = 0x9e100001;
|
|
||||||
__asm __volatile ("flush %0 + 8" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[1] = 0x40000000 | (displacement >> 2);
|
|
||||||
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[0] = 0x8210000f;
|
|
||||||
__asm __volatile ("flush %0" : : "r" (insns));
|
|
||||||
}
|
|
||||||
/* Worst case, ho hum... */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int high32 = (value >> 32);
|
|
||||||
unsigned int low32 = (unsigned int) value;
|
|
||||||
|
|
||||||
/* ??? Some tricks can be stolen from the sparc64 egcs backend
|
|
||||||
constant formation code I wrote. -DaveM */
|
|
||||||
|
|
||||||
if (__builtin_expect (high32 & 0x3ff, 0))
|
|
||||||
{
|
|
||||||
/* sethi %hh(value), %g1
|
|
||||||
sethi %lm(value), %g5
|
|
||||||
or %g1, %hm(value), %g1
|
|
||||||
or %g5, %lo(value), %g5
|
|
||||||
sllx %g1, 32, %g1
|
|
||||||
jmpl %g1 + %g5, %g0
|
|
||||||
nop */
|
|
||||||
|
|
||||||
insns[5] = 0x81c04005;
|
|
||||||
__asm __volatile ("flush %0 + 20" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[4] = 0x83287020;
|
|
||||||
__asm __volatile ("flush %0 + 16" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[3] = 0x8a116000 | (low32 & 0x3ff);
|
|
||||||
__asm __volatile ("flush %0 + 12" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[2] = 0x82106000 | (high32 & 0x3ff);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* sethi %hh(value), %g1
|
|
||||||
sethi %lm(value), %g5
|
|
||||||
sllx %g1, 32, %g1
|
|
||||||
or %g5, %lo(value), %g5
|
|
||||||
jmpl %g1 + %g5, %g0
|
|
||||||
nop */
|
|
||||||
|
|
||||||
insns[4] = 0x81c04005;
|
|
||||||
__asm __volatile ("flush %0 + 16" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[3] = 0x8a116000 | (low32 & 0x3ff);
|
|
||||||
__asm __volatile ("flush %0 + 12" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[2] = 0x83287020;
|
|
||||||
}
|
|
||||||
|
|
||||||
__asm __volatile ("flush %0 + 8" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[1] = 0x0b000000 | (low32 >> 10);
|
|
||||||
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
|
||||||
|
|
||||||
insns[0] = 0x03000000 | (high32 >> 10);
|
|
||||||
__asm __volatile ("flush %0" : : "r" (insns));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Elf64_Addr __attribute__ ((always_inline))
|
static inline Elf64_Addr __attribute__ ((always_inline))
|
||||||
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||||
const Elf64_Rela *reloc,
|
const Elf64_Rela *reloc,
|
||||||
@ -549,6 +424,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
|
|||||||
|
|
||||||
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
|
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
|
||||||
|
|
||||||
|
if (sym != NULL
|
||||||
|
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
|
||||||
|
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
|
||||||
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
|
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
|
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
|
||||||
@ -576,6 +456,13 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
|
|||||||
case R_SPARC_GLOB_DAT:
|
case R_SPARC_GLOB_DAT:
|
||||||
*reloc_addr = value;
|
*reloc_addr = value;
|
||||||
break;
|
break;
|
||||||
|
case R_SPARC_IRELATIVE:
|
||||||
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
|
*reloc_addr = value;
|
||||||
|
break;
|
||||||
|
case R_SPARC_JMP_IREL:
|
||||||
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
|
/* Fall thru */
|
||||||
case R_SPARC_JMP_SLOT:
|
case R_SPARC_JMP_SLOT:
|
||||||
#ifdef RESOLVE_CONFLICT_FIND_MAP
|
#ifdef RESOLVE_CONFLICT_FIND_MAP
|
||||||
/* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
|
/* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
|
||||||
@ -757,16 +644,29 @@ __attribute__ ((always_inline))
|
|||||||
elf_machine_lazy_rel (struct link_map *map,
|
elf_machine_lazy_rel (struct link_map *map,
|
||||||
Elf64_Addr l_addr, const Elf64_Rela *reloc)
|
Elf64_Addr l_addr, const Elf64_Rela *reloc)
|
||||||
{
|
{
|
||||||
switch (ELF64_R_TYPE (reloc->r_info))
|
Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
|
||||||
|
const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
|
||||||
|
|
||||||
|
if (__builtin_expect (r_type == R_SPARC_JMP_SLOT, 1))
|
||||||
|
;
|
||||||
|
else if (r_type == R_SPARC_JMP_IREL
|
||||||
|
|| r_type == R_SPARC_IRELATIVE)
|
||||||
{
|
{
|
||||||
case R_SPARC_NONE:
|
Elf64_Addr value = map->l_addr + reloc->r_addend;
|
||||||
break;
|
value = ((Elf64_Addr (*) (void)) value) ();
|
||||||
case R_SPARC_JMP_SLOT:
|
if (r_type == R_SPARC_JMP_IREL)
|
||||||
break;
|
{
|
||||||
default:
|
/* 'high' is always zero, for large PLT entries the linker
|
||||||
_dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
|
emits an R_SPARC_IRELATIVE. */
|
||||||
break;
|
sparc64_fixup_plt (map, reloc, reloc_addr, value, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*reloc_addr = value;
|
||||||
}
|
}
|
||||||
|
else if (r_type == R_SPARC_NONE)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
_dl_reloc_bad_type (map, r_type, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* RESOLVE_MAP */
|
#endif /* RESOLVE_MAP */
|
||||||
|
144
sysdeps/sparc/sparc64/dl-plt.h
Normal file
144
sysdeps/sparc/sparc64/dl-plt.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/* PLT fixups. Sparc 64-bit version.
|
||||||
|
Copyright (C) 1997-2006, 2010 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, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
/* We have 4 cases to handle. And we code different code sequences
|
||||||
|
for each one. I love V9 code models... */
|
||||||
|
static inline void __attribute__ ((always_inline))
|
||||||
|
sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc,
|
||||||
|
Elf64_Addr *reloc_addr, Elf64_Addr value,
|
||||||
|
Elf64_Addr high, int t)
|
||||||
|
{
|
||||||
|
unsigned int *insns = (unsigned int *) reloc_addr;
|
||||||
|
Elf64_Addr plt_vaddr = (Elf64_Addr) reloc_addr;
|
||||||
|
Elf64_Sxword disp = value - plt_vaddr;
|
||||||
|
|
||||||
|
/* Now move plt_vaddr up to the call instruction. */
|
||||||
|
plt_vaddr += ((t + 1) * 4);
|
||||||
|
|
||||||
|
/* PLT entries .PLT32768 and above look always the same. */
|
||||||
|
if (__builtin_expect (high, 0) != 0)
|
||||||
|
{
|
||||||
|
*reloc_addr = value - map->l_addr;
|
||||||
|
}
|
||||||
|
/* Near destination. */
|
||||||
|
else if (disp >= -0x800000 && disp < 0x800000)
|
||||||
|
{
|
||||||
|
/* As this is just one instruction, it is thread safe and so
|
||||||
|
we can avoid the unnecessary sethi FOO, %g1.
|
||||||
|
b,a target */
|
||||||
|
insns[0] = 0x30800000 | ((disp >> 2) & 0x3fffff);
|
||||||
|
__asm __volatile ("flush %0" : : "r" (insns));
|
||||||
|
}
|
||||||
|
/* 32-bit Sparc style, the target is in the lower 32-bits of
|
||||||
|
address space. */
|
||||||
|
else if (insns += t, (value >> 32) == 0)
|
||||||
|
{
|
||||||
|
/* sethi %hi(target), %g1
|
||||||
|
jmpl %g1 + %lo(target), %g0 */
|
||||||
|
|
||||||
|
insns[1] = 0x81c06000 | (value & 0x3ff);
|
||||||
|
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[0] = 0x03000000 | ((unsigned int)(value >> 10));
|
||||||
|
__asm __volatile ("flush %0" : : "r" (insns));
|
||||||
|
}
|
||||||
|
/* We can also get somewhat simple sequences if the distance between
|
||||||
|
the target and the PLT entry is within +/- 2GB. */
|
||||||
|
else if ((plt_vaddr > value
|
||||||
|
&& ((plt_vaddr - value) >> 31) == 0)
|
||||||
|
|| (value > plt_vaddr
|
||||||
|
&& ((value - plt_vaddr) >> 31) == 0))
|
||||||
|
{
|
||||||
|
unsigned int displacement;
|
||||||
|
|
||||||
|
if (plt_vaddr > value)
|
||||||
|
displacement = (0 - (plt_vaddr - value));
|
||||||
|
else
|
||||||
|
displacement = value - plt_vaddr;
|
||||||
|
|
||||||
|
/* mov %o7, %g1
|
||||||
|
call displacement
|
||||||
|
mov %g1, %o7 */
|
||||||
|
|
||||||
|
insns[2] = 0x9e100001;
|
||||||
|
__asm __volatile ("flush %0 + 8" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[1] = 0x40000000 | (displacement >> 2);
|
||||||
|
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[0] = 0x8210000f;
|
||||||
|
__asm __volatile ("flush %0" : : "r" (insns));
|
||||||
|
}
|
||||||
|
/* Worst case, ho hum... */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int high32 = (value >> 32);
|
||||||
|
unsigned int low32 = (unsigned int) value;
|
||||||
|
|
||||||
|
/* ??? Some tricks can be stolen from the sparc64 egcs backend
|
||||||
|
constant formation code I wrote. -DaveM */
|
||||||
|
|
||||||
|
if (__builtin_expect (high32 & 0x3ff, 0))
|
||||||
|
{
|
||||||
|
/* sethi %hh(value), %g1
|
||||||
|
sethi %lm(value), %g5
|
||||||
|
or %g1, %hm(value), %g1
|
||||||
|
or %g5, %lo(value), %g5
|
||||||
|
sllx %g1, 32, %g1
|
||||||
|
jmpl %g1 + %g5, %g0
|
||||||
|
nop */
|
||||||
|
|
||||||
|
insns[5] = 0x81c04005;
|
||||||
|
__asm __volatile ("flush %0 + 20" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[4] = 0x83287020;
|
||||||
|
__asm __volatile ("flush %0 + 16" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[3] = 0x8a116000 | (low32 & 0x3ff);
|
||||||
|
__asm __volatile ("flush %0 + 12" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[2] = 0x82106000 | (high32 & 0x3ff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* sethi %hh(value), %g1
|
||||||
|
sethi %lm(value), %g5
|
||||||
|
sllx %g1, 32, %g1
|
||||||
|
or %g5, %lo(value), %g5
|
||||||
|
jmpl %g1 + %g5, %g0
|
||||||
|
nop */
|
||||||
|
|
||||||
|
insns[4] = 0x81c04005;
|
||||||
|
__asm __volatile ("flush %0 + 16" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[3] = 0x8a116000 | (low32 & 0x3ff);
|
||||||
|
__asm __volatile ("flush %0 + 12" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[2] = 0x83287020;
|
||||||
|
}
|
||||||
|
|
||||||
|
__asm __volatile ("flush %0 + 8" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[1] = 0x0b000000 | (low32 >> 10);
|
||||||
|
__asm __volatile ("flush %0 + 4" : : "r" (insns));
|
||||||
|
|
||||||
|
insns[0] = 0x03000000 | (high32 >> 10);
|
||||||
|
__asm __volatile ("flush %0" : : "r" (insns));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user