fptr.c (__canonicalize_funcptr_for_compare): New file and function.

* pa/fptr.c (__canonicalize_funcptr_for_compare): New file and function.
	* pa.md (canonicalize_funcptr_for_compare): Output library call to
	canonicalize_funcptr_for_compare_libfunc on TARGET_ELF32.
	* pa32-linux.h (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL,
	CTOR_LIST_BEGIN): New defines.
	* pa/t-linux (LIB2FUNCS_EXTRA): New define.
	(fptr.c): Add make rules.

From-SVN: r59842
This commit is contained in:
John David Anglin 2002-12-05 01:57:27 +00:00 committed by John David Anglin
parent 16823694d5
commit 9e1ab8c1a5
5 changed files with 177 additions and 4 deletions

View File

@ -1,3 +1,13 @@
2002-12-04 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa/fptr.c (__canonicalize_funcptr_for_compare): New file and function.
* pa.md (canonicalize_funcptr_for_compare): Output library call to
canonicalize_funcptr_for_compare_libfunc on TARGET_ELF32.
* pa32-linux.h (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL,
CTOR_LIST_BEGIN): New defines.
* pa/t-linux (LIB2FUNCS_EXTRA): New define.
(fptr.c): Add make rules.
2002-12-04 Geoffrey Keating <geoffk@apple.com>
* combine.c (combine_simplify_rtx): Add new canonicalizations.

127
gcc/config/pa/fptr.c Normal file
View File

@ -0,0 +1,127 @@
/* Subroutine for function pointer canonicalization on PA-RISC with ELF32.
Copyright 2002 Free Software Foundation, Inc.
Contributed by John David Anglin (dave.anglin@nrc.ca).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* WARNING: The code is this function depends on internal and undocumented
details of the GNU linker and dynamic loader as implemented for parisc
linux. */
/* This MUST match the defines sysdeps/hppa/dl-machine.h and
bfd/elf32-hppa.c. */
#define GOT_FROM_PLT_STUB (4*4)
/* List of byte offsets in _dl_runtime_resolve to search for "bl" branches.
The first "bl" branch instruction found MUST be a call to fixup. See
the define for TRAMPOLINE_TEMPLATE in sysdeps/hppa/dl-machine.h. If
the trampoline template is changed, the list must be appropriately
updated. The offset of -4 allows for a magic branch at the start of
the template should it be necessary to change the current branch
position. */
#define NOFFSETS 2
static int fixup_branch_offset[NOFFSETS] = { 32, -4 };
#define GET_FIELD(X, FROM, TO) \
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
#define SIGN_EXTEND(VAL,BITS) \
((int) ((VAL) >> ((BITS) - 1) ? (-1 << (BITS)) | (VAL) : (VAL)))
struct link_map;
typedef int (*fptr_t) (void);
typedef int (*fixup_t) (struct link_map *, unsigned int);
extern unsigned int _GLOBAL_OFFSET_TABLE_;
/* __canonicalize_funcptr_for_compare must be hidden so that it is not
placed in the dynamic symbol table. Like millicode functions, it
must be linked into all binaries in order access the got table of
that binary. However, we don't use the millicode calling convention
and the routine must be a normal function so that it can be compiled
as pic code. */
unsigned int __canonicalize_funcptr_for_compare (fptr_t)
__attribute__ ((visibility ("hidden")));
unsigned int
__canonicalize_funcptr_for_compare (fptr)
fptr_t fptr;
{
static unsigned int fixup_plabel[2];
static fixup_t fixup;
unsigned int *plabel, *got;
/* -1 is special. It is used in crtend to mark the end of a list of
function pointers. Also return immediately if the plabel bit is
not set in the function pointer. In this case, the function pointer
points directly to the function. */
if ((int) fptr == -1 || !((int) fptr & 2))
return (unsigned int) fptr;
/* The function pointer points to a function descriptor (plabel). If
the plabel hasn't been resolved, the first word of the plabel points
to the entry of the PLT stub just before the global offset table.
The second word in the plabel contains the relocation offset for the
function. */
plabel = (unsigned int *) ((unsigned int) fptr & ~3);
got = (unsigned int *) (plabel[0] + GOT_FROM_PLT_STUB);
/* Return the address of the function if the plabel has been resolved. */
if (got != &_GLOBAL_OFFSET_TABLE_)
return plabel[0];
/* Initialize our plabel for calling fixup if we haven't done so already.
This code needs to be thread safe but we don't have to be too careful
as the result is invariant. */
if (!fixup)
{
int i;
unsigned int *iptr;
/* Find the first "bl" branch in the offset search list. This is a
call to fixup or a magic branch to fixup at the beginning of the
trampoline template. The fixup function does the actual runtime
resolution of function decriptors. We only look for "bl" branches
with a 17-bit pc-relative displacement. */
for (i = 0; i < NOFFSETS; i++)
{
iptr = (unsigned int *) (got[-2] + fixup_branch_offset[i]);
if ((*iptr & 0xfc00e000) == 0xe8000000)
break;
}
/* This should not happen... */
if (i == NOFFSETS)
return ~0;
/* Extract the 17-bit displacement from the instruction. */
iptr += SIGN_EXTEND (GET_FIELD (*iptr, 19, 28) |
GET_FIELD (*iptr, 29, 29) << 10 |
GET_FIELD (*iptr, 11, 15) << 11 |
GET_FIELD (*iptr, 31, 31) << 16, 17);
/* Build a plabel for an indirect call to fixup. */
fixup_plabel[0] = (unsigned int) iptr + 8; /* address of fixup */
fixup_plabel[1] = got[-1]; /* ltp for fixup */
fixup = (fixup_t) ((int) fixup_plabel | 3);
}
/* Call fixup to resolve the function address. got[1] contains the
link_map pointer and plabel[1] the relocation offset. */
fixup ((struct link_map *) got[1], plabel[1]);
return plabel[0];
}

View File

@ -7277,9 +7277,20 @@
(clobber (reg:SI 31))])
(set (match_operand:SI 0 "register_operand" "")
(reg:SI 29))]
"! TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && !TARGET_ELF32"
"!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
"
{
if (TARGET_ELF32)
{
rtx canonicalize_funcptr_for_compare_libfunc
= init_one_libfunc (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL);
emit_library_call_value (canonicalize_funcptr_for_compare_libfunc,
operands[0], LCT_NORMAL, Pmode,
1, operands[1], Pmode);
DONE;
}
operands[2] = gen_reg_rtx (SImode);
if (GET_CODE (operands[1]) != REG)
{

View File

@ -29,3 +29,22 @@ Boston, MA 02111-1307, USA. */
subspace stubs, so we allow sibcalls to all functions. */
#undef FUNCTION_OK_FOR_SIBCALL
#define FUNCTION_OK_FOR_SIBCALL(DECL) 1
/* We need a libcall to canonicalize function pointers because of
the way function pointers are handled when doing lazy linking. */
#define CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL \
"__canonicalize_funcptr_for_compare"
/* The libcall __canonicalize_funcptr_for_compare is referenced in
crtend.o and the reference isn't resolved in objects that don't
compare function pointers. Thus, we need to play games to provide
a reference in crtbegin.o. The rest of the define is the same
as that in crtstuff.c */
#define CTOR_LIST_BEGIN \
asm (".type __canonicalize_funcptr_for_compare,@function\n" \
" .text\n" \
" .word __canonicalize_funcptr_for_compare-$PIC_pcrel$0"); \
STATIC func_ptr __CTOR_LIST__[1] \
__attribute__ ((__unused__, section(".ctors"), \
aligned(sizeof(func_ptr)))) \
= { (func_ptr) (-1) }

View File

@ -5,8 +5,14 @@
LIB1ASMFUNCS = _divI _divU _remI _remU _div_const _mulI _dyncall
LIB1ASMSRC = pa/milli64.S
# Compile crtbeginS.o and crtendS.o as PIC.
CRTSTUFF_T_CFLAGS_S = -fPIC
# Compile libgcc2.a as PIC.
TARGET_LIBGCC2_CFLAGS = -fPIC -DELF=1 -DLINUX=1
LIB2FUNCS_EXTRA=fptr.c
fptr.c: $(srcdir)/config/pa/fptr.c
rm -f fptr.c
cp $(srcdir)/config/pa/fptr.c .
# Compile crtbeginS.o and crtendS.o as PIC.
CRTSTUFF_T_CFLAGS_S = -fPIC