]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/i386/dl-machine.h
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / i386 / dl-machine.h
CommitLineData
d66e34cd 1/* Machine-dependent ELF dynamic relocation inline functions. i386 version.
2b778ceb 2 Copyright (C) 1995-2021 Free Software Foundation, Inc.
47707456 3 This file is part of the GNU C Library.
d66e34cd 4
47707456 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.
d66e34cd 9
47707456
UD
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
41bdb6e2 13 Lesser General Public License for more details.
d66e34cd 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/>. */
d66e34cd 18
f51d1dfd
RM
19#ifndef dl_machine_h
20#define dl_machine_h
21
d66e34cd
RM
22#define ELF_MACHINE_NAME "i386"
23
1f07e617 24#include <sys/param.h>
7b09d09d 25#include <sysdep.h>
2e36cb48 26#include <tls.h>
c9ff0187 27#include <dl-tlsdesc.h>
2e36cb48 28
ceb579a3 29/* Return nonzero iff ELF header is compatible with the running host. */
e75154a6 30static inline int __attribute__ ((unused))
ceb579a3 31elf_machine_matches_host (const Elf32_Ehdr *ehdr)
d66e34cd 32{
ceb579a3 33 return ehdr->e_machine == EM_386;
d66e34cd
RM
34}
35
36
6ce3881d
RM
37/* Return the link-time address of _DYNAMIC. Conveniently, this is the
38 first element of the GOT, a special entry that is never relocated. */
39static inline Elf32_Addr __attribute__ ((unused, const))
40elf_machine_dynamic (void)
41{
42 /* This produces a GOTOFF reloc that resolves to zero at link time, so in
43 fact just loads from the GOT register directly. By doing it without
44 an asm we can let the compiler choose any register. */
45 extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
46 return _GLOBAL_OFFSET_TABLE_[0];
47}
48
49/* Return the run-time load address of the shared object. */
50static inline Elf32_Addr __attribute__ ((unused))
51elf_machine_load_address (void)
52{
53 /* Compute the difference between the runtime address of _DYNAMIC as seen
54 by a GOTOFF reference, and the link-time address found in the special
55 unrelocated first GOT entry. */
02d2d892
L
56 extern Elf32_Dyn bygotoff[] asm ("_DYNAMIC") attribute_hidden;
57 return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();
6ce3881d
RM
58}
59
d66e34cd
RM
60/* Set up the loaded object described by L so its unrelocated PLT
61 entries will jump to the on-demand fixup code in dl-runtime.c. */
62
9c7ff11a 63static inline int __attribute__ ((unused, always_inline))
3996f34b 64elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
d66e34cd 65{
a1a9d215 66 Elf32_Addr *got;
5c82e15e
UD
67 extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
68 extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
7b1f9406
L
69 extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
70 extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
71 /* Check if SHSTK is enabled by kernel. */
72 bool shstk_enabled
674ea882 73 = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
a1a9d215 74
a2e1b046
RM
75 if (l->l_info[DT_JMPREL] && lazy)
76 {
77 /* The GOT entries for functions in the PLT have not yet been filled
78 in. Their initial contents will arrange when called to push an
79 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
80 and then jump to _GLOBAL_OFFSET_TABLE[2]. */
a42195db 81 got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
32e6df36
UD
82 /* If a library is prelinked but we have to relocate anyway,
83 we have to be able to undo the prelinking of .got.plt.
84 The prelinker saved us here address of .plt + 0x16. */
85 if (got[1])
86 {
87 l->l_mach.plt = got[1] + l->l_addr;
88 l->l_mach.gotplt = (Elf32_Addr) &got[3];
d6b5d570 89 }
a2e1b046 90 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
3996f34b
UD
91
92 /* The got[2] entry contains the address of a function which gets
93 called to get the address of a so far unresolved function and
94 jump to it. The profiling extension of the dynamic linker allows
95 to intercept the calls to collect information. In this case we
96 don't store the address in the GOT so that all future calls also
97 end in this function. */
a1ffb40e 98 if (__glibc_unlikely (profile))
3996f34b 99 {
7b1f9406
L
100 got[2] = (shstk_enabled
101 ? (Elf32_Addr) &_dl_runtime_profile_shstk
102 : (Elf32_Addr) &_dl_runtime_profile);
c0fb8a56 103
9dcafc55
UD
104 if (GLRO(dl_profile) != NULL
105 && _dl_name_match_p (GLRO(dl_profile), l))
c0fb8a56
UD
106 /* This is the object we are looking for. Say that we really
107 want profiling and the timers are started. */
d6b5d570 108 GL(dl_profile_map) = l;
3996f34b
UD
109 }
110 else
111 /* This function will get called to fix up the GOT entry indicated by
112 the offset on the stack, and then jump to the resolved address. */
7b1f9406
L
113 got[2] = (shstk_enabled
114 ? (Elf32_Addr) &_dl_runtime_resolve_shstk
115 : (Elf32_Addr) &_dl_runtime_resolve);
a2e1b046 116 }
d66e34cd 117
0501d603
UD
118 return lazy;
119}
831372e7 120
868b78c8
RM
121#ifdef IN_DL_RUNTIME
122
2bdd4ca6 123# ifndef PROF
868b78c8
RM
124/* We add a declaration of this function here so that in dl-runtime.c
125 the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
126 in registers.
127
128 We cannot use this scheme for profiling because the _mcount call
129 destroys the passed register information. */
9dcafc55 130#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
1e5f1d86 131
70d9946a 132extern ElfW(Addr) _dl_fixup (struct link_map *l,
9dcafc55 133 ElfW(Word) reloc_offset)
1e5f1d86 134 ARCH_FIXUP_ATTRIBUTE;
9dcafc55
UD
135extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
136 ElfW(Word) reloc_offset,
91bf35de 137 ElfW(Addr) retaddr, void *regs,
9dcafc55 138 long int *framesizep)
1e5f1d86 139 ARCH_FIXUP_ATTRIBUTE;
868b78c8
RM
140# endif
141
5ae9d168 142#endif
d66e34cd 143
5bf62f2d
RM
144/* Mask identifying addresses reserved for the user program,
145 where the dynamic linker should not map anything. */
407765e9 146#define ELF_MACHINE_USER_ADDRESS_MASK 0xf0000000UL
5bf62f2d 147
d66e34cd
RM
148/* Initial entry point code for the dynamic linker.
149 The C function `_dl_start' is the real entry point;
150 its return value is the user program's entry point. */
151
2a56ca2a
AJ
152#define RTLD_START asm ("\n\
153 .text\n\
9ad04ff7
UD
154 .align 16\n\
1550: movl (%esp), %ebx\n\
156 ret\n\
157 .align 16\n\
d66e34cd 158.globl _start\n\
421f82e5
RM
159.globl _dl_start_user\n\
160_start:\n\
50746436 161 movl %esp, %eax\n\
630bf491
FW
162 subl $12, %esp\n\
163 pushl %eax\n\
421f82e5 164 call _dl_start\n\
630bf491 165 addl $16, %esp\n\
421f82e5
RM
166_dl_start_user:\n\
167 # Save the user entry point address in %edi.\n\
168 movl %eax, %edi\n\
97716954
UD
169 # Point %ebx at the GOT.\n\
170 call 0b\n\
171 addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\
a1a9d215
RM
172 # See if we were run as a command with the executable file\n\
173 # name as an extra leading argument.\n\
5c82e15e 174 movl _dl_skip_args@GOTOFF(%ebx), %eax\n\
24906b43 175 # Pop the original argument count.\n\
0a63529d 176 popl %edx\n\
24906b43
RM
177 # Adjust the stack pointer to skip _dl_skip_args words.\n\
178 leal (%esp,%eax,4), %esp\n\
5879ee9f 179 # Subtract _dl_skip_args from argc.\n\
0a63529d 180 subl %eax, %edx\n\
5879ee9f 181 # Push argc back on the stack.\n\
0a63529d 182 push %edx\n\
5879ee9f
RM
183 # The special initializer gets called with the stack just\n\
184 # as the application's entry point will see it; it can\n\
185 # switch stacks if it moves these contents over.\n\
186" RTLD_START_SPECIAL_INIT "\n\
dacc8ffa 187 # Load the parameters again.\n\
b3f85fd2 188 # (eax, edx, ecx, esi) = (_dl_loaded, argc, argv, envp)\n\
0d01dace
UD
189 movl _rtld_local@GOTOFF(%ebx), %eax\n\
190 leal 8(%esp,%edx,4), %esi\n\
5879ee9f 191 leal 4(%esp), %ecx\n\
be184b1d
UD
192 movl %esp, %ebp\n\
193 # Make sure _dl_init is run with 16 byte aligned stack.\n\
194 andl $-16, %esp\n\
b3f85fd2 195 subl $12, %esp\n\
be184b1d 196 pushl %ebp\n\
b3f85fd2 197 # Arguments for _dl_init.\n\
0d01dace 198 pushl %esi\n\
b3f85fd2
FW
199 pushl %ecx\n\
200 pushl %edx\n\
201 pushl %eax\n\
be184b1d
UD
202 # Clear %ebp, so that even constructors have terminated backchain.\n\
203 xorl %ebp, %ebp\n\
dacc8ffa 204 # Call the function to run the initializers.\n\
7432d613 205 call _dl_init\n\
39778c6c 206 # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
5c82e15e 207 leal _dl_fini@GOTOFF(%ebx), %edx\n\
be184b1d 208 # Restore %esp _start expects.\n\
b3f85fd2 209 movl 16(%esp), %esp\n\
421f82e5
RM
210 # Jump to the user's entry point.\n\
211 jmp *%edi\n\
2a56ca2a 212 .previous\n\
d66e34cd 213");
f51d1dfd 214
5879ee9f 215#ifndef RTLD_START_SPECIAL_INIT
50746436 216# define RTLD_START_SPECIAL_INIT /* nothing */
5879ee9f
RM
217#endif
218
2e36cb48
UD
219/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
220 TLS variable, so undefined references should not be allowed to
221 define the value.
209826bc 222 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
62da1e3b
L
223 of the main executable's symbols, as for a COPY reloc.
224 ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA iff TYPE describes relocation may
225 against protected data whose address be external due to copy relocation.
226 */
2e36cb48
UD
227# define elf_machine_type_class(type) \
228 ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
1d0ad773 229 || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
c9ff0187 230 || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC) \
2e36cb48 231 * ELF_RTYPE_CLASS_PLT) \
62da1e3b
L
232 | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY) \
233 | (((type) == R_386_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
bc9f6000
UD
234
235/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 236#define ELF_MACHINE_JMP_SLOT R_386_JMP_SLOT
f51d1dfd 237
32e6df36
UD
238/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
239 Prelinked libraries may use Elf32_Rela though. */
240#define ELF_MACHINE_PLT_REL 1
f51d1dfd 241
0a54e401
UD
242/* We define an initialization functions. This is called very early in
243 _dl_sysdep_start. */
244#define DL_PLATFORM_INIT dl_platform_init ()
245
0a54e401
UD
246static inline void __attribute__ ((unused))
247dl_platform_init (void)
248{
1432d38e 249#if IS_IN (rtld)
0f09154c
L
250 /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which
251 has been called early from __libc_start_main in static executable. */
252 _dl_x86_init_cpu_features ();
1432d38e
L
253#else
254 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
255 /* Avoid an empty string which would disturb us. */
256 GLRO(dl_platform) = NULL;
4facca0b 257#endif
0a54e401
UD
258}
259
c0282c06
UD
260static inline Elf32_Addr
261elf_machine_fixup_plt (struct link_map *map, lookup_t t,
0572433b 262 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
c0282c06 263 const Elf32_Rel *reloc,
a2b08ee5
UD
264 Elf32_Addr *reloc_addr, Elf32_Addr value)
265{
c0282c06 266 return *reloc_addr = value;
a2b08ee5
UD
267}
268
dfd2257a
UD
269/* Return the final value of a plt relocation. */
270static inline Elf32_Addr
271elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
272 Elf32_Addr value)
273{
274 return value;
275}
276
9dcafc55
UD
277
278/* Names of the architecture-specific auditing callback functions. */
279#define ARCH_LA_PLTENTER i86_gnu_pltenter
280#define ARCH_LA_PLTEXIT i86_gnu_pltexit
281
0ecb606c 282#endif /* !dl_machine_h */
f51d1dfd 283
32e6df36
UD
284/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
285 Prelinked libraries may use Elf32_Rela though. */
17112921 286#define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
80b5c505 287#define ELF_MACHINE_NO_REL 0
32e6df36 288
9cfe5381
RM
289#ifdef RESOLVE_MAP
290
f51d1dfd
RM
291/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
292 MAP is the object containing the reloc. */
293
7dfde5a0 294auto inline void
ee600e3f 295__attribute ((always_inline))
c84142e8 296elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
3996f34b 297 const Elf32_Sym *sym, const struct r_found_version *version,
3a62d00d 298 void *const reloc_addr_arg, int skip_ifunc)
f51d1dfd 299{
87d254a7 300 Elf32_Addr *const reloc_addr = reloc_addr_arg;
1721af3f
UD
301 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
302
f81ce288 303# if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
a1ffb40e 304 if (__glibc_unlikely (r_type == R_386_RELATIVE))
f51d1dfd 305 {
f81ce288 306# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
a778db06
UD
307 /* This is defined in rtld.c, but nowhere in the static libc.a;
308 make the reference weak so static programs can still link.
309 This declaration cannot be done when compiling rtld.c
310 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
311 common defn for _dl_rtld_map, which is incompatible with a
312 weak decl in the same file. */
f81ce288 313# ifndef SHARED
a778db06 314 weak_extern (_dl_rtld_map);
f81ce288 315# endif
5688da55 316 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
f81ce288 317# endif
f51d1dfd 318 *reloc_addr += map->l_addr;
f51d1dfd 319 }
f81ce288 320# ifndef RTLD_BOOTSTRAP
a1ffb40e 321 else if (__glibc_unlikely (r_type == R_386_NONE))
1721af3f 322 return;
f81ce288 323# endif
1721af3f 324 else
f81ce288 325# endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
bc9f6000 326 {
de7f5ce7 327# ifndef RTLD_BOOTSTRAP
bc9f6000 328 const Elf32_Sym *const refsym = sym;
de7f5ce7 329# endif
5d6feea8 330 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
10a446dd 331 Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
bc9f6000 332
f81ce288 333 if (sym != NULL
f886c16c
L
334 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
335 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
336 && __glibc_likely (!skip_ifunc))
0e6d3adc
L
337 {
338# ifndef RTLD_BOOTSTRAP
339 if (sym_map != map
340 && sym_map->l_type != lt_executable
341 && !sym_map->l_relocated)
342 {
343 const char *strtab
344 = (const char *) D_PTR (map, l_info[DT_STRTAB]);
6fab532b 345 _dl_error_printf ("\
0e6d3adc
L
346%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
347 RTLD_PROGNAME, map->l_name,
348 sym_map->l_name,
349 strtab + refsym->st_name);
350 }
351# endif
352 value = ((Elf32_Addr (*) (void)) value) ();
353 }
f81ce288 354
1721af3f 355 switch (r_type)
bc9f6000 356 {
22676eaf
L
357# ifndef RTLD_BOOTSTRAP
358 case R_386_SIZE32:
359 /* Set to symbol size plus addend. */
360 *reloc_addr += sym->st_size;
361 break;
362# endif
a778db06
UD
363 case R_386_GLOB_DAT:
364 case R_386_JMP_SLOT:
365 *reloc_addr = value;
366 break;
535b764d 367
535b764d 368 case R_386_TLS_DTPMOD32:
d063d164 369# ifdef RTLD_BOOTSTRAP
535b764d
UD
370 /* During startup the dynamic linker is always the module
371 with index 1.
372 XXX If this relocation is necessary move before RESOLVE
373 call. */
374 *reloc_addr = 1;
d063d164 375# else
5d6feea8
UD
376 /* Get the information from the link map returned by the
377 resolv function. */
378 if (sym_map != NULL)
379 *reloc_addr = sym_map->l_tls_modid;
d063d164 380# endif
535b764d
UD
381 break;
382 case R_386_TLS_DTPOFF32:
d063d164 383# ifndef RTLD_BOOTSTRAP
535b764d
UD
384 /* During relocation all TLS symbols are defined and used.
385 Therefore the offset is already correct. */
5d6feea8 386 if (sym != NULL)
4730fc68 387 *reloc_addr = sym->st_value;
d063d164 388# endif
535b764d 389 break;
c9ff0187
UD
390 case R_386_TLS_DESC:
391 {
392 struct tlsdesc volatile *td =
393 (struct tlsdesc volatile *)reloc_addr;
394
d063d164 395# ifndef RTLD_BOOTSTRAP
c9ff0187
UD
396 if (! sym)
397 td->entry = _dl_tlsdesc_undefweak;
398 else
d063d164 399# endif
c9ff0187 400 {
d063d164
UD
401# ifndef RTLD_BOOTSTRAP
402# ifndef SHARED
c9ff0187 403 CHECK_STATIC_TLS (map, sym_map);
d063d164 404# else
c9ff0187
UD
405 if (!TRY_STATIC_TLS (map, sym_map))
406 {
407 td->arg = _dl_make_tlsdesc_dynamic
408 (sym_map, sym->st_value + (ElfW(Word))td->arg);
409 td->entry = _dl_tlsdesc_dynamic;
410 }
411 else
412# endif
d063d164 413# endif
c9ff0187
UD
414 {
415 td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
416 + (ElfW(Word))td->arg);
417 td->entry = _dl_tlsdesc_return;
418 }
419 }
420 break;
421 }
535b764d
UD
422 case R_386_TLS_TPOFF32:
423 /* The offset is positive, backward from the thread pointer. */
f81ce288 424# ifdef RTLD_BOOTSTRAP
534feaab 425 *reloc_addr += map->l_tls_offset - sym->st_value;
f81ce288 426# else
3632a260 427 /* We know the offset of object the symbol is contained in.
5d6feea8
UD
428 It is a positive value which will be subtracted from the
429 thread pointer. To get the variable position in the TLS
430 block we subtract the offset from that of the TLS block. */
4730fc68 431 if (sym != NULL)
eb775e67 432 {
eb775e67 433 CHECK_STATIC_TLS (map, sym_map);
aff4519d 434 *reloc_addr += sym_map->l_tls_offset - sym->st_value;
eb775e67 435 }
d063d164 436# endif
1d0ad773
RM
437 break;
438 case R_386_TLS_TPOFF:
439 /* The offset is negative, forward from the thread pointer. */
d063d164 440# ifdef RTLD_BOOTSTRAP
1d0ad773 441 *reloc_addr += sym->st_value - map->l_tls_offset;
d063d164 442# else
1d0ad773
RM
443 /* We know the offset of object the symbol is contained in.
444 It is a negative value which will be added to the
445 thread pointer. */
446 if (sym != NULL)
eb775e67 447 {
eb775e67 448 CHECK_STATIC_TLS (map, sym_map);
aff4519d 449 *reloc_addr += sym->st_value - sym_map->l_tls_offset;
eb775e67 450 }
d063d164 451# endif
535b764d
UD
452 break;
453
f81ce288 454# ifndef RTLD_BOOTSTRAP
a778db06
UD
455 case R_386_32:
456 *reloc_addr += value;
457 break;
458 case R_386_PC32:
459 *reloc_addr += (value - (Elf32_Addr) reloc_addr);
460 break;
bc9f6000 461 case R_386_COPY:
5107cf1d
UD
462 if (sym == NULL)
463 /* This can happen in trace mode if an object could not be
464 found. */
465 break;
f886c16c
L
466 if (__glibc_unlikely (sym->st_size > refsym->st_size)
467 || (__glibc_unlikely(sym->st_size < refsym->st_size)
afdca0f2 468 && GLRO(dl_verbose)))
1f07e617
UD
469 {
470 const char *strtab;
471
a42195db 472 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
35fc382a
UD
473 _dl_error_printf ("\
474%s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 475 RTLD_PROGNAME, strtab + refsym->st_name);
1f07e617 476 }
87d254a7
AO
477 memcpy (reloc_addr_arg, (void *) value,
478 MIN (sym->st_size, refsym->st_size));
bc9f6000 479 break;
74414708
UD
480 case R_386_IRELATIVE:
481 value = map->l_addr + *reloc_addr;
4db71d2f
FW
482 if (__glibc_likely (!skip_ifunc))
483 value = ((Elf32_Addr (*) (void)) value) ();
74414708
UD
484 *reloc_addr = value;
485 break;
bc9f6000 486 default:
1721af3f 487 _dl_reloc_bad_type (map, r_type, 0);
bc9f6000 488 break;
f81ce288 489# endif /* !RTLD_BOOTSTRAP */
5d6feea8 490 }
bc9f6000 491 }
f51d1dfd
RM
492}
493
f81ce288 494# ifndef RTLD_BOOTSTRAP
7dfde5a0
AJ
495auto inline void
496__attribute__ ((always_inline))
32e6df36
UD
497elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
498 const Elf32_Sym *sym, const struct r_found_version *version,
3a62d00d 499 void *const reloc_addr_arg, int skip_ifunc)
32e6df36 500{
87d254a7 501 Elf32_Addr *const reloc_addr = reloc_addr_arg;
5d6feea8
UD
502 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
503
32e6df36
UD
504 if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
505 *reloc_addr = map->l_addr + reloc->r_addend;
5d6feea8 506 else if (r_type != R_386_NONE)
32e6df36 507 {
f81ce288 508# ifndef RESOLVE_CONFLICT_FIND_MAP
92712dee 509 const Elf32_Sym *const refsym = sym;
f81ce288 510# endif
5d6feea8 511 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
10a446dd 512 Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
32e6df36 513
f81ce288 514 if (sym != NULL
f886c16c
L
515 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
516 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
517 && __glibc_likely (!skip_ifunc))
f81ce288
UD
518 value = ((Elf32_Addr (*) (void)) value) ();
519
32e6df36
UD
520 switch (ELF32_R_TYPE (reloc->r_info))
521 {
22676eaf
L
522 case R_386_SIZE32:
523 /* Set to symbol size plus addend. */
524 value = sym->st_size;
e0cb7b61 525 /* Fall through. */
32e6df36
UD
526 case R_386_GLOB_DAT:
527 case R_386_JMP_SLOT:
528 case R_386_32:
529 *reloc_addr = value + reloc->r_addend;
530 break;
f81ce288 531# ifndef RESOLVE_CONFLICT_FIND_MAP
8e27f45e 532 /* Not needed for dl-conflict.c. */
32e6df36
UD
533 case R_386_PC32:
534 *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
535 break;
4730fc68 536
4730fc68 537 case R_386_TLS_DTPMOD32:
4730fc68
RM
538 /* Get the information from the link map returned by the
539 resolv function. */
540 if (sym_map != NULL)
541 *reloc_addr = sym_map->l_tls_modid;
4730fc68
RM
542 break;
543 case R_386_TLS_DTPOFF32:
4730fc68
RM
544 /* During relocation all TLS symbols are defined and used.
545 Therefore the offset is already correct. */
546 *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
4730fc68 547 break;
c9ff0187
UD
548 case R_386_TLS_DESC:
549 {
550 struct tlsdesc volatile *td =
551 (struct tlsdesc volatile *)reloc_addr;
552
f81ce288 553# ifndef RTLD_BOOTSTRAP
c9ff0187
UD
554 if (!sym)
555 {
556 td->arg = (void*)reloc->r_addend;
557 td->entry = _dl_tlsdesc_undefweak;
558 }
559 else
f81ce288 560# endif
c9ff0187 561 {
f81ce288
UD
562# ifndef RTLD_BOOTSTRAP
563# ifndef SHARED
c9ff0187 564 CHECK_STATIC_TLS (map, sym_map);
f81ce288 565# else
c9ff0187
UD
566 if (!TRY_STATIC_TLS (map, sym_map))
567 {
568 td->arg = _dl_make_tlsdesc_dynamic
569 (sym_map, sym->st_value + reloc->r_addend);
570 td->entry = _dl_tlsdesc_dynamic;
571 }
572 else
f81ce288
UD
573# endif
574# endif
c9ff0187
UD
575 {
576 td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
577 + reloc->r_addend);
578 td->entry = _dl_tlsdesc_return;
579 }
580 }
581 }
582 break;
4730fc68
RM
583 case R_386_TLS_TPOFF32:
584 /* The offset is positive, backward from the thread pointer. */
4730fc68
RM
585 /* We know the offset of object the symbol is contained in.
586 It is a positive value which will be subtracted from the
587 thread pointer. To get the variable position in the TLS
588 block we subtract the offset from that of the TLS block. */
d40eb37a
UD
589 if (sym != NULL)
590 {
591 CHECK_STATIC_TLS (map, sym_map);
592 *reloc_addr = sym_map->l_tls_offset - sym->st_value
593 + reloc->r_addend;
594 }
1d0ad773
RM
595 break;
596 case R_386_TLS_TPOFF:
597 /* The offset is negative, forward from the thread pointer. */
598 /* We know the offset of object the symbol is contained in.
599 It is a negative value which will be added to the
600 thread pointer. */
d40eb37a
UD
601 if (sym != NULL)
602 {
603 CHECK_STATIC_TLS (map, sym_map);
604 *reloc_addr = sym->st_value - sym_map->l_tls_offset
605 + reloc->r_addend;
606 }
4730fc68 607 break;
92712dee
RM
608 case R_386_COPY:
609 if (sym == NULL)
610 /* This can happen in trace mode if an object could not be
611 found. */
612 break;
f886c16c
L
613 if (__glibc_unlikely (sym->st_size > refsym->st_size)
614 || (__glibc_unlikely (sym->st_size < refsym->st_size)
afdca0f2 615 && GLRO(dl_verbose)))
92712dee
RM
616 {
617 const char *strtab;
618
619 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
620 _dl_error_printf ("\
621%s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 622 RTLD_PROGNAME, strtab + refsym->st_name);
92712dee 623 }
87d254a7
AO
624 memcpy (reloc_addr_arg, (void *) value,
625 MIN (sym->st_size, refsym->st_size));
92712dee 626 break;
f81ce288 627# endif /* !RESOLVE_CONFLICT_FIND_MAP */
74414708
UD
628 case R_386_IRELATIVE:
629 value = map->l_addr + reloc->r_addend;
4db71d2f
FW
630 if (__glibc_likely (!skip_ifunc))
631 value = ((Elf32_Addr (*) (void)) value) ();
74414708
UD
632 *reloc_addr = value;
633 break;
32e6df36
UD
634 default:
635 /* We add these checks in the version to relocate ld.so only
636 if we are still debugging. */
5d6feea8 637 _dl_reloc_bad_type (map, r_type, 0);
32e6df36
UD
638 break;
639 }
640 }
641}
f81ce288 642# endif /* !RTLD_BOOTSTRAP */
32e6df36 643
7dfde5a0 644auto inline void
ee600e3f 645__attribute ((always_inline))
1721af3f 646elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
87d254a7 647 void *const reloc_addr_arg)
1721af3f 648{
87d254a7 649 Elf32_Addr *const reloc_addr = reloc_addr_arg;
a711b01d 650 assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);
1721af3f
UD
651 *reloc_addr += l_addr;
652}
653
f81ce288 654# ifndef RTLD_BOOTSTRAP
7dfde5a0
AJ
655auto inline void
656__attribute__ ((always_inline))
32e6df36 657elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
87d254a7 658 void *const reloc_addr_arg)
32e6df36 659{
87d254a7 660 Elf32_Addr *const reloc_addr = reloc_addr_arg;
32e6df36
UD
661 *reloc_addr = l_addr + reloc->r_addend;
662}
f81ce288 663# endif /* !RTLD_BOOTSTRAP */
32e6df36 664
7dfde5a0
AJ
665auto inline void
666__attribute__ ((always_inline))
421c80d2 667elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
668 Elf32_Addr l_addr, const Elf32_Rel *reloc,
669 int skip_ifunc)
f51d1dfd 670{
b0cf070b 671 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
1721af3f 672 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
b0cf070b 673 /* Check for unexpected PLT reloc type. */
a1ffb40e 674 if (__glibc_likely (r_type == R_386_JMP_SLOT))
32e6df36 675 {
f886c16c
L
676 /* Prelink has been deprecated. */
677 if (__glibc_likely (map->l_mach.plt == 0))
32e6df36
UD
678 *reloc_addr += l_addr;
679 else
50746436
UD
680 *reloc_addr = (map->l_mach.plt
681 + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
32e6df36 682 }
a1ffb40e 683 else if (__glibc_likely (r_type == R_386_TLS_DESC))
c9ff0187
UD
684 {
685 struct tlsdesc volatile * __attribute__((__unused__)) td =
686 (struct tlsdesc volatile *)reloc_addr;
687
688 /* Handle relocations that reference the local *ABS* in a simple
689 way, so as to preserve a potential addend. */
690 if (ELF32_R_SYM (reloc->r_info) == 0)
691 td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
692 /* Given a known-zero addend, we can store a pointer to the
693 reloc in the arg position. */
694 else if (td->arg == 0)
695 {
696 td->arg = (void*)reloc;
697 td->entry = _dl_tlsdesc_resolve_rel;
698 }
699 else
700 {
701 /* We could handle non-*ABS* relocations with non-zero addends
702 by allocating dynamically an arg to hold a pointer to the
703 reloc, but that sounds pointless. */
704 const Elf32_Rel *const r = reloc;
705 /* The code below was borrowed from elf_dynamic_do_rel(). */
706 const ElfW(Sym) *const symtab =
707 (const void *) D_PTR (map, l_info[DT_SYMTAB]);
708
f81ce288 709# ifdef RTLD_BOOTSTRAP
c9ff0187
UD
710 /* The dynamic linker always uses versioning. */
711 assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
f81ce288 712# else
c9ff0187 713 if (map->l_info[VERSYMIDX (DT_VERSYM)])
f81ce288 714# endif
c9ff0187
UD
715 {
716 const ElfW(Half) *const version =
717 (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
718 ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
719 elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
720 &map->l_versions[ndx],
3a62d00d 721 (void *) (l_addr + r->r_offset), skip_ifunc);
c9ff0187 722 }
f81ce288 723# ifndef RTLD_BOOTSTRAP
c9ff0187
UD
724 else
725 elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
3a62d00d 726 (void *) (l_addr + r->r_offset), skip_ifunc);
f81ce288 727# endif
c9ff0187
UD
728 }
729 }
a1ffb40e 730 else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
74414708
UD
731 {
732 Elf32_Addr value = map->l_addr + *reloc_addr;
a1ffb40e 733 if (__glibc_likely (!skip_ifunc))
3a62d00d 734 value = ((Elf32_Addr (*) (void)) value) ();
74414708
UD
735 *reloc_addr = value;
736 }
421c80d2 737 else
1721af3f 738 _dl_reloc_bad_type (map, r_type, 1);
f51d1dfd
RM
739}
740
f81ce288 741# ifndef RTLD_BOOTSTRAP
32e6df36 742
7dfde5a0
AJ
743auto inline void
744__attribute__ ((always_inline))
32e6df36 745elf_machine_lazy_rela (struct link_map *map,
3a62d00d
AS
746 Elf32_Addr l_addr, const Elf32_Rela *reloc,
747 int skip_ifunc)
32e6df36 748{
c9ff0187
UD
749 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
750 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
a1ffb40e 751 if (__glibc_likely (r_type == R_386_JMP_SLOT))
c9ff0187 752 ;
a1ffb40e 753 else if (__glibc_likely (r_type == R_386_TLS_DESC))
c9ff0187
UD
754 {
755 struct tlsdesc volatile * __attribute__((__unused__)) td =
756 (struct tlsdesc volatile *)reloc_addr;
757
758 td->arg = (void*)reloc;
759 td->entry = _dl_tlsdesc_resolve_rela;
760 }
a1ffb40e 761 else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
74414708
UD
762 {
763 Elf32_Addr value = map->l_addr + reloc->r_addend;
a1ffb40e 764 if (__glibc_likely (!skip_ifunc))
3a62d00d 765 value = ((Elf32_Addr (*) (void)) value) ();
74414708
UD
766 *reloc_addr = value;
767 }
c9ff0187
UD
768 else
769 _dl_reloc_bad_type (map, r_type, 1);
32e6df36
UD
770}
771
f81ce288 772# endif /* !RTLD_BOOTSTRAP */
32e6df36 773
9dcafc55 774#endif /* RESOLVE_MAP */