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