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