Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  SPARC version.
00002    Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef dl_machine_h
00022 #define dl_machine_h
00023 
00024 #define ELF_MACHINE_NAME "sparc"
00025 
00026 #include <string.h>
00027 #include <sys/param.h>
00028 #include <ldsodefs.h>
00029 #include <tls.h>
00030 
00031 #ifndef VALIDX
00032 # define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
00033                     + DT_EXTRANUM + DT_VALTAGIDX (tag))
00034 #endif
00035 
00036 /* Some SPARC opcodes we need to use for self-modifying code.  */
00037 #define OPCODE_NOP   0x01000000 /* nop */
00038 #define OPCODE_CALL  0x40000000 /* call ?; add PC-rel word address */
00039 #define OPCODE_SETHI_G1     0x03000000 /* sethi ?, %g1; add value>>10 */
00040 #define OPCODE_JMP_G1       0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
00041 #define OPCODE_SAVE_SP      0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
00042 #define OPCODE_BA    0x30800000 /* b,a ?; add PC-rel word address */
00043 
00044 /* Return nonzero iff ELF header is compatible with the running host.  */
00045 static inline int
00046 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00047 {
00048   if (ehdr->e_machine == EM_SPARC)
00049     return 1;
00050   else if (ehdr->e_machine == EM_SPARC32PLUS)
00051     {
00052       /* XXX The following is wrong!  Dave Miller rejected to implement it
00053         correctly.  If this causes problems shoot *him*!  */
00054 #ifdef SHARED
00055       return GLRO(dl_hwcap) & GLRO(dl_hwcap_mask) & HWCAP_SPARC_V9;
00056 #else
00057       return GLRO(dl_hwcap) & HWCAP_SPARC_V9;
00058 #endif
00059     }
00060   else
00061     return 0;
00062 }
00063 
00064 /* We have to do this because elf_machine_{dynamic,load_address} can be
00065    invoked from functions that have no GOT references, and thus the compiler
00066    has no obligation to load the PIC register.  */
00067 #define LOAD_PIC_REG(PIC_REG)      \
00068 do {   register Elf32_Addr pc __asm("o7"); \
00069        __asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
00070              "call 1f\n\t" \
00071              "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
00072              "1:\tadd %1, %0, %1" \
00073              : "=r" (pc), "=r" (PIC_REG)); \
00074 } while (0)
00075 
00076 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00077    first element of the GOT.  This must be inlined in a function which
00078    uses global data.  */
00079 static inline Elf32_Addr
00080 elf_machine_dynamic (void)
00081 {
00082   register Elf32_Addr *got asm ("%l7");
00083 
00084   LOAD_PIC_REG (got);
00085 
00086   return *got;
00087 }
00088 
00089 /* Return the run-time load address of the shared object.  */
00090 static inline Elf32_Addr
00091 elf_machine_load_address (void)
00092 {
00093   register Elf32_Addr *pc __asm ("%o7"), *got __asm ("%l7");
00094 
00095   __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
00096         "call 1f\n\t"
00097         " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
00098         "call _DYNAMIC\n\t"
00099         "call _GLOBAL_OFFSET_TABLE_\n"
00100         "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
00101 
00102   /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
00103      *got is _DYNAMIC
00104      pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
00105      pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12  */
00106   return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
00107 }
00108 
00109 /* Set up the loaded object described by L so its unrelocated PLT
00110    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00111 
00112 static inline int
00113 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00114 {
00115   Elf32_Addr *plt;
00116   extern void _dl_runtime_resolve (Elf32_Word);
00117   extern void _dl_runtime_profile (Elf32_Word);
00118 
00119   if (l->l_info[DT_JMPREL] && lazy)
00120     {
00121       Elf32_Addr rfunc;
00122 
00123       /* The entries for functions in the PLT have not yet been filled in.
00124         Their initial contents will arrange when called to set the high 22
00125         bits of %g1 with an offset into the .rela.plt section and jump to
00126         the beginning of the PLT.  */
00127       plt = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00128       if (__builtin_expect(profile, 0))
00129        {
00130          rfunc = (Elf32_Addr) &_dl_runtime_profile;
00131 
00132          if (GLRO(dl_profile) != NULL
00133              && _dl_name_match_p (GLRO(dl_profile), l))
00134            GL(dl_profile_map) = l;
00135        }
00136       else
00137        {
00138          rfunc = (Elf32_Addr) &_dl_runtime_resolve;
00139        }
00140 
00141       /* The beginning of the PLT does:
00142 
00143               sethi %hi(_dl_runtime_{resolve,profile}), %g2
00144         pltpc:       jmpl %g2 + %lo(_dl_runtime_{resolve,profile}), %g2
00145                nop
00146               .word MAP
00147 
00148          The PC value (pltpc) saved in %g2 by the jmpl points near the
00149         location where we store the link_map pointer for this object.  */
00150 
00151       plt[0] = 0x05000000 | ((rfunc >> 10) & 0x003fffff);
00152       plt[1] = 0x85c0a000 | (rfunc & 0x3ff);
00153       plt[2] = OPCODE_NOP;  /* Fill call delay slot.  */
00154       plt[3] = (Elf32_Addr) l;
00155       if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
00156          || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
00157        {
00158          /* Need to reinitialize .plt to undo prelinking.  */
00159          Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
00160          Elf32_Rela *relaend
00161            = (Elf32_Rela *) ((char *) rela
00162                            + l->l_info[DT_PLTRELSZ]->d_un.d_val);
00163 #if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
00164          /* Note that we don't mask the hwcap here, as the flush is
00165             essential to functionality on those cpu's that implement it.
00166             For sparcv9 we can assume flush is present.  */
00167          const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
00168 #else
00169          const int do_flush = 1;
00170 #endif
00171 
00172          /* prelink must ensure there are no R_SPARC_NONE relocs left
00173             in .rela.plt.  */
00174          while (rela < relaend)
00175            {
00176              *(unsigned int *) rela->r_offset
00177               = OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt);
00178              *(unsigned int *) (rela->r_offset + 4)
00179               = OPCODE_BA | ((((Elf32_Addr) plt
00180                              - rela->r_offset - 4) >> 2) & 0x3fffff);
00181              if (do_flush)
00182               {
00183                 __asm __volatile ("flush %0" : : "r"(rela->r_offset));
00184                 __asm __volatile ("flush %0+4" : : "r"(rela->r_offset));
00185               }
00186              ++rela;
00187            }
00188        }
00189     }
00190 
00191   return lazy;
00192 }
00193 
00194 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
00195    PLT entries should not be allowed to define the value.
00196    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00197    of the main executable's symbols, as for a COPY reloc.  */
00198 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00199 # define elf_machine_type_class(type) \
00200   ((((type) == R_SPARC_JMP_SLOT                                             \
00201      || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64))     \
00202     * ELF_RTYPE_CLASS_PLT)                                           \
00203    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
00204 #else
00205 # define elf_machine_type_class(type) \
00206   ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)                     \
00207    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
00208 #endif
00209 
00210 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00211 #define ELF_MACHINE_JMP_SLOT       R_SPARC_JMP_SLOT
00212 
00213 /* The SPARC never uses Elf32_Rel relocations.  */
00214 #define ELF_MACHINE_NO_REL 1
00215 
00216 /* The SPARC overlaps DT_RELA and DT_PLTREL.  */
00217 #define ELF_MACHINE_PLTREL_OVERLAP 1
00218 
00219 /* Undo the sub %sp, 6*4, %sp; add %sp, 22*4, %o0 below to get at the
00220    value we want in __libc_stack_end.  */
00221 #define DL_STACK_END(cookie) \
00222   ((void *) (((long) (cookie)) - (22 - 6) * 4))
00223 
00224 /* Initial entry point code for the dynamic linker.
00225    The C function `_dl_start' is the real entry point;
00226    its return value is the user program's entry point.  */
00227 
00228 #define RTLD_START __asm__ ("\
00229        .text\n\
00230        .globl _start\n\
00231        .type  _start, @function\n\
00232        .align 32\n\
00233 _start:\n\
00234   /* Allocate space for functions to drop their arguments.  */\n\
00235        sub    %sp, 6*4, %sp\n\
00236   /* Pass pointer to argument block to _dl_start.  */\n\
00237        call   _dl_start\n\
00238         add   %sp, 22*4, %o0\n\
00239        /* FALTHRU */\n\
00240        .globl _dl_start_user\n\
00241        .type  _dl_start_user, @function\n\
00242 _dl_start_user:\n\
00243   /* Load the PIC register.  */\n\
00244 1:     call   2f\n\
00245         sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
00246 2:     or     %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
00247        add    %l7, %o7, %l7\n\
00248   /* Save the user entry point address in %l0 */\n\
00249        mov    %o0, %l0\n\
00250   /* See if we were run as a command with the executable file name as an\n\
00251      extra leading argument.  If so, adjust the contents of the stack.  */\n\
00252        sethi  %hi(_dl_skip_args), %g2\n\
00253        or     %g2, %lo(_dl_skip_args), %g2\n\
00254        ld     [%l7+%g2], %i0\n\
00255        ld     [%i0], %i0\n\
00256        tst    %i0\n\
00257        beq    3f\n\
00258         ld    [%sp+22*4], %i5             /* load argc */\n\
00259        /* Find out how far to shift.  */\n\
00260        sethi  %hi(_dl_argv), %l3\n\
00261        or     %l3, %lo(_dl_argv), %l3\n\
00262        ld     [%l7+%l3], %l3\n\
00263        sub    %i5, %i0, %i5\n\
00264        ld     [%l3], %l4\n\
00265        sll    %i0, 2, %i2\n\
00266        st     %i5, [%sp+22*4]\n\
00267        sub    %l4, %i2, %l4\n\
00268        add    %sp, 23*4, %i1\n\
00269        add    %i1, %i2, %i2\n\
00270        st     %l4, [%l3]\n\
00271        /* Copy down argv */\n\
00272 21:    ld     [%i2], %i3\n\
00273        add    %i2, 4, %i2\n\
00274        tst    %i3\n\
00275        st     %i3, [%i1]\n\
00276        bne    21b\n\
00277         add   %i1, 4, %i1\n\
00278        /* Copy down env */\n\
00279 22:    ld     [%i2], %i3\n\
00280        add    %i2, 4, %i2\n\
00281        tst    %i3\n\
00282        st     %i3, [%i1]\n\
00283        bne    22b\n\
00284         add   %i1, 4, %i1\n\
00285        /* Copy down auxiliary table.  */\n\
00286 23:    ld     [%i2], %i3\n\
00287        ld     [%i2+4], %i4\n\
00288        add    %i2, 8, %i2\n\
00289        tst    %i3\n\
00290        st     %i3, [%i1]\n\
00291        st     %i4, [%i1+4]\n\
00292        bne    23b\n\
00293         add   %i1, 8, %i1\n\
00294   /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp.  */\n\
00295 3:     sethi  %hi(_rtld_local), %o0\n\
00296        add    %sp, 23*4, %o2\n\
00297        orcc   %o0, %lo(_rtld_local), %o0\n\
00298        sll    %i5, 2, %o3\n\
00299        ld     [%l7+%o0], %o0\n\
00300        add    %o3, 4, %o3\n\
00301        mov    %i5, %o1\n\
00302        add    %o2, %o3, %o3\n\
00303        call   _dl_init_internal\n\
00304         ld    [%o0], %o0\n\
00305   /* Pass our finalizer function to the user in %g1.  */\n\
00306        sethi  %hi(_dl_fini), %g1\n\
00307        or     %g1, %lo(_dl_fini), %g1\n\
00308        ld     [%l7+%g1], %g1\n\
00309   /* Jump to the user's entry point and deallocate the extra stack we got.  */\n\
00310        jmp    %l0\n\
00311         add   %sp, 6*4, %sp\n\
00312        .size   _dl_start_user, . - _dl_start_user\n\
00313        .previous");
00314 
00315 static inline __attribute__ ((always_inline)) Elf32_Addr
00316 sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
00317                Elf32_Addr value, int t, int do_flush)
00318 {
00319   Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
00320 
00321   if (0 && disp >= -0x800000 && disp < 0x800000)
00322     {
00323       /* Don't need to worry about thread safety. We're writing just one
00324         instruction.  */
00325 
00326       reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
00327       if (do_flush)
00328        __asm __volatile ("flush %0" : : "r"(reloc_addr));
00329     }
00330   else
00331     {
00332       /* For thread safety, write the instructions from the bottom and
00333         flush before we overwrite the critical "b,a".  This of course
00334         need not be done during bootstrapping, since there are no threads.
00335         But we also can't tell if we _can_ use flush, so don't. */
00336 
00337       reloc_addr += t;
00338       reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
00339       if (do_flush)
00340        __asm __volatile ("flush %0+4" : : "r"(reloc_addr));
00341 
00342       reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
00343       if (do_flush)
00344        __asm __volatile ("flush %0" : : "r"(reloc_addr));
00345     }
00346 
00347   return value;
00348 }
00349 
00350 static inline Elf32_Addr
00351 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00352                      const Elf32_Rela *reloc,
00353                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00354 {
00355 #ifdef __sparc_v9__
00356   /* Sparc v9 can assume flush is always present.  */
00357   const int do_flush = 1;
00358 #else
00359   /* Note that we don't mask the hwcap here, as the flush is essential to
00360      functionality on those cpu's that implement it.  */
00361   const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
00362 #endif
00363   return sparc_fixup_plt (reloc, reloc_addr, value, 1, do_flush);
00364 }
00365 
00366 /* Return the final value of a plt relocation.  */
00367 static inline Elf32_Addr
00368 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
00369                      Elf32_Addr value)
00370 {
00371   return value + reloc->r_addend;
00372 }
00373 
00374 #endif /* dl_machine_h */
00375 
00376 #define ARCH_LA_PLTENTER    sparc32_gnu_pltenter
00377 #define ARCH_LA_PLTEXIT            sparc32_gnu_pltexit
00378 
00379 #ifdef RESOLVE_MAP
00380 
00381 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00382    MAP is the object containing the reloc.  */
00383 
00384 auto inline void
00385 __attribute__ ((always_inline))
00386 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00387                 const Elf32_Sym *sym, const struct r_found_version *version,
00388                 void *const reloc_addr_arg)
00389 {
00390   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00391   const Elf32_Sym *const refsym = sym;
00392   Elf32_Addr value;
00393   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00394   struct link_map *sym_map = NULL;
00395 
00396 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00397   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
00398      reference weak so static programs can still link.  This declaration
00399      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
00400      because rtld.c contains the common defn for _dl_rtld_map, which is
00401      incompatible with a weak decl in the same file.  */
00402   weak_extern (_dl_rtld_map);
00403 #endif
00404 
00405   if (__builtin_expect (r_type == R_SPARC_NONE, 0))
00406     return;
00407 
00408 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
00409   if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0))
00410     {
00411 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00412       if (map != &_dl_rtld_map) /* Already done in rtld itself. */
00413 # endif
00414        *reloc_addr += map->l_addr + reloc->r_addend;
00415       return;
00416     }
00417 #endif
00418 
00419 #ifndef RESOLVE_CONFLICT_FIND_MAP
00420   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
00421       && sym->st_shndx != SHN_UNDEF)
00422     {
00423       value = map->l_addr;
00424     }
00425   else
00426     {
00427       sym_map = RESOLVE_MAP (&sym, version, r_type);
00428       value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00429     }
00430 #else
00431   value = 0;
00432 #endif
00433 
00434   value += reloc->r_addend; /* Assume copy relocs have zero addend.  */
00435 
00436   switch (r_type)
00437     {
00438 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
00439     case R_SPARC_COPY:
00440       if (sym == NULL)
00441        /* This can happen in trace mode if an object could not be
00442           found.  */
00443        break;
00444       if (sym->st_size > refsym->st_size
00445          || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
00446        {
00447          const char *strtab;
00448 
00449          strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00450          _dl_error_printf ("\
00451 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00452                          rtld_progname ?: "<program name unknown>",
00453                          strtab + refsym->st_name);
00454        }
00455       memcpy (reloc_addr_arg, (void *) value,
00456              MIN (sym->st_size, refsym->st_size));
00457       break;
00458 #endif
00459     case R_SPARC_GLOB_DAT:
00460     case R_SPARC_32:
00461       *reloc_addr = value;
00462       break;
00463     case R_SPARC_JMP_SLOT:
00464       {
00465 #if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
00466        /* Note that we don't mask the hwcap here, as the flush is
00467           essential to functionality on those cpu's that implement
00468           it.  For sparcv9 we can assume flush is present.  */
00469        const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
00470 #else
00471        /* Unfortunately, this is necessary, so that we can ensure
00472           ld.so will not execute corrupt PLT entry instructions. */
00473        const int do_flush = 1;
00474 #endif
00475        /* At this point we don't need to bother with thread safety,
00476           so we can optimize the first instruction of .plt out.  */
00477        sparc_fixup_plt (reloc, reloc_addr, value, 0, do_flush);
00478       }
00479       break;
00480 #if (!defined RTLD_BOOTSTRAP || USE___THREAD) \
00481     && !defined RESOLVE_CONFLICT_FIND_MAP
00482     case R_SPARC_TLS_DTPMOD32:
00483       /* Get the information from the link map returned by the
00484         resolv function.  */
00485       if (sym_map != NULL)
00486        *reloc_addr = sym_map->l_tls_modid;
00487       break;
00488     case R_SPARC_TLS_DTPOFF32:
00489       /* During relocation all TLS symbols are defined and used.
00490         Therefore the offset is already correct.  */
00491       *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
00492       break;
00493     case R_SPARC_TLS_TPOFF32:
00494       /* The offset is negative, forward from the thread pointer.  */
00495       /* We know the offset of object the symbol is contained in.
00496         It is a negative value which will be added to the
00497         thread pointer.  */
00498       if (sym != NULL)
00499        {
00500          CHECK_STATIC_TLS (map, sym_map);
00501          *reloc_addr = sym->st_value - sym_map->l_tls_offset
00502            + reloc->r_addend;
00503        }
00504       break;
00505 # ifndef RTLD_BOOTSTRAP
00506     case R_SPARC_TLS_LE_HIX22:
00507     case R_SPARC_TLS_LE_LOX10:
00508       if (sym != NULL)
00509        {
00510          CHECK_STATIC_TLS (map, sym_map);
00511          value = sym->st_value - sym_map->l_tls_offset
00512            + reloc->r_addend;
00513          if (r_type == R_SPARC_TLS_LE_HIX22)
00514            *reloc_addr = (*reloc_addr & 0xffc00000) | ((~value) >> 10);
00515          else
00516            *reloc_addr = (*reloc_addr & 0xffffe000) | (value & 0x3ff)
00517              | 0x1c00;
00518        }
00519       break;
00520 # endif
00521 #endif
00522 #ifndef RTLD_BOOTSTRAP
00523     case R_SPARC_8:
00524       *(char *) reloc_addr = value;
00525       break;
00526     case R_SPARC_16:
00527       *(short *) reloc_addr = value;
00528       break;
00529     case R_SPARC_DISP8:
00530       *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
00531       break;
00532     case R_SPARC_DISP16:
00533       *(short *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
00534       break;
00535     case R_SPARC_DISP32:
00536       *reloc_addr = (value - (Elf32_Addr) reloc_addr);
00537       break;
00538     case R_SPARC_LO10:
00539       *reloc_addr = (*reloc_addr & ~0x3ff) | (value & 0x3ff);
00540       break;
00541     case R_SPARC_WDISP30:
00542       *reloc_addr = ((*reloc_addr & 0xc0000000)
00543                    | ((value - (unsigned int) reloc_addr) >> 2));
00544       break;
00545     case R_SPARC_HI22:
00546       *reloc_addr = (*reloc_addr & 0xffc00000) | (value >> 10);
00547       break;
00548     case R_SPARC_UA16:
00549       ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
00550       ((unsigned char *) reloc_addr_arg) [1] = value;
00551       break;
00552     case R_SPARC_UA32:
00553       ((unsigned char *) reloc_addr_arg) [0] = value >> 24;
00554       ((unsigned char *) reloc_addr_arg) [1] = value >> 16;
00555       ((unsigned char *) reloc_addr_arg) [2] = value >> 8;
00556       ((unsigned char *) reloc_addr_arg) [3] = value;
00557       break;
00558 #endif
00559 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
00560     default:
00561       _dl_reloc_bad_type (map, r_type, 0);
00562       break;
00563 #endif
00564     }
00565 }
00566 
00567 auto inline void
00568 __attribute__ ((always_inline))
00569 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00570                         void *const reloc_addr_arg)
00571 {
00572   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00573   *reloc_addr += l_addr + reloc->r_addend;
00574 }
00575 
00576 auto inline void
00577 __attribute__ ((always_inline))
00578 elf_machine_lazy_rel (struct link_map *map,
00579                     Elf32_Addr l_addr, const Elf32_Rela *reloc)
00580 {
00581   switch (ELF32_R_TYPE (reloc->r_info))
00582     {
00583     case R_SPARC_NONE:
00584       break;
00585     case R_SPARC_JMP_SLOT:
00586       break;
00587     default:
00588       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
00589       break;
00590     }
00591 }
00592 
00593 #endif /* RESOLVE_MAP */