]>
sourceware.org Git - glibc.git/blob - sysdeps/sparc/sparc32/dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions. SPARC version.
2 Copyright (C) 1996, 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 "sparc"
25 #include <sys/param.h>
28 /* Some SPARC opcodes we need to use for self-modifying code. */
29 #define OPCODE_NOP 0x01000000 /* nop */
30 #define OPCODE_CALL 0x40000000 /* call ?; add PC-rel word address */
31 #define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
32 #define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
33 #define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
36 /* Return nonzero iff E_MACHINE is compatible with the running host. */
38 elf_machine_matches_host (Elf32_Half e_machine
)
40 return e_machine
== EM_SPARC
;
44 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
45 first element of the GOT. This must be inlined in a function which
47 static inline Elf32_Addr
48 elf_machine_dynamic (void)
50 register Elf32_Addr
*got
asm ("%l7");
54 /* Return the run-time load address of the shared object. */
55 static inline Elf32_Addr
56 elf_machine_load_address (void)
58 register Elf32_Addr pc
__asm("%o7"), pic
__asm("%l7"), got
;
60 /* Utilize the fact that a local .got entry will be partially
61 initialized at startup awaiting its RELATIVE fixup. */
63 __asm("sethi %%hi(.Load_address),%1\n"
66 "or %1,%%lo(.Load_address),%1\n"
68 : "=r"(pc
), "=r"(got
) : "r"(pic
));
73 /* Set up the loaded object described by L so its unrelocated PLT
74 entries will jump to the on-demand fixup code in dl-runtime.c. */
77 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
80 extern void _dl_runtime_resolve (Elf32_Word
);
82 if (l
->l_info
[DT_JMPREL
] && lazy
)
84 /* The entries for functions in the PLT have not yet been filled in.
85 Their initial contents will arrange when called to set the high 22
86 bits of %g1 with an offset into the .rela.plt section and jump to
87 the beginning of the PLT. */
88 plt
= (Elf32_Addr
*) (l
->l_addr
+ l
->l_info
[DT_PLTGOT
]->d_un
.d_ptr
);
90 /* The beginning of the PLT does:
93 pltpc: call _dl_runtime_resolve
97 This saves the register window containing the arguments, and the
98 PC value (pltpc) implicitly saved in %o7 by the call points near the
99 location where we store the link_map pointer for this object. */
101 plt
[0] = OPCODE_SAVE_SP
;
102 /* Construct PC-relative word address. */
103 plt
[1] = OPCODE_CALL
| (((Elf32_Addr
) &_dl_runtime_resolve
-
104 (Elf32_Addr
) &plt
[1]) >> 2);
105 plt
[2] = OPCODE_NOP
; /* Fill call delay slot. */
106 plt
[3] = (Elf32_Addr
) l
;
112 /* This code is used in dl-runtime.c to call the `fixup' function
113 and then redirect to the address it returns. */
114 #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
115 .globl _dl_runtime_resolve
116 .type _dl_runtime_resolve, @function
118 /* Set up the arguments to fixup --
119 %o0 = link_map out of plt0
120 %o1 = offset of reloc entry */
127 .size _dl_runtime_resolve, . - _dl_runtime_resolve");
129 /* The address of the JMP_SLOT reloc is the .plt entry, thus we don't
130 dereference the reloc's addr to get the final destination. Ideally
131 there would be a generic way to return the value of the symbol from
132 elf_machine_relplt, but as it is, the address of the .plt entry is
134 #define ELF_FIXUP_RETURN_VALUE(map, result) ((Elf32_Addr) &(result))
136 /* Nonzero iff TYPE should not be allowed to resolve to one of
137 the main executable's symbols, as for a COPY reloc. */
138 #define elf_machine_lookup_noexec_p(type) ((type) == R_SPARC_COPY)
140 /* Nonzero iff TYPE describes relocation of a PLT entry, so
141 PLT entries should not be allowed to define the value. */
142 #define elf_machine_lookup_noplt_p(type) ((type) == R_SPARC_JMP_SLOT)
144 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
145 #define ELF_MACHINE_RELOC_NOPLT R_SPARC_JMP_SLOT
147 /* The SPARC never uses Elf32_Rel relocations. */
148 #define ELF_MACHINE_NO_REL 1
150 /* The SPARC overlaps DT_RELA and DT_PLTREL. */
151 #define ELF_MACHINE_PLTREL_OVERLAP 1
153 /* The PLT uses Elf32_Rela relocs. */
154 #define elf_machine_relplt elf_machine_rela
156 /* Initial entry point code for the dynamic linker.
157 The C function `_dl_start' is the real entry point;
158 its return value is the user program's entry point. */
160 #define RTLD_START __asm__ ("\
163 .type _start,@function
165 /* Allocate space for functions to drop their arguments. */
167 /* Pass pointer to argument block to _dl_start. */
171 .globl _dl_start_user
172 .type _dl_start_user,@function
174 /* Load the PIC register. */
176 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7
177 2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7
179 /* Save the user entry point address in %l0 */
181 /* See if we were run as a command with the executable file name as an
182 extra leading argument. If so, adjust the contents of the stack. */
183 sethi %hi(_dl_skip_args), %g2
184 or %g2, %lo(_dl_skip_args), %g2
190 /* Find out how far to shift. */
191 ld [%sp+22*4], %i1 /* load argc */
211 /* Copy down auxiliary table. */
220 /* Load _dl_default_scope[2] to pass to _dl_init_next. */
221 3: sethi %hi(_dl_default_scope), %g1
222 or %g1, %lo(_dl_default_scope), %g1
225 /* Call _dl_init_next to return the address of an initializer to run. */
226 4: call _dl_init_next
234 /* Clear the startup flag. */
235 5: sethi %hi(_dl_starting_up), %g1
236 or %g1, %lo(_dl_starting_up), %g1
239 /* Pass our finalizer function to the user in %g1. */
240 sethi %hi(_dl_fini), %g1
241 or %g1, %lo(_dl_fini), %g1
243 /* Jump to the user's entry point and deallocate the extra stack we got. */
246 .size _dl_start_user,.-_dl_start_user
250 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
251 MAP is the object containing the reloc. */
254 elf_machine_rela (struct link_map
*map
, const Elf32_Rela
*reloc
,
255 const Elf32_Sym
*sym
, const struct r_found_version
*version
,
256 Elf32_Addr
*const reloc_addr
)
258 extern unsigned long _dl_hwcap
;
260 if (ELF32_R_TYPE (reloc
->r_info
) == R_SPARC_RELATIVE
)
262 #ifndef RTLD_BOOTSTRAP
263 if (map
!= &_dl_rtld_map
) /* Already done in rtld itself. */
265 *reloc_addr
+= map
->l_addr
+ reloc
->r_addend
;
269 const Elf32_Sym
*const refsym
= sym
;
271 if (sym
->st_shndx
!= SHN_UNDEF
&&
272 ELF32_ST_BIND (sym
->st_info
) == STB_LOCAL
)
276 value
= RESOLVE (&sym
, version
, ELF32_R_TYPE (reloc
->r_info
));
278 value
+= sym
->st_value
;
280 value
+= reloc
->r_addend
; /* Assume copy relocs have zero addend. */
282 switch (ELF32_R_TYPE (reloc
->r_info
))
285 #ifndef RTLD_BOOTSTRAP
286 if (sym
->st_size
> refsym
->st_size
287 || (_dl_verbose
&& sym
->st_size
< refsym
->st_size
))
289 extern char **_dl_argv
;
292 strtab
= ((void *) map
->l_addr
293 + map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
294 _dl_sysdep_error (_dl_argv
[0] ?: "<program name unknown>",
295 ": Symbol `", strtab
+ refsym
->st_name
,
296 "' has different size in shared object, "
297 "consider re-linking\n", NULL
);
299 memcpy (reloc_addr
, (void *) value
, MIN (sym
->st_size
,
303 case R_SPARC_GLOB_DAT
:
307 case R_SPARC_JMP_SLOT
:
308 /* For thread safety, write the instructions from the bottom and
309 flush before we overwrite the critical "b,a". */
310 reloc_addr
[2] = OPCODE_JMP_G1
| (value
& 0x3ff);
311 if (_dl_hwcap
& HWCAP_SPARC_FLUSH
)
312 __asm
__volatile ("flush %0+8" : : "r"(reloc_addr
));
313 reloc_addr
[1] = OPCODE_SETHI_G1
| (value
>> 10);
314 if (_dl_hwcap
& HWCAP_SPARC_FLUSH
)
315 __asm
__volatile ("flush %0+4" : : "r"(reloc_addr
));
318 *(char *) reloc_addr
= value
;
321 *(short *) reloc_addr
= value
;
324 *(char *) reloc_addr
= (value
- (Elf32_Addr
) reloc_addr
);
327 *(short *) reloc_addr
= (value
- (Elf32_Addr
) reloc_addr
);
330 *reloc_addr
= (value
- (Elf32_Addr
) reloc_addr
);
333 *reloc_addr
= (*reloc_addr
& ~0x3ff) | (value
& 0x3ff);
335 case R_SPARC_WDISP30
:
336 *reloc_addr
= ((*reloc_addr
& 0xc0000000)
337 | ((value
- (unsigned int) reloc_addr
) >> 2));
340 *reloc_addr
= (*reloc_addr
& 0xffc00000) | (value
>> 10);
342 case R_SPARC_NONE
: /* Alright, Wilbur. */
345 assert (! "unexpected dynamic reloc type");
352 elf_machine_lazy_rel (struct link_map
*map
, const Elf32_Rela
*reloc
)
354 switch (ELF32_R_TYPE (reloc
->r_info
))
358 case R_SPARC_JMP_SLOT
:
361 assert (! "unexpected PLT reloc type");
This page took 0.055226 seconds and 5 git commands to generate.