Made stuff work on SPARC HW
[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
156       if(GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH)
157         for(int i = 0; i < 4; i++)
158           asm volatile("flush %0" : : "r"(&plt[i]));
159
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           Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
165           Elf32_Rela *relaend
166             = (Elf32_Rela *) ((char *) rela
167                               + l->l_info[DT_PLTRELSZ]->d_un.d_val);
168 #if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
169           /* Note that we don't mask the hwcap here, as the flush is
170              essential to functionality on those cpu's that implement it.
171              For sparcv9 we can assume flush is present.  */
172           const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
173 #else
174           const int do_flush = 1;
175 #endif
176
177           /* prelink must ensure there are no R_SPARC_NONE relocs left
178              in .rela.plt.  */
179           while (rela < relaend)
180             {
181               *(unsigned int *) rela->r_offset
182                 = OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt);
183               *(unsigned int *) (rela->r_offset + 4)
184                 = OPCODE_BA | ((((Elf32_Addr) plt
185                                  - rela->r_offset - 4) >> 2) & 0x3fffff);
186               if (do_flush)
187                 {
188                   __asm __volatile ("flush %0" : : "r"(rela->r_offset));
189                   __asm __volatile ("flush %0+4" : : "r"(rela->r_offset));
190                 }
191               ++rela;
192             }
193         }
194     }
195
196   return lazy;
197 }
198
199 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
200    PLT entries should not be allowed to define the value.
201    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
202    of the main executable's symbols, as for a COPY reloc.  */
203 #if !defined RTLD_BOOTSTRAP || USE___THREAD
204 # define elf_machine_type_class(type) \
205   ((((type) == R_SPARC_JMP_SLOT                                               \
206      || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64))     \
207     * ELF_RTYPE_CLASS_PLT)                                                    \
208    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
209 #else
210 # define elf_machine_type_class(type) \
211   ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)                       \
212    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
213 #endif
214
215 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
216 #define ELF_MACHINE_JMP_SLOT    R_SPARC_JMP_SLOT
217
218 /* The SPARC never uses Elf32_Rel relocations.  */
219 #define ELF_MACHINE_NO_REL 1
220
221 /* The SPARC overlaps DT_RELA and DT_PLTREL.  */
222 #define ELF_MACHINE_PLTREL_OVERLAP 1
223
224 /* Undo the sub %sp, 6*4, %sp; add %sp, 22*4, %o0 below to get at the
225    value we want in __libc_stack_end.  */
226 #define DL_STACK_END(cookie) \
227   ((void *) (((long) (cookie)) - (22 - 6) * 4))
228
229 /* Initial entry point code for the dynamic linker.
230    The C function `_dl_start' is the real entry point;
231    its return value is the user program's entry point.  */
232
233 #define RTLD_START __asm__ ("\
234         .text\n\
235         .globl  _start\n\
236         .type   _start, @function\n\
237         .align  32\n\
238 _start:\n\
239   /* Allocate space for functions to drop their arguments.  */\n\
240         sub     %sp, 6*4, %sp\n\
241   /* Pass pointer to argument block to _dl_start.  */\n\
242         call    _dl_start\n\
243          add    %sp, 22*4, %o0\n\
244         /* FALTHRU */\n\
245         .globl  _dl_start_user\n\
246         .type   _dl_start_user, @function\n\
247 _dl_start_user:\n\
248   /* Load the PIC register.  */\n\
249 1:      call    2f\n\
250          sethi  %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
251 2:      or      %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
252         add     %l7, %o7, %l7\n\
253   /* Save the user entry point address in %l0 */\n\
254         mov     %o0, %l0\n\
255   /* See if we were run as a command with the executable file name as an\n\
256      extra leading argument.  If so, adjust the contents of the stack.  */\n\
257         sethi   %hi(_dl_skip_args), %g2\n\
258         or      %g2, %lo(_dl_skip_args), %g2\n\
259         ld      [%l7+%g2], %i0\n\
260         ld      [%i0], %i0\n\
261         tst     %i0\n\
262         beq     3f\n\
263          ld     [%sp+22*4], %i5         /* load argc */\n\
264         /* Find out how far to shift.  */\n\
265         sethi   %hi(_dl_argv), %l3\n\
266         or      %l3, %lo(_dl_argv), %l3\n\
267         ld      [%l7+%l3], %l3\n\
268         sub     %i5, %i0, %i5\n\
269         ld      [%l3], %l4\n\
270         sll     %i0, 2, %i2\n\
271         st      %i5, [%sp+22*4]\n\
272         sub     %l4, %i2, %l4\n\
273         add     %sp, 23*4, %i1\n\
274         add     %i1, %i2, %i2\n\
275         st      %l4, [%l3]\n\
276         /* Copy down argv */\n\
277 21:     ld      [%i2], %i3\n\
278         add     %i2, 4, %i2\n\
279         tst     %i3\n\
280         st      %i3, [%i1]\n\
281         bne     21b\n\
282          add    %i1, 4, %i1\n\
283         /* Copy down env */\n\
284 22:     ld      [%i2], %i3\n\
285         add     %i2, 4, %i2\n\
286         tst     %i3\n\
287         st      %i3, [%i1]\n\
288         bne     22b\n\
289          add    %i1, 4, %i1\n\
290         /* Copy down auxiliary table.  */\n\
291 23:     ld      [%i2], %i3\n\
292         ld      [%i2+4], %i4\n\
293         add     %i2, 8, %i2\n\
294         tst     %i3\n\
295         st      %i3, [%i1]\n\
296         st      %i4, [%i1+4]\n\
297         bne     23b\n\
298          add    %i1, 8, %i1\n\
299   /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp.  */\n\
300 3:      sethi   %hi(_rtld_local), %o0\n\
301         add     %sp, 23*4, %o2\n\
302         orcc    %o0, %lo(_rtld_local), %o0\n\
303         sll     %i5, 2, %o3\n\
304         ld      [%l7+%o0], %o0\n\
305         add     %o3, 4, %o3\n\
306         mov     %i5, %o1\n\
307         add     %o2, %o3, %o3\n\
308         call    _dl_init_internal\n\
309          ld     [%o0], %o0\n\
310   /* Pass our finalizer function to the user in %g1.  */\n\
311         sethi   %hi(_dl_fini), %g1\n\
312         or      %g1, %lo(_dl_fini), %g1\n\
313         ld      [%l7+%g1], %g1\n\
314   /* Jump to the user's entry point and deallocate the extra stack we got.  */\n\
315         jmp     %l0\n\
316          add    %sp, 6*4, %sp\n\
317         .size   _dl_start_user, . - _dl_start_user\n\
318         .previous");
319
320 static inline __attribute__ ((always_inline)) Elf32_Addr
321 sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
322                  Elf32_Addr value, int t, int do_flush)
323 {
324   Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
325
326   if (0 && disp >= -0x800000 && disp < 0x800000)
327     {
328       /* Don't need to worry about thread safety. We're writing just one
329          instruction.  */
330
331       reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
332       if (do_flush)
333         __asm __volatile ("flush %0" : : "r"(reloc_addr));
334     }
335   else
336     {
337       /* For thread safety, write the instructions from the bottom and
338          flush before we overwrite the critical "b,a".  This of course
339          need not be done during bootstrapping, since there are no threads.
340          But we also can't tell if we _can_ use flush, so don't. */
341
342       reloc_addr += t;
343       reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
344       if (do_flush)
345         __asm __volatile ("flush %0+4" : : "r"(reloc_addr));
346
347       reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
348       if (do_flush)
349         __asm __volatile ("flush %0" : : "r"(reloc_addr));
350     }
351
352   return value;
353 }
354
355 static inline Elf32_Addr
356 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
357                        const Elf32_Rela *reloc,
358                        Elf32_Addr *reloc_addr, Elf32_Addr value)
359 {
360 #ifdef __sparc_v9__
361   /* Sparc v9 can assume flush is always present.  */
362   const int do_flush = 1;
363 #else
364   /* Note that we don't mask the hwcap here, as the flush is essential to
365      functionality on those cpu's that implement it.  */
366   const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
367 #endif
368   return sparc_fixup_plt (reloc, reloc_addr, value, 1, do_flush);
369 }
370
371 /* Return the final value of a plt relocation.  */
372 static inline Elf32_Addr
373 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
374                        Elf32_Addr value)
375 {
376   return value + reloc->r_addend;
377 }
378
379 #endif /* dl_machine_h */
380
381 #define ARCH_LA_PLTENTER        sparc32_gnu_pltenter
382 #define ARCH_LA_PLTEXIT         sparc32_gnu_pltexit
383
384 #ifdef RESOLVE_MAP
385
386 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
387    MAP is the object containing the reloc.  */
388
389 auto inline void
390 __attribute__ ((always_inline))
391 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
392                   const Elf32_Sym *sym, const struct r_found_version *version,
393                   void *const reloc_addr_arg)
394 {
395   Elf32_Addr *const reloc_addr = reloc_addr_arg;
396   const Elf32_Sym *const refsym = sym;
397   Elf32_Addr value;
398   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
399   struct link_map *sym_map = NULL;
400
401 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
402   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
403      reference weak so static programs can still link.  This declaration
404      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
405      because rtld.c contains the common defn for _dl_rtld_map, which is
406      incompatible with a weak decl in the same file.  */
407   weak_extern (_dl_rtld_map);
408 #endif
409
410   if (__builtin_expect (r_type == R_SPARC_NONE, 0))
411     return;
412
413 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
414   if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0))
415     {
416 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
417       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
418 # endif
419         *reloc_addr += map->l_addr + reloc->r_addend;
420       return;
421     }
422 #endif
423
424 #ifndef RESOLVE_CONFLICT_FIND_MAP
425   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
426       && sym->st_shndx != SHN_UNDEF)
427     {
428       value = map->l_addr;
429     }
430   else
431     {
432       sym_map = RESOLVE_MAP (&sym, version, r_type);
433       value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
434     }
435 #else
436   value = 0;
437 #endif
438
439   value += reloc->r_addend;     /* Assume copy relocs have zero addend.  */
440
441   switch (r_type)
442     {
443 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
444     case R_SPARC_COPY:
445       if (sym == NULL)
446         /* This can happen in trace mode if an object could not be
447            found.  */
448         break;
449       if (sym->st_size > refsym->st_size
450           || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
451         {
452           const char *strtab;
453
454           strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
455           _dl_error_printf ("\
456 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
457                             rtld_progname ?: "<program name unknown>",
458                             strtab + refsym->st_name);
459         }
460       memcpy (reloc_addr_arg, (void *) value,
461               MIN (sym->st_size, refsym->st_size));
462       break;
463 #endif
464     case R_SPARC_GLOB_DAT:
465     case R_SPARC_32:
466       *reloc_addr = value;
467       break;
468     case R_SPARC_JMP_SLOT:
469       {
470 #if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
471         /* Note that we don't mask the hwcap here, as the flush is
472            essential to functionality on those cpu's that implement
473            it.  For sparcv9 we can assume flush is present.  */
474         const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
475 #else
476         /* Unfortunately, this is necessary, so that we can ensure
477            ld.so will not execute corrupt PLT entry instructions. */
478         const int do_flush = 1;
479 #endif
480         /* At this point we don't need to bother with thread safety,
481            so we can optimize the first instruction of .plt out.  */
482         sparc_fixup_plt (reloc, reloc_addr, value, 0, do_flush);
483       }
484       break;
485 #if (!defined RTLD_BOOTSTRAP || USE___THREAD) \
486     && !defined RESOLVE_CONFLICT_FIND_MAP
487     case R_SPARC_TLS_DTPMOD32:
488       /* Get the information from the link map returned by the
489          resolv function.  */
490       if (sym_map != NULL)
491         *reloc_addr = sym_map->l_tls_modid;
492       break;
493     case R_SPARC_TLS_DTPOFF32:
494       /* During relocation all TLS symbols are defined and used.
495          Therefore the offset is already correct.  */
496       *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
497       break;
498     case R_SPARC_TLS_TPOFF32:
499       /* The offset is negative, forward from the thread pointer.  */
500       /* We know the offset of object the symbol is contained in.
501          It is a negative value which will be added to the
502          thread pointer.  */
503       if (sym != NULL)
504         {
505           CHECK_STATIC_TLS (map, sym_map);
506           *reloc_addr = sym->st_value - sym_map->l_tls_offset
507             + reloc->r_addend;
508         }
509       break;
510 # ifndef RTLD_BOOTSTRAP
511     case R_SPARC_TLS_LE_HIX22:
512     case R_SPARC_TLS_LE_LOX10:
513       if (sym != NULL)
514         {
515           CHECK_STATIC_TLS (map, sym_map);
516           value = sym->st_value - sym_map->l_tls_offset
517             + reloc->r_addend;
518           if (r_type == R_SPARC_TLS_LE_HIX22)
519             *reloc_addr = (*reloc_addr & 0xffc00000) | ((~value) >> 10);
520           else
521             *reloc_addr = (*reloc_addr & 0xffffe000) | (value & 0x3ff)
522               | 0x1c00;
523         }
524       break;
525 # endif
526 #endif
527 #ifndef RTLD_BOOTSTRAP
528     case R_SPARC_8:
529       *(char *) reloc_addr = value;
530       break;
531     case R_SPARC_16:
532       *(short *) reloc_addr = value;
533       break;
534     case R_SPARC_DISP8:
535       *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
536       break;
537     case R_SPARC_DISP16:
538       *(short *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
539       break;
540     case R_SPARC_DISP32:
541       *reloc_addr = (value - (Elf32_Addr) reloc_addr);
542       break;
543     case R_SPARC_LO10:
544       *reloc_addr = (*reloc_addr & ~0x3ff) | (value & 0x3ff);
545       break;
546     case R_SPARC_WDISP30:
547       *reloc_addr = ((*reloc_addr & 0xc0000000)
548                      | ((value - (unsigned int) reloc_addr) >> 2));
549       break;
550     case R_SPARC_HI22:
551       *reloc_addr = (*reloc_addr & 0xffc00000) | (value >> 10);
552       break;
553     case R_SPARC_UA16:
554       ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
555       ((unsigned char *) reloc_addr_arg) [1] = value;
556       break;
557     case R_SPARC_UA32:
558       ((unsigned char *) reloc_addr_arg) [0] = value >> 24;
559       ((unsigned char *) reloc_addr_arg) [1] = value >> 16;
560       ((unsigned char *) reloc_addr_arg) [2] = value >> 8;
561       ((unsigned char *) reloc_addr_arg) [3] = value;
562       break;
563 #endif
564 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
565     default:
566       _dl_reloc_bad_type (map, r_type, 0);
567       break;
568 #endif
569     }
570 }
571
572 auto inline void
573 __attribute__ ((always_inline))
574 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
575                            void *const reloc_addr_arg)
576 {
577   Elf32_Addr *const reloc_addr = reloc_addr_arg;
578   *reloc_addr += l_addr + reloc->r_addend;
579 }
580
581 auto inline void
582 __attribute__ ((always_inline))
583 elf_machine_lazy_rel (struct link_map *map,
584                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
585 {
586   switch (ELF32_R_TYPE (reloc->r_info))
587     {
588     case R_SPARC_NONE:
589       break;
590     case R_SPARC_JMP_SLOT:
591       break;
592     default:
593       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
594       break;
595     }
596 }
597
598 #endif  /* RESOLVE_MAP */