(linenum→info "unix/slp.c:2238")

glibc/2.7/elf/dl-runtime.c

    1: /* On-demand PLT fixup for shared objects.
    2:    Copyright (C) 1995-2006, 2007 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #define IN_DL_RUNTIME 1         /* This can be tested in dl-machine.h.  */
   21: 
   22: #include <alloca.h>
   23: #include <stdlib.h>
   24: #include <unistd.h>
   25: #include <sys/param.h>
   26: #include <ldsodefs.h>
   27: #include <sysdep-cancel.h>
   28: #include "dynamic-link.h"
   29: #include <tls.h>
   30: 
   31: 
   32: #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
   33:     || ELF_MACHINE_NO_REL
   34: # define PLTREL  ElfW(Rela)
   35: #else
   36: # define PLTREL  ElfW(Rel)
   37: #endif
   38: 
   39: #ifndef VERSYMIDX
   40: # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
   41: #endif
   42: 
   43: /* The fixup functions might have need special attributes.  If none
   44:    are provided define the macro as empty.  */
   45: #ifndef ARCH_FIXUP_ATTRIBUTE
   46: # define ARCH_FIXUP_ATTRIBUTE
   47: #endif
   48: 
   49: 
   50: /* This function is called through a special trampoline from the PLT the
   51:    first time each PLT entry is called.  We must perform the relocation
   52:    specified in the PLT of the given shared object, and return the resolved
   53:    function address to the trampoline, which will restart the original call
   54:    to that address.  Future calls will bounce directly from the PLT to the
   55:    function.  */
   56: 
   57: #ifndef ELF_MACHINE_NO_PLT
   58: DL_FIXUP_VALUE_TYPE
   59: __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
   60: _dl_fixup (
   61: # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
   62:            ELF_MACHINE_RUNTIME_FIXUP_ARGS,
   63: # endif
   64:            /* GKM FIXME: Fix trampoline to pass bounds so we can do
   65:               without the `__unbounded' qualifier.  */
   66:            struct link_map *__unbounded l, ElfW(Word) reloc_offset)
   67: {
   68:   const ElfW(Sym) *const symtab
   69:     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
   70:   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
   71: 
   72:   const PLTREL *const reloc
   73:     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
   74:   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
   75:   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
   76:   lookup_t result;
   77:   DL_FIXUP_VALUE_TYPE value;
   78: 
   79:   /* Sanity check that we're really looking at a PLT relocation.  */
   80:   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
   81: 
   82:    /* Look up the target symbol.  If the normal lookup rules are not
   83:       used don't look in the global scope.  */
   84:   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
   85:     {
   86:       const struct r_found_version *version = NULL;
   87: 
   88:       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
   89:         {
   90:           const ElfW(Half) *vernum =
   91:             (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
   92:           ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
   93:           version = &l->l_versions[ndx];
   94:           if (version->hash == 0)
   95:             version = NULL;
   96:         }
   97: 
   98:       /* We need to keep the scope around so do some locking.  This is
   99:          not necessary for objects which cannot be unloaded or when
  100:          we are not using any threads (yet).  */
  101:       int flags = DL_LOOKUP_ADD_DEPENDENCY;
  102:       if (!RTLD_SINGLE_THREAD_P)
  103:         {
  104:           THREAD_GSCOPE_SET_FLAG ();
  105:           flags |= DL_LOOKUP_GSCOPE_LOCK;
  106:         }
  107: 
  108:       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
  109:                                     version, ELF_RTYPE_CLASS_PLT, flags, NULL);
  110: 
  111:       /* We are done with the global scope.  */
  112:       if (!RTLD_SINGLE_THREAD_P)
  113:         THREAD_GSCOPE_RESET_FLAG ();
  114: 
  115:       /* Currently result contains the base load address (or link map)
  116:          of the object that defines sym.  Now add in the symbol
  117:          offset.  */
  118:       value = DL_FIXUP_MAKE_VALUE (result,
  119:                                    sym ? (LOOKUP_VALUE_ADDRESS (result)
  120:                                           + sym->st_value) : 0);
  121:     }
  122:   else
  123:     {
  124:       /* We already found the symbol.  The module (and therefore its load
  125:          address) is also known.  */
  126:       value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
  127:       result = l;
  128:     }
  129: 
  130:   /* And now perhaps the relocation addend.  */
  131:   value = elf_machine_plt_value (l, reloc, value);
  132: 
  133:   /* Finally, fix up the plt itself.  */
  134:   if (__builtin_expect (GLRO(dl_bind_not), 0))
  135:     return value;
  136: 
  137:   return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
  138: }
  139: #endif
  140: 
  141: #if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
  142: 
  143: DL_FIXUP_VALUE_TYPE
  144: __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
  145: _dl_profile_fixup (
  146: #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
  147:                    ELF_MACHINE_RUNTIME_FIXUP_ARGS,
  148: #endif
  149:                    struct link_map *l, ElfW(Word) reloc_offset,
  150:                    ElfW(Addr) retaddr, void *regs, long int *framesizep)
  151: {
  152:   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
  153: 
  154:   /* This is the address in the array where we store the result of previous
  155:      relocations.  */
  156:   struct reloc_result *reloc_result
  157:     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
  158:   DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
  159: 
  160:   DL_FIXUP_VALUE_TYPE value = *resultp;
  161:   if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
  162:     {
  163:       /* This is the first time we have to relocate this object.  */
  164:       const ElfW(Sym) *const symtab
  165:         = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
  166:       const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
  167: 
  168:       const PLTREL *const reloc
  169:         = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
  170:       const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
  171:       const ElfW(Sym) *defsym = refsym;
  172:       lookup_t result;
  173: 
  174:       /* Sanity check that we're really looking at a PLT relocation.  */
  175:       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
  176: 
  177:       /* Look up the target symbol.  If the symbol is marked STV_PROTECTED
  178:          don't look in the global scope.  */
  179:       if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
  180:         {
  181:           const struct r_found_version *version = NULL;
  182: 
  183:           if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
  184:             {
  185:               const ElfW(Half) *vernum =
  186:                 (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
  187:               ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
  188:               version = &l->l_versions[ndx];
  189:               if (version->hash == 0)
  190:                 version = NULL;
  191:             }
  192: 
  193:           /* We need to keep the scope around so do some locking.  This is
  194:              not necessary for objects which cannot be unloaded or when
  195:              we are not using any threads (yet).  */
  196:           int flags = DL_LOOKUP_ADD_DEPENDENCY;
  197:           if (!RTLD_SINGLE_THREAD_P)
  198:             {
  199:               THREAD_GSCOPE_SET_FLAG ();
  200:               flags |= DL_LOOKUP_GSCOPE_LOCK;
  201:             }
  202: 
  203:           result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
  204:                                         &defsym, l->l_scope, version,
  205:                                         ELF_RTYPE_CLASS_PLT, flags, NULL);
  206: 
  207:           /* We are done with the global scope.  */
  208:           if (!RTLD_SINGLE_THREAD_P)
  209:             THREAD_GSCOPE_RESET_FLAG ();
  210: 
  211:           /* Currently result contains the base load address (or link map)
  212:              of the object that defines sym.  Now add in the symbol
  213:              offset.  */
  214:           value = DL_FIXUP_MAKE_VALUE (result,
  215:                                        defsym != NULL
  216:                                        ? LOOKUP_VALUE_ADDRESS (result)
  217:                                          + defsym->st_value : 0);
  218:         }
  219:       else
  220:         {
  221:           /* We already found the symbol.  The module (and therefore its load
  222:              address) is also known.  */
  223:           value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + refsym->st_value);
  224:           result = l;
  225:         }
  226:       /* And now perhaps the relocation addend.  */
  227:       value = elf_machine_plt_value (l, reloc, value);
  228: 
  229: #ifdef SHARED
  230:       /* Auditing checkpoint: we have a new binding.  Provide the
  231:          auditing libraries the possibility to change the value and
  232:          tell us whether further auditing is wanted.  */
  233:       if (defsym != NULL && GLRO(dl_naudit) > 0)
  234:         {
  235:           reloc_result->bound = result;
  236:           /* Compute index of the symbol entry in the symbol table of
  237:              the DSO with the definition.  */
  238:           reloc_result->boundndx = (defsym
  239:                                     - (ElfW(Sym) *) D_PTR (result,
  240:                                                            l_info[DT_SYMTAB]));
  241: 
  242:           /* Determine whether any of the two participating DSOs is
  243:              interested in auditing.  */
  244:           if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
  245:             {
  246:               unsigned int altvalue = 0;
  247:               struct audit_ifaces *afct = GLRO(dl_audit);
  248:               /* Synthesize a symbol record where the st_value field is
  249:                  the result.  */
  250:               ElfW(Sym) sym = *defsym;
  251:               sym.st_value = DL_FIXUP_VALUE_ADDR (value);
  252: 
  253:               /* Keep track whether there is any interest in tracing
  254:                  the call in the lower two bits.  */
  255:               assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
  256:               assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
  257:               reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
  258: 
  259:               const char *strtab2 = (const void *) D_PTR (result,
  260:                                                           l_info[DT_STRTAB]);
  261: 
  262:               for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
  263:                 {
  264:                   /* XXX Check whether both DSOs must request action or
  265:                      only one */
  266:                   if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
  267:                       && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
  268:                     {
  269:                       unsigned int flags = altvalue;
  270:                       if (afct->symbind != NULL)
  271:                         {
  272:                           uintptr_t new_value
  273:                             = afct->symbind (&sym, reloc_result->boundndx,
  274:                                              &l->l_audit[cnt].cookie,
  275:                                              &result->l_audit[cnt].cookie,
  276:                                              &flags,
  277:                                              strtab2 + defsym->st_name);
  278:                           if (new_value != (uintptr_t) sym.st_value)
  279:                             {
  280:                               altvalue = LA_SYMB_ALTVALUE;
  281:                               sym.st_value = new_value;
  282:                             }
  283:                         }
  284: 
  285:                       /* Remember the results for every audit library and
  286:                          store a summary in the first two bits.  */
  287:                       reloc_result->enterexit
  288:                         &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
  289:                       reloc_result->enterexit
  290:                         |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
  291:                             << ((cnt + 1) * 2));
  292:                     }
  293:                   else
  294:                     /* If the bind flags say this auditor is not interested,
  295:                        set the bits manually.  */
  296:                     reloc_result->enterexit
  297:                       |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
  298:                           << ((cnt + 1) * 2));
  299: 
  300:                   afct = afct->next;
  301:                 }
  302: 
  303:               reloc_result->flags = altvalue;
  304:               value = DL_FIXUP_ADDR_VALUE (sym.st_value);
  305:             }
  306:           else
  307:             /* Set all bits since this symbol binding is not interesting.  */
  308:             reloc_result->enterexit = (1u << DL_NNS) - 1;
  309:         }
  310: #endif
  311: 
  312:       /* Store the result for later runs.  */
  313:       if (__builtin_expect (! GLRO(dl_bind_not), 1))
  314:         *resultp = value;
  315:     }
  316: 
  317:   /* By default we do not call the pltexit function.  */
  318:   long int framesize = -1;
  319: 
  320: #ifdef SHARED
  321:   /* Auditing checkpoint: report the PLT entering and allow the
  322:      auditors to change the value.  */
  323:   if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
  324:       /* Don't do anything if no auditor wants to intercept this call.  */
  325:       && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
  326:     {
  327:       ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
  328:                                                 l_info[DT_SYMTAB])
  329:                            + reloc_result->boundndx);
  330: 
  331:       /* Set up the sym parameter.  */
  332:       ElfW(Sym) sym = *defsym;
  333:       sym.st_value = DL_FIXUP_VALUE_ADDR (value);
  334: 
  335:       /* Get the symbol name.  */
  336:       const char *strtab = (const void *) D_PTR (reloc_result->bound,
  337:                                                  l_info[DT_STRTAB]);
  338:       const char *symname = strtab + sym.st_name;
  339: 
  340:       /* Keep track of overwritten addresses.  */
  341:       unsigned int altvalue = reloc_result->flags;
  342: 
  343:       struct audit_ifaces *afct = GLRO(dl_audit);
  344:       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
  345:         {
  346:           if (afct->ARCH_LA_PLTENTER != NULL
  347:               && (reloc_result->enterexit
  348:                   & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
  349:             {
  350:               unsigned int flags = altvalue;
  351:               long int new_framesize = -1;
  352:               uintptr_t new_value
  353:                 = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
  354:                                           &l->l_audit[cnt].cookie,
  355:                                           &reloc_result->bound->l_audit[cnt].cookie,
  356:                                           regs, &flags, symname,
  357:                                           &new_framesize);
  358:               if (new_value != (uintptr_t) sym.st_value)
  359:                 {
  360:                   altvalue = LA_SYMB_ALTVALUE;
  361:                   sym.st_value = new_value;
  362:                 }
  363: 
  364:               /* Remember the results for every audit library and
  365:                  store a summary in the first two bits.  */
  366:               reloc_result->enterexit
  367:                 |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
  368:                     << (2 * (cnt + 1)));
  369: 
  370:               if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
  371:                                               << (2 * (cnt + 1))))
  372:                   == 0 && new_framesize != -1 && framesize != -2)
  373:                 {
  374:                   /* If this is the first call providing information,
  375:                      use it.  */
  376:                   if (framesize == -1)
  377:                     framesize = new_framesize;
  378:                   /* If two pltenter calls provide conflicting information,
  379:                      use the larger value.  */
  380:                   else if (new_framesize != framesize)
  381:                     framesize = MAX (new_framesize, framesize);
  382:                 }
  383:             }
  384: 
  385:           afct = afct->next;
  386:         }
  387: 
  388:       value = DL_FIXUP_ADDR_VALUE (sym.st_value);
  389:     }
  390: #endif
  391: 
  392:   /* Store the frame size information.  */
  393:   *framesizep = framesize;
  394: 
  395:   (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
  396: 
  397:   return value;
  398: }
  399: 
  400: #endif /* PROF && ELF_MACHINE_NO_PLT */
  401: 
  402: 
  403: #include <stdio.h>
  404: void
  405: ARCH_FIXUP_ATTRIBUTE
  406: _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_offset,
  407:                   const void *inregs, void *outregs)
  408: {
  409: #ifdef SHARED
  410:   /* This is the address in the array where we store the result of previous
  411:      relocations.  */
  412:   // XXX Maybe the bound information must be stored on the stack since
  413:   // XXX with bind_not a new value could have been stored in the meantime.
  414:   struct reloc_result *reloc_result
  415:     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
  416:   ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
  417:                                             l_info[DT_SYMTAB])
  418:                        + reloc_result->boundndx);
  419: 
  420:   /* Set up the sym parameter.  */
  421:   ElfW(Sym) sym = *defsym;
  422: 
  423:   /* Get the symbol name.  */
  424:   const char *strtab = (const void *) D_PTR (reloc_result->bound,
  425:                                              l_info[DT_STRTAB]);
  426:   const char *symname = strtab + sym.st_name;
  427: 
  428:   struct audit_ifaces *afct = GLRO(dl_audit);
  429:   for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
  430:     {
  431:       if (afct->ARCH_LA_PLTEXIT != NULL
  432:           && (reloc_result->enterexit
  433:               & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
  434:         {
  435:           afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
  436:                                  &l->l_audit[cnt].cookie,
  437:                                  &reloc_result->bound->l_audit[cnt].cookie,
  438:                                  inregs, outregs, symname);
  439:         }
  440: 
  441:       afct = afct->next;
  442:     }
  443: #endif
  444: }
Syntax (Markdown)