Back to index

glibc  2.9
dl-runtime.c
Go to the documentation of this file.
00001 /* On-demand PLT fixup for shared objects.
00002    Copyright (C) 1995-2006, 2007 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 #define IN_DL_RUNTIME 1            /* This can be tested in dl-machine.h.  */
00021 
00022 #include <alloca.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <sys/param.h>
00026 #include <ldsodefs.h>
00027 #include <sysdep-cancel.h>
00028 #include "dynamic-link.h"
00029 #include <tls.h>
00030 
00031 
00032 #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
00033     || ELF_MACHINE_NO_REL
00034 # define PLTREL  ElfW(Rela)
00035 #else
00036 # define PLTREL  ElfW(Rel)
00037 #endif
00038 
00039 #ifndef VERSYMIDX
00040 # define VERSYMIDX(sym)     (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
00041 #endif
00042 
00043 /* The fixup functions might have need special attributes.  If none
00044    are provided define the macro as empty.  */
00045 #ifndef ARCH_FIXUP_ATTRIBUTE
00046 # define ARCH_FIXUP_ATTRIBUTE
00047 #endif
00048 
00049 
00050 /* This function is called through a special trampoline from the PLT the
00051    first time each PLT entry is called.  We must perform the relocation
00052    specified in the PLT of the given shared object, and return the resolved
00053    function address to the trampoline, which will restart the original call
00054    to that address.  Future calls will bounce directly from the PLT to the
00055    function.  */
00056 
00057 #ifndef ELF_MACHINE_NO_PLT
00058 DL_FIXUP_VALUE_TYPE
00059 __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
00060 _dl_fixup (
00061 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
00062           ELF_MACHINE_RUNTIME_FIXUP_ARGS,
00063 # endif
00064           /* GKM FIXME: Fix trampoline to pass bounds so we can do
00065              without the `__unbounded' qualifier.  */
00066           struct link_map *__unbounded l, ElfW(Word) reloc_offset)
00067 {
00068   const ElfW(Sym) *const symtab
00069     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
00070   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
00071 
00072   const PLTREL *const reloc
00073     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
00074   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
00075   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
00076   lookup_t result;
00077   DL_FIXUP_VALUE_TYPE value;
00078 
00079   /* Sanity check that we're really looking at a PLT relocation.  */
00080   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
00081 
00082    /* Look up the target symbol.  If the normal lookup rules are not
00083       used don't look in the global scope.  */
00084   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
00085     {
00086       const struct r_found_version *version = NULL;
00087 
00088       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
00089        {
00090          const ElfW(Half) *vernum =
00091            (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
00092          ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
00093          version = &l->l_versions[ndx];
00094          if (version->hash == 0)
00095            version = NULL;
00096        }
00097 
00098       /* We need to keep the scope around so do some locking.  This is
00099         not necessary for objects which cannot be unloaded or when
00100         we are not using any threads (yet).  */
00101       int flags = DL_LOOKUP_ADD_DEPENDENCY;
00102       if (!RTLD_SINGLE_THREAD_P)
00103        {
00104          THREAD_GSCOPE_SET_FLAG ();
00105          flags |= DL_LOOKUP_GSCOPE_LOCK;
00106        }
00107 
00108       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
00109                                 version, ELF_RTYPE_CLASS_PLT, flags, NULL);
00110 
00111       /* We are done with the global scope.  */
00112       if (!RTLD_SINGLE_THREAD_P)
00113        THREAD_GSCOPE_RESET_FLAG ();
00114 
00115       /* Currently result contains the base load address (or link map)
00116         of the object that defines sym.  Now add in the symbol
00117         offset.  */
00118       value = DL_FIXUP_MAKE_VALUE (result,
00119                                sym ? (LOOKUP_VALUE_ADDRESS (result)
00120                                      + sym->st_value) : 0);
00121     }
00122   else
00123     {
00124       /* We already found the symbol.  The module (and therefore its load
00125         address) is also known.  */
00126       value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
00127       result = l;
00128     }
00129 
00130   /* And now perhaps the relocation addend.  */
00131   value = elf_machine_plt_value (l, reloc, value);
00132 
00133   /* Finally, fix up the plt itself.  */
00134   if (__builtin_expect (GLRO(dl_bind_not), 0))
00135     return value;
00136 
00137   return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
00138 }
00139 #endif
00140 
00141 #if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
00142 
00143 DL_FIXUP_VALUE_TYPE
00144 __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
00145 _dl_profile_fixup (
00146 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
00147                  ELF_MACHINE_RUNTIME_FIXUP_ARGS,
00148 #endif
00149                  struct link_map *l, ElfW(Word) reloc_offset,
00150                  ElfW(Addr) retaddr, void *regs, long int *framesizep)
00151 {
00152   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
00153 
00154   /* This is the address in the array where we store the result of previous
00155      relocations.  */
00156   struct reloc_result *reloc_result
00157     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
00158   DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
00159 
00160   DL_FIXUP_VALUE_TYPE value = *resultp;
00161   if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
00162     {
00163       /* This is the first time we have to relocate this object.  */
00164       const ElfW(Sym) *const symtab
00165        = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
00166       const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
00167 
00168       const PLTREL *const reloc
00169        = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
00170       const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
00171       const ElfW(Sym) *defsym = refsym;
00172       lookup_t result;
00173 
00174       /* Sanity check that we're really looking at a PLT relocation.  */
00175       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
00176 
00177       /* Look up the target symbol.  If the symbol is marked STV_PROTECTED
00178         don't look in the global scope.  */
00179       if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
00180        {
00181          const struct r_found_version *version = NULL;
00182 
00183          if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
00184            {
00185              const ElfW(Half) *vernum =
00186               (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
00187              ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
00188              version = &l->l_versions[ndx];
00189              if (version->hash == 0)
00190               version = NULL;
00191            }
00192 
00193          /* We need to keep the scope around so do some locking.  This is
00194             not necessary for objects which cannot be unloaded or when
00195             we are not using any threads (yet).  */
00196          int flags = DL_LOOKUP_ADD_DEPENDENCY;
00197          if (!RTLD_SINGLE_THREAD_P)
00198            {
00199              THREAD_GSCOPE_SET_FLAG ();
00200              flags |= DL_LOOKUP_GSCOPE_LOCK;
00201            }
00202 
00203          result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
00204                                    &defsym, l->l_scope, version,
00205                                    ELF_RTYPE_CLASS_PLT, flags, NULL);
00206 
00207          /* We are done with the global scope.  */
00208          if (!RTLD_SINGLE_THREAD_P)
00209            THREAD_GSCOPE_RESET_FLAG ();
00210 
00211          /* Currently result contains the base load address (or link map)
00212             of the object that defines sym.  Now add in the symbol
00213             offset.  */
00214          value = DL_FIXUP_MAKE_VALUE (result,
00215                                    defsym != NULL
00216                                    ? LOOKUP_VALUE_ADDRESS (result)
00217                                     + defsym->st_value : 0);
00218        }
00219       else
00220        {
00221          /* We already found the symbol.  The module (and therefore its load
00222             address) is also known.  */
00223          value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + refsym->st_value);
00224          result = l;
00225        }
00226       /* And now perhaps the relocation addend.  */
00227       value = elf_machine_plt_value (l, reloc, value);
00228 
00229 #ifdef SHARED
00230       /* Auditing checkpoint: we have a new binding.  Provide the
00231         auditing libraries the possibility to change the value and
00232         tell us whether further auditing is wanted.  */
00233       if (defsym != NULL && GLRO(dl_naudit) > 0)
00234        {
00235          reloc_result->bound = result;
00236          /* Compute index of the symbol entry in the symbol table of
00237             the DSO with the definition.  */
00238          reloc_result->boundndx = (defsym
00239                                 - (ElfW(Sym) *) D_PTR (result,
00240                                                     l_info[DT_SYMTAB]));
00241 
00242          /* Determine whether any of the two participating DSOs is
00243             interested in auditing.  */
00244          if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
00245            {
00246              unsigned int altvalue = 0;
00247              struct audit_ifaces *afct = GLRO(dl_audit);
00248              /* Synthesize a symbol record where the st_value field is
00249                the result.  */
00250              ElfW(Sym) sym = *defsym;
00251              sym.st_value = DL_FIXUP_VALUE_ADDR (value);
00252 
00253              /* Keep track whether there is any interest in tracing
00254                the call in the lower two bits.  */
00255              assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
00256              assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
00257              reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
00258 
00259              const char *strtab2 = (const void *) D_PTR (result,
00260                                                    l_info[DT_STRTAB]);
00261 
00262              for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
00263               {
00264                 /* XXX Check whether both DSOs must request action or
00265                    only one */
00266                 if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
00267                     && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
00268                   {
00269                     unsigned int flags = altvalue;
00270                     if (afct->symbind != NULL)
00271                      {
00272                        uintptr_t new_value
00273                          = afct->symbind (&sym, reloc_result->boundndx,
00274                                         &l->l_audit[cnt].cookie,
00275                                         &result->l_audit[cnt].cookie,
00276                                         &flags,
00277                                         strtab2 + defsym->st_name);
00278                        if (new_value != (uintptr_t) sym.st_value)
00279                          {
00280                            altvalue = LA_SYMB_ALTVALUE;
00281                            sym.st_value = new_value;
00282                          }
00283                      }
00284 
00285                     /* Remember the results for every audit library and
00286                       store a summary in the first two bits.  */
00287                     reloc_result->enterexit
00288                      &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
00289                     reloc_result->enterexit
00290                      |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
00291                          << ((cnt + 1) * 2));
00292                   }
00293                 else
00294                   /* If the bind flags say this auditor is not interested,
00295                      set the bits manually.  */
00296                   reloc_result->enterexit
00297                     |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
00298                        << ((cnt + 1) * 2));
00299 
00300                 afct = afct->next;
00301               }
00302 
00303              reloc_result->flags = altvalue;
00304              value = DL_FIXUP_ADDR_VALUE (sym.st_value);
00305            }
00306          else
00307            /* Set all bits since this symbol binding is not interesting.  */
00308            reloc_result->enterexit = (1u << DL_NNS) - 1;
00309        }
00310 #endif
00311 
00312       /* Store the result for later runs.  */
00313       if (__builtin_expect (! GLRO(dl_bind_not), 1))
00314        *resultp = value;
00315     }
00316 
00317   /* By default we do not call the pltexit function.  */
00318   long int framesize = -1;
00319 
00320 #ifdef SHARED
00321   /* Auditing checkpoint: report the PLT entering and allow the
00322      auditors to change the value.  */
00323   if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
00324       /* Don't do anything if no auditor wants to intercept this call.  */
00325       && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
00326     {
00327       ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
00328                                           l_info[DT_SYMTAB])
00329                         + reloc_result->boundndx);
00330 
00331       /* Set up the sym parameter.  */
00332       ElfW(Sym) sym = *defsym;
00333       sym.st_value = DL_FIXUP_VALUE_ADDR (value);
00334 
00335       /* Get the symbol name.  */
00336       const char *strtab = (const void *) D_PTR (reloc_result->bound,
00337                                            l_info[DT_STRTAB]);
00338       const char *symname = strtab + sym.st_name;
00339 
00340       /* Keep track of overwritten addresses.  */
00341       unsigned int altvalue = reloc_result->flags;
00342 
00343       struct audit_ifaces *afct = GLRO(dl_audit);
00344       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
00345        {
00346          if (afct->ARCH_LA_PLTENTER != NULL
00347              && (reloc_result->enterexit
00348                 & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
00349            {
00350              unsigned int flags = altvalue;
00351              long int new_framesize = -1;
00352              uintptr_t new_value
00353               = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
00354                                      &l->l_audit[cnt].cookie,
00355                                      &reloc_result->bound->l_audit[cnt].cookie,
00356                                      regs, &flags, symname,
00357                                      &new_framesize);
00358              if (new_value != (uintptr_t) sym.st_value)
00359               {
00360                 altvalue = LA_SYMB_ALTVALUE;
00361                 sym.st_value = new_value;
00362               }
00363 
00364              /* Remember the results for every audit library and
00365                store a summary in the first two bits.  */
00366              reloc_result->enterexit
00367               |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
00368                   << (2 * (cnt + 1)));
00369 
00370              if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
00371                                          << (2 * (cnt + 1))))
00372                 == 0 && new_framesize != -1 && framesize != -2)
00373               {
00374                 /* If this is the first call providing information,
00375                    use it.  */
00376                 if (framesize == -1)
00377                   framesize = new_framesize;
00378                 /* If two pltenter calls provide conflicting information,
00379                    use the larger value.  */
00380                 else if (new_framesize != framesize)
00381                   framesize = MAX (new_framesize, framesize);
00382               }
00383            }
00384 
00385          afct = afct->next;
00386        }
00387 
00388       value = DL_FIXUP_ADDR_VALUE (sym.st_value);
00389     }
00390 #endif
00391 
00392   /* Store the frame size information.  */
00393   *framesizep = framesize;
00394 
00395   (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
00396 
00397   return value;
00398 }
00399 
00400 #endif /* PROF && ELF_MACHINE_NO_PLT */
00401 
00402 
00403 #include <stdio.h>
00404 void
00405 ARCH_FIXUP_ATTRIBUTE
00406 _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_offset,
00407                 const void *inregs, void *outregs)
00408 {
00409 #ifdef SHARED
00410   /* This is the address in the array where we store the result of previous
00411      relocations.  */
00412   // XXX Maybe the bound information must be stored on the stack since
00413   // XXX with bind_not a new value could have been stored in the meantime.
00414   struct reloc_result *reloc_result
00415     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
00416   ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
00417                                        l_info[DT_SYMTAB])
00418                      + reloc_result->boundndx);
00419 
00420   /* Set up the sym parameter.  */
00421   ElfW(Sym) sym = *defsym;
00422 
00423   /* Get the symbol name.  */
00424   const char *strtab = (const void *) D_PTR (reloc_result->bound,
00425                                         l_info[DT_STRTAB]);
00426   const char *symname = strtab + sym.st_name;
00427 
00428   struct audit_ifaces *afct = GLRO(dl_audit);
00429   for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
00430     {
00431       if (afct->ARCH_LA_PLTEXIT != NULL
00432          && (reloc_result->enterexit
00433              & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
00434        {
00435          afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
00436                              &l->l_audit[cnt].cookie,
00437                              &reloc_result->bound->l_audit[cnt].cookie,
00438                              inregs, outregs, symname);
00439        }
00440 
00441       afct = afct->next;
00442     }
00443 #endif
00444 }