0
|
1 /* Subroutine for function pointer canonicalization on PA-RISC with ELF32.
|
|
2 Copyright 2002, 2003, 2004, 2007, 2009 Free Software Foundation, Inc.
|
|
3 Contributed by John David Anglin (dave.anglin@nrc.ca).
|
|
4
|
|
5 This file is part of GCC.
|
|
6
|
|
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
|
|
9 Software Foundation; either version 3, or (at your option) any later
|
|
10 version.
|
|
11
|
|
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.
|
|
16
|
|
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
|
|
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
|
|
65 __canonicalize_funcptr_for_compare (fptr_t fptr)
|
|
66 {
|
|
67 static unsigned int fixup_plabel[2];
|
|
68 static fixup_t fixup;
|
|
69 unsigned int *plabel, *got;
|
|
70
|
|
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))
|
|
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
|
|
101 resolution of function descriptors. We only look for "bl" branches
|
|
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 }
|