[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#187652: [patch] [3.2.3/hppa] fix function pointer comparisions



Will do. What about applying this patch upstream for 3.2.3?

Randolph Chung writes:
> Package: gcc
> Version: 3.2.3
> Severity: important
> Tags: patch
> 
> Please include the attached patch in the next gcc-3.2.3 upload. It
> fixes an important bug in doing function pointer comparisions on hppa.
> This patch was backported from the gcc-3.3 branch. Test-compiled with no
> regressions. This bug causes some X programs to be miscompiled and not
> work.
> 
> thanks
> randolph
> -- 
> Randolph Chung
> Debian GNU/Linux Developer, hppa/ia64 ports
> http://www.tausq.org/
> #! /bin/sh -e
> 
> # DP: Handle function pointer comparisions on hppa properly
> # DP: Backported from gcc-3.3 branch
> # DP: http://gcc.gnu.org/ml/gcc-cvs/2002-12/msg00157.html
> # DP: http://gcc.gnu.org/ml/gcc-cvs/2002-12/msg00195.html
> 
> dir=
> if [ $# -eq 3 -a "$2" = '-d' ]; then
>     pdir="-d $3"
>     dir="$3/"
> elif [ $# -ne 1 ]; then
>     echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
>     exit 1
> fi
> case "$1" in
>     -patch)
>         patch $pdir -f --no-backup-if-mismatch -p1 < $0
>         #cd ${dir}gcc && autoconf
>         ;;
>     -unpatch)
>         patch $pdir -f --no-backup-if-mismatch -R -p1 < $0
>         #rm ${dir}gcc/configure
>         ;;
>     *)
>         echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
>         exit 1
> esac
> exit 0
> 
> 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-05  John David Anglin  <dave@hiauly1.hia.nrc.ca>
> 
> 	* pa32-linux.h (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL): Move define.
> 	* pa.h (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL): To here.
> 
> 
> diff -uNrp src.orig/gcc/config/pa/fptr.c src/gcc/config/pa/fptr.c
> --- src.orig/gcc/config/pa/fptr.c	1969-12-31 16:00:00.000000000 -0800
> +++ src/gcc/config/pa/fptr.c	2003-03-30 14:50:24.000000000 -0800
> @@ -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];
> +}
> diff -uNrp src.orig/gcc/config/pa/pa.h src/gcc/config/pa/pa.h
> --- src.orig/gcc/config/pa/pa.h	2002-12-28 16:29:03.000000000 -0800
> +++ src/gcc/config/pa/pa.h	2003-03-30 14:50:24.000000000 -0800
> @@ -2033,3 +2033,7 @@ while (0)
>    {"cmpib_comparison_operator", {EQ, NE, LT, LE, LEU,			\
>     GT, GTU, GE}},							\
>    {"movb_comparison_operator", {EQ, NE, LT, GE}},
> +
> +/* We need a libcall to canonicalize function pointers on TARGET_ELF32.  */
> +#define CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL \
> +  "__canonicalize_funcptr_for_compare"
> diff -uNrp src.orig/gcc/config/pa/pa.md src/gcc/config/pa/pa.md
> --- src.orig/gcc/config/pa/pa.md	2003-02-21 02:19:25.000000000 -0800
> +++ src/gcc/config/pa/pa.md	2003-03-30 14:50:24.000000000 -0800
> @@ -7144,9 +7144,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)
>      {
> diff -uNrp src.orig/gcc/config/pa/pa32-linux.h src/gcc/config/pa/pa32-linux.h
> --- src.orig/gcc/config/pa/pa32-linux.h	2002-03-01 15:38:29.000000000 -0800
> +++ src/gcc/config/pa/pa32-linux.h	2003-03-30 14:52:25.000000000 -0800
> @@ -24,3 +24,17 @@ Boston, MA 02111-1307, USA.  */
>  
>  #undef CPP_SPEC
>  #define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{mhppa:-D__hppa__} %{posix:-D_POSIX_SOURCE} -D_PA_RISC1_1"
> +
> +/* 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) }
> diff -uNrp src.orig/gcc/config/pa/t-linux src/gcc/config/pa/t-linux
> --- src.orig/gcc/config/pa/t-linux	2002-05-01 02:45:08.000000000 -0700
> +++ src/gcc/config/pa/t-linux	2003-03-30 14:50:24.000000000 -0800
> @@ -9,8 +9,14 @@ LIB1ASMFUNCS =  _divI _divU _remI _remU 
>  
>  LIB1ASMSRC = pa/milli32.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



Reply to: