Warning: This file is not a C or C++ file. It does not have highlighting.

1/* Machine-dependent ELF dynamic relocation inline functions. RISC-V version.
2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
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
16 License along with the GNU C Library. If not, see
17 <https://www.gnu.org/licenses/>. */
18
19#ifndef dl_machine_h
20#define dl_machine_h
21
22#define ELF_MACHINE_NAME "RISC-V"
23
24#include <entry.h>
25#include <elf/elf.h>
26#include <sys/asm.h>
27#include <dl-tls.h>
28#include <dl-irel.h>
29#include <dl-static-tls.h>
30#include <dl-machine-rel.h>
31
32#ifndef _RTLD_PROLOGUE
33# define _RTLD_PROLOGUE(entry) \
34 ".globl\t" __STRING (entry) "\n\t" \
35 ".type\t" __STRING (entry) ", @function\n" \
36 __STRING (entry) ":\n\t"
37#endif
38
39#ifndef _RTLD_EPILOGUE
40# define _RTLD_EPILOGUE(entry) \
41 ".size\t" __STRING (entry) ", . - " __STRING (entry) "\n\t"
42#endif
43
44#define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT
45
46#define elf_machine_type_class(type) \
47 ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT \
48 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPREL32) \
49 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPMOD32) \
50 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32) \
51 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64) \
52 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64) \
53 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))) \
54 | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
55
56/* Return nonzero iff ELF header is compatible with the running host. */
57static inline int __attribute_used__
58elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
59{
60 /* We can only run RISC-V binaries. */
61 if (ehdr->e_machine != EM_RISCV)
62 return 0;
63
64 /* Ensure the library's floating-point ABI matches that of the running
65 system. For now we don't support mixing XLEN, so there's no need (or way)
66 to check it matches. */
67#ifdef __riscv_float_abi_double
68 if ((ehdr->e_flags & EF_RISCV_FLOAT_ABI) != EF_RISCV_FLOAT_ABI_DOUBLE)
69 return 0;
70#else
71 if ((ehdr->e_flags & EF_RISCV_FLOAT_ABI) != EF_RISCV_FLOAT_ABI_SOFT)
72 return 0;
73#endif
74
75 return 1;
76}
77
78/* Return the run-time load address of the shared object. */
79static inline ElfW(Addr)
80elf_machine_load_address (void)
81{
82 extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
83 return (ElfW(Addr)) &__ehdr_start;
84}
85
86/* Return the link-time address of _DYNAMIC. */
87static inline ElfW(Addr)
88elf_machine_dynamic (void)
89{
90 extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
91 return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
92}
93
94#define STRINGXP(X) __STRING (X)
95#define STRINGXV(X) STRINGV_ (X)
96#define STRINGV_(...) # __VA_ARGS__
97
98/* Initial entry point code for the dynamic linker.
99 The C function `_dl_start' is the real entry point;
100 its return value is the user program's entry point. */
101
102#define RTLD_START asm (\
103 ".text\n\
104 " _RTLD_PROLOGUE (ENTRY_POINT) "\
105 mv a0, sp\n\
106 jal _dl_start\n\
107 " _RTLD_PROLOGUE (_dl_start_user) "\
108 # Stash user entry point in s0.\n\
109 mv s0, a0\n\
110 # See if we were run as a command with the executable file\n\
111 # name as an extra leading argument.\n\
112 lw a0, _dl_skip_args\n\
113 # Load the original argument count.\n\
114 " STRINGXP (REG_L) " a1, 0(sp)\n\
115 # Subtract _dl_skip_args from it.\n\
116 sub a1, a1, a0\n\
117 # Adjust the stack pointer to skip _dl_skip_args words.\n\
118 sll a0, a0, " STRINGXP (PTRLOG) "\n\
119 add sp, sp, a0\n\
120 # Save back the modified argument count.\n\
121 " STRINGXP (REG_S) " a1, 0(sp)\n\
122 # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
123 " STRINGXP (REG_L) " a0, _rtld_local\n\
124 add a2, sp, " STRINGXP (SZREG) "\n\
125 sll a3, a1, " STRINGXP (PTRLOG) "\n\
126 add a3, a3, a2\n\
127 add a3, a3, " STRINGXP (SZREG) "\n\
128 # Stash the stack pointer in s1.\n\
129 mv s1, sp\n\
130 # Align stack to 128 bits for the _dl_init call.\n\
131 andi sp, sp,-16\n\
132 # Call the function to run the initializers.\n\
133 jal _dl_init\n\
134 # Restore the stack pointer for _start.\n\
135 mv sp, s1\n\
136 # Pass our finalizer function to _start.\n\
137 lla a0, _dl_fini\n\
138 # Jump to the user entry point.\n\
139 jr s0\n\
140 " _RTLD_EPILOGUE (ENTRY_POINT) \
141 _RTLD_EPILOGUE (_dl_start_user) "\
142 .previous" \
143);
144
145/* Names of the architecture-specific auditing callback functions. */
146#define ARCH_LA_PLTENTER riscv_gnu_pltenter
147#define ARCH_LA_PLTEXIT riscv_gnu_pltexit
148
149/* Bias .got.plt entry by the offset requested by the PLT header. */
150#define elf_machine_plt_value(map, reloc, value) (value)
151
152static inline ElfW(Addr)
153elf_machine_fixup_plt (struct link_map *map, lookup_t t,
154 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
155 const ElfW(Rela) *reloc,
156 ElfW(Addr) *reloc_addr, ElfW(Addr) value)
157{
158 return *reloc_addr = value;
159}
160
161#endif /* !dl_machine_h */
162
163#ifdef RESOLVE_MAP
164
165/* Perform a relocation described by R_INFO at the location pointed to
166 by RELOC_ADDR. SYM is the relocation symbol specified by R_INFO and
167 MAP is the object containing the reloc. */
168
169static inline void
170__attribute__ ((always_inline))
171elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
172 const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
173 const struct r_found_version *version,
174 void *const reloc_addr, int skip_ifunc)
175{
176 ElfW(Addr) r_info = reloc->r_info;
177 const unsigned long int r_type = ELFW (R_TYPE) (r_info);
178 ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
179 const ElfW(Sym) *const __attribute__ ((unused)) refsym = sym;
180 struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
181 ElfW(Addr) value = 0;
182 if (sym_map != NULL)
183 value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
184
185 if (sym != NULL
186 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
187 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
188 && __glibc_likely (!skip_ifunc))
189 value = elf_ifunc_invoke (value);
190
191
192 switch (r_type)
193 {
194#ifndef RTLD_BOOTSTRAP
195 case __WORDSIZE == 64 ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32:
196 if (sym_map)
197 *addr_field = sym_map->l_tls_modid;
198 break;
199
200 case __WORDSIZE == 64 ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32:
201 if (sym != NULL)
202 *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
203 break;
204
205 case __WORDSIZE == 64 ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32:
206 if (sym != NULL)
207 {
208 CHECK_STATIC_TLS (map, sym_map);
209 *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
210 }
211 break;
212
213 case R_RISCV_COPY:
214 {
215 if (__glibc_unlikely (sym == NULL))
216 /* This can happen in trace mode if an object could not be
217 found. */
218 break;
219
220 /* Handle TLS copy relocations. */
221 if (__glibc_unlikely (ELFW (ST_TYPE) (sym->st_info) == STT_TLS))
222 {
223 /* There's nothing to do if the symbol is in .tbss. */
224 if (__glibc_likely (sym->st_value >= sym_map->l_tls_initimage_size))
225 break;
226 value += (ElfW(Addr)) sym_map->l_tls_initimage - sym_map->l_addr;
227 }
228
229 size_t size = sym->st_size;
230 if (__glibc_unlikely (sym->st_size != refsym->st_size))
231 {
232 const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
233 if (sym->st_size > refsym->st_size)
234 size = refsym->st_size;
235 if (sym->st_size > refsym->st_size || GLRO(dl_verbose))
236 _dl_error_printf ("\
237 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
238 rtld_progname ?: "<program name unknown>",
239 strtab + refsym->st_name);
240 }
241
242 memcpy (reloc_addr, (void *)value, size);
243 break;
244 }
245#endif
246
247#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
248 case R_RISCV_RELATIVE:
249 {
250# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
251 /* This is defined in rtld.c, but nowhere in the static libc.a;
252 make the reference weak so static programs can still link.
253 This declaration cannot be done when compiling rtld.c
254 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
255 common defn for _dl_rtld_map, which is incompatible with a
256 weak decl in the same file. */
257# ifndef SHARED
258 weak_extern (GL(dl_rtld_map));
259# endif
260 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
261# endif
262 *addr_field = map->l_addr + reloc->r_addend;
263 break;
264 }
265#endif
266
267 case R_RISCV_IRELATIVE:
268 value = map->l_addr + reloc->r_addend;
269 if (__glibc_likely (!skip_ifunc))
270 value = elf_ifunc_invoke (value);
271 *addr_field = value;
272 break;
273
274 case R_RISCV_JUMP_SLOT:
275 case __WORDSIZE == 64 ? R_RISCV_64 : R_RISCV_32:
276 *addr_field = value;
277 break;
278
279 case R_RISCV_NONE:
280 break;
281
282 default:
283 _dl_reloc_bad_type (map, r_type, 0);
284 break;
285 }
286}
287
288static inline void
289__attribute__ ((always_inline))
290elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
291 void *const reloc_addr)
292{
293 *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
294}
295
296static inline void
297__attribute__ ((always_inline))
298elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
299 ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
300 int skip_ifunc)
301{
302 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
303 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
304
305 /* Check for unexpected PLT reloc type. */
306 if (__glibc_likely (r_type == R_RISCV_JUMP_SLOT))
307 {
308 if (__glibc_unlikely (map->l_mach.plt == 0))
309 {
310 if (l_addr)
311 *reloc_addr += l_addr;
312 }
313 else
314 *reloc_addr = map->l_mach.plt;
315 }
316 else if (__glibc_unlikely (r_type == R_RISCV_IRELATIVE))
317 {
318 ElfW(Addr) value = map->l_addr + reloc->r_addend;
319 if (__glibc_likely (!skip_ifunc))
320 value = elf_ifunc_invoke (value);
321 *reloc_addr = value;
322 }
323 else
324 _dl_reloc_bad_type (map, r_type, 1);
325}
326
327/* Set up the loaded object described by L so its stub function
328 will jump to the on-demand fixup code __dl_runtime_resolve. */
329
330static inline int
331__attribute__ ((always_inline))
332elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
333 int lazy, int profile)
334{
335#ifndef RTLD_BOOTSTRAP
336 /* If using PLTs, fill in the first two entries of .got.plt. */
337 if (l->l_info[DT_JMPREL])
338 {
339 extern void _dl_runtime_resolve (void) __attribute__ ((visibility ("hidden")));
340 ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
341 /* If a library is prelinked but we have to relocate anyway,
342 we have to be able to undo the prelinking of .got.plt.
343 The prelinker saved the address of .plt for us here. */
344 if (gotplt[1])
345 l->l_mach.plt = gotplt[1] + l->l_addr;
346 gotplt[0] = (ElfW(Addr)) &_dl_runtime_resolve;
347 gotplt[1] = (ElfW(Addr)) l;
348 }
349
350 if (l->l_type == lt_executable)
351 {
352 /* The __global_pointer$ may not be defined by the linker if the
353 $gp register does not be used to access the global variable
354 in the executable program. Therefore, the search symbol is
355 set to a weak symbol to avoid we error out if the
356 __global_pointer$ is not found. */
357 ElfW(Sym) gp_sym = { 0 };
358 gp_sym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE));
359
360 const ElfW(Sym) *ref = &gp_sym;
361 _dl_lookup_symbol_x ("__global_pointer$", l, &ref,
362 l->l_scope, NULL, 0, 0, NULL);
363 if (ref)
364 asm (
365 "mv gp, %0\n"
366 :
367 : "r" (ref->st_value)
368 );
369 }
370#endif
371 return lazy;
372}
373
374#endif /* RESOLVE_MAP */
375

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of glibc/sysdeps/riscv/dl-machine.h