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