Back to index

glibc  2.9
dl-object.c
Go to the documentation of this file.
00001 /* Storage management for the chain of loaded shared objects.
00002    Copyright (C) 1995-2002,2004,2006,2007,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 <string.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <ldsodefs.h>
00025 
00026 #include <assert.h>
00027 
00028 
00029 /* Allocate a `struct link_map' for a new object being loaded,
00030    and enter it into the _dl_loaded list.  */
00031 
00032 struct link_map *
00033 internal_function
00034 _dl_new_object (char *realname, const char *libname, int type,
00035               struct link_map *loader, int mode, Lmid_t nsid)
00036 {
00037   struct link_map *l;
00038   int idx;
00039   size_t libname_len = strlen (libname) + 1;
00040   struct link_map *new;
00041   struct libname_list *newname;
00042 #ifdef SHARED
00043   /* We create the map for the executable before we know whether we have
00044      auditing libraries and if yes, how many.  Assume the worst.  */
00045   unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
00046                                        ? DL_NNS : 0);
00047   size_t audit_space = naudit * sizeof (new->l_audit[0]);
00048 #else
00049 # define audit_space 0
00050 #endif
00051 
00052   new = (struct link_map *) calloc (sizeof (*new) + audit_space
00053                                 + sizeof (struct link_map *)
00054                                 + sizeof (*newname) + libname_len, 1);
00055   if (new == NULL)
00056     return NULL;
00057 
00058   new->l_real = new;
00059   new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
00060                                                      + audit_space);
00061 
00062   new->l_libname = newname
00063     = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
00064   newname->name = (char *) memcpy (newname + 1, libname, libname_len);
00065   /* newname->next = NULL;  We use calloc therefore not necessary.  */
00066   newname->dont_free = 1;
00067 
00068   new->l_name = realname;
00069   new->l_type = type;
00070   new->l_loader = loader;
00071 #if NO_TLS_OFFSET != 0
00072   new->l_tls_offset = NO_TLS_OFFSET;
00073 #endif
00074   new->l_ns = nsid;
00075 
00076 #ifdef SHARED
00077   for (unsigned int cnt = 0; cnt < naudit; ++cnt)
00078     {
00079       new->l_audit[cnt].cookie = (uintptr_t) new;
00080       /* new->l_audit[cnt].bindflags = 0; */
00081     }
00082 #endif
00083 
00084   /* new->l_global = 0;     We use calloc therefore not necessary.  */
00085 
00086   /* Use the 'l_scope_mem' array by default for the the 'l_scope'
00087      information.  If we need more entries we will allocate a large
00088      array dynamically.  */
00089   new->l_scope = new->l_scope_mem;
00090   new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
00091 
00092   /* Counter for the scopes we have to handle.  */
00093   idx = 0;
00094 
00095   if (GL(dl_ns)[nsid]._ns_loaded != NULL)
00096     {
00097       l = GL(dl_ns)[nsid]._ns_loaded;
00098       while (l->l_next != NULL)
00099        l = l->l_next;
00100       new->l_prev = l;
00101       /* new->l_next = NULL;       Would be necessary but we use calloc.  */
00102       l->l_next = new;
00103 
00104       /* Add the global scope.  */
00105       new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
00106     }
00107   else
00108     GL(dl_ns)[nsid]._ns_loaded = new;
00109   ++GL(dl_ns)[nsid]._ns_nloaded;
00110   new->l_serial = GL(dl_load_adds);
00111   ++GL(dl_load_adds);
00112 
00113   /* If we have no loader the new object acts as it.  */
00114   if (loader == NULL)
00115     loader = new;
00116   else
00117     /* Determine the local scope.  */
00118     while (loader->l_loader != NULL)
00119       loader = loader->l_loader;
00120 
00121   /* Insert the scope if it isn't the global scope we already added.  */
00122   if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
00123     {
00124       if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
00125        {
00126          new->l_scope[1] = new->l_scope[0];
00127          idx = 0;
00128        }
00129 
00130       new->l_scope[idx] = &loader->l_searchlist;
00131     }
00132 
00133   new->l_local_scope[0] = &new->l_searchlist;
00134 
00135   /* Don't try to find the origin for the main map which has the name "".  */
00136   if (realname[0] != '\0')
00137     {
00138       size_t realname_len = strlen (realname) + 1;
00139       char *origin;
00140       char *cp;
00141 
00142       if (realname[0] == '/')
00143        {
00144          /* It is an absolute path.  Use it.  But we have to make a
00145             copy since we strip out the trailing slash.  */
00146          cp = origin = (char *) malloc (realname_len);
00147          if (origin == NULL)
00148            {
00149              origin = (char *) -1;
00150              goto out;
00151            }
00152        }
00153       else
00154        {
00155          size_t len = realname_len;
00156          char *result = NULL;
00157 
00158          /* Get the current directory name.  */
00159          origin = NULL;
00160          do
00161            {
00162              char *new_origin;
00163 
00164              len += 128;
00165              new_origin = (char *) realloc (origin, len);
00166              if (new_origin == NULL)
00167               /* We exit the loop.  Note that result == NULL.  */
00168               break;
00169              origin = new_origin;
00170            }
00171          while ((result = __getcwd (origin, len - realname_len)) == NULL
00172                && errno == ERANGE);
00173 
00174          if (result == NULL)
00175            {
00176              /* We were not able to determine the current directory.
00177                 Note that free(origin) is OK if origin == NULL.  */
00178              free (origin);
00179              origin = (char *) -1;
00180              goto out;
00181            }
00182 
00183          /* Find the end of the path and see whether we have to add a
00184             slash.  We could use rawmemchr but this need not be
00185             fast.  */
00186          cp = (strchr) (origin, '\0');
00187          if (cp[-1] != '/')
00188            *cp++ = '/';
00189        }
00190 
00191       /* Add the real file name.  */
00192       cp = __mempcpy (cp, realname, realname_len);
00193 
00194       /* Now remove the filename and the slash.  Leave the slash if
00195         the name is something like "/foo".  */
00196       do
00197        --cp;
00198       while (*cp != '/');
00199 
00200       if (cp == origin)
00201        /* Keep the only slash which is the first character.  */
00202        ++cp;
00203       *cp = '\0';
00204 
00205     out:
00206       new->l_origin = origin;
00207     }
00208 
00209   return new;
00210 }