Back to index

glibc  2.9
dl-fini.c
Go to the documentation of this file.
00001 /* Call the termination functions of loaded shared objects.
00002    Copyright (C) 1995,96,1998-2002,2004, 2005 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 <alloca.h>
00021 #include <assert.h>
00022 #include <string.h>
00023 #include <ldsodefs.h>
00024 
00025 
00026 /* Type of the constructor functions.  */
00027 typedef void (*fini_t) (void);
00028 
00029 
00030 void
00031 internal_function
00032 _dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps,
00033               char *used, Lmid_t ns)
00034 {
00035   if (ns == LM_ID_BASE)
00036     /* The main executable always comes first.  */
00037     l = l->l_next;
00038 
00039   for (; l != NULL; l = l->l_next)
00040     /* Do not handle ld.so in secondary namespaces and object which
00041        are not removed.  */
00042     if (l == l->l_real && l->l_idx != -1)
00043       {
00044        /* Find the place in the 'maps' array.  */
00045        unsigned int j;
00046        for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
00047          assert (j < nmaps);
00048 
00049        /* Find all object for which the current one is a dependency
00050           and move the found object (if necessary) in front.  */
00051        for (unsigned int k = j + 1; k < nmaps; ++k)
00052          {
00053            struct link_map **runp = maps[k]->l_initfini;
00054            if (runp != NULL)
00055              {
00056               while (*runp != NULL)
00057                 if (*runp == l)
00058                   {
00059                     struct link_map *here = maps[k];
00060 
00061                     /* Move it now.  */
00062                     memmove (&maps[j] + 1,
00063                             &maps[j], (k - j) * sizeof (struct link_map *));
00064                     maps[j] = here;
00065 
00066                     if (used != NULL)
00067                      {
00068                        char here_used = used[k];
00069 
00070                        memmove (&used[j] + 1,
00071                                &used[j], (k - j) * sizeof (char));
00072                        used[j] = here_used;
00073                      }
00074 
00075                     ++j;
00076 
00077                     break;
00078                   }
00079                 else
00080                   ++runp;
00081              }
00082 
00083            if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
00084              {
00085               unsigned int m = maps[k]->l_reldeps->act;
00086               struct link_map **relmaps = &maps[k]->l_reldeps->list[0];
00087 
00088               while (m-- > 0)
00089                 {
00090                   if (relmaps[m] == l)
00091                     {
00092                      struct link_map *here = maps[k];
00093 
00094                      /* Move it now.  */
00095                      memmove (&maps[j] + 1,
00096                              &maps[j],
00097                              (k - j) * sizeof (struct link_map *));
00098                      maps[j] = here;
00099 
00100                      if (used != NULL)
00101                        {
00102                          char here_used = used[k];
00103 
00104                          memmove (&used[j] + 1,
00105                                  &used[j], (k - j) * sizeof (char));
00106                          used[j] = here_used;
00107                        }
00108 
00109                      break;
00110                     }
00111                 }
00112              }
00113          }
00114       }
00115 }
00116 
00117 
00118 void
00119 internal_function
00120 _dl_fini (void)
00121 {
00122   /* Lots of fun ahead.  We have to call the destructors for all still
00123      loaded objects, in all namespaces.  The problem is that the ELF
00124      specification now demands that dependencies between the modules
00125      are taken into account.  I.e., the destructor for a module is
00126      called before the ones for any of its dependencies.
00127 
00128      To make things more complicated, we cannot simply use the reverse
00129      order of the constructors.  Since the user might have loaded objects
00130      using `dlopen' there are possibly several other modules with its
00131      dependencies to be taken into account.  Therefore we have to start
00132      determining the order of the modules once again from the beginning.  */
00133   struct link_map **maps = NULL;
00134   size_t maps_size = 0;
00135 
00136   /* We run the destructors of the main namespaces last.  As for the
00137      other namespaces, we pick run the destructors in them in reverse
00138      order of the namespace ID.  */
00139 #ifdef SHARED
00140   int do_audit = 0;
00141  again:
00142 #endif
00143   for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
00144     {
00145       /* Protect against concurrent loads and unloads.  */
00146       __rtld_lock_lock_recursive (GL(dl_load_lock));
00147 
00148       unsigned int nmaps = 0;
00149       unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
00150       /* No need to do anything for empty namespaces or those used for
00151         auditing DSOs.  */
00152       if (nloaded == 0
00153 #ifdef SHARED
00154          || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
00155 #endif
00156          )
00157        goto out;
00158 
00159       /* XXX Could it be (in static binaries) that there is no object
00160         loaded?  */
00161       assert (ns != LM_ID_BASE || nloaded > 0);
00162 
00163       /* Now we can allocate an array to hold all the pointers and copy
00164         the pointers in.  */
00165       if (maps_size < nloaded * sizeof (struct link_map *))
00166        {
00167          if (maps_size == 0)
00168            {
00169              maps_size = nloaded * sizeof (struct link_map *);
00170              maps = (struct link_map **) alloca (maps_size);
00171            }
00172          else
00173            maps = (struct link_map **)
00174              extend_alloca (maps, maps_size,
00175                           nloaded * sizeof (struct link_map *));
00176        }
00177 
00178       unsigned int i;
00179       struct link_map *l;
00180       assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
00181       for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
00182        /* Do not handle ld.so in secondary namespaces.  */
00183        if (l == l->l_real)
00184          {
00185            assert (i < nloaded);
00186 
00187            maps[i] = l;
00188            l->l_idx = i;
00189            ++i;
00190 
00191            /* Bump l_direct_opencount of all objects so that they are
00192               not dlclose()ed from underneath us.  */
00193            ++l->l_direct_opencount;
00194          }
00195       assert (ns != LM_ID_BASE || i == nloaded);
00196       assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
00197       nmaps = i;
00198 
00199       if (nmaps != 0)
00200        /* Now we have to do the sorting.  */
00201        _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);
00202 
00203       /* We do not rely on the linked list of loaded object anymore from
00204         this point on.  We have our own list here (maps).  The various
00205         members of this list cannot vanish since the open count is too
00206         high and will be decremented in this loop.  So we release the
00207         lock so that some code which might be called from a destructor
00208         can directly or indirectly access the lock.  */
00209     out:
00210       __rtld_lock_unlock_recursive (GL(dl_load_lock));
00211 
00212       /* 'maps' now contains the objects in the right order.  Now call the
00213         destructors.  We have to process this array from the front.  */
00214       for (i = 0; i < nmaps; ++i)
00215        {
00216          l = maps[i];
00217 
00218          if (l->l_init_called)
00219            {
00220              /* Make sure nothing happens if we are called twice.  */
00221              l->l_init_called = 0;
00222 
00223              /* Is there a destructor function?  */
00224              if (l->l_info[DT_FINI_ARRAY] != NULL
00225                 || l->l_info[DT_FINI] != NULL)
00226               {
00227                 /* When debugging print a message first.  */
00228                 if (__builtin_expect (GLRO(dl_debug_mask)
00229                                    & DL_DEBUG_IMPCALLS, 0))
00230                   _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
00231                                   l->l_name[0] ? l->l_name : rtld_progname,
00232                                   ns);
00233 
00234                 /* First see whether an array is given.  */
00235                 if (l->l_info[DT_FINI_ARRAY] != NULL)
00236                   {
00237                     ElfW(Addr) *array =
00238                      (ElfW(Addr) *) (l->l_addr
00239                                    + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
00240                     unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
00241                                    / sizeof (ElfW(Addr)));
00242                     while (i-- > 0)
00243                      ((fini_t) array[i]) ();
00244                   }
00245 
00246                 /* Next try the old-style destructor.  */
00247                 if (l->l_info[DT_FINI] != NULL)
00248                   ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
00249               }
00250 
00251 #ifdef SHARED
00252              /* Auditing checkpoint: another object closed.  */
00253              if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0))
00254               {
00255                 struct audit_ifaces *afct = GLRO(dl_audit);
00256                 for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
00257                   {
00258                     if (afct->objclose != NULL)
00259                      /* Return value is ignored.  */
00260                      (void) afct->objclose (&l->l_audit[cnt].cookie);
00261 
00262                     afct = afct->next;
00263                   }
00264               }
00265 #endif
00266            }
00267 
00268          /* Correct the previous increment.  */
00269          --l->l_direct_opencount;
00270        }
00271     }
00272 
00273 #ifdef SHARED
00274   if (! do_audit && GLRO(dl_naudit) > 0)
00275     {
00276       do_audit = 1;
00277       goto again;
00278     }
00279 
00280   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
00281     _dl_debug_printf ("\nruntime linker statistics:\n"
00282                     "           final number of relocations: %lu\n"
00283                     "final number of relocations from cache: %lu\n",
00284                     GL(dl_num_relocations),
00285                     GL(dl_num_cache_relocations));
00286 #endif
00287 }