Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  MIPS version.
00002    Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007
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 #ifndef dl_machine_h
00024 #define dl_machine_h
00025 
00026 #define ELF_MACHINE_NAME "MIPS"
00027 
00028 #include <entry.h>
00029 
00030 #ifndef ENTRY_POINT
00031 #error ENTRY_POINT needs to be defined for MIPS.
00032 #endif
00033 
00034 #include <sgidefs.h>
00035 #include <sys/asm.h>
00036 #include <dl-tls.h>
00037 
00038 /* The offset of gp from GOT might be system-dependent.  It's set by
00039    ld.  The same value is also */
00040 #define OFFSET_GP_GOT 0x7ff0
00041 
00042 #ifndef _RTLD_PROLOGUE
00043 # define _RTLD_PROLOGUE(entry)                                        \
00044        ".globl\t" __STRING(entry) "\n\t"                       \
00045        ".ent\t" __STRING(entry) "\n\t"                                \
00046        ".type\t" __STRING(entry) ", @function\n"               \
00047        __STRING(entry) ":\n\t"
00048 #endif
00049 
00050 #ifndef _RTLD_EPILOGUE
00051 # define _RTLD_EPILOGUE(entry)                                        \
00052        ".end\t" __STRING(entry) "\n\t"                                \
00053        ".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
00054 #endif
00055 
00056 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
00057    This only makes sense on MIPS when using PLTs, so choose the
00058    PLT relocation (not encountered when not using PLTs).  */
00059 #define ELF_MACHINE_JMP_SLOT                     R_MIPS_JUMP_SLOT
00060 #define elf_machine_type_class(type) \
00061   ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)    \
00062    | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
00063 
00064 #define ELF_MACHINE_PLT_REL 1
00065 
00066 /* Translate a processor specific dynamic tag to the index
00067    in l_info array.  */
00068 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
00069 
00070 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
00071    with the run-time address of the r_debug structure  */
00072 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
00073 do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
00074        *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
00075        (ElfW(Addr)) (r); \
00076    } while (0)
00077 
00078 /* Allow ABIVERSION == 1, meaning PLTs and copy relocations are
00079    required.  */
00080 #define VALID_ELF_ABIVERSION(ver)  (ver == 0 || ver == 2)
00081 #define VALID_ELF_OSABI(osabi)            (osabi == ELFOSABI_SYSV)
00082 #define VALID_ELF_HEADER(hdr,exp,size) \
00083   memcmp (hdr,exp,size-2) == 0 \
00084   && VALID_ELF_OSABI (hdr[EI_OSABI]) \
00085   && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
00086 
00087 /* Return nonzero iff ELF header is compatible with the running host.  */
00088 static inline int __attribute_used__
00089 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
00090 {
00091 #if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
00092   /* Don't link o32 and n32 together.  */
00093   if (((ehdr->e_flags & EF_MIPS_ABI2) != 0) != (_MIPS_SIM == _ABIN32))
00094     return 0;
00095 #endif
00096 
00097   switch (ehdr->e_machine)
00098     {
00099     case EM_MIPS:
00100     case EM_MIPS_RS3_LE:
00101       return 1;
00102     default:
00103       return 0;
00104     }
00105 }
00106 
00107 static inline ElfW(Addr) *
00108 elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
00109 {
00110   /* FIXME: the offset of gp from GOT may be system-dependent. */
00111   return (ElfW(Addr) *) (gpreg - OFFSET_GP_GOT);
00112 }
00113 
00114 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00115    first element of the GOT.  This must be inlined in a function which
00116    uses global data.  We assume its $gp points to the primary GOT.  */
00117 static inline ElfW(Addr)
00118 elf_machine_dynamic (void)
00119 {
00120   register ElfW(Addr) gp __asm__ ("$28");
00121   return *elf_mips_got_from_gpreg (gp);
00122 }
00123 
00124 #define STRINGXP(X) __STRING(X)
00125 #define STRINGXV(X) STRINGV_(X)
00126 #define STRINGV_(...) # __VA_ARGS__
00127 
00128 /* Return the run-time load address of the shared object.  */
00129 static inline ElfW(Addr)
00130 elf_machine_load_address (void)
00131 {
00132   ElfW(Addr) addr;
00133   asm ("      .set noreorder\n"
00134        "      " STRINGXP (PTR_LA) " %0, 0f\n"
00135        "      bltzal $0, 0f\n"
00136        "      nop\n"
00137        "0:    " STRINGXP (PTR_SUBU) " %0, $31, %0\n"
00138        "      .set reorder\n"
00139        :      "=r" (addr)
00140        :      /* No inputs */
00141        :      "$31");
00142   return addr;
00143 }
00144 
00145 /* The MSB of got[1] of a gnu object is set to identify gnu objects.  */
00146 #if _MIPS_SIM == _ABI64
00147 # define ELF_MIPS_GNU_GOT1_MASK    0x8000000000000000L
00148 #else
00149 # define ELF_MIPS_GNU_GOT1_MASK    0x80000000L
00150 #endif
00151 
00152 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
00153    fiddles with global data.  */
00154 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)                   \
00155 do {                                                           \
00156   struct link_map *map = &bootstrap_map;                       \
00157   ElfW(Sym) *sym;                                              \
00158   ElfW(Addr) *got;                                             \
00159   int i, n;                                                    \
00160                                                                \
00161   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);                \
00162                                                                \
00163   if (__builtin_expect (map->l_addr == 0, 1))                         \
00164     break;                                                     \
00165                                                                \
00166   /* got[0] is reserved. got[1] is also reserved for the dynamic object      \
00167      generated by gnu ld. Skip these reserved entries from            \
00168      relocation.  */                                           \
00169   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;                       \
00170   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;                 \
00171                                                                \
00172   /* Add the run-time displacement to all local got entries. */              \
00173   while (i < n)                                                       \
00174     got[i++] += map->l_addr;                                          \
00175                                                                \
00176   /* Handle global got entries. */                             \
00177   got += n;                                                    \
00178   sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB])                   \
00179        + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;                   \
00180   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val                    \
00181        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);                  \
00182                                                                \
00183   while (i--)                                                  \
00184     {                                                          \
00185       if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)  \
00186        *got = map->l_addr + sym->st_value;                            \
00187       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC               \
00188               && *got != sym->st_value)                        \
00189        *got += map->l_addr;                                    \
00190       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)           \
00191        {                                                       \
00192          if (sym->st_other == 0)                               \
00193            *got += map->l_addr;                                \
00194        }                                                       \
00195       else                                                     \
00196        *got = map->l_addr + sym->st_value;                            \
00197                                                                \
00198       got++;                                                   \
00199       sym++;                                                   \
00200     }                                                          \
00201 } while(0)
00202 
00203 
00204 /* Mask identifying addresses reserved for the user program,
00205    where the dynamic linker should not map anything.  */
00206 #define ELF_MACHINE_USER_ADDRESS_MASK     0x80000000UL
00207 
00208 
00209 /* Initial entry point code for the dynamic linker.
00210    The C function `_dl_start' is the real entry point;
00211    its return value is the user program's entry point.
00212    Note how we have to be careful about two things:
00213 
00214    1) That we allocate a minimal stack of 24 bytes for
00215       every function call, the MIPS ABI states that even
00216       if all arguments are passed in registers the procedure
00217       called can use the 16 byte area pointed to by $sp
00218       when it is called to store away the arguments passed
00219       to it.
00220 
00221    2) That under Linux the entry is named __start
00222       and not just plain _start.  */
00223 
00224 #define RTLD_START asm (\
00225        ".text\n\
00226        " _RTLD_PROLOGUE(ENTRY_POINT) "\
00227        " STRINGXV(SETUP_GPX($25)) "\n\
00228        " STRINGXV(SETUP_GPX64($18,$25)) "\n\
00229        # i386 ABI book says that the first entry of GOT holds\n\
00230        # the address of the dynamic structure. Though MIPS ABI\n\
00231        # doesn't say nothing about this, I emulate this here.\n\
00232        " STRINGXP(PTR_LA) " $4, _DYNAMIC\n\
00233        # Subtract OFFSET_GP_GOT\n\
00234        " STRINGXP(PTR_S) " $4, -0x7ff0($28)\n\
00235        move $4, $29\n\
00236        " STRINGXP(PTR_SUBIU) " $29, 16\n\
00237        \n\
00238        " STRINGXP(PTR_LA) " $8, .Lcoff\n\
00239        bltzal $8, .Lcoff\n\
00240 .Lcoff:       " STRINGXP(PTR_SUBU) " $8, $31, $8\n\
00241        \n\
00242        " STRINGXP(PTR_LA) " $25, _dl_start\n\
00243        " STRINGXP(PTR_ADDU) " $25, $8\n\
00244        jalr $25\n\
00245        \n\
00246        " STRINGXP(PTR_ADDIU) " $29, 16\n\
00247        # Get the value of label '_dl_start_user' in t9 ($25).\n\
00248        " STRINGXP(PTR_LA) " $25, _dl_start_user\n\
00249        " _RTLD_EPILOGUE(ENTRY_POINT) "\
00250        \n\
00251        \n\
00252        " _RTLD_PROLOGUE(_dl_start_user) "\
00253        " STRINGXP(SETUP_GP) "\n\
00254        " STRINGXV(SETUP_GP64($18,_dl_start_user)) "\n\
00255        move $16, $28\n\
00256        # Save the user entry point address in a saved register.\n\
00257        move $17, $2\n\
00258        # See if we were run as a command with the executable file\n\
00259        # name as an extra leading argument.\n\
00260        lw $2, _dl_skip_args\n\
00261        beq $2, $0, 1f\n\
00262        # Load the original argument count.\n\
00263        " STRINGXP(PTR_L) " $4, 0($29)\n\
00264        # Subtract _dl_skip_args from it.\n\
00265        subu $4, $2\n\
00266        # Adjust the stack pointer to skip _dl_skip_args words.\n\
00267        sll $2, " STRINGXP (PTRLOG) "\n\
00268        " STRINGXP(PTR_ADDU) " $29, $2\n\
00269        # Save back the modified argument count.\n\
00270        " STRINGXP(PTR_S) " $4, 0($29)\n\
00271 1:     # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
00272        " STRINGXP(PTR_L) " $4, _rtld_local\n\
00273        " STRINGXP(PTR_L) /* or lw???  fixme */ " $5, 0($29)\n\
00274        " STRINGXP(PTR_LA) " $6, " STRINGXP (PTRSIZE) "($29)\n\
00275        sll $7, $5, " STRINGXP (PTRLOG) "\n\
00276        " STRINGXP(PTR_ADDU) " $7, $7, $6\n\
00277        " STRINGXP(PTR_ADDU) " $7, $7, " STRINGXP (PTRSIZE) " \n\
00278        # Make sure the stack pointer is aligned for _dl_init_internal.\n\
00279        and $2, $29, -2 * " STRINGXP(SZREG) "\n\
00280        " STRINGXP(PTR_S) " $29, -" STRINGXP(SZREG) "($2)\n\
00281        " STRINGXP(PTR_SUBIU) " $29, $2, 32\n\
00282        " STRINGXP(SAVE_GP(16)) "\n\
00283        # Call the function to run the initializers.\n\
00284        jal _dl_init_internal\n\
00285        # Restore the stack pointer for _start.\n\
00286        " STRINGXP(PTR_L)  " $29, 32-" STRINGXP(SZREG) "($29)\n\
00287        # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
00288        " STRINGXP(PTR_LA) " $2, _dl_fini\n\
00289        # Jump to the user entry point.\n\
00290        move $25, $17\n\
00291        jr $25\n\t"\
00292        _RTLD_EPILOGUE(_dl_start_user)\
00293        ".previous"\
00294 );
00295 
00296 /* Names of the architecture-specific auditing callback functions.  */
00297 # if _MIPS_SIM == _ABIO32
00298 #  define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
00299 #  define ARCH_LA_PLTEXIT mips_o32_gnu_pltexit
00300 # elif _MIPS_SIM == _ABIN32
00301 #  define ARCH_LA_PLTENTER mips_n32_gnu_pltenter
00302 #  define ARCH_LA_PLTEXIT mips_n32_gnu_pltexit
00303 # else
00304 #  define ARCH_LA_PLTENTER mips_n64_gnu_pltenter
00305 #  define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
00306 # endif
00307 
00308 /* For a non-writable PLT, rewrite the .got.plt entry at RELOC_ADDR to
00309    point at the symbol with address VALUE.  For a writable PLT, rewrite
00310    the corresponding PLT entry instead.  */
00311 static inline ElfW(Addr)
00312 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00313                      const ElfW(Rel) *reloc,
00314                      ElfW(Addr) *reloc_addr, ElfW(Addr) value)
00315 {
00316   return *reloc_addr = value;
00317 }
00318 
00319 static inline ElfW(Addr)
00320 elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc,
00321                      ElfW(Addr) value)
00322 {
00323   return value;
00324 }
00325 
00326 #endif /* !dl_machine_h */
00327 
00328 #ifdef RESOLVE_MAP
00329 
00330 /* Perform a relocation described by R_INFO at the location pointed to
00331    by RELOC_ADDR.  SYM is the relocation symbol specified by R_INFO and
00332    MAP is the object containing the reloc.  */
00333 
00334 auto inline void
00335 __attribute__ ((always_inline))
00336 elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
00337                  const ElfW(Sym) *sym, const struct r_found_version *version,
00338                  void *reloc_addr, ElfW(Addr) r_addend, int inplace_p)
00339 {
00340   const unsigned long int r_type = ELFW(R_TYPE) (r_info);
00341   ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
00342 
00343 #if !defined RTLD_BOOTSTRAP && !defined SHARED
00344   /* This is defined in rtld.c, but nowhere in the static libc.a;
00345      make the reference weak so static programs can still link.  This
00346      declaration cannot be done when compiling rtld.c (i.e.  #ifdef
00347      RTLD_BOOTSTRAP) because rtld.c contains the common defn for
00348      _dl_rtld_map, which is incompatible with a weak decl in the same
00349      file.  */
00350   weak_extern (GL(dl_rtld_map));
00351 #endif
00352 
00353   switch (r_type)
00354     {
00355 #if defined (USE_TLS) && !defined (RTLD_BOOTSTRAP)
00356 # if _MIPS_SIM == _ABI64
00357     case R_MIPS_TLS_DTPMOD64:
00358     case R_MIPS_TLS_DTPREL64:
00359     case R_MIPS_TLS_TPREL64:
00360 # else
00361     case R_MIPS_TLS_DTPMOD32:
00362     case R_MIPS_TLS_DTPREL32:
00363     case R_MIPS_TLS_TPREL32:
00364 # endif
00365       {
00366        struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00367 
00368        switch (r_type)
00369          {
00370          case R_MIPS_TLS_DTPMOD64:
00371          case R_MIPS_TLS_DTPMOD32:
00372            if (sym_map)
00373              *addr_field = sym_map->l_tls_modid;
00374            break;
00375 
00376          case R_MIPS_TLS_DTPREL64:
00377          case R_MIPS_TLS_DTPREL32:
00378            if (sym)
00379              {
00380               if (inplace_p)
00381                 r_addend = *addr_field;
00382               *addr_field = r_addend + TLS_DTPREL_VALUE (sym);
00383              }
00384            break;
00385 
00386          case R_MIPS_TLS_TPREL32:
00387          case R_MIPS_TLS_TPREL64:
00388            if (sym)
00389              {
00390               CHECK_STATIC_TLS (map, sym_map);
00391               if (inplace_p)
00392                 r_addend = *addr_field;
00393               *addr_field = r_addend + TLS_TPREL_VALUE (sym_map, sym);
00394              }
00395            break;
00396          }
00397 
00398        break;
00399       }
00400 #endif
00401 
00402 #if _MIPS_SIM == _ABI64
00403     case (R_MIPS_64 << 8) | R_MIPS_REL32:
00404 #else
00405     case R_MIPS_REL32:
00406 #endif
00407       {
00408        int symidx = ELFW(R_SYM) (r_info);
00409        ElfW(Addr) reloc_value;
00410 
00411        if (inplace_p)
00412          /* Support relocations on mis-aligned offsets.  */
00413          __builtin_memcpy (&reloc_value, reloc_addr, sizeof (reloc_value));
00414        else
00415          reloc_value = r_addend;
00416 
00417        if (symidx)
00418          {
00419            const ElfW(Word) gotsym
00420              = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
00421 
00422            if ((ElfW(Word))symidx < gotsym)
00423              {
00424               /* This wouldn't work for a symbol imported from other
00425                  libraries for which there's no GOT entry, but MIPS
00426                  requires every symbol referenced in a dynamic
00427                  relocation to have a GOT entry in the primary GOT,
00428                  so we only get here for locally-defined symbols.
00429                  For section symbols, we should *NOT* be adding
00430                  sym->st_value (per the definition of the meaning of
00431                  S in reloc expressions in the ELF64 MIPS ABI),
00432                  since it should have already been added to
00433                  reloc_value by the linker, but older versions of
00434                  GNU ld didn't add it, and newer versions don't emit
00435                  useless relocations to section symbols any more, so
00436                  it is safe to keep on adding sym->st_value, even
00437                  though it's not ABI compliant.  Some day we should
00438                  bite the bullet and stop doing this.  */
00439 #ifndef RTLD_BOOTSTRAP
00440               if (map != &GL(dl_rtld_map))
00441 #endif
00442                 reloc_value += sym->st_value + map->l_addr;
00443              }
00444            else
00445              {
00446 #ifndef RTLD_BOOTSTRAP
00447               const ElfW(Addr) *got
00448                 = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
00449               const ElfW(Word) local_gotno
00450                 = (const ElfW(Word))
00451                   map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
00452 
00453               reloc_value += got[symidx + local_gotno - gotsym];
00454 #endif
00455              }
00456          }
00457        else
00458 #ifndef RTLD_BOOTSTRAP
00459          if (map != &GL(dl_rtld_map))
00460 #endif
00461            reloc_value += map->l_addr;
00462 
00463        __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
00464       }
00465       break;
00466 #ifndef RTLD_BOOTSTRAP
00467 #if _MIPS_SIM == _ABI64
00468     case (R_MIPS_64 << 8) | R_MIPS_GLOB_DAT:
00469 #else
00470     case R_MIPS_GLOB_DAT:
00471 #endif
00472       {
00473        int symidx = ELFW(R_SYM) (r_info);
00474        const ElfW(Word) gotsym
00475          = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
00476 
00477        if (__builtin_expect ((ElfW(Word)) symidx >= gotsym, 1))
00478          {
00479            const ElfW(Addr) *got
00480              = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
00481            const ElfW(Word) local_gotno
00482              = ((const ElfW(Word))
00483                map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val);
00484 
00485            ElfW(Addr) reloc_value = got[symidx + local_gotno - gotsym];
00486            __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
00487          }
00488       }
00489       break;
00490 #endif
00491     case R_MIPS_NONE:              /* Alright, Wilbur.  */
00492       break;
00493 
00494     case R_MIPS_JUMP_SLOT:
00495       {
00496        struct link_map *sym_map;
00497        ElfW(Addr) value;
00498 
00499        /* The addend for a jump slot relocation must always be zero:
00500           calls via the PLT always branch to the symbol's address and
00501           not to the address plus a non-zero offset.  */
00502        if (r_addend != 0)
00503          _dl_signal_error (0, map->l_name, NULL,
00504                          "found jump slot relocation with non-zero addend");
00505 
00506        sym_map = RESOLVE_MAP (&sym, version, r_type);
00507        value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00508        *addr_field = value;
00509 
00510        break;
00511       }
00512 
00513     case R_MIPS_COPY:
00514       {
00515        const ElfW(Sym) *const refsym = sym;
00516        struct link_map *sym_map;
00517        ElfW(Addr) value;
00518 
00519        /* Calculate the address of the symbol.  */
00520        sym_map = RESOLVE_MAP (&sym, version, r_type);
00521        value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00522 
00523        if (__builtin_expect (sym == NULL, 0))
00524          /* This can happen in trace mode if an object could not be
00525             found.  */
00526          break;
00527        if (__builtin_expect (sym->st_size > refsym->st_size, 0)
00528            || (__builtin_expect (sym->st_size < refsym->st_size, 0)
00529               && GLRO(dl_verbose)))
00530          {
00531            const char *strtab;
00532 
00533            strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00534            _dl_error_printf ("\
00535   %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00536                            rtld_progname ?: "<program name unknown>",
00537                            strtab + refsym->st_name);
00538          }
00539        memcpy (reloc_addr, (void *) value,
00540                MIN (sym->st_size, refsym->st_size));
00541        break;
00542       }
00543 
00544 #if _MIPS_SIM == _ABI64
00545     case R_MIPS_64:
00546       /* For full compliance with the ELF64 ABI, one must precede the
00547         _REL32/_64 pair of relocations with a _64 relocation, such
00548         that the in-place addend is read as a 64-bit value.  IRIX
00549         didn't pick up on this requirement, so we treat the
00550         _REL32/_64 relocation as a 64-bit relocation even if it's by
00551         itself.  For ABI compliance, we ignore such _64 dummy
00552         relocations.  For RELA, this may be simply removed, since
00553         it's totally unnecessary.  */
00554       if (ELFW(R_SYM) (r_info) == 0)
00555        break;
00556       /* Fall through.  */
00557 #endif
00558     default:
00559       _dl_reloc_bad_type (map, r_type, 0);
00560       break;
00561     }
00562 }
00563 
00564 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00565    MAP is the object containing the reloc.  */
00566 
00567 auto inline void
00568 __attribute__ ((always_inline))
00569 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
00570                const ElfW(Sym) *sym, const struct r_found_version *version,
00571                void *const reloc_addr)
00572 {
00573   elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1);
00574 }
00575 
00576 auto inline void
00577 __attribute__((always_inline))
00578 elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
00579                        void *const reloc_addr)
00580 {
00581   /* XXX Nothing to do.  There is no relative relocation, right?  */
00582 }
00583 
00584 auto inline void
00585 __attribute__((always_inline))
00586 elf_machine_lazy_rel (struct link_map *map,
00587                     ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
00588 {
00589   ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00590   const unsigned int r_type = ELFW(R_TYPE) (reloc->r_info);
00591   /* Check for unexpected PLT reloc type.  */
00592   if (__builtin_expect (r_type == R_MIPS_JUMP_SLOT, 1))
00593     {
00594       if (__builtin_expect (map->l_mach.plt, 0) == 0)
00595        {
00596          /* Nothing is required here since we only support lazy
00597             relocation in executables.  */
00598        }
00599       else
00600        *reloc_addr = map->l_mach.plt;
00601     }
00602   else
00603     _dl_reloc_bad_type (map, r_type, 1);
00604 }
00605 
00606 auto inline void
00607 __attribute__ ((always_inline))
00608 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
00609                 const ElfW(Sym) *sym, const struct r_found_version *version,
00610                void *const reloc_addr)
00611 {
00612   elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr,
00613                    reloc->r_addend, 0);
00614 }
00615 
00616 auto inline void
00617 __attribute__((always_inline))
00618 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
00619                         void *const reloc_addr)
00620 {
00621 }
00622 
00623 #ifndef RTLD_BOOTSTRAP
00624 /* Relocate GOT. */
00625 auto inline void
00626 __attribute__((always_inline))
00627 elf_machine_got_rel (struct link_map *map, int lazy)
00628 {
00629   ElfW(Addr) *got;
00630   ElfW(Sym) *sym;
00631   const ElfW(Half) *vernum;
00632   int i, n, symidx;
00633 
00634 #define RESOLVE_GOTSYM(sym,vernum,sym_index,reloc)                      \
00635     ({                                                           \
00636       const ElfW(Sym) *ref = sym;                                \
00637       const struct r_found_version *version                             \
00638         = vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL;        \
00639       struct link_map *sym_map;                                         \
00640       sym_map = RESOLVE_MAP (&ref, version, reloc);                     \
00641       ref ? sym_map->l_addr + ref->st_value : 0;                 \
00642     })
00643 
00644   if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
00645     vernum = (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
00646   else
00647     vernum = NULL;
00648 
00649   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
00650 
00651   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
00652   /* The dynamic linker's local got entries have already been relocated.  */
00653   if (map != &GL(dl_rtld_map))
00654     {
00655       /* got[0] is reserved. got[1] is also reserved for the dynamic object
00656         generated by gnu ld. Skip these reserved entries from relocation.  */
00657       i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
00658 
00659       /* Add the run-time displacement to all local got entries if
00660          needed.  */
00661       if (__builtin_expect (map->l_addr != 0, 0))
00662        {
00663          while (i < n)
00664            got[i++] += map->l_addr;
00665        }
00666     }
00667 
00668   /* Handle global got entries. */
00669   got += n;
00670   /* Keep track of the symbol index.  */
00671   symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
00672   sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
00673   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
00674        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
00675 
00676   /* This loop doesn't handle Quickstart.  */
00677   while (i--)
00678     {
00679       if (sym->st_shndx == SHN_UNDEF)
00680        {
00681          if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_value
00682              && !(sym->st_other & STO_MIPS_PLT))
00683            {
00684              if (lazy)
00685               *got = sym->st_value + map->l_addr;
00686              else
00687               /* This is a lazy-binding stub, so we don't need the
00688                  canonical address.  */
00689               *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
00690            }
00691          else
00692            *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
00693        }
00694       else if (sym->st_shndx == SHN_COMMON)
00695        *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
00696       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
00697               && *got != sym->st_value)
00698        {
00699          if (lazy)
00700            *got += map->l_addr;
00701          else
00702            /* This is a lazy-binding stub, so we don't need the
00703               canonical address.  */
00704            *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
00705        }
00706       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
00707        {
00708          if (sym->st_other == 0)
00709            *got += map->l_addr;
00710        }
00711       else
00712        *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
00713 
00714       ++got;
00715       ++sym;
00716       ++symidx;
00717     }
00718 
00719 #undef RESOLVE_GOTSYM
00720 }
00721 #endif
00722 
00723 /* Set up the loaded object described by L so its stub function
00724    will jump to the on-demand fixup code __dl_runtime_resolve.  */
00725 
00726 auto inline int
00727 __attribute__((always_inline))
00728 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00729 {
00730 # ifndef RTLD_BOOTSTRAP
00731   ElfW(Addr) *got;
00732   extern void _dl_runtime_resolve (ElfW(Word));
00733   extern void _dl_runtime_pltresolve (void);
00734   extern int _dl_mips_gnu_objects;
00735 
00736   if (lazy)
00737     {
00738       /* The GOT entries for functions have not yet been filled in.
00739         Their initial contents will arrange when called to put an
00740         offset into the .dynsym section in t8, the return address
00741         in t7 and then jump to _GLOBAL_OFFSET_TABLE[0].  */
00742       got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
00743 
00744       /* This function will get called to fix up the GOT entry indicated by
00745         the register t8, and then jump to the resolved address.  */
00746       got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
00747 
00748       /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
00749         of got[1] of a gnu object is set to identify gnu objects.
00750         Where we can store l for non gnu objects? XXX  */
00751       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
00752        got[1] = ((ElfW(Addr)) l | ELF_MIPS_GNU_GOT1_MASK);
00753       else
00754        _dl_mips_gnu_objects = 0;
00755     }
00756 
00757   /* Relocate global offset table.  */
00758   elf_machine_got_rel (l, lazy);
00759 
00760   /* If using PLTs, fill in the first two entries of .got.plt.  */
00761   if (l->l_info[DT_JMPREL] && lazy)
00762     {
00763       ElfW(Addr) *gotplt;
00764       gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_MIPS (PLTGOT)]);
00765       /* If a library is prelinked but we have to relocate anyway,
00766         we have to be able to undo the prelinking of .got.plt.
00767         The prelinker saved the address of .plt for us here.  */
00768       if (gotplt[1])
00769        l->l_mach.plt = gotplt[1] + l->l_addr;
00770       gotplt[0] = (ElfW(Addr)) &_dl_runtime_pltresolve;
00771       gotplt[1] = (ElfW(Addr)) l;
00772     }
00773 
00774 # endif
00775   return lazy;
00776 }
00777 
00778 #endif /* RESOLVE_MAP */