Back to index

glibc  2.9
dl-trampoline.c
Go to the documentation of this file.
00001 /* PLT trampoline.  MIPS version.
00002    Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 /*  FIXME: Profiling of shared libraries is not implemented yet.  */
00023 
00024 #include <sysdep.h>
00025 #include <link.h>
00026 #include <elf.h>
00027 #include <ldsodefs.h>
00028 #include <dl-machine.h>
00029 
00030 /* Get link map for callers object containing STUB_PC.  */
00031 static inline struct link_map *
00032 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
00033 {
00034   extern int _dl_mips_gnu_objects;
00035 
00036   /* got[1] is reserved to keep its link map address for the shared
00037      object generated by the gnu linker.  If all are such objects, we
00038      can find the link map from current GPREG simply.  If not so, get
00039      the link map for caller's object containing STUB_PC.  */
00040 
00041   if (_dl_mips_gnu_objects)
00042     {
00043       ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
00044       ElfW(Word) g1;
00045 
00046       g1 = ((ElfW(Word) *) got)[1];
00047 
00048       if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
00049        {
00050          struct link_map *l =
00051            (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
00052          ElfW(Addr) base, limit;
00053          const ElfW(Phdr) *p = l->l_phdr;
00054          ElfW(Half) this, nent = l->l_phnum;
00055 
00056          /* For the common case of a stub being called from the containing
00057             object, STUB_PC will point to somewhere within the object that
00058             is described by the link map fetched via got[1].  Otherwise we
00059             have to scan all maps.  */
00060          for (this = 0; this < nent; this++)
00061            {
00062              if (p[this].p_type == PT_LOAD)
00063               {
00064                 base = p[this].p_vaddr + l->l_addr;
00065                 limit = base + p[this].p_memsz;
00066                 if (stub_pc >= base && stub_pc < limit)
00067                   return l;
00068               }
00069            }
00070        }
00071     }
00072 
00073     struct link_map *l;
00074     Lmid_t nsid;
00075 
00076     for (nsid = 0; nsid < DL_NNS; ++nsid)
00077       for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
00078        {
00079          ElfW(Addr) base, limit;
00080          const ElfW(Phdr) *p = l->l_phdr;
00081          ElfW(Half) this, nent = l->l_phnum;
00082 
00083          for (this = 0; this < nent; ++this)
00084            {
00085              if (p[this].p_type == PT_LOAD)
00086               {
00087                 base = p[this].p_vaddr + l->l_addr;
00088                 limit = base + p[this].p_memsz;
00089                 if (stub_pc >= base && stub_pc < limit)
00090                   return l;
00091               }
00092            }
00093        }
00094 
00095   _dl_signal_error (0, NULL, NULL, "cannot find runtime link map");
00096   return NULL;
00097 }
00098 
00099 /* Define mips specific runtime resolver. The function __dl_runtime_resolve
00100    is called from assembler function _dl_runtime_resolve which converts
00101    special argument registers t7 ($15) and t8 ($24):
00102      t7  address to return to the caller of the function
00103      t8  index for this function symbol in .dynsym
00104    to usual c arguments.
00105 
00106    Other architectures call fixup from dl-runtime.c in
00107    _dl_runtime_resolve.  MIPS instead calls __dl_runtime_resolve.  We
00108    have to use our own version because of the way the got section is
00109    treated on MIPS (we've also got ELF_MACHINE_PLT defined).  */
00110 
00111 /* The flag _dl_mips_gnu_objects is set if all dynamic objects are
00112    generated by the gnu linker. */
00113 int _dl_mips_gnu_objects = 1;
00114 
00115 #define VERSYMIDX(sym)  (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
00116 
00117 /* This is called from assembly stubs below which the compiler can't see.  */
00118 static ElfW(Addr)
00119 __dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))
00120                 __attribute_used__;
00121 
00122 static ElfW(Addr)
00123 __dl_runtime_resolve (ElfW(Word) sym_index,
00124                     ElfW(Word) return_address,
00125                     ElfW(Addr) old_gpreg,
00126                     ElfW(Addr) stub_pc)
00127 {
00128   struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);
00129   const ElfW(Sym) *const symtab
00130     = (const ElfW(Sym) *) D_PTR (l, l_info[DT_SYMTAB]);
00131   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
00132   ElfW(Addr) *got
00133     = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
00134   const ElfW(Word) local_gotno
00135     = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
00136   const ElfW(Word) gotsym
00137     = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
00138   const ElfW(Sym) *sym = &symtab[sym_index];
00139   struct link_map *sym_map;
00140   ElfW(Addr) value;
00141 
00142   /* FIXME: The symbol versioning stuff is not tested yet.  */
00143   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
00144     {
00145       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
00146        {
00147        default:
00148          {
00149            const ElfW(Half) *vernum =
00150              (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
00151            ElfW(Half) ndx = vernum[sym_index] & 0x7fff;
00152            const struct r_found_version *version = &l->l_versions[ndx];
00153 
00154            if (version->hash != 0)
00155              {
00156               sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
00157                                           &sym, l->l_scope, version,
00158                                           ELF_RTYPE_CLASS_PLT, 0, 0);
00159               break;
00160              }
00161            /* Fall through.  */
00162          }
00163        case 0:
00164          sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
00165                                     l->l_scope, 0, ELF_RTYPE_CLASS_PLT,
00166                                     DL_LOOKUP_ADD_DEPENDENCY, 0);
00167        }
00168 
00169       /* Currently value contains the base load address of the object
00170         that defines sym.  Now add in the symbol offset.  */
00171       value = (sym ? sym_map->l_addr + sym->st_value : 0);
00172     }
00173   else
00174     /* We already found the symbol.  The module (and therefore its load
00175        address) is also known.  */
00176     value = l->l_addr + sym->st_value;
00177 
00178   /* Apply the relocation with that value.  */
00179   *(got + local_gotno + sym_index - gotsym) = value;
00180 
00181   return value;
00182 }
00183 
00184 #if _MIPS_SIM == _ABIO32
00185 #define ELF_DL_FRAME_SIZE 40
00186 
00187 #define ELF_DL_SAVE_ARG_REGS "\
00188        sw     $15, 36($29)\n                                                \
00189        sw     $4, 16($29)\n                                          \
00190        sw     $5, 20($29)\n                                          \
00191        sw     $6, 24($29)\n                                          \
00192        sw     $7, 28($29)\n                                          \
00193 "
00194 
00195 #define ELF_DL_RESTORE_ARG_REGS "\
00196        lw     $31, 36($29)\n                                                \
00197        lw     $4, 16($29)\n                                          \
00198        lw     $5, 20($29)\n                                          \
00199        lw     $6, 24($29)\n                                          \
00200        lw     $7, 28($29)\n                                          \
00201 "
00202 
00203 /* The PLT resolver should also save and restore $2 and $3, which are used
00204    as arguments to MIPS16 stub functions.  */
00205 #define ELF_DL_PLT_FRAME_SIZE 48
00206 
00207 #define ELF_DL_PLT_SAVE_ARG_REGS \
00208        ELF_DL_SAVE_ARG_REGS "\
00209        sw     $2, 40($29)\n                                          \
00210        sw     $3, 44($29)\n                                          \
00211 "
00212 
00213 #define ELF_DL_PLT_RESTORE_ARG_REGS \
00214        ELF_DL_RESTORE_ARG_REGS "\
00215        lw     $2, 40($29)\n                                          \
00216        lw     $3, 44($29)\n                                          \
00217 "
00218 
00219 #define IFABIO32(X) X
00220 #define IFNEWABI(X)
00221 
00222 #else /* _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 */
00223 
00224 #define ELF_DL_FRAME_SIZE 80
00225 
00226 #define ELF_DL_SAVE_ARG_REGS "\
00227        sd     $15, 72($29)\n                                                \
00228        sd     $4, 8($29)\n                                           \
00229        sd     $5, 16($29)\n                                          \
00230        sd     $6, 24($29)\n                                          \
00231        sd     $7, 32($29)\n                                          \
00232        sd     $8, 40($29)\n                                          \
00233        sd     $9, 48($29)\n                                          \
00234        sd     $10, 56($29)\n                                                \
00235        sd     $11, 64($29)\n                                                \
00236 "
00237 
00238 #define ELF_DL_RESTORE_ARG_REGS "\
00239        ld     $31, 72($29)\n                                                \
00240        ld     $4, 8($29)\n                                           \
00241        ld     $5, 16($29)\n                                          \
00242        ld     $6, 24($29)\n                                          \
00243        ld     $7, 32($29)\n                                          \
00244        ld     $8, 40($29)\n                                          \
00245        ld     $9, 48($29)\n                                          \
00246        ld     $10, 56($29)\n                                                \
00247        ld     $11, 64($29)\n                                                \
00248 "
00249 
00250 /* The PLT resolver should also save and restore $2 and $3, which are used
00251    as arguments to MIPS16 stub functions.  */
00252 #define ELF_DL_PLT_FRAME_SIZE 96
00253 
00254 #define ELF_DL_PLT_SAVE_ARG_REGS \
00255        ELF_DL_SAVE_ARG_REGS "\
00256        sd     $2, 80($29)\n                                          \
00257        sd     $3, 88($29)\n                                          \
00258 "
00259 
00260 #define ELF_DL_PLT_RESTORE_ARG_REGS \
00261        ELF_DL_RESTORE_ARG_REGS "\
00262        ld     $2, 80($29)\n                                          \
00263        ld     $3, 88($29)\n                                          \
00264 "
00265 
00266 #define IFABIO32(X)
00267 #define IFNEWABI(X) X
00268 
00269 #endif
00270 
00271 asm ("\n\
00272        .text\n\
00273        .align 2\n\
00274        .globl _dl_runtime_resolve\n\
00275        .type  _dl_runtime_resolve,@function\n\
00276        .ent   _dl_runtime_resolve\n\
00277 _dl_runtime_resolve:\n\
00278        .frame $29, " STRINGXP(ELF_DL_FRAME_SIZE) ", $31\n\
00279        .set noreorder\n\
00280        # Save GP.\n\
00281        move   $3, $28\n\
00282        # Save arguments and sp value in stack.\n\
00283        " STRINGXP(PTR_SUBIU) "  $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
00284        # Modify t9 ($25) so as to point .cpload instruction.\n\
00285        " IFABIO32(STRINGXP(PTR_ADDIU) "   $25, 12\n") "\
00286        # Compute GP.\n\
00287        " STRINGXP(SETUP_GP) "\n\
00288        " STRINGXV(SETUP_GP64 (0, _dl_runtime_resolve)) "\n\
00289        .set reorder\n\
00290        # Save slot call pc.\n\
00291        move   $2, $31\n\
00292        " IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
00293        " ELF_DL_SAVE_ARG_REGS "\
00294        move   $4, $24\n\
00295        move   $5, $15\n\
00296        move   $6, $3\n\
00297        move   $7, $2\n\
00298        jal    __dl_runtime_resolve\n\
00299        " ELF_DL_RESTORE_ARG_REGS "\
00300        " STRINGXP(RESTORE_GP64) "\n\
00301        " STRINGXP(PTR_ADDIU) "     $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
00302        move   $25, $2\n\
00303        jr     $25\n\
00304        .end   _dl_runtime_resolve\n\
00305        .previous\n\
00306 ");
00307 
00308 /* Assembler veneer called from the PLT header code when using PLTs.
00309 
00310    Code in each PLT entry and the PLT header fills in the arguments to
00311    this function:
00312 
00313    - $15 (o32 t7, n32/n64 t3) - caller's return address
00314    - $24 (t8) - PLT entry index
00315    - $25 (t9) - address of _dl_runtime_pltresolve
00316    - o32 $28 (gp), n32/n64 $14 (t2) - address of .got.plt
00317 
00318    Different registers are used for .got.plt because the ABI was
00319    originally designed for o32, where gp was available (call
00320    clobbered).  On n32/n64 gp is call saved.
00321 
00322    _dl_fixup needs:
00323 
00324    - $4 (a0) - link map address
00325    - $5 (a1) - .rel.plt offset (== PLT entry index * 8)  */
00326 
00327 asm ("\n\
00328        .text\n\
00329        .align 2\n\
00330        .globl _dl_runtime_pltresolve\n\
00331        .type  _dl_runtime_pltresolve,@function\n\
00332        .ent   _dl_runtime_pltresolve\n\
00333 _dl_runtime_pltresolve:\n\
00334        .frame $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
00335        .set noreorder\n\
00336        # Save arguments and sp value in stack.\n\
00337        " STRINGXP(PTR_SUBIU) "     $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
00338        " IFABIO32(STRINGXP(PTR_L) "       $13, " STRINGXP(PTRSIZE) "($28)") "\n\
00339        " IFNEWABI(STRINGXP(PTR_L) "       $13, " STRINGXP(PTRSIZE) "($14)") "\n\
00340        # Modify t9 ($25) so as to point .cpload instruction.\n\
00341        " IFABIO32(STRINGXP(PTR_ADDIU) "   $25, 12\n") "\
00342        # Compute GP.\n\
00343        " STRINGXP(SETUP_GP) "\n\
00344        " STRINGXV(SETUP_GP64 (0, _dl_runtime_pltresolve)) "\n\
00345        .set reorder\n\
00346        " IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
00347        " ELF_DL_PLT_SAVE_ARG_REGS "\
00348        move   $4, $13\n\
00349        sll    $5, $24, " STRINGXP(PTRLOG) " + 1\n\
00350        jal    _dl_fixup\n\
00351        move   $25, $2\n\
00352        " ELF_DL_PLT_RESTORE_ARG_REGS "\
00353        " STRINGXP(RESTORE_GP64) "\n\
00354        " STRINGXP(PTR_ADDIU) "     $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
00355        jr     $25\n\
00356        .end   _dl_runtime_pltresolve\n\
00357        .previous\n\
00358 ");
00359