]>
Commit | Line | Data |
---|---|---|
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 | 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 | ||
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. */ | |
43 | static inline Elf32_Addr __attribute__ ((unused, const)) | |
44 | elf_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. */ | |
54 | static inline Elf32_Addr __attribute__ ((unused)) | |
55 | elf_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 | 69 | static inline Elf32_Addr __attribute__ ((unused)) |
47707456 | 70 | elf_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 | 78 | static inline Elf32_Addr __attribute__ ((unused)) |
d66e34cd RM |
79 | elf_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 | 98 | static inline int __attribute__ ((unused, always_inline)) |
3996f34b | 99 | elf_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. */ | |
157 | static ElfW(Addr) fixup (struct link_map *__unbounded l, ElfW(Word) reloc_offset) | |
158 | __attribute__ ((regparm (2), unused)); | |
159 | static 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\ |
273 | 0: 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 |
353 | static inline void __attribute__ ((unused)) |
354 | dl_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 |
361 | static inline Elf32_Addr |
362 | elf_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. */ |
370 | static inline Elf32_Addr | |
371 | elf_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 | ||
390 | static inline void | |
c84142e8 | 391 | elf_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 |
534 | static inline void | |
535 | elf_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 |
636 | static inline void |
637 | elf_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 |
646 | static inline void | |
647 | elf_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 | 655 | static inline void |
421c80d2 RM |
656 | elf_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 | ||
676 | static inline void | |
677 | elf_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 */ |