]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/sparc/sparc32/dl-machine.h
[BZ #2510, BZ #2830, BZ #3137, BZ #3313, BZ #3426, BZ #3465, BZ #3480, BZ #3483,...
[thirdparty/glibc.git] / sysdeps / sparc / sparc32 / dl-machine.h
CommitLineData
4f54cdb1 1/* Machine-dependent ELF dynamic relocation inline functions. SPARC version.
b01fe5f7 2 Copyright (C) 1996-2003, 2004, 2005, 2006 Free Software Foundation, Inc.
47707456 3 This file is part of the GNU C Library.
4f54cdb1 4
47707456 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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
41bdb6e2 13 Lesser General Public License for more details.
4f54cdb1 14
41bdb6e2
AJ
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
4f54cdb1 19
62f29da7
UD
20#ifndef dl_machine_h
21#define dl_machine_h
22
4f54cdb1
RM
23#define ELF_MACHINE_NAME "sparc"
24
4f54cdb1 25#include <string.h>
1f07e617 26#include <sys/param.h>
a42195db 27#include <ldsodefs.h>
62f29da7 28#include <tls.h>
4f54cdb1 29
32e6df36
UD
30#ifndef VALIDX
31# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
32 + DT_EXTRANUM + DT_VALTAGIDX (tag))
33#endif
4f54cdb1
RM
34
35/* Some SPARC opcodes we need to use for self-modifying code. */
36#define OPCODE_NOP 0x01000000 /* nop */
f752bfe3 37#define OPCODE_CALL 0x40000000 /* call ?; add PC-rel word address */
4f54cdb1
RM
38#define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
39#define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
f41c8091 40#define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
32e6df36 41#define OPCODE_BA 0x30800000 /* b,a ?; add PC-rel word address */
4f54cdb1 42
ceb579a3 43/* Return nonzero iff ELF header is compatible with the running host. */
4f54cdb1 44static inline int
ceb579a3 45elf_machine_matches_host (const Elf32_Ehdr *ehdr)
4f54cdb1 46{
ceb579a3 47 if (ehdr->e_machine == EM_SPARC)
4194bc66 48 return 1;
ceb579a3 49 else if (ehdr->e_machine == EM_SPARC32PLUS)
4194bc66 50 {
63ae7b63
UD
51 /* XXX The following is wrong! Dave Miller rejected to implement it
52 correctly. If this causes problems shoot *him*! */
137ffcdc 53#ifdef SHARED
afdca0f2 54 return GLRO(dl_hwcap) & GLRO(dl_hwcap_mask) & HWCAP_SPARC_V9;
137ffcdc 55#else
afdca0f2 56 return GLRO(dl_hwcap) & HWCAP_SPARC_V9;
137ffcdc 57#endif
4194bc66
RH
58 }
59 else
60 return 0;
4f54cdb1
RM
61}
62
cf299341
UD
63/* We have to do this because elf_machine_{dynamic,load_address} can be
64 invoked from functions that have no GOT references, and thus the compiler
65 has no obligation to load the PIC register. */
66#define LOAD_PIC_REG(PIC_REG) \
67do { register Elf32_Addr pc __asm("o7"); \
68 __asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
69 "call 1f\n\t" \
70 "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
71 "1:\tadd %1, %0, %1" \
72 : "=r" (pc), "=r" (PIC_REG)); \
73} while (0)
4f54cdb1 74
47707456
UD
75/* Return the link-time address of _DYNAMIC. Conveniently, this is the
76 first element of the GOT. This must be inlined in a function which
77 uses global data. */
78static inline Elf32_Addr
79elf_machine_dynamic (void)
4f54cdb1
RM
80{
81 register Elf32_Addr *got asm ("%l7");
cf299341
UD
82
83 LOAD_PIC_REG (got);
84
47707456 85 return *got;
4f54cdb1
RM
86}
87
4f54cdb1
RM
88/* Return the run-time load address of the shared object. */
89static inline Elf32_Addr
90elf_machine_load_address (void)
91{
8243d6f1
RM
92 register Elf32_Addr *pc __asm ("%o7"), *got __asm ("%l7");
93
94 __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
95 "call 1f\n\t"
96 " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
97 "call _DYNAMIC\n\t"
98 "call _GLOBAL_OFFSET_TABLE_\n"
99 "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
100
101 /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
102 *got is _DYNAMIC
103 pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
104 pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12 */
105 return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
ca34d7a7
UD
106}
107
f41c8091
UD
108/* Set up the loaded object described by L so its unrelocated PLT
109 entries will jump to the on-demand fixup code in dl-runtime.c. */
110
111static inline int
112elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
113{
114 Elf32_Addr *plt;
115 extern void _dl_runtime_resolve (Elf32_Word);
9c4c0024 116 extern void _dl_runtime_profile (Elf32_Word);
f41c8091
UD
117
118 if (l->l_info[DT_JMPREL] && lazy)
119 {
9c4c0024
UD
120 Elf32_Addr rfunc;
121
f41c8091
UD
122 /* The entries for functions in the PLT have not yet been filled in.
123 Their initial contents will arrange when called to set the high 22
124 bits of %g1 with an offset into the .rela.plt section and jump to
125 the beginning of the PLT. */
b86120ed 126 plt = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
404a4e2f 127 if (__builtin_expect(profile, 0))
9c4c0024
UD
128 {
129 rfunc = (Elf32_Addr) &_dl_runtime_profile;
130
404a4e2f
RM
131 if (GLRO(dl_profile) != NULL
132 && _dl_name_match_p (GLRO(dl_profile), l))
5688da55 133 GL(dl_profile_map) = l;
9c4c0024 134 }
404a4e2f
RM
135 else
136 {
137 rfunc = (Elf32_Addr) &_dl_runtime_resolve;
138 }
f41c8091
UD
139
140 /* The beginning of the PLT does:
141
404a4e2f
RM
142 sethi %hi(_dl_runtime_{resolve,profile}), %g2
143 pltpc: jmpl %g2 + %lo(_dl_runtime_{resolve,profile}), %g2
144 nop
f41c8091
UD
145 .word MAP
146
404a4e2f 147 The PC value (pltpc) saved in %g2 by the jmpl points near the
f41c8091
UD
148 location where we store the link_map pointer for this object. */
149
404a4e2f
RM
150 plt[0] = 0x05000000 | ((rfunc >> 10) & 0x003fffff);
151 plt[1] = 0x85c0a000 | (rfunc & 0x3ff);
f41c8091
UD
152 plt[2] = OPCODE_NOP; /* Fill call delay slot. */
153 plt[3] = (Elf32_Addr) l;
32e6df36
UD
154 if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
155 || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
156 {
157 /* Need to reinitialize .plt to undo prelinking. */
32e6df36
UD
158 int do_flush;
159 Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
160 Elf32_Rela *relaend
161 = (Elf32_Rela *) ((char *) rela
162 + l->l_info[DT_PLTRELSZ]->d_un.d_val);
afdca0f2 163 do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
32e6df36
UD
164
165 /* prelink must ensure there are no R_SPARC_NONE relocs left
166 in .rela.plt. */
167 while (rela < relaend)
168 {
169 *(unsigned int *) rela->r_offset
170 = OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt);
171 *(unsigned int *) (rela->r_offset + 4)
172 = OPCODE_BA | ((((Elf32_Addr) plt
173 - rela->r_offset - 4) >> 2) & 0x3fffff);
174 if (do_flush)
175 {
176 __asm __volatile ("flush %0" : : "r"(rela->r_offset));
177 __asm __volatile ("flush %0+4" : : "r"(rela->r_offset));
178 }
179 ++rela;
180 }
181 }
f41c8091
UD
182 }
183
184 return lazy;
4f54cdb1
RM
185}
186
cf5a372e
UD
187/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
188 PLT entries should not be allowed to define the value.
189 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
190 of the main executable's symbols, as for a COPY reloc. */
11bf311e 191#if !defined RTLD_BOOTSTRAP || USE___THREAD
62f29da7
UD
192# define elf_machine_type_class(type) \
193 ((((type) == R_SPARC_JMP_SLOT \
194 || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
195 * ELF_RTYPE_CLASS_PLT) \
196 | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
197#else
198# define elf_machine_type_class(type) \
199 ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
cf5a372e 200 | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
62f29da7 201#endif
f41c8091
UD
202
203/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 204#define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
f41c8091
UD
205
206/* The SPARC never uses Elf32_Rel relocations. */
207#define ELF_MACHINE_NO_REL 1
208
209/* The SPARC overlaps DT_RELA and DT_PLTREL. */
210#define ELF_MACHINE_PLTREL_OVERLAP 1
211
97716954
UD
212/* Undo the sub %sp, 6*4, %sp; add %sp, 22*4, %o0 below to get at the
213 value we want in __libc_stack_end. */
214#define DL_STACK_END(cookie) \
215 ((void *) (((long) (cookie)) - (22 - 6) * 4))
216
f41c8091
UD
217/* Initial entry point code for the dynamic linker.
218 The C function `_dl_start' is the real entry point;
219 its return value is the user program's entry point. */
220
221#define RTLD_START __asm__ ("\
669ed638
UD
222 .text\n\
223 .globl _start\n\
224 .type _start, @function\n\
225 .align 32\n\
226_start:\n\
227 /* Allocate space for functions to drop their arguments. */\n\
228 sub %sp, 6*4, %sp\n\
229 /* Pass pointer to argument block to _dl_start. */\n\
230 call _dl_start\n\
231 add %sp, 22*4, %o0\n\
232 /* FALTHRU */\n\
233 .globl _dl_start_user\n\
234 .type _dl_start_user, @function\n\
235_dl_start_user:\n\
236 /* Load the PIC register. */\n\
2371: call 2f\n\
238 sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
2392: or %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
240 add %l7, %o7, %l7\n\
241 /* Save the user entry point address in %l0 */\n\
242 mov %o0, %l0\n\
669ed638
UD
243 /* See if we were run as a command with the executable file name as an\n\
244 extra leading argument. If so, adjust the contents of the stack. */\n\
97716954
UD
245 sethi %hi(_dl_skip_args), %g2\n\
246 or %g2, %lo(_dl_skip_args), %g2\n\
669ed638
UD
247 ld [%l7+%g2], %i0\n\
248 ld [%i0], %i0\n\
249 tst %i0\n\
250 beq 3f\n\
251 ld [%sp+22*4], %i5 /* load argc */\n\
252 /* Find out how far to shift. */\n\
253 sethi %hi(_dl_argv), %l3\n\
254 or %l3, %lo(_dl_argv), %l3\n\
255 ld [%l7+%l3], %l3\n\
256 sub %i5, %i0, %i5\n\
257 ld [%l3], %l4\n\
258 sll %i0, 2, %i2\n\
259 st %i5, [%sp+22*4]\n\
260 sub %l4, %i2, %l4\n\
261 add %sp, 23*4, %i1\n\
262 add %i1, %i2, %i2\n\
263 st %l4, [%l3]\n\
264 /* Copy down argv */\n\
26521: ld [%i2], %i3\n\
266 add %i2, 4, %i2\n\
267 tst %i3\n\
268 st %i3, [%i1]\n\
269 bne 21b\n\
270 add %i1, 4, %i1\n\
271 /* Copy down env */\n\
27222: ld [%i2], %i3\n\
273 add %i2, 4, %i2\n\
274 tst %i3\n\
275 st %i3, [%i1]\n\
276 bne 22b\n\
277 add %i1, 4, %i1\n\
278 /* Copy down auxiliary table. */\n\
27923: ld [%i2], %i3\n\
280 ld [%i2+4], %i4\n\
281 add %i2, 8, %i2\n\
282 tst %i3\n\
283 st %i3, [%i1]\n\
284 st %i4, [%i1+4]\n\
285 bne 23b\n\
286 add %i1, 8, %i1\n\
287 /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp. */\n\
2883: sethi %hi(_rtld_local), %o0\n\
289 add %sp, 23*4, %o2\n\
290 orcc %o0, %lo(_rtld_local), %o0\n\
291 sll %i5, 2, %o3\n\
292 ld [%l7+%o0], %o0\n\
293 add %o3, 4, %o3\n\
294 mov %i5, %o1\n\
295 add %o2, %o3, %o3\n\
296 call _dl_init_internal\n\
297 ld [%o0], %o0\n\
298 /* Pass our finalizer function to the user in %g1. */\n\
299 sethi %hi(_dl_fini), %g1\n\
300 or %g1, %lo(_dl_fini), %g1\n\
301 ld [%l7+%g1], %g1\n\
302 /* Jump to the user's entry point and deallocate the extra stack we got. */\n\
303 jmp %l0\n\
304 add %sp, 6*4, %sp\n\
305 .size _dl_start_user, . - _dl_start_user\n\
9c4c0024 306 .previous");
f41c8091 307
c0282c06 308static inline Elf32_Addr
32e6df36
UD
309sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
310 Elf32_Addr value, int t)
a2b08ee5 311{
32e6df36 312 Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
4194bc66
RH
313#ifndef RTLD_BOOTSTRAP
314 /* Note that we don't mask the hwcap here, as the flush is essential to
315 functionality on those cpu's that implement it. */
afdca0f2 316 int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
4194bc66 317#else
bf47fa23
UD
318 /* Unfortunately, this is necessary, so that we can ensure
319 ld.so will not execute corrupt PLT entry instructions. */
320 const int do_flush = 1;
4194bc66 321#endif
5688da55 322
32e6df36
UD
323 if (0 && disp >= -0x800000 && disp < 0x800000)
324 {
325 /* Don't need to worry about thread safety. We're writing just one
326 instruction. */
dfd2257a 327
32e6df36
UD
328 reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
329 if (do_flush)
330 __asm __volatile ("flush %0" : : "r"(reloc_addr));
331 }
332 else
333 {
334 /* For thread safety, write the instructions from the bottom and
335 flush before we overwrite the critical "b,a". This of course
336 need not be done during bootstrapping, since there are no threads.
337 But we also can't tell if we _can_ use flush, so don't. */
338
339 reloc_addr += t;
340 reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
341 if (do_flush)
342 __asm __volatile ("flush %0+4" : : "r"(reloc_addr));
343
344 reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
345 if (do_flush)
346 __asm __volatile ("flush %0" : : "r"(reloc_addr));
347 }
c0282c06
UD
348
349 return value;
a2b08ee5
UD
350}
351
32e6df36
UD
352static inline Elf32_Addr
353elf_machine_fixup_plt (struct link_map *map, lookup_t t,
354 const Elf32_Rela *reloc,
355 Elf32_Addr *reloc_addr, Elf32_Addr value)
356{
357 return sparc_fixup_plt (reloc, reloc_addr, value, 1);
358}
359
dfd2257a
UD
360/* Return the final value of a plt relocation. */
361static inline Elf32_Addr
362elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
363 Elf32_Addr value)
364{
365 return value + reloc->r_addend;
366}
367
62f29da7
UD
368#endif /* dl_machine_h */
369
404a4e2f
RM
370#define ARCH_LA_PLTENTER sparc32_gnu_pltenter
371#define ARCH_LA_PLTEXIT sparc32_gnu_pltexit
372
373#ifdef RESOLVE_MAP
a2b08ee5 374
4f54cdb1
RM
375/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
376 MAP is the object containing the reloc. */
377
1b243ca9
RM
378auto inline void
379__attribute__ ((always_inline))
0d8733c4 380elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
8f2ece69 381 const Elf32_Sym *sym, const struct r_found_version *version,
87d254a7 382 void *const reloc_addr_arg)
4f54cdb1 383{
87d254a7 384 Elf32_Addr *const reloc_addr = reloc_addr_arg;
404a4e2f
RM
385 const Elf32_Sym *const refsym = sym;
386 Elf32_Addr value;
1721af3f 387 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
404a4e2f 388 struct link_map *sym_map = NULL;
1721af3f 389
ee0cb67e 390#if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
4194bc66
RH
391 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
392 reference weak so static programs can still link. This declaration
393 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
394 because rtld.c contains the common defn for _dl_rtld_map, which is
395 incompatible with a weak decl in the same file. */
396 weak_extern (_dl_rtld_map);
397#endif
398
404a4e2f
RM
399 if (__builtin_expect (r_type == R_SPARC_NONE, 0))
400 return;
401
84aafa91 402#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
1721af3f 403 if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0))
993b3242 404 {
ee0cb67e 405# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
993b3242 406 if (map != &_dl_rtld_map) /* Already done in rtld itself. */
ee0cb67e 407# endif
993b3242 408 *reloc_addr += map->l_addr + reloc->r_addend;
404a4e2f 409 return;
0ecb606c 410 }
a334319f 411#endif
404a4e2f 412
a334319f 413#ifndef RESOLVE_CONFLICT_FIND_MAP
404a4e2f
RM
414 if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
415 && sym->st_shndx != SHN_UNDEF)
416 {
417 value = map->l_addr;
418 }
419 else
420 {
421 sym_map = RESOLVE_MAP (&sym, version, r_type);
422 value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
423 }
32e6df36 424#else
404a4e2f 425 value = 0;
32e6df36 426#endif
ceb2d9aa 427
404a4e2f
RM
428 value += reloc->r_addend; /* Assume copy relocs have zero addend. */
429
430 switch (r_type)
431 {
a334319f 432#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
404a4e2f
RM
433 case R_SPARC_COPY:
434 if (sym == NULL)
435 /* This can happen in trace mode if an object could not be
436 found. */
437 break;
438 if (sym->st_size > refsym->st_size
439 || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
440 {
441 const char *strtab;
1f07e617 442
404a4e2f
RM
443 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
444 _dl_error_printf ("\
b9fb7870 445%s: Symbol `%s' has different size in shared object, consider re-linking\n",
404a4e2f
RM
446 rtld_progname ?: "<program name unknown>",
447 strtab + refsym->st_name);
448 }
449 memcpy (reloc_addr_arg, (void *) value,
450 MIN (sym->st_size, refsym->st_size));
451 break;
33e09162 452#endif
404a4e2f
RM
453 case R_SPARC_GLOB_DAT:
454 case R_SPARC_32:
455 *reloc_addr = value;
456 break;
457 case R_SPARC_JMP_SLOT:
458 /* At this point we don't need to bother with thread safety,
459 so we can optimize the first instruction of .plt out. */
460 sparc_fixup_plt (reloc, reloc_addr, value, 0);
461 break;
11bf311e 462#if (!defined RTLD_BOOTSTRAP || USE___THREAD) \
62f29da7 463 && !defined RESOLVE_CONFLICT_FIND_MAP
404a4e2f
RM
464 case R_SPARC_TLS_DTPMOD32:
465 /* Get the information from the link map returned by the
466 resolv function. */
467 if (sym_map != NULL)
468 *reloc_addr = sym_map->l_tls_modid;
469 break;
470 case R_SPARC_TLS_DTPOFF32:
471 /* During relocation all TLS symbols are defined and used.
472 Therefore the offset is already correct. */
473 *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
474 break;
475 case R_SPARC_TLS_TPOFF32:
476 /* The offset is negative, forward from the thread pointer. */
477 /* We know the offset of object the symbol is contained in.
478 It is a negative value which will be added to the
479 thread pointer. */
480 if (sym != NULL)
481 {
482 CHECK_STATIC_TLS (map, sym_map);
483 *reloc_addr = sym->st_value - sym_map->l_tls_offset
484 + reloc->r_addend;
485 }
486 break;
62f29da7 487# ifndef RTLD_BOOTSTRAP
404a4e2f
RM
488 case R_SPARC_TLS_LE_HIX22:
489 case R_SPARC_TLS_LE_LOX10:
490 if (sym != NULL)
491 {
492 CHECK_STATIC_TLS (map, sym_map);
493 value = sym->st_value - sym_map->l_tls_offset
494 + reloc->r_addend;
495 if (r_type == R_SPARC_TLS_LE_HIX22)
496 *reloc_addr = (*reloc_addr & 0xffc00000) | ((~value) >> 10);
497 else
498 *reloc_addr = (*reloc_addr & 0xffffe000) | (value & 0x3ff)
499 | 0x1c00;
500 }
501 break;
62f29da7
UD
502# endif
503#endif
33e09162 504#ifndef RTLD_BOOTSTRAP
404a4e2f
RM
505 case R_SPARC_8:
506 *(char *) reloc_addr = value;
507 break;
508 case R_SPARC_16:
509 *(short *) reloc_addr = value;
510 break;
511 case R_SPARC_DISP8:
512 *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
513 break;
514 case R_SPARC_DISP16:
515 *(short *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
516 break;
517 case R_SPARC_DISP32:
518 *reloc_addr = (value - (Elf32_Addr) reloc_addr);
519 break;
520 case R_SPARC_LO10:
521 *reloc_addr = (*reloc_addr & ~0x3ff) | (value & 0x3ff);
522 break;
523 case R_SPARC_WDISP30:
524 *reloc_addr = ((*reloc_addr & 0xc0000000)
525 | ((value - (unsigned int) reloc_addr) >> 2));
526 break;
527 case R_SPARC_HI22:
528 *reloc_addr = (*reloc_addr & 0xffc00000) | (value >> 10);
529 break;
530 case R_SPARC_UA16:
531 ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
532 ((unsigned char *) reloc_addr_arg) [1] = value;
533 break;
534 case R_SPARC_UA32:
535 ((unsigned char *) reloc_addr_arg) [0] = value >> 24;
536 ((unsigned char *) reloc_addr_arg) [1] = value >> 16;
537 ((unsigned char *) reloc_addr_arg) [2] = value >> 8;
538 ((unsigned char *) reloc_addr_arg) [3] = value;
539 break;
33e09162 540#endif
33e09162 541#if !defined RTLD_BOOTSTRAP || defined _NDEBUG
404a4e2f
RM
542 default:
543 _dl_reloc_bad_type (map, r_type, 0);
544 break;
33e09162 545#endif
4f54cdb1
RM
546 }
547}
548
1b243ca9
RM
549auto inline void
550__attribute__ ((always_inline))
1f2a1df3 551elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
87d254a7 552 void *const reloc_addr_arg)
1721af3f 553{
87d254a7 554 Elf32_Addr *const reloc_addr = reloc_addr_arg;
1721af3f
UD
555 *reloc_addr += l_addr + reloc->r_addend;
556}
557
1b243ca9
RM
558auto inline void
559__attribute__ ((always_inline))
421c80d2
RM
560elf_machine_lazy_rel (struct link_map *map,
561 Elf32_Addr l_addr, const Elf32_Rela *reloc)
4f54cdb1
RM
562{
563 switch (ELF32_R_TYPE (reloc->r_info))
564 {
565 case R_SPARC_NONE:
566 break;
567 case R_SPARC_JMP_SLOT:
568 break;
569 default:
421c80d2 570 _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
4f54cdb1
RM
571 break;
572 }
573}
574
404a4e2f 575#endif /* RESOLVE_MAP */