]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/pa/fptr.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / pa / fptr.c
CommitLineData
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 5This file is part of GCC.
9e1ab8c1 6
0af0580f
JDA
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
748086b7 9Software Foundation; either version 3, or (at your option) any later
0af0580f 10version.
9e1ab8c1 11
0af0580f
JDA
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
9e1ab8c1 16
748086b7
JJ
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see 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 43static 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
50struct link_map;
51typedef int (*fptr_t) (void);
52typedef int (*fixup_t) (struct link_map *, unsigned int);
53extern unsigned int _GLOBAL_OFFSET_TABLE_;
54
66a00b11 55static 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. */
74unsigned int __canonicalize_funcptr_for_compare (fptr_t)
75 __attribute__ ((visibility ("hidden")));
76
77unsigned 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