]>
Commit | Line | Data |
---|---|---|
9e1ab8c1 | 1 | /* Subroutine for function pointer canonicalization on PA-RISC with ELF32. |
83ffe9cd | 2 | Copyright (C) 2002-2023 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 | |
9a32d437 | 43 | static int fixup_branch_offset[NOFFSETS] = { -4, 32 }; |
9e1ab8c1 JDA |
44 | |
45 | #define GET_FIELD(X, FROM, TO) \ | |
46 | ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) | |
47 | #define SIGN_EXTEND(VAL,BITS) \ | |
7a84bf71 | 48 | ((int) ((VAL) >> ((BITS) - 1) ? ((unsigned)(-1) << (BITS)) | (VAL) : (VAL))) |
9e1ab8c1 JDA |
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 | ||
66a00b11 | 55 | static inline int |
85093ac6 | 56 | _dl_read_access_allowed (unsigned int addr) |
66a00b11 JDA |
57 | { |
58 | int result; | |
59 | ||
60 | asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : ); | |
61 | ||
62 | return result; | |
63 | } | |
64 | ||
c49af82c JDA |
65 | #pragma GCC diagnostic push |
66 | #pragma GCC diagnostic ignored "-Warray-bounds" | |
67 | ||
9e1ab8c1 JDA |
68 | /* __canonicalize_funcptr_for_compare must be hidden so that it is not |
69 | placed in the dynamic symbol table. Like millicode functions, it | |
70 | must be linked into all binaries in order access the got table of | |
71 | that binary. However, we don't use the millicode calling convention | |
72 | and the routine must be a normal function so that it can be compiled | |
73 | as pic code. */ | |
74 | unsigned int __canonicalize_funcptr_for_compare (fptr_t) | |
75 | __attribute__ ((visibility ("hidden"))); | |
76 | ||
77 | unsigned int | |
95f576c1 | 78 | __canonicalize_funcptr_for_compare (fptr_t fptr) |
9e1ab8c1 | 79 | { |
787c1027 JDA |
80 | static unsigned int fixup_plabel[2] __attribute__((used)); |
81 | fixup_t fixup; | |
85093ac6 JDA |
82 | volatile unsigned int *plabel; |
83 | unsigned int *got, *iptr, reloc_offset; | |
787c1027 | 84 | int i; |
9e1ab8c1 | 85 | |
3f320b7e JDA |
86 | /* -1 and page 0 are special. -1 is used in crtend to mark the end of |
87 | a list of function pointers. Also return immediately if the plabel | |
88 | bit is not set in the function pointer. In this case, the function | |
89 | pointer points directly to the function. */ | |
90 | if ((int) fptr == -1 || (unsigned int) fptr < 4096 || !((int) fptr & 2)) | |
9e1ab8c1 JDA |
91 | return (unsigned int) fptr; |
92 | ||
93 | /* The function pointer points to a function descriptor (plabel). If | |
94 | the plabel hasn't been resolved, the first word of the plabel points | |
95 | to the entry of the PLT stub just before the global offset table. | |
96 | The second word in the plabel contains the relocation offset for the | |
97 | function. */ | |
85093ac6 JDA |
98 | plabel = (volatile unsigned int *) ((unsigned int) fptr & ~3); |
99 | if (!_dl_read_access_allowed ((unsigned int)plabel)) | |
66a00b11 JDA |
100 | return (unsigned int) fptr; |
101 | ||
102 | /* Load first word of candidate descriptor. It should be a pointer | |
103 | with word alignment and point to memory that can be read. */ | |
104 | got = (unsigned int *) plabel[0]; | |
105 | if (((unsigned int) got & 3) != 0 | |
85093ac6 | 106 | || !_dl_read_access_allowed ((unsigned int)got)) |
66a00b11 JDA |
107 | return (unsigned int) fptr; |
108 | ||
85093ac6 JDA |
109 | /* We need to load the relocation offset before the function address. */ |
110 | reloc_offset = plabel[1]; | |
111 | __sync_synchronize(); | |
9e1ab8c1 JDA |
112 | got = (unsigned int *) (plabel[0] + GOT_FROM_PLT_STUB); |
113 | ||
114 | /* Return the address of the function if the plabel has been resolved. */ | |
115 | if (got != &_GLOBAL_OFFSET_TABLE_) | |
116 | return plabel[0]; | |
117 | ||
787c1027 JDA |
118 | /* Find the first "bl" branch in the offset search list. This is a |
119 | call to _dl_fixup or a magic branch to fixup at the beginning of the | |
120 | trampoline template. The fixup function does the actual runtime | |
121 | resolution of function descriptors. We only look for "bl" branches | |
122 | with a 17-bit pc-relative displacement. */ | |
123 | for (i = 0; i < NOFFSETS; i++) | |
9e1ab8c1 | 124 | { |
787c1027 JDA |
125 | iptr = (unsigned int *) (got[-2] + fixup_branch_offset[i]); |
126 | if ((*iptr & 0xfc00e000) == 0xe8000000) | |
127 | break; | |
9e1ab8c1 JDA |
128 | } |
129 | ||
787c1027 JDA |
130 | /* This should not happen... */ |
131 | if (i == NOFFSETS) | |
132 | return ~0; | |
133 | ||
134 | /* Extract the 17-bit displacement from the instruction. */ | |
135 | iptr += SIGN_EXTEND (GET_FIELD (*iptr, 19, 28) | | |
136 | GET_FIELD (*iptr, 29, 29) << 10 | | |
137 | GET_FIELD (*iptr, 11, 15) << 11 | | |
138 | GET_FIELD (*iptr, 31, 31) << 16, 17); | |
139 | ||
140 | /* Build a plabel for an indirect call to _dl_fixup. */ | |
141 | fixup_plabel[0] = (unsigned int) iptr + 8; /* address of fixup */ | |
142 | fixup_plabel[1] = got[-1]; /* ltp for fixup */ | |
9f92937b | 143 | fixup = (fixup_t) ((int) fixup_plabel | 2); |
787c1027 | 144 | |
9e1ab8c1 JDA |
145 | /* Call fixup to resolve the function address. got[1] contains the |
146 | link_map pointer and plabel[1] the relocation offset. */ | |
85093ac6 | 147 | fixup ((struct link_map *) got[1], reloc_offset); |
9e1ab8c1 JDA |
148 | |
149 | return plabel[0]; | |
150 | } | |
c49af82c JDA |
151 | |
152 | #pragma GCC diagnostic pop |