]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/sh/dl-machine.h
po: Update translations
[thirdparty/glibc.git] / sysdeps / sh / dl-machine.h
CommitLineData
65074d23 1/* Machine-dependent ELF dynamic relocation inline functions. SH version.
dff8da6b 2 Copyright (C) 1999-2024 Free Software Foundation, Inc.
65074d23
UD
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
41bdb6e2
AJ
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.
65074d23
UD
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
41bdb6e2
AJ
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
65074d23 14
41bdb6e2 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/>. */
65074d23
UD
18
19#ifndef dl_machine_h
20#define dl_machine_h
21
65074d23
UD
22#define ELF_MACHINE_NAME "SH"
23
24#include <sys/param.h>
c2a4357a 25#include <sysdep.h>
65074d23 26#include <assert.h>
d6d89608
AZ
27#include <dl-static-tls.h>
28#include <dl-machine-rel.h>
65074d23 29
ceb579a3 30/* Return nonzero iff ELF header is compatible with the running host. */
65074d23 31static inline int __attribute__ ((unused))
ceb579a3 32elf_machine_matches_host (const Elf32_Ehdr *ehdr)
65074d23 33{
ceb579a3 34 return ehdr->e_machine == EM_SH;
65074d23
UD
35}
36
37
38/* Return the link-time address of _DYNAMIC. Conveniently, this is the
39 first element of the GOT. This must be inlined in a function which
40 uses global data. */
41static inline Elf32_Addr __attribute__ ((unused))
42elf_machine_dynamic (void)
43{
44 register Elf32_Addr *got;
45 asm ("mov r12,%0" :"=r" (got));
46 return *got;
47}
48
49
50/* Return the run-time load address of the shared object. */
51static inline Elf32_Addr __attribute__ ((unused))
52elf_machine_load_address (void)
53{
54 Elf32_Addr addr;
e438a468
UD
55 asm ("mov.l 1f,r0\n\
56 mov.l 3f,r2\n\
045fcd26
UD
57 add r12,r2\n\
58 mov.l @(r0,r12),r0\n\
e438a468 59 bra 2f\n\
045fcd26
UD
60 sub r0,r2\n\
61 .align 2\n\
e438a468
UD
62 1: .long _dl_start@GOT\n\
63 3: .long _dl_start@GOTOFF\n\
64 2: mov r2,%0"
65074d23
UD
65 : "=r" (addr) : : "r0", "r1", "r2");
66 return addr;
67}
68
69
70/* Set up the loaded object described by L so its unrelocated PLT
71 entries will jump to the on-demand fixup code in dl-runtime.c. */
72
c2a4357a 73static inline int __attribute__ ((unused, always_inline))
490e6c62
FS
74elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
75 int lazy, int profile)
65074d23
UD
76{
77 Elf32_Addr *got;
78 extern void _dl_runtime_resolve (Elf32_Word);
79 extern void _dl_runtime_profile (Elf32_Word);
80
81 if (l->l_info[DT_JMPREL] && lazy)
82 {
83 /* The GOT entries for functions in the PLT have not yet been filled
84 in. Their initial contents will arrange when called to load an
85 offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
86 and then jump to _GLOBAL_OFFSET_TABLE[2]. */
87 got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
32e6df36
UD
88 /* If a library is prelinked but we have to relocate anyway,
89 we have to be able to undo the prelinking of .got.plt.
90 The prelinker saved us here address of .plt + 36. */
91 if (got[1])
92 {
93 l->l_mach.plt = got[1] + l->l_addr;
94 l->l_mach.gotplt = (Elf32_Addr) &got[3];
95 }
65074d23
UD
96 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
97
98 /* The got[2] entry contains the address of a function which gets
99 called to get the address of a so far unresolved function and
100 jump to it. The profiling extension of the dynamic linker allows
101 to intercept the calls to collect information. In this case we
102 don't store the address in the GOT so that all future calls also
103 end in this function. */
55f41ef8 104#ifdef SHARED
65074d23
UD
105 if (profile)
106 {
107 got[2] = (Elf32_Addr) &_dl_runtime_profile;
108 /* Say that we really want profiling and the timers are started. */
537e7234
UD
109 if (GLRO(dl_profile) != NULL
110 && _dl_name_match_p (GLRO(dl_profile), l))
111 GL(dl_profile_map) = l;
65074d23
UD
112 }
113 else
55f41ef8 114#endif
65074d23
UD
115 /* This function will get called to fix up the GOT entry indicated by
116 the offset on the stack, and then jump to the resolved address. */
117 got[2] = (Elf32_Addr) &_dl_runtime_resolve;
118 }
119 return lazy;
120}
121
65074d23 122#define ELF_MACHINE_RUNTIME_FIXUP_ARGS int plt_type
d072f3f7 123#define ELF_MACHINE_RUNTIME_FIXUP_PARAMS plt_type
65074d23 124
65074d23
UD
125/* Mask identifying addresses reserved for the user program,
126 where the dynamic linker should not map anything. */
127#define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
128
129/* Initial entry point code for the dynamic linker.
130 The C function `_dl_start' is the real entry point;
131 its return value is the user program's entry point. */
132
133#define RTLD_START asm ("\
134.text\n\
135.globl _start\n\
136.globl _dl_start_user\n\
137_start:\n\
138 mov r15,r4\n\
139 mov.l .L_dl_start,r1\n\
140 mova .L_dl_start,r0\n\
141 add r1,r0\n\
142 jsr @r0\n\
143 nop\n\
144_dl_start_user:\n\
145 ! Save the user entry point address in r8.\n\
146 mov r0,r8\n\
147 ! Point r12 at the GOT.\n\
148 mov.l 1f,r12\n\
149 mova 1f,r0\n\
150 bra 2f\n\
151 add r0,r12\n\
152 .align 2\n\
1531: .long _GLOBAL_OFFSET_TABLE_\n\
4dc1f653 1542: ! Get the original argument count.\n\
65074d23 155 mov.l @r15,r5\n\
65074d23
UD
156 ! Compute argv address and envp.\n\
157 mov r15,r6\n\
158 add #4,r6\n\
159 mov r5,r7\n\
160 shll2 r7\n\
161 add r15,r7\n\
c2a4357a 162 add #8,r7\n\
65074d23
UD
163 mov.l .L_dl_loaded,r0\n\
164 mov.l @(r0,r12),r0\n\
165 mov.l @r0,r4\n\
166 ! Call _dl_init.\n\
167 mov.l .L_dl_init,r1\n\
168 mova .L_dl_init,r0\n\
169 add r1,r0\n\
170 jsr @r0\n\
171 nop\n\
6c1232e2 1721: ! Pass our finalizer function to the user in r4, as per ELF ABI.\n\
65074d23
UD
173 mov.l .L_dl_fini,r0\n\
174 mov.l @(r0,r12),r4\n\
175 ! Jump to the user's entry point.\n\
176 jmp @r8\n\
177 nop\n\
178 .align 2\n\
179.L_dl_start:\n\
180 .long _dl_start@PLT\n\
65074d23 181.L_dl_init:\n\
c5684fdb 182 .long _dl_init@PLT\n\
65074d23 183.L_dl_loaded:\n\
0d01dace 184 .long _rtld_local@GOT\n\
65074d23
UD
185.L_dl_fini:\n\
186 .long _dl_fini@GOT\n\
537e7234
UD
187 .type __fpscr_values,@object\n\
188 .global __fpscr_values\n\
189__fpscr_values:\n\
190 .long 0\n\
191 .long 0x80000\n\
192 .weak __fpscr_values\n\
65074d23
UD
193.previous\n\
194");
195
3632a260
UD
196/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
197 TLS variable, so undefined references should not be allowed to
198 define the value.
209826bc 199 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
cf5a372e 200 of the main executable's symbols, as for a COPY reloc. */
d063d164 201#define elf_machine_type_class(type) \
3632a260
UD
202 ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32 \
203 || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32) \
204 * ELF_RTYPE_CLASS_PLT) \
205 | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
65074d23
UD
206
207/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
208#define ELF_MACHINE_JMP_SLOT R_SH_JMP_SLOT
209
210/* We define an initialization functions. This is called very early in
211 _dl_sysdep_start. */
212#define DL_PLATFORM_INIT dl_platform_init ()
213
65074d23
UD
214static inline void __attribute__ ((unused))
215dl_platform_init (void)
216{
d3a4a571 217 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
65074d23 218 /* Avoid an empty string which would disturb us. */
d3a4a571 219 GLRO(dl_platform) = NULL;
65074d23
UD
220}
221
222static inline Elf32_Addr
223elf_machine_fixup_plt (struct link_map *map, lookup_t t,
0572433b 224 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
65074d23
UD
225 const Elf32_Rela *reloc,
226 Elf32_Addr *reloc_addr, Elf32_Addr value)
227{
228 return *reloc_addr = value;
229}
230
231/* Return the final value of a plt relocation. */
232static inline Elf32_Addr
233elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
234 Elf32_Addr value)
235{
236 return value + reloc->r_addend;
237}
238
537e7234
UD
239#define ARCH_LA_PLTENTER sh_gnu_pltenter
240#define ARCH_LA_PLTEXIT sh_gnu_pltexit
241
0ecb606c 242#endif /* !dl_machine_h */
65074d23 243
9cfe5381
RM
244#ifdef RESOLVE_MAP
245
65074d23
UD
246/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
247 MAP is the object containing the reloc. */
248
490e6c62 249static inline void
c2a4357a 250__attribute ((always_inline))
490e6c62
FS
251elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
252 const Elf32_Rela *reloc, const Elf32_Sym *sym,
253 const struct r_found_version *version,
3a62d00d 254 void *const reloc_addr_arg, int skip_ifunc)
65074d23 255{
87d254a7 256 Elf32_Addr *const reloc_addr = reloc_addr_arg;
1721af3f 257 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
045fcd26
UD
258 Elf32_Addr value;
259
87d254a7 260#define COPY_UNALIGNED_WORD(swp, twp, align) \
045fcd26 261 { \
87d254a7 262 void *__s = (swp), *__t = (twp); \
d3a4a571
UD
263 unsigned char *__s1 = __s, *__t1 = __t; \
264 unsigned short *__s2 = __s, *__t2 = __t; \
265 unsigned long *__s4 = __s, *__t4 = __t; \
045fcd26
UD
266 switch ((align)) \
267 { \
268 case 0: \
d3a4a571 269 *__t4 = *__s4; \
045fcd26
UD
270 break; \
271 case 2: \
d3a4a571
UD
272 *__t2++ = *__s2++; \
273 *__t2 = *__s2; \
045fcd26
UD
274 break; \
275 default: \
d3a4a571
UD
276 *__t1++ = *__s1++; \
277 *__t1++ = *__s1++; \
278 *__t1++ = *__s1++; \
279 *__t1 = *__s1; \
045fcd26
UD
280 break; \
281 } \
282 }
283
a1ffb40e 284 if (__glibc_unlikely (r_type == R_SH_RELATIVE))
65074d23
UD
285 {
286#ifndef RTLD_BOOTSTRAP
5688da55 287 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
65074d23 288#endif
876f9634
UD
289 {
290 if (reloc->r_addend)
045fcd26 291 value = map->l_addr + reloc->r_addend;
876f9634 292 else
045fcd26 293 {
87d254a7
AO
294 COPY_UNALIGNED_WORD (reloc_addr_arg, &value,
295 (int) reloc_addr_arg & 3);
045fcd26
UD
296 value += map->l_addr;
297 }
87d254a7
AO
298 COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
299 (int) reloc_addr_arg & 3);
876f9634 300 }
65074d23 301 }
1721af3f 302#ifndef RTLD_BOOTSTRAP
a1ffb40e 303 else if (__glibc_unlikely (r_type == R_SH_NONE))
1721af3f
UD
304 return;
305#endif
306 else
65074d23
UD
307 {
308 const Elf32_Sym *const refsym = sym;
490e6c62
FS
309 struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
310 r_type);
045fcd26 311
10a446dd 312 value = SYMBOL_ADDRESS (sym_map, sym, true);
65074d23
UD
313 value += reloc->r_addend;
314
3632a260 315 switch (r_type)
65074d23
UD
316 {
317 case R_SH_COPY:
318 if (sym == NULL)
319 /* This can happen in trace mode if an object could not be
320 found. */
321 break;
322 if (sym->st_size > refsym->st_size
d3a4a571 323 || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
65074d23
UD
324 {
325 const char *strtab;
326
327 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
35fc382a 328 _dl_error_printf ("\
729399c3 329%s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 330 RTLD_PROGNAME, strtab + refsym->st_name);
65074d23 331 }
87d254a7
AO
332 memcpy (reloc_addr_arg, (void *) value,
333 MIN (sym->st_size, refsym->st_size));
65074d23
UD
334 break;
335 case R_SH_GLOB_DAT:
336 case R_SH_JMP_SLOT:
045fcd26 337 /* These addresses are always aligned. */
65074d23
UD
338 *reloc_addr = value;
339 break;
3632a260
UD
340 /* XXX Remove TLS relocations which are not needed. */
341 case R_SH_TLS_DTPMOD32:
d063d164 342#ifdef RTLD_BOOTSTRAP
3632a260
UD
343 /* During startup the dynamic linker is always the module
344 with index 1.
345 XXX If this relocation is necessary move before RESOLVE
346 call. */
347 *reloc_addr = 1;
d063d164 348#else
3632a260
UD
349 /* Get the information from the link map returned by the
350 resolv function. */
351 if (sym_map != NULL)
352 *reloc_addr = sym_map->l_tls_modid;
d063d164 353#endif
3632a260
UD
354 break;
355 case R_SH_TLS_DTPOFF32:
d063d164 356#ifndef RTLD_BOOTSTRAP
3632a260
UD
357 /* During relocation all TLS symbols are defined and used.
358 Therefore the offset is already correct. */
359 if (sym != NULL)
360 *reloc_addr = sym->st_value;
d063d164 361#endif
3632a260
UD
362 break;
363 case R_SH_TLS_TPOFF32:
364 /* The offset is positive, afterward from the thread pointer. */
d063d164 365#ifdef RTLD_BOOTSTRAP
aa298c08 366 *reloc_addr = map->l_tls_offset + sym->st_value + reloc->r_addend;
d063d164 367#else
3632a260
UD
368 /* We know the offset of object the symbol is contained in.
369 It is a positive value which will be added to the thread
370 pointer. To get the variable position in the TLS block
371 we add the offset from that of the TLS block. */
d40eb37a
UD
372 if (sym != NULL)
373 {
374 CHECK_STATIC_TLS (map, sym_map);
375 *reloc_addr = sym_map->l_tls_offset + sym->st_value
376 + reloc->r_addend;
377 }
d063d164 378#endif
3632a260 379 break;
65074d23
UD
380 case R_SH_DIR32:
381 {
6628c742 382#if !defined RTLD_BOOTSTRAP
65074d23
UD
383 /* This is defined in rtld.c, but nowhere in the static
384 libc.a; make the reference weak so static programs can
385 still link. This declaration cannot be done when
386 compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP) because
387 rtld.c contains the common defn for _dl_rtld_map, which
388 is incompatible with a weak decl in the same file. */
5688da55 389# ifndef SHARED
d3a4a571 390 weak_extern (_dl_rtld_map);
5688da55
UD
391# endif
392 if (map == &GL(dl_rtld_map))
65074d23
UD
393 /* Undo the relocation done here during bootstrapping.
394 Now we will relocate it anew, possibly using a
395 binding found in the user program or a loaded library
396 rather than the dynamic linker's built-in definitions
397 used while loading those libraries. */
10a446dd 398 value -= SYMBOL_ADDRESS (map, refsym, true) + reloc->r_addend;
65074d23 399#endif
87d254a7
AO
400 COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
401 (int) reloc_addr_arg & 3);
65074d23
UD
402 break;
403 }
404 case R_SH_REL32:
045fcd26 405 value = (value - (Elf32_Addr) reloc_addr);
87d254a7
AO
406 COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
407 (int) reloc_addr_arg & 3);
65074d23
UD
408 break;
409 default:
3632a260 410 _dl_reloc_bad_type (map, r_type, 0);
65074d23
UD
411 break;
412 }
413 }
1721af3f
UD
414}
415
490e6c62 416static inline void
c2a4357a 417__attribute__ ((always_inline))
1f2a1df3 418elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
87d254a7 419 void *const reloc_addr_arg)
1721af3f 420{
9596d0dd
UD
421 Elf32_Addr value;
422
1721af3f
UD
423 if (reloc->r_addend)
424 value = l_addr + reloc->r_addend;
425 else
426 {
87d254a7 427 COPY_UNALIGNED_WORD (reloc_addr_arg, &value, (int) reloc_addr_arg & 3);
1721af3f
UD
428 value += l_addr;
429 }
87d254a7 430 COPY_UNALIGNED_WORD (&value, reloc_addr_arg, (int) reloc_addr_arg & 3);
045fcd26
UD
431
432#undef COPY_UNALIGNED_WORD
65074d23
UD
433}
434
490e6c62 435static inline void
c2a4357a 436__attribute__ ((always_inline))
490e6c62 437elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
3a62d00d
AS
438 Elf32_Addr l_addr, const Elf32_Rela *reloc,
439 int skip_ifunc)
65074d23
UD
440{
441 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
442 /* Check for unexpected PLT reloc type. */
443 if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
32e6df36
UD
444 {
445 if (__builtin_expect (map->l_mach.plt, 0) == 0)
446 *reloc_addr += l_addr;
447 else
448 *reloc_addr =
449 map->l_mach.plt
450 + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 7;
451 }
65074d23
UD
452 else
453 _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
454}
455
537e7234 456#endif /* RESOLVE_MAP */