]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/riscv/dl-machine.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / riscv / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions. RISC-V version.
2 Copyright (C) 2011-2019 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 <http://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
29 #ifndef _RTLD_PROLOGUE
30 # define _RTLD_PROLOGUE(entry) \
31 ".globl\t" __STRING (entry) "\n\t" \
32 ".type\t" __STRING (entry) ", @function\n" \
33 __STRING (entry) ":\n\t"
34 #endif
35
36 #ifndef _RTLD_EPILOGUE
37 # define _RTLD_EPILOGUE(entry) \
38 ".size\t" __STRING (entry) ", . - " __STRING (entry) "\n\t"
39 #endif
40
41 #define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT
42
43 #define elf_machine_type_class(type) \
44 ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT \
45 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPREL32) \
46 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPMOD32) \
47 || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32) \
48 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64) \
49 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64) \
50 || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))) \
51 | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
52
53 #define ELF_MACHINE_NO_REL 1
54 #define ELF_MACHINE_NO_RELA 0
55
56 /* Return nonzero iff ELF header is compatible with the running host. */
57 static inline int __attribute_used__
58 elf_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 link-time address of _DYNAMIC. */
79 static inline ElfW(Addr)
80 elf_machine_dynamic (void)
81 {
82 extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__ ((visibility ("hidden")));
83 return _GLOBAL_OFFSET_TABLE_;
84 }
85
86 #define STRINGXP(X) __STRING (X)
87 #define STRINGXV(X) STRINGV_ (X)
88 #define STRINGV_(...) # __VA_ARGS__
89
90 /* Return the run-time load address of the shared object. */
91 static inline ElfW(Addr)
92 elf_machine_load_address (void)
93 {
94 ElfW(Addr) load_addr;
95 asm ("lla %0, _DYNAMIC" : "=r" (load_addr));
96 return load_addr - elf_machine_dynamic ();
97 }
98
99 /* Initial entry point code for the dynamic linker.
100 The C function `_dl_start' is the real entry point;
101 its return value is the user program's entry point. */
102
103 #define RTLD_START asm (\
104 ".text\n\
105 " _RTLD_PROLOGUE (ENTRY_POINT) "\
106 mv a0, sp\n\
107 jal _dl_start\n\
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 # Call the function to run the initializers.\n\
129 jal _dl_init\n\
130 # Pass our finalizer function to _start.\n\
131 lla a0, _dl_fini\n\
132 # Jump to the user entry point.\n\
133 jr s0\n\
134 " _RTLD_EPILOGUE (ENTRY_POINT) "\
135 .previous" \
136 );
137
138 /* Names of the architecture-specific auditing callback functions. */
139 #define ARCH_LA_PLTENTER riscv_gnu_pltenter
140 #define ARCH_LA_PLTEXIT riscv_gnu_pltexit
141
142 /* Bias .got.plt entry by the offset requested by the PLT header. */
143 #define elf_machine_plt_value(map, reloc, value) (value)
144
145 static inline ElfW(Addr)
146 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
147 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
148 const ElfW(Rela) *reloc,
149 ElfW(Addr) *reloc_addr, ElfW(Addr) value)
150 {
151 return *reloc_addr = value;
152 }
153
154 #endif /* !dl_machine_h */
155
156 #ifdef RESOLVE_MAP
157
158 /* Perform a relocation described by R_INFO at the location pointed to
159 by RELOC_ADDR. SYM is the relocation symbol specified by R_INFO and
160 MAP is the object containing the reloc. */
161
162 auto inline void
163 __attribute__ ((always_inline))
164 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
165 const ElfW(Sym) *sym, const struct r_found_version *version,
166 void *const reloc_addr, int skip_ifunc)
167 {
168 ElfW(Addr) r_info = reloc->r_info;
169 const unsigned long int r_type = ELFW (R_TYPE) (r_info);
170 ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
171 const ElfW(Sym) *const __attribute__ ((unused)) refsym = sym;
172 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
173 ElfW(Addr) value = 0;
174 if (sym_map != NULL)
175 value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
176
177 switch (r_type)
178 {
179 #ifndef RTLD_BOOTSTRAP
180 case __WORDSIZE == 64 ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32:
181 if (sym_map)
182 *addr_field = sym_map->l_tls_modid;
183 break;
184
185 case __WORDSIZE == 64 ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32:
186 if (sym != NULL)
187 *addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
188 break;
189
190 case __WORDSIZE == 64 ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32:
191 if (sym != NULL)
192 {
193 CHECK_STATIC_TLS (map, sym_map);
194 *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
195 }
196 break;
197
198 case R_RISCV_COPY:
199 {
200 if (__glibc_unlikely (sym == NULL))
201 /* This can happen in trace mode if an object could not be
202 found. */
203 break;
204
205 /* Handle TLS copy relocations. */
206 if (__glibc_unlikely (ELFW (ST_TYPE) (sym->st_info) == STT_TLS))
207 {
208 /* There's nothing to do if the symbol is in .tbss. */
209 if (__glibc_likely (sym->st_value >= sym_map->l_tls_initimage_size))
210 break;
211 value += (ElfW(Addr)) sym_map->l_tls_initimage - sym_map->l_addr;
212 }
213
214 size_t size = sym->st_size;
215 if (__glibc_unlikely (sym->st_size != refsym->st_size))
216 {
217 const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
218 if (sym->st_size > refsym->st_size)
219 size = refsym->st_size;
220 if (sym->st_size > refsym->st_size || GLRO(dl_verbose))
221 _dl_error_printf ("\
222 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
223 rtld_progname ?: "<program name unknown>",
224 strtab + refsym->st_name);
225 }
226
227 memcpy (reloc_addr, (void *)value, size);
228 break;
229 }
230 #endif
231
232 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
233 case R_RISCV_RELATIVE:
234 {
235 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
236 /* This is defined in rtld.c, but nowhere in the static libc.a;
237 make the reference weak so static programs can still link.
238 This declaration cannot be done when compiling rtld.c
239 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
240 common defn for _dl_rtld_map, which is incompatible with a
241 weak decl in the same file. */
242 # ifndef SHARED
243 weak_extern (GL(dl_rtld_map));
244 # endif
245 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
246 # endif
247 *addr_field = map->l_addr + reloc->r_addend;
248 break;
249 }
250 #endif
251
252 case R_RISCV_JUMP_SLOT:
253 case __WORDSIZE == 64 ? R_RISCV_64 : R_RISCV_32:
254 *addr_field = value;
255 break;
256
257 case R_RISCV_NONE:
258 break;
259
260 default:
261 _dl_reloc_bad_type (map, r_type, 0);
262 break;
263 }
264 }
265
266 auto inline void
267 __attribute__ ((always_inline))
268 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
269 void *const reloc_addr)
270 {
271 *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
272 }
273
274 auto inline void
275 __attribute__ ((always_inline))
276 elf_machine_lazy_rel (struct link_map *map, ElfW(Addr) l_addr,
277 const ElfW(Rela) *reloc, int skip_ifunc)
278 {
279 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
280 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
281
282 /* Check for unexpected PLT reloc type. */
283 if (__glibc_likely (r_type == R_RISCV_JUMP_SLOT))
284 {
285 if (__glibc_unlikely (map->l_mach.plt == 0))
286 {
287 if (l_addr)
288 *reloc_addr += l_addr;
289 }
290 else
291 *reloc_addr = map->l_mach.plt;
292 }
293 else
294 _dl_reloc_bad_type (map, r_type, 1);
295 }
296
297 /* Set up the loaded object described by L so its stub function
298 will jump to the on-demand fixup code __dl_runtime_resolve. */
299
300 auto inline int
301 __attribute__ ((always_inline))
302 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
303 {
304 #ifndef RTLD_BOOTSTRAP
305 /* If using PLTs, fill in the first two entries of .got.plt. */
306 if (l->l_info[DT_JMPREL])
307 {
308 extern void _dl_runtime_resolve (void) __attribute__ ((visibility ("hidden")));
309 ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
310 /* If a library is prelinked but we have to relocate anyway,
311 we have to be able to undo the prelinking of .got.plt.
312 The prelinker saved the address of .plt for us here. */
313 if (gotplt[1])
314 l->l_mach.plt = gotplt[1] + l->l_addr;
315 gotplt[0] = (ElfW(Addr)) &_dl_runtime_resolve;
316 gotplt[1] = (ElfW(Addr)) l;
317 }
318 #endif
319
320 return lazy;
321 }
322
323 #endif /* RESOLVE_MAP */