1 /* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version.
2 Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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. */
20 #define ELF_MACHINE_NAME "sparc64"
23 #include <sys/param.h>
27 #define ELF64_R_TYPE_ID(info) ((info) & 0xff)
28 #define ELF64_R_TYPE_DATA(info) ((info) >> 8)
30 /* Return nonzero iff E_MACHINE is compatible with the running host. */
32 elf_machine_matches_host (Elf64_Half e_machine
)
34 return e_machine
== EM_SPARCV9
;
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
40 static inline Elf64_Addr
41 elf_machine_dynamic (void)
43 register Elf64_Addr
*elf_pic_register
__asm__("%l7");
45 return *elf_pic_register
;
48 /* Return the run-time load address of the shared object. */
49 static inline Elf64_Addr
50 elf_machine_load_address (void)
52 register Elf64_Addr elf_pic_register
__asm__("%l7");
55 /* Utilize the fact that a local .got entry will be partially
56 initialized at startup awaiting its RELATIVE fixup. */
58 __asm("sethi %%hi(.Load_address), %1\n"
61 "or %1, %%lo(.Load_address), %1\n\t"
62 : "=r"(pc
), "=r"(la
));
64 return pc
- *(Elf64_Addr
*)(elf_pic_register
+ la
);
67 /* We have 4 cases to handle. And we code different code sequences
68 for each one. I love V9 code models... */
69 static inline Elf64_Addr
70 elf_machine_fixup_plt (struct link_map
*map
, lookup_t t
,
71 const Elf64_Rela
*reloc
,
72 Elf64_Addr
*reloc_addr
, Elf64_Addr value
)
74 unsigned int *insns
= (unsigned int *) reloc_addr
;
75 Elf64_Addr plt_vaddr
= (Elf64_Addr
) reloc_addr
;
77 /* Now move plt_vaddr up to the call instruction. */
80 /* PLT entries .PLT32768 and above look always the same. */
81 if (__builtin_expect (reloc
->r_addend
, 0) != 0)
83 *reloc_addr
= value
- map
->l_addr
;
85 /* 32-bit Sparc style, the target is in the lower 32-bits of
87 else if ((value
>> 32) == 0)
89 /* sethi %hi(target), %g1
90 jmpl %g1 + %lo(target), %g0 */
92 insns
[2] = 0x81c06000 | (value
& 0x3ff);
93 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
95 insns
[1] = 0x03000000 | ((unsigned int)(value
>> 10));
96 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
98 /* We can also get somewhat simple sequences if the distance between
99 the target and the PLT entry is within +/- 2GB. */
100 else if ((plt_vaddr
> value
101 && ((plt_vaddr
- value
) >> 32) == 0)
102 || (value
> plt_vaddr
103 && ((value
- plt_vaddr
) >> 32) == 0))
105 unsigned int displacement
;
107 if (plt_vaddr
> value
)
108 displacement
= (0 - (plt_vaddr
- value
));
110 displacement
= value
- plt_vaddr
;
116 insns
[3] = 0x9e100001;
117 __asm
__volatile ("flush %0 + 12" : : "r" (insns
));
119 insns
[2] = 0x40000000 | (displacement
>> 2);
120 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
122 insns
[1] = 0x8210000f;
123 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
125 /* Worst case, ho hum... */
128 unsigned int high32
= (value
>> 32);
129 unsigned int low32
= (unsigned int) value
;
131 /* ??? Some tricks can be stolen from the sparc64 egcs backend
132 constant formation code I wrote. -DaveM */
134 /* sethi %hh(value), %g1
135 sethi %lm(value), %g5
136 or %g1, %hm(value), %g1
137 or %g5, %lo(value), %g5
142 insns
[6] = 0x81c04005;
143 __asm
__volatile ("flush %0 + 24" : : "r" (insns
));
145 insns
[5] = 0x83287020;
146 __asm
__volatile ("flush %0 + 20" : : "r" (insns
));
148 insns
[4] = 0x8a116000 | (low32
& 0x3ff);
149 __asm
__volatile ("flush %0 + 16" : : "r" (insns
));
151 insns
[3] = 0x82106000 | (high32
& 0x3ff);
152 __asm
__volatile ("flush %0 + 12" : : "r" (insns
));
154 insns
[2] = 0x0b000000 | (low32
>> 10);
155 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
157 insns
[1] = 0x03000000 | (high32
>> 10);
158 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
164 /* Return the final value of a plt relocation. */
165 static inline Elf64_Addr
166 elf_machine_plt_value (struct link_map
*map
, const Elf64_Rela
*reloc
,
169 return value
+ reloc
->r_addend
;
174 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
175 MAP is the object containing the reloc. */
178 elf_machine_rela (struct link_map
*map
, const Elf64_Rela
*reloc
,
179 const Elf64_Sym
*sym
, const struct r_found_version
*version
,
180 Elf64_Addr
*const reloc_addr
)
182 #ifndef RTLD_BOOTSTRAP
183 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
184 reference weak so static programs can still link. This declaration
185 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
186 because rtld.c contains the common defn for _dl_rtld_map, which is
187 incompatible with a weak decl in the same file. */
188 weak_extern (_dl_rtld_map
);
191 if (ELF64_R_TYPE_ID (reloc
->r_info
) == R_SPARC_RELATIVE
)
193 #ifndef RTLD_BOOTSTRAP
194 if (map
!= &_dl_rtld_map
) /* Already done in rtld itself. */
196 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
198 else if (ELF64_R_TYPE_ID (reloc
->r_info
) != R_SPARC_NONE
) /* Who is Wilbur? */
200 const Elf64_Sym
*const refsym
= sym
;
202 if (sym
->st_shndx
!= SHN_UNDEF
&&
203 ELF64_ST_BIND (sym
->st_info
) == STB_LOCAL
)
207 value
= RESOLVE (&sym
, version
, ELF64_R_TYPE_ID (reloc
->r_info
));
209 value
+= sym
->st_value
;
211 value
+= reloc
->r_addend
; /* Assume copy relocs have zero addend. */
213 switch (ELF64_R_TYPE_ID (reloc
->r_info
))
217 /* This can happen in trace mode if an object could not be
220 if (sym
->st_size
> refsym
->st_size
221 || (_dl_verbose
&& sym
->st_size
< refsym
->st_size
))
223 extern char **_dl_argv
;
226 strtab
= (const void *) D_PTR (map
, l_info
[DT_STRTAB
]);
227 _dl_sysdep_error (_dl_argv
[0] ?: "<program name unknown>",
228 ": Symbol `", strtab
+ refsym
->st_name
,
229 "' has different size in shared object, "
230 "consider re-linking\n", NULL
);
232 memcpy (reloc_addr
, (void *) value
, MIN (sym
->st_size
,
237 case R_SPARC_GLOB_DAT
:
241 *(char *) reloc_addr
= value
;
244 *(short *) reloc_addr
= value
;
247 *(unsigned int *) reloc_addr
= value
;
250 *(char *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
253 *(short *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
256 *(unsigned int *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
258 case R_SPARC_WDISP30
:
259 *(unsigned int *) reloc_addr
=
260 ((*(unsigned int *)reloc_addr
& 0xc0000000) |
261 ((value
- (Elf64_Addr
) reloc_addr
) >> 2));
264 /* MEDLOW code model relocs */
266 *(unsigned int *) reloc_addr
=
267 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
271 *(unsigned int *) reloc_addr
=
272 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
276 *(unsigned int *) reloc_addr
=
277 ((*(unsigned int *)reloc_addr
& ~0x1fff) |
278 (((value
& 0x3ff) + ELF64_R_TYPE_DATA (reloc
->r_info
)) & 0x1fff));
281 /* MEDMID code model relocs */
283 *(unsigned int *) reloc_addr
=
284 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
288 *(unsigned int *) reloc_addr
=
289 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
290 ((value
>> 12) & 0x3ff));
293 *(unsigned int *) reloc_addr
=
294 ((*(unsigned int *)reloc_addr
& ~0xfff) |
298 /* MEDANY code model relocs */
300 *(unsigned int *) reloc_addr
=
301 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
305 *(unsigned int *) reloc_addr
=
306 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
307 ((value
>> 32) & 0x3ff));
310 *(unsigned int *) reloc_addr
=
311 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
312 ((value
>> 10) & 0x003fffff));
315 case R_SPARC_JMP_SLOT
:
316 elf_machine_fixup_plt(map
, NULL
, reloc
, reloc_addr
, value
);
320 _dl_reloc_bad_type (map
, ELFW(R_TYPE
) (reloc
->r_info
), 0);
327 elf_machine_lazy_rel (struct link_map
*map
,
328 Elf64_Addr l_addr
, const Elf64_Rela
*reloc
)
330 switch (ELF64_R_TYPE (reloc
->r_info
))
334 case R_SPARC_JMP_SLOT
:
337 _dl_reloc_bad_type (map
, ELFW(R_TYPE
) (reloc
->r_info
), 1);
344 /* Nonzero iff TYPE should not be allowed to resolve to one of
345 the main executable's symbols, as for a COPY reloc. */
346 #define elf_machine_lookup_noexec_p(type) ((type) == R_SPARC_COPY)
348 /* Nonzero iff TYPE describes relocation of a PLT entry, so
349 PLT entries should not be allowed to define the value. */
350 #define elf_machine_lookup_noplt_p(type) ((type) == R_SPARC_JMP_SLOT)
352 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
353 #define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
355 /* The SPARC never uses Elf64_Rel relocations. */
356 #define ELF_MACHINE_NO_REL 1
358 /* The SPARC overlaps DT_RELA and DT_PLTREL. */
359 #define ELF_MACHINE_PLTREL_OVERLAP 1
361 /* Set up the loaded object described by L so its unrelocated PLT
362 entries will jump to the on-demand fixup code in dl-runtime.c. */
365 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
367 if (l
->l_info
[DT_JMPREL
] && lazy
)
369 extern void _dl_runtime_resolve_0 (void);
370 extern void _dl_runtime_resolve_1 (void);
371 extern void _dl_runtime_profile_0 (void);
372 extern void _dl_runtime_profile_1 (void);
373 Elf64_Addr res0_addr
, res1_addr
;
374 unsigned int *plt
= (void *) D_PTR (l
, l_info
[DT_PLTGOT
]);
378 res0_addr
= (Elf64_Addr
) &_dl_runtime_resolve_0
;
379 res1_addr
= (Elf64_Addr
) &_dl_runtime_resolve_1
;
383 res0_addr
= (Elf64_Addr
) &_dl_runtime_profile_0
;
384 res1_addr
= (Elf64_Addr
) &_dl_runtime_profile_1
;
385 if (_dl_name_match_p (_dl_profile
, l
))
392 sethi %hh(_dl_runtime_{resolve,profile}_0), %l0
393 sethi %lm(_dl_runtime_{resolve,profile}_0), %l1
394 or %l0, %hm(_dl_runtime_{resolve,profile}_0), %l0
395 or %l1, %lo(_dl_runtime_{resolve,profile}_0), %l1
398 sethi %hi(0xffc00), %l2
402 plt
[1] = 0x21000000 | (res0_addr
>> (64 - 22));
403 plt
[2] = 0x23000000 | ((res0_addr
>> 10) & 0x003fffff);
404 plt
[3] = 0xa0142000 | ((res0_addr
>> 32) & 0x3ff);
405 plt
[4] = 0xa2146000 | (res0_addr
& 0x3ff);
413 sethi %hh(_dl_runtime_{resolve,profile}_1), %l0
414 sethi %lm(_dl_runtime_{resolve,profile}_1), %l1
415 or %l0, %hm(_dl_runtime_{resolve,profile}_1), %l0
416 or %l1, %lo(_dl_runtime_{resolve,profile}_1), %l1
422 plt
[8 + 0] = 0x9de3bf40;
423 plt
[8 + 1] = 0x21000000 | (res1_addr
>> (64 - 22));
424 plt
[8 + 2] = 0x23000000 | ((res1_addr
>> 10) & 0x003fffff);
425 plt
[8 + 3] = 0xa0142000 | ((res1_addr
>> 32) & 0x3ff);
426 plt
[8 + 4] = 0xa2146000 | (res1_addr
& 0x3ff);
427 plt
[8 + 5] = 0xa12c3020;
428 plt
[8 + 6] = 0xadc40011;
429 plt
[8 + 7] = 0x9330700c;
431 /* Now put the magic cookie at the beginning of .PLT3
432 Entry .PLT4 is unused by this implementation. */
433 *((struct link_map
**)(&plt
[16 + 0])) = l
;
439 /* This code is used in dl-runtime.c to call the `fixup' function
440 and then redirect to the address it returns. */
441 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
444 .globl " #tramp_name "_0
445 .type " #tramp_name "_0, @function
448 ! sethi %hi(1047552), %l2 - Done in .PLT0
449 ldx [%l6 + 32 + 8], %o0
454 sethi %hi(32768), %l4
471 .size " #tramp_name "_0, . - " #tramp_name "_0
473 .globl " #tramp_name "_1
474 .type " #tramp_name "_1, @function
477 ! srlx %g1, 12, %o1 - Done in .PLT1
485 .size " #tramp_name "_1, . - " #tramp_name "_1
489 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
490 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
491 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
493 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
494 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
495 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, fixup);
498 /* The PLT uses Elf64_Rela relocs. */
499 #define elf_machine_relplt elf_machine_rela
501 /* Initial entry point code for the dynamic linker.
502 The C function `_dl_start' is the real entry point;
503 its return value is the user program's entry point. */
506 #define __S(x) __S1(x)
508 #define RTLD_START __asm__ ( "\
511 .type _start, @function
514 /* Make room for functions to drop their arguments on the stack. */
516 /* Pass pointer to argument block to _dl_start. */
518 add %sp," __S(STACK_BIAS) "+22*8,%o0
520 .size _start, .-_start
522 .global _dl_start_user
523 .type _dl_start_user, @function
525 /* Load the GOT register. */
527 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
528 11: or %l7,%lo(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
530 /* Save the user entry point address in %l0. */
532 /* Store the highest stack address. */
533 sethi %hi(__libc_stack_end), %g5
534 or %g5, %lo(__libc_stack_end), %g5
538 /* See if we were run as a command with the executable file name as an
539 extra leading argument. If so, we must shift things around since we
540 must keep the stack doubleword aligned. */
541 sethi %hi(_dl_skip_args), %g5
542 or %g5, %lo(_dl_skip_args), %g5
546 ldx [%sp+" __S(STACK_BIAS) "+22*8], %i5
547 /* Find out how far to shift. */
550 stx %i5, [%sp+" __S(STACK_BIAS) "+22*8]
551 add %sp, " __S(STACK_BIAS) "+23*8, %i1
553 /* Copy down argv. */
559 /* Copy down envp. */
565 /* Copy down auxiliary table. */
573 /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp. */
574 2: sethi %hi(_dl_loaded), %o0
575 add %sp, " __S(STACK_BIAS) "+23*8, %o2
576 orcc %o0, %lo(_dl_loaded), %o0
584 /* Pass our finalizer function to the user in %g1. */
585 sethi %hi(_dl_fini), %g1
586 or %g1, %lo(_dl_fini), %g1
588 /* Jump to the user's entry point and deallocate the extra stack we got. */
591 .size _dl_start_user, . - _dl_start_user