fptr.c (__canonicalize_funcptr_for_compare): New file and function.
authorJohn David Anglin <dave@hiauly1.hia.nrc.ca>
Thu, 5 Dec 2002 01:57:27 +0000 (01:57 +0000)
committerJohn David Anglin <danglin@gcc.gnu.org>
Thu, 5 Dec 2002 01:57:27 +0000 (01:57 +0000)
* 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

gcc/ChangeLog
gcc/config/pa/fptr.c [new file with mode: 0644]
gcc/config/pa/pa.md
gcc/config/pa/pa32-linux.h
gcc/config/pa/t-linux

index cb473f5..00855d9 100644 (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.
diff --git a/gcc/config/pa/fptr.c b/gcc/config/pa/fptr.c
new file mode 100644 (file)
index 0000000..e0bd88a
--- /dev/null
@@ -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];
+}
index cd28ce8..640196b 100644 (file)
              (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)
     {
index c8ea72d..f685fa8 100644 (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) }
index 9a338c2..561bc00 100644 (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