Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  CRIS version.
00002    Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #ifndef dl_machine_h
00021 #define dl_machine_h
00022 
00023 #define ELF_MACHINE_NAME "CRIS"
00024 
00025 #include <sys/param.h>
00026 
00027 #ifdef __PIC__
00028 # define CALL_FN(x)                                                  \
00029        "move.d       $pc,$r9\n\t"                                           \
00030        "add.d " #x " - .,$r9\n\t"                                    \
00031        "jsr   $r9"
00032 #else
00033 # define CALL_FN(x) "jsr " #x
00034 #endif
00035 
00036 /* Return nonzero iff ELF header is compatible with the running host.  */
00037 
00038 static inline int
00039 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00040 {
00041   return ehdr->e_machine == EM_CRIS;
00042 }
00043 
00044 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00045    first element of the GOT.  This must be inlined in a function which
00046    uses global data.  */
00047 
00048 static inline Elf32_Addr
00049 elf_machine_dynamic (void)
00050 {
00051   /* Don't just set this to an asm variable "r0" since that's not logical
00052      (like, the variable is uninitialized and the register is fixed) and
00053      may make GCC trip over itself doing register allocation.  Yes, I'm
00054      paranoid.  Why do you ask?  */
00055   Elf32_Addr *got;
00056 
00057   __asm__ ("move.d $r0,%0" : "=rm" (got));
00058   return *got;
00059 }
00060 
00061 /* Return the run-time load address of the shared object.  We do it like
00062    m68k and i386, by taking an arbitrary local symbol, forcing a GOT entry
00063    for it, and peeking into the GOT table, which is set to the link-time
00064    file-relative symbol value (regardless of whether the target is REL or
00065    RELA).  We subtract this link-time file-relative value from the "local"
00066    value we calculate from GOT position and GOT offset.  FIXME: Perhaps
00067    there's some other symbol we could use, that we don't *have* to force a
00068    GOT entry for.  */
00069 
00070 static inline Elf32_Addr
00071 elf_machine_load_address (void)
00072 {
00073   Elf32_Addr gotaddr_diff;
00074   __asm__ ("sub.d [$r0+_dl_start:GOT16],$r0,%0\n\t"
00075           "add.d _dl_start:GOTOFF,%0" : "=r" (gotaddr_diff));
00076   return gotaddr_diff;
00077 }
00078 
00079 /* Set up the loaded object described by L so its unrelocated PLT
00080    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00081 
00082 static inline int
00083 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00084 {
00085   Elf32_Addr *got;
00086   extern void _dl_runtime_resolve (Elf32_Word);
00087   extern void _dl_runtime_profile (Elf32_Word);
00088 
00089   if (l->l_info[DT_JMPREL] && lazy)
00090     {
00091       /* The GOT entries for functions in the PLT have not yet been
00092         filled in.  Their initial contents will arrange when called
00093         to push an offset into the .rela.plt section, push
00094         _GLOBAL_OFFSET_TABLE_[1], and then jump to
00095         _GLOBAL_OFFSET_TABLE_[2].  */
00096       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00097       got[1] = (Elf32_Addr) l;     /* Identify this shared object.  */
00098 
00099       /* The got[2] entry contains the address of a function which gets
00100         called to get the address of a so far unresolved function and
00101         jump to it.  The profiling extension of the dynamic linker allows
00102         to intercept the calls to collect information.  In this case we
00103         don't store the address in the GOT so that all future calls also
00104         end in this function.  */
00105       if (__builtin_expect (profile, 0))
00106        {
00107          got[2] = (Elf32_Addr) &_dl_runtime_profile;
00108 
00109          if (_dl_name_match_p (GL(dl_profile), l))
00110            {
00111              /* This is the object we are looking for.  Say that we really
00112                want profiling and the timers are started.  */
00113              GL(dl_profile_map) = l;
00114            }
00115        }
00116       else
00117        /* This function will get called to fix up the GOT entry indicated by
00118           the offset on the stack, and then jump to the resolved address.  */
00119        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
00120     }
00121 
00122   return lazy;
00123 }
00124 
00125 /* This code is used in dl-runtime.c to call the `fixup' function
00126    and then redirect to the address it returns.
00127 
00128    We get here with the offset into the relocation table pushed on stack,
00129    and the link map in MOF.  */
00130 
00131 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
00132 "; Trampoline for " #fixup_name "\n\
00133        .globl " #tramp_name "\n\
00134        .type " #tramp_name ", @function\n\
00135 " #tramp_name ":\n\
00136        push   $r13\n\
00137        push   $r12\n\
00138        push   $r11\n\
00139        push   $r10\n\
00140        push   $r9\n\
00141        push   $srp\n\
00142        move.d [$sp+6*4],$r11\n\
00143        move   $mof,$r10\n\
00144        " CALL_FN (fixup_name) "\n\
00145        move.d $r10,[$sp+6*4]\n\
00146        pop    $srp\n\
00147        pop    $r9\n\
00148        pop    $r10\n\
00149        pop    $r11\n\
00150        pop    $r12\n\
00151        pop    $r13\n\
00152        jump   [$sp+]\n\
00153        .size " #tramp_name ", . - " #tramp_name "\n"
00154 #ifndef PROF
00155 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
00156 asm (TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup) \
00157      TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup));
00158 #else
00159 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
00160 asm (TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup) \
00161      ".globl _dl_runtime_profile\n" \
00162      ".set _dl_runtime_profile, _dl_runtime_resolve");
00163 #endif
00164 
00165 
00166 /* Mask identifying addresses reserved for the user program,
00167    where the dynamic linker should not map anything.  */
00168 #define ELF_MACHINE_USER_ADDRESS_MASK     0xf8000000UL
00169 
00170 /* Initial entry point code for the dynamic linker.
00171    The C function `_dl_start' is the real entry point;
00172    its return value is the user program's entry point.  */
00173 
00174 #define RTLD_START asm ("\
00175        .text\n\
00176        .globl _start\n\
00177        .type  _start,@function\n\
00178 _start:\n\
00179        move.d $sp,$r10\n\
00180        " CALL_FN (_dl_start) "\n\
00181        /* FALLTHRU */\n\
00182 \n\
00183        .globl _dl_start_user\n\
00184        .type _dl_start_user,@function\n\
00185 _dl_start_user:\n\
00186        ; Save the user entry point address in R1.\n\
00187        move.d $r10,$r1\n\
00188        ; Point R0 at the GOT.\n\
00189        move.d $pc,$r0\n\
00190        sub.d  .:GOTOFF,$r0\n\
00191        ; See if we were run as a command with the executable file\n\
00192        ; name as an extra leading argument.\n\
00193        move.d [$r0+_dl_skip_args:GOT16],$r13\n\
00194        move.d [$r13],$r9\n\
00195        ; Get the original argument count\n\
00196        move.d [$sp],$r11\n\
00197        ; Subtract _dl_skip_args from it.\n\
00198        sub.d  $r9,$r11\n\
00199        ; Adjust the stack pointer to skip _dl_skip_args words.\n\
00200        addi   $r9.d,$sp\n\
00201        ; Put the new argc in place as expected by the user entry.\n\
00202        move.d $r11,[$sp]\n\
00203        ; Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
00204        ;  env: skip scaled argc and skip stored argc and NULL at end of argv[].\n\
00205        move.d $sp,$r13\n\
00206        addi   $r11.d,$r13\n\
00207        addq   8,$r13\n\
00208        ;  argv: skip stored argc.\n\
00209        move.d $sp,$r12\n\
00210        addq   4,$r12\n\
00211        ;  main_map: at _dl_loaded.\n\
00212        move.d [$r0+_rtld_local:GOT16],$r9\n\
00213        move.d [$r9],$r10\n\
00214        move.d _dl_init_internal:PLTG,$r9\n\
00215        add.d  $r0,$r9\n\
00216        jsr    $r9\n\
00217        ; Pass our finalizer function to the user in R10.\n\
00218        move.d [$r0+_dl_fini:GOT16],$r10\n\
00219        ; Terminate the frame-pointer.\n\
00220        moveq  0,$r8\n\
00221        ; Cause SEGV if user entry returns.\n\
00222        move   $r8,$srp\n\
00223        ; Jump to the user's entry point.\n\
00224        jump   $r1\n\
00225        .size _dl_start_user, . - _dl_start_user\n\
00226        .previous");
00227 
00228 /* The union of reloc-type-classes where the reloc TYPE is a member.
00229 
00230    TYPE is in the class ELF_RTYPE_CLASS_PLT if it can describe a
00231    relocation for a PLT entry, that is, for which a PLT entry should not
00232    be allowed to define the value.  The GNU linker for CRIS can merge a
00233    .got.plt entry (R_CRIS_JUMP_SLOT) with a .got entry (R_CRIS_GLOB_DAT),
00234    so we need to match both these reloc types.
00235 
00236    TYPE is in the class ELF_RTYPE_CLASS_NOCOPY if it should not be allowed
00237    to resolve to one of the main executable's symbols, as for a COPY
00238    reloc.  */
00239 #define elf_machine_type_class(type)                           \
00240   ((((((type) == R_CRIS_JUMP_SLOT))                            \
00241      || ((type) == R_CRIS_GLOB_DAT)) * ELF_RTYPE_CLASS_PLT)    \
00242    | (((type) == R_CRIS_COPY) * ELF_RTYPE_CLASS_COPY))
00243 
00244 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00245 #define ELF_MACHINE_JMP_SLOT       R_CRIS_JUMP_SLOT
00246 
00247 /* CRIS never uses Elf32_Rel relocations.  */
00248 #define ELF_MACHINE_NO_REL 1
00249 
00250 /* We define an initialization functions.  This is called very early in
00251    _dl_sysdep_start.  */
00252 #define DL_PLATFORM_INIT dl_platform_init ()
00253 
00254 static inline void __attribute__ ((unused))
00255 dl_platform_init (void)
00256 {
00257   if (GL(dl_platform) != NULL && *GL(dl_platform) == '\0')
00258     /* Avoid an empty string which would disturb us.  */
00259     GL(dl_platform) = NULL;
00260 }
00261 
00262 static inline Elf32_Addr
00263 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00264                      const Elf32_Rela *reloc,
00265                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00266 {
00267   return *reloc_addr = value;
00268 }
00269 
00270 /* Return the final value of a plt relocation.  */
00271 static inline Elf32_Addr
00272 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
00273                      Elf32_Addr value)
00274 {
00275   return value + reloc->r_addend;
00276 }
00277 
00278 #endif /* !dl_machine_h */
00279 
00280 #ifdef RESOLVE
00281 
00282 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00283    MAP is the object containing the reloc.  */
00284 
00285 static inline void
00286 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00287                 const Elf32_Sym *sym, const struct r_found_version *version,
00288                 void *const reloc_addr_arg)
00289 {
00290   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00291   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00292 
00293   if (__builtin_expect (r_type == R_CRIS_RELATIVE, 0))
00294     *reloc_addr = map->l_addr + reloc->r_addend;
00295   else
00296     {
00297 #ifndef RTLD_BOOTSTRAP
00298       const Elf32_Sym *const refsym = sym;
00299 #endif
00300       Elf32_Addr value;
00301       if (sym->st_shndx != SHN_UNDEF
00302          && ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
00303        value = map->l_addr;
00304       else
00305        {
00306          value = RESOLVE (&sym, version, r_type);
00307          if (sym)
00308            value += sym->st_value;
00309        }
00310       value += reloc->r_addend;    /* Assume copy relocs have zero addend.  */
00311 
00312       switch (r_type)
00313        {
00314 #ifndef RTLD_BOOTSTRAP
00315        case R_CRIS_COPY:
00316          if (sym == NULL)
00317            /* This can happen in trace mode if an object could not be
00318               found.  */
00319            break;
00320          if (sym->st_size > refsym->st_size
00321              || (GL(dl_verbose) && sym->st_size < refsym->st_size))
00322            {
00323              const char *strtab;
00324 
00325              strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00326              _dl_error_printf ("\
00327 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00328                             rtld_progname ?: "<program name unknown>",
00329                             strtab + refsym->st_name);
00330            }
00331          memcpy (reloc_addr_arg, (void *) value,
00332                 MIN (sym->st_size, refsym->st_size));
00333          break;
00334 
00335        case R_CRIS_32:
00336 #endif
00337        case R_CRIS_GLOB_DAT:
00338        case R_CRIS_JUMP_SLOT:
00339          *reloc_addr = value;
00340          break;
00341 #ifndef RTLD_BOOTSTRAP
00342        case R_CRIS_8:
00343          *(char *) reloc_addr = value;
00344          break;
00345        case R_CRIS_16:
00346          *(short *) reloc_addr = value;
00347          break;
00348        case R_CRIS_8_PCREL:
00349          *(char *) reloc_addr
00350            = value + reloc->r_addend - (Elf32_Addr) reloc_addr - 1;
00351          break;
00352        case R_CRIS_16_PCREL:
00353          *(short *) reloc_addr
00354            = value + reloc->r_addend - (Elf32_Addr) reloc_addr - 2;
00355          break;
00356        case R_CRIS_32_PCREL:
00357          *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr - 4;
00358          break;
00359 #endif
00360        case R_CRIS_NONE:
00361          break;
00362 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
00363        default:
00364          _dl_reloc_bad_type (map, r_type, 0);
00365          break;
00366 #endif
00367        }
00368     }
00369 }
00370 
00371 static inline void
00372 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00373                         void *const reloc_addr_arg)
00374 {
00375   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00376   *reloc_addr = l_addr + reloc->r_addend;
00377 }
00378 
00379 static inline void
00380 elf_machine_lazy_rel (struct link_map *map,
00381                     Elf32_Addr l_addr, const Elf32_Rela *reloc)
00382 {
00383   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00384   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00385   if (__builtin_expect (r_type == R_CRIS_JUMP_SLOT, 1))
00386     *reloc_addr += l_addr;
00387   else
00388     _dl_reloc_bad_type (map, r_type, 1);
00389 }
00390 
00391 #endif /* RESOLVE */