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