]>
Commit | Line | Data |
---|---|---|
9e1ab8c1 | 1 | /* Subroutine for function pointer canonicalization on PA-RISC with ELF32. |
66647d44 | 2 | Copyright 2002, 2003, 2004, 2007, 2009 Free Software Foundation, Inc. |
9e1ab8c1 JDA |
3 | Contributed by John David Anglin (dave.anglin@nrc.ca). |
4 | ||
b7849684 | 5 | This file is part of GCC. |
9e1ab8c1 | 6 | |
0af0580f JDA |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 9 | Software Foundation; either version 3, or (at your option) any later |
0af0580f | 10 | version. |
9e1ab8c1 | 11 | |
0af0580f JDA |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
9e1ab8c1 | 16 | |
748086b7 JJ |
17 | Under Section 7 of GPL version 3, you are granted additional |
18 | permissions described in the GCC Runtime Library Exception, version | |
19 | 3.1, as published by the Free Software Foundation. | |
20 | ||
21 | You should have received a copy of the GNU General Public License and | |
22 | a copy of the GCC Runtime Library Exception along with this program; | |
23 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | <http://www.gnu.org/licenses/>. */ | |
25 | ||
9e1ab8c1 JDA |
26 | |
27 | /* WARNING: The code is this function depends on internal and undocumented | |
28 | details of the GNU linker and dynamic loader as implemented for parisc | |
29 | linux. */ | |
30 | ||
31 | /* This MUST match the defines sysdeps/hppa/dl-machine.h and | |
32 | bfd/elf32-hppa.c. */ | |
33 | #define GOT_FROM_PLT_STUB (4*4) | |
34 | ||
35 | /* List of byte offsets in _dl_runtime_resolve to search for "bl" branches. | |
36 | The first "bl" branch instruction found MUST be a call to fixup. See | |
37 | the define for TRAMPOLINE_TEMPLATE in sysdeps/hppa/dl-machine.h. If | |
38 | the trampoline template is changed, the list must be appropriately | |
39 | updated. The offset of -4 allows for a magic branch at the start of | |
40 | the template should it be necessary to change the current branch | |
41 | position. */ | |
42 | #define NOFFSETS 2 | |
43 | static int fixup_branch_offset[NOFFSETS] = { 32, -4 }; | |
44 | ||
45 | #define GET_FIELD(X, FROM, TO) \ | |
46 | ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) | |
47 | #define SIGN_EXTEND(VAL,BITS) \ | |
48 | ((int) ((VAL) >> ((BITS) - 1) ? (-1 << (BITS)) | (VAL) : (VAL))) | |
49 | ||
50 | struct link_map; | |
51 | typedef int (*fptr_t) (void); | |
52 | typedef int (*fixup_t) (struct link_map *, unsigned int); | |
53 | extern unsigned int _GLOBAL_OFFSET_TABLE_; | |
54 | ||
55 | /* __canonicalize_funcptr_for_compare must be hidden so that it is not | |
56 | placed in the dynamic symbol table. Like millicode functions, it | |
57 | must be linked into all binaries in order access the got table of | |
58 | that binary. However, we don't use the millicode calling convention | |
59 | and the routine must be a normal function so that it can be compiled | |
60 | as pic code. */ | |
61 | unsigned int __canonicalize_funcptr_for_compare (fptr_t) | |
62 | __attribute__ ((visibility ("hidden"))); | |
63 | ||
64 | unsigned int | |
95f576c1 | 65 | __canonicalize_funcptr_for_compare (fptr_t fptr) |
9e1ab8c1 JDA |
66 | { |
67 | static unsigned int fixup_plabel[2]; | |
68 | static fixup_t fixup; | |
69 | unsigned int *plabel, *got; | |
70 | ||
3f320b7e JDA |
71 | /* -1 and page 0 are special. -1 is used in crtend to mark the end of |
72 | a list of function pointers. Also return immediately if the plabel | |
73 | bit is not set in the function pointer. In this case, the function | |
74 | pointer points directly to the function. */ | |
75 | if ((int) fptr == -1 || (unsigned int) fptr < 4096 || !((int) fptr & 2)) | |
9e1ab8c1 JDA |
76 | return (unsigned int) fptr; |
77 | ||
78 | /* The function pointer points to a function descriptor (plabel). If | |
79 | the plabel hasn't been resolved, the first word of the plabel points | |
80 | to the entry of the PLT stub just before the global offset table. | |
81 | The second word in the plabel contains the relocation offset for the | |
82 | function. */ | |
83 | plabel = (unsigned int *) ((unsigned int) fptr & ~3); | |
84 | got = (unsigned int *) (plabel[0] + GOT_FROM_PLT_STUB); | |
85 | ||
86 | /* Return the address of the function if the plabel has been resolved. */ | |
87 | if (got != &_GLOBAL_OFFSET_TABLE_) | |
88 | return plabel[0]; | |
89 | ||
90 | /* Initialize our plabel for calling fixup if we haven't done so already. | |
91 | This code needs to be thread safe but we don't have to be too careful | |
92 | as the result is invariant. */ | |
93 | if (!fixup) | |
94 | { | |
95 | int i; | |
96 | unsigned int *iptr; | |
97 | ||
98 | /* Find the first "bl" branch in the offset search list. This is a | |
99 | call to fixup or a magic branch to fixup at the beginning of the | |
100 | trampoline template. The fixup function does the actual runtime | |
c1207243 | 101 | resolution of function descriptors. We only look for "bl" branches |
9e1ab8c1 JDA |
102 | with a 17-bit pc-relative displacement. */ |
103 | for (i = 0; i < NOFFSETS; i++) | |
104 | { | |
105 | iptr = (unsigned int *) (got[-2] + fixup_branch_offset[i]); | |
106 | if ((*iptr & 0xfc00e000) == 0xe8000000) | |
107 | break; | |
108 | } | |
109 | ||
110 | /* This should not happen... */ | |
111 | if (i == NOFFSETS) | |
112 | return ~0; | |
113 | ||
114 | /* Extract the 17-bit displacement from the instruction. */ | |
115 | iptr += SIGN_EXTEND (GET_FIELD (*iptr, 19, 28) | | |
116 | GET_FIELD (*iptr, 29, 29) << 10 | | |
117 | GET_FIELD (*iptr, 11, 15) << 11 | | |
118 | GET_FIELD (*iptr, 31, 31) << 16, 17); | |
119 | ||
120 | /* Build a plabel for an indirect call to fixup. */ | |
121 | fixup_plabel[0] = (unsigned int) iptr + 8; /* address of fixup */ | |
122 | fixup_plabel[1] = got[-1]; /* ltp for fixup */ | |
123 | fixup = (fixup_t) ((int) fixup_plabel | 3); | |
124 | } | |
125 | ||
126 | /* Call fixup to resolve the function address. got[1] contains the | |
127 | link_map pointer and plabel[1] the relocation offset. */ | |
128 | fixup ((struct link_map *) got[1], plabel[1]); | |
129 | ||
130 | return plabel[0]; | |
131 | } |