1 | /* RISC-V PLT trampoline |
2 | Copyright (C) 2017-2024 Free Software Foundation, Inc. |
3 | |
4 | This file is part of the GNU C Library. |
5 | |
6 | The GNU C Library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2.1 of the License, or (at your option) any later version. |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Lesser General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library. If not, see |
18 | <https://www.gnu.org/licenses/>. */ |
19 | |
20 | #include <sysdep.h> |
21 | #include <sys/asm.h> |
22 | |
23 | #include "dl-link.h" |
24 | |
25 | /* Assembler veneer called from the PLT header code for lazy loading. |
26 | The PLT header passes its own args in t0-t2. */ |
27 | |
28 | #ifdef __riscv_float_abi_soft |
29 | # define FRAME_SIZE (-((-10 * SZREG) & ALMASK)) |
30 | #else |
31 | # define FRAME_SIZE (-((-10 * SZREG - 8 * SZFREG) & ALMASK)) |
32 | #endif |
33 | |
34 | ENTRY (_dl_runtime_resolve) |
35 | # Save arguments to stack. |
36 | addi sp, sp, -FRAME_SIZE |
37 | REG_S ra, 9*SZREG(sp) |
38 | REG_S a0, 1*SZREG(sp) |
39 | REG_S a1, 2*SZREG(sp) |
40 | REG_S a2, 3*SZREG(sp) |
41 | REG_S a3, 4*SZREG(sp) |
42 | REG_S a4, 5*SZREG(sp) |
43 | REG_S a5, 6*SZREG(sp) |
44 | REG_S a6, 7*SZREG(sp) |
45 | REG_S a7, 8*SZREG(sp) |
46 | |
47 | #ifndef __riscv_float_abi_soft |
48 | FREG_S fa0, (10*SZREG + 0*SZFREG)(sp) |
49 | FREG_S fa1, (10*SZREG + 1*SZFREG)(sp) |
50 | FREG_S fa2, (10*SZREG + 2*SZFREG)(sp) |
51 | FREG_S fa3, (10*SZREG + 3*SZFREG)(sp) |
52 | FREG_S fa4, (10*SZREG + 4*SZFREG)(sp) |
53 | FREG_S fa5, (10*SZREG + 5*SZFREG)(sp) |
54 | FREG_S fa6, (10*SZREG + 6*SZFREG)(sp) |
55 | FREG_S fa7, (10*SZREG + 7*SZFREG)(sp) |
56 | #endif |
57 | |
58 | # Update .got.plt and obtain runtime address of callee. |
59 | slli a1, t1, 1 |
60 | mv a0, t0 # link map |
61 | add a1, a1, t1 # reloc offset (== thrice the .got.plt offset) |
62 | la a2, _dl_fixup |
63 | jalr a2 |
64 | mv t1, a0 |
65 | |
66 | # Restore arguments from stack. |
67 | REG_L ra, 9*SZREG(sp) |
68 | REG_L a0, 1*SZREG(sp) |
69 | REG_L a1, 2*SZREG(sp) |
70 | REG_L a2, 3*SZREG(sp) |
71 | REG_L a3, 4*SZREG(sp) |
72 | REG_L a4, 5*SZREG(sp) |
73 | REG_L a5, 6*SZREG(sp) |
74 | REG_L a6, 7*SZREG(sp) |
75 | REG_L a7, 8*SZREG(sp) |
76 | |
77 | #ifndef __riscv_float_abi_soft |
78 | FREG_L fa0, (10*SZREG + 0*SZFREG)(sp) |
79 | FREG_L fa1, (10*SZREG + 1*SZFREG)(sp) |
80 | FREG_L fa2, (10*SZREG + 2*SZFREG)(sp) |
81 | FREG_L fa3, (10*SZREG + 3*SZFREG)(sp) |
82 | FREG_L fa4, (10*SZREG + 4*SZFREG)(sp) |
83 | FREG_L fa5, (10*SZREG + 5*SZFREG)(sp) |
84 | FREG_L fa6, (10*SZREG + 6*SZFREG)(sp) |
85 | FREG_L fa7, (10*SZREG + 7*SZFREG)(sp) |
86 | #endif |
87 | |
88 | addi sp, sp, FRAME_SIZE |
89 | |
90 | # Invoke the callee. |
91 | jr t1 |
92 | END (_dl_runtime_resolve) |
93 | |
94 | #if !defined PROF && defined SHARED |
95 | ENTRY (_dl_runtime_profile) |
96 | /* RISC-V we get called with: |
97 | t0 linkr_map pointer |
98 | t1 the scaled offset stored in t0, which can be used |
99 | to calculate the offset of the current symbol in .rela.plt |
100 | t2 %hi(%pcrel(.got.plt)) stored in t2, no use in this function |
101 | t3 dl resolver entry point, no use in this function |
102 | |
103 | Stack frame layout with hard float: |
104 | RV64 RV32 |
105 | [sp, #96] [sp, #48] La_riscv_regs |
106 | [sp, #48] [sp, #24] La_riscv_retval |
107 | [sp, #40] [sp, #20] frame size return from pltenter |
108 | [sp, #32] [sp, #16] dl_profile_call saved a1 |
109 | [sp, #24] [sp, #12] dl_profile_call saved a0 |
110 | [sp, #16] [sp, #8] T1 |
111 | [sp, #0] [sp, #0] ra, fp <- fp |
112 | */ |
113 | |
114 | # define OFFSET_T1 2*SZREG |
115 | # define OFFSET_SAVED_CALL_A0 OFFSET_T1 + SZREG |
116 | # define OFFSET_SAVED_CALL_A1 OFFSET_SAVED_CALL_A0 + SZREG |
117 | # define OFFSET_FS OFFSET_SAVED_CALL_A1 + SZREG |
118 | # define OFFSET_RV OFFSET_FS + SZREG |
119 | # define OFFSET_RG OFFSET_RV + DL_SIZEOF_RV |
120 | |
121 | # define SF_SIZE (-(-(OFFSET_RG + DL_SIZEOF_RG) & ALMASK)) |
122 | |
123 | # Save arguments to stack. |
124 | add sp, sp, -SF_SIZE |
125 | REG_S ra, 0(sp) |
126 | REG_S fp, SZREG(sp) |
127 | |
128 | mv fp, sp |
129 | |
130 | REG_S a0, OFFSET_RG + DL_OFFSET_RG_A0 + 0*SZREG(fp) |
131 | REG_S a1, OFFSET_RG + DL_OFFSET_RG_A0 + 1*SZREG(fp) |
132 | REG_S a2, OFFSET_RG + DL_OFFSET_RG_A0 + 2*SZREG(fp) |
133 | REG_S a3, OFFSET_RG + DL_OFFSET_RG_A0 + 3*SZREG(fp) |
134 | REG_S a4, OFFSET_RG + DL_OFFSET_RG_A0 + 4*SZREG(fp) |
135 | REG_S a5, OFFSET_RG + DL_OFFSET_RG_A0 + 5*SZREG(fp) |
136 | REG_S a6, OFFSET_RG + DL_OFFSET_RG_A0 + 6*SZREG(fp) |
137 | REG_S a7, OFFSET_RG + DL_OFFSET_RG_A0 + 7*SZREG(fp) |
138 | |
139 | #ifndef __riscv_float_abi_soft |
140 | FREG_S fa0, OFFSET_RG + DL_OFFSET_RG_FA0 + 0*SZFREG(fp) |
141 | FREG_S fa1, OFFSET_RG + DL_OFFSET_RG_FA0 + 1*SZFREG(fp) |
142 | FREG_S fa2, OFFSET_RG + DL_OFFSET_RG_FA0 + 2*SZFREG(fp) |
143 | FREG_S fa3, OFFSET_RG + DL_OFFSET_RG_FA0 + 3*SZFREG(fp) |
144 | FREG_S fa4, OFFSET_RG + DL_OFFSET_RG_FA0 + 4*SZFREG(fp) |
145 | FREG_S fa5, OFFSET_RG + DL_OFFSET_RG_FA0 + 5*SZFREG(fp) |
146 | FREG_S fa6, OFFSET_RG + DL_OFFSET_RG_FA0 + 6*SZFREG(fp) |
147 | FREG_S fa7, OFFSET_RG + DL_OFFSET_RG_FA0 + 7*SZFREG(fp) |
148 | #endif |
149 | |
150 | # Update .got.plt and obtain runtime address of callee. |
151 | slli a1, t1, 1 |
152 | mv a0, t0 |
153 | add a1, a1, t1 # link map |
154 | mv a2, ra # return addr |
155 | addi a3, fp, OFFSET_RG # La_riscv_regs pointer |
156 | addi a4, fp, OFFSET_FS # frame size return from pltenter |
157 | |
158 | REG_S a0, OFFSET_SAVED_CALL_A0(fp) |
159 | REG_S a1, OFFSET_SAVED_CALL_A1(fp) |
160 | |
161 | la t2, _dl_profile_fixup |
162 | jalr t2 |
163 | |
164 | REG_L t3, OFFSET_FS(fp) |
165 | bgez t3, 1f |
166 | |
167 | # Save the return. |
168 | mv t4, a0 |
169 | |
170 | # Restore arguments from stack. |
171 | REG_L a0, OFFSET_RG + DL_OFFSET_RG_A0 + 0*SZREG(fp) |
172 | REG_L a1, OFFSET_RG + DL_OFFSET_RG_A0 + 1*SZREG(fp) |
173 | REG_L a2, OFFSET_RG + DL_OFFSET_RG_A0 + 2*SZREG(fp) |
174 | REG_L a3, OFFSET_RG + DL_OFFSET_RG_A0 + 3*SZREG(fp) |
175 | REG_L a4, OFFSET_RG + DL_OFFSET_RG_A0 + 4*SZREG(fp) |
176 | REG_L a5, OFFSET_RG + DL_OFFSET_RG_A0 + 5*SZREG(fp) |
177 | REG_L a6, OFFSET_RG + DL_OFFSET_RG_A0 + 6*SZREG(fp) |
178 | REG_L a7, OFFSET_RG + DL_OFFSET_RG_A0 + 7*SZREG(fp) |
179 | |
180 | #ifndef __riscv_float_abi_soft |
181 | FREG_L fa0, OFFSET_RG + DL_OFFSET_RG_FA0 + 0*SZFREG(fp) |
182 | FREG_L fa1, OFFSET_RG + DL_OFFSET_RG_FA0 + 1*SZFREG(fp) |
183 | FREG_L fa2, OFFSET_RG + DL_OFFSET_RG_FA0 + 2*SZFREG(fp) |
184 | FREG_L fa3, OFFSET_RG + DL_OFFSET_RG_FA0 + 3*SZFREG(fp) |
185 | FREG_L fa4, OFFSET_RG + DL_OFFSET_RG_FA0 + 4*SZFREG(fp) |
186 | FREG_L fa5, OFFSET_RG + DL_OFFSET_RG_FA0 + 5*SZFREG(fp) |
187 | FREG_L fa6, OFFSET_RG + DL_OFFSET_RG_FA0 + 6*SZFREG(fp) |
188 | FREG_L fa7, OFFSET_RG + DL_OFFSET_RG_FA0 + 7*SZFREG(fp) |
189 | #endif |
190 | |
191 | REG_L ra, 0(fp) |
192 | REG_L fp, SZREG(fp) |
193 | |
194 | addi sp, sp, SF_SIZE |
195 | jr t4 |
196 | |
197 | 1: |
198 | # The new frame size is in t3. |
199 | sub sp, fp, t3 |
200 | andi sp, sp, ALMASK |
201 | |
202 | REG_S a0, OFFSET_T1(fp) |
203 | |
204 | mv a0, sp |
205 | addi a1, fp, SF_SIZE |
206 | mv a2, t3 |
207 | la t4, memcpy |
208 | jalr t4 |
209 | |
210 | REG_L t4, OFFSET_T1(fp) |
211 | |
212 | # Call the function. |
213 | REG_L a0, OFFSET_RG + DL_OFFSET_RG_A0 + 0*SZREG(fp) |
214 | REG_L a1, OFFSET_RG + DL_OFFSET_RG_A0 + 1*SZREG(fp) |
215 | REG_L a2, OFFSET_RG + DL_OFFSET_RG_A0 + 2*SZREG(fp) |
216 | REG_L a3, OFFSET_RG + DL_OFFSET_RG_A0 + 3*SZREG(fp) |
217 | REG_L a4, OFFSET_RG + DL_OFFSET_RG_A0 + 4*SZREG(fp) |
218 | REG_L a5, OFFSET_RG + DL_OFFSET_RG_A0 + 5*SZREG(fp) |
219 | REG_L a6, OFFSET_RG + DL_OFFSET_RG_A0 + 6*SZREG(fp) |
220 | REG_L a7, OFFSET_RG + DL_OFFSET_RG_A0 + 7*SZREG(fp) |
221 | |
222 | #ifndef __riscv_float_abi_soft |
223 | FREG_L fa0, OFFSET_RG + DL_OFFSET_RG_FA0 + 0*SZFREG(fp) |
224 | FREG_L fa1, OFFSET_RG + DL_OFFSET_RG_FA0 + 1*SZFREG(fp) |
225 | FREG_L fa2, OFFSET_RG + DL_OFFSET_RG_FA0 + 2*SZFREG(fp) |
226 | FREG_L fa3, OFFSET_RG + DL_OFFSET_RG_FA0 + 3*SZFREG(fp) |
227 | FREG_L fa4, OFFSET_RG + DL_OFFSET_RG_FA0 + 4*SZFREG(fp) |
228 | FREG_L fa5, OFFSET_RG + DL_OFFSET_RG_FA0 + 5*SZFREG(fp) |
229 | FREG_L fa6, OFFSET_RG + DL_OFFSET_RG_FA0 + 6*SZFREG(fp) |
230 | FREG_L fa7, OFFSET_RG + DL_OFFSET_RG_FA0 + 7*SZFREG(fp) |
231 | #endif |
232 | jalr t4 |
233 | |
234 | REG_S a0, OFFSET_SAVED_CALL_A0 + DL_OFFSET_RV_A0(fp) |
235 | REG_S a1, OFFSET_SAVED_CALL_A0 + DL_OFFSET_RV_A0 + SZREG(fp) |
236 | |
237 | #ifndef __riscv_float_abi_soft |
238 | FREG_S fa0, OFFSET_SAVED_CALL_A0 + DL_OFFSET_RV_FA0(fp) |
239 | FREG_S fa1, OFFSET_SAVED_CALL_A0 + DL_OFFSET_RV_FA0 + SZFREG(fp) |
240 | #endif |
241 | |
242 | # Setup call to pltexit. |
243 | REG_L a0, OFFSET_SAVED_CALL_A0(fp) |
244 | REG_L a1, OFFSET_SAVED_CALL_A0 + SZREG(fp) |
245 | addi a2, fp, OFFSET_RG |
246 | addi a3, fp, OFFSET_RV |
247 | la t4, _dl_audit_pltexit |
248 | jalr t4 |
249 | |
250 | REG_L a0, OFFSET_RV + DL_OFFSET_RV_A0(fp) |
251 | REG_L a1, OFFSET_RV + DL_OFFSET_RV_A0 + SZREG(fp) |
252 | |
253 | #ifndef __riscv_float_abi_soft |
254 | FREG_L fa0, OFFSET_RV + DL_OFFSET_RV_FA0(fp) |
255 | FREG_L fa1, OFFSET_RV + DL_OFFSET_RV_FA0 + SZFREG(fp) |
256 | #endif |
257 | |
258 | # RA from within La_riscv_reg. |
259 | REG_L ra, OFFSET_RG + DL_OFFSET_RG_RA(fp) |
260 | mv sp, fp |
261 | ADDI sp, sp, SF_SIZE |
262 | REG_S fp, SZREG(fp) |
263 | |
264 | jr ra |
265 | |
266 | END (_dl_runtime_profile) |
267 | #endif /* SHARED */ |
268 | |