Back to index

glibc  2.9
dl-reloc.c
Go to the documentation of this file.
00001 /* Relocate a shared object and resolve its references to other loaded objects.
00002    Copyright (C) 1995-2004, 2005, 2006, 2008 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 #include <errno.h>
00021 #include <libintl.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <ldsodefs.h>
00025 #include <sys/mman.h>
00026 #include <sys/param.h>
00027 #include <sys/types.h>
00028 #include "dynamic-link.h"
00029 
00030 /* Statistics function.  */
00031 #ifdef SHARED
00032 # define bump_num_cache_relocations() ++GL(dl_num_cache_relocations)
00033 #else
00034 # define bump_num_cache_relocations() ((void) 0)
00035 #endif
00036 
00037 
00038 /* We are trying to perform a static TLS relocation in MAP, but it was
00039    dynamically loaded.  This can only work if there is enough surplus in
00040    the static TLS area already allocated for each running thread.  If this
00041    object's TLS segment is too big to fit, we fail.  If it fits,
00042    we set MAP->l_tls_offset and return.
00043    This function intentionally does not return any value but signals error
00044    directly, as static TLS should be rare and code handling it should
00045    not be inlined as much as possible.  */
00046 int
00047 internal_function
00048 _dl_try_allocate_static_tls (struct link_map *map)
00049 {
00050   /* If we've already used the variable with dynamic access, or if the
00051      alignment requirements are too high, fail.  */
00052   if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
00053       || map->l_tls_align > GL(dl_tls_static_align))
00054     {
00055     fail:
00056       return -1;
00057     }
00058 
00059 #if TLS_TCB_AT_TP
00060   size_t freebytes;
00061   size_t n;
00062   size_t blsize;
00063 
00064   freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used) - TLS_TCB_SIZE;
00065 
00066   blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
00067   if (freebytes < blsize)
00068     goto fail;
00069 
00070   n = (freebytes - blsize) / map->l_tls_align;
00071 
00072   size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
00073                                        - map->l_tls_firstbyte_offset);
00074 
00075   map->l_tls_offset = GL(dl_tls_static_used) = offset;
00076 #elif TLS_DTV_AT_TP
00077   size_t used;
00078   size_t check;
00079 
00080   size_t offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
00081   used = offset + map->l_tls_blocksize;
00082   check = used;
00083   /* dl_tls_static_used includes the TCB at the beginning.  */
00084 
00085   if (check > GL(dl_tls_static_size))
00086     goto fail;
00087 
00088   map->l_tls_offset = offset;
00089   GL(dl_tls_static_used) = used;
00090 #else
00091 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
00092 #endif
00093 
00094   /* If the object is not yet relocated we cannot initialize the
00095      static TLS region.  Delay it.  */
00096   if (map->l_real->l_relocated)
00097     {
00098 #ifdef SHARED
00099       if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
00100                          0))
00101        /* Update the slot information data for at least the generation of
00102           the DSO we are allocating data for.  */
00103        (void) _dl_update_slotinfo (map->l_tls_modid);
00104 #endif
00105 
00106       GL(dl_init_static_tls) (map);
00107     }
00108   else
00109     map->l_need_tls_init = 1;
00110 
00111   return 0;
00112 }
00113 
00114 void
00115 internal_function __attribute_noinline__
00116 _dl_allocate_static_tls (struct link_map *map)
00117 {
00118   if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
00119       || _dl_try_allocate_static_tls (map))
00120     {
00121       _dl_signal_error (0, map->l_name, NULL, N_("\
00122 cannot allocate memory in static TLS block"));
00123     }
00124 }
00125 
00126 /* Initialize static TLS area and DTV for current (only) thread.
00127    libpthread implementations should provide their own hook
00128    to handle all threads.  */
00129 void
00130 _dl_nothread_init_static_tls (struct link_map *map)
00131 {
00132 #if TLS_TCB_AT_TP
00133   void *dest = (char *) THREAD_SELF - map->l_tls_offset;
00134 #elif TLS_DTV_AT_TP
00135   void *dest = (char *) THREAD_SELF + map->l_tls_offset + TLS_PRE_TCB_SIZE;
00136 #else
00137 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
00138 #endif
00139 
00140   /* Fill in the DTV slot so that a later LD/GD access will find it.  */
00141   dtv_t *dtv = THREAD_DTV ();
00142   assert (map->l_tls_modid <= dtv[-1].counter);
00143   dtv[map->l_tls_modid].pointer.val = dest;
00144   dtv[map->l_tls_modid].pointer.is_static = true;
00145 
00146   /* Initialize the memory.  */
00147   memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
00148          '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
00149 }
00150 
00151 
00152 void
00153 _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
00154                    int lazy, int consider_profiling)
00155 {
00156   struct textrels
00157   {
00158     caddr_t start;
00159     size_t len;
00160     int prot;
00161     struct textrels *next;
00162   } *textrels = NULL;
00163   /* Initialize it to make the compiler happy.  */
00164   const char *errstring = NULL;
00165 
00166 #ifdef SHARED
00167   /* If we are auditing, install the same handlers we need for profiling.  */
00168   consider_profiling |= GLRO(dl_audit) != NULL;
00169 #elif defined PROF
00170   /* Never use dynamic linker profiling for gprof profiling code.  */
00171 # define consider_profiling 0
00172 #endif
00173 
00174   if (l->l_relocated)
00175     return;
00176 
00177   /* If DT_BIND_NOW is set relocate all references in this object.  We
00178      do not do this if we are profiling, of course.  */
00179   // XXX Correct for auditing?
00180   if (!consider_profiling
00181       && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
00182     lazy = 0;
00183 
00184   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0))
00185     _dl_debug_printf ("\nrelocation processing: %s%s\n",
00186                     l->l_name[0] ? l->l_name : rtld_progname,
00187                     lazy ? " (lazy)" : "");
00188 
00189   /* DT_TEXTREL is now in level 2 and might phase out at some time.
00190      But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
00191      testing easier and therefore it will be available at all time.  */
00192   if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
00193     {
00194       /* Bletch.  We must make read-only segments writable
00195         long enough to relocate them.  */
00196       const ElfW(Phdr) *ph;
00197       for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
00198        if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
00199          {
00200            struct textrels *newp;
00201 
00202            newp = (struct textrels *) alloca (sizeof (*newp));
00203            newp->len = (((ph->p_vaddr + ph->p_memsz + GLRO(dl_pagesize) - 1)
00204                        & ~(GLRO(dl_pagesize) - 1))
00205                       - (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
00206            newp->start = ((ph->p_vaddr & ~(GLRO(dl_pagesize) - 1))
00207                         + (caddr_t) l->l_addr);
00208 
00209            if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
00210              {
00211               errstring = N_("cannot make segment writable for relocation");
00212              call_error:
00213               _dl_signal_error (errno, l->l_name, NULL, errstring);
00214              }
00215 
00216 #if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
00217            newp->prot = (PF_TO_PROT
00218                        >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
00219 #else
00220            newp->prot = 0;
00221            if (ph->p_flags & PF_R)
00222              newp->prot |= PROT_READ;
00223            if (ph->p_flags & PF_W)
00224              newp->prot |= PROT_WRITE;
00225            if (ph->p_flags & PF_X)
00226              newp->prot |= PROT_EXEC;
00227 #endif
00228            newp->next = textrels;
00229            textrels = newp;
00230          }
00231     }
00232 
00233   {
00234     /* Do the actual relocation of the object's GOT and other data.  */
00235 
00236     /* String table object symbols.  */
00237     const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
00238 
00239     /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
00240 #define RESOLVE_MAP(ref, version, r_type) \
00241     (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL                           \
00242      ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0)              \
00243         && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class)  \
00244        ? (bump_num_cache_relocations (),                             \
00245           (*ref) = l->l_lookup_cache.ret,                            \
00246           l->l_lookup_cache.value)                                   \
00247        : ({ lookup_t _lr;                                            \
00248             int _tc = elf_machine_type_class (r_type);                      \
00249             l->l_lookup_cache.type_class = _tc;                      \
00250             l->l_lookup_cache.sym = (*ref);                                 \
00251             const struct r_found_version *v = NULL;                         \
00252             int flags = DL_LOOKUP_ADD_DEPENDENCY;                           \
00253             if ((version) != NULL && (version)->hash != 0)                  \
00254               {                                                      \
00255                v = (version);                                               \
00256                flags = 0;                                            \
00257               }                                                      \
00258             _lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref),   \
00259                                    scope, v, _tc, flags, NULL);             \
00260             l->l_lookup_cache.ret = (*ref);                                 \
00261             l->l_lookup_cache.value = _lr; }))                              \
00262      : l)
00263 
00264 #include "dynamic-link.h"
00265 
00266     ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);
00267 
00268 #ifndef PROF
00269     if (__builtin_expect (consider_profiling, 0))
00270       {
00271        /* Allocate the array which will contain the already found
00272           relocations.  If the shared object lacks a PLT (for example
00273           if it only contains lead function) the l_info[DT_PLTRELSZ]
00274           will be NULL.  */
00275        if (l->l_info[DT_PLTRELSZ] == NULL)
00276          {
00277            errstring = N_("%s: no PLTREL found in object %s\n");
00278          fatal:
00279            _dl_fatal_printf (errstring,
00280                            rtld_progname ?: "<program name unknown>",
00281                            l->l_name);
00282          }
00283 
00284        l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
00285                                 l->l_info[DT_PLTRELSZ]->d_un.d_val);
00286        if (l->l_reloc_result == NULL)
00287          {
00288            errstring = N_("\
00289 %s: out of memory to store relocation results for %s\n");
00290            goto fatal;
00291          }
00292       }
00293 #endif
00294   }
00295 
00296   /* Mark the object so we know this work has been done.  */
00297   l->l_relocated = 1;
00298 
00299   /* Undo the segment protection changes.  */
00300   while (__builtin_expect (textrels != NULL, 0))
00301     {
00302       if (__mprotect (textrels->start, textrels->len, textrels->prot) < 0)
00303        {
00304          errstring = N_("cannot restore segment prot after reloc");
00305          goto call_error;
00306        }
00307 
00308       textrels = textrels->next;
00309     }
00310 
00311   /* In case we can protect the data now that the relocations are
00312      done, do it.  */
00313   if (l->l_relro_size != 0)
00314     _dl_protect_relro (l);
00315 }
00316 
00317 
00318 void internal_function
00319 _dl_protect_relro (struct link_map *l)
00320 {
00321   ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
00322                     & ~(GLRO(dl_pagesize) - 1));
00323   ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
00324                   & ~(GLRO(dl_pagesize) - 1));
00325 
00326   if (start != end
00327       && __mprotect ((void *) start, end - start, PROT_READ) < 0)
00328     {
00329       static const char errstring[] = N_("\
00330 cannot apply additional memory protection after relocation");
00331       _dl_signal_error (errno, l->l_name, NULL, errstring);
00332     }
00333 }
00334 
00335 void
00336 internal_function __attribute_noinline__
00337 _dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt)
00338 {
00339   extern const char INTUSE(_itoa_lower_digits)[] attribute_hidden;
00340 #define DIGIT(b)     INTUSE(_itoa_lower_digits)[(b) & 0xf];
00341 
00342   /* XXX We cannot translate these messages.  */
00343   static const char msg[2][32
00344 #if __ELF_NATIVE_CLASS == 64
00345                         + 6
00346 #endif
00347   ] = { "unexpected reloc type 0x",
00348        "unexpected PLT reloc type 0x" };
00349   char msgbuf[sizeof (msg[0])];
00350   char *cp;
00351 
00352   cp = __stpcpy (msgbuf, msg[plt]);
00353 #if __ELF_NATIVE_CLASS == 64
00354   if (__builtin_expect(type > 0xff, 0))
00355     {
00356       *cp++ = DIGIT (type >> 28);
00357       *cp++ = DIGIT (type >> 24);
00358       *cp++ = DIGIT (type >> 20);
00359       *cp++ = DIGIT (type >> 16);
00360       *cp++ = DIGIT (type >> 12);
00361       *cp++ = DIGIT (type >> 8);
00362     }
00363 #endif
00364   *cp++ = DIGIT (type >> 4);
00365   *cp++ = DIGIT (type);
00366   *cp = '\0';
00367 
00368   _dl_signal_error (0, map->l_name, NULL, msgbuf);
00369 }