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>
|
||||
|
||||
* elf/elf.h: Define m68k TLS relocations.
|
||||
|
@ -1324,6 +1324,8 @@ typedef struct
|
||||
#define R_SPARC_H34 85
|
||||
#define R_SPARC_SIZE32 86
|
||||
#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_VTENTRY 251
|
||||
#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.
|
||||
Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
|
||||
Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
|
||||
Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
@ -27,20 +27,13 @@
|
||||
#include <sys/param.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <tls.h>
|
||||
#include <dl-plt.h>
|
||||
|
||||
#ifndef VALIDX
|
||||
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
|
||||
#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. */
|
||||
static inline int
|
||||
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
|
||||
@ -312,41 +305,6 @@ _dl_start_user:\n\
|
||||
.size _dl_start_user, . - _dl_start_user\n\
|
||||
.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
|
||||
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||
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. */
|
||||
|
||||
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)
|
||||
{
|
||||
#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:
|
||||
*reloc_addr = value;
|
||||
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:
|
||||
{
|
||||
#if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
|
||||
@ -578,16 +550,21 @@ __attribute__ ((always_inline))
|
||||
elf_machine_lazy_rel (struct link_map *map,
|
||||
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:
|
||||
break;
|
||||
case R_SPARC_JMP_SLOT:
|
||||
break;
|
||||
default:
|
||||
_dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
|
||||
break;
|
||||
Elf32_Addr value = map->l_addr + reloc->r_addend;
|
||||
value = ((Elf32_Addr (*) (void)) value) ();
|
||||
sparc_fixup_plt (reloc, reloc_addr, value, 0, 1);
|
||||
}
|
||||
else if (r_type == R_SPARC_NONE)
|
||||
;
|
||||
else
|
||||
_dl_reloc_bad_type (map, r_type, 1);
|
||||
}
|
||||
|
||||
#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.
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 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
|
||||
@ -27,6 +27,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sysdep.h>
|
||||
#include <dl-plt.h>
|
||||
|
||||
#ifndef VALIDX
|
||||
# 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;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||
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. */
|
||||
|
||||
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)
|
||||
{
|
||||
#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:
|
||||
*reloc_addr = value;
|
||||
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:
|
||||
#ifdef RESOLVE_CONFLICT_FIND_MAP
|
||||
/* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
|
||||
@ -757,16 +644,29 @@ __attribute__ ((always_inline))
|
||||
elf_machine_lazy_rel (struct link_map *map,
|
||||
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:
|
||||
break;
|
||||
case R_SPARC_JMP_SLOT:
|
||||
break;
|
||||
default:
|
||||
_dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
|
||||
break;
|
||||
Elf64_Addr value = map->l_addr + reloc->r_addend;
|
||||
value = ((Elf64_Addr (*) (void)) value) ();
|
||||
if (r_type == R_SPARC_JMP_IREL)
|
||||
{
|
||||
/* '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
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else if (r_type == R_SPARC_NONE)
|
||||
;
|
||||
else
|
||||
_dl_reloc_bad_type (map, r_type, 1);
|
||||
}
|
||||
|
||||
#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