00001 /* Subroutine for function pointer canonicalization on PA-RISC with ELF32. 00002 Copyright 2002, 2003, 2004 Free Software Foundation, Inc. 00003 Contributed by John David Anglin (dave.anglin@nrc.ca). 00004 00005 This file is part of GCC. 00006 00007 GCC is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2, or (at your option) 00010 any later version. 00011 00012 GCC is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with GCC; see the file COPYING. If not, write to 00019 the Free Software Foundation, 59 Temple Place - Suite 330, 00020 Boston, MA 02111-1307, USA. */ 00021 00022 /* WARNING: The code is this function depends on internal and undocumented 00023 details of the GNU linker and dynamic loader as implemented for parisc 00024 linux. */ 00025 00026 /* This MUST match the defines sysdeps/hppa/dl-machine.h and 00027 bfd/elf32-hppa.c. */ 00028 #define GOT_FROM_PLT_STUB (4*4) 00029 00030 /* List of byte offsets in _dl_runtime_resolve to search for "bl" branches. 00031 The first "bl" branch instruction found MUST be a call to fixup. See 00032 the define for TRAMPOLINE_TEMPLATE in sysdeps/hppa/dl-machine.h. If 00033 the trampoline template is changed, the list must be appropriately 00034 updated. The offset of -4 allows for a magic branch at the start of 00035 the template should it be necessary to change the current branch 00036 position. */ 00037 #define NOFFSETS 2 00038 static int fixup_branch_offset[NOFFSETS] = { 32, -4 }; 00039 00040 #define GET_FIELD(X, FROM, TO) \ 00041 ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) 00042 #define SIGN_EXTEND(VAL,BITS) \ 00043 ((int) ((VAL) >> ((BITS) - 1) ? (-1 << (BITS)) | (VAL) : (VAL))) 00044 00045 struct link_map; 00046 typedef int (*fptr_t) (void); 00047 typedef int (*fixup_t) (struct link_map *, unsigned int); 00048 extern unsigned int _GLOBAL_OFFSET_TABLE_; 00049 00050 /* __canonicalize_funcptr_for_compare must be hidden so that it is not 00051 placed in the dynamic symbol table. Like millicode functions, it 00052 must be linked into all binaries in order access the got table of 00053 that binary. However, we don't use the millicode calling convention 00054 and the routine must be a normal function so that it can be compiled 00055 as pic code. */ 00056 unsigned int __canonicalize_funcptr_for_compare (fptr_t) 00057 __attribute__ ((visibility ("hidden"))); 00058 00059 unsigned int 00060 __canonicalize_funcptr_for_compare (fptr_t fptr) 00061 { 00062 static unsigned int fixup_plabel[2]; 00063 static fixup_t fixup; 00064 unsigned int *plabel, *got; 00065 00066 /* -1 and page 0 are special. -1 is used in crtend to mark the end of 00067 a list of function pointers. Also return immediately if the plabel 00068 bit is not set in the function pointer. In this case, the function 00069 pointer points directly to the function. */ 00070 if ((int) fptr == -1 || (unsigned int) fptr < 4096 || !((int) fptr & 2)) 00071 return (unsigned int) fptr; 00072 00073 /* The function pointer points to a function descriptor (plabel). If 00074 the plabel hasn't been resolved, the first word of the plabel points 00075 to the entry of the PLT stub just before the global offset table. 00076 The second word in the plabel contains the relocation offset for the 00077 function. */ 00078 plabel = (unsigned int *) ((unsigned int) fptr & ~3); 00079 got = (unsigned int *) (plabel[0] + GOT_FROM_PLT_STUB); 00080 00081 /* Return the address of the function if the plabel has been resolved. */ 00082 if (got != &_GLOBAL_OFFSET_TABLE_) 00083 return plabel[0]; 00084 00085 /* Initialize our plabel for calling fixup if we haven't done so already. 00086 This code needs to be thread safe but we don't have to be too careful 00087 as the result is invariant. */ 00088 if (!fixup) 00089 { 00090 int i; 00091 unsigned int *iptr; 00092 00093 /* Find the first "bl" branch in the offset search list. This is a 00094 call to fixup or a magic branch to fixup at the beginning of the 00095 trampoline template. The fixup function does the actual runtime 00096 resolution of function descriptors. We only look for "bl" branches 00097 with a 17-bit pc-relative displacement. */ 00098 for (i = 0; i < NOFFSETS; i++) 00099 { 00100 iptr = (unsigned int *) (got[-2] + fixup_branch_offset[i]); 00101 if ((*iptr & 0xfc00e000) == 0xe8000000) 00102 break; 00103 } 00104 00105 /* This should not happen... */ 00106 if (i == NOFFSETS) 00107 return ~0; 00108 00109 /* Extract the 17-bit displacement from the instruction. */ 00110 iptr += SIGN_EXTEND (GET_FIELD (*iptr, 19, 28) | 00111 GET_FIELD (*iptr, 29, 29) << 10 | 00112 GET_FIELD (*iptr, 11, 15) << 11 | 00113 GET_FIELD (*iptr, 31, 31) << 16, 17); 00114 00115 /* Build a plabel for an indirect call to fixup. */ 00116 fixup_plabel[0] = (unsigned int) iptr + 8; /* address of fixup */ 00117 fixup_plabel[1] = got[-1]; /* ltp for fixup */ 00118 fixup = (fixup_t) ((int) fixup_plabel | 3); 00119 } 00120 00121 /* Call fixup to resolve the function address. got[1] contains the 00122 link_map pointer and plabel[1] the relocation offset. */ 00123 fixup ((struct link_map *) got[1], plabel[1]); 00124 00125 return plabel[0]; 00126 }
1.5.6