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