]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/s390/s390-64/dl-machine.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / s390 / s390-64 / dl-machine.h
CommitLineData
ffeac417
UD
1/* Machine-dependent ELF dynamic relocation inline functions.
2 64 bit S/390 Version.
04277e02 3 Copyright (C) 2001-2019 Free Software Foundation, Inc.
ffeac417 4 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
847b055c
AJ
5 This file is part of the GNU C Library.
6
7 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
847b055c
AJ
11
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 15 Lesser General Public License for more details.
847b055c 16
41bdb6e2 17 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>. */
847b055c
AJ
20
21#ifndef dl_machine_h
22#define dl_machine_h
1721af3f 23
ffeac417 24#define ELF_MACHINE_NAME "s390x"
847b055c
AJ
25
26#include <sys/param.h>
27#include <string.h>
28#include <link.h>
4603c51e 29#include <sysdeps/s390/dl-procinfo.h>
08f43f9b
AK
30#include <dl-irel.h>
31
32#define ELF_MACHINE_IRELATIVE R_390_IRELATIVE
847b055c 33
9672b937
AJ
34/* This is an older, now obsolete value. */
35#define EM_S390_OLD 0xA390
847b055c 36
ffeac417 37/* Return nonzero iff E_MACHINE is compatible with the running host. */
847b055c 38static inline int
ffeac417 39elf_machine_matches_host (const Elf64_Ehdr *ehdr)
847b055c 40{
ffeac417
UD
41 return (ehdr->e_machine == EM_S390 || ehdr->e_machine == EM_S390_OLD)
42 && ehdr->e_ident[EI_CLASS] == ELFCLASS64;
847b055c
AJ
43}
44
847b055c
AJ
45/* Return the link-time address of _DYNAMIC. Conveniently, this is the
46 first element of the GOT. This must be inlined in a function which
47 uses global data. */
48
ffeac417 49static inline Elf64_Addr
847b055c
AJ
50elf_machine_dynamic (void)
51{
ffeac417 52 register Elf64_Addr *got;
847b055c 53
31cf3942
SL
54 __asm__ ( " larl %0,_GLOBAL_OFFSET_TABLE_\n"
55 : "=&a" (got) : : "0" );
847b055c
AJ
56
57 return *got;
58}
59
847b055c 60/* Return the run-time load address of the shared object. */
ffeac417 61static inline Elf64_Addr
847b055c
AJ
62elf_machine_load_address (void)
63{
ffeac417
UD
64 Elf64_Addr addr;
65
31cf3942
SL
66 __asm__( " larl %0,_dl_start\n"
67 " larl 1,_GLOBAL_OFFSET_TABLE_\n"
68 " lghi 2,_dl_start@GOT\n"
69 " slg %0,0(2,1)"
70 : "=&d" (addr) : : "1", "2" );
847b055c
AJ
71 return addr;
72}
73
74/* Set up the loaded object described by L so its unrelocated PLT
75 entries will jump to the on-demand fixup code in dl-runtime.c. */
76
77static inline int __attribute__ ((unused))
78elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
79{
ffeac417
UD
80 extern void _dl_runtime_resolve (Elf64_Word);
81 extern void _dl_runtime_profile (Elf64_Word);
4603c51e
SL
82#if defined HAVE_S390_VX_ASM_SUPPORT
83 extern void _dl_runtime_resolve_vx (Elf64_Word);
84 extern void _dl_runtime_profile_vx (Elf64_Word);
85#endif
847b055c 86
1721af3f 87 if (l->l_info[DT_JMPREL] && lazy)
847b055c
AJ
88 {
89 /* The GOT entries for functions in the PLT have not yet been filled
90 in. Their initial contents will arrange when called to push an
ffeac417 91 offset into the .rela.plt section, push _GLOBAL_OFFSET_TABLE_[1],
847b055c 92 and then jump to _GLOBAL_OFFSET_TABLE[2]. */
ffeac417
UD
93 Elf64_Addr *got;
94 got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
32e6df36
UD
95 /* If a library is prelinked but we have to relocate anyway,
96 we have to be able to undo the prelinking of .got.plt.
97 The prelinker saved us here address of .plt + 0x2e. */
98 if (got[1])
99 {
100 l->l_mach.plt = got[1] + l->l_addr;
dd8f8da9 101 l->l_mach.jmprel = (const Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]);
32e6df36 102 }
ffeac417 103 got[1] = (Elf64_Addr) l; /* Identify this shared object. */
847b055c
AJ
104
105 /* The got[2] entry contains the address of a function which gets
106 called to get the address of a so far unresolved function and
107 jump to it. The profiling extension of the dynamic linker allows
ffeac417 108 to intercept the calls to collect information. In this case we
847b055c 109 don't store the address in the GOT so that all future calls also
ffeac417 110 end in this function. */
a1ffb40e 111 if (__glibc_unlikely (profile))
847b055c 112 {
4603c51e
SL
113#if defined HAVE_S390_VX_ASM_SUPPORT
114 if (GLRO(dl_hwcap) & HWCAP_S390_VX)
115 got[2] = (Elf64_Addr) &_dl_runtime_profile_vx;
116 else
117 got[2] = (Elf64_Addr) &_dl_runtime_profile;
118#else
ffeac417 119 got[2] = (Elf64_Addr) &_dl_runtime_profile;
4603c51e 120#endif
1721af3f 121
bb38d32c
UD
122 if (GLRO(dl_profile) != NULL
123 && _dl_name_match_p (GLRO(dl_profile), l))
847b055c
AJ
124 /* This is the object we are looking for. Say that we really
125 want profiling and the timers are started. */
5688da55 126 GL(dl_profile_map) = l;
847b055c
AJ
127 }
128 else
4603c51e
SL
129 {
130 /* This function will get called to fix up the GOT entry indicated by
131 the offset on the stack, and then jump to the resolved address. */
132#if defined HAVE_S390_VX_ASM_SUPPORT
133 if (GLRO(dl_hwcap) & HWCAP_S390_VX)
134 got[2] = (Elf64_Addr) &_dl_runtime_resolve_vx;
135 else
136 got[2] = (Elf64_Addr) &_dl_runtime_resolve;
137#else
138 got[2] = (Elf64_Addr) &_dl_runtime_resolve;
139#endif
140 }
847b055c
AJ
141 }
142
143 return lazy;
144}
145
847b055c
AJ
146/* Initial entry point code for the dynamic linker.
147 The C function `_dl_start' is the real entry point;
ffeac417 148 its return value is the user program's entry point. */
847b055c 149
31cf3942 150#define RTLD_START __asm__ ("\n\
847b055c
AJ
151.text\n\
152.align 4\n\
153.globl _start\n\
154.globl _dl_start_user\n\
155_start:\n\
ffeac417 156 lgr %r2,%r15\n\
847b055c 157 # Alloc stack frame\n\
ffeac417 158 aghi %r15,-160\n\
847b055c 159 # Set the back chain to zero\n\
ffeac417 160 xc 0(8,%r15),0(%r15)\n\
847b055c 161 # Call _dl_start with %r2 pointing to arg on stack\n\
ffeac417 162 brasl %r14,_dl_start # call _dl_start\n\
847b055c
AJ
163_dl_start_user:\n\
164 # Save the user entry point address in %r8.\n\
ffeac417 165 lgr %r8,%r2\n\
847b055c 166 # Point %r12 at the GOT.\n\
ffeac417 167 larl %r12,_GLOBAL_OFFSET_TABLE_\n\
847b055c
AJ
168 # See if we were run as a command with the executable file\n\
169 # name as an extra leading argument.\n\
669ed638 170 lghi %r1,_dl_skip_args@GOT\n\
ffeac417
UD
171 lg %r1,0(%r1,%r12)\n\
172 lgf %r1,0(%r1) # load _dl_skip_args\n\
847b055c 173 # Get the original argument count.\n\
ffeac417 174 lg %r0,160(%r15)\n\
847b055c 175 # Subtract _dl_skip_args from it.\n\
ffeac417 176 sgr %r0,%r1\n\
847b055c 177 # Adjust the stack pointer to skip _dl_skip_args words.\n\
ffeac417
UD
178 sllg %r1,%r1,3\n\
179 agr %r15,%r1\n\
847b055c 180 # Set the back chain to zero again\n\
ffeac417 181 xc 0(8,%r15),0(%r15)\n\
847b055c 182 # Store back the modified argument count.\n\
ffeac417 183 stg %r0,160(%r15)\n\
847b055c
AJ
184 # The special initializer gets called with the stack just\n\
185 # as the application's entry point will see it; it can\n\
186 # switch stacks if it moves these contents over.\n\
187" RTLD_START_SPECIAL_INIT "\n\
188 # Call the function to run the initializers.\n\
189 # Load the parameters:\n\
190 # (%r2, %r3, %r4, %r5) = (_dl_loaded, argc, argv, envp)\n\
669ed638 191 lghi %r2,_rtld_local@GOT\n\
ffeac417
UD
192 lg %r2,0(%r2,%r12)\n\
193 lg %r2,0(%r2)\n\
194 lg %r3,160(%r15)\n\
195 la %r4,168(%r15)\n\
196 lgr %r5,%r3\n\
197 sllg %r5,%r5,3\n\
198 la %r5,176(%r5,%r15)\n\
c5684fdb 199 brasl %r14,_dl_init@PLT\n\
847b055c 200 # Pass our finalizer function to the user in %r14, as per ELF ABI.\n\
669ed638 201 lghi %r14,_dl_fini@GOT\n\
ffeac417 202 lg %r14,0(%r14,%r12)\n\
847b055c 203 # Free stack frame\n\
ffeac417 204 aghi %r15,160\n\
847b055c
AJ
205 # Jump to the user's entry point (saved in %r8).\n\
206 br %r8\n\
847b055c
AJ
207");
208
209#ifndef RTLD_START_SPECIAL_INIT
210#define RTLD_START_SPECIAL_INIT /* nothing */
211#endif
212
e6ebd2e4
UD
213/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
214 TLS variable, so undefined references should not be allowed to
215 define the value.
209826bc 216 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
cf5a372e 217 of the main executable's symbols, as for a COPY reloc. */
11bf311e 218#define elf_machine_type_class(type) \
e6ebd2e4
UD
219 ((((type) == R_390_JMP_SLOT || (type) == R_390_TLS_DTPMOD \
220 || (type) == R_390_TLS_DTPOFF || (type) == R_390_TLS_TPOFF) \
221 * ELF_RTYPE_CLASS_PLT) \
222 | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
847b055c
AJ
223
224/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
1721af3f 225#define ELF_MACHINE_JMP_SLOT R_390_JMP_SLOT
847b055c 226
ffeac417 227/* The 64 bit S/390 never uses Elf64_Rel relocations. */
847b055c 228#define ELF_MACHINE_NO_REL 1
4cf5b6d0 229#define ELF_MACHINE_NO_RELA 0
847b055c 230
847b055c
AJ
231/* We define an initialization functions. This is called very early in
232 _dl_sysdep_start. */
233#define DL_PLATFORM_INIT dl_platform_init ()
234
847b055c
AJ
235static inline void __attribute__ ((unused))
236dl_platform_init (void)
237{
afdca0f2 238 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
847b055c 239 /* Avoid an empty string which would disturb us. */
afdca0f2 240 GLRO(dl_platform) = NULL;
847b055c
AJ
241}
242
ffeac417 243static inline Elf64_Addr
847b055c 244elf_machine_fixup_plt (struct link_map *map, lookup_t t,
0572433b 245 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
ffeac417
UD
246 const Elf64_Rela *reloc,
247 Elf64_Addr *reloc_addr, Elf64_Addr value)
847b055c
AJ
248{
249 return *reloc_addr = value;
250}
251
ffeac417
UD
252/* Return the final value of a plt relocation. */
253static inline Elf64_Addr
254elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
255 Elf64_Addr value)
847b055c
AJ
256{
257 return value;
1721af3f 258}
847b055c 259
bb38d32c
UD
260/* Names of the architecture-specific auditing callback functions. */
261#define ARCH_LA_PLTENTER s390_64_gnu_pltenter
262#define ARCH_LA_PLTEXIT s390_64_gnu_pltexit
263
1721af3f 264#endif /* !dl_machine_h */
847b055c 265
bb38d32c 266#ifdef RESOLVE_MAP
847b055c
AJ
267
268/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
269 MAP is the object containing the reloc. */
270
bb38d32c
UD
271auto inline void
272__attribute__ ((always_inline))
ffeac417 273elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
87d254a7 274 const Elf64_Sym *sym, const struct r_found_version *version,
3a62d00d 275 void *const reloc_addr_arg, int skip_ifunc)
847b055c 276{
87d254a7 277 Elf64_Addr *const reloc_addr = reloc_addr_arg;
1721af3f
UD
278 const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
279
e6ebd2e4 280#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
a1ffb40e 281 if (__glibc_unlikely (r_type == R_390_RELATIVE))
e6ebd2e4
UD
282 {
283# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
284 /* This is defined in rtld.c, but nowhere in the static libc.a;
285 make the reference weak so static programs can still link.
286 This declaration cannot be done when compiling rtld.c
287 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
288 common defn for _dl_rtld_map, which is incompatible with a
289 weak decl in the same file. */
290# ifndef SHARED
291 weak_extern (GL(dl_rtld_map));
292# endif
293 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
294# endif
295 *reloc_addr = map->l_addr + reloc->r_addend;
296 }
297 else
847b055c 298#endif
a1ffb40e 299 if (__glibc_unlikely (r_type == R_390_NONE))
e6ebd2e4 300 return;
1721af3f 301 else
847b055c 302 {
47df8251
SL
303#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
304 /* Only needed for R_390_COPY below. */
ffeac417 305 const Elf64_Sym *const refsym = sym;
d347a4ab 306#endif
e6ebd2e4 307 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
10a446dd 308 Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
1721af3f 309
08f43f9b
AK
310 if (sym != NULL
311 && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
312 0)
313 && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
314 && __builtin_expect (!skip_ifunc, 1))
315 value = elf_ifunc_invoke (value);
316
1721af3f 317 switch (r_type)
847b055c 318 {
08f43f9b
AK
319 case R_390_IRELATIVE:
320 value = map->l_addr + reloc->r_addend;
a1ffb40e 321 if (__glibc_likely (!skip_ifunc))
08f43f9b
AK
322 value = elf_ifunc_invoke (value);
323 *reloc_addr = value;
324 break;
ffeac417
UD
325 case R_390_GLOB_DAT:
326 case R_390_JMP_SLOT:
327 *reloc_addr = value + reloc->r_addend;
328 break;
e6ebd2e4 329
d063d164 330#ifndef RESOLVE_CONFLICT_FIND_MAP
e6ebd2e4
UD
331 case R_390_TLS_DTPMOD:
332# ifdef RTLD_BOOTSTRAP
333 /* During startup the dynamic linker is always the module
334 with index 1.
335 XXX If this relocation is necessary move before RESOLVE
336 call. */
337 *reloc_addr = 1;
338# else
339 /* Get the information from the link map returned by the
340 resolv function. */
341 if (sym_map != NULL)
342 *reloc_addr = sym_map->l_tls_modid;
343# endif
344 break;
345 case R_390_TLS_DTPOFF:
346# ifndef RTLD_BOOTSTRAP
347 /* During relocation all TLS symbols are defined and used.
348 Therefore the offset is already correct. */
349 if (sym != NULL)
350 *reloc_addr = sym->st_value + reloc->r_addend;
351# endif
352 break;
353 case R_390_TLS_TPOFF:
354 /* The offset is negative, forward from the thread pointer. */
355# ifdef RTLD_BOOTSTRAP
356 *reloc_addr = sym->st_value + reloc->r_addend - map->l_tls_offset;
357# else
358 /* We know the offset of the object the symbol is contained in.
359 It is a negative value which will be added to the
360 thread pointer. */
361 if (sym != NULL)
362 {
363 CHECK_STATIC_TLS (map, sym_map);
364 *reloc_addr = (sym->st_value + reloc->r_addend
365 - sym_map->l_tls_offset);
366 }
367#endif
368 break;
369#endif /* use TLS */
370
ffeac417 371#ifndef RTLD_BOOTSTRAP
8e27f45e
RM
372# ifndef RESOLVE_CONFLICT_FIND_MAP
373 /* Not needed for dl-conflict.c. */
847b055c
AJ
374 case R_390_COPY:
375 if (sym == NULL)
376 /* This can happen in trace mode if an object could not be
377 found. */
378 break;
379 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
380 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
afdca0f2 381 && __builtin_expect (GLRO(dl_verbose), 0)))
847b055c
AJ
382 {
383 const char *strtab;
384
ffeac417 385 strtab = (const char *) D_PTR (map,l_info[DT_STRTAB]);
35fc382a
UD
386 _dl_error_printf ("\
387%s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 388 RTLD_PROGNAME, strtab + refsym->st_name);
847b055c 389 }
87d254a7
AO
390 memcpy (reloc_addr_arg, (void *) value,
391 MIN (sym->st_size, refsym->st_size));
1721af3f 392 break;
8e27f45e 393# endif
ffeac417
UD
394 case R_390_64:
395 *reloc_addr = value + reloc->r_addend;
847b055c
AJ
396 break;
397 case R_390_32:
ffeac417
UD
398 *(unsigned int *) reloc_addr = value + reloc->r_addend;
399 break;
400 case R_390_16:
401 *(unsigned short *) reloc_addr = value + reloc->r_addend;
402 break;
403 case R_390_8:
404 *(char *) reloc_addr = value + reloc->r_addend;
405 break;
8e27f45e 406# ifndef RESOLVE_CONFLICT_FIND_MAP
ffeac417
UD
407 case R_390_PC64:
408 *reloc_addr = value +reloc->r_addend - (Elf64_Addr) reloc_addr;
409 break;
410 case R_390_PC32DBL:
ffeac417
UD
411 *(unsigned int *) reloc_addr = (unsigned int)
412 ((int) (value + reloc->r_addend - (Elf64_Addr) reloc_addr) >> 1);
413 break;
847b055c 414 case R_390_PC32:
1721af3f 415 *(unsigned int *) reloc_addr =
ffeac417
UD
416 value + reloc->r_addend - (Elf64_Addr) reloc_addr;
417 break;
418 case R_390_PC16DBL:
ffeac417
UD
419 *(unsigned short *) reloc_addr = (unsigned short)
420 ((short) (value + reloc->r_addend - (Elf64_Addr) reloc_addr) >> 1);
847b055c 421 break;
ffeac417 422 case R_390_PC16:
1721af3f 423 *(unsigned short *) reloc_addr =
ffeac417 424 value + reloc->r_addend - (Elf64_Addr) reloc_addr;
847b055c 425 break;
961d4a2e
UD
426 case R_390_NONE:
427 break;
8e27f45e 428# endif
ffeac417
UD
429#endif
430#if !defined(RTLD_BOOTSTRAP) || defined(_NDEBUG)
847b055c 431 default:
ffeac417
UD
432 /* We add these checks in the version to relocate ld.so only
433 if we are still debugging. */
1721af3f 434 _dl_reloc_bad_type (map, r_type, 0);
847b055c 435 break;
ffeac417 436#endif
847b055c
AJ
437 }
438 }
1721af3f
UD
439}
440
bb38d32c
UD
441auto inline void
442__attribute__ ((always_inline))
7c69dc8b 443elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
87d254a7 444 void *const reloc_addr_arg)
1721af3f 445{
87d254a7 446 Elf64_Addr *const reloc_addr = reloc_addr_arg;
1721af3f
UD
447 *reloc_addr = l_addr + reloc->r_addend;
448}
847b055c 449
bb38d32c
UD
450auto inline void
451__attribute__ ((always_inline))
847b055c 452elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
453 Elf64_Addr l_addr, const Elf64_Rela *reloc,
454 int skip_ifunc)
847b055c 455{
ffeac417 456 Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
e6ebd2e4 457 const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
847b055c 458 /* Check for unexpected PLT reloc type. */
a1ffb40e 459 if (__glibc_likely (r_type == R_390_JMP_SLOT))
32e6df36
UD
460 {
461 if (__builtin_expect (map->l_mach.plt, 0) == 0)
462 *reloc_addr += l_addr;
463 else
dd8f8da9 464 *reloc_addr = map->l_mach.plt + (reloc - map->l_mach.jmprel) * 32;
32e6df36 465 }
a1ffb40e 466 else if (__glibc_likely (r_type == R_390_IRELATIVE))
08f43f9b
AK
467 {
468 Elf64_Addr value = map->l_addr + reloc->r_addend;
a1ffb40e 469 if (__glibc_likely (!skip_ifunc))
08f43f9b
AK
470 value = elf_ifunc_invoke (value);
471 *reloc_addr = value;
472 }
847b055c 473 else
1721af3f 474 _dl_reloc_bad_type (map, r_type, 1);
847b055c
AJ
475}
476
bb38d32c 477#endif /* RESOLVE_MAP */