1 /* Machine-dependent ELF dynamic relocation inline functions. Sparc64 version.
2 Copyright (C) 1997 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"
25 #include <sys/param.h>
29 /* Translate a processor-specific dynamic tag to the index into l_info. */
30 #define DT_SPARC(x) (DT_SPARC_##x - DT_LOPROC + DT_NUM)
32 /* Return nonzero iff E_MACHINE is compatible with the running host. */
34 elf_machine_matches_host (Elf64_Half e_machine
)
36 return e_machine
== EM_SPARC64
;
39 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
40 first element of the GOT. This must be inlined in a function which
42 static inline Elf64_Addr
43 elf_machine_dynamic (void)
45 register Elf64_Addr elf_pic_register
__asm__("%l7");
47 return *(Elf64_Addr
*)elf_pic_register
;
51 /* Return the run-time load address of the shared object. */
52 static inline Elf64_Addr
53 elf_machine_load_address (void)
55 register Elf64_Addr elf_pic_register
__asm__("%l7");
58 /* Utilize the fact that a local .got entry will be partially
59 initialized at startup awaiting its RELATIVE fixup. */
61 __asm("sethi %%hi(.Load_address), %1\n"
64 "or %1, %%lo(.Load_address), %1\n\t"
65 : "=r"(pc
), "=r"(la
));
67 return pc
- *(Elf64_Addr
*)(elf_pic_register
+ la
);
71 elf_machine_fixup_plt(struct link_map
*map
, const Elf64_Rela
*reloc
,
72 Elf64_Addr
*reloc_addr
, Elf64_Addr value
)
74 Elf64_Dyn
*pltfmt
= map
->l_info
[DT_SPARC(PLTFMT
)];
75 switch (pltfmt
? pltfmt
->d_un
.d_val
: 0)
77 case 1: /* .got.plt with absolute addresses */
80 case 2: /* .got.plt with got-relative addresses */
81 *reloc_addr
= value
- (map
->l_info
[DT_PLTGOT
]->d_un
.d_ptr
+ map
->l_addr
);
84 assert (! "unexpected .plt format type");
88 /* Return the final value of a plt relocation. */
89 static inline Elf64_Addr
90 elf_machine_plt_value (struct link_map
*map
, const Elf64_Rela
*reloc
,
93 return value
+ reloc
->r_addend
;
98 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
99 MAP is the object containing the reloc. */
102 elf_machine_rela (struct link_map
*map
, const Elf64_Rela
*reloc
,
103 const Elf64_Sym
*sym
, const struct r_found_version
*version
,
104 Elf64_Addr
*const reloc_addr
)
106 #ifndef RTLD_BOOTSTRAP
107 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
108 reference weak so static programs can still link. This declaration
109 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
110 because rtld.c contains the common defn for _dl_rtld_map, which is
111 incompatible with a weak decl in the same file. */
112 weak_extern (_dl_rtld_map
);
115 if (ELF64_R_TYPE (reloc
->r_info
) == R_SPARC_RELATIVE
)
117 #ifndef RTLD_BOOTSTRAP
118 if (map
!= &_dl_rtld_map
) /* Already done in rtld itself. */
120 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
124 const Elf64_Sym
*const refsym
= sym
;
126 if (sym
->st_shndx
!= SHN_UNDEF
&&
127 ELF64_ST_BIND (sym
->st_info
) == STB_LOCAL
)
131 value
= RESOLVE (&sym
, version
, ELF64_R_TYPE (reloc
->r_info
));
133 value
+= sym
->st_value
;
135 value
+= reloc
->r_addend
; /* Assume copy relocs have zero addend. */
137 switch (ELF64_R_TYPE (reloc
->r_info
))
140 if (sym
->st_size
> refsym
->st_size
141 || (_dl_verbose
&& sym
->st_size
< refsym
->st_size
))
143 extern char **_dl_argv
;
146 strtab
= ((void *) map
->l_addr
147 + map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
148 _dl_sysdep_error (_dl_argv
[0] ?: "<program name unknown>",
149 ": Symbol `", strtab
+ refsym
->st_name
,
150 "' has different size in shared object, "
151 "consider re-linking\n", NULL
);
153 memcpy (reloc_addr
, (void *) value
, MIN (sym
->st_size
,
158 case R_SPARC_GLOB_DAT
:
162 *(char *) reloc_addr
= value
;
165 *(short *) reloc_addr
= value
;
168 *(char *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
171 *(short *) reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
174 *(unsigned int *)reloc_addr
= (value
- (Elf64_Addr
) reloc_addr
);
177 *(unsigned *)reloc_addr
= (*(unsigned *)reloc_addr
& ~0x3ff)
180 case R_SPARC_WDISP30
:
181 *(unsigned *)reloc_addr
= ((*(unsigned *)reloc_addr
& 0xc0000000)
182 | ((value
- (Elf64_Addr
) reloc_addr
) >> 2));
185 *(unsigned *)reloc_addr
= (*(unsigned *)reloc_addr
& 0xffc00000)
189 case R_SPARC_JMP_SLOT
:
190 elf_machine_fixup_plt(map
, reloc
, reloc_addr
, value
);
193 case R_SPARC_NONE
: /* Alright, Wilbur. */
196 assert (! "unexpected dynamic reloc type");
203 elf_machine_lazy_rel (struct link_map
*map
, const Elf64_Rela
*reloc
)
205 switch (ELF64_R_TYPE (reloc
->r_info
))
209 case R_SPARC_JMP_SLOT
:
212 assert (! "unexpected PLT reloc type");
219 /* Nonzero iff TYPE should not be allowed to resolve to one of
220 the main executable's symbols, as for a COPY reloc. */
221 #define elf_machine_lookup_noexec_p(type) ((type) == R_SPARC_COPY)
223 /* Nonzero iff TYPE describes relocation of a PLT entry, so
224 PLT entries should not be allowed to define the value. */
225 #define elf_machine_lookup_noplt_p(type) ((type) == R_SPARC_JMP_SLOT)
227 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
228 #define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
230 /* The SPARC never uses Elf64_Rel relocations. */
231 #define ELF_MACHINE_NO_REL 1
233 /* The SPARC overlaps DT_RELA and DT_PLTREL. */
234 #define ELF_MACHINE_PLTREL_OVERLAP 1
236 /* Set up the loaded object described by L so its unrelocated PLT
237 entries will jump to the on-demand fixup code in dl-runtime.c. */
240 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
243 extern void _dl_runtime_resolve (void);
245 if (l
->l_info
[DT_JMPREL
] && lazy
)
247 got
= (Elf64_Addr
*) (l
->l_addr
+ l
->l_info
[DT_PLTGOT
]->d_un
.d_ptr
);
248 /* This function will get called to fix up the GOT entry indicated by
249 the offset on the stack, and then jump to the resolved address. */
250 got
[1] = (Elf64_Addr
) &_dl_runtime_resolve
;
251 got
[2] = (Elf64_Addr
) l
; /* Identify this shared object. */
257 /* This code is used in dl-runtime.c to call the `fixup' function
258 and then redirect to the address it returns. */
259 #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
260 .globl _dl_runtime_resolve
261 .type _dl_runtime_resolve, @function
269 .size _dl_runtime_resolve, .-_dl_runtime_resolve
272 /* The PLT uses Elf64_Rela relocs. */
273 #define elf_machine_relplt elf_machine_rela
276 /* Initial entry point code for the dynamic linker.
277 The C function `_dl_start' is the real entry point;
278 its return value is the user program's entry point. */
281 #define __S(x) __S1(x)
283 #define RTLD_START __asm__ ( "\
285 .type _start, @function
287 /* Make room for functions to drop their arguments on the stack. */
289 /* Pass pointer to argument block to _dl_start. */
291 add %sp," __S(STACK_BIAS) "+22*8,%o0
293 .size _start, .-_start
295 .global _dl_start_user
296 .type _dl_start_user, @function
298 /* Load the GOT register. */
300 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
301 11: or %l7,%lo(_GLOBAL_OFFSET_TABLE_-(1b-.)),%l7
303 /* Save the user entry point address in %l0. */
305 /* See if we were run as a command with the executable file name as an
306 extra leading argument. If so, we must shift things around since we
307 must keep the stack doubleword aligned. */
308 sethi %hi(_dl_skip_args), %g2
309 or %g2, %lo(_dl_skip_args), %g2
314 /* Find out how far to shift. */
315 ldx [%sp+" __S(STACK_BIAS) "+22*8], %i1
318 stx %i1, [%sp+" __S(STACK_BIAS) "+22*8]
319 add %sp, " __S(STACK_BIAS) "+23*8, %i1
321 /* Copy down argv. */
327 /* Copy down envp. */
333 /* Copy down auxiliary table. */
341 /* Load _dl_default_scope[2] to pass to _dl_init_next. */
342 2: sethi %hi(_dl_default_scope), %g2
343 or %g2, %lo(_dl_default_scope), %g2
346 /* Call _dl_init_next to return the address of an initializer to run. */
347 3: call _dl_init_next
354 /* Clear the startup flag. */
355 4: sethi %hi(_dl_starting_up), %g2
356 or %g2, %lo(_dl_starting_up), %g2
359 /* Pass our finalizer function to the user in %g1. */
360 sethi %hi(_dl_fini), %g1
361 or %g1, %lo(_dl_fini), %g1
363 /* Jump to the user's entry point & undo the allocation of the xtra regs. */
366 .size _dl_start_user, .-_dl_start_user");