]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Machine-dependent ELF dynamic relocation inline functions. i386 version. |
d6b5d570 | 2 | Copyright (C) 1995,96,97,98,99,2000,2001,2002 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 UD |
25 | #include <sys/param.h> |
26 | ||
2e36cb48 UD |
27 | #include <tls.h> |
28 | ||
ceb579a3 | 29 | /* Return nonzero iff ELF header is compatible with the running host. */ |
e75154a6 | 30 | static inline int __attribute__ ((unused)) |
ceb579a3 | 31 | elf_machine_matches_host (const Elf32_Ehdr *ehdr) |
d66e34cd | 32 | { |
ceb579a3 | 33 | return ehdr->e_machine == EM_386; |
d66e34cd RM |
34 | } |
35 | ||
36 | ||
47707456 UD |
37 | /* Return the link-time address of _DYNAMIC. Conveniently, this is the |
38 | first element of the GOT. This must be inlined in a function which | |
39 | uses global data. */ | |
0a54e401 | 40 | static inline Elf32_Addr __attribute__ ((unused)) |
47707456 | 41 | elf_machine_dynamic (void) |
d66e34cd RM |
42 | { |
43 | register Elf32_Addr *got asm ("%ebx"); | |
47707456 | 44 | return *got; |
d66e34cd RM |
45 | } |
46 | ||
47 | ||
48 | /* Return the run-time load address of the shared object. */ | |
e75154a6 | 49 | static inline Elf32_Addr __attribute__ ((unused)) |
d66e34cd RM |
50 | elf_machine_load_address (void) |
51 | { | |
52 | Elf32_Addr addr; | |
92f1da4d UD |
53 | asm ("leal _dl_start@GOTOFF(%%ebx), %0\n" |
54 | "subl _dl_start@GOT(%%ebx), %0" | |
55 | : "=r" (addr) : : "cc"); | |
d66e34cd RM |
56 | return addr; |
57 | } | |
d66e34cd | 58 | |
7884bf47 | 59 | #if !defined PROF && !__BOUNDED_POINTERS__ |
831372e7 UD |
60 | /* We add a declaration of this function here so that in dl-runtime.c |
61 | the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters | |
5ae9d168 UD |
62 | in registers. |
63 | ||
64 | We cannot use this scheme for profiling because the _mcount call | |
65 | destroys the passed register information. */ | |
7884bf47 GM |
66 | /* GKM FIXME: Fix trampoline to pass bounds so we can do |
67 | without the `__unbounded' qualifier. */ | |
68 | static ElfW(Addr) fixup (struct link_map *__unbounded l, ElfW(Word) reloc_offset) | |
831372e7 | 69 | __attribute__ ((regparm (2), unused)); |
3996f34b UD |
70 | static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset, |
71 | ElfW(Addr) retaddr) | |
72 | __attribute__ ((regparm (3), unused)); | |
5ae9d168 | 73 | #endif |
831372e7 | 74 | |
d66e34cd RM |
75 | /* Set up the loaded object described by L so its unrelocated PLT |
76 | entries will jump to the on-demand fixup code in dl-runtime.c. */ | |
77 | ||
0a54e401 | 78 | static inline int __attribute__ ((unused)) |
3996f34b | 79 | elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) |
d66e34cd | 80 | { |
a1a9d215 | 81 | Elf32_Addr *got; |
5c82e15e UD |
82 | extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; |
83 | extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; | |
a1a9d215 | 84 | |
a2e1b046 RM |
85 | if (l->l_info[DT_JMPREL] && lazy) |
86 | { | |
87 | /* The GOT entries for functions in the PLT have not yet been filled | |
88 | in. Their initial contents will arrange when called to push an | |
89 | offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1], | |
90 | and then jump to _GLOBAL_OFFSET_TABLE[2]. */ | |
a42195db | 91 | got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); |
32e6df36 UD |
92 | /* If a library is prelinked but we have to relocate anyway, |
93 | we have to be able to undo the prelinking of .got.plt. | |
94 | The prelinker saved us here address of .plt + 0x16. */ | |
95 | if (got[1]) | |
96 | { | |
97 | l->l_mach.plt = got[1] + l->l_addr; | |
98 | l->l_mach.gotplt = (Elf32_Addr) &got[3]; | |
d6b5d570 | 99 | } |
a2e1b046 | 100 | got[1] = (Elf32_Addr) l; /* Identify this shared object. */ |
3996f34b UD |
101 | |
102 | /* The got[2] entry contains the address of a function which gets | |
103 | called to get the address of a so far unresolved function and | |
104 | jump to it. The profiling extension of the dynamic linker allows | |
105 | to intercept the calls to collect information. In this case we | |
106 | don't store the address in the GOT so that all future calls also | |
107 | end in this function. */ | |
d4f170a9 | 108 | if (__builtin_expect (profile, 0)) |
3996f34b UD |
109 | { |
110 | got[2] = (Elf32_Addr) &_dl_runtime_profile; | |
c0fb8a56 | 111 | |
d6b5d570 | 112 | if (_dl_name_match_p (GL(dl_profile), l)) |
c0fb8a56 UD |
113 | /* This is the object we are looking for. Say that we really |
114 | want profiling and the timers are started. */ | |
d6b5d570 | 115 | GL(dl_profile_map) = l; |
3996f34b UD |
116 | } |
117 | else | |
118 | /* This function will get called to fix up the GOT entry indicated by | |
119 | the offset on the stack, and then jump to the resolved address. */ | |
120 | got[2] = (Elf32_Addr) &_dl_runtime_resolve; | |
a2e1b046 | 121 | } |
d66e34cd | 122 | |
0501d603 UD |
123 | return lazy; |
124 | } | |
831372e7 | 125 | |
0501d603 UD |
126 | /* This code is used in dl-runtime.c to call the `fixup' function |
127 | and then redirect to the address it returns. */ | |
7884bf47 | 128 | #if !defined PROF && !__BOUNDED_POINTERS__ |
5ae9d168 | 129 | # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\ |
2a56ca2a AJ |
130 | .text\n\ |
131 | .globl _dl_runtime_resolve\n\ | |
132 | .type _dl_runtime_resolve, @function\n\ | |
133 | .align 16\n\ | |
134 | _dl_runtime_resolve:\n\ | |
135 | pushl %eax # Preserve registers otherwise clobbered.\n\ | |
136 | pushl %ecx\n\ | |
137 | pushl %edx\n\ | |
138 | movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\ | |
139 | movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\ | |
140 | call fixup # Call resolver.\n\ | |
141 | popl %edx # Get register content back.\n\ | |
142 | popl %ecx\n\ | |
143 | xchgl %eax, (%esp) # Get %eax contents end store function address.\n\ | |
144 | ret $8 # Jump to function address.\n\ | |
145 | .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\ | |
146 | \n\ | |
147 | .globl _dl_runtime_profile\n\ | |
148 | .type _dl_runtime_profile, @function\n\ | |
149 | .align 16\n\ | |
150 | _dl_runtime_profile:\n\ | |
151 | pushl %eax # Preserve registers otherwise clobbered.\n\ | |
152 | pushl %ecx\n\ | |
153 | pushl %edx\n\ | |
154 | movl 20(%esp), %ecx # Load return address\n\ | |
155 | movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\ | |
156 | movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\ | |
157 | call profile_fixup # Call resolver.\n\ | |
158 | popl %edx # Get register content back.\n\ | |
159 | popl %ecx\n\ | |
160 | xchgl %eax, (%esp) # Get %eax contents end store function address.\n\ | |
161 | ret $8 # Jump to function address.\n\ | |
162 | .size _dl_runtime_profile, .-_dl_runtime_profile\n\ | |
163 | .previous\n\ | |
38334018 | 164 | "); |
5ae9d168 | 165 | #else |
2a56ca2a AJ |
166 | # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\ |
167 | .text\n\ | |
168 | .globl _dl_runtime_resolve\n\ | |
169 | .globl _dl_runtime_profile\n\ | |
170 | .type _dl_runtime_resolve, @function\n\ | |
171 | .type _dl_runtime_profile, @function\n\ | |
172 | .align 16\n\ | |
173 | _dl_runtime_resolve:\n\ | |
174 | _dl_runtime_profile:\n\ | |
175 | pushl %eax # Preserve registers otherwise clobbered.\n\ | |
176 | pushl %ecx\n\ | |
177 | pushl %edx\n\ | |
178 | movl 16(%esp), %edx # Push the arguments for `fixup'\n\ | |
179 | movl 12(%esp), %eax\n\ | |
180 | pushl %edx\n\ | |
181 | pushl %eax\n\ | |
182 | call fixup # Call resolver.\n\ | |
183 | popl %edx # Pop the parameters\n\ | |
184 | popl %ecx\n\ | |
185 | popl %edx # Get register content back.\n\ | |
186 | popl %ecx\n\ | |
187 | xchgl %eax, (%esp) # Get %eax contents end store function address.\n\ | |
188 | ret $8 # Jump to function address.\n\ | |
189 | .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\ | |
190 | .size _dl_runtime_profile, .-_dl_runtime_profile\n\ | |
191 | .previous\n\ | |
5ae9d168 UD |
192 | "); |
193 | #endif | |
d66e34cd | 194 | |
5bf62f2d RM |
195 | /* Mask identifying addresses reserved for the user program, |
196 | where the dynamic linker should not map anything. */ | |
197 | #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL | |
198 | ||
d66e34cd RM |
199 | /* Initial entry point code for the dynamic linker. |
200 | The C function `_dl_start' is the real entry point; | |
201 | its return value is the user program's entry point. */ | |
202 | ||
2a56ca2a AJ |
203 | #define RTLD_START asm ("\n\ |
204 | .text\n\ | |
9ad04ff7 UD |
205 | .align 16\n\ |
206 | 0: movl (%esp), %ebx\n\ | |
207 | ret\n\ | |
208 | .align 16\n\ | |
d66e34cd | 209 | .globl _start\n\ |
421f82e5 RM |
210 | .globl _dl_start_user\n\ |
211 | _start:\n\ | |
50746436 UD |
212 | # Note that _dl_start gets the parameter in %eax.\n\ |
213 | movl %esp, %eax\n\ | |
421f82e5 RM |
214 | call _dl_start\n\ |
215 | _dl_start_user:\n\ | |
216 | # Save the user entry point address in %edi.\n\ | |
217 | movl %eax, %edi\n\ | |
2a56ca2a | 218 | # Point %ebx at the GOT.\n\ |
9ad04ff7 UD |
219 | call 0b\n\ |
220 | addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\ | |
c0fb8a56 | 221 | # Store the highest stack address\n\ |
95a99ee6 UD |
222 | movl __libc_stack_end@GOT(%ebx), %eax\n\ |
223 | movl %esp, (%eax)\n\ | |
a1a9d215 RM |
224 | # See if we were run as a command with the executable file\n\ |
225 | # name as an extra leading argument.\n\ | |
5c82e15e | 226 | movl _dl_skip_args@GOTOFF(%ebx), %eax\n\ |
24906b43 | 227 | # Pop the original argument count.\n\ |
0a63529d | 228 | popl %edx\n\ |
24906b43 RM |
229 | # Adjust the stack pointer to skip _dl_skip_args words.\n\ |
230 | leal (%esp,%eax,4), %esp\n\ | |
5879ee9f | 231 | # Subtract _dl_skip_args from argc.\n\ |
0a63529d | 232 | subl %eax, %edx\n\ |
5879ee9f | 233 | # Push argc back on the stack.\n\ |
0a63529d | 234 | push %edx\n\ |
5879ee9f RM |
235 | # The special initializer gets called with the stack just\n\ |
236 | # as the application's entry point will see it; it can\n\ | |
237 | # switch stacks if it moves these contents over.\n\ | |
238 | " RTLD_START_SPECIAL_INIT "\n\ | |
dacc8ffa | 239 | # Load the parameters again.\n\ |
5879ee9f | 240 | # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\ |
0d01dace UD |
241 | movl _rtld_local@GOTOFF(%ebx), %eax\n\ |
242 | leal 8(%esp,%edx,4), %esi\n\ | |
5879ee9f | 243 | leal 4(%esp), %ecx\n\ |
0d01dace | 244 | pushl %esi\n\ |
dacc8ffa | 245 | # Call the function to run the initializers.\n\ |
7969407a | 246 | call _dl_init_internal@PLT\n\ |
39778c6c | 247 | # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\ |
5c82e15e | 248 | leal _dl_fini@GOTOFF(%ebx), %edx\n\ |
421f82e5 RM |
249 | # Jump to the user's entry point.\n\ |
250 | jmp *%edi\n\ | |
2a56ca2a | 251 | .previous\n\ |
d66e34cd | 252 | "); |
f51d1dfd | 253 | |
5879ee9f | 254 | #ifndef RTLD_START_SPECIAL_INIT |
50746436 | 255 | # define RTLD_START_SPECIAL_INIT /* nothing */ |
5879ee9f RM |
256 | #endif |
257 | ||
2e36cb48 UD |
258 | /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or |
259 | TLS variable, so undefined references should not be allowed to | |
260 | define the value. | |
cf5a372e UD |
261 | ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one |
262 | of the main executable's symbols, as for a COPY reloc. */ | |
2e36cb48 UD |
263 | #ifdef USE_TLS |
264 | # define elf_machine_type_class(type) \ | |
265 | ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \ | |
266 | || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32) \ | |
267 | * ELF_RTYPE_CLASS_PLT) \ | |
268 | | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY)) | |
269 | #else | |
270 | # define elf_machine_type_class(type) \ | |
271 | ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ | |
cf5a372e | 272 | | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY)) |
2e36cb48 | 273 | #endif |
bc9f6000 UD |
274 | |
275 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ | |
a2b08ee5 | 276 | #define ELF_MACHINE_JMP_SLOT R_386_JMP_SLOT |
f51d1dfd | 277 | |
32e6df36 UD |
278 | /* The i386 never uses Elf32_Rela relocations for the dynamic linker. |
279 | Prelinked libraries may use Elf32_Rela though. */ | |
280 | #define ELF_MACHINE_PLT_REL 1 | |
f51d1dfd | 281 | |
0a54e401 UD |
282 | /* We define an initialization functions. This is called very early in |
283 | _dl_sysdep_start. */ | |
284 | #define DL_PLATFORM_INIT dl_platform_init () | |
285 | ||
0a54e401 UD |
286 | static inline void __attribute__ ((unused)) |
287 | dl_platform_init (void) | |
288 | { | |
d6b5d570 | 289 | if (GL(dl_platform) != NULL && *GL(dl_platform) == '\0') |
27a5bb33 | 290 | /* Avoid an empty string which would disturb us. */ |
d6b5d570 | 291 | GL(dl_platform) = NULL; |
0a54e401 UD |
292 | } |
293 | ||
c0282c06 UD |
294 | static inline Elf32_Addr |
295 | elf_machine_fixup_plt (struct link_map *map, lookup_t t, | |
296 | const Elf32_Rel *reloc, | |
a2b08ee5 UD |
297 | Elf32_Addr *reloc_addr, Elf32_Addr value) |
298 | { | |
c0282c06 | 299 | return *reloc_addr = value; |
a2b08ee5 UD |
300 | } |
301 | ||
dfd2257a UD |
302 | /* Return the final value of a plt relocation. */ |
303 | static inline Elf32_Addr | |
304 | elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc, | |
305 | Elf32_Addr value) | |
306 | { | |
307 | return value; | |
308 | } | |
309 | ||
f51d1dfd RM |
310 | #endif /* !dl_machine_h */ |
311 | ||
312 | #ifdef RESOLVE | |
313 | ||
32e6df36 UD |
314 | /* The i386 never uses Elf32_Rela relocations for the dynamic linker. |
315 | Prelinked libraries may use Elf32_Rela though. */ | |
316 | #ifdef RTLD_BOOTSTRAP | |
50746436 | 317 | # define ELF_MACHINE_NO_RELA 1 |
32e6df36 UD |
318 | #endif |
319 | ||
f51d1dfd RM |
320 | /* Perform the relocation specified by RELOC and SYM (which is fully resolved). |
321 | MAP is the object containing the reloc. */ | |
322 | ||
323 | static inline void | |
c84142e8 | 324 | elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, |
3996f34b UD |
325 | const Elf32_Sym *sym, const struct r_found_version *version, |
326 | Elf32_Addr *const reloc_addr) | |
f51d1dfd | 327 | { |
1721af3f UD |
328 | const unsigned int r_type = ELF32_R_TYPE (reloc->r_info); |
329 | ||
a711b01d | 330 | #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC |
1721af3f | 331 | if (__builtin_expect (r_type == R_386_RELATIVE, 0)) |
f51d1dfd | 332 | { |
ee0cb67e | 333 | # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC |
a778db06 UD |
334 | /* This is defined in rtld.c, but nowhere in the static libc.a; |
335 | make the reference weak so static programs can still link. | |
336 | This declaration cannot be done when compiling rtld.c | |
337 | (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the | |
338 | common defn for _dl_rtld_map, which is incompatible with a | |
339 | weak decl in the same file. */ | |
5688da55 | 340 | # ifndef SHARED |
a778db06 | 341 | weak_extern (_dl_rtld_map); |
5688da55 UD |
342 | # endif |
343 | if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */ | |
a711b01d | 344 | # endif |
f51d1dfd | 345 | *reloc_addr += map->l_addr; |
f51d1dfd | 346 | } |
a711b01d | 347 | # ifndef RTLD_BOOTSTRAP |
3dc51a93 | 348 | else if (__builtin_expect (r_type == R_386_NONE, 0)) |
1721af3f | 349 | return; |
a711b01d | 350 | # endif |
1721af3f | 351 | else |
a711b01d | 352 | #endif |
bc9f6000 | 353 | { |
bc9f6000 | 354 | const Elf32_Sym *const refsym = sym; |
5d6feea8 UD |
355 | #if defined USE_TLS && !defined RTLD_BOOTSTRAP |
356 | struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); | |
357 | Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value; | |
358 | #else | |
1721af3f | 359 | Elf32_Addr value = RESOLVE (&sym, version, r_type); |
5d6feea8 | 360 | |
535b764d | 361 | # ifndef RTLD_BOOTSTRAP |
5d6feea8 | 362 | if (sym != NULL) |
535b764d | 363 | # endif |
bc9f6000 | 364 | value += sym->st_value; |
5d6feea8 | 365 | #endif |
bc9f6000 | 366 | |
1721af3f | 367 | switch (r_type) |
bc9f6000 | 368 | { |
a778db06 UD |
369 | case R_386_GLOB_DAT: |
370 | case R_386_JMP_SLOT: | |
371 | *reloc_addr = value; | |
372 | break; | |
535b764d UD |
373 | |
374 | /* XXX Remove TLS relocations which are not needed. */ | |
375 | ||
5d6feea8 | 376 | #ifdef USE_TLS |
535b764d UD |
377 | case R_386_TLS_DTPMOD32: |
378 | # ifdef RTLD_BOOTSTRAP | |
379 | /* During startup the dynamic linker is always the module | |
380 | with index 1. | |
381 | XXX If this relocation is necessary move before RESOLVE | |
382 | call. */ | |
383 | *reloc_addr = 1; | |
384 | # else | |
5d6feea8 UD |
385 | /* Get the information from the link map returned by the |
386 | resolv function. */ | |
387 | if (sym_map != NULL) | |
388 | *reloc_addr = sym_map->l_tls_modid; | |
535b764d UD |
389 | # endif |
390 | break; | |
391 | case R_386_TLS_DTPOFF32: | |
392 | # ifndef RTLD_BOOTSTRAP | |
393 | /* During relocation all TLS symbols are defined and used. | |
394 | Therefore the offset is already correct. */ | |
5d6feea8 UD |
395 | if (sym != NULL) |
396 | *reloc_addr = sym->st_value; | |
535b764d UD |
397 | # endif |
398 | break; | |
399 | case R_386_TLS_TPOFF32: | |
400 | /* The offset is positive, backward from the thread pointer. */ | |
401 | # ifdef RTLD_BOOTSTRAP | |
739d440d | 402 | *reloc_addr = map->l_tls_offset - sym->st_value; |
535b764d | 403 | # else |
3632a260 | 404 | /* We know the offset of object the symbol is contained in. |
5d6feea8 UD |
405 | It is a positive value which will be subtracted from the |
406 | thread pointer. To get the variable position in the TLS | |
407 | block we subtract the offset from that of the TLS block. */ | |
408 | if (sym_map != NULL && sym != NULL) | |
409 | *reloc_addr = sym_map->l_tls_offset - sym->st_value; | |
535b764d UD |
410 | # endif |
411 | break; | |
5d6feea8 | 412 | #endif /* use TLS */ |
535b764d | 413 | |
5d6feea8 | 414 | #ifndef RTLD_BOOTSTRAP |
a778db06 UD |
415 | case R_386_32: |
416 | *reloc_addr += value; | |
417 | break; | |
418 | case R_386_PC32: | |
419 | *reloc_addr += (value - (Elf32_Addr) reloc_addr); | |
420 | break; | |
bc9f6000 | 421 | case R_386_COPY: |
5107cf1d UD |
422 | if (sym == NULL) |
423 | /* This can happen in trace mode if an object could not be | |
424 | found. */ | |
425 | break; | |
20b02a2e UD |
426 | if (__builtin_expect (sym->st_size > refsym->st_size, 0) |
427 | || (__builtin_expect (sym->st_size < refsym->st_size, 0) | |
d6b5d570 | 428 | && GL(dl_verbose))) |
1f07e617 UD |
429 | { |
430 | const char *strtab; | |
431 | ||
a42195db | 432 | strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]); |
35fc382a UD |
433 | _dl_error_printf ("\ |
434 | %s: Symbol `%s' has different size in shared object, consider re-linking\n", | |
e6caf4e1 | 435 | rtld_progname ?: "<program name unknown>", |
35fc382a | 436 | strtab + refsym->st_name); |
1f07e617 UD |
437 | } |
438 | memcpy (reloc_addr, (void *) value, MIN (sym->st_size, | |
439 | refsym->st_size)); | |
bc9f6000 | 440 | break; |
bc9f6000 | 441 | default: |
1721af3f | 442 | _dl_reloc_bad_type (map, r_type, 0); |
bc9f6000 | 443 | break; |
680254fe | 444 | #endif |
5d6feea8 | 445 | } |
bc9f6000 | 446 | } |
f51d1dfd RM |
447 | } |
448 | ||
32e6df36 UD |
449 | #ifndef RTLD_BOOTSTRAP |
450 | static inline void | |
451 | elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, | |
452 | const Elf32_Sym *sym, const struct r_found_version *version, | |
453 | Elf32_Addr *const reloc_addr) | |
454 | { | |
5d6feea8 UD |
455 | const unsigned int r_type = ELF32_R_TYPE (reloc->r_info); |
456 | ||
32e6df36 UD |
457 | if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE) |
458 | *reloc_addr = map->l_addr + reloc->r_addend; | |
5d6feea8 | 459 | else if (r_type != R_386_NONE) |
32e6df36 | 460 | { |
5d6feea8 UD |
461 | # ifdef USE_TLS |
462 | struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); | |
463 | Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value; | |
464 | # else | |
32e6df36 | 465 | Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info)); |
5d6feea8 | 466 | if (sym != NULL) |
32e6df36 | 467 | value += sym->st_value; |
5d6feea8 | 468 | #endif |
32e6df36 UD |
469 | |
470 | switch (ELF32_R_TYPE (reloc->r_info)) | |
471 | { | |
472 | case R_386_GLOB_DAT: | |
473 | case R_386_JMP_SLOT: | |
474 | case R_386_32: | |
475 | *reloc_addr = value + reloc->r_addend; | |
476 | break; | |
477 | case R_386_PC32: | |
478 | *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr); | |
479 | break; | |
5d6feea8 | 480 | /* XXX Do we have to handle the TLS relocation here? */ |
32e6df36 UD |
481 | default: |
482 | /* We add these checks in the version to relocate ld.so only | |
483 | if we are still debugging. */ | |
5d6feea8 | 484 | _dl_reloc_bad_type (map, r_type, 0); |
32e6df36 UD |
485 | break; |
486 | } | |
487 | } | |
488 | } | |
489 | #endif | |
490 | ||
1721af3f UD |
491 | static inline void |
492 | elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc, | |
493 | Elf32_Addr *const reloc_addr) | |
494 | { | |
a711b01d | 495 | assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE); |
1721af3f UD |
496 | *reloc_addr += l_addr; |
497 | } | |
498 | ||
32e6df36 UD |
499 | #ifndef RTLD_BOOTSTRAP |
500 | static inline void | |
501 | elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc, | |
502 | Elf32_Addr *const reloc_addr) | |
503 | { | |
504 | *reloc_addr = l_addr + reloc->r_addend; | |
505 | } | |
506 | #endif | |
507 | ||
f51d1dfd | 508 | static inline void |
421c80d2 RM |
509 | elf_machine_lazy_rel (struct link_map *map, |
510 | Elf32_Addr l_addr, const Elf32_Rel *reloc) | |
f51d1dfd | 511 | { |
b0cf070b | 512 | Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset); |
1721af3f | 513 | const unsigned int r_type = ELF32_R_TYPE (reloc->r_info); |
b0cf070b | 514 | /* Check for unexpected PLT reloc type. */ |
1721af3f | 515 | if (__builtin_expect (r_type == R_386_JMP_SLOT, 1)) |
32e6df36 UD |
516 | { |
517 | if (__builtin_expect (map->l_mach.plt, 0) == 0) | |
518 | *reloc_addr += l_addr; | |
519 | else | |
50746436 UD |
520 | *reloc_addr = (map->l_mach.plt |
521 | + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4); | |
32e6df36 | 522 | } |
421c80d2 | 523 | else |
1721af3f | 524 | _dl_reloc_bad_type (map, r_type, 1); |
f51d1dfd RM |
525 | } |
526 | ||
32e6df36 UD |
527 | #ifndef RTLD_BOOTSTRAP |
528 | ||
529 | static inline void | |
530 | elf_machine_lazy_rela (struct link_map *map, | |
531 | Elf32_Addr l_addr, const Elf32_Rela *reloc) | |
532 | { | |
533 | } | |
534 | ||
535 | #endif | |
536 | ||
f51d1dfd | 537 | #endif /* RESOLVE */ |