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