Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  Sparc64 version.
00002    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
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 "sparc64"
00025 
00026 #include <string.h>
00027 #include <sys/param.h>
00028 #include <ldsodefs.h>
00029 #include <sysdep.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 #define ELF64_R_TYPE_ID(info)      ((info) & 0xff)
00037 #define ELF64_R_TYPE_DATA(info) ((info) >> 8)
00038 
00039 /* Return nonzero iff ELF header is compatible with the running host.  */
00040 static inline int
00041 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
00042 {
00043   return ehdr->e_machine == EM_SPARCV9;
00044 }
00045 
00046 /* We have to do this because elf_machine_{dynamic,load_address} can be
00047    invoked from functions that have no GOT references, and thus the compiler
00048    has no obligation to load the PIC register.  */
00049 #define LOAD_PIC_REG(PIC_REG)      \
00050 do {   Elf64_Addr tmp;             \
00051        __asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
00052              "rd %%pc, %0\n\t" \
00053              "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \
00054              "add %0, %1, %0" \
00055              : "=r" (PIC_REG), "=r" (tmp)); \
00056 } while (0)
00057 
00058 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00059    first element of the GOT.  This must be inlined in a function which
00060    uses global data.  */
00061 static inline Elf64_Addr
00062 elf_machine_dynamic (void)
00063 {
00064   register Elf64_Addr *elf_pic_register __asm__("%l7");
00065 
00066   LOAD_PIC_REG (elf_pic_register);
00067 
00068   return *elf_pic_register;
00069 }
00070 
00071 /* Return the run-time load address of the shared object.  */
00072 static inline Elf64_Addr
00073 elf_machine_load_address (void)
00074 {
00075   register Elf32_Addr *pc __asm ("%o7");
00076   register Elf64_Addr *got __asm ("%l7");
00077 
00078   __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
00079          "call 1f\n\t"
00080          " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
00081          "call _DYNAMIC\n\t"
00082          "call _GLOBAL_OFFSET_TABLE_\n"
00083          "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
00084 
00085   /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
00086      *got is _DYNAMIC
00087      pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
00088      pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12  */
00089   return (Elf64_Addr) got - *got + (Elf32_Sword) ((pc[2] - pc[3]) * 4) - 4;
00090 }
00091 
00092 /* We have 4 cases to handle.  And we code different code sequences
00093    for each one.  I love V9 code models...  */
00094 static inline void __attribute__ ((always_inline))
00095 sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc,
00096                  Elf64_Addr *reloc_addr, Elf64_Addr value,
00097                  Elf64_Addr high, int t)
00098 {
00099   unsigned int *insns = (unsigned int *) reloc_addr;
00100   Elf64_Addr plt_vaddr = (Elf64_Addr) reloc_addr;
00101   Elf64_Sxword disp = value - plt_vaddr;
00102 
00103   /* Now move plt_vaddr up to the call instruction.  */
00104   plt_vaddr += ((t + 1) * 4);
00105 
00106   /* PLT entries .PLT32768 and above look always the same.  */
00107   if (__builtin_expect (high, 0) != 0)
00108     {
00109       *reloc_addr = value - map->l_addr;
00110     }
00111   /* Near destination.  */
00112   else if (disp >= -0x800000 && disp < 0x800000)
00113     {
00114       /* As this is just one instruction, it is thread safe and so
00115         we can avoid the unnecessary sethi FOO, %g1.
00116         b,a target  */
00117       insns[0] = 0x30800000 | ((disp >> 2) & 0x3fffff);
00118       __asm __volatile ("flush %0" : : "r" (insns));
00119     }
00120   /* 32-bit Sparc style, the target is in the lower 32-bits of
00121      address space.  */
00122   else if (insns += t, (value >> 32) == 0)
00123     {
00124       /* sethi       %hi(target), %g1
00125         jmpl  %g1 + %lo(target), %g0  */
00126 
00127       insns[1] = 0x81c06000 | (value & 0x3ff);
00128       __asm __volatile ("flush %0 + 4" : : "r" (insns));
00129 
00130       insns[0] = 0x03000000 | ((unsigned int)(value >> 10));
00131       __asm __volatile ("flush %0" : : "r" (insns));
00132     }
00133   /* We can also get somewhat simple sequences if the distance between
00134      the target and the PLT entry is within +/- 2GB.  */
00135   else if ((plt_vaddr > value
00136            && ((plt_vaddr - value) >> 31) == 0)
00137           || (value > plt_vaddr
00138               && ((value - plt_vaddr) >> 31) == 0))
00139     {
00140       unsigned int displacement;
00141 
00142       if (plt_vaddr > value)
00143        displacement = (0 - (plt_vaddr - value));
00144       else
00145        displacement = value - plt_vaddr;
00146 
00147       /* mov  %o7, %g1
00148         call  displacement
00149          mov  %g1, %o7  */
00150 
00151       insns[2] = 0x9e100001;
00152       __asm __volatile ("flush %0 + 8" : : "r" (insns));
00153 
00154       insns[1] = 0x40000000 | (displacement >> 2);
00155       __asm __volatile ("flush %0 + 4" : : "r" (insns));
00156 
00157       insns[0] = 0x8210000f;
00158       __asm __volatile ("flush %0" : : "r" (insns));
00159     }
00160   /* Worst case, ho hum...  */
00161   else
00162     {
00163       unsigned int high32 = (value >> 32);
00164       unsigned int low32 = (unsigned int) value;
00165 
00166       /* ??? Some tricks can be stolen from the sparc64 egcs backend
00167             constant formation code I wrote.  -DaveM  */
00168 
00169       if (__builtin_expect (high32 & 0x3ff, 0))
00170        {
00171          /* sethi    %hh(value), %g1
00172             sethi    %lm(value), %g5
00173             or              %g1, %hm(value), %g1
00174             or              %g5, %lo(value), %g5
00175             sllx     %g1, 32, %g1
00176             jmpl     %g1 + %g5, %g0
00177              nop  */
00178 
00179          insns[5] = 0x81c04005;
00180          __asm __volatile ("flush %0 + 20" : : "r" (insns));
00181 
00182          insns[4] = 0x83287020;
00183          __asm __volatile ("flush %0 + 16" : : "r" (insns));
00184 
00185          insns[3] = 0x8a116000 | (low32 & 0x3ff);
00186          __asm __volatile ("flush %0 + 12" : : "r" (insns));
00187 
00188          insns[2] = 0x82106000 | (high32 & 0x3ff);
00189        }
00190       else
00191        {
00192          /* sethi    %hh(value), %g1
00193             sethi    %lm(value), %g5
00194             sllx     %g1, 32, %g1
00195             or              %g5, %lo(value), %g5
00196             jmpl     %g1 + %g5, %g0
00197              nop  */
00198 
00199          insns[4] = 0x81c04005;
00200          __asm __volatile ("flush %0 + 16" : : "r" (insns));
00201 
00202          insns[3] = 0x8a116000 | (low32 & 0x3ff);
00203          __asm __volatile ("flush %0 + 12" : : "r" (insns));
00204 
00205          insns[2] = 0x83287020;
00206        }
00207 
00208       __asm __volatile ("flush %0 + 8" : : "r" (insns));
00209 
00210       insns[1] = 0x0b000000 | (low32 >> 10);
00211       __asm __volatile ("flush %0 + 4" : : "r" (insns));
00212 
00213       insns[0] = 0x03000000 | (high32 >> 10);
00214       __asm __volatile ("flush %0" : : "r" (insns));
00215     }
00216 }
00217 
00218 static inline Elf64_Addr __attribute__ ((always_inline))
00219 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00220                      const Elf64_Rela *reloc,
00221                      Elf64_Addr *reloc_addr, Elf64_Addr value)
00222 {
00223   sparc64_fixup_plt (map, reloc, reloc_addr, value + reloc->r_addend,
00224                    reloc->r_addend, 1);
00225   return value;
00226 }
00227 
00228 /* Return the final value of a plt relocation.  */
00229 static inline Elf64_Addr
00230 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
00231                      Elf64_Addr value)
00232 {
00233   /* Don't add addend here, but in elf_machine_fixup_plt instead.
00234      value + reloc->r_addend is the value which should actually be
00235      stored into .plt data slot.  */
00236   return value;
00237 }
00238 
00239 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
00240    PLT entries should not be allowed to define the value.
00241    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00242    of the main executable's symbols, as for a COPY reloc.  */
00243 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00244 # define elf_machine_type_class(type) \
00245   ((((type) == R_SPARC_JMP_SLOT                                             \
00246      || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64))     \
00247     * ELF_RTYPE_CLASS_PLT)                                           \
00248    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
00249 #else
00250 # define elf_machine_type_class(type) \
00251   ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
00252    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
00253 #endif
00254 
00255 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00256 #define ELF_MACHINE_JMP_SLOT       R_SPARC_JMP_SLOT
00257 
00258 /* The SPARC never uses Elf64_Rel relocations.  */
00259 #define ELF_MACHINE_NO_REL 1
00260 
00261 /* The SPARC overlaps DT_RELA and DT_PLTREL.  */
00262 #define ELF_MACHINE_PLTREL_OVERLAP 1
00263 
00264 /* Set up the loaded object described by L so its unrelocated PLT
00265    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00266 
00267 static inline int
00268 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00269 {
00270   if (l->l_info[DT_JMPREL] && lazy)
00271     {
00272       extern void _dl_runtime_resolve_0 (void);
00273       extern void _dl_runtime_resolve_1 (void);
00274       extern void _dl_runtime_profile_0 (void);
00275       extern void _dl_runtime_profile_1 (void);
00276       Elf64_Addr res0_addr, res1_addr;
00277       unsigned int *plt = (void *) D_PTR (l, l_info[DT_PLTGOT]);
00278 
00279       if (__builtin_expect(profile, 0))
00280        {
00281          res0_addr = (Elf64_Addr) &_dl_runtime_profile_0;
00282          res1_addr = (Elf64_Addr) &_dl_runtime_profile_1;
00283 
00284          if (GLRO(dl_profile) != NULL
00285              && _dl_name_match_p (GLRO(dl_profile), l))
00286            GL(dl_profile_map) = l;
00287        }
00288       else
00289        {
00290          res0_addr = (Elf64_Addr) &_dl_runtime_resolve_0;
00291          res1_addr = (Elf64_Addr) &_dl_runtime_resolve_1;
00292        }
00293 
00294       /* PLT0 looks like:
00295 
00296          sethi       %uhi(_dl_runtime_{resolve,profile}_0), %g4
00297         sethi %hi(_dl_runtime_{resolve,profile}_0), %g5
00298         or    %g4, %ulo(_dl_runtime_{resolve,profile}_0), %g4
00299         or    %g5, %lo(_dl_runtime_{resolve,profile}_0), %g5
00300         sllx  %g4, 32, %g4
00301         add   %g4, %g5, %g5
00302         jmpl  %g5, %g4
00303          nop
00304        */
00305 
00306       plt[0] = 0x09000000 | (res0_addr >> (64 - 22));
00307       plt[1] = 0x0b000000 | ((res0_addr >> 10) & 0x003fffff);
00308       plt[2] = 0x88112000 | ((res0_addr >> 32) & 0x3ff);
00309       plt[3] = 0x8a116000 | (res0_addr & 0x3ff);
00310       plt[4] = 0x89293020;
00311       plt[5] = 0x8a010005;
00312       plt[6] = 0x89c14000;
00313       plt[7] = 0x01000000;
00314 
00315       /* PLT1 looks like:
00316 
00317          sethi       %uhi(_dl_runtime_{resolve,profile}_1), %g4
00318         sethi %hi(_dl_runtime_{resolve,profile}_1), %g5
00319         or    %g4, %ulo(_dl_runtime_{resolve,profile}_1), %g4
00320         or    %g5, %lo(_dl_runtime_{resolve,profile}_1), %g5
00321         sllx  %g4, 32, %g4
00322         add   %g4, %g5, %g5
00323         jmpl  %g5, %g4
00324          nop
00325        */
00326 
00327       plt[8] = 0x09000000 | (res1_addr >> (64 - 22));
00328       plt[9] = 0x0b000000 | ((res1_addr >> 10) & 0x003fffff);
00329       plt[10] = 0x88112000 | ((res1_addr >> 32) & 0x3ff);
00330       plt[11] = 0x8a116000 | (res1_addr & 0x3ff);
00331       plt[12] = 0x89293020;
00332       plt[13] = 0x8a010005;
00333       plt[14] = 0x89c14000;
00334       plt[15] = 0x01000000;
00335 
00336       /* Now put the magic cookie at the beginning of .PLT2
00337         Entry .PLT3 is unused by this implementation.  */
00338       *((struct link_map **)(&plt[16])) = l;
00339 
00340       if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
00341          || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
00342        {
00343          /* Need to reinitialize .plt to undo prelinking.  */
00344          Elf64_Rela *rela = (Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]);
00345          Elf64_Rela *relaend
00346            = (Elf64_Rela *) ((char *) rela
00347                            + l->l_info[DT_PLTRELSZ]->d_un.d_val);
00348 
00349          /* prelink must ensure there are no R_SPARC_NONE relocs left
00350             in .rela.plt.  */
00351          while (rela < relaend)
00352            {
00353              if (__builtin_expect (rela->r_addend, 0) != 0)
00354               {
00355                   Elf64_Addr slot = ((rela->r_offset + 0x400
00356                                   - (Elf64_Addr) plt)
00357                                  / 0x1400) * 0x1400
00358                                 + (Elf64_Addr) plt - 0x400;
00359                 /* ldx [%o7 + X], %g1  */
00360                 unsigned int first_ldx = *(unsigned int *)(slot + 12);
00361                 Elf64_Addr ptr = slot + (first_ldx & 0xfff) + 4;
00362 
00363                 *(Elf64_Addr *) rela->r_offset
00364                   = (Elf64_Addr) plt
00365                     - (slot + ((rela->r_offset - ptr) / 8) * 24 + 4);
00366                 ++rela;
00367                 continue;
00368               }
00369 
00370              *(unsigned int *) rela->r_offset
00371               = 0x03000000 | (rela->r_offset - (Elf64_Addr) plt);
00372              *(unsigned int *) (rela->r_offset + 4)
00373               = 0x30680000 | ((((Elf64_Addr) plt + 32
00374                               - rela->r_offset - 4) >> 2) & 0x7ffff);
00375              __asm __volatile ("flush %0" : : "r" (rela->r_offset));
00376              __asm __volatile ("flush %0+4" : : "r" (rela->r_offset));
00377              ++rela;
00378            }
00379        }
00380     }
00381 
00382   return lazy;
00383 }
00384 
00385 /* The PLT uses Elf64_Rela relocs.  */
00386 #define elf_machine_relplt elf_machine_rela
00387 
00388 /* Undo the sub %sp, 6*8, %sp; add %sp, STACK_BIAS + 22*8, %o0 below
00389    to get at the value we want in __libc_stack_end.  */
00390 #define DL_STACK_END(cookie) \
00391   ((void *) (((long) (cookie)) - (22 - 6) * 8 - STACK_BIAS))
00392 
00393 /* Initial entry point code for the dynamic linker.
00394    The C function `_dl_start' is the real entry point;
00395    its return value is the user program's entry point.  */
00396 
00397 #define __S1(x)      #x
00398 #define __S(x)       __S1(x)
00399 
00400 #define RTLD_START __asm__ ( "\n"                              \
00401 "      .text\n"                                                \
00402 "      .global       _start\n"                                        \
00403 "      .type  _start, @function\n"                             \
00404 "      .align 32\n"                                            \
00405 "_start:\n"                                                    \
00406 "   /* Make room for functions to drop their arguments on the stack.  */\n" \
00407 "      sub    %sp, 6*8, %sp\n"                                 \
00408 "   /* Pass pointer to argument block to _dl_start.  */\n"            \
00409 "      call   _dl_start\n"                                     \
00410 "       add    %sp," __S(STACK_BIAS) "+22*8,%o0\n"                    \
00411 "      /* FALLTHRU */\n"                                       \
00412 "      .size _start, .-_start\n"                               \
00413 "\n"                                                           \
00414 "      .global       _dl_start_user\n"                                \
00415 "      .type  _dl_start_user, @function\n"                            \
00416 "_dl_start_user:\n"                                            \
00417 "   /* Load the GOT register.  */\n"                                  \
00418 "1:    call   11f\n"                                           \
00419 "       sethi %hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n"        \
00420 "11:   or     %l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n"          \
00421 "      sethi  %hi(_dl_skip_args), %g5\n"                       \
00422 "      add    %l7, %o7, %l7\n"                                 \
00423 "      or     %g5, %lo(_dl_skip_args), %g5\n"                         \
00424 "   /* Save the user entry point address in %l0.  */\n"               \
00425 "      mov    %o0, %l0\n"                                      \
00426 "   /* See if we were run as a command with the executable file name as an\n" \
00427 "      extra leading argument.  If so, we must shift things around since we\n" \
00428 "      must keep the stack doubleword aligned.  */\n"                 \
00429 "      ldx    [%l7 + %g5], %i0\n"                              \
00430 "      ld     [%i0], %i0\n"                                    \
00431 "      brz,pt %i0, 2f\n"                                       \
00432 "       ldx   [%sp + " __S(STACK_BIAS) " + 22*8], %i5\n"              \
00433 "      /* Find out how far to shift.  */\n"                           \
00434 "      sethi  %hi(_dl_argv), %l4\n"                                   \
00435 "      sub    %i5, %i0, %i5\n"                                 \
00436 "      or     %l4, %lo(_dl_argv), %l4\n"                       \
00437 "      sllx   %i0, 3, %l6\n"                                          \
00438 "      ldx    [%l7 + %l4], %l4\n"                              \
00439 "      stx    %i5, [%sp + " __S(STACK_BIAS) " + 22*8]\n"              \
00440 "      add    %sp, " __S(STACK_BIAS) " + 23*8, %i1\n"                 \
00441 "      add    %i1, %l6, %i2\n"                                 \
00442 "      ldx    [%l4], %l5\n"                                    \
00443 "      /* Copy down argv.  */\n"                               \
00444 "12:   ldx    [%i2], %i3\n"                                    \
00445 "      add    %i2, 8, %i2\n"                                          \
00446 "      stx    %i3, [%i1]\n"                                    \
00447 "      brnz,pt       %i3, 12b\n"                                      \
00448 "       add   %i1, 8, %i1\n"                                          \
00449 "      sub    %l5, %l6, %l5\n"                                 \
00450 "      /* Copy down envp.  */\n"                               \
00451 "13:   ldx    [%i2], %i3\n"                                    \
00452 "      add    %i2, 8, %i2\n"                                          \
00453 "      stx    %i3, [%i1]\n"                                    \
00454 "      brnz,pt       %i3, 13b\n"                                      \
00455 "       add   %i1, 8, %i1\n"                                          \
00456 "      /* Copy down auxiliary table.  */\n"                           \
00457 "14:   ldx    [%i2], %i3\n"                                    \
00458 "      ldx    [%i2 + 8], %i4\n"                                \
00459 "      add    %i2, 16, %i2\n"                                         \
00460 "      stx    %i3, [%i1]\n"                                    \
00461 "      stx    %i4, [%i1 + 8]\n"                                \
00462 "      brnz,pt       %i3, 14b\n"                                      \
00463 "       add   %i1, 16, %i1\n"                                         \
00464 "      stx    %l5, [%l4]\n"                                    \
00465 "  /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp.  */\n"    \
00466 "2:    sethi  %hi(_rtld_local), %o0\n"                         \
00467 "      add    %sp, " __S(STACK_BIAS) " + 23*8, %o2\n"                 \
00468 "      orcc   %o0, %lo(_rtld_local), %o0\n"                           \
00469 "      sllx   %i5, 3, %o3\n"                                          \
00470 "      ldx    [%l7 + %o0], %o0\n"                              \
00471 "      add    %o3, 8, %o3\n"                                          \
00472 "      mov    %i5, %o1\n"                                      \
00473 "      add    %o2, %o3, %o3\n"                                 \
00474 "      call   _dl_init_internal\n"                             \
00475 "       ldx   [%o0], %o0\n"                                    \
00476 "   /* Pass our finalizer function to the user in %g1.  */\n"         \
00477 "      sethi  %hi(_dl_fini), %g1\n"                                   \
00478 "      or     %g1, %lo(_dl_fini), %g1\n"                       \
00479 "      ldx    [%l7 + %g1], %g1\n"                              \
00480 "  /* Jump to the user's entry point and deallocate the extra stack we got.  */\n" \
00481 "      jmp    %l0\n"                                           \
00482 "       add   %sp, 6*8, %sp\n"                                 \
00483 "      .size  _dl_start_user, . - _dl_start_user\n"                   \
00484 "      .previous\n");
00485 
00486 #endif /* dl_machine_h */
00487 
00488 #define ARCH_LA_PLTENTER    sparc64_gnu_pltenter
00489 #define ARCH_LA_PLTEXIT            sparc64_gnu_pltexit
00490 
00491 #ifdef RESOLVE_MAP
00492 
00493 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00494    MAP is the object containing the reloc.  */
00495 
00496 auto inline void
00497 __attribute__ ((always_inline))
00498 elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
00499                 const Elf64_Sym *sym, const struct r_found_version *version,
00500                 void *const reloc_addr_arg)
00501 {
00502   Elf64_Addr *const reloc_addr = reloc_addr_arg;
00503 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
00504   const Elf64_Sym *const refsym = sym;
00505 #endif
00506   Elf64_Addr value;
00507   const unsigned long int r_type = ELF64_R_TYPE_ID (reloc->r_info);
00508 #if !defined RESOLVE_CONFLICT_FIND_MAP
00509   struct link_map *sym_map = NULL;
00510 #endif
00511 
00512 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00513   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
00514      reference weak so static programs can still link.  This declaration
00515      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
00516      because rtld.c contains the common defn for _dl_rtld_map, which is
00517      incompatible with a weak decl in the same file.  */
00518   weak_extern (_dl_rtld_map);
00519 #endif
00520 
00521   if (__builtin_expect (r_type == R_SPARC_NONE, 0))
00522     return;
00523 
00524 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
00525   if (__builtin_expect (r_type == R_SPARC_RELATIVE, 0))
00526     {
00527 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00528       if (map != &_dl_rtld_map) /* Already done in rtld itself. */
00529 # endif
00530        *reloc_addr += map->l_addr + reloc->r_addend;
00531       return;
00532     }
00533 #endif
00534 
00535 #ifndef RESOLVE_CONFLICT_FIND_MAP
00536   if (__builtin_expect (ELF64_ST_BIND (sym->st_info) == STB_LOCAL, 0)
00537       && sym->st_shndx != SHN_UNDEF)
00538     {
00539       value = map->l_addr;
00540     }
00541   else
00542     {
00543       sym_map = RESOLVE_MAP (&sym, version, r_type);
00544       value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00545     }
00546 #else
00547   value = 0;
00548 #endif
00549 
00550   value += reloc->r_addend; /* Assume copy relocs have zero addend.  */
00551 
00552   switch (r_type)
00553     {
00554 #if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
00555     case R_SPARC_COPY:
00556       if (sym == NULL)
00557        /* This can happen in trace mode if an object could not be
00558           found.  */
00559        break;
00560       if (sym->st_size > refsym->st_size
00561          || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
00562        {
00563          const char *strtab;
00564 
00565          strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00566          _dl_error_printf ("\
00567 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00568                          rtld_progname ?: "<program name unknown>",
00569                          strtab + refsym->st_name);
00570        }
00571       memcpy (reloc_addr_arg, (void *) value,
00572              MIN (sym->st_size, refsym->st_size));
00573       break;
00574 #endif
00575     case R_SPARC_64:
00576     case R_SPARC_GLOB_DAT:
00577       *reloc_addr = value;
00578       break;
00579     case R_SPARC_JMP_SLOT:
00580 #ifdef RESOLVE_CONFLICT_FIND_MAP
00581       /* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
00582         relocs should be turned into R_SPARC_64 relocs
00583         in .gnu.conflict section.
00584         r_addend non-zero does not mean it is a .plt[32768+]
00585         reloc, instead it is the actual address of the function
00586         to call.  */
00587       sparc64_fixup_plt (NULL, reloc, reloc_addr, value, 0, 0);
00588 #else
00589       sparc64_fixup_plt (map, reloc, reloc_addr, value, reloc->r_addend, 0);
00590 #endif
00591       break;
00592 #if (!defined RTLD_BOOTSTRAP || USE___THREAD) \
00593     && !defined RESOLVE_CONFLICT_FIND_MAP
00594     case R_SPARC_TLS_DTPMOD64:
00595       /* Get the information from the link map returned by the
00596         resolv function.  */
00597       if (sym_map != NULL)
00598        *reloc_addr = sym_map->l_tls_modid;
00599       break;
00600     case R_SPARC_TLS_DTPOFF64:
00601       /* During relocation all TLS symbols are defined and used.
00602         Therefore the offset is already correct.  */
00603       *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
00604       break;
00605     case R_SPARC_TLS_TPOFF64:
00606       /* The offset is negative, forward from the thread pointer.  */
00607       /* We know the offset of object the symbol is contained in.
00608         It is a negative value which will be added to the
00609         thread pointer.  */
00610       if (sym != NULL)
00611        {
00612          CHECK_STATIC_TLS (map, sym_map);
00613          *reloc_addr = sym->st_value - sym_map->l_tls_offset
00614            + reloc->r_addend;
00615        }
00616       break;
00617 # ifndef RTLD_BOOTSTRAP
00618     case R_SPARC_TLS_LE_HIX22:
00619     case R_SPARC_TLS_LE_LOX10:
00620       if (sym != NULL)
00621        {
00622          CHECK_STATIC_TLS (map, sym_map);
00623          value = sym->st_value - sym_map->l_tls_offset
00624            + reloc->r_addend;
00625          if (r_type == R_SPARC_TLS_LE_HIX22)
00626            *reloc_addr = (*reloc_addr & 0xffc00000)
00627              | (((~value) >> 10) & 0x3fffff);
00628          else
00629            *reloc_addr = (*reloc_addr & 0xffffe000) | (value & 0x3ff)
00630              | 0x1c00;
00631        }
00632       break;
00633 # endif
00634 #endif
00635 #ifndef RTLD_BOOTSTRAP
00636     case R_SPARC_8:
00637       *(char *) reloc_addr = value;
00638       break;
00639     case R_SPARC_16:
00640       *(short *) reloc_addr = value;
00641       break;
00642     case R_SPARC_32:
00643       *(unsigned int *) reloc_addr = value;
00644       break;
00645     case R_SPARC_DISP8:
00646       *(char *) reloc_addr = (value - (Elf64_Addr) reloc_addr);
00647       break;
00648     case R_SPARC_DISP16:
00649       *(short *) reloc_addr = (value - (Elf64_Addr) reloc_addr);
00650       break;
00651     case R_SPARC_DISP32:
00652       *(unsigned int *) reloc_addr = (value - (Elf64_Addr) reloc_addr);
00653       break;
00654     case R_SPARC_WDISP30:
00655       *(unsigned int *) reloc_addr =
00656        ((*(unsigned int *)reloc_addr & 0xc0000000) |
00657         (((value - (Elf64_Addr) reloc_addr) >> 2) & 0x3fffffff));
00658       break;
00659 
00660       /* MEDLOW code model relocs */
00661     case R_SPARC_LO10:
00662       *(unsigned int *) reloc_addr =
00663        ((*(unsigned int *)reloc_addr & ~0x3ff) |
00664         (value & 0x3ff));
00665       break;
00666     case R_SPARC_HI22:
00667       *(unsigned int *) reloc_addr =
00668        ((*(unsigned int *)reloc_addr & 0xffc00000) |
00669         ((value >> 10) & 0x3fffff));
00670       break;
00671     case R_SPARC_OLO10:
00672       *(unsigned int *) reloc_addr =
00673        ((*(unsigned int *)reloc_addr & ~0x1fff) |
00674         (((value & 0x3ff) + ELF64_R_TYPE_DATA (reloc->r_info)) & 0x1fff));
00675       break;
00676 
00677       /* MEDMID code model relocs */
00678     case R_SPARC_H44:
00679       *(unsigned int *) reloc_addr =
00680        ((*(unsigned int *)reloc_addr & 0xffc00000) |
00681         ((value >> 22) & 0x3fffff));
00682       break;
00683     case R_SPARC_M44:
00684       *(unsigned int *) reloc_addr =
00685        ((*(unsigned int *)reloc_addr & ~0x3ff) |
00686         ((value >> 12) & 0x3ff));
00687       break;
00688     case R_SPARC_L44:
00689       *(unsigned int *) reloc_addr =
00690        ((*(unsigned int *)reloc_addr & ~0xfff) |
00691         (value & 0xfff));
00692       break;
00693 
00694       /* MEDANY code model relocs */
00695     case R_SPARC_HH22:
00696       *(unsigned int *) reloc_addr =
00697        ((*(unsigned int *)reloc_addr & 0xffc00000) |
00698         (value >> 42));
00699       break;
00700     case R_SPARC_HM10:
00701       *(unsigned int *) reloc_addr =
00702        ((*(unsigned int *)reloc_addr & ~0x3ff) |
00703         ((value >> 32) & 0x3ff));
00704       break;
00705     case R_SPARC_LM22:
00706       *(unsigned int *) reloc_addr =
00707        ((*(unsigned int *)reloc_addr & 0xffc00000) |
00708         ((value >> 10) & 0x003fffff));
00709       break;
00710     case R_SPARC_UA16:
00711       ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
00712       ((unsigned char *) reloc_addr_arg) [1] = value;
00713       break;
00714     case R_SPARC_UA32:
00715       ((unsigned char *) reloc_addr_arg) [0] = value >> 24;
00716       ((unsigned char *) reloc_addr_arg) [1] = value >> 16;
00717       ((unsigned char *) reloc_addr_arg) [2] = value >> 8;
00718       ((unsigned char *) reloc_addr_arg) [3] = value;
00719       break;
00720     case R_SPARC_UA64:
00721       if (! ((long) reloc_addr_arg & 3))
00722        {
00723          /* Common in .eh_frame */
00724          ((unsigned int *) reloc_addr_arg) [0] = value >> 32;
00725          ((unsigned int *) reloc_addr_arg) [1] = value;
00726          break;
00727        }
00728       ((unsigned char *) reloc_addr_arg) [0] = value >> 56;
00729       ((unsigned char *) reloc_addr_arg) [1] = value >> 48;
00730       ((unsigned char *) reloc_addr_arg) [2] = value >> 40;
00731       ((unsigned char *) reloc_addr_arg) [3] = value >> 32;
00732       ((unsigned char *) reloc_addr_arg) [4] = value >> 24;
00733       ((unsigned char *) reloc_addr_arg) [5] = value >> 16;
00734       ((unsigned char *) reloc_addr_arg) [6] = value >> 8;
00735       ((unsigned char *) reloc_addr_arg) [7] = value;
00736       break;
00737 #endif
00738 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
00739     default:
00740       _dl_reloc_bad_type (map, r_type, 0);
00741       break;
00742 #endif
00743     }
00744 }
00745 
00746 auto inline void
00747 __attribute__ ((always_inline))
00748 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
00749                         void *const reloc_addr_arg)
00750 {
00751   Elf64_Addr *const reloc_addr = reloc_addr_arg;
00752   *reloc_addr = l_addr + reloc->r_addend;
00753 }
00754 
00755 auto inline void
00756 __attribute__ ((always_inline))
00757 elf_machine_lazy_rel (struct link_map *map,
00758                     Elf64_Addr l_addr, const Elf64_Rela *reloc)
00759 {
00760   switch (ELF64_R_TYPE (reloc->r_info))
00761     {
00762     case R_SPARC_NONE:
00763       break;
00764     case R_SPARC_JMP_SLOT:
00765       break;
00766     default:
00767       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
00768       break;
00769     }
00770 }
00771 
00772 #endif /* RESOLVE_MAP */