45bb0bf1525517238082e8c34bbef6760ad14a49
[kopensolaris-gnu/glibc.git] / sysdeps / sparc / sparc32 / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  SPARC version.
2    Copyright (C) 1996-2002, 2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
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.
9
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    Lesser General Public License for more details.
14
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.  */
19
20 #ifndef dl_machine_h
21 #define dl_machine_h
22
23 #define ELF_MACHINE_NAME "sparc"
24
25 #include <string.h>
26 #include <sys/param.h>
27 #include <ldsodefs.h>
28 #include <tls.h>
29
30 #ifndef VALIDX
31 # define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
32                       + DT_EXTRANUM + DT_VALTAGIDX (tag))
33 #endif
34
35 /* Some SPARC opcodes we need to use for self-modifying code.  */
36 #define OPCODE_NOP      0x01000000 /* nop */
37 #define OPCODE_CALL     0x40000000 /* call ?; add PC-rel word address */
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 */
40 #define OPCODE_SAVE_SP  0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
41 #define OPCODE_BA       0x30800000 /* b,a ?; add PC-rel word address */
42
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));         \
46                            _px; })
47
48
49 /* Use a different preload file when running in 32-bit emulation mode
50    on a 64-bit host.  */
51 #define LD_SO_PRELOAD ((GL(dl_hwcap) & HWCAP_SPARC_V9) \
52                        ? "/etc/ld.so.preload32" \
53                        : "/etc/ld.so.preload")
54
55
56 /* Return nonzero iff ELF header is compatible with the running host.  */
57 static inline int
58 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
59 {
60   if (ehdr->e_machine == EM_SPARC)
61     return 1;
62   else if (ehdr->e_machine == EM_SPARC32PLUS)
63     {
64       unsigned long *hwcap;
65 #ifndef SHARED
66       weak_extern (_dl_hwcap);
67       weak_extern (_dl_hwcap_mask);
68 #endif
69
70       hwcap = WEAKADDR (GL(dl_hwcap));
71       /* XXX The following is wrong!  Dave Miller rejected to implement it
72          correctly.  If this causes problems shoot *him*!  */
73       return hwcap == NULL || (*hwcap & GL(dl_hwcap_mask) & HWCAP_SPARC_V9);
74     }
75   else
76     return 0;
77 }
78
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)   \
83 do {    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)
90
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.  */
94 static inline Elf32_Addr
95 elf_machine_dynamic (void)
96 {
97   register Elf32_Addr *got asm ("%l7");
98
99   LOAD_PIC_REG (got);
100
101   return *got;
102 }
103
104 /* Return the run-time load address of the shared object.  */
105 static inline Elf32_Addr
106 elf_machine_load_address (void)
107 {
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;
122 }
123
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
127 static inline int
128 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
129 {
130   Elf32_Addr *plt;
131   extern void _dl_runtime_resolve (Elf32_Word);
132   extern void _dl_runtime_profile (Elf32_Word);
133
134   if (l->l_info[DT_JMPREL] && lazy)
135     {
136       Elf32_Addr rfunc;
137
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.  */
142       plt = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
143       if (! profile)
144         rfunc = (Elf32_Addr) &_dl_runtime_resolve;
145       else
146         {
147           rfunc = (Elf32_Addr) &_dl_runtime_profile;
148
149           if (_dl_name_match_p (GL(dl_profile), l))
150             GL(dl_profile_map) = l;
151         }
152
153       /* The beginning of the PLT does:
154
155                 save %sp, -64, %sp
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.  */
166       plt[1] = OPCODE_CALL | ((rfunc - (Elf32_Addr) &plt[1]) >> 2);
167       plt[2] = OPCODE_NOP;      /* Fill call delay slot.  */
168       plt[3] = (Elf32_Addr) l;
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);
179 #ifndef SHARED
180           weak_extern (_dl_hwcap);
181 #endif
182           hwcap = WEAKADDR (GL(dl_hwcap));
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         }
202     }
203
204   return lazy;
205 }
206
207 /* This code is used in dl-runtime.c to call the `fixup' function
208    and then redirect to the address it returns.  */
209 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name)     \
210   asm ( "\
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\
228         .previous")
229
230 #ifndef PROF
231 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
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
239
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.  */
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)                       \
253    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
254 #endif
255
256 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
257 #define ELF_MACHINE_JMP_SLOT    R_SPARC_JMP_SLOT
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
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__ ("\
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\
285 1:      call    2f\n\
286          sethi  %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
287 2:      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\
319 21:     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\
326 22:     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\
333 23:     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\
342 3:      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\
360         .previous");
361
362 static inline Elf32_Addr
363 sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
364                  Elf32_Addr value, int t)
365 {
366   Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
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.  */
370   unsigned long *hwcap;
371   int do_flush;
372 # ifndef SHARED
373   weak_extern (_dl_hwcap);
374 # endif
375   hwcap = WEAKADDR (GL(dl_hwcap));
376   do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH));
377 #else
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;
381 #endif
382
383   if (0 && disp >= -0x800000 && disp < 0x800000)
384     {
385       /* Don't need to worry about thread safety. We're writing just one
386          instruction.  */
387
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     }
408
409   return value;
410 }
411
412 static inline Elf32_Addr
413 elf_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
420 /* Return the final value of a plt relocation.  */
421 static inline Elf32_Addr
422 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
423                        Elf32_Addr value)
424 {
425   return value + reloc->r_addend;
426 }
427
428 #endif /* dl_machine_h */
429
430 #ifdef RESOLVE
431
432 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
433    MAP is the object containing the reloc.  */
434
435 static inline void
436 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
437                   const Elf32_Sym *sym, const struct r_found_version *version,
438                   void *const reloc_addr_arg)
439 {
440   Elf32_Addr *const reloc_addr = reloc_addr_arg;
441   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
442
443 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
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
452 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
453   if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0))
454     {
455 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
456       if (map != &_dl_rtld_map) /* Already done in rtld itself. */
457 # endif
458         *reloc_addr += map->l_addr + reloc->r_addend;
459     }
460   else
461 #endif
462     {
463 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
464       const Elf32_Sym *const refsym = sym;
465 #endif
466 #if defined USE_TLS && !defined RTLD_BOOTSTRAP
467       struct link_map *sym_map;
468 #endif
469       Elf32_Addr value;
470 #ifndef RESOLVE_CONFLICT_FIND_MAP
471       if (sym->st_shndx != SHN_UNDEF &&
472           ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
473         {
474           value = map->l_addr;
475 # if defined USE_TLS && !defined RTLD_BOOTSTRAP
476           sym_map = map;
477 # endif
478         }
479       else
480         {
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    
485           value = RESOLVE (&sym, version, r_type);
486           if (sym)
487             value += sym->st_value;
488 # endif
489         }
490 #else
491       value = 0;
492 #endif
493       value += reloc->r_addend; /* Assume copy relocs have zero addend.  */
494
495       switch (r_type)
496         {
497 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
498         case R_SPARC_COPY:
499           if (sym == NULL)
500             /* This can happen in trace mode if an object could not be
501                found.  */
502             break;
503           if (sym->st_size > refsym->st_size
504               || (GL(dl_verbose) && sym->st_size < refsym->st_size))
505             {
506               const char *strtab;
507
508               strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
509               _dl_error_printf ("\
510 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
511                                 rtld_progname ?: "<program name unknown>",
512                                 strtab + refsym->st_name);
513             }
514           memcpy (reloc_addr_arg, (void *) value,
515                   MIN (sym->st_size, refsym->st_size));
516           break;
517 #endif
518         case R_SPARC_GLOB_DAT:
519         case R_SPARC_32:
520           *reloc_addr = value;
521           break;
522         case R_SPARC_JMP_SLOT:
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);
526           break;
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
564 #ifndef RTLD_BOOTSTRAP
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;
590         case R_SPARC_UA16:
591           ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
592           ((unsigned char *) reloc_addr_arg) [1] = value;
593           break;
594         case R_SPARC_UA32:
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;
599           break;
600 #endif
601         case R_SPARC_NONE:              /* Alright, Wilbur.  */
602           break;
603 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
604         default:
605           _dl_reloc_bad_type (map, r_type, 0);
606           break;
607 #endif
608         }
609     }
610 }
611
612 static inline void
613 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
614                            void *const reloc_addr_arg)
615 {
616   Elf32_Addr *const reloc_addr = reloc_addr_arg;
617   *reloc_addr += l_addr + reloc->r_addend;
618 }
619
620 static inline void
621 elf_machine_lazy_rel (struct link_map *map,
622                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
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:
631       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
632       break;
633     }
634 }
635
636 #endif  /* RESOLVE */