]> sourceware.org Git - glibc.git/blame - sysdeps/i386/dl-machine.h
* sysdeps/i386/dl-machine.h (RTLD_START): Set __libc_stack_end before
[glibc.git] / sysdeps / i386 / dl-machine.h
CommitLineData
d66e34cd 1/* Machine-dependent ELF dynamic relocation inline functions. i386 version.
aff4519d 2 Copyright (C) 1995-2002, 2003 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
AJ
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
d66e34cd 19
f51d1dfd
RM
20#ifndef dl_machine_h
21#define dl_machine_h
22
d66e34cd
RM
23#define ELF_MACHINE_NAME "i386"
24
1f07e617 25#include <sys/param.h>
7b09d09d 26#include <sysdep.h>
2e36cb48
UD
27#include <tls.h>
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#if defined PI_STATIC_AND_HIDDEN \
38 && defined HAVE_VISIBILITY_ATTRIBUTE && defined HAVE_HIDDEN \
39 && !defined HAVE_BROKEN_VISIBILITY_ATTRIBUTE
40
41/* Return the link-time address of _DYNAMIC. Conveniently, this is the
42 first element of the GOT, a special entry that is never relocated. */
43static inline Elf32_Addr __attribute__ ((unused, const))
44elf_machine_dynamic (void)
45{
46 /* This produces a GOTOFF reloc that resolves to zero at link time, so in
47 fact just loads from the GOT register directly. By doing it without
48 an asm we can let the compiler choose any register. */
49 extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
50 return _GLOBAL_OFFSET_TABLE_[0];
51}
52
53/* Return the run-time load address of the shared object. */
54static inline Elf32_Addr __attribute__ ((unused))
55elf_machine_load_address (void)
56{
57 /* Compute the difference between the runtime address of _DYNAMIC as seen
58 by a GOTOFF reference, and the link-time address found in the special
59 unrelocated first GOT entry. */
60 extern Elf32_Dyn bygotoff[] asm ("_DYNAMIC") attribute_hidden;
61 return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();
62}
63
64#else /* Without .hidden support, we can't compile the code above. */
65
47707456
UD
66/* Return the link-time address of _DYNAMIC. Conveniently, this is the
67 first element of the GOT. This must be inlined in a function which
68 uses global data. */
0a54e401 69static inline Elf32_Addr __attribute__ ((unused))
47707456 70elf_machine_dynamic (void)
d66e34cd
RM
71{
72 register Elf32_Addr *got asm ("%ebx");
47707456 73 return *got;
d66e34cd
RM
74}
75
76
77/* Return the run-time load address of the shared object. */
e75154a6 78static inline Elf32_Addr __attribute__ ((unused))
d66e34cd
RM
79elf_machine_load_address (void)
80{
16495f81
RM
81 /* It doesn't matter what variable this is, the reference never makes
82 it to assembly. We need a dummy reference to some global variable
83 via the GOT to make sure the compiler initialized %ebx in time. */
84 extern int _dl_argc;
d66e34cd 85 Elf32_Addr addr;
92f1da4d
UD
86 asm ("leal _dl_start@GOTOFF(%%ebx), %0\n"
87 "subl _dl_start@GOT(%%ebx), %0"
16495f81 88 : "=r" (addr) : "m" (_dl_argc) : "cc");
d66e34cd
RM
89 return addr;
90}
d66e34cd 91
6ce3881d
RM
92#endif
93
94
d66e34cd
RM
95/* Set up the loaded object described by L so its unrelocated PLT
96 entries will jump to the on-demand fixup code in dl-runtime.c. */
97
9c7ff11a 98static inline int __attribute__ ((unused, always_inline))
3996f34b 99elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
d66e34cd 100{
a1a9d215 101 Elf32_Addr *got;
5c82e15e
UD
102 extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
103 extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
a1a9d215 104
a2e1b046
RM
105 if (l->l_info[DT_JMPREL] && lazy)
106 {
107 /* The GOT entries for functions in the PLT have not yet been filled
108 in. Their initial contents will arrange when called to push an
109 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
110 and then jump to _GLOBAL_OFFSET_TABLE[2]. */
a42195db 111 got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
32e6df36
UD
112 /* If a library is prelinked but we have to relocate anyway,
113 we have to be able to undo the prelinking of .got.plt.
114 The prelinker saved us here address of .plt + 0x16. */
115 if (got[1])
116 {
117 l->l_mach.plt = got[1] + l->l_addr;
118 l->l_mach.gotplt = (Elf32_Addr) &got[3];
d6b5d570 119 }
a2e1b046 120 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
3996f34b
UD
121
122 /* The got[2] entry contains the address of a function which gets
123 called to get the address of a so far unresolved function and
124 jump to it. The profiling extension of the dynamic linker allows
125 to intercept the calls to collect information. In this case we
126 don't store the address in the GOT so that all future calls also
127 end in this function. */
d4f170a9 128 if (__builtin_expect (profile, 0))
3996f34b
UD
129 {
130 got[2] = (Elf32_Addr) &_dl_runtime_profile;
c0fb8a56 131
d6b5d570 132 if (_dl_name_match_p (GL(dl_profile), l))
c0fb8a56
UD
133 /* This is the object we are looking for. Say that we really
134 want profiling and the timers are started. */
d6b5d570 135 GL(dl_profile_map) = l;
3996f34b
UD
136 }
137 else
138 /* This function will get called to fix up the GOT entry indicated by
139 the offset on the stack, and then jump to the resolved address. */
140 got[2] = (Elf32_Addr) &_dl_runtime_resolve;
a2e1b046 141 }
d66e34cd 142
0501d603
UD
143 return lazy;
144}
831372e7 145
868b78c8
RM
146#ifdef IN_DL_RUNTIME
147
148# if !defined PROF && !__BOUNDED_POINTERS__
149/* We add a declaration of this function here so that in dl-runtime.c
150 the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
151 in registers.
152
153 We cannot use this scheme for profiling because the _mcount call
154 destroys the passed register information. */
155/* GKM FIXME: Fix trampoline to pass bounds so we can do
156 without the `__unbounded' qualifier. */
157static ElfW(Addr) fixup (struct link_map *__unbounded l, ElfW(Word) reloc_offset)
158 __attribute__ ((regparm (2), unused));
159static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
160 ElfW(Addr) retaddr)
161 __attribute__ ((regparm (3), unused));
162# endif
163
0501d603
UD
164/* This code is used in dl-runtime.c to call the `fixup' function
165 and then redirect to the address it returns. */
868b78c8
RM
166# if !defined PROF && !__BOUNDED_POINTERS__
167# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
2a56ca2a
AJ
168 .text\n\
169 .globl _dl_runtime_resolve\n\
170 .type _dl_runtime_resolve, @function\n\
06e2e0a7 171 " CFI_STARTPROC "\n\
2a56ca2a
AJ
172 .align 16\n\
173_dl_runtime_resolve:\n\
06e2e0a7 174 " CFI_ADJUST_CFA_OFFSET (8) "\n\
2a56ca2a 175 pushl %eax # Preserve registers otherwise clobbered.\n\
06e2e0a7 176 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 177 pushl %ecx\n\
06e2e0a7 178 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 179 pushl %edx\n\
06e2e0a7 180 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a
AJ
181 movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
182 movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
183 call fixup # Call resolver.\n\
184 popl %edx # Get register content back.\n\
06e2e0a7 185 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a 186 popl %ecx\n\
06e2e0a7 187 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a
AJ
188 xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
189 ret $8 # Jump to function address.\n\
06e2e0a7 190 " CFI_ENDPROC "\n\
2a56ca2a
AJ
191 .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
192\n\
193 .globl _dl_runtime_profile\n\
194 .type _dl_runtime_profile, @function\n\
06e2e0a7 195 " CFI_STARTPROC "\n\
2a56ca2a
AJ
196 .align 16\n\
197_dl_runtime_profile:\n\
06e2e0a7 198 " CFI_ADJUST_CFA_OFFSET (8) "\n\
2a56ca2a 199 pushl %eax # Preserve registers otherwise clobbered.\n\
06e2e0a7 200 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 201 pushl %ecx\n\
06e2e0a7 202 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 203 pushl %edx\n\
06e2e0a7 204 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a
AJ
205 movl 20(%esp), %ecx # Load return address\n\
206 movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
207 movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
208 call profile_fixup # Call resolver.\n\
209 popl %edx # Get register content back.\n\
06e2e0a7 210 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a 211 popl %ecx\n\
06e2e0a7 212 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a
AJ
213 xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
214 ret $8 # Jump to function address.\n\
06e2e0a7 215 " CFI_ENDPROC "\n\
2a56ca2a
AJ
216 .size _dl_runtime_profile, .-_dl_runtime_profile\n\
217 .previous\n\
38334018 218");
868b78c8 219# else
d025fe26 220# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
2a56ca2a
AJ
221 .text\n\
222 .globl _dl_runtime_resolve\n\
223 .globl _dl_runtime_profile\n\
224 .type _dl_runtime_resolve, @function\n\
225 .type _dl_runtime_profile, @function\n\
06e2e0a7 226 " CFI_STARTPROC "\n\
2a56ca2a
AJ
227 .align 16\n\
228_dl_runtime_resolve:\n\
229_dl_runtime_profile:\n\
06e2e0a7 230 " CFI_ADJUST_CFA_OFFSET (8) "\n\
2a56ca2a 231 pushl %eax # Preserve registers otherwise clobbered.\n\
06e2e0a7 232 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 233 pushl %ecx\n\
06e2e0a7 234 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 235 pushl %edx\n\
06e2e0a7 236 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a
AJ
237 movl 16(%esp), %edx # Push the arguments for `fixup'\n\
238 movl 12(%esp), %eax\n\
239 pushl %edx\n\
06e2e0a7 240 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a 241 pushl %eax\n\
06e2e0a7 242 " CFI_ADJUST_CFA_OFFSET (4) "\n\
2a56ca2a
AJ
243 call fixup # Call resolver.\n\
244 popl %edx # Pop the parameters\n\
06e2e0a7 245 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a 246 popl %ecx\n\
06e2e0a7 247 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a 248 popl %edx # Get register content back.\n\
06e2e0a7 249 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a 250 popl %ecx\n\
06e2e0a7 251 " CFI_ADJUST_CFA_OFFSET (-4) "\n\
2a56ca2a
AJ
252 xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
253 ret $8 # Jump to function address.\n\
06e2e0a7 254 " CFI_ENDPROC "\n\
2a56ca2a
AJ
255 .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
256 .size _dl_runtime_profile, .-_dl_runtime_profile\n\
257 .previous\n\
5ae9d168 258");
868b78c8 259# endif
5ae9d168 260#endif
d66e34cd 261
5bf62f2d
RM
262/* Mask identifying addresses reserved for the user program,
263 where the dynamic linker should not map anything. */
264#define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL
265
d66e34cd
RM
266/* Initial entry point code for the dynamic linker.
267 The C function `_dl_start' is the real entry point;
268 its return value is the user program's entry point. */
269
2a56ca2a
AJ
270#define RTLD_START asm ("\n\
271 .text\n\
9ad04ff7
UD
272 .align 16\n\
2730: movl (%esp), %ebx\n\
274 ret\n\
275 .align 16\n\
d66e34cd 276.globl _start\n\
421f82e5
RM
277.globl _dl_start_user\n\
278_start:\n\
2abf9ff1
RM
279 # Point %ebx at the GOT.\n\
280 call 0b\n\
281 addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\
50746436
UD
282 # Note that _dl_start gets the parameter in %eax.\n\
283 movl %esp, %eax\n\
2abf9ff1
RM
284 # Store the highest stack address\n\
285 movl %eax, __libc_stack_end@GOTOFF(%ebx)\n\
421f82e5
RM
286 call _dl_start\n\
287_dl_start_user:\n\
288 # Save the user entry point address in %edi.\n\
289 movl %eax, %edi\n\
a1a9d215
RM
290 # See if we were run as a command with the executable file\n\
291 # name as an extra leading argument.\n\
5c82e15e 292 movl _dl_skip_args@GOTOFF(%ebx), %eax\n\
24906b43 293 # Pop the original argument count.\n\
0a63529d 294 popl %edx\n\
24906b43
RM
295 # Adjust the stack pointer to skip _dl_skip_args words.\n\
296 leal (%esp,%eax,4), %esp\n\
5879ee9f 297 # Subtract _dl_skip_args from argc.\n\
0a63529d 298 subl %eax, %edx\n\
5879ee9f 299 # Push argc back on the stack.\n\
0a63529d 300 push %edx\n\
5879ee9f
RM
301 # The special initializer gets called with the stack just\n\
302 # as the application's entry point will see it; it can\n\
303 # switch stacks if it moves these contents over.\n\
304" RTLD_START_SPECIAL_INIT "\n\
dacc8ffa 305 # Load the parameters again.\n\
5879ee9f 306 # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\
0d01dace
UD
307 movl _rtld_local@GOTOFF(%ebx), %eax\n\
308 leal 8(%esp,%edx,4), %esi\n\
5879ee9f 309 leal 4(%esp), %ecx\n\
0d01dace 310 pushl %esi\n\
dacc8ffa 311 # Call the function to run the initializers.\n\
7969407a 312 call _dl_init_internal@PLT\n\
39778c6c 313 # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
5c82e15e 314 leal _dl_fini@GOTOFF(%ebx), %edx\n\
421f82e5
RM
315 # Jump to the user's entry point.\n\
316 jmp *%edi\n\
2a56ca2a 317 .previous\n\
d66e34cd 318");
f51d1dfd 319
5879ee9f 320#ifndef RTLD_START_SPECIAL_INIT
50746436 321# define RTLD_START_SPECIAL_INIT /* nothing */
5879ee9f
RM
322#endif
323
2e36cb48
UD
324/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
325 TLS variable, so undefined references should not be allowed to
326 define the value.
cf5a372e
UD
327 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
328 of the main executable's symbols, as for a COPY reloc. */
ce460d04 329#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
2e36cb48
UD
330# define elf_machine_type_class(type) \
331 ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
1d0ad773
RM
332 || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
333 || (type) == R_386_TLS_TPOFF) \
2e36cb48
UD
334 * ELF_RTYPE_CLASS_PLT) \
335 | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
336#else
337# define elf_machine_type_class(type) \
338 ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
cf5a372e 339 | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
2e36cb48 340#endif
bc9f6000
UD
341
342/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 343#define ELF_MACHINE_JMP_SLOT R_386_JMP_SLOT
f51d1dfd 344
32e6df36
UD
345/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
346 Prelinked libraries may use Elf32_Rela though. */
347#define ELF_MACHINE_PLT_REL 1
f51d1dfd 348
0a54e401
UD
349/* We define an initialization functions. This is called very early in
350 _dl_sysdep_start. */
351#define DL_PLATFORM_INIT dl_platform_init ()
352
0a54e401
UD
353static inline void __attribute__ ((unused))
354dl_platform_init (void)
355{
d6b5d570 356 if (GL(dl_platform) != NULL && *GL(dl_platform) == '\0')
27a5bb33 357 /* Avoid an empty string which would disturb us. */
d6b5d570 358 GL(dl_platform) = NULL;
0a54e401
UD
359}
360
c0282c06
UD
361static inline Elf32_Addr
362elf_machine_fixup_plt (struct link_map *map, lookup_t t,
363 const Elf32_Rel *reloc,
a2b08ee5
UD
364 Elf32_Addr *reloc_addr, Elf32_Addr value)
365{
c0282c06 366 return *reloc_addr = value;
a2b08ee5
UD
367}
368
dfd2257a
UD
369/* Return the final value of a plt relocation. */
370static inline Elf32_Addr
371elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
372 Elf32_Addr value)
373{
374 return value;
375}
376
f51d1dfd
RM
377#endif /* !dl_machine_h */
378
379#ifdef RESOLVE
380
32e6df36
UD
381/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
382 Prelinked libraries may use Elf32_Rela though. */
383#ifdef RTLD_BOOTSTRAP
50746436 384# define ELF_MACHINE_NO_RELA 1
32e6df36
UD
385#endif
386
f51d1dfd
RM
387/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
388 MAP is the object containing the reloc. */
389
390static inline void
c84142e8 391elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
3996f34b 392 const Elf32_Sym *sym, const struct r_found_version *version,
87d254a7 393 void *const reloc_addr_arg)
f51d1dfd 394{
87d254a7 395 Elf32_Addr *const reloc_addr = reloc_addr_arg;
1721af3f
UD
396 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
397
a711b01d 398#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
1721af3f 399 if (__builtin_expect (r_type == R_386_RELATIVE, 0))
f51d1dfd 400 {
ee0cb67e 401# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
a778db06
UD
402 /* This is defined in rtld.c, but nowhere in the static libc.a;
403 make the reference weak so static programs can still link.
404 This declaration cannot be done when compiling rtld.c
405 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
406 common defn for _dl_rtld_map, which is incompatible with a
407 weak decl in the same file. */
5688da55 408# ifndef SHARED
a778db06 409 weak_extern (_dl_rtld_map);
5688da55
UD
410# endif
411 if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
a711b01d 412# endif
f51d1dfd 413 *reloc_addr += map->l_addr;
f51d1dfd 414 }
a711b01d 415# ifndef RTLD_BOOTSTRAP
3dc51a93 416 else if (__builtin_expect (r_type == R_386_NONE, 0))
1721af3f 417 return;
a711b01d 418# endif
1721af3f 419 else
d025fe26 420#endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
bc9f6000 421 {
bc9f6000 422 const Elf32_Sym *const refsym = sym;
5d6feea8
UD
423#if defined USE_TLS && !defined RTLD_BOOTSTRAP
424 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
425 Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
426#else
1721af3f 427 Elf32_Addr value = RESOLVE (&sym, version, r_type);
5d6feea8 428
535b764d 429# ifndef RTLD_BOOTSTRAP
5d6feea8 430 if (sym != NULL)
535b764d 431# endif
bc9f6000 432 value += sym->st_value;
d025fe26 433#endif /* use TLS and !RTLD_BOOTSTRAP */
bc9f6000 434
1721af3f 435 switch (r_type)
bc9f6000 436 {
a778db06
UD
437 case R_386_GLOB_DAT:
438 case R_386_JMP_SLOT:
439 *reloc_addr = value;
440 break;
535b764d 441
ce460d04 442#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
535b764d
UD
443 case R_386_TLS_DTPMOD32:
444# ifdef RTLD_BOOTSTRAP
445 /* During startup the dynamic linker is always the module
446 with index 1.
447 XXX If this relocation is necessary move before RESOLVE
448 call. */
449 *reloc_addr = 1;
450# else
5d6feea8
UD
451 /* Get the information from the link map returned by the
452 resolv function. */
453 if (sym_map != NULL)
454 *reloc_addr = sym_map->l_tls_modid;
535b764d
UD
455# endif
456 break;
457 case R_386_TLS_DTPOFF32:
458# ifndef RTLD_BOOTSTRAP
459 /* During relocation all TLS symbols are defined and used.
460 Therefore the offset is already correct. */
5d6feea8 461 if (sym != NULL)
4730fc68 462 *reloc_addr = sym->st_value;
535b764d
UD
463# endif
464 break;
465 case R_386_TLS_TPOFF32:
466 /* The offset is positive, backward from the thread pointer. */
467# ifdef RTLD_BOOTSTRAP
534feaab 468 *reloc_addr += map->l_tls_offset - sym->st_value;
535b764d 469# else
3632a260 470 /* We know the offset of object the symbol is contained in.
5d6feea8
UD
471 It is a positive value which will be subtracted from the
472 thread pointer. To get the variable position in the TLS
473 block we subtract the offset from that of the TLS block. */
4730fc68 474 if (sym != NULL)
eb775e67 475 {
eb775e67 476 CHECK_STATIC_TLS (map, sym_map);
aff4519d 477 *reloc_addr += sym_map->l_tls_offset - sym->st_value;
eb775e67 478 }
1d0ad773
RM
479# endif
480 break;
481 case R_386_TLS_TPOFF:
482 /* The offset is negative, forward from the thread pointer. */
483# ifdef RTLD_BOOTSTRAP
484 *reloc_addr += sym->st_value - map->l_tls_offset;
485# else
486 /* We know the offset of object the symbol is contained in.
487 It is a negative value which will be added to the
488 thread pointer. */
489 if (sym != NULL)
eb775e67 490 {
eb775e67 491 CHECK_STATIC_TLS (map, sym_map);
aff4519d 492 *reloc_addr += sym->st_value - sym_map->l_tls_offset;
eb775e67 493 }
535b764d
UD
494# endif
495 break;
5d6feea8 496#endif /* use TLS */
535b764d 497
5d6feea8 498#ifndef RTLD_BOOTSTRAP
a778db06
UD
499 case R_386_32:
500 *reloc_addr += value;
501 break;
502 case R_386_PC32:
503 *reloc_addr += (value - (Elf32_Addr) reloc_addr);
504 break;
bc9f6000 505 case R_386_COPY:
5107cf1d
UD
506 if (sym == NULL)
507 /* This can happen in trace mode if an object could not be
508 found. */
509 break;
20b02a2e
UD
510 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
511 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
d6b5d570 512 && GL(dl_verbose)))
1f07e617
UD
513 {
514 const char *strtab;
515
a42195db 516 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
35fc382a
UD
517 _dl_error_printf ("\
518%s: Symbol `%s' has different size in shared object, consider re-linking\n",
e6caf4e1 519 rtld_progname ?: "<program name unknown>",
35fc382a 520 strtab + refsym->st_name);
1f07e617 521 }
87d254a7
AO
522 memcpy (reloc_addr_arg, (void *) value,
523 MIN (sym->st_size, refsym->st_size));
bc9f6000 524 break;
bc9f6000 525 default:
1721af3f 526 _dl_reloc_bad_type (map, r_type, 0);
bc9f6000 527 break;
d025fe26 528#endif /* !RTLD_BOOTSTRAP */
5d6feea8 529 }
bc9f6000 530 }
f51d1dfd
RM
531}
532
32e6df36
UD
533#ifndef RTLD_BOOTSTRAP
534static inline void
535elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
536 const Elf32_Sym *sym, const struct r_found_version *version,
87d254a7 537 void *const reloc_addr_arg)
32e6df36 538{
87d254a7 539 Elf32_Addr *const reloc_addr = reloc_addr_arg;
5d6feea8
UD
540 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
541
32e6df36
UD
542 if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
543 *reloc_addr = map->l_addr + reloc->r_addend;
5d6feea8 544 else if (r_type != R_386_NONE)
32e6df36 545 {
92712dee
RM
546# ifndef RESOLVE_CONFLICT_FIND_MAP
547 const Elf32_Sym *const refsym = sym;
548# endif
5d6feea8
UD
549# ifdef USE_TLS
550 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
551 Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
552# else
8e27f45e 553 Elf32_Addr value = RESOLVE (&sym, version, r_type);
5d6feea8 554 if (sym != NULL)
32e6df36 555 value += sym->st_value;
d025fe26 556# endif
32e6df36
UD
557
558 switch (ELF32_R_TYPE (reloc->r_info))
559 {
560 case R_386_GLOB_DAT:
561 case R_386_JMP_SLOT:
562 case R_386_32:
563 *reloc_addr = value + reloc->r_addend;
564 break;
8e27f45e
RM
565# ifndef RESOLVE_CONFLICT_FIND_MAP
566 /* Not needed for dl-conflict.c. */
32e6df36
UD
567 case R_386_PC32:
568 *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
569 break;
4730fc68 570
8e27f45e 571# ifdef USE_TLS
4730fc68 572 case R_386_TLS_DTPMOD32:
4730fc68
RM
573 /* Get the information from the link map returned by the
574 resolv function. */
575 if (sym_map != NULL)
576 *reloc_addr = sym_map->l_tls_modid;
4730fc68
RM
577 break;
578 case R_386_TLS_DTPOFF32:
4730fc68
RM
579 /* During relocation all TLS symbols are defined and used.
580 Therefore the offset is already correct. */
581 *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
4730fc68
RM
582 break;
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. */
aff4519d 589 CHECK_STATIC_TLS (map, sym_map);
4730fc68
RM
590 *reloc_addr
591 = (sym == NULL ? 0 : sym_map->l_tls_offset - sym->st_value)
592 + reloc->r_addend;
1d0ad773
RM
593 break;
594 case R_386_TLS_TPOFF:
595 /* The offset is negative, forward from the thread pointer. */
596 /* We know the offset of object the symbol is contained in.
597 It is a negative value which will be added to the
598 thread pointer. */
aff4519d 599 CHECK_STATIC_TLS (map, sym_map);
1d0ad773
RM
600 *reloc_addr
601 = (sym == NULL ? 0 : sym->st_value - sym_map->l_tls_offset)
602 + reloc->r_addend;
4730fc68 603 break;
8e27f45e 604# endif /* use TLS */
92712dee
RM
605 case R_386_COPY:
606 if (sym == NULL)
607 /* This can happen in trace mode if an object could not be
608 found. */
609 break;
610 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
611 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
612 && GL(dl_verbose)))
613 {
614 const char *strtab;
615
616 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
617 _dl_error_printf ("\
618%s: Symbol `%s' has different size in shared object, consider re-linking\n",
619 rtld_progname ?: "<program name unknown>",
620 strtab + refsym->st_name);
621 }
87d254a7
AO
622 memcpy (reloc_addr_arg, (void *) value,
623 MIN (sym->st_size, refsym->st_size));
92712dee
RM
624 break;
625# endif /* !RESOLVE_CONFLICT_FIND_MAP */
32e6df36
UD
626 default:
627 /* We add these checks in the version to relocate ld.so only
628 if we are still debugging. */
5d6feea8 629 _dl_reloc_bad_type (map, r_type, 0);
32e6df36
UD
630 break;
631 }
632 }
633}
d025fe26 634#endif /* !RTLD_BOOTSTRAP */
32e6df36 635
1721af3f
UD
636static inline void
637elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
87d254a7 638 void *const reloc_addr_arg)
1721af3f 639{
87d254a7 640 Elf32_Addr *const reloc_addr = reloc_addr_arg;
a711b01d 641 assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);
1721af3f
UD
642 *reloc_addr += l_addr;
643}
644
32e6df36
UD
645#ifndef RTLD_BOOTSTRAP
646static inline void
647elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
87d254a7 648 void *const reloc_addr_arg)
32e6df36 649{
87d254a7 650 Elf32_Addr *const reloc_addr = reloc_addr_arg;
32e6df36
UD
651 *reloc_addr = l_addr + reloc->r_addend;
652}
d025fe26 653#endif /* !RTLD_BOOTSTRAP */
32e6df36 654
f51d1dfd 655static inline void
421c80d2
RM
656elf_machine_lazy_rel (struct link_map *map,
657 Elf32_Addr l_addr, const Elf32_Rel *reloc)
f51d1dfd 658{
b0cf070b 659 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
1721af3f 660 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
b0cf070b 661 /* Check for unexpected PLT reloc type. */
1721af3f 662 if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
32e6df36
UD
663 {
664 if (__builtin_expect (map->l_mach.plt, 0) == 0)
665 *reloc_addr += l_addr;
666 else
50746436
UD
667 *reloc_addr = (map->l_mach.plt
668 + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
32e6df36 669 }
421c80d2 670 else
1721af3f 671 _dl_reloc_bad_type (map, r_type, 1);
f51d1dfd
RM
672}
673
32e6df36
UD
674#ifndef RTLD_BOOTSTRAP
675
676static inline void
677elf_machine_lazy_rela (struct link_map *map,
678 Elf32_Addr l_addr, const Elf32_Rela *reloc)
679{
680}
681
d025fe26 682#endif /* !RTLD_BOOTSTRAP */
32e6df36 683
f51d1dfd 684#endif /* RESOLVE */
This page took 0.380781 seconds and 5 git commands to generate.