Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  SH version.
00002    Copyright (C) 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 "SH"
00025 
00026 #include <sys/param.h>
00027 #include <sysdep.h>
00028 #include <assert.h>
00029 
00030 /* Return nonzero iff ELF header is compatible with the running host.  */
00031 static inline int __attribute__ ((unused))
00032 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00033 {
00034   return ehdr->e_machine == EM_SH;
00035 }
00036 
00037 
00038 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00039    first element of the GOT.  This must be inlined in a function which
00040    uses global data.  */
00041 static inline Elf32_Addr __attribute__ ((unused))
00042 elf_machine_dynamic (void)
00043 {
00044   register Elf32_Addr *got;
00045   asm ("mov r12,%0" :"=r" (got));
00046   return *got;
00047 }
00048 
00049 
00050 /* Return the run-time load address of the shared object.  */
00051 static inline Elf32_Addr __attribute__ ((unused))
00052 elf_machine_load_address (void)
00053 {
00054   Elf32_Addr addr;
00055   asm ("mov.l 1f,r0\n\
00056        mov.l 3f,r2\n\
00057        add r12,r2\n\
00058        mov.l @(r0,r12),r0\n\
00059        bra 2f\n\
00060         sub r0,r2\n\
00061        .align 2\n\
00062        1: .long _dl_start@GOT\n\
00063        3: .long _dl_start@GOTOFF\n\
00064        2: mov r2,%0"
00065        : "=r" (addr) : : "r0", "r1", "r2");
00066   return addr;
00067 }
00068 
00069 
00070 /* Set up the loaded object described by L so its unrelocated PLT
00071    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00072 
00073 static inline int __attribute__ ((unused, always_inline))
00074 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00075 {
00076   Elf32_Addr *got;
00077   extern void _dl_runtime_resolve (Elf32_Word);
00078   extern void _dl_runtime_profile (Elf32_Word);
00079 
00080   if (l->l_info[DT_JMPREL] && lazy)
00081     {
00082       /* The GOT entries for functions in the PLT have not yet been filled
00083         in.  Their initial contents will arrange when called to load an
00084         offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
00085         and then jump to _GLOBAL_OFFSET_TABLE[2].  */
00086       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00087       /* If a library is prelinked but we have to relocate anyway,
00088         we have to be able to undo the prelinking of .got.plt.
00089         The prelinker saved us here address of .plt + 36.  */
00090       if (got[1])
00091        {
00092          l->l_mach.plt = got[1] + l->l_addr;
00093          l->l_mach.gotplt = (Elf32_Addr) &got[3];
00094        }
00095       got[1] = (Elf32_Addr) l;     /* Identify this shared object.     */
00096 
00097       /* The got[2] entry contains the address of a function which gets
00098         called to get the address of a so far unresolved function and
00099         jump to it.  The profiling extension of the dynamic linker allows
00100         to intercept the calls to collect information.   In this case we
00101         don't store the address in the GOT so that all future calls also
00102         end in this function.      */
00103       if (profile)
00104        {
00105          got[2] = (Elf32_Addr) &_dl_runtime_profile;
00106          /* Say that we really want profiling and the timers are started.  */
00107          if (GLRO(dl_profile) != NULL
00108              && _dl_name_match_p (GLRO(dl_profile), l))
00109            GL(dl_profile_map) = l;
00110        }
00111       else
00112        /* This function will get called to fix up the GOT entry indicated by
00113           the offset on the stack, and then jump to the resolved address.  */
00114        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
00115     }
00116   return lazy;
00117 }
00118 
00119 #define ELF_MACHINE_RUNTIME_FIXUP_ARGS int plt_type
00120 
00121 /* Mask identifying addresses reserved for the user program,
00122    where the dynamic linker should not map anything.  */
00123 #define ELF_MACHINE_USER_ADDRESS_MASK     0x80000000UL
00124 
00125 /* Initial entry point code for the dynamic linker.
00126    The C function `_dl_start' is the real entry point;
00127    its return value is the user program's entry point.  */
00128 
00129 #define RTLD_START asm ("\
00130 .text\n\
00131 .globl _start\n\
00132 .globl _dl_start_user\n\
00133 _start:\n\
00134        mov r15,r4\n\
00135        mov.l .L_dl_start,r1\n\
00136        mova .L_dl_start,r0\n\
00137        add r1,r0\n\
00138        jsr @r0\n\
00139         nop\n\
00140 _dl_start_user:\n\
00141        ! Save the user entry point address in r8.\n\
00142        mov r0,r8\n\
00143        ! Point r12 at the GOT.\n\
00144        mov.l 1f,r12\n\
00145        mova 1f,r0\n\
00146        bra 2f\n\
00147         add r0,r12\n\
00148        .align 2\n\
00149 1:     .long _GLOBAL_OFFSET_TABLE_\n\
00150 2:     ! See if we were run as a command with the executable file\n\
00151        ! name as an extra leading argument.\n\
00152        mov.l .L_dl_skip_args,r0\n\
00153        mov.l @(r0,r12),r0\n\
00154        mov.l @r0,r0\n\
00155        ! Get the original argument count.\n\
00156        mov.l @r15,r5\n\
00157        ! Subtract _dl_skip_args from it.\n\
00158        sub r0,r5\n\
00159        ! Adjust the stack pointer to skip _dl_skip_args words.\n\
00160        shll2 r0\n\
00161        add r0,r15\n\
00162        ! Store back the modified argument count.\n\
00163        mov.l r5,@r15\n\
00164        ! Compute argv address and envp.\n\
00165        mov r15,r6\n\
00166        add #4,r6\n\
00167        mov r5,r7\n\
00168        shll2 r7\n\
00169        add r15,r7\n\
00170        add #8,r7\n\
00171        mov.l .L_dl_loaded,r0\n\
00172        mov.l @(r0,r12),r0\n\
00173        mov.l @r0,r4\n\
00174        ! Call _dl_init.\n\
00175        mov.l .L_dl_init,r1\n\
00176        mova .L_dl_init,r0\n\
00177        add r1,r0\n\
00178        jsr @r0\n\
00179         nop\n\
00180 1:     ! Pass our finalizer function to the user in r4, as per ELF ABI.\n\
00181        mov.l .L_dl_fini,r0\n\
00182        mov.l @(r0,r12),r4\n\
00183        ! Jump to the user's entry point.\n\
00184        jmp @r8\n\
00185         nop\n\
00186        .align 2\n\
00187 .L_dl_start:\n\
00188        .long _dl_start@PLT\n\
00189 .L_dl_skip_args:\n\
00190        .long _dl_skip_args@GOT\n\
00191 .L_dl_init:\n\
00192        .long _dl_init_internal@PLT\n\
00193 .L_dl_loaded:\n\
00194        .long _rtld_local@GOT\n\
00195 .L_dl_fini:\n\
00196        .long _dl_fini@GOT\n\
00197        .type __fpscr_values,@object\n\
00198        .global __fpscr_values\n\
00199 __fpscr_values:\n\
00200        .long   0\n\
00201        .long   0x80000\n\
00202        .weak __fpscr_values\n\
00203 .previous\n\
00204 ");
00205 
00206 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
00207    TLS variable, so undefined references should not be allowed to
00208    define the value.
00209    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00210    of the main executable's symbols, as for a COPY reloc.  */
00211 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00212 # define elf_machine_type_class(type) \
00213   ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32                 \
00214      || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32)          \
00215     * ELF_RTYPE_CLASS_PLT)                                           \
00216    | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
00217 #else
00218 #define elf_machine_type_class(type) \
00219   ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)    \
00220    | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
00221 #endif
00222 
00223 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00224 #define ELF_MACHINE_JMP_SLOT       R_SH_JMP_SLOT
00225 
00226 /* We define an initialization functions.  This is called very early in
00227    _dl_sysdep_start.  */
00228 #define DL_PLATFORM_INIT dl_platform_init ()
00229 
00230 static inline void __attribute__ ((unused))
00231 dl_platform_init (void)
00232 {
00233   if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
00234     /* Avoid an empty string which would disturb us.  */
00235     GLRO(dl_platform) = NULL;
00236 }
00237 
00238 static inline Elf32_Addr
00239 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00240                      const Elf32_Rela *reloc,
00241                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00242 {
00243   return *reloc_addr = value;
00244 }
00245 
00246 /* Return the final value of a plt relocation.   */
00247 static inline Elf32_Addr
00248 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
00249                      Elf32_Addr value)
00250 {
00251   return value + reloc->r_addend;
00252 }
00253 
00254 #define ARCH_LA_PLTENTER sh_gnu_pltenter
00255 #define ARCH_LA_PLTEXIT sh_gnu_pltexit
00256 
00257 #endif /* !dl_machine_h */
00258 
00259 /* SH never uses Elf32_Rel relocations.    */
00260 #define ELF_MACHINE_NO_REL 1
00261 
00262 #ifdef RESOLVE_MAP
00263 
00264 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00265    MAP is the object containing the reloc.  */
00266 
00267 auto inline void
00268 __attribute ((always_inline))
00269 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00270                 const Elf32_Sym *sym, const struct r_found_version *version,
00271                 void *const reloc_addr_arg)
00272 {
00273   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00274   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00275   Elf32_Addr value;
00276 
00277 #define COPY_UNALIGNED_WORD(swp, twp, align) \
00278   { \
00279     void *__s = (swp), *__t = (twp); \
00280     unsigned char *__s1 = __s, *__t1 = __t; \
00281     unsigned short *__s2 = __s, *__t2 = __t; \
00282     unsigned long *__s4 = __s, *__t4 = __t; \
00283     switch ((align)) \
00284     { \
00285     case 0: \
00286       *__t4 = *__s4; \
00287       break; \
00288     case 2: \
00289       *__t2++ = *__s2++; \
00290       *__t2 = *__s2; \
00291       break; \
00292     default: \
00293       *__t1++ = *__s1++; \
00294       *__t1++ = *__s1++; \
00295       *__t1++ = *__s1++; \
00296       *__t1 = *__s1; \
00297       break; \
00298     } \
00299   }
00300 
00301   if (__builtin_expect (r_type == R_SH_RELATIVE, 0))
00302     {
00303 #ifndef RTLD_BOOTSTRAP
00304       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.     */
00305 #endif
00306        {
00307          if (reloc->r_addend)
00308            value = map->l_addr + reloc->r_addend;
00309          else
00310            {
00311              COPY_UNALIGNED_WORD (reloc_addr_arg, &value,
00312                                (int) reloc_addr_arg & 3);
00313              value += map->l_addr;
00314            }
00315          COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
00316                             (int) reloc_addr_arg & 3);
00317        }
00318     }
00319 #ifndef RTLD_BOOTSTRAP
00320   else if (__builtin_expect (r_type == R_SH_NONE, 0))
00321     return;
00322 #endif
00323   else
00324     {
00325       const Elf32_Sym *const refsym = sym;
00326       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00327 
00328       value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00329       value += reloc->r_addend;
00330 
00331       switch (r_type)
00332        {
00333        case R_SH_COPY:
00334          if (sym == NULL)
00335            /* This can happen in trace mode if an object could not be
00336               found.  */
00337            break;
00338          if (sym->st_size > refsym->st_size
00339              || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
00340            {
00341              const char *strtab;
00342 
00343              strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
00344              _dl_error_printf ("\
00345 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00346                             rtld_progname ?: "<program name unknown>",
00347                             strtab + refsym->st_name);
00348            }
00349          memcpy (reloc_addr_arg, (void *) value,
00350                 MIN (sym->st_size, refsym->st_size));
00351          break;
00352        case R_SH_GLOB_DAT:
00353        case R_SH_JMP_SLOT:
00354          /* These addresses are always aligned.  */
00355          *reloc_addr = value;
00356          break;
00357 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00358          /* XXX Remove TLS relocations which are not needed.  */
00359        case R_SH_TLS_DTPMOD32:
00360 # ifdef RTLD_BOOTSTRAP
00361          /* During startup the dynamic linker is always the module
00362             with index 1.
00363             XXX If this relocation is necessary move before RESOLVE
00364             call.  */
00365          *reloc_addr = 1;
00366 # else
00367          /* Get the information from the link map returned by the
00368             resolv function.  */
00369          if (sym_map != NULL)
00370            *reloc_addr = sym_map->l_tls_modid;
00371 # endif
00372          break;
00373        case R_SH_TLS_DTPOFF32:
00374 # ifndef RTLD_BOOTSTRAP
00375          /* During relocation all TLS symbols are defined and used.
00376             Therefore the offset is already correct.  */
00377          if (sym != NULL)
00378            *reloc_addr = sym->st_value;
00379 # endif
00380          break;
00381        case R_SH_TLS_TPOFF32:
00382          /* The offset is positive, afterward from the thread pointer.  */
00383 # ifdef RTLD_BOOTSTRAP
00384          *reloc_addr = map->l_tls_offset + sym->st_value + reloc->r_addend;
00385 # else
00386          /* We know the offset of object the symbol is contained in.
00387             It is a positive value which will be added to the thread
00388             pointer.  To get the variable position in the TLS block
00389             we add the offset from that of the TLS block.  */
00390          if (sym != NULL)
00391            {
00392              CHECK_STATIC_TLS (map, sym_map);
00393              *reloc_addr = sym_map->l_tls_offset + sym->st_value
00394                          + reloc->r_addend;
00395            }
00396 # endif
00397          break;
00398 #endif /* use TLS */
00399        case R_SH_DIR32:
00400          {
00401 #ifndef RTLD_BOOTSTRAP
00402           /* This is defined in rtld.c, but nowhere in the static
00403              libc.a; make the reference weak so static programs can
00404              still link.  This declaration cannot be done when
00405              compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP) because
00406              rtld.c contains the common defn for _dl_rtld_map, which
00407              is incompatible with a weak decl in the same file.  */
00408 # ifndef SHARED
00409            weak_extern (_dl_rtld_map);
00410 # endif
00411            if (map == &GL(dl_rtld_map))
00412              /* Undo the relocation done here during bootstrapping.
00413                Now we will relocate it anew, possibly using a
00414                binding found in the user program or a loaded library
00415                rather than the dynamic linker's built-in definitions
00416                used while loading those libraries.  */
00417              value -= map->l_addr + refsym->st_value + reloc->r_addend;
00418 #endif
00419            COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
00420                              (int) reloc_addr_arg & 3);
00421            break;
00422          }
00423        case R_SH_REL32:
00424          value = (value - (Elf32_Addr) reloc_addr);
00425          COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
00426                             (int) reloc_addr_arg & 3);
00427          break;
00428        default:
00429          _dl_reloc_bad_type (map, r_type, 0);
00430          break;
00431        }
00432     }
00433 }
00434 
00435 auto inline void
00436 __attribute__ ((always_inline))
00437 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00438                         void *const reloc_addr_arg)
00439 {
00440   Elf32_Addr value;
00441 
00442   if (reloc->r_addend)
00443     value = l_addr + reloc->r_addend;
00444   else
00445     {
00446       COPY_UNALIGNED_WORD (reloc_addr_arg, &value, (int) reloc_addr_arg & 3);
00447       value += l_addr;
00448     }
00449   COPY_UNALIGNED_WORD (&value, reloc_addr_arg, (int) reloc_addr_arg & 3);
00450 
00451 #undef COPY_UNALIGNED_WORD
00452 }
00453 
00454 auto inline void
00455 __attribute__ ((always_inline))
00456 elf_machine_lazy_rel (struct link_map *map,
00457                     Elf32_Addr l_addr, const Elf32_Rela *reloc)
00458 {
00459   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00460   /* Check for unexpected PLT reloc type.  */
00461   if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
00462     {
00463       if (__builtin_expect (map->l_mach.plt, 0) == 0)
00464        *reloc_addr += l_addr;
00465       else
00466        *reloc_addr =
00467          map->l_mach.plt
00468          + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 7;
00469     }
00470   else
00471     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
00472 }
00473 
00474 #endif /* RESOLVE_MAP */