]>
Commit | Line | Data |
---|---|---|
311927f1 | 1 | /* PLT fixups. Sparc 64-bit version. |
6d7e8eda | 2 | Copyright (C) 1997-2023 Free Software Foundation, Inc. |
311927f1 DM |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
311927f1 | 18 | |
42675c6f DM |
19 | #ifndef _DL_PLT_H |
20 | #define _DL_PLT_H | |
21 | ||
311927f1 DM |
22 | /* We have 4 cases to handle. And we code different code sequences |
23 | for each one. I love V9 code models... */ | |
24 | static inline void __attribute__ ((always_inline)) | |
25 | sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc, | |
26 | Elf64_Addr *reloc_addr, Elf64_Addr value, | |
27 | Elf64_Addr high, int t) | |
28 | { | |
29 | unsigned int *insns = (unsigned int *) reloc_addr; | |
30 | Elf64_Addr plt_vaddr = (Elf64_Addr) reloc_addr; | |
31 | Elf64_Sxword disp = value - plt_vaddr; | |
32 | ||
7ec1221f DM |
33 | /* 't' is '0' if we are resolving this PLT entry for RTLD bootstrap, |
34 | in which case we'll be resolving all PLT entries and thus can | |
35 | optimize by overwriting instructions starting at the first PLT entry | |
36 | instruction and we need not be mindful of thread safety. | |
37 | ||
38 | Otherwise, 't' is '1'. | |
39 | ||
40 | Now move plt_vaddr up to the call instruction. */ | |
311927f1 DM |
41 | plt_vaddr += ((t + 1) * 4); |
42 | ||
43 | /* PLT entries .PLT32768 and above look always the same. */ | |
44 | if (__builtin_expect (high, 0) != 0) | |
45 | { | |
46 | *reloc_addr = value - map->l_addr; | |
47 | } | |
48 | /* Near destination. */ | |
49 | else if (disp >= -0x800000 && disp < 0x800000) | |
50 | { | |
7ec1221f DM |
51 | unsigned int insn; |
52 | ||
53 | /* ba,a */ | |
54 | insn = 0x30800000 | ((disp >> 2) & 0x3fffff); | |
55 | ||
56 | if (disp >= -0x100000 && disp < 0x100000) | |
57 | { | |
58 | /* ba,a,pt %icc */ | |
59 | insn = 0x30480000 | ((disp >> 2) & 0x07ffff); | |
60 | } | |
61 | ||
62 | /* As this is just one instruction, it is thread safe and so we | |
63 | can avoid the unnecessary sethi FOO, %g1. Each 64-bit PLT | |
64 | entry is 8 instructions long, so we can't run into the 'jmp' | |
65 | delay slot problems 32-bit PLTs can. */ | |
66 | insns[0] = insn; | |
311927f1 DM |
67 | __asm __volatile ("flush %0" : : "r" (insns)); |
68 | } | |
69 | /* 32-bit Sparc style, the target is in the lower 32-bits of | |
70 | address space. */ | |
71 | else if (insns += t, (value >> 32) == 0) | |
72 | { | |
73 | /* sethi %hi(target), %g1 | |
74 | jmpl %g1 + %lo(target), %g0 */ | |
75 | ||
76 | insns[1] = 0x81c06000 | (value & 0x3ff); | |
77 | __asm __volatile ("flush %0 + 4" : : "r" (insns)); | |
78 | ||
79 | insns[0] = 0x03000000 | ((unsigned int)(value >> 10)); | |
80 | __asm __volatile ("flush %0" : : "r" (insns)); | |
81 | } | |
82 | /* We can also get somewhat simple sequences if the distance between | |
83 | the target and the PLT entry is within +/- 2GB. */ | |
84 | else if ((plt_vaddr > value | |
85 | && ((plt_vaddr - value) >> 31) == 0) | |
86 | || (value > plt_vaddr | |
87 | && ((value - plt_vaddr) >> 31) == 0)) | |
88 | { | |
89 | unsigned int displacement; | |
90 | ||
91 | if (plt_vaddr > value) | |
92 | displacement = (0 - (plt_vaddr - value)); | |
93 | else | |
94 | displacement = value - plt_vaddr; | |
95 | ||
96 | /* mov %o7, %g1 | |
97 | call displacement | |
98 | mov %g1, %o7 */ | |
99 | ||
100 | insns[2] = 0x9e100001; | |
101 | __asm __volatile ("flush %0 + 8" : : "r" (insns)); | |
102 | ||
103 | insns[1] = 0x40000000 | (displacement >> 2); | |
104 | __asm __volatile ("flush %0 + 4" : : "r" (insns)); | |
105 | ||
106 | insns[0] = 0x8210000f; | |
107 | __asm __volatile ("flush %0" : : "r" (insns)); | |
108 | } | |
109 | /* Worst case, ho hum... */ | |
110 | else | |
111 | { | |
112 | unsigned int high32 = (value >> 32); | |
113 | unsigned int low32 = (unsigned int) value; | |
114 | ||
115 | /* ??? Some tricks can be stolen from the sparc64 egcs backend | |
116 | constant formation code I wrote. -DaveM */ | |
117 | ||
a1ffb40e | 118 | if (__glibc_unlikely (high32 & 0x3ff)) |
311927f1 DM |
119 | { |
120 | /* sethi %hh(value), %g1 | |
121 | sethi %lm(value), %g5 | |
122 | or %g1, %hm(value), %g1 | |
123 | or %g5, %lo(value), %g5 | |
124 | sllx %g1, 32, %g1 | |
125 | jmpl %g1 + %g5, %g0 | |
126 | nop */ | |
127 | ||
128 | insns[5] = 0x81c04005; | |
129 | __asm __volatile ("flush %0 + 20" : : "r" (insns)); | |
130 | ||
131 | insns[4] = 0x83287020; | |
132 | __asm __volatile ("flush %0 + 16" : : "r" (insns)); | |
133 | ||
134 | insns[3] = 0x8a116000 | (low32 & 0x3ff); | |
135 | __asm __volatile ("flush %0 + 12" : : "r" (insns)); | |
136 | ||
137 | insns[2] = 0x82106000 | (high32 & 0x3ff); | |
138 | } | |
139 | else | |
140 | { | |
141 | /* sethi %hh(value), %g1 | |
142 | sethi %lm(value), %g5 | |
143 | sllx %g1, 32, %g1 | |
144 | or %g5, %lo(value), %g5 | |
145 | jmpl %g1 + %g5, %g0 | |
146 | nop */ | |
147 | ||
148 | insns[4] = 0x81c04005; | |
149 | __asm __volatile ("flush %0 + 16" : : "r" (insns)); | |
150 | ||
151 | insns[3] = 0x8a116000 | (low32 & 0x3ff); | |
152 | __asm __volatile ("flush %0 + 12" : : "r" (insns)); | |
153 | ||
154 | insns[2] = 0x83287020; | |
155 | } | |
156 | ||
157 | __asm __volatile ("flush %0 + 8" : : "r" (insns)); | |
158 | ||
159 | insns[1] = 0x0b000000 | (low32 >> 10); | |
160 | __asm __volatile ("flush %0 + 4" : : "r" (insns)); | |
161 | ||
162 | insns[0] = 0x03000000 | (high32 >> 10); | |
163 | __asm __volatile ("flush %0" : : "r" (insns)); | |
164 | } | |
165 | } | |
42675c6f DM |
166 | |
167 | #endif /* dl-plt.h */ |