]> sourceware.org Git - glibc.git/blame - sysdeps/sparc/sparc32/dl-machine.h
Update.
[glibc.git] / sysdeps / sparc / sparc32 / dl-machine.h
CommitLineData
4f54cdb1 1/* Machine-dependent ELF dynamic relocation inline functions. SPARC version.
f420344c 2 Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
47707456 3 This file is part of the GNU C Library.
4f54cdb1 4
47707456
UD
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
4f54cdb1 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
13 Library General Public License for more details.
4f54cdb1 14
47707456
UD
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
4f54cdb1
RM
19
20#define ELF_MACHINE_NAME "sparc"
21
4f54cdb1 22#include <string.h>
1f07e617 23#include <sys/param.h>
4194bc66 24#include <elf/ldsodefs.h>
4f54cdb1
RM
25
26
27/* Some SPARC opcodes we need to use for self-modifying code. */
28#define OPCODE_NOP 0x01000000 /* nop */
f752bfe3 29#define OPCODE_CALL 0x40000000 /* call ?; add PC-rel word address */
4f54cdb1
RM
30#define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
31#define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
f41c8091 32#define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
4f54cdb1 33
4194bc66
RH
34/* Protect some broken versions of gcc from misinterpreting weak addresses. */
35#define WEAKADDR(x) ({ __typeof(x) *_px = &x; \
36 __asm ("" : "=r" (_px) : "0" (_px)); \
b062f051 37 _px; })
4194bc66
RH
38
39
40/* Use a different preload file when running in 32-bit emulation mode
41 on a 64-bit host. */
42#define LD_SO_PRELOAD ((_dl_hwcap & HWCAP_SPARC_V9) ? "/etc/ld.so.preload32" \
43 : "/etc/ld.so.preload")
44
45
4f54cdb1
RM
46/* Return nonzero iff E_MACHINE is compatible with the running host. */
47static inline int
48elf_machine_matches_host (Elf32_Half e_machine)
49{
4194bc66
RH
50 if (e_machine == EM_SPARC)
51 return 1;
52 else if (e_machine == EM_SPARC32PLUS)
53 {
b7e6f7bf
RH
54 unsigned long *hwcap;
55 weak_extern (_dl_hwcap);
56 weak_extern (_dl_hwcap_mask);
57
58 hwcap = WEAKADDR(_dl_hwcap);
4194bc66
RH
59 return hwcap && (*hwcap & _dl_hwcap_mask & HWCAP_SPARC_V9);
60 }
61 else
62 return 0;
4f54cdb1
RM
63}
64
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. */
69static inline Elf32_Addr
70elf_machine_dynamic (void)
4f54cdb1
RM
71{
72 register Elf32_Addr *got asm ("%l7");
47707456 73 return *got;
4f54cdb1
RM
74}
75
4f54cdb1
RM
76/* Return the run-time load address of the shared object. */
77static inline Elf32_Addr
78elf_machine_load_address (void)
79{
f41c8091 80 register Elf32_Addr pc __asm("%o7"), pic __asm("%l7"), got;
ca34d7a7
UD
81
82 /* Utilize the fact that a local .got entry will be partially
83 initialized at startup awaiting its RELATIVE fixup. */
84
85 __asm("sethi %%hi(.Load_address),%1\n"
86 ".Load_address:\n\t"
87 "call 1f\n\t"
88 "or %1,%%lo(.Load_address),%1\n"
f41c8091
UD
89 "1:\tld [%2+%1],%1"
90 : "=r"(pc), "=r"(got) : "r"(pic));
ca34d7a7
UD
91
92 return pc - got;
93}
94
f41c8091
UD
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
98static inline int
99elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
100{
101 Elf32_Addr *plt;
102 extern void _dl_runtime_resolve (Elf32_Word);
9c4c0024 103 extern void _dl_runtime_profile (Elf32_Word);
f41c8091
UD
104
105 if (l->l_info[DT_JMPREL] && lazy)
106 {
9c4c0024
UD
107 Elf32_Addr rfunc;
108
f41c8091
UD
109 /* The entries for functions in the PLT have not yet been filled in.
110 Their initial contents will arrange when called to set the high 22
111 bits of %g1 with an offset into the .rela.plt section and jump to
112 the beginning of the PLT. */
7796221a 113 plt = (Elf32_Addr *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
9c4c0024
UD
114 if (! profile)
115 rfunc = (Elf32_Addr) &_dl_runtime_resolve;
116 else
117 {
118 rfunc = (Elf32_Addr) &_dl_runtime_profile;
119
120 if (_dl_name_match_p (_dl_profile, l))
121 _dl_profile_map = l;
122 }
f41c8091
UD
123
124 /* The beginning of the PLT does:
125
126 save %sp, -64, %sp
127 pltpc: call _dl_runtime_resolve
128 nop
129 .word MAP
130
131 This saves the register window containing the arguments, and the
132 PC value (pltpc) implicitly saved in %o7 by the call points near the
133 location where we store the link_map pointer for this object. */
134
135 plt[0] = OPCODE_SAVE_SP;
136 /* Construct PC-relative word address. */
9c4c0024 137 plt[1] = OPCODE_CALL | ((rfunc - (Elf32_Addr) &plt[1]) >> 2);
f41c8091
UD
138 plt[2] = OPCODE_NOP; /* Fill call delay slot. */
139 plt[3] = (Elf32_Addr) l;
140 }
141
142 return lazy;
4f54cdb1
RM
143}
144
f41c8091
UD
145/* This code is used in dl-runtime.c to call the `fixup' function
146 and then redirect to the address it returns. */
9c4c0024
UD
147#define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
148 asm ( "\
149 .text
150 .globl " #tramp_name "
151 .type " #tramp_name ", @function
152 .align 32
153" #tramp_name ":
f41c8091
UD
154 /* Set up the arguments to fixup --
155 %o0 = link_map out of plt0
9c4c0024
UD
156 %o1 = offset of reloc entry
157 %o2 = return address */
f41c8091
UD
158 ld [%o7 + 8], %o0
159 srl %g1, 10, %o1
9c4c0024
UD
160 mov %i7, %o2
161 call " #fixup_name "
f41c8091
UD
162 sub %o1, 4*12, %o1
163 jmp %o0
164 restore
9c4c0024
UD
165 .size " #tramp_name ", . - " #tramp_name "
166 .previous")
167
168#ifndef PROF
169#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
170 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
171 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
172#else
173#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
174 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
175 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, fixup);
176#endif
f41c8091 177
f41c8091
UD
178/* Nonzero iff TYPE should not be allowed to resolve to one of
179 the main executable's symbols, as for a COPY reloc. */
180#define elf_machine_lookup_noexec_p(type) ((type) == R_SPARC_COPY)
181
182/* Nonzero iff TYPE describes relocation of a PLT entry, so
183 PLT entries should not be allowed to define the value. */
184#define elf_machine_lookup_noplt_p(type) ((type) == R_SPARC_JMP_SLOT)
185
186/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 187#define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
f41c8091
UD
188
189/* The SPARC never uses Elf32_Rel relocations. */
190#define ELF_MACHINE_NO_REL 1
191
192/* The SPARC overlaps DT_RELA and DT_PLTREL. */
193#define ELF_MACHINE_PLTREL_OVERLAP 1
194
f41c8091
UD
195/* Initial entry point code for the dynamic linker.
196 The C function `_dl_start' is the real entry point;
197 its return value is the user program's entry point. */
198
199#define RTLD_START __asm__ ("\
9c4c0024
UD
200 .text
201 .globl _start
202 .type _start, @function
203 .align 32
f41c8091
UD
204_start:
205 /* Allocate space for functions to drop their arguments. */
206 sub %sp, 6*4, %sp
207 /* Pass pointer to argument block to _dl_start. */
208 call _dl_start
209 add %sp, 22*4, %o0
210 /* FALTHRU */
9c4c0024
UD
211 .globl _dl_start_user
212 .type _dl_start_user, @function
f41c8091
UD
213_dl_start_user:
214 /* Load the PIC register. */
2151: call 2f
216 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7
2172: or %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7
218 add %l7, %o7, %l7
219 /* Save the user entry point address in %l0 */
220 mov %o0, %l0
9c4c0024
UD
221 /* Store the highest stack address. */
222 sethi %hi(__libc_stack_end), %g2
223 or %g2, %lo(__libc_stack_end), %g2
224 ld [%l7 + %g2], %l1
225 add %sp, 6*4, %l2
226 st %l2, [%l1]
f41c8091
UD
227 /* See if we were run as a command with the executable file name as an
228 extra leading argument. If so, adjust the contents of the stack. */
229 sethi %hi(_dl_skip_args), %g2
230 or %g2, %lo(_dl_skip_args), %g2
231 ld [%l7+%g2], %i0
232 ld [%i0], %i0
233 tst %i0
234 beq 3f
235 nop
236 /* Find out how far to shift. */
237 ld [%sp+22*4], %i1 /* load argc */
238 sub %i1, %i0, %i1
239 sll %i0, 2, %i2
240 st %i1, [%sp+22*4]
241 add %sp, 23*4, %i1
242 add %i1, %i2, %i2
243 /* Copy down argv */
24421: ld [%i2], %i3
245 add %i2, 4, %i2
246 tst %i3
247 st %i3, [%i1]
248 bne 21b
249 add %i1, 4, %i1
250 /* Copy down env */
25122: ld [%i2], %i3
252 add %i2, 4, %i2
253 tst %i3
254 st %i3, [%i1]
255 bne 22b
256 add %i1, 4, %i1
257 /* Copy down auxiliary table. */
25823: ld [%i2], %i3
259 ld [%i2+4], %i4
260 add %i2, 8, %i2
261 tst %i3
262 st %i3, [%i1]
263 st %i4, [%i1+4]
264 bne 23b
265 add %i1, 8, %i1
9c4c0024 266 /* Load searchlist of the main object to pass to _dl_init_next. */
25c849b1
RH
2673: sethi %hi(_dl_main_searchlist), %g1
268 or %g1, %lo(_dl_main_searchlist), %g1
f41c8091 269 ld [%l7+%g1], %l1
25c849b1 270 ld [%l1], %l1
f41c8091
UD
271 /* Call _dl_init_next to return the address of an initializer to run. */
2724: call _dl_init_next
273 mov %l1, %o0
274 tst %o0
275 beq 5f
276 nop
277 jmpl %o0, %o7
9c4c0024 278 sub %o7, 28, %o7
f41c8091
UD
279 /* Clear the startup flag. */
2805: sethi %hi(_dl_starting_up), %g1
281 or %g1, %lo(_dl_starting_up), %g1
282 ld [%l7+%g1], %g1
283 st %g0, [%g1]
284 /* Pass our finalizer function to the user in %g1. */
285 sethi %hi(_dl_fini), %g1
286 or %g1, %lo(_dl_fini), %g1
287 ld [%l7+%g1], %g1
288 /* Jump to the user's entry point and deallocate the extra stack we got. */
289 jmp %l0
290 add %sp, 6*4, %sp
9c4c0024
UD
291 .size _dl_start_user, . - _dl_start_user
292 .previous");
f41c8091 293
a2b08ee5
UD
294static inline void
295elf_machine_fixup_plt (struct link_map *map, const Elf32_Rela *reloc,
296 Elf32_Addr *reloc_addr, Elf32_Addr value)
297{
4194bc66
RH
298#ifndef RTLD_BOOTSTRAP
299 /* Note that we don't mask the hwcap here, as the flush is essential to
300 functionality on those cpu's that implement it. */
b7e6f7bf
RH
301 unsigned long *hwcap;
302 int do_flush;
303 weak_extern (_dl_hwcap);
304 hwcap = WEAKADDR(_dl_hwcap);
305 do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH));
4194bc66 306#else
bf47fa23
UD
307 /* Unfortunately, this is necessary, so that we can ensure
308 ld.so will not execute corrupt PLT entry instructions. */
309 const int do_flush = 1;
4194bc66 310#endif
dfd2257a 311
a2b08ee5
UD
312 /* For thread safety, write the instructions from the bottom and
313 flush before we overwrite the critical "b,a". This of course
314 need not be done during bootstrapping, since there are no threads.
315 But we also can't tell if we _can_ use flush, so don't. */
316
317 reloc_addr[2] = OPCODE_JMP_G1 | (value & 0x3ff);
4194bc66 318 if (do_flush)
a2b08ee5 319 __asm __volatile ("flush %0+8" : : "r"(reloc_addr));
a2b08ee5
UD
320
321 reloc_addr[1] = OPCODE_SETHI_G1 | (value >> 10);
4194bc66 322 if (do_flush)
a2b08ee5 323 __asm __volatile ("flush %0+4" : : "r"(reloc_addr));
a2b08ee5
UD
324}
325
dfd2257a
UD
326/* Return the final value of a plt relocation. */
327static inline Elf32_Addr
328elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
329 Elf32_Addr value)
330{
331 return value + reloc->r_addend;
332}
333
ceb2d9aa 334#ifdef RESOLVE
a2b08ee5 335
4f54cdb1
RM
336/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
337 MAP is the object containing the reloc. */
338
339static inline void
0d8733c4 340elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
8f2ece69
UD
341 const Elf32_Sym *sym, const struct r_found_version *version,
342 Elf32_Addr *const reloc_addr)
4f54cdb1 343{
4194bc66
RH
344#ifndef RTLD_BOOTSTRAP
345 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
346 reference weak so static programs can still link. This declaration
347 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
348 because rtld.c contains the common defn for _dl_rtld_map, which is
349 incompatible with a weak decl in the same file. */
350 weak_extern (_dl_rtld_map);
351#endif
352
bc9f6000 353 if (ELF32_R_TYPE (reloc->r_info) == R_SPARC_RELATIVE)
993b3242
UD
354 {
355#ifndef RTLD_BOOTSTRAP
356 if (map != &_dl_rtld_map) /* Already done in rtld itself. */
357#endif
358 *reloc_addr += map->l_addr + reloc->r_addend;
359 }
bc9f6000 360 else
4f54cdb1 361 {
1f07e617 362 const Elf32_Sym *const refsym = sym;
bc9f6000
UD
363 Elf32_Addr value;
364 if (sym->st_shndx != SHN_UNDEF &&
365 ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
366 value = map->l_addr;
367 else
ceb2d9aa 368 {
bc9f6000
UD
369 value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
370 if (sym)
371 value += sym->st_value;
ceb2d9aa 372 }
bc9f6000 373 value += reloc->r_addend; /* Assume copy relocs have zero addend. */
ceb2d9aa 374
bc9f6000
UD
375 switch (ELF32_R_TYPE (reloc->r_info))
376 {
377 case R_SPARC_COPY:
9c4c0024
UD
378 if (sym == NULL)
379 /* This can happen in trace mode if an object could not be
380 found. */
381 break;
cf29ffbe
UD
382 if (sym->st_size > refsym->st_size
383 || (_dl_verbose && sym->st_size < refsym->st_size))
1f07e617 384 {
60c96635 385 extern char **_dl_argv;
1f07e617
UD
386 const char *strtab;
387
f420344c 388 strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
60c96635
UD
389 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
390 ": Symbol `", strtab + refsym->st_name,
1f07e617
UD
391 "' has different size in shared object, "
392 "consider re-linking\n", NULL);
393 }
394 memcpy (reloc_addr, (void *) value, MIN (sym->st_size,
395 refsym->st_size));
bc9f6000
UD
396 break;
397 case R_SPARC_GLOB_DAT:
398 case R_SPARC_32:
399 *reloc_addr = value;
400 break;
401 case R_SPARC_JMP_SLOT:
a2b08ee5 402 elf_machine_fixup_plt(map, reloc, reloc_addr, value);
bc9f6000
UD
403 break;
404 case R_SPARC_8:
405 *(char *) reloc_addr = value;
406 break;
407 case R_SPARC_16:
408 *(short *) reloc_addr = value;
409 break;
410 case R_SPARC_DISP8:
411 *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
412 break;
413 case R_SPARC_DISP16:
414 *(short *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
415 break;
416 case R_SPARC_DISP32:
417 *reloc_addr = (value - (Elf32_Addr) reloc_addr);
418 break;
419 case R_SPARC_LO10:
420 *reloc_addr = (*reloc_addr & ~0x3ff) | (value & 0x3ff);
421 break;
422 case R_SPARC_WDISP30:
423 *reloc_addr = ((*reloc_addr & 0xc0000000)
424 | ((value - (unsigned int) reloc_addr) >> 2));
425 break;
426 case R_SPARC_HI22:
427 *reloc_addr = (*reloc_addr & 0xffc00000) | (value >> 10);
428 break;
429 case R_SPARC_NONE: /* Alright, Wilbur. */
430 break;
431 default:
421c80d2 432 _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
bc9f6000
UD
433 break;
434 }
4f54cdb1
RM
435 }
436}
437
438static inline void
421c80d2
RM
439elf_machine_lazy_rel (struct link_map *map,
440 Elf32_Addr l_addr, const Elf32_Rela *reloc)
4f54cdb1
RM
441{
442 switch (ELF32_R_TYPE (reloc->r_info))
443 {
444 case R_SPARC_NONE:
445 break;
446 case R_SPARC_JMP_SLOT:
447 break;
448 default:
421c80d2 449 _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
4f54cdb1
RM
450 break;
451 }
452}
453
0d8733c4 454#endif /* RESOLVE */
This page took 0.153203 seconds and 5 git commands to generate.