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
34ENTRY (_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
92END (_dl_runtime_resolve)
93
94#if !defined PROF && defined SHARED
95ENTRY (_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
1971:
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
266END (_dl_runtime_profile)
267#endif /* SHARED */
268

source code of glibc/sysdeps/riscv/dl-trampoline.S