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