1 /* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version.
2 Copyright (C) 1997, 1998 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"
24 #include <sys/param.h>
25 #include <elf/ldsodefs.h>
28 /* Return nonzero iff E_MACHINE is compatible with the running host. */
30 elf_machine_matches_host (Elf64_Half e_machine
)
32 return e_machine
== EM_SPARCV9
;
35 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
36 first element of the GOT. This must be inlined in a function which
38 static inline Elf64_Addr
39 elf_machine_dynamic (void)
41 register Elf64_Addr
*elf_pic_register
__asm__("%l7");
43 return *elf_pic_register
;
46 /* Return the run-time load address of the shared object. */
47 static inline Elf64_Addr
48 elf_machine_load_address (void)
50 register Elf64_Addr elf_pic_register
__asm__("%l7");
53 /* Utilize the fact that a local .got entry will be partially
54 initialized at startup awaiting its RELATIVE fixup. */
56 __asm("sethi %%hi(.Load_address), %1\n"
59 "or %1, %%lo(.Load_address), %1\n\t"
60 : "=r"(pc
), "=r"(la
));
62 return pc
- *(Elf64_Addr
*)(elf_pic_register
+ la
);
65 /* We have 3 cases to handle. And we code different code sequences
66 for each one. I love V9 code models... */
68 elf_machine_fixup_plt(struct link_map
*map
, const Elf64_Rela
*reloc
,
69 Elf64_Addr
*reloc_addr
, Elf64_Addr value
)
71 unsigned int *insns
= (unsigned int *) reloc_addr
;
72 Elf64_Addr plt_vaddr
= (Elf64_Addr
) reloc_addr
;
74 /* Now move plt_vaddr up to the call instruction. */
77 /* 32-bit Sparc style, the target is in the lower 32-bits of
79 if ((value
>> 32) == 0)
81 /* sethi %hi(target), %g1
82 jmpl %g1 + %lo(target), %g0 */
84 insns
[2] = 0x81c06000 | (value
& 0x3ff);
85 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
87 insns
[1] = 0x03000000 | ((unsigned int)(value
>> 10));
88 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
90 /* We can also get somewhat simple sequences if the distance between
91 the target and the PLT entry is within +/- 2GB. */
92 else if ((plt_vaddr
> value
93 && ((plt_vaddr
- value
) >> 32) == 0)
95 && ((value
- plt_vaddr
) >> 32) == 0))
97 unsigned int displacement
;
99 if (plt_vaddr
> value
)
100 displacement
= (0 - (plt_vaddr
- value
));
102 displacement
= value
- plt_vaddr
;
108 insns
[3] = 0x9e100001;
109 __asm
__volatile ("flush %0 + 12" : : "r" (insns
));
111 insns
[2] = 0x40000000 | (displacement
>> 2);
112 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
114 insns
[1] = 0x8210000f;
115 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
117 /* Worst case, ho hum... */
120 unsigned int high32
= (value
>> 32);
121 unsigned int low32
= (unsigned int) value
;
123 /* ??? Some tricks can be stolen from the sparc64 egcs backend
124 constant formation code I wrote. -DaveM */
126 /* sethi %hh(value), %g1
127 sethi %lm(value), %g2
128 or %g1, %hl(value), %g1
129 or %g2, %lo(value), %g2
134 insns
[6] = 0x81c04002;
135 __asm
__volatile ("flush %0 + 24" : : "r" (insns
));
137 insns
[5] = 0x83287020;
138 __asm
__volatile ("flush %0 + 20" : : "r" (insns
));
140 insns
[4] = 0x8410a000 | (low32
& 0x3ff);
141 __asm
__volatile ("flush %0 + 16" : : "r" (insns
));
143 insns
[3] = 0x82106000 | (high32
& 0x3ff);
144 __asm
__volatile ("flush %0 + 12" : : "r" (insns
));
146 insns
[2] = 0x05000000 | (low32
>> 10);
147 __asm
__volatile ("flush %0 + 8" : : "r" (insns
));
149 insns
[1] = 0x03000000 | (high32
>> 10);
150 __asm
__volatile ("flush %0 + 4" : : "r" (insns
));
154 /* Return the final value of a plt relocation. */
155 static inline Elf64_Addr
156 elf_machine_plt_value (struct link_map
*map
, const Elf64_Rela
*reloc
,
159 return value
+ reloc
->r_addend
;
164 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
165 MAP is the object containing the reloc. */
168 elf_machine_rela (struct link_map
*map
, const Elf64_Rela
*reloc
,
169 const Elf64_Sym
*sym
, const struct r_found_version
*version
,
170 Elf64_Addr
*const reloc_addr
)
172 #ifndef RTLD_BOOTSTRAP
173 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
174 reference weak so static programs can still link. This declaration
175 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
176 because rtld.c contains the common defn for _dl_rtld_map, which is
177 incompatible with a weak decl in the same file. */
178 weak_extern (_dl_rtld_map
);
181 if (ELF64_R_TYPE (reloc
->r_info
) == R_SPARC_RELATIVE
)
183 #ifndef RTLD_BOOTSTRAP
184 if (map
!= &_dl_rtld_map
) /* Already done in rtld itself. */
186 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
188 else if (ELF64_R_TYPE (reloc
->r_info
) != R_SPARC_NONE
) /* Who is Wilbur? */
190 const Elf64_Sym
*const refsym
= sym
;
192 if (sym
->st_shndx
!= SHN_UNDEF
&&
193 ELF64_ST_BIND (sym
->st_info
) == STB_LOCAL
)
197 value
= RESOLVE (&sym
, version
, ELF64_R_TYPE (reloc
->r_info
));
199 value
+= sym
->st_value
;
201 value
+= reloc
->r_addend
; /* Assume copy relocs have zero addend. */
203 switch (ELF64_R_TYPE (reloc
->r_info
))
207 /* This can happen in trace mode if an object could not be
210 if (sym
->st_size
> refsym
->st_size
211 || (_dl_verbose
&& sym
->st_size
< refsym
->st_size
))
213 extern char **_dl_argv
;
216 strtab
= ((void *) map
->l_addr
217 + map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
218 _dl_sysdep_error (_dl_argv
[0] ?: "<program name unknown>",
219 ": Symbol `", strtab
+ refsym
->st_name
,
220 "' has different size in shared object, "
221 "consider re-linking\n", NULL
);
223 memcpy (reloc_addr
, (void *) value
, MIN (sym
->st_size
,
228 case R_SPARC_GLOB_DAT
:
232 *(char *) reloc_addr
= value
;
235 *(short *) reloc_addr
= value
;
238 *(unsigned int *) reloc_addr
= value
;
241 *(char *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
244 *(short *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
247 *(unsigned int *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
249 case R_SPARC_WDISP30
:
250 *(unsigned int *) reloc_addr
=
251 ((*(unsigned int *)reloc_addr
& 0xc0000000) |
252 ((value
- (Elf64_Addr
) reloc_addr
) >> 2));
255 /* MEDLOW code model relocs */
257 *(unsigned int *) reloc_addr
=
258 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
262 *(unsigned int *) reloc_addr
=
263 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
267 /* MEDMID code model relocs */
269 *(unsigned int *) reloc_addr
=
270 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
274 *(unsigned int *) reloc_addr
=
275 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
276 ((value
>> 12) & 0x3ff));
279 *(unsigned int *) reloc_addr
=
280 ((*(unsigned int *)reloc_addr
& ~0xfff) |
284 /* MEDANY code model relocs */
286 *(unsigned int *) reloc_addr
=
287 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
291 *(unsigned int *) reloc_addr
=
292 ((*(unsigned int *)reloc_addr
& ~0x3ff) |
293 ((value
>> 32) & 0x3ff));
296 *(unsigned int *) reloc_addr
=
297 ((*(unsigned int *)reloc_addr
& 0xffc00000) |
298 ((value
>> 10) & 0x003fffff));
301 case R_SPARC_JMP_SLOT
:
302 elf_machine_fixup_plt(map
, reloc
, reloc_addr
, value
);
306 assert (! "unexpected dynamic reloc type");
313 elf_machine_lazy_rel (Elf64_Addr l_addr
, const Elf64_Rela
*reloc
)
315 switch (ELF64_R_TYPE (reloc
->r_info
))
319 case R_SPARC_JMP_SLOT
:
322 assert (! "unexpected PLT reloc type");
329 /* Nonzero iff TYPE should not be allowed to resolve to one of
330 the main executable's symbols, as for a COPY reloc. */
331 #define elf_machine_lookup_noexec_p(type) ((type) == R_SPARC_COPY)
333 /* Nonzero iff TYPE describes relocation of a PLT entry, so
334 PLT entries should not be allowed to define the value. */
335 #define elf_machine_lookup_noplt_p(type) ((type) == R_SPARC_JMP_SLOT)
337 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
338 #define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
340 /* The SPARC never uses Elf64_Rel relocations. */
341 #define ELF_MACHINE_NO_REL 1
343 /* The SPARC overlaps DT_RELA and DT_PLTREL. */
344 #define ELF_MACHINE_PLTREL_OVERLAP 1
346 /* Set up the loaded object described by L so its unrelocated PLT
347 entries will jump to the on-demand fixup code in dl-runtime.c. */
350 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
352 if (l
->l_info
[DT_JMPREL
] && lazy
)
354 extern void _dl_runtime_resolve_0 (void);
355 extern void _dl_runtime_resolve_1 (void);
356 extern void _dl_runtime_profile_0 (void);
357 extern void _dl_runtime_profile_1 (void);
358 Elf64_Addr res0_addr
, res1_addr
;
359 unsigned int *plt
= (unsigned int *)
360 (l
->l_addr
+ l
->l_info
[DT_PLTGOT
]->d_un
.d_ptr
);
364 res0_addr
= (Elf64_Addr
) &_dl_runtime_resolve_0
;
365 res1_addr
= (Elf64_Addr
) &_dl_runtime_resolve_1
;
369 res0_addr
= (Elf64_Addr
) &_dl_runtime_profile_0
;
370 res1_addr
= (Elf64_Addr
) &_dl_runtime_profile_1
;
371 if (_dl_name_match_p (_dl_profile
, l
))
378 sethi %hh(_dl_runtime_{resolve,profile}_0), %g3
379 sethi %lm(_dl_runtime_{resolve,profile}_0), %g4
380 or %g3, %hm(_dl_runtime_{resolve,profile}_0), %g3
381 or %g4, %lo(_dl_runtime_{resolve,profile}_0), %g4
386 PLT1 is similar except we jump to _dl_runtime_{resolve,profile}_1. */
389 plt
[1] = 0x07000000 | (res0_addr
>> (64 - 22));
390 plt
[2] = 0x09000000 | ((res0_addr
>> 10) & 0x003fffff);
391 plt
[3] = 0x8610e000 | ((res0_addr
>> 32) & 0x3ff);
392 plt
[4] = 0x88112000 | (res0_addr
& 0x3ff);
397 plt
[8 + 0] = 0x9de3bf40;
398 plt
[8 + 1] = 0x07000000 | (res1_addr
>> (64 - 22));
399 plt
[8 + 2] = 0x09000000 | ((res1_addr
>> 10) & 0x003fffff);
400 plt
[8 + 3] = 0x8610e000 | ((res1_addr
>> 32) & 0x3ff);
401 plt
[8 + 4] = 0x88112000 | (res1_addr
& 0x3ff);
402 plt
[8 + 5] = 0x8728f020;
403 plt
[8 + 6] = 0x91c0c004;
404 plt
[8 + 7] = 0x01000000;
406 /* Now put the magic cookie at the beginning of .PLT3
407 Entry .PLT4 is unused by this implementation. */
408 *((struct link_map
**)(&plt
[16 + 0])) = l
;
414 /* This code is used in dl-runtime.c to call the `fixup' function
415 and then redirect to the address it returns. */
416 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
419 .globl " #tramp_name "_0
420 .type " #tramp_name "_0, @function
423 ldx [%o0 + 32 + 8], %l0
424 sethi %hi(1048576), %g2
429 sethi %hi(32768), %o2
447 .size " #tramp_name "_0, . - " #tramp_name "_0
449 .globl " #tramp_name "_1
450 .type " #tramp_name "_1, @function
462 .size " #tramp_name "_1, . - " #tramp_name "_1
466 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
467 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
468 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
470 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
471 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
472 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, fixup);
475 /* The PLT uses Elf64_Rela relocs. */
476 #define elf_machine_relplt elf_machine_rela
478 /* Initial entry point code for the dynamic linker.
479 The C function `_dl_start' is the real entry point;
480 its return value is the user program's entry point. */
483 #define __S(x) __S1(x)
485 #define RTLD_START __asm__ ( "\
488 .type _start, @function
491 /* Make room for functions to drop their arguments on the stack. */
493 /* Pass pointer to argument block to _dl_start. */
495 add %sp," __S(STACK_BIAS) "+22*8,%o0
497 .size _start, .-_start
499 .global _dl_start_user
500 .type _dl_start_user, @function
502 /* Load the GOT register. */
504 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
505 11: or %l7,%lo(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
507 /* Save the user entry point address in %l0. */
509 /* Store the highest stack address. */
510 sethi %hi(__libc_stack_end), %g2
511 or %g2, %lo(__libc_stack_end), %g2
515 /* See if we were run as a command with the executable file name as an
516 extra leading argument. If so, we must shift things around since we
517 must keep the stack doubleword aligned. */
518 sethi %hi(_dl_skip_args), %g2
519 or %g2, %lo(_dl_skip_args), %g2
524 /* Find out how far to shift. */
525 ldx [%sp+" __S(STACK_BIAS) "+22*8], %i1
528 stx %i1, [%sp+" __S(STACK_BIAS) "+22*8]
529 add %sp, " __S(STACK_BIAS) "+23*8, %i1
531 /* Copy down argv. */
537 /* Copy down envp. */
543 /* Copy down auxiliary table. */
551 /* Load searchlist of the main object to pass to _dl_init_next. */
552 2: sethi %hi(_dl_main_searchlist), %g2
553 or %g2, %lo(_dl_main_searchlist), %g2
556 /* Call _dl_init_next to return the address of an initializer to run. */
557 3: call _dl_init_next
563 /* Clear the startup flag. */
564 4: sethi %hi(_dl_starting_up), %g2
565 or %g2, %lo(_dl_starting_up), %g2
568 /* Pass our finalizer function to the user in %g1. */
569 sethi %hi(_dl_fini), %g1
570 or %g1, %lo(_dl_fini), %g1
572 /* Jump to the user's entry point and deallocate the extra stack we got. */
575 .size _dl_start_user, . - _dl_start_user