OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/gnu-src/newlib-1.17.0/newlib/libc/sys/linux/dl
    from Rev 148 to Rev 158
    Reverse comparison

Rev 148 → Rev 158

/dl-open.c
0,0 → 1,487
/* Load a shared object at runtime, relocate it, and run its initializer.
Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
 
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
 
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <libintl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h> /* Check whether MAP_COPY is defined. */
#include <sys/param.h>
#include <ldsodefs.h>
#include <bp-sym.h>
 
#include <dl-dst.h>
#include <machine/weakalias.h>
 
 
extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry))
weak_function;
 
/* This function is used to unload the cache file if necessary. */
extern void _dl_unload_cache (void);
 
int __libc_argc = 0;
char **__libc_argv = NULL;
 
extern char **environ;
 
extern int _dl_lazy; /* Do we do lazy relocations? */
 
/* Undefine the following for debugging. */
/* #define SCOPE_DEBUG 1 */
#ifdef SCOPE_DEBUG
static void show_scope (struct link_map *new);
#endif
 
extern size_t _dl_platformlen;
 
/* We must be carefull not to leave us in an inconsistent state. Thus we
catch any error and re-raise it after cleaning up. */
 
struct dl_open_args
{
const char *file;
int mode;
const void *caller;
struct link_map *map;
};
 
 
static int
add_to_global (struct link_map *new)
{
struct link_map **new_global;
unsigned int to_add = 0;
unsigned int cnt;
 
/* Count the objects we have to put in the global scope. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
if (new->l_searchlist.r_list[cnt]->l_global == 0)
++to_add;
 
/* The symbols of the new objects and its dependencies are to be
introduced into the global scope that will be used to resolve
references from other dynamically-loaded objects.
 
The global scope is the searchlist in the main link map. We
extend this list if necessary. There is one problem though:
since this structure was allocated very early (before the libc
is loaded) the memory it uses is allocated by the malloc()-stub
in the ld.so. When we come here these functions are not used
anymore. Instead the malloc() implementation of the libc is
used. But this means the block from the main map cannot be used
in an realloc() call. Therefore we allocate a completely new
array the first time we have to add something to the locale scope. */
 
if (_dl_global_scope_alloc == 0)
{
/* This is the first dynamic object given global scope. */
_dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
new_global = (struct link_map **)
malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
if (new_global == NULL)
{
_dl_global_scope_alloc = 0;
nomem:
_dl_signal_error (ENOMEM, new->l_libname->name, NULL,
N_("cannot extend global scope"));
return 1;
}
 
/* Copy over the old entries. */
memcpy (new_global, _dl_main_searchlist->r_list,
(_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
 
_dl_main_searchlist->r_list = new_global;
}
else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
{
/* We have to extend the existing array of link maps in the
main map. */
new_global = (struct link_map **)
realloc (_dl_main_searchlist->r_list,
((_dl_global_scope_alloc + to_add + 8)
* sizeof (struct link_map *)));
if (new_global == NULL)
goto nomem;
 
_dl_global_scope_alloc += to_add + 8;
_dl_main_searchlist->r_list = new_global;
}
 
/* Now add the new entries. */
for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
{
struct link_map *map = new->l_searchlist.r_list[cnt];
 
if (map->l_global == 0)
{
map->l_global = 1;
_dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
++_dl_main_searchlist->r_nlist;
}
}
 
return 0;
}
 
 
static void
dl_open_worker (void *a)
{
struct dl_open_args *args = a;
const char *file = args->file;
int mode = args->mode;
struct link_map *new, *l;
const char *dst;
int lazy;
unsigned int i;
 
/* Maybe we have to expand a DST. */
dst = strchr (file, '$');
if (dst != NULL)
{
const void *caller = args->caller;
size_t len = strlen (file);
size_t required;
struct link_map *call_map;
char *new_file;
 
/* We have to find out from which object the caller is calling. */
call_map = NULL;
for (l = _dl_loaded; l; l = l->l_next)
if (caller >= (const void *) l->l_map_start
&& caller < (const void *) l->l_map_end)
{
/* There must be exactly one DSO for the range of the virtual
memory. Otherwise something is really broken. */
call_map = l;
break;
}
 
if (call_map == NULL)
/* In this case we assume this is the main application. */
call_map = _dl_loaded;
 
/* Determine how much space we need. We have to allocate the
memory locally. */
required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
 
/* Get space for the new file name. */
new_file = (char *) alloca (required + 1);
 
/* Generate the new file name. */
DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
 
/* If the substitution failed don't try to load. */
if (*new_file == '\0')
_dl_signal_error (0, "dlopen", NULL,
N_("empty dynamic string token substitution"));
 
/* Now we have a new file name. */
file = new_file;
}
 
/* Load the named object. */
args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0,
mode);
 
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
set and the object is not already loaded. */
if (new == NULL)
{
assert (mode & RTLD_NOLOAD);
return;
}
 
/* It was already open. */
if (new->l_searchlist.r_list != NULL)
{
/* Let the user know about the opencount. */
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
_dl_debug_printf ("opening file=%s; opencount == %u\n\n",
new->l_name, new->l_opencount);
 
/* If the user requested the object to be in the global namespace
but it is not so far, add it now. */
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
(void) add_to_global (new);
 
/* Increment just the reference counter of the object. */
++new->l_opencount;
 
return;
}
 
/* Load that object's dependencies. */
_dl_map_object_deps (new, NULL, 0, 0);
 
/* So far, so good. Now check the versions. */
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
if (new->l_searchlist.r_list[i]->l_versions == NULL)
(void) _dl_check_map_versions (new->l_searchlist.r_list[i], 0, 0);
 
#ifdef SCOPE_DEBUG
show_scope (new);
#endif
 
/* Only do lazy relocation if `LD_BIND_NOW' is not set. */
lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy;
 
/* Relocate the objects loaded. We do this in reverse order so that copy
relocs of earlier objects overwrite the data written by later objects. */
 
l = new;
while (l->l_next)
l = l->l_next;
while (1)
{
if (! l->l_relocated)
{
#if 0
#ifdef SHARED
if (_dl_profile != NULL)
{
/* If this here is the shared object which we want to profile
make sure the profile is started. We can find out whether
this is necessary or not by observing the `_dl_profile_map'
variable. If was NULL but is not NULL afterwars we must
start the profiling. */
struct link_map *old_profile_map = _dl_profile_map;
 
_dl_relocate_object (l, l->l_scope, 1, 1);
 
if (old_profile_map == NULL && _dl_profile_map != NULL)
/* We must prepare the profiling. */
_dl_start_profile (_dl_profile_map, _dl_profile_output);
}
else
#endif
#endif
_dl_relocate_object (l, l->l_scope, lazy, 0);
}
 
if (l == new)
break;
l = l->l_prev;
}
 
/* Increment the open count for all dependencies. If the file is
not loaded as a dependency here add the search list of the newly
loaded object to the scope. */
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
if (++new->l_searchlist.r_list[i]->l_opencount > 1
&& new->l_searchlist.r_list[i]->l_type == lt_loaded)
{
struct link_map *imap = new->l_searchlist.r_list[i];
struct r_scope_elem **runp = imap->l_scope;
size_t cnt = 0;
 
while (*runp != NULL)
{
/* This can happen if imap was just loaded, but during
relocation had l_opencount bumped because of relocation
dependency. Avoid duplicates in l_scope. */
if (__builtin_expect (*runp == &new->l_searchlist, 0))
break;
 
++cnt;
++runp;
}
 
if (*runp != NULL)
/* Avoid duplicates. */
continue;
 
if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
{
/* The 'r_scope' array is too small. Allocate a new one
dynamically. */
struct r_scope_elem **newp;
size_t new_size = imap->l_scope_max * 2;
 
if (imap->l_scope == imap->l_scope_mem)
{
newp = (struct r_scope_elem **)
malloc (new_size * sizeof (struct r_scope_elem *));
if (newp == NULL)
_dl_signal_error (ENOMEM, "dlopen", NULL,
N_("cannot create scope list"));
imap->l_scope = memcpy (newp, imap->l_scope,
cnt * sizeof (imap->l_scope[0]));
}
else
{
newp = (struct r_scope_elem **)
realloc (imap->l_scope,
new_size * sizeof (struct r_scope_elem *));
if (newp == NULL)
_dl_signal_error (ENOMEM, "dlopen", NULL,
N_("cannot create scope list"));
imap->l_scope = newp;
}
 
imap->l_scope_max = new_size;
}
 
imap->l_scope[cnt++] = &new->l_searchlist;
imap->l_scope[cnt] = NULL;
}
 
/* Run the initializer functions of new objects. */
_dl_init (new, __libc_argc, __libc_argv, environ);
 
/* Now we can make the new map available in the global scope. */
if (mode & RTLD_GLOBAL)
/* Move the object in the global namespace. */
if (add_to_global (new) != 0)
/* It failed. */
return;
 
/* Mark the object as not deletable if the RTLD_NODELETE flags was
passed. */
if (__builtin_expect (mode & RTLD_NODELETE, 0))
new->l_flags_1 |= DF_1_NODELETE;
 
/* Let the user know about the opencount. */
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
_dl_debug_printf ("opening file=%s; opencount == %u\n\n",
new->l_name, new->l_opencount);
}
 
 
void *
internal_function
_dl_open (const char *file, int mode, const void *caller)
{
struct dl_open_args args;
const char *objname;
const char *errstring;
int errcode;
 
if ((mode & RTLD_BINDING_MASK) == 0)
/* One of the flags must be set. */
_dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
 
/* Make sure we are alone. */
#ifdef HAVE_DD_LOCK
__lock_acquire_recursive(_dl_load_lock);
#endif
 
args.file = file;
args.mode = mode;
args.caller = caller;
args.map = NULL;
errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args);
 
#ifndef MAP_COPY
/* We must munmap() the cache file. */
_dl_unload_cache ();
#endif
 
/* Release the lock. */
#ifdef HAVE_DD_LOCK
__lock_release_recursive(_dl_load_lock);
#endif
 
 
if (errstring)
{
/* Some error occurred during loading. */
char *local_errstring;
size_t len_errstring;
 
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
if (args.map)
{
unsigned int i;
 
/* Increment open counters for all objects since this has
not happened yet. */
for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
++args.map->l_searchlist.r_list[i]->l_opencount;
 
_dl_close (args.map);
}
 
/* Make a local copy of the error string so that we can release the
memory allocated for it. */
len_errstring = strlen (errstring) + 1;
if (objname == errstring + len_errstring)
{
size_t total_len = len_errstring + strlen (objname) + 1;
local_errstring = alloca (total_len);
memcpy (local_errstring, errstring, total_len);
objname = local_errstring + len_errstring;
}
else
{
local_errstring = alloca (len_errstring);
memcpy (local_errstring, errstring, len_errstring);
}
 
if (errstring != _dl_out_of_memory)
free ((char *) errstring);
 
/* Reraise the error. */
_dl_signal_error (errcode, objname, NULL, local_errstring);
}
 
#ifndef SHARED
DL_STATIC_INIT (args.map);
#endif
 
return args.map;
}
 
 
#ifdef SCOPE_DEBUG
#include <unistd.h>
 
static void
show_scope (struct link_map *new)
{
int scope_cnt;
 
for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
{
char numbuf[2];
unsigned int cnt;
 
numbuf[0] = '0' + scope_cnt;
numbuf[1] = '\0';
_dl_printf ("scope %s:", numbuf);
 
for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
_dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name);
else
_dl_printf (" <main>");
 
_dl_printf ("\n");
}
}
#endif
dl-open.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-cache.c =================================================================== --- dl-cache.c (nonexistent) +++ dl-cache.c (revision 158) @@ -0,0 +1,271 @@ +/* Support for reading /etc/ld.so.cache files written by Linux ldconfig. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + +extern const char *_dl_platform; + +#ifndef _DL_PLATFORMS_COUNT +# define _DL_PLATFORMS_COUNT 0 +#endif + +/* This is the starting address and the size of the mmap()ed file. */ +static struct cache_file *cache; +static struct cache_file_new *cache_new; +static size_t cachesize; + +/* 1 if cache_data + PTR points into the cache. */ +#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size) + +/* This is the cache ID we expect. Normally it is 3 for glibc linked + binaries. */ +int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID; + +#define SEARCH_CACHE(cache) \ +/* We use binary search since the table is sorted in the cache file. \ + The first matching entry in the table is returned. \ + It is important to use the same algorithm as used while generating \ + the cache file. */ \ +do \ + { \ + left = 0; \ + right = cache->nlibs - 1; \ + \ + while (left <= right) \ + { \ + __typeof__ (cache->libs[0].key) key; \ + \ + middle = (left + right) / 2; \ + \ + key = cache->libs[middle].key; \ + \ + /* Make sure string table indices are not bogus before using \ + them. */ \ + if (! _dl_cache_verify_ptr (key)) \ + { \ + cmpres = 1; \ + break; \ + } \ + \ + /* Actually compare the entry with the key. */ \ + cmpres = _dl_cache_libcmp (name, cache_data + key); \ + if (__builtin_expect (cmpres == 0, 0)) \ + { \ + /* Found it. LEFT now marks the last entry for which we \ + know the name is correct. */ \ + left = middle; \ + \ + /* There might be entries with this name before the one we \ + found. So we have to find the beginning. */ \ + while (middle > 0) \ + { \ + __typeof__ (cache->libs[0].key) key; \ + \ + key = cache->libs[middle - 1].key; \ + /* Make sure string table indices are not bogus before \ + using them. */ \ + if (! _dl_cache_verify_ptr (key) \ + /* Actually compare the entry. */ \ + || _dl_cache_libcmp (name, cache_data + key) != 0) \ + break; \ + --middle; \ + } \ + \ + do \ + { \ + int flags; \ + __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \ + \ + /* Only perform the name test if necessary. */ \ + if (middle > left \ + /* We haven't seen this string so far. Test whether the \ + index is ok and whether the name matches. Otherwise \ + we are done. */ \ + && (! _dl_cache_verify_ptr (lib->key) \ + || (_dl_cache_libcmp (name, cache_data + lib->key) \ + != 0))) \ + break; \ + \ + flags = lib->flags; \ + if (_dl_cache_check_flags (flags) \ + && _dl_cache_verify_ptr (lib->value)) \ + { \ + if (best == NULL || flags == _dl_correct_cache_id) \ + { \ + HWCAP_CHECK; \ + best = cache_data + lib->value; \ + \ + if (flags == _dl_correct_cache_id) \ + /* We've found an exact match for the shared \ + object and no general `ELF' release. Stop \ + searching. */ \ + break; \ + } \ + } \ + } \ + while (++middle <= right); \ + break; \ + } \ + \ + if (cmpres < 0) \ + left = middle + 1; \ + else \ + right = middle - 1; \ + } \ + } \ +while (0) + + + +/* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. */ + +const char * +internal_function +_dl_load_cache_lookup (const char *name) +{ + int left, right, middle; + int cmpres; + const char *cache_data; + uint32_t cache_data_size; + const char *best; + + if (cache == NULL) + { + /* Read the contents of the file. */ + void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, + PROT_READ); + + /* We can handle three different cache file formats here: + - the old libc5/glibc2.0/2.1 format + - the old format with the new format in it + - only the new format + The following checks if the cache contains any of these formats. */ + if (file != MAP_FAILED && cachesize > sizeof *cache + && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0) + { + size_t offset; + /* Looks ok. */ + cache = file; + + /* Check for new version. */ + offset = ALIGN_CACHE (sizeof (struct cache_file) + + cache->nlibs * sizeof (struct file_entry)); + + cache_new = (struct cache_file_new *) ((void *) cache + offset); + if (cachesize < (offset + sizeof (struct cache_file_new)) + || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) + cache_new = (void *) -1; + } + else if (file != MAP_FAILED && cachesize > sizeof *cache_new + && memcmp (file, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) == 0) + { + cache_new = file; + cache = file; + } + else + { + if (file != MAP_FAILED) + munmap (file, cachesize); + cache = (void *) -1; + } + + assert (cache != NULL); + } + + if (cache == (void *) -1) + /* Previously looked for the cache file and didn't find it. */ + return NULL; + + best = NULL; + + if (cache_new != (void *) -1) + { + /* This file ends in static libraries where we don't have a hwcap. */ + unsigned long int *hwcap; + uint64_t platform; + #pragma weak _dl_hwcap + + /* This is where the strings start. */ + cache_data = (const char *) cache_new; + + /* Now we can compute how large the string table is. */ + cache_data_size = (const char *) cache + cachesize - cache_data; + + hwcap = &_dl_hwcap; + platform = _dl_string_platform (_dl_platform); + if (platform != -1) + platform = 1ULL << platform; + + /* Only accept hwcap if it's for the right platform. */ +#define HWCAP_CHECK \ + if (_dl_osversion && cache_new->libs[middle].osversion > _dl_osversion) \ + continue; \ + if (_DL_PLATFORMS_COUNT && platform != -1 \ + && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \ + && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \ + continue; \ + if (hwcap \ + && ((lib->hwcap & *hwcap & ~_DL_HWCAP_PLATFORM) > *hwcap)) \ + continue + SEARCH_CACHE (cache_new); + } + else + { + /* This is where the strings start. */ + cache_data = (const char *) &cache->libs[cache->nlibs]; + + /* Now we can compute how large the string table is. */ + cache_data_size = (const char *) cache + cachesize - cache_data; + +#undef HWCAP_CHECK +#define HWCAP_CHECK do {} while (0) + SEARCH_CACHE (cache); + } + + /* Print our result if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0) && best != NULL) + _dl_debug_printf (" trying file=%s\n", best); + + return best; +} + +#ifndef MAP_COPY +/* If the system does not support MAP_COPY we cannot leave the file open + all the time since this would create problems when the file is replaced. + Therefore we provide this function to close the file and open it again + once needed. */ +void +_dl_unload_cache (void) +{ + if (cache != NULL && cache != (struct cache_file *) -1) + { + munmap (cache, cachesize); + cache = NULL; + } +} +#endif
dl-cache.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-init.c =================================================================== --- dl-init.c (nonexistent) +++ dl-init.c (revision 158) @@ -0,0 +1,149 @@ +/* Return the next shared object initializer function not yet run. + Copyright (C) 1995,1996,1998,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + + +/* Type of the initializer. */ +typedef void (*init_t) (int, char **, char **); + +/* Flag, nonzero during startup phase. */ +extern int _dl_starting_up; + +/* The object to be initialized first. */ +extern struct link_map *_dl_initfirst; + + +static void +call_init (struct link_map *l, int argc, char **argv, char **env) +{ + if (l->l_init_called) + /* This object is all done. */ + return; + + /* Avoid handling this constructor again in case we have a circular + dependency. */ + l->l_init_called = 1; + + /* Check for object which constructors we do not run here. */ + if (__builtin_expect (l->l_name[0], 'a') == '\0' + && l->l_type == lt_executable) + return; + + /* Are there any constructors? */ + if (l->l_info[DT_INIT] == NULL + && __builtin_expect (l->l_info[DT_INIT_ARRAY] == NULL, 1)) + return; + + /* Print a debug message if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling init: %s\n\n", + l->l_name[0] ? l->l_name : _dl_argv[0]); + + /* Now run the local constructors. There are two forms of them: + - the one named by DT_INIT + - the others in the DT_INIT_ARRAY. + */ + if (l->l_info[DT_INIT] != NULL) + { + init_t init = (init_t) DL_DT_INIT_ADDRESS + (l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr); + + /* Call the function. */ + init (argc, argv, env); + } + + /* Next see whether there is an array with initialization functions. */ + if (l->l_info[DT_INIT_ARRAY] != NULL) + { + unsigned int j; + unsigned int jm; + ElfW(Addr) *addrs; + + jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)); + + addrs = (ElfW(Addr) *) (l->l_info[DT_INIT_ARRAY]->d_un.d_ptr + + l->l_addr); + for (j = 0; j < jm; ++j) + ((init_t) addrs[j]) (argc, argv, env); + } +} + + +void +internal_function +_dl_init (struct link_map *main_map, int argc, char **argv, char **env) +{ + ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY]; + struct r_debug *r; + unsigned int i; + + if (__builtin_expect (_dl_initfirst != NULL, 0)) + { + call_init (_dl_initfirst, argc, argv, env); + _dl_initfirst = NULL; + } + + /* Don't do anything if there is no preinit array. */ + if (__builtin_expect (preinit_array != NULL, 0) + && (i = preinit_array->d_un.d_val / sizeof (ElfW(Addr))) > 0) + { + ElfW(Addr) *addrs; + unsigned int cnt; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling preinit: %s\n\n", + main_map->l_name[0] + ? main_map->l_name : _dl_argv[0]); + + addrs = (ElfW(Addr) *) (main_map->l_info[DT_PREINIT_ARRAY]->d_un.d_ptr + + main_map->l_addr); + for (cnt = 0; cnt < i; ++cnt) + ((init_t) addrs[cnt]) (argc, argv, env); + } + + /* Notify the debugger we have added some objects. We need to call + _dl_debug_initialize in a static program in case dynamic linking has + not been used before. */ + r = _dl_debug_initialize (0); + r->r_state = RT_ADD; + _dl_debug_state (); + + /* Stupid users forced the ELF specification to be changed. It now + says that the dynamic loader is responsible for determining the + order in which the constructors have to run. The constructors + for all dependencies of an object must run before the constructor + for the object itself. Circular dependencies are left unspecified. + + This is highly questionable since it puts the burden on the dynamic + loader which has to find the dependencies at runtime instead of + letting the user do it right. Stupidity rules! */ + + i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + call_init (main_map->l_initfini[i], argc, argv, env); + + /* Notify the debugger all new objects are now ready to go. */ + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + + /* Finished starting up. */ + _dl_starting_up = 0; +}
dl-init.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-reloc.c =================================================================== --- dl-reloc.c (nonexistent) +++ dl-reloc.c (revision 158) @@ -0,0 +1,211 @@ +/* Relocate a shared object and resolve its references to other loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic-link.h" + +/* Statistics function. */ +unsigned long int _dl_num_cache_relocations; + + +void +_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int lazy, int consider_profiling) +{ + struct textrels + { + caddr_t start; + size_t len; + int prot; + struct textrels *next; + } *textrels = NULL; + /* Initialize it to make the compiler happy. */ + const char *errstring = NULL; + + if (l->l_relocated) + return; + + /* If DT_BIND_NOW is set relocate all references in this object. We + do not do this if we are profiling, of course. */ + if (!consider_profiling + && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0)) + lazy = 0; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_RELOC, 0)) + _dl_printf ("\nrelocation processing: %s%s\n", + l->l_name[0] ? l->l_name : _dl_argv[0], lazy ? " (lazy)" : ""); + + /* DT_TEXTREL is now in level 2 and might phase out at some time. + But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make + testing easier and therefore it will be available at all time. */ + if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0)) + { + /* Bletch. We must make read-only segments writable + long enough to relocate them. */ + const ElfW(Phdr) *ph; + for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0) + { + struct textrels *newp; + + newp = (struct textrels *) alloca (sizeof (*newp)); + newp->len = (((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)) + - (ph->p_vaddr & ~(_dl_pagesize - 1))); + newp->start = ((ph->p_vaddr & ~(_dl_pagesize - 1)) + + (caddr_t) l->l_addr); + + if (mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0) + { + errstring = N_("cannot make segment writable for relocation"); + call_error: + _dl_signal_error (errno, l->l_name, NULL, errstring); + } + +#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + newp->prot = (PF_TO_PROT + >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf; +#else + newp->prot = 0; + if (ph->p_flags & PF_R) + newp->prot |= PROT_READ; + if (ph->p_flags & PF_W) + newp->prot |= PROT_WRITE; + if (ph->p_flags & PF_X) + newp->prot |= PROT_EXEC; +#endif + newp->next = textrels; + textrels = newp; + } + } + + { + /* Do the actual relocation of the object's GOT and other data. */ + + /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */ +#define RESOLVE_MAP(ref, version, r_type, scope) \ + (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + ? ((__builtin_expect ((*ref) == map->l_lookup_cache.sym, 0) \ + && elf_machine_type_class (r_type) == map->l_lookup_cache.type_class)\ + ? (++_dl_num_cache_relocations, \ + (*ref) = map->l_lookup_cache.ret, \ + map->l_lookup_cache.value) \ + : ({ lookup_t _lr; \ + int _tc = elf_machine_type_class (r_type); \ + map->l_lookup_cache.type_class = _tc; \ + map->l_lookup_cache.sym = (*ref); \ + _lr = ((version) != NULL && (version)->hash != 0 \ + ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, \ + map, (ref), scope, \ + (version), _tc, 0) \ + : _dl_lookup_symbol (strtab + (*ref)->st_name, map, (ref),\ + scope, _tc, 0)); \ + map->l_lookup_cache.ret = (*ref); \ + map->l_lookup_cache.value = _lr; })) \ + : map) +#define RESOLVE(ref, version, r_type, scope) \ + (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + ? ((__builtin_expect ((*ref) == map->l_lookup_cache.sym, 0) \ + && elf_machine_type_class (r_type) == map->l_lookup_cache.type_class)\ + ? (++_dl_num_cache_relocations, \ + (*ref) = map->l_lookup_cache.ret, \ + map->l_lookup_cache.value) \ + : ({ lookup_t _lr; \ + int _tc = elf_machine_type_class (r_type); \ + map->l_lookup_cache.type_class = _tc; \ + map->l_lookup_cache.sym = (*ref); \ + _lr = ((version) != NULL && (version)->hash != 0 \ + ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, \ + map, (ref), scope, \ + (version), _tc, 0) \ + : _dl_lookup_symbol (strtab + (*ref)->st_name, map, (ref),\ + scope, _tc, 0)); \ + map->l_lookup_cache.ret = (*ref); \ + map->l_lookup_cache.value = _lr; })) \ + : map->l_addr) + +#include "dynamic-link.h" + + ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling); + + if (__builtin_expect (consider_profiling, 0)) + { + /* Allocate the array which will contain the already found + relocations. If the shared object lacks a PLT (for example + if it only contains lead function) the l_info[DT_PLTRELSZ] + will be NULL. */ + if (l->l_info[DT_PLTRELSZ] == NULL) + { + errstring = N_("%s: profiler found no PLTREL in object %s\n"); + fatal: + _dl_fatal_printf (errstring, + _dl_argv[0] ?: "", + l->l_name); + } + + l->l_reloc_result = + (ElfW(Addr) *) calloc (sizeof (ElfW(Addr)), + l->l_info[DT_PLTRELSZ]->d_un.d_val); + if (l->l_reloc_result == NULL) + { + errstring = N_("\ +%s: profiler out of memory shadowing PLTREL of %s\n"); + goto fatal; + } + } + } + + /* Mark the object so we know this work has been done. */ + l->l_relocated = 1; + + /* Undo the segment protection changes. */ + while (__builtin_expect (textrels != NULL, 0)) + { + if (mprotect (textrels->start, textrels->len, textrels->prot) < 0) + { + errstring = N_("cannot restore segment prot after reloc"); + goto call_error; + } + + textrels = textrels->next; + } +} + +#include + +void +internal_function +_dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt) +{ + /* XXX We cannot translate these messages. */ + static const char msg[2][32] = { "unexpected reloc type", + "unexpected PLT reloc type" }; + char msgbuf[sizeof (msg[0])]; + + strcpy (msgbuf, msg[plt]); + + _dl_signal_error (0, map->l_name, NULL, msgbuf); +}
dl-reloc.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: Makefile.in =================================================================== --- Makefile.in (nonexistent) +++ Makefile.in (revision 158) @@ -0,0 +1,610 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(srcdir)/../../../../Makefile.shared \ + $(srcdir)/Makefile.in $(srcdir)/Makefile.am +subdir = dl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../../../../libtool.m4 \ + $(top_srcdir)/../../../../ltoptions.m4 \ + $(top_srcdir)/../../../../ltsugar.m4 \ + $(top_srcdir)/../../../../ltversion.m4 \ + $(top_srcdir)/../../../../lt~obsolete.m4 \ + $(top_srcdir)/../../../acinclude.m4 \ + $(top_srcdir)/../../../confsubdir.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/../../../../mkinstalldirs +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +lib_a_AR = $(AR) $(ARFLAGS) +lib_a_LIBADD = +am__objects_1 = lib_a-dl-addr.$(OBJEXT) lib_a-dl-deps.$(OBJEXT) \ + lib_a-dl-init.$(OBJEXT) lib_a-dl-load.$(OBJEXT) \ + lib_a-dl-misc.$(OBJEXT) lib_a-dl-profile.$(OBJEXT) \ + lib_a-dl-runtime.$(OBJEXT) lib_a-dl-version.$(OBJEXT) \ + lib_a-dl-close.$(OBJEXT) lib_a-dl-error.$(OBJEXT) \ + lib_a-dl-iteratephdr.$(OBJEXT) lib_a-dl-lookup.$(OBJEXT) \ + lib_a-dl-object.$(OBJEXT) lib_a-dl-profstub.$(OBJEXT) \ + lib_a-dl-support.$(OBJEXT) lib_a-dl-debug.$(OBJEXT) \ + lib_a-dl-fini.$(OBJEXT) lib_a-dl-libc.$(OBJEXT) \ + lib_a-dl-open.$(OBJEXT) lib_a-dl-reloc.$(OBJEXT) \ + lib_a-dl-sym.$(OBJEXT) lib_a-dl-cache.$(OBJEXT) +@USE_LIBTOOL_FALSE@am_lib_a_OBJECTS = $(am__objects_1) +lib_a_OBJECTS = $(am_lib_a_OBJECTS) +LTLIBRARIES = $(noinst_LTLIBRARIES) +libdl_la_LIBADD = +am__objects_2 = dl-addr.lo dl-deps.lo dl-init.lo dl-load.lo dl-misc.lo \ + dl-profile.lo dl-runtime.lo dl-version.lo dl-close.lo \ + dl-error.lo dl-iteratephdr.lo dl-lookup.lo dl-object.lo \ + dl-profstub.lo dl-support.lo dl-debug.lo dl-fini.lo dl-libc.lo \ + dl-open.lo dl-reloc.lo dl-sym.lo dl-cache.lo +@USE_LIBTOOL_TRUE@am_libdl_la_OBJECTS = $(am__objects_2) +libdl_la_OBJECTS = $(am_libdl_la_OBJECTS) +@USE_LIBTOOL_TRUE@am_libdl_la_rpath = +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(lib_a_SOURCES) $(libdl_la_SOURCES) +DATA = $(noinst_DATA) +ETAGS = etags +CTAGS = ctags +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ELIX_LEVEL_0_FALSE = @ELIX_LEVEL_0_FALSE@ +ELIX_LEVEL_0_TRUE = @ELIX_LEVEL_0_TRUE@ +ELIX_LEVEL_1_FALSE = @ELIX_LEVEL_1_FALSE@ +ELIX_LEVEL_1_TRUE = @ELIX_LEVEL_1_TRUE@ +ELIX_LEVEL_2_FALSE = @ELIX_LEVEL_2_FALSE@ +ELIX_LEVEL_2_TRUE = @ELIX_LEVEL_2_TRUE@ +ELIX_LEVEL_3_FALSE = @ELIX_LEVEL_3_FALSE@ +ELIX_LEVEL_3_TRUE = @ELIX_LEVEL_3_TRUE@ +ELIX_LEVEL_4_FALSE = @ELIX_LEVEL_4_FALSE@ +ELIX_LEVEL_4_TRUE = @ELIX_LEVEL_4_TRUE@ +EXEEXT = @EXEEXT@ +EXTRA_SUBDIRS = @EXTRA_SUBDIRS@ +EXTRA_SUBLIBS = @EXTRA_SUBLIBS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_MACH_LIB = @LINUX_MACH_LIB@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MAY_SUPPLY_SYSCALLS_FALSE = @MAY_SUPPLY_SYSCALLS_FALSE@ +MAY_SUPPLY_SYSCALLS_TRUE = @MAY_SUPPLY_SYSCALLS_TRUE@ +NEWLIB_CFLAGS = @NEWLIB_CFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +READELF = @READELF@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_LIBTOOL_FALSE = @USE_LIBTOOL_FALSE@ +USE_LIBTOOL_TRUE = @USE_LIBTOOL_TRUE@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_AS = @ac_ct_AS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ +ac_ct_DSYMUTIL = @ac_ct_DSYMUTIL@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_LIPO = @ac_ct_LIPO@ +ac_ct_NMEDIT = @ac_ct_NMEDIT@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_OTOOL = @ac_ct_OTOOL@ +ac_ct_OTOOL64 = @ac_ct_OTOOL64@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_READELF = @ac_ct_READELF@ +ac_ct_STRIP = @ac_ct_STRIP@ +aext = @aext@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libm_machine_dir = @libm_machine_dir@ +localstatedir = @localstatedir@ +lpfx = @lpfx@ +lt_ECHO = @lt_ECHO@ +machine_dir = @machine_dir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +newlib_basedir = @newlib_basedir@ +oext = @oext@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +subdirs = @subdirs@ +sys_dir = @sys_dir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AUTOMAKE_OPTIONS = cygnus +INCLUDES = -DSHARED -D_GNU_SOURCE $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -I$(srcdir)/.. +LIB_SOURCES = \ + dl-addr.c dl-deps.c dl-init.c dl-load.c dl-misc.c dl-profile.c dl-runtime.c dl-version.c \ + dl-close.c dl-error.c dl-iteratephdr.c dl-lookup.c dl-object.c dl-profstub.c dl-support.c \ + dl-debug.c dl-fini.c dl-libc.c dl-open.c dl-reloc.c dl-sym.c dl-cache.c + +AM_CFLAGS = -D_GNU_SOURCE -D__strerror_r=strerror_r +libdl_la_LDFLAGS = -Xcompiler -nostdlib +@USE_LIBTOOL_TRUE@noinst_LTLIBRARIES = libdl.la +@USE_LIBTOOL_TRUE@libdl_la_SOURCES = $(LIB_SOURCES) +@USE_LIBTOOL_FALSE@noinst_DATA = +@USE_LIBTOOL_TRUE@noinst_DATA = objectlist.awk.in +@USE_LIBTOOL_FALSE@noinst_LIBRARIES = lib.a +@USE_LIBTOOL_FALSE@lib_a_SOURCES = $(LIB_SOURCES) +@USE_LIBTOOL_FALSE@lib_a_CFLAGS = $(AM_CFLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../../../../Makefile.shared $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --cygnus dl/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --cygnus dl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +lib.a: $(lib_a_OBJECTS) $(lib_a_DEPENDENCIES) + -rm -f lib.a + $(lib_a_AR) lib.a $(lib_a_OBJECTS) $(lib_a_LIBADD) + $(RANLIB) lib.a + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdl.la: $(libdl_la_OBJECTS) $(libdl_la_DEPENDENCIES) + $(LINK) $(am_libdl_la_rpath) $(libdl_la_LDFLAGS) $(libdl_la_OBJECTS) $(libdl_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +lib_a-dl-addr.o: dl-addr.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-addr.o `test -f 'dl-addr.c' || echo '$(srcdir)/'`dl-addr.c + +lib_a-dl-addr.obj: dl-addr.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-addr.obj `if test -f 'dl-addr.c'; then $(CYGPATH_W) 'dl-addr.c'; else $(CYGPATH_W) '$(srcdir)/dl-addr.c'; fi` + +lib_a-dl-deps.o: dl-deps.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-deps.o `test -f 'dl-deps.c' || echo '$(srcdir)/'`dl-deps.c + +lib_a-dl-deps.obj: dl-deps.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-deps.obj `if test -f 'dl-deps.c'; then $(CYGPATH_W) 'dl-deps.c'; else $(CYGPATH_W) '$(srcdir)/dl-deps.c'; fi` + +lib_a-dl-init.o: dl-init.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-init.o `test -f 'dl-init.c' || echo '$(srcdir)/'`dl-init.c + +lib_a-dl-init.obj: dl-init.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-init.obj `if test -f 'dl-init.c'; then $(CYGPATH_W) 'dl-init.c'; else $(CYGPATH_W) '$(srcdir)/dl-init.c'; fi` + +lib_a-dl-load.o: dl-load.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-load.o `test -f 'dl-load.c' || echo '$(srcdir)/'`dl-load.c + +lib_a-dl-load.obj: dl-load.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-load.obj `if test -f 'dl-load.c'; then $(CYGPATH_W) 'dl-load.c'; else $(CYGPATH_W) '$(srcdir)/dl-load.c'; fi` + +lib_a-dl-misc.o: dl-misc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-misc.o `test -f 'dl-misc.c' || echo '$(srcdir)/'`dl-misc.c + +lib_a-dl-misc.obj: dl-misc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-misc.obj `if test -f 'dl-misc.c'; then $(CYGPATH_W) 'dl-misc.c'; else $(CYGPATH_W) '$(srcdir)/dl-misc.c'; fi` + +lib_a-dl-profile.o: dl-profile.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-profile.o `test -f 'dl-profile.c' || echo '$(srcdir)/'`dl-profile.c + +lib_a-dl-profile.obj: dl-profile.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-profile.obj `if test -f 'dl-profile.c'; then $(CYGPATH_W) 'dl-profile.c'; else $(CYGPATH_W) '$(srcdir)/dl-profile.c'; fi` + +lib_a-dl-runtime.o: dl-runtime.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-runtime.o `test -f 'dl-runtime.c' || echo '$(srcdir)/'`dl-runtime.c + +lib_a-dl-runtime.obj: dl-runtime.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-runtime.obj `if test -f 'dl-runtime.c'; then $(CYGPATH_W) 'dl-runtime.c'; else $(CYGPATH_W) '$(srcdir)/dl-runtime.c'; fi` + +lib_a-dl-version.o: dl-version.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-version.o `test -f 'dl-version.c' || echo '$(srcdir)/'`dl-version.c + +lib_a-dl-version.obj: dl-version.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-version.obj `if test -f 'dl-version.c'; then $(CYGPATH_W) 'dl-version.c'; else $(CYGPATH_W) '$(srcdir)/dl-version.c'; fi` + +lib_a-dl-close.o: dl-close.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-close.o `test -f 'dl-close.c' || echo '$(srcdir)/'`dl-close.c + +lib_a-dl-close.obj: dl-close.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-close.obj `if test -f 'dl-close.c'; then $(CYGPATH_W) 'dl-close.c'; else $(CYGPATH_W) '$(srcdir)/dl-close.c'; fi` + +lib_a-dl-error.o: dl-error.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-error.o `test -f 'dl-error.c' || echo '$(srcdir)/'`dl-error.c + +lib_a-dl-error.obj: dl-error.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-error.obj `if test -f 'dl-error.c'; then $(CYGPATH_W) 'dl-error.c'; else $(CYGPATH_W) '$(srcdir)/dl-error.c'; fi` + +lib_a-dl-iteratephdr.o: dl-iteratephdr.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-iteratephdr.o `test -f 'dl-iteratephdr.c' || echo '$(srcdir)/'`dl-iteratephdr.c + +lib_a-dl-iteratephdr.obj: dl-iteratephdr.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-iteratephdr.obj `if test -f 'dl-iteratephdr.c'; then $(CYGPATH_W) 'dl-iteratephdr.c'; else $(CYGPATH_W) '$(srcdir)/dl-iteratephdr.c'; fi` + +lib_a-dl-lookup.o: dl-lookup.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-lookup.o `test -f 'dl-lookup.c' || echo '$(srcdir)/'`dl-lookup.c + +lib_a-dl-lookup.obj: dl-lookup.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-lookup.obj `if test -f 'dl-lookup.c'; then $(CYGPATH_W) 'dl-lookup.c'; else $(CYGPATH_W) '$(srcdir)/dl-lookup.c'; fi` + +lib_a-dl-object.o: dl-object.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-object.o `test -f 'dl-object.c' || echo '$(srcdir)/'`dl-object.c + +lib_a-dl-object.obj: dl-object.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-object.obj `if test -f 'dl-object.c'; then $(CYGPATH_W) 'dl-object.c'; else $(CYGPATH_W) '$(srcdir)/dl-object.c'; fi` + +lib_a-dl-profstub.o: dl-profstub.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-profstub.o `test -f 'dl-profstub.c' || echo '$(srcdir)/'`dl-profstub.c + +lib_a-dl-profstub.obj: dl-profstub.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-profstub.obj `if test -f 'dl-profstub.c'; then $(CYGPATH_W) 'dl-profstub.c'; else $(CYGPATH_W) '$(srcdir)/dl-profstub.c'; fi` + +lib_a-dl-support.o: dl-support.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-support.o `test -f 'dl-support.c' || echo '$(srcdir)/'`dl-support.c + +lib_a-dl-support.obj: dl-support.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-support.obj `if test -f 'dl-support.c'; then $(CYGPATH_W) 'dl-support.c'; else $(CYGPATH_W) '$(srcdir)/dl-support.c'; fi` + +lib_a-dl-debug.o: dl-debug.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-debug.o `test -f 'dl-debug.c' || echo '$(srcdir)/'`dl-debug.c + +lib_a-dl-debug.obj: dl-debug.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-debug.obj `if test -f 'dl-debug.c'; then $(CYGPATH_W) 'dl-debug.c'; else $(CYGPATH_W) '$(srcdir)/dl-debug.c'; fi` + +lib_a-dl-fini.o: dl-fini.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-fini.o `test -f 'dl-fini.c' || echo '$(srcdir)/'`dl-fini.c + +lib_a-dl-fini.obj: dl-fini.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-fini.obj `if test -f 'dl-fini.c'; then $(CYGPATH_W) 'dl-fini.c'; else $(CYGPATH_W) '$(srcdir)/dl-fini.c'; fi` + +lib_a-dl-libc.o: dl-libc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-libc.o `test -f 'dl-libc.c' || echo '$(srcdir)/'`dl-libc.c + +lib_a-dl-libc.obj: dl-libc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-libc.obj `if test -f 'dl-libc.c'; then $(CYGPATH_W) 'dl-libc.c'; else $(CYGPATH_W) '$(srcdir)/dl-libc.c'; fi` + +lib_a-dl-open.o: dl-open.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-open.o `test -f 'dl-open.c' || echo '$(srcdir)/'`dl-open.c + +lib_a-dl-open.obj: dl-open.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-open.obj `if test -f 'dl-open.c'; then $(CYGPATH_W) 'dl-open.c'; else $(CYGPATH_W) '$(srcdir)/dl-open.c'; fi` + +lib_a-dl-reloc.o: dl-reloc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-reloc.o `test -f 'dl-reloc.c' || echo '$(srcdir)/'`dl-reloc.c + +lib_a-dl-reloc.obj: dl-reloc.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-reloc.obj `if test -f 'dl-reloc.c'; then $(CYGPATH_W) 'dl-reloc.c'; else $(CYGPATH_W) '$(srcdir)/dl-reloc.c'; fi` + +lib_a-dl-sym.o: dl-sym.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-sym.o `test -f 'dl-sym.c' || echo '$(srcdir)/'`dl-sym.c + +lib_a-dl-sym.obj: dl-sym.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-sym.obj `if test -f 'dl-sym.c'; then $(CYGPATH_W) 'dl-sym.c'; else $(CYGPATH_W) '$(srcdir)/dl-sym.c'; fi` + +lib_a-dl-cache.o: dl-cache.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-cache.o `test -f 'dl-cache.c' || echo '$(srcdir)/'`dl-cache.c + +lib_a-dl-cache.obj: dl-cache.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dl-cache.obj `if test -f 'dl-cache.c'; then $(CYGPATH_W) 'dl-cache.c'; else $(CYGPATH_W) '$(srcdir)/dl-cache.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +check-am: +check: check-am +all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(DATA) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES clean-noinstLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +objectlist.awk.in: $(noinst_LTLIBRARIES) + -rm -f objectlist.awk.in + for i in `ls *.lo` ; \ + do \ + echo $$i `pwd`/$$i >> objectlist.awk.in ; \ + done +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: libintl.h =================================================================== --- libintl.h (nonexistent) +++ libintl.h (revision 158) @@ -0,0 +1,2 @@ +#define N_(x) x +
libintl.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-object.c =================================================================== --- dl-object.c (nonexistent) +++ dl-object.c (revision 158) @@ -0,0 +1,163 @@ +/* Storage management for the chain of loaded shared objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +#include + + +/* Allocate a `struct link_map' for a new object being loaded, + and enter it into the _dl_loaded list. */ + +struct link_map * +internal_function +_dl_new_object (char *realname, const char *libname, int type, + struct link_map *loader) +{ + struct link_map *l; + int idx; + size_t libname_len = strlen (libname) + 1; + struct link_map *new; + struct libname_list *newname; + + new = (struct link_map *) calloc (sizeof (*new) + sizeof (*newname) + + libname_len, 1); + if (new == NULL) + return NULL; + + new->l_libname = newname = (struct libname_list *) (new + 1); + newname->name = (char *) memcpy (newname + 1, libname, libname_len); + /* newname->next = NULL; We use calloc therefore not necessary. */ + newname->dont_free = 1; + + new->l_name = realname; + new->l_type = type; + new->l_loader = loader; + /* new->l_global = 0; We use calloc therefore not necessary. */ + + /* Use the 'l_scope_mem' array by default for the the 'l_scope' + information. If we need more entries we will allocate a large + array dynamically. */ + new->l_scope = new->l_scope_mem; + new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]); + + /* Counter for the scopes we have to handle. */ + idx = 0; + + if (_dl_loaded != NULL) + { + l = _dl_loaded; + while (l->l_next != NULL) + l = l->l_next; + new->l_prev = l; + /* new->l_next = NULL; Would be necessary but we use calloc. */ + l->l_next = new; + + /* Add the global scope. */ + new->l_scope[idx++] = &_dl_loaded->l_searchlist; + } + else + _dl_loaded = new; + ++_dl_nloaded; + + /* If we have no loader the new object acts as it. */ + if (loader == NULL) + loader = new; + else + /* Determine the local scope. */ + while (loader->l_loader != NULL) + loader = loader->l_loader; + + /* Insert the scope if it isn't the global scope we already added. */ + if (idx == 0 || &loader->l_searchlist != new->l_scope[0]) + new->l_scope[idx] = &loader->l_searchlist; + + new->l_local_scope[0] = &new->l_searchlist; + + /* Don't try to find the origin for the main map which has the name "". */ + if (realname[0] != '\0') + { + size_t realname_len = strlen (realname) + 1; + char *origin; + char *cp; + + if (realname[0] == '/') + { + /* It is an absolute path. Use it. But we have to make a + copy since we strip out the trailing slash. */ + cp = origin = (char *) malloc (realname_len); + if (origin == NULL) + { + origin = (char *) -1; + goto out; + } + } + else + { + size_t len = realname_len; + char *result = NULL; + + /* Get the current directory name. */ + origin = NULL; + do + { + len += 128; + origin = (char *) realloc (origin, len); + } + while (origin != NULL + && (result = getcwd (origin, len - realname_len)) == NULL + && errno == ERANGE); + + if (result == NULL) + { + /* We were not able to determine the current directory. + Note that free(origin) is OK if origin == NULL. */ + free (origin); + origin = (char *) -1; + goto out; + } + + /* Find the end of the path and see whether we have to add + a slash. */ + cp = memchr (origin, '\0', strlen(origin)); + if (cp[-1] != '/') + *cp++ = '/'; + } + + /* Add the real file name. */ + memcpy (cp, realname, realname_len); + + /* Now remove the filename and the slash. Leave the slash if it + the name is something like "/foo". */ + cp = strrchr (origin, '/'); + if (cp == origin) + origin[1] = '\0'; + else + *cp = '\0'; + + out: + new->l_origin = origin; + } + + return new; +}
dl-object.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-cache.h =================================================================== --- dl-cache.h (nonexistent) +++ dl-cache.h (revision 158) @@ -0,0 +1,140 @@ +/* Support for reading /etc/ld.so.cache files written by Linux ldconfig. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#ifndef _DL_CACHE_DEFAULT_ID +# define _DL_CACHE_DEFAULT_ID 3 +#endif + +#ifndef _dl_cache_check_flags +# define _dl_cache_check_flags(flags) \ + ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID) +#endif + +#ifndef SYSCONFDIR +# define SYSCONFDIR "/etc" +#endif + +#ifndef LD_SO_CACHE +# define LD_SO_CACHE SYSCONFDIR "/ld.so.cache" +#endif + +#define CACHEMAGIC "ld.so-1.7.0" + +/* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another + format has been added in a compatible way: + The beginning of the string table is used for the new table: + old_magic + nlibs + libs[0] + ... + libs[nlibs-1] + pad, new magic needs to be aligned + - this is string[0] for the old format + new magic - this is string[0] for the new format + newnlibs + ... + newlibs[0] + ... + newlibs[newnlibs-1] + string 1 + string 2 + ... +*/ +struct file_entry +{ + int flags; /* This is 1 for an ELF library. */ + unsigned int key, value; /* String table indices. */ +}; + +struct cache_file +{ + char magic[sizeof CACHEMAGIC - 1]; + unsigned int nlibs; + struct file_entry libs[0]; +}; + +#define CACHEMAGIC_NEW "glibc-ld.so.cache" +#define CACHE_VERSION "1.1" +#define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION + + +struct file_entry_new +{ + int32_t flags; /* This is 1 for an ELF library. */ + uint32_t key, value; /* String table indices. */ + uint32_t osversion; /* Required OS version. */ + uint64_t hwcap; /* Hwcap entry. */ +}; + +struct cache_file_new +{ + char magic[sizeof CACHEMAGIC_NEW - 1]; + char version[sizeof CACHE_VERSION - 1]; + uint32_t nlibs; /* Number of entries. */ + uint32_t len_strings; /* Size of string table. */ + uint32_t unused[5]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ +}; + +/* Used to align cache_file_new. */ +#define ALIGN_CACHE(addr) \ +(((addr) + __alignof__ (struct cache_file_new) -1) \ + & (~(__alignof__ (struct cache_file_new) - 1))) + +static int +_dl_cache_libcmp (const char *p1, const char *p2) +{ + while (*p1 != '\0') + { + if (*p1 >= '0' && *p1 <= '9') + { + if (*p2 >= '0' && *p2 <= '9') + { + /* Must compare this numerically. */ + int val1; + int val2; + + val1 = *p1++ - '0'; + val2 = *p2++ - '0'; + while (*p1 >= '0' && *p1 <= '9') + val1 = val1 * 10 + *p1++ - '0'; + while (*p2 >= '0' && *p2 <= '9') + val2 = val2 * 10 + *p2++ - '0'; + if (val1 != val2) + return val1 - val2; + } + else + return 1; + } + else if (*p2 >= '0' && *p2 <= '9') + return -1; + else if (*p1 != *p2) + return *p1 - *p2; + else + { + ++p1; + ++p2; + } + } + return *p1 - *p2; +}
dl-cache.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-addr.c =================================================================== --- dl-addr.c (nonexistent) +++ dl-addr.c (revision 158) @@ -0,0 +1,101 @@ +/* Locate the shared object symbol nearest a given address. + Copyright (C) 1996-2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +int +internal_function +_dl_addr (const void *address, Dl_info *info) +{ + const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address); + struct link_map *l, *match; + const ElfW(Sym) *symtab, *matchsym; + const char *strtab; + ElfW(Word) strtabsize; + + /* Find the highest-addressed object that ADDRESS is not below. */ + match = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (addr >= l->l_map_start && addr < l->l_map_end) + { + /* We know ADDRESS lies within L if in any shared object. + Make sure it isn't past the end of L's segments. */ + size_t n = l->l_phnum; + if (n > 0) + { + do + --n; + while (l->l_phdr[n].p_type != PT_LOAD); + if (addr >= (l->l_addr + + l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz)) + /* Off the end of the highest-addressed shared object. */ + continue; + } + + match = l; + break; + } + + if (match == NULL) + return 0; + + /* Now we know what object the address lies in. */ + info->dli_fname = match->l_name; + info->dli_fbase = (void *) match->l_addr; + + /* If this is the main program the information is incomplete. */ + if (__builtin_expect (info->dli_fbase == NULL, 0)) + { + info->dli_fname = _dl_argv[0]; + info->dli_fbase = (void *) match->l_map_start; + } + + symtab = (const void *) D_PTR (match, l_info[DT_SYMTAB]); + strtab = (const void *) D_PTR (match, l_info[DT_STRTAB]); + strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + /* We assume that the string table follows the symbol table, because + there is no way in ELF to know the size of the dynamic symbol table!! */ + for (matchsym = NULL; (void *) symtab < (void *) strtab; ++symtab) + if (addr >= match->l_addr + symtab->st_value + && ((symtab->st_size == 0 && addr == match->l_addr + symtab->st_value) + || addr < match->l_addr + symtab->st_value + symtab->st_size) + && symtab->st_name < strtabsize + && (matchsym == NULL || matchsym->st_value < symtab->st_value) + && (ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL + || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)) + matchsym = symtab; + + if (matchsym) + { + /* We found a symbol close by. Fill in its name and exact address. */ + info->dli_sname = strtab + matchsym->st_name; + info->dli_saddr = (void *) (match->l_addr + matchsym->st_value); + } + else + { + /* No symbol matches. We return only the containing object. */ + info->dli_sname = NULL; + info->dli_saddr = NULL; + } + + return 1; +}
dl-addr.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-iteratephdr.c =================================================================== --- dl-iteratephdr.c (nonexistent) +++ dl-iteratephdr.c (revision 158) @@ -0,0 +1,65 @@ +/* Get loaded objects program headers. + Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2001. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +int +__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), void *data) +{ + struct link_map *l; + struct dl_phdr_info info; + int ret = 0; + + /* Make sure we are alone. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + for (l = _dl_loaded; l != NULL; l = l->l_next) + { + /* Skip the dynamic linker. */ + if (l->l_phdr == NULL) + continue; + info.dlpi_addr = l->l_addr; + info.dlpi_name = l->l_name; + info.dlpi_phdr = l->l_phdr; + info.dlpi_phnum = l->l_phnum; + ret = callback (&info, sizeof (struct dl_phdr_info), data); + if (ret) + break; + } + + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + + return ret; +} + +#ifdef SHARED +weak_alias (__dl_iterate_phdr, dl_iterate_phdr); +#endif
dl-iteratephdr.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: ldsodefs.h =================================================================== --- ldsodefs.h (nonexistent) +++ ldsodefs.h (revision 158) @@ -0,0 +1,536 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LDSODEFS_H +#define _LDSODEFS_H 1 + +#include + +#define __need_size_t +#define __need_NULL +#include +#include + +#include +#include +#include +#include + +#include "dl-local.h" + +__BEGIN_DECLS + +/* We use this macro to refer to ELF types independent of the native wordsize. + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ +#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) + +#define internal_function +/* All references to the value of l_info[DT_PLTGOT], + l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], + l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] + have to be accessed via the D_PTR macro. The macro is needed since for + most architectures the entry is already relocated - but for some not + and we need to relocate at access time. */ +#ifdef DL_RO_DYN_SECTION +# define D_PTR(map,i) (map->i->d_un.d_ptr + map->l_addr) +#else +# define D_PTR(map,i) map->i->d_un.d_ptr +#endif + +/* On some platforms more information than just the address of the symbol + is needed from the lookup functions. In this case we return the whole + link map. */ +#ifdef DL_LOOKUP_RETURNS_MAP +typedef struct link_map *lookup_t; +# define LOOKUP_VALUE(map) map +# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0) +#else +typedef ElfW(Addr) lookup_t; +# define LOOKUP_VALUE(map) map->l_addr +# define LOOKUP_VALUE_ADDRESS(address) address +#endif + +/* on some architectures a pointer to a function is not just a pointer + to the actual code of the function but rather an architecture + specific descriptor. */ +#ifndef ELF_FUNCTION_PTR_IS_SPECIAL +# define DL_SYMBOL_ADDRESS(map, ref) \ + (void *) (LOOKUP_VALUE_ADDRESS (map) + ref->st_value) +# define DL_LOOKUP_ADDRESS(addr) ((ElfW(Addr)) (addr)) +# define DL_DT_INIT_ADDRESS(map, start) (start) +# define DL_DT_FINI_ADDRESS(map, start) (start) +#endif + +/* Unmap a loaded object, called by _dl_close (). */ +#ifndef DL_UNMAP_IS_SPECIAL +# define DL_UNMAP(map) \ + __munmap ((void *) (map)->l_map_start, \ + (map)->l_map_end - (map)->l_map_start) +#endif + +/* By default we do not need special support to initialize DSOs loaded + by statically linked binaries. */ +#ifndef DL_STATIC_INIT +# define DL_STATIC_INIT(map) +#endif + +/* Reloc type classes as returned by elf_machine_type_class(). + ELF_RTYPE_CLASS_PLT means this reloc should not be satisfied by + some PLT symbol, ELF_RTYPE_CLASS_COPY means this reloc should not be + satisfied by any symbol in the executable. */ +#define ELF_RTYPE_CLASS_PLT 1 +#define ELF_RTYPE_CLASS_COPY 2 + +/* ELF uses the PF_x macros to specify the segment permissions, mmap + uses PROT_xxx. In most cases the three macros have the values 1, 2, + and 3 but not in a matching order. The following macros allows + converting from the PF_x values to PROT_xxx values. */ +#define PF_TO_PROT \ + ((PROT_READ << (PF_R * 4)) \ + | (PROT_WRITE << (PF_W * 4)) \ + | (PROT_EXEC << (PF_X * 4)) \ + | ((PROT_READ | PROT_WRITE) << ((PF_R | PF_W) * 4)) \ + | ((PROT_READ | PROT_EXEC) << ((PF_R | PF_X) * 4)) \ + | ((PROT_WRITE | PROT_EXEC) << (PF_W | PF_X) * 4) \ + | ((PROT_READ | PROT_WRITE | PROT_EXEC) << ((PF_R | PF_W | PF_X) * 4))) + + +/* For the version handling we need an array with only names and their + hash values. */ +struct r_found_version + { + const char *name; + ElfW(Word) hash; + + int hidden; + const char *filename; + }; + +/* We want to cache information about the searches for shared objects. */ + +enum r_dir_status { unknown, nonexisting, existing }; + +struct r_search_path_elem + { + /* This link is only used in the `all_dirs' member of `r_search_path'. */ + struct r_search_path_elem *next; + + /* Strings saying where the definition came from. */ + const char *what; + const char *where; + + /* Basename for this search path element. The string must end with + a slash character. */ + const char *dirname; + size_t dirnamelen; + + enum r_dir_status status[0]; + }; + +struct r_strlenpair + { + const char *str; + size_t len; + }; + + +/* A data structure for a simple single linked list of strings. */ +struct libname_list + { + const char *name; /* Name requested (before search). */ + struct libname_list *next; /* Link to next name for this object. */ + int dont_free; /* Flag whether this element should be freed + if the object is not entirely unloaded. */ + }; + + +/* Test whether given NAME matches any of the names of the given object. */ +static __inline int +__attribute__ ((unused)) +_dl_name_match_p (const char *__name, struct link_map *__map) +{ + int __found = strcmp (__name, __map->l_name) == 0; + struct libname_list *__runp = __map->l_libname; + + while (! __found && __runp != NULL) + if (strcmp (__name, __runp->name) == 0) + __found = 1; + else + __runp = __runp->next; + + return __found; +} + +/* Function used as argument for `_dl_receive_error' function. The + arguments are the error code, error string, and the objname the + error occurred in. */ +typedef void (*receiver_fct) (int, const char *, const char *); + +/* Internal functions of the run-time dynamic linker. + These can be accessed if you link again the dynamic linker + as a shared library, as in `-lld' or `/lib/ld.so' explicitly; + but are not normally of interest to user programs. + + The `-ldl' library functions in provide a simple + user interface to run-time dynamic linking. */ + + +/* Parameters passed to the dynamic linker. */ +extern char **_dl_argv; + +/* Cached value of `getpagesize ()'. */ +extern size_t _dl_pagesize; + +/* OS version. */ +extern unsigned int _dl_osversion; + +/* File descriptor referring to the zero-fill device. */ +extern int _dl_zerofd; + +/* Name of the shared object to be profiled (if any). */ +extern const char *_dl_profile; +/* Map of shared object to be profiled. */ +extern struct link_map *_dl_profile_map; +/* Filename of the output file. */ +extern const char *_dl_profile_output; + +/* If nonzero the appropriate debug information is printed. */ +extern int _dl_debug_mask; +#define DL_DEBUG_LIBS (1 << 0) +#define DL_DEBUG_IMPCALLS (1 << 1) +#define DL_DEBUG_BINDINGS (1 << 2) +#define DL_DEBUG_SYMBOLS (1 << 3) +#define DL_DEBUG_VERSIONS (1 << 4) +#define DL_DEBUG_RELOC (1 << 5) +#define DL_DEBUG_FILES (1 << 6) +#define DL_DEBUG_STATISTICS (1 << 7) +/* This one is used only internally. */ +#define DL_DEBUG_HELP (1 << 8) + +/* Expect cache ID. */ +extern int _dl_correct_cache_id; + +/* Mask for hardware capabilities that are available. */ +extern unsigned long int _dl_hwcap; + +/* Mask for important hardware capabilities we honour. */ +extern unsigned long int _dl_hwcap_mask; + +/* File descriptor to write debug messages to. */ +extern int _dl_debug_fd; + +/* Names of shared object for which the RPATH should be ignored. */ +extern const char *_dl_inhibit_rpath; + +/* Nonzero if references should be treated as weak during runtime linking. */ +extern int _dl_dynamic_weak; + +/* The array with message we print as a last resort. */ +extern const char _dl_out_of_memory[]; + +/* Nonzero if runtime lookups should not update the .got/.plt. */ +extern int _dl_bind_not; + +/* List of search directories. */ +extern struct r_search_path_elem *_dl_all_dirs; +extern struct r_search_path_elem *_dl_init_all_dirs; + +/* OS-dependent function to open the zero-fill device. */ +extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */ + + +/* During the program run we must not modify the global data of + loaded shared object simultanously in two threads. Therefore we + protect `_dl_open' and `_dl_close' in dl-close.c. + + This must be a recursive lock since the initializer function of + the loaded object might as well require a call to this function. + At this time it is not anymore a problem to modify the tables. */ +__libc_lock_define_recursive (extern, _dl_load_lock) + + +/* Write message on the debug file descriptor. The parameters are + interpreted as for a `printf' call. All the lines start with a + tag showing the PID. */ +extern void _dl_debug_printf (const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +/* Write message on the debug file descriptor. The parameters are + interpreted as for a `printf' call. All the lines buf the first + start with a tag showing the PID. */ +extern void _dl_debug_printf_c (const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + + +/* Write a message on the specified descriptor FD. The parameters are + interpreted as for a `printf' call. */ +extern void _dl_dprintf (int fd, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ +#define _dl_printf(fmt, args...) \ + _dl_dprintf (STDOUT_FILENO, fmt, ##args) + +/* Write a message on the specified descriptor standard error. The + parameters are interpreted as for a `printf' call. */ +#define _dl_error_printf(fmt, args...) \ + _dl_dprintf (STDERR_FILENO, fmt, ##args) + +/* Write a message on the specified descriptor standard error and exit + the program. The parameters are interpreted as for a `printf' call. */ +#define _dl_fatal_printf(fmt, args...) \ + do \ + { \ + _dl_dprintf (STDERR_FILENO, fmt, ##args); \ + _exit (127); \ + } \ + while (1) + + +/* This function is called by all the internal dynamic linker functions + when they encounter an error. ERRCODE is either an `errno' code or + zero; OBJECT is the name of the problematical shared object, or null if + it is a general problem; ERRSTRING is a string describing the specific + problem. */ +extern void _dl_signal_error (int errcode, const char *object, + const char *occurred, const char *errstring) + internal_function + __attribute__ ((__noreturn__)); + +/* Like _dl_signal_error, but may return when called in the context of + _dl_receive_error. */ +extern void _dl_signal_cerror (int errcode, const char *object, + const char *occation, const char *errstring) + internal_function; + +/* Call OPERATE, receiving errors from `dl_signal_cerror'. Unlike + `_dl_catch_error' the operation is resumed after the OPERATE + function returns. + ARGS is passed as argument to OPERATE. */ +extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), + void *args) + internal_function; + + +/* Open the shared object NAME and map in its segments. + LOADER's DT_RPATH is used in searching for NAME. + If the object is already opened, returns its existing map. + For preloaded shared objects PRELOADED is set to a non-zero + value to allow additional security checks. */ +extern struct link_map *_dl_map_object (struct link_map *loader, + const char *name, int preloaded, + int type, int trace_mode, int mode) + internal_function; + +/* Call _dl_map_object on the dependencies of MAP, and set up + MAP->l_searchlist. PRELOADS points to a vector of NPRELOADS previously + loaded objects that will be inserted into MAP->l_searchlist after MAP + but before its dependencies. */ +extern void _dl_map_object_deps (struct link_map *map, + struct link_map **preloads, + unsigned int npreloads, int trace_mode) + internal_function; + +/* Cache the locations of MAP's hash table. */ +extern void _dl_setup_hash (struct link_map *map) internal_function; + + +/* Search loaded objects' symbol tables for a definition of the symbol + referred to by UNDEF. *SYM is the symbol table entry containing the + reference; it is replaced with the defining symbol, and the base load + address of the defining object is returned. SYMBOL_SCOPE is a + null-terminated list of object scopes to search; each object's + l_searchlist (i.e. the segment of the dependency tree starting at that + object) is searched in turn. REFERENCE_NAME should name the object + containing the reference; it is used in error messages. + TYPE_CLASS describes the type of symbol we are looking for. */ +extern lookup_t _dl_lookup_symbol (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + int type_class, int explicit) + internal_function; + +/* Lookup versioned symbol. */ +extern lookup_t _dl_lookup_versioned_symbol (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + int type_class, int explicit) + internal_function; + +/* For handling RTLD_NEXT we must be able to skip shared objects. */ +extern lookup_t _dl_lookup_symbol_skip (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + struct link_map *skip_this) + internal_function; + +/* For handling RTLD_NEXT with versioned symbols we must be able to + skip shared objects. */ +extern lookup_t _dl_lookup_versioned_symbol_skip (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + struct link_map *skip_this) + internal_function; + +/* Look up symbol NAME in MAP's scope and return its run-time address. */ +extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name) + internal_function; + + +/* Structure describing the dynamic linker itself. */ +extern struct link_map _dl_rtld_map; +/* And a pointer to the map for the main map. */ +extern struct link_map *_dl_loaded; +/* Number of object in the _dl_loaded list. */ +extern unsigned int _dl_nloaded; +/* Array representing global scope. */ +extern struct r_scope_elem *_dl_global_scope[2]; +/* Direct pointer to the searchlist of the main object. */ +extern struct r_scope_elem *_dl_main_searchlist; +/* Copy of the content of `_dl_main_searchlist'. */ +extern struct r_scope_elem _dl_initial_searchlist; +/* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +extern size_t _dl_global_scope_alloc; + +/* Allocate a `struct link_map' for a new object being loaded, + and enter it into the _dl_main_map list. */ +extern struct link_map *_dl_new_object (char *realname, const char *libname, + int type, struct link_map *loader) + internal_function; + +/* Relocate the given object (if it hasn't already been). + SCOPE is passed to _dl_lookup_symbol in symbol lookups. + If LAZY is nonzero, don't relocate its PLT. */ +extern void _dl_relocate_object (struct link_map *map, + struct r_scope_elem *scope[], + int lazy, int consider_profiling); + +/* Call _dl_signal_error with a message about an unhandled reloc type. + TYPE is the result of ELFW(R_TYPE) (r_info), i.e. an R__* value. + PLT is nonzero if this was a PLT reloc; it just affects the message. */ +extern void _dl_reloc_bad_type (struct link_map *map, + unsigned int type, int plt) + internal_function __attribute__ ((__noreturn__)); + +/* Check the version dependencies of all objects available through + MAP. If VERBOSE print some more diagnostics. */ +extern int _dl_check_all_versions (struct link_map *map, int verbose, + int trace_mode) + internal_function; + +/* Check the version dependencies for MAP. If VERBOSE print some more + diagnostics. */ +extern int _dl_check_map_versions (struct link_map *map, int verbose, + int trace_mode) + internal_function; + +/* Initialize the object in SCOPE by calling the constructors with + ARGC, ARGV, and ENV as the parameters. */ +extern void _dl_init (struct link_map *main_map, int argc, char **argv, + char **env) internal_function; + +/* Call the finalizer functions of all shared objects whose + initializer functions have completed. */ +extern void _dl_fini (void) internal_function; + +/* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' + says what change is taking place. This function's address is + the value of the `r_brk' member. */ +extern void _dl_debug_state (void); + +/* Initialize `struct r_debug' if it has not already been done. The + argument is the run-time load address of the dynamic linker, to be put + in the `r_ldbase' member. Returns the address of the structure. */ +extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase) + internal_function; + +/* Initialize the basic data structure for the search paths. */ +extern void _dl_init_paths (const char *library_path) internal_function; + +/* Gather the information needed to install the profiling tables and start + the timers. */ +extern void _dl_start_profile (struct link_map *map, const char *output_dir) + internal_function; + +/* The actual functions used to keep book on the calls. */ +extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc); + +/* This function is simply a wrapper around the _dl_mcount function + which does not require a FROMPC parameter since this is the + calling function. */ +extern void _dl_mcount_wrapper (void *selfpc); + +/* Show the members of the auxiliary array passed up from the kernel. */ +extern void _dl_show_auxv (void) internal_function; + +/* Return all environment variables starting with `LD_', one after the + other. */ +extern char *_dl_next_ld_env_entry (char ***position) internal_function; + +/* Return an array with the names of the important hardware capabilities. */ +extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform, + size_t paltform_len, + size_t *sz, + size_t *max_capstrlen) + internal_function; + +/* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. */ +extern const char *_dl_load_cache_lookup (const char *name) + internal_function; + +/* If the system does not support MAP_COPY we cannot leave the file open + all the time since this would create problems when the file is replaced. + Therefore we provide this function to close the file and open it again + once needed. */ +extern void _dl_unload_cache (void); + +/* System-dependent function to read a file's whole contents in the + most convenient manner available. *SIZEP gets the size of the + file. On error MAP_FAILED is returned. */ +extern void *_dl_sysdep_read_whole_file (const char *file, size_t *sizep, + int prot) + internal_function; + +/* System-specific function to do initial startup for the dynamic linker. + After this, file access calls and getenv must work. This is responsible + for setting __libc_enable_secure if we need to be secure (e.g. setuid), + and for setting _dl_argc and _dl_argv, and then calling _dl_main. */ +extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, + void (*dl_main) (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, + ElfW(Addr) *user_entry)); + +extern void _dl_sysdep_start_cleanup (void) + internal_function; + + +__END_DECLS + +#endif /* ldsodefs.h */
ldsodefs.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-load.c =================================================================== --- dl-load.c (nonexistent) +++ dl-load.c (revision 158) @@ -0,0 +1,1830 @@ +/* Map in a shared object's segments from the file. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic-link.h" +#include +#include + +#include + +/* On some systems, no flag bits are given to specify file mapping. */ +#ifndef MAP_FILE +# define MAP_FILE 0 +#endif + +/* The right way to map in the shared library files is MAP_COPY, which + makes a virtual copy of the data at the time of the mmap call; this + guarantees the mapped pages will be consistent even if the file is + overwritten. Some losing VM systems like Linux's lack MAP_COPY. All we + get is MAP_PRIVATE, which copies each page when it is modified; this + means if the file is overwritten, we may at some point get some pages + from the new version after starting with pages from the old version. */ +#ifndef MAP_COPY +# define MAP_COPY MAP_PRIVATE +#endif + +/* Some systems link their relocatable objects for another base address + than 0. We want to know the base address for these such that we can + subtract this address from the segment addresses during mapping. + This results in a more efficient address space usage. Defaults to + zero for almost all systems. */ +#ifndef MAP_BASE_ADDR +# define MAP_BASE_ADDR(l) 0 +#endif + + +#include +#if BYTE_ORDER == BIG_ENDIAN +# define byteorder ELFDATA2MSB +#elif BYTE_ORDER == LITTLE_ENDIAN +# define byteorder ELFDATA2LSB +#else +# error "Unknown BYTE_ORDER " BYTE_ORDER +# define byteorder ELFDATANONE +#endif + +#define STRING(x) __STRING (x) + +#ifdef MAP_ANON +/* The fd is not examined when using MAP_ANON. */ +# define ANONFD -1 +#else +int _dl_zerofd = -1; +# define ANONFD _dl_zerofd +#endif + +/* Handle situations where we have a preferred location in memory for + the shared objects. */ +#ifdef ELF_PREFERRED_ADDRESS_DATA +ELF_PREFERRED_ADDRESS_DATA; +#endif +#ifndef ELF_PREFERRED_ADDRESS +# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref) +#endif +#ifndef ELF_FIXED_ADDRESS +# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0) +#endif + +/* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most + cases the program header follows the ELF header directly. If this + is not the case all bets are off and we can make the header arbitrarily + large and still won't get it read. This means the only question is + how large are the ELF and program header combined. The ELF header + in 64-bit files is 56 bytes long. Each program header entry is again + 56 bytes long. I.e., even with a file which has 17 program header + entries we only have to read 1kB. And 17 program header entries is + plenty, normal files have < 10. If this heuristic should really fail + for some file the code in `_dl_map_object_from_fd' knows how to + recover. */ +struct filebuf +{ + ssize_t len; + char buf[1024]; +}; + +size_t _dl_pagesize; + +unsigned int _dl_osversion; + +int _dl_clktck; + +extern const char *_dl_platform; +extern size_t _dl_platformlen; + +/* The object to be initialized first. */ +struct link_map *_dl_initfirst; + +/* This is the decomposed LD_LIBRARY_PATH search path. */ +static struct r_search_path_struct env_path_list; + +/* List of the hardware capabilities we might end up using. */ +static const struct r_strlenpair *capstr; +static size_t ncapstr; +static size_t max_capstrlen; + + +/* Get the generated information about the trusted directories. */ +#include "trusted-dirs.h" + +static const char system_dirs[] = SYSTEM_DIRS; +static const size_t system_dirs_len[] = +{ + SYSTEM_DIRS_LEN +}; +#define nsystem_dirs_len \ + (sizeof (system_dirs_len) / sizeof (system_dirs_len[0])) + + +/* Local version of `strdup' function. */ +static inline char * +local_strdup (const char *s) +{ + size_t len = strlen (s) + 1; + void *new = malloc (len); + + if (new == NULL) + return NULL; + + return (char *) memcpy (new, s, len); +} + + +static size_t +is_dst (const char *start, const char *name, const char *str, size_t cmplen, + int is_path, int secure) +{ + size_t len; + + if (strncmp (name, str, cmplen) == 0) + len = cmplen + 1; + else if (strncmp (name, str + 1, cmplen - 2) == 0 + && (name[cmplen - 2] == '\0' || name[cmplen - 2] == '/' + || (is_path && name[cmplen - 2] == ':'))) + len = cmplen - 1; + else + return 0; + + if (__builtin_expect (secure, 0) + && ((name[len - 1] != '\0' && (!is_path || name[len - 1] != ':')) + || (name != start + 1 && (!is_path || name[-2] != ':')))) + return 0; + + return len; +} + + +size_t +_dl_dst_count (const char *name, int is_path) +{ + const char *const start = name; + size_t cnt = 0; + + do + { + size_t len = 1; + + /* $ORIGIN is not expanded for SUID/GUID programs (except if it + is $ORIGIN alone) and it must always appear first in path. + + Note that it is no bug that the string in the second and + fourth `strncmp' call is longer than the sequence which is + actually tested. */ + if ((len = is_dst (start, name + 1, "{ORIGIN}", 8, is_path, + 0)) != 0 + || ((len = is_dst (start, name + 1, "{PLATFORM}", 10, is_path, 0)) + != 0)) + ++cnt; + + name = strchr (name + len, '$'); + } + while (name != NULL); + + return cnt; +} + + +char * +_dl_dst_substitute (struct link_map *l, const char *name, char *result, + int is_path) +{ + const char *const start = name; + char *last_elem, *wp; + + /* Now fill the result path. While copying over the string we keep + track of the start of the last path element. When we come accross + a DST we copy over the value or (if the value is not available) + leave the entire path element out. */ + last_elem = wp = result; + + do + { + if (__builtin_expect (*name == '$', 0)) + { + const char *repl = NULL; + size_t len = 1; + + /* Note that it is no bug that the string in the second and + fourth `strncmp' call is longer than the sequence which + is actually tested. */ + if ((len = is_dst (start, name + 1, "{ORIGIN}", 8, is_path, + 0)) != 0) + repl = l->l_origin; + else if ((len = is_dst (start, name + 1, "{PLATFORM}", 10, is_path, + 0)) != 0) + repl = _dl_platform; + + if (repl != NULL && repl != (const char *) -1) + { + wp = strcpy (wp, repl); + wp += strlen (repl); + name += len; + } + else if (len > 1) + { + /* We cannot use this path element, the value of the + replacement is unknown. */ + wp = last_elem; + name += len; + while (*name != '\0' && (!is_path || *name != ':')) + ++name; + } + else + /* No DST we recognize. */ + *wp++ = *name++; + } + else + { + *wp++ = *name++; + if (is_path && *name == ':') + last_elem = wp; + } + } + while (*name != '\0'); + + *wp = '\0'; + + return result; +} + + +/* Return copy of argument with all recognized dynamic string tokens + ($ORIGIN and $PLATFORM for now) replaced. On some platforms it + might not be possible to determine the path from which the object + belonging to the map is loaded. In this case the path element + containing $ORIGIN is left out. */ +static char * +expand_dynamic_string_token (struct link_map *l, const char *s) +{ + /* We make two runs over the string. First we determine how large the + resulting string is and then we copy it over. Since this is now + frequently executed operation we are looking here not for performance + but rather for code size. */ + size_t cnt; + size_t total; + char *result; + + /* Determine the number of DST elements. */ + cnt = DL_DST_COUNT (s, 1); + + /* If we do not have to replace anything simply copy the string. */ + if (__builtin_expect (cnt, 0) == 0) + return local_strdup (s); + + /* Determine the length of the substituted string. */ + total = DL_DST_REQUIRED (l, s, strlen (s), cnt); + + /* Allocate the necessary memory. */ + result = (char *) malloc (total + 1); + if (result == NULL) + return NULL; + + return DL_DST_SUBSTITUTE (l, s, result, 1); +} + + +/* Add `name' to the list of names for a particular shared object. + `name' is expected to have been allocated with malloc and will + be freed if the shared object already has this name. + Returns false if the object already had this name. */ +static void +internal_function +add_name_to_object (struct link_map *l, const char *name) +{ + struct libname_list *lnp, *lastp; + struct libname_list *newname; + size_t name_len; + + lastp = NULL; + for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next) + if (strcmp (name, lnp->name) == 0) + return; + + name_len = strlen (name) + 1; + newname = (struct libname_list *) malloc (sizeof *newname + name_len); + if (newname == NULL) + { + /* No more memory. */ + _dl_signal_error (ENOMEM, name, NULL, N_("cannot allocate name record")); + return; + } + /* The object should have a libname set from _dl_new_object. */ + assert (lastp != NULL); + + newname->name = memcpy (newname + 1, name, name_len); + newname->next = NULL; + newname->dont_free = 0; + lastp->next = newname; +} + +/* All known directories in sorted order. */ +struct r_search_path_elem *_dl_all_dirs; + +/* All directories after startup. */ +struct r_search_path_elem *_dl_init_all_dirs; + +/* Standard search directories. */ +static struct r_search_path_struct rtld_search_dirs; + +static size_t max_dirnamelen; + +static inline struct r_search_path_elem ** +fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, + int check_trusted, const char *what, const char *where) +{ + char *cp; + size_t nelems = 0; + + printf("In fillin_rpath\n"); + while ((cp = strsep (&rpath, sep)) != NULL) + { + struct r_search_path_elem *dirp; + size_t len = strlen (cp); + + /* `strsep' can pass an empty string. This has to be + interpreted as `use the current directory'. */ + if (len == 0) + { + static const char curwd[] = "./"; + cp = (char *) curwd; + } + + /* Remove trailing slashes (except for "/"). */ + while (len > 1 && cp[len - 1] == '/') + --len; + + /* Now add one if there is none so far. */ + if (len > 0 && cp[len - 1] != '/') + cp[len++] = '/'; + + /* Make sure we don't use untrusted directories if we run SUID. */ + if (__builtin_expect (check_trusted, 0)) + { + const char *trun = system_dirs; + size_t idx; + int unsecure = 1; + + /* All trusted directories must be complete names. */ + if (cp[0] == '/') + { + for (idx = 0; idx < nsystem_dirs_len; ++idx) + { + if (len == system_dirs_len[idx] + && memcmp (trun, cp, len) == 0) + { + /* Found it. */ + unsecure = 0; + break; + } + + trun += system_dirs_len[idx] + 1; + } + } + + if (unsecure) + /* Simply drop this directory. */ + continue; + } + + /* See if this directory is already known. */ + for (dirp = _dl_all_dirs; dirp != NULL; dirp = dirp->next) + if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0) + break; + + if (dirp != NULL) + { + /* It is available, see whether it's on our own list. */ + size_t cnt; + for (cnt = 0; cnt < nelems; ++cnt) + if (result[cnt] == dirp) + break; + + if (cnt == nelems) + result[nelems++] = dirp; + } + else + { + size_t cnt; + enum r_dir_status init_val; + size_t where_len = where ? strlen (where) + 1 : 0; + + /* It's a new directory. Create an entry and add it. */ + dirp = (struct r_search_path_elem *) + malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status) + + where_len + len + 1); + if (dirp == NULL) + _dl_signal_error (ENOMEM, NULL, NULL, + N_("cannot create cache for search path")); + + dirp->dirname = ((char *) dirp + sizeof (*dirp) + + ncapstr * sizeof (enum r_dir_status)); + *((char *) (memcpy ((char *) dirp->dirname, cp, len) + len)) = '\0'; + dirp->dirnamelen = len; + + if (len > max_dirnamelen) + max_dirnamelen = len; + + /* We have to make sure all the relative directories are + never ignored. The current directory might change and + all our saved information would be void. */ + init_val = cp[0] != '/' ? existing : unknown; + for (cnt = 0; cnt < ncapstr; ++cnt) + dirp->status[cnt] = init_val; + + dirp->what = what; + if (__builtin_expect (where != NULL, 1)) + dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1 + + ncapstr * sizeof (enum r_dir_status), + where, where_len); + else + dirp->where = NULL; + + dirp->next = _dl_all_dirs; + _dl_all_dirs = dirp; + + /* Put it in the result array. */ + result[nelems++] = dirp; + } + } + + /* Terminate the array. */ + result[nelems] = NULL; + + return result; +} + + +static void +internal_function +decompose_rpath (struct r_search_path_struct *sps, + const char *rpath, struct link_map *l, const char *what) +{ + /* Make a copy we can work with. */ + const char *where = l->l_name; + char *copy; + char *cp; + struct r_search_path_elem **result; + size_t nelems; + /* Initialize to please the compiler. */ + const char *errstring = NULL; + + /* First see whether we must forget the RUNPATH and RPATH from this + object. */ + if (__builtin_expect (_dl_inhibit_rpath != NULL, 0)) + { + const char *found = strstr (_dl_inhibit_rpath, where); + if (found != NULL) + { + size_t len = strlen (where); + if ((found == _dl_inhibit_rpath || found[-1] == ':') + && (found[len] == '\0' || found[len] == ':')) + { + /* This object is on the list of objects for which the + RUNPATH and RPATH must not be used. */ + result = (struct r_search_path_elem **) + malloc (sizeof (*result)); + if (result == NULL) + { + signal_error_cache: + errstring = N_("cannot create cache for search path"); + signal_error: + _dl_signal_error (ENOMEM, NULL, NULL, errstring); + } + + result[0] = NULL; + + sps->dirs = result; + sps->malloced = 1; + + return; + } + } + } + + /* Make a writable copy. At the same time expand possible dynamic + string tokens. */ + copy = expand_dynamic_string_token (l, rpath); + if (copy == NULL) + { + errstring = N_("cannot create RUNPATH/RPATH copy"); + goto signal_error; + } + + /* Count the number of necessary elements in the result array. */ + nelems = 0; + for (cp = copy; *cp != '\0'; ++cp) + if (*cp == ':') + ++nelems; + + /* Allocate room for the result. NELEMS + 1 is an upper limit for the + number of necessary entries. */ + result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1) + * sizeof (*result)); + if (result == NULL) + goto signal_error_cache; + + fillin_rpath (copy, result, ":", 0, what, where); + + /* Free the copied RPATH string. `fillin_rpath' make own copies if + necessary. */ + free (copy); + + sps->dirs = result; + /* The caller will change this value if we haven't used a real malloc. */ + sps->malloced = 1; +} + + +void +internal_function +_dl_init_paths (const char *llp) +{ + size_t idx; + const char *strp; + struct r_search_path_elem *pelem, **aelem; + size_t round_size; +#ifdef SHARED + struct link_map *l; +#endif + /* Initialize to please the compiler. */ + const char *errstring = NULL; + + /* Fill in the information about the application's RPATH and the + directories addressed by the LD_LIBRARY_PATH environment variable. */ + + /* Get the capabilities. */ + capstr = _dl_important_hwcaps (_dl_platform, _dl_platformlen, + &ncapstr, &max_capstrlen); + + /* First set up the rest of the default search directory entries. */ + aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) + malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *)); + if (rtld_search_dirs.dirs == NULL) + { + errstring = N_("cannot create search path array"); + signal_error: + _dl_signal_error (ENOMEM, NULL, NULL, errstring); + } + + round_size = ((2 * sizeof (struct r_search_path_elem) - 1 + + ncapstr * sizeof (enum r_dir_status)) + / sizeof (struct r_search_path_elem)); + + rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) + malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) + * round_size * sizeof (struct r_search_path_elem)); + if (rtld_search_dirs.dirs[0] == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + + rtld_search_dirs.malloced = 0; + pelem = _dl_all_dirs = rtld_search_dirs.dirs[0]; + strp = system_dirs; + idx = 0; + + do + { + size_t cnt; + + *aelem++ = pelem; + + pelem->what = "system search path"; + pelem->where = NULL; + + pelem->dirname = strp; + pelem->dirnamelen = system_dirs_len[idx]; + strp += system_dirs_len[idx] + 1; + + /* System paths must be absolute. */ + assert (pelem->dirname[0] == '/'); + for (cnt = 0; cnt < ncapstr; ++cnt) + pelem->status[cnt] = unknown; + + pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size)); + + pelem += round_size; + } + while (idx < nsystem_dirs_len); + + max_dirnamelen = SYSTEM_DIRS_MAX_LEN; + *aelem = NULL; + +#ifdef SHARED + /* This points to the map of the main object. */ + l = _dl_loaded; + if (l != NULL) + { + assert (l->l_type != lt_loaded); + + if (l->l_info[DT_RUNPATH]) + { + /* Allocate room for the search path and fill in information + from RUNPATH. */ + decompose_rpath (&l->l_runpath_dirs, + (const void *) (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RUNPATH]->d_un.d_val), + l, "RUNPATH"); + + /* The RPATH is ignored. */ + l->l_rpath_dirs.dirs = (void *) -1; + } + else + { + l->l_runpath_dirs.dirs = (void *) -1; + + if (l->l_info[DT_RPATH]) + { + /* Allocate room for the search path and fill in information + from RPATH. */ + decompose_rpath (&l->l_rpath_dirs, + (const void *) (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RPATH]->d_un.d_val), + l, "RPATH"); + l->l_rpath_dirs.malloced = 0; + } + else + l->l_rpath_dirs.dirs = (void *) -1; + } + } +#endif /* SHARED */ + + if (llp != NULL && *llp != '\0') + { + size_t nllp; + const char *cp = llp; + const char *old = llp; + size_t len = strlen (old) + 1; + char *new = alloca(len); + char *llp_tmp; + + llp_tmp = memcpy (new, old, len); + + /* Decompose the LD_LIBRARY_PATH contents. First determine how many + elements it has. */ + nllp = 1; + while (*cp) + { + if (*cp == ':' || *cp == ';') + ++nllp; + ++cp; + } + + env_path_list.dirs = (struct r_search_path_elem **) + malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); + if (env_path_list.dirs == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + + (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", + 0, "LD_LIBRARY_PATH", NULL); + + if (env_path_list.dirs[0] == NULL) + { + free (env_path_list.dirs); + env_path_list.dirs = (void *) -1; + } + + env_path_list.malloced = 0; + } + else + env_path_list.dirs = (void *) -1; + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = _dl_all_dirs; +} + + +/* Think twice before changing anything in this function. It is placed + here and prepared using the `alloca' magic to prevent it from being + inlined. The function is only called in case of an error. But then + performance does not count. The function used to be "inlinable" and + the compiled did so all the time. This increased the code size for + absolutely no good reason. */ +static void +__attribute__ ((noreturn)) +lose (int code, int fd, const char *name, char *realname, struct link_map *l, + const char *msg) +{ + /* The use of `alloca' here looks ridiculous but it helps. The goal + is to avoid the function from being inlined. There is no official + way to do this so we use this trick. gcc never inlines functions + which use `alloca'. */ + int *a = (int *) alloca (sizeof (int)); + a[0] = fd; + /* The file might already be closed. */ + if (a[0] != -1) + (void) close (a[0]); + if (l != NULL) + { + /* Remove the stillborn object from the list and free it. */ + assert (l->l_next == NULL); +#ifndef SHARED + if (l->l_prev == NULL) + /* No other module loaded. */ + _dl_loaded = NULL; + else +#endif + l->l_prev->l_next = NULL; + --_dl_nloaded; + free (l); + } + free (realname); + _dl_signal_error (code, name, NULL, msg); +} + + +/* Map in the shared object NAME, actually located in REALNAME, and already + opened on FD. */ + +#ifndef EXTERNAL_MAP_FROM_FD +static +#endif +struct link_map * +_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, + char *realname, struct link_map *loader, int l_type, + int mode) +{ + struct link_map *l = NULL; + const ElfW(Ehdr) *header; + const ElfW(Phdr) *phdr; + const ElfW(Phdr) *ph; + size_t maplength; + int type; + struct stat64 st; + /* Initialize to keep the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* Get file information. */ + if (__builtin_expect (fstat64 (fd, &st) < 0, 0)) + { + errstring = N_("cannot stat shared object"); + call_lose_errno: + errval = errno; + call_lose: + fprintf (stderr, "%s\n", errstring); + lose (errval, fd, name, realname, l, errstring); + } + + /* Look again to see if the real name matched another already loaded. */ + for (l = _dl_loaded; l; l = l->l_next) + if (l->l_ino == st.st_ino && l->l_dev == st.st_dev) + { + /* The object is already loaded. + Just bump its reference count and return it. */ + close (fd); + + /* If the name is not in the list of names for this object add + it. */ + free (realname); + add_name_to_object (l, name); + + return l; + } + + if (mode & RTLD_NOLOAD) + /* We are not supposed to load the object unless it is already + loaded. So return now. */ + return NULL; + + /* Print debugging message. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("file=%s; generating link map\n", name); + + /* This is the ELF header. We read it in `open_verify'. */ + header = (void *) fbp->buf; + +#ifndef MAP_ANON +# define MAP_ANON 0 + if (_dl_zerofd == -1) + { + _dl_zerofd = _dl_sysdep_open_zero_fill (); + if (_dl_zerofd == -1) + { + close (fd); + _dl_signal_error (errno, NULL, NULL, + N_("cannot open zero fill device")); + } + } +#endif + + /* Enter the new object in the list of loaded objects. */ + l = _dl_new_object (realname, name, l_type, loader); + if (__builtin_expect (! l, 0)) + { + errstring = N_("cannot create shared object descriptor"); + goto call_lose_errno; + } + + /* Extract the remaining details we need from the ELF header + and then read in the program header table. */ + l->l_entry = header->e_entry; + type = header->e_type; + l->l_phnum = header->e_phnum; + + maplength = header->e_phnum * sizeof (ElfW(Phdr)); + if (header->e_phoff + maplength <= fbp->len) + phdr = (void *) (fbp->buf + header->e_phoff); + else + { + phdr = alloca (maplength); + lseek (fd, SEEK_SET, header->e_phoff); + if (__libc_read (fd, (void *) phdr, maplength) != maplength) + { + errstring = N_("cannot read file data"); + goto call_lose_errno; + } + } + + { + /* Scan the program header table, collecting its load commands. */ + struct loadcmd + { + ElfW(Addr) mapstart, mapend, dataend, allocend; + off_t mapoff; + int prot; + } loadcmds[l->l_phnum], *c; + size_t nloadcmds = 0; + + /* The struct is initialized to zero so this is not necessary: + l->l_ld = 0; + l->l_phdr = 0; + l->l_addr = 0; */ + for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph) + switch (ph->p_type) + { + /* These entries tell us where to find things once the file's + segments are mapped in. We record the addresses it says + verbatim, and later correct for the run-time load address. */ + case PT_DYNAMIC: + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); + break; + + case PT_PHDR: + l->l_phdr = (void *) ph->p_vaddr; + break; + + case PT_LOAD: + /* A load command tells us to map in part of the file. + We record the load commands and process them all later. */ + if ((ph->p_align & (_dl_pagesize - 1)) != 0) + { + errstring = N_("ELF load command alignment not page-aligned"); + goto call_lose; + } + if (((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)) != 0) + { + errstring + = N_("ELF load command address/offset not properly aligned"); + goto call_lose; + } + + { + struct loadcmd *c = &loadcmds[nloadcmds++]; + c->mapstart = ph->p_vaddr & ~(ph->p_align - 1); + c->mapend = ((ph->p_vaddr + ph->p_filesz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + c->dataend = ph->p_vaddr + ph->p_filesz; + c->allocend = ph->p_vaddr + ph->p_memsz; + c->mapoff = ph->p_offset & ~(ph->p_align - 1); + + /* Optimize a common case. */ +#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + c->prot = (PF_TO_PROT + >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf; +#else + c->prot = 0; + if (ph->p_flags & PF_R) + c->prot |= PROT_READ; + if (ph->p_flags & PF_W) + c->prot |= PROT_WRITE; + if (ph->p_flags & PF_X) + c->prot |= PROT_EXEC; +#endif + } + break; + } + + /* Now process the load commands and map segments into memory. */ + c = loadcmds; + + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart; + + if (__builtin_expect (type, ET_DYN) == ET_DYN) + { + /* This is a position-independent shared object. We can let the + kernel map it anywhere it likes, but we must have space for all + the segments in their specified positions relative to the first. + So we map the first segment without MAP_FIXED, but with its + extent increased to cover all the segments. Then we remove + access from excess portion, and there is known sufficient space + there to remap from the later segments. + + As a refinement, sometimes we have an address that we would + prefer to map such objects at; but this is only a preference, + the OS can do whatever it likes. */ + ElfW(Addr) mappref; + mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart) + - MAP_BASE_ADDR (l)); + + /* Remember which part of the address space this object uses. */ + l->l_map_start = (ElfW(Addr)) mmap ((void *) mappref, maplength, + c->prot, MAP_COPY | MAP_FILE, + fd, c->mapoff); + if ((void *) l->l_map_start == MAP_FAILED) + { + map_error: + errstring = N_("failed to map segment from shared object"); + goto call_lose_errno; + } + + l->l_map_end = l->l_map_start + maplength; + l->l_addr = l->l_map_start - c->mapstart; + + /* Change protection on the excess portion to disallow all access; + the portions we do not remap later will be inaccessible as if + unallocated. Then jump into the normal segment-mapping loop to + handle the portion of the segment past the end of the file + mapping. */ + mprotect ((caddr_t) (l->l_addr + c->mapend), + loadcmds[nloadcmds - 1].allocend - c->mapend, + PROT_NONE); + + goto postmap; + } + else + { + /* This object is loaded at a fixed address. This must never + happen for objects loaded with dlopen(). */ + if (__builtin_expect (mode & __RTLD_DLOPEN, 0)) + { + errstring = N_("cannot dynamically load executable"); + goto call_lose; + } + + /* Notify ELF_PREFERRED_ADDRESS that we have to load this one + fixed. */ + ELF_FIXED_ADDRESS (loader, c->mapstart); + } + + /* Remember which part of the address space this object uses. */ + l->l_map_start = c->mapstart + l->l_addr; + l->l_map_end = l->l_map_start + maplength; + + while (c < &loadcmds[nloadcmds]) + { + if (c->mapend > c->mapstart + /* Map the segment contents from the file. */ + && (mmap ((void *) (l->l_addr + c->mapstart), + c->mapend - c->mapstart, c->prot, + MAP_FIXED | MAP_COPY | MAP_FILE, fd, c->mapoff) + == MAP_FAILED)) + goto map_error; + + postmap: + if (l->l_phdr == 0 + && c->mapoff <= header->e_phoff + && (c->mapend - c->mapstart + c->mapoff + >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr)))) + /* Found the program header in this segment. */ + l->l_phdr = (void *) (c->mapstart + header->e_phoff - c->mapoff); + + if (c->allocend > c->dataend) + { + /* Extra zero pages should appear at the end of this segment, + after the data mapped from the file. */ + ElfW(Addr) zero, zeroend, zeropage; + + zero = l->l_addr + c->dataend; + zeroend = l->l_addr + c->allocend; + zeropage = (zero + _dl_pagesize - 1) & ~(_dl_pagesize - 1); + + if (zeroend < zeropage) + /* All the extra data is in the last page of the segment. + We can just zero it. */ + zeropage = zeroend; + + if (zeropage > zero) + { + /* Zero the final part of the last page of the segment. */ + if ((c->prot & PROT_WRITE) == 0) + { + /* Dag nab it. */ + if (mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), + _dl_pagesize, c->prot|PROT_WRITE) < 0) + { + errstring = N_("cannot change memory protections"); + goto call_lose_errno; + } + } + memset ((void *) zero, '\0', zeropage - zero); + if ((c->prot & PROT_WRITE) == 0) + mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), + _dl_pagesize, c->prot); + } + + if (zeroend > zeropage) + { + /* Map the remaining zero pages in from the zero fill FD. */ + caddr_t mapat; + mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, + c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, + ANONFD, 0); + if (mapat == MAP_FAILED) + { + errstring = N_("cannot map zero-fill pages"); + goto call_lose_errno; + } + } + } + + ++c; + } + + if (l->l_phdr == NULL) + { + /* The program header is not contained in any of the segments. + We have to allocate memory ourself and copy it over from + out temporary place. */ + ElfW(Phdr) *newp = (ElfW(Phdr) *) malloc (header->e_phnum + * sizeof (ElfW(Phdr))); + if (newp == NULL) + { + errstring = N_("cannot allocate memory for program header"); + goto call_lose_errno; + } + + l->l_phdr = memcpy (newp, phdr, + (header->e_phnum * sizeof (ElfW(Phdr)))); + l->l_phdr_allocated = 1; + } + else + /* Adjust the PT_PHDR value by the runtime load address. */ + l->l_phdr = (ElfW(Addr)) l->l_phdr + l->l_addr; + } + + /* We are done mapping in the file. We no longer need the descriptor. */ + close (fd); + /* Signal that we closed the file. */ + fd = -1; + + if (l->l_type == lt_library && type == ET_EXEC) + l->l_type = lt_executable; + + if (l->l_ld == 0) + { + if (type == ET_DYN) + { + errstring = N_("object file has no dynamic section"); + goto call_lose; + } + } + else + l->l_ld = (ElfW(Addr)) l->l_ld + l->l_addr; + + l->l_entry += l->l_addr; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf (" dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n" + " entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n", + (int) sizeof (void *) * 2, (unsigned long int) l->l_ld, + (int) sizeof (void *) * 2, (unsigned long int) l->l_addr, + (int) sizeof (void *) * 2, maplength, + (int) sizeof (void *) * 2, (unsigned long int) l->l_entry, + (int) sizeof (void *) * 2, (unsigned long int) l->l_phdr, + (int) sizeof (void *) * 2, l->l_phnum); + + elf_get_dynamic_info (l); + + /* Make sure we are dlopen()ing an object which has the DF_1_NOOPEN + flag set. */ + if (__builtin_expect (l->l_flags_1 & DF_1_NOOPEN, 0) + && (mode & __RTLD_DLOPEN)) + { + /* We are not supposed to load this object. Free all resources. */ + munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start); + + if (!l->l_libname->dont_free) + free (l->l_libname); + + if (l->l_phdr_allocated) + free ((void *) l->l_phdr); + + errstring = N_("shared object cannot be dlopen()ed"); + goto call_lose; + } + + if (l->l_info[DT_HASH]) + _dl_setup_hash (l); + + /* If this object has DT_SYMBOLIC set modify now its scope. We don't + have to do this for the main map. */ + if (__builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0) + && &l->l_searchlist != l->l_scope[0]) + { + /* Create an appropriate searchlist. It contains only this map. + + XXX This is the definition of DT_SYMBOLIC in SysVr4. The old + GNU ld.so implementation had a different interpretation which + is more reasonable. We are prepared to add this possibility + back as part of a GNU extension of the ELF format. */ + l->l_symbolic_searchlist.r_list = + (struct link_map **) malloc (sizeof (struct link_map *)); + + if (l->l_symbolic_searchlist.r_list == NULL) + { + errstring = N_("cannot create searchlist"); + goto call_lose_errno; + } + + l->l_symbolic_searchlist.r_list[0] = l; + l->l_symbolic_searchlist.r_nlist = 1; + + /* Now move the existing entries one back. */ + memmove (&l->l_scope[1], &l->l_scope[0], + (l->l_scope_max - 1) * sizeof (l->l_scope[0])); + + /* Now add the new entry. */ + l->l_scope[0] = &l->l_symbolic_searchlist; + } + + /* Remember whether this object must be initialized first. */ + if (l->l_flags_1 & DF_1_INITFIRST) + _dl_initfirst = l; + + /* Finally the file information. */ + l->l_dev = st.st_dev; + l->l_ino = st.st_ino; + + return l; +} + +/* Print search path. */ +static void +print_search_path (struct r_search_path_elem **list, + const char *what, const char *name) +{ + char buf[max_dirnamelen + max_capstrlen]; + int first = 1; + + _dl_debug_printf (" search path="); + + while (*list != NULL && (*list)->what == what) /* Yes, ==. */ + { + char *endp = memcpy (buf, (*list)->dirname, (*list)->dirnamelen); + size_t cnt; + endp += (*list)->dirnamelen; + + + for (cnt = 0; cnt < ncapstr; ++cnt) + if ((*list)->status[cnt] != nonexisting) + { + char *cp = memcpy (endp, capstr[cnt].str, capstr[cnt].len); + cp += capstr[cnt].len; + + if (cp == buf || (cp == buf + 1 && buf[0] == '/')) + cp[0] = '\0'; + else + cp[-1] = '\0'; + + _dl_debug_printf_c (first ? "%s" : ":%s", buf); + first = 0; + } + + ++list; + } + + if (name != NULL) + _dl_debug_printf_c ("\t\t(%s from file %s)\n", what, + name[0] ? name : _dl_argv[0]); + else + _dl_debug_printf_c ("\t\t(%s)\n", what); +} + +/* Open a file and verify it is an ELF file for this architecture. We + ignore only ELF files for other architectures. Non-ELF files and + ELF files with different header information cause fatal errors since + this could mean there is something wrong in the installation and the + user might want to know about this. */ +static int +open_verify (const char *name, struct filebuf *fbp) +{ + /* This is the expected ELF header. */ +#define ELF32_CLASS ELFCLASS32 +#define ELF64_CLASS ELFCLASS64 +#ifndef VALID_ELF_HEADER +# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0) +# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV) +# define VALID_ELF_ABIVERSION(ver) (ver == 0) +#endif + static const unsigned char expected[EI_PAD] = + { + [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFW(CLASS), + [EI_DATA] = byteorder, + [EI_VERSION] = EV_CURRENT, + [EI_OSABI] = ELFOSABI_SYSV, + [EI_ABIVERSION] = 0 + }; + static const struct + { + ElfW(Word) vendorlen; + ElfW(Word) datalen; + ElfW(Word) type; + char vendor[4]; + } expected_note = { 4, 16, 1, "GNU" }; + int fd; + /* Initialize it to make the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* Open the file. We always open files read-only. */ + fd = open (name, O_RDONLY); + if (fd != -1) + { + ElfW(Ehdr) *ehdr; + ElfW(Phdr) *phdr, *ph; + ElfW(Word) *abi_note, abi_note_buf[8]; + unsigned int osversion; + size_t maplength; + + /* We successfully openened the file. Now verify it is a file + we can use. */ + __set_errno (0); + fbp->len = __libc_read (fd, fbp->buf, sizeof (fbp->buf)); + + /* This is where the ELF header is loaded. */ + assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); + ehdr = (ElfW(Ehdr) *) fbp->buf; + + /* Now run the tests. */ + if (__builtin_expect (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)), 0)) + { + errval = errno; + errstring = (errval == 0 + ? N_("file too short") : N_("cannot read file data")); + call_lose: + lose (errval, fd, name, NULL, NULL, errstring); + } + + /* See whether the ELF header is what we expect. */ + if (__builtin_expect (! VALID_ELF_HEADER (ehdr->e_ident, expected, + EI_PAD), 0)) + { + /* Something is wrong. */ + if (*(Elf32_Word *) &ehdr->e_ident != +#if BYTE_ORDER == LITTLE_ENDIAN + ((ELFMAG0 << (EI_MAG0 * 8)) | + (ELFMAG1 << (EI_MAG1 * 8)) | + (ELFMAG2 << (EI_MAG2 * 8)) | + (ELFMAG3 << (EI_MAG3 * 8))) +#else + ((ELFMAG0 << (EI_MAG3 * 8)) | + (ELFMAG1 << (EI_MAG2 * 8)) | + (ELFMAG2 << (EI_MAG1 * 8)) | + (ELFMAG3 << (EI_MAG0 * 8))) +#endif + ) + errstring = N_("invalid ELF header"); + else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) + /* This is not a fatal error. On architectures where + 32-bit and 64-bit binaries can be run this might + happen. */ + goto close_and_out; + else if (ehdr->e_ident[EI_DATA] != byteorder) + { + if (BYTE_ORDER == BIG_ENDIAN) + errstring = N_("ELF file data encoding not big-endian"); + else + errstring = N_("ELF file data encoding not little-endian"); + } + else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) + errstring + = N_("ELF file version ident does not match current one"); + /* XXX We should be able so set system specific versions which are + allowed here. */ + else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) + errstring = N_("ELF file OS ABI invalid"); + else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_ABIVERSION])) + errstring = N_("ELF file ABI version invalid"); + else + /* Otherwise we don't know what went wrong. */ + errstring = N_("internal error"); + + goto call_lose; + } + + if (__builtin_expect (ehdr->e_version, EV_CURRENT) != EV_CURRENT) + { + errstring = N_("ELF file version does not match current one"); + goto call_lose; + } + if (! __builtin_expect (elf_machine_matches_host (ehdr), 1)) + goto close_and_out; + else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr))) + != sizeof (ElfW(Phdr))) + { + errstring = N_("ELF file's phentsize not the expected size"); + goto call_lose; + } + else if (__builtin_expect (ehdr->e_type, ET_DYN) != ET_DYN + && __builtin_expect (ehdr->e_type, ET_EXEC) != ET_EXEC) + { + errstring = N_("only ET_DYN and ET_EXEC can be loaded"); + goto call_lose; + } + + maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); + if (ehdr->e_phoff + maplength <= fbp->len) + phdr = (void *) (fbp->buf + ehdr->e_phoff); + else + { + phdr = alloca (maplength); + lseek (fd, SEEK_SET, ehdr->e_phoff); + if (__libc_read (fd, (void *) phdr, maplength) != maplength) + { + read_error: + errval = errno; + errstring = N_("cannot read file data"); + goto call_lose; + } + } + + /* Check .note.ABI-tag if present. */ + for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph) + if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4) + { + if (ph->p_offset + 32 <= fbp->len) + abi_note = (void *) (fbp->buf + ph->p_offset); + else + { + lseek (fd, SEEK_SET, ph->p_offset); + if (__libc_read (fd, (void *) abi_note_buf, 32) != 32) + goto read_error; + + abi_note = abi_note_buf; + } + + if (memcmp (abi_note, &expected_note, sizeof (expected_note))) + continue; + + osversion = (abi_note[5] & 0xff) * 65536 + + (abi_note[6] & 0xff) * 256 + + (abi_note[7] & 0xff); + if (abi_note[4] != __ABI_TAG_OS + || (_dl_osversion && _dl_osversion < osversion)) + { + close_and_out: + close (fd); + __set_errno (ENOENT); + fd = -1; + } + + break; + } + } + + return fd; +} + +/* Try to open NAME in one of the directories in *DIRSP. + Return the fd, or -1. If successful, fill in *REALNAME + with the malloc'd full directory name. If it turns out + that none of the directories in *DIRSP exists, *DIRSP is + replaced with (void *) -1, and the old value is free()d + if MAY_FREE_DIRS is true. */ + +static int +open_path (const char *name, size_t namelen, int preloaded, + struct r_search_path_struct *sps, char **realname, + struct filebuf *fbp) +{ + struct r_search_path_elem **dirs = sps->dirs; + char *buf; + int fd = -1; + const char *current_what = NULL; + int any = 0; + + buf = alloca (max_dirnamelen + max_capstrlen + namelen); + do + { + struct r_search_path_elem *this_dir = *dirs; + size_t buflen = 0; + size_t cnt; + char *edp; + int here_any = 0; + int err; + + /* If we are debugging the search for libraries print the path + now if it hasn't happened now. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0) + && current_what != this_dir->what) + { + current_what = this_dir->what; + print_search_path (dirs, current_what, this_dir->where); + } + + edp = (char *) (memcpy (buf, this_dir->dirname, this_dir->dirnamelen) + this_dir->dirnamelen); + for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt) + { + char *tmp; + /* Skip this directory if we know it does not exist. */ + if (this_dir->status[cnt] == nonexisting) + continue; + + tmp = memcpy (edp, capstr[cnt].str, capstr[cnt].len); + tmp += capstr[cnt].len; + + tmp = memcpy (tmp, name, namelen); + tmp += namelen; + buflen = ((char *) (tmp - buf)); + + /* Print name we try if this is wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf (" trying file=%s\n", buf); + + fd = open_verify (buf, fbp); + if (this_dir->status[cnt] == unknown) + { + if (fd != -1) + this_dir->status[cnt] = existing; + else + { + /* We failed to open machine dependent library. Let's + test whether there is any directory at all. */ + struct stat64 st; + + buf[buflen - namelen - 1] = '\0'; + + if (stat64 (buf, &st) != 0 + || ! S_ISDIR (st.st_mode)) + /* The directory does not exist or it is no directory. */ + this_dir->status[cnt] = nonexisting; + else + this_dir->status[cnt] = existing; + } + } + + /* Remember whether we found any existing directory. */ + here_any |= this_dir->status[cnt] == existing; + + if (fd != -1 && __builtin_expect (preloaded, 0) + && 0) + { + /* This is an extra security effort to make sure nobody can + preload broken shared objects which are in the trusted + directories and so exploit the bugs. */ + struct stat64 st; + + if (fstat64 (fd, &st) != 0 + || (st.st_mode & S_ISUID) == 0) + { + /* The shared object cannot be tested for being SUID + or this bit is not set. In this case we must not + use this object. */ + close (fd); + fd = -1; + /* We simply ignore the file, signal this by setting + the error value which would have been set by `open'. */ + errno = ENOENT; + } + } + } + + if (fd != -1) + { + *realname = (char *) malloc (buflen); + if (*realname != NULL) + { + memcpy (*realname, buf, buflen); + return fd; + } + else + { + /* No memory for the name, we certainly won't be able + to load and link it. */ + close (fd); + return -1; + } + } + if (here_any && (err = errno) != ENOENT && err != EACCES) + /* The file exists and is readable, but something went wrong. */ + return -1; + + /* Remember whether we found anything. */ + any |= here_any; + } + while (*++dirs != NULL); + + /* Remove the whole path if none of the directories exists. */ + if (__builtin_expect (! any, 0)) + { + /* Paths which were allocated using the minimal malloc() in ld.so + must not be freed using the general free() in libc. */ + if (sps->malloced) + free (sps->dirs); + sps->dirs = (void *) -1; + } + + return -1; +} + +/* Map in the shared object file NAME. */ + +struct link_map * +internal_function +_dl_map_object (struct link_map *loader, const char *name, int preloaded, + int type, int trace_mode, int mode) +{ + int fd; + char *realname; + char *name_copy; + struct link_map *l; + struct filebuf fb; + + /* Look for this name among those already loaded. */ + for (l = _dl_loaded; l; l = l->l_next) + { + /* If the requested name matches the soname of a loaded object, + use that object. Elide this check for names that have not + yet been opened. */ + if (__builtin_expect (l->l_faked, 0) != 0) + continue; + if (!_dl_name_match_p (name, l)) + { + const char *soname; + + if (__builtin_expect (l->l_soname_added, 1) + || l->l_info[DT_SONAME] == NULL) + continue; + + soname = ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val); + if (strcmp (name, soname) != 0) + continue; + + /* We have a match on a new name -- cache it. */ + add_name_to_object (l, soname); + l->l_soname_added = 1; + } + + /* We have a match. */ + return l; + } + + /* Display information if we are debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0) && loader != NULL) + _dl_debug_printf ("\nfile=%s; needed by %s\n", name, + loader->l_name[0] ? loader->l_name : _dl_argv[0]); + + if (strchr (name, '/') == NULL) + { + /* Search for NAME in several places. */ + + size_t namelen = strlen (name) + 1; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("find library=%s; searching\n", name); + + fd = -1; + + /* When the object has the RUNPATH information we don't use any + RPATHs. */ + if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL) + { + /* First try the DT_RPATH of the dependent object that caused NAME + to be loaded. Then that object's dependent, and on up. */ + for (l = loader; fd == -1 && l; l = l->l_loader) + { + if (l->l_rpath_dirs.dirs == NULL) + { + if (l->l_info[DT_RPATH] == NULL) + { + /* There is no path. */ + l->l_rpath_dirs.dirs = (void *) -1; + continue; + } + else + { + /* Make sure the cache information is available. */ + size_t ptrval = (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RPATH]->d_un.d_val); + decompose_rpath (&l->l_rpath_dirs, + (const char *) ptrval, l, "RPATH"); + } + } + + if (l->l_rpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, + &realname, &fb); + } + + /* If dynamically linked, try the DT_RPATH of the executable + itself. */ + l = _dl_loaded; + if (fd == -1 && l && l->l_type != lt_loaded && l != loader + && l->l_rpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, + &realname, &fb); + } + + /* Try the LD_LIBRARY_PATH environment variable. */ + if (fd == -1 && env_path_list.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &env_path_list, + &realname, &fb); + + /* Look at the RUNPATH information for this binary. + + Note that this is no real loop. 'while' is used only to enable + us to use 'break' instead of a 'goto' to jump to the end. The + loop is always left after the first round. */ + while (fd == -1 && loader != NULL + && loader->l_runpath_dirs.dirs != (void *) -1) + { + if (loader->l_runpath_dirs.dirs == NULL) + { + if (loader->l_info[DT_RUNPATH] == NULL) + { + /* No RUNPATH. */ + loader->l_runpath_dirs.dirs = (void *) -1; + break; + } + else + { + /* Make sure the cache information is available. */ + size_t ptrval = (D_PTR (loader, l_info[DT_STRTAB]) + + loader->l_info[DT_RUNPATH]->d_un.d_val); + decompose_rpath (&loader->l_runpath_dirs, + (const char *) ptrval, loader, "RUNPATH"); + } + } + + if (loader->l_runpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, + &loader->l_runpath_dirs, &realname, &fb); + break; + } + + if (fd == -1 + && (__builtin_expect (! preloaded, 1) || ! 0)) + { + /* Check the list of libraries in the file /etc/ld.so.cache, + for compatibility with Linux's ldconfig program. */ + const char *cached = _dl_load_cache_lookup (name); + + if (cached != NULL) + { +#ifdef SHARED + l = loader ?: _dl_loaded; +#else + l = loader; +#endif + + /* If the loader has the DF_1_NODEFLIB flag set we must not + use a cache entry from any of these directories. */ + if ( +#ifndef SHARED + /* 'l' is always != NULL for dynamically linked objects. */ + l != NULL && +#endif + __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0)) + { + const char *dirp = system_dirs; + unsigned int cnt = 0; + + do + { + if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0) + { + /* The prefix matches. Don't use the entry. */ + cached = NULL; + break; + } + + dirp += system_dirs_len[cnt] + 1; + ++cnt; + } + while (cnt < nsystem_dirs_len); + } + + if (cached != NULL) + { + fd = open_verify (cached, &fb); + if (__builtin_expect (fd != -1, 1)) + { + realname = local_strdup (cached); + if (realname == NULL) + { + close (fd); + fd = -1; + } + } + } + } + } + + /* Finally, try the default path. */ + if (fd == -1 + && ((l = loader ?: _dl_loaded) + /* 'l' is always != NULL for dynamically linked objects. */ +#ifdef SHARED + , +#else + == NULL || +#endif + __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1)) + && rtld_search_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &rtld_search_dirs, + &realname, &fb); + + /* Add another newline when we a tracing the library loading. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("\n"); + } + else + { + /* The path may contain dynamic string tokens. */ + realname = (loader + ? expand_dynamic_string_token (loader, name) + : local_strdup (name)); + if (realname == NULL) + fd = -1; + else + { + fd = open_verify (realname, &fb); + if (__builtin_expect (fd, 0) == -1) + free (realname); + } + } + + if (__builtin_expect (fd, 0) == -1) + { + if (trace_mode) + { + /* We haven't found an appropriate library. But since we + are only interested in the list of libraries this isn't + so severe. Fake an entry with all the information we + have. */ + static const Elf_Symndx dummy_bucket = STN_UNDEF; + + /* Enter the new object in the list of loaded objects. */ + if ((name_copy = local_strdup (name)) == NULL + || (l = _dl_new_object (name_copy, name, type, loader)) == NULL) + _dl_signal_error (ENOMEM, name, NULL, + N_("cannot create shared object descriptor")); + /* Signal that this is a faked entry. */ + l->l_faked = 1; + /* Since the descriptor is initialized with zero we do not + have do this here. + l->l_reserved = 0; */ + l->l_buckets = &dummy_bucket; + l->l_nbuckets = 1; + l->l_relocated = 1; + + return l; + } + else + _dl_signal_error (errno, name, NULL, + N_("cannot open shared object file")); + } + + return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode); +}
dl-load.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: do-lookup.h =================================================================== --- do-lookup.h (nonexistent) +++ do-lookup.h (revision 158) @@ -0,0 +1,201 @@ +/* Look up a symbol in the loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if VERSIONED +# define FCT do_lookup_versioned +# define ARG const struct r_found_version *const version, +#else +# define FCT do_lookup +# define ARG +#endif + +/* Inner part of the lookup functions. We return a value > 0 if we + found the symbol, the value 0 if nothing is found and < 0 if + something bad happened. */ +static inline int +FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, + struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG + struct link_map *skip, int type_class) +{ + struct link_map **list = scope->r_list; + size_t n = scope->r_nlist; + struct link_map *map; + + do + { + const ElfW(Sym) *symtab; + const char *strtab; + const ElfW(Half) *verstab; + Elf_Symndx symidx; + const ElfW(Sym) *sym; +#if ! VERSIONED + int num_versions = 0; + const ElfW(Sym) *versioned_sym = NULL; +#endif + + map = list[i]; + + /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */ + if (skip != NULL && map == skip) + continue; + + /* Don't search the executable when resolving a copy reloc. */ + if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable) + continue; + + /* Print some debugging info if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_SYMBOLS, 0)) + _dl_debug_printf ("symbol=%s; lookup in file=%s\n", undef_name, + map->l_name[0] ? map->l_name : _dl_argv[0]); + + symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); + strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + verstab = map->l_versyms; + + /* Search the appropriate hash bucket in this object's symbol table + for a definition for the same symbol name. */ + for (symidx = map->l_buckets[hash % map->l_nbuckets]; + symidx != STN_UNDEF; + symidx = map->l_chain[symidx]) + { + sym = &symtab[symidx]; + + assert (ELF_RTYPE_CLASS_PLT == 1); + if (sym->st_value == 0 || /* No value. */ + /* ((type_class & ELF_RTYPE_CLASS_PLT) + && (sym->st_shndx == SHN_UNDEF)) */ + (type_class & (sym->st_shndx == SHN_UNDEF))) + continue; + + if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC + && ELFW(ST_TYPE) (sym->st_info) != STT_COMMON) + /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_COMMON and + STT_FUNC entries since these are no code/data definitions. */ + continue; + + if (sym != ref && strcmp (strtab + sym->st_name, undef_name)) + /* Not the symbol we are looking for. */ + continue; + +#if VERSIONED + if (__builtin_expect (verstab == NULL, 0)) + { + /* We need a versioned symbol but haven't found any. If + this is the object which is referenced in the verneed + entry it is a bug in the library since a symbol must + not simply disappear. + + It would also be a bug in the object since it means that + the list of required versions is incomplete and so the + tests in dl-version.c haven't found a problem.*/ + assert (version->filename == NULL + || ! _dl_name_match_p (version->filename, map)); + + /* Otherwise we accept the symbol. */ + } + else + { + /* We can match the version information or use the + default one if it is not hidden. */ + ElfW(Half) ndx = verstab[symidx] & 0x7fff; + if ((map->l_versions[ndx].hash != version->hash + || strcmp (map->l_versions[ndx].name, version->name)) + && (version->hidden || map->l_versions[ndx].hash + || (verstab[symidx] & 0x8000))) + /* It's not the version we want. */ + continue; + } +#else + /* No specific version is selected. When the object file + also does not define a version we have a match. + Otherwise we accept the default version, or in case there + is only one version defined, this one version. */ + if (verstab != NULL) + { + ElfW(Half) ndx = verstab[symidx] & 0x7fff; + if (ndx > 2) /* map->l_versions[ndx].hash != 0) */ + { + /* Don't accept hidden symbols. */ + if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0) + /* No version so far. */ + versioned_sym = sym; + continue; + } + } +#endif + + /* There cannot be another entry for this symbol so stop here. */ + goto found_it; + } + + /* If we have seen exactly one versioned symbol while we are + looking for an unversioned symbol and the version is not the + default version we still accept this symbol since there are + no possible ambiguities. */ +#if VERSIONED + sym = NULL; +#else + sym = num_versions == 1 ? versioned_sym : NULL; +#endif + + if (sym != NULL) + { + found_it: + switch (ELFW(ST_BIND) (sym->st_info)) + { + case STB_WEAK: + /* Weak definition. Use this value if we don't find another. */ + if (__builtin_expect (_dl_dynamic_weak, 0)) + { + if (! result->s) + { + result->s = sym; + result->m = map; + } + break; + } + /* FALLTHROUGH */ + case STB_GLOBAL: + /* Global definition. Just what we need. */ + result->s = sym; + result->m = map; + return 1; + default: + /* Local symbols are ignored. */ + break; + } + } + +#if VERSIONED + /* If this current map is the one mentioned in the verneed entry + and we have not found a weak entry, it is a bug. */ + if (symidx == STN_UNDEF && version->filename != NULL + && __builtin_expect (_dl_name_match_p (version->filename, map), 0)) + return -1; +#endif + } + while (++i < n); + + /* We have not found anything until now. */ + return 0; +} + +#undef FCT +#undef ARG +#undef VERSIONED
do-lookup.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: unsecvars.h =================================================================== --- unsecvars.h (nonexistent) +++ unsecvars.h (revision 158) @@ -0,0 +1,19 @@ +/* Environment variable to be removed for SUID programs. The names are + all stuffed in a single string which means they have to be terminated + with a '\0' explicitly. */ +#define UNSECURE_ENVVARS \ + "LD_PRELOAD\0" \ + "LD_LIBRARY_PATH\0" \ + "LD_ORIGIN_PATH\0" \ + "LD_DEBUG_OUTPUT\0" \ + "LD_PROFILE\0" \ + "GCONV_PATH\0" \ + "HOSTALIASES\0" \ + "LOCALDOMAIN\0" \ + "LOCPATH\0" \ + "MALLOC_TRACE\0" \ + "NLSPATH\0" \ + "RESOLV_HOST_CONF\0" \ + "RES_OPTIONS\0" \ + "TMPDIR\0" \ + "TZDIR\0"
unsecvars.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-version.c =================================================================== --- dl-version.c (nonexistent) +++ dl-version.c (revision 158) @@ -0,0 +1,385 @@ +/* Handle symbol and library versioning. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include + +#include + + +#ifndef VERSYMIDX +# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) +#endif + + +#define make_string(string, rest...) \ + ({ \ + const char *all[] = { string, ## rest }; \ + size_t len, cnt; \ + char *result, *cp; \ + \ + len = 1; \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + len += strlen (all[cnt]); \ + \ + cp = result = alloca (len); \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + { \ + cp = strcpy (cp, all[cnt]); \ + cp += strlen (all[cnt]); \ + } \ + \ + result; \ + }) + + +static inline struct link_map * +find_needed (const char *name, struct link_map *map) +{ + struct link_map *tmap; + unsigned int n; + + for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next) + if (_dl_name_match_p (name, tmap)) + return tmap; + + /* The required object is not in the global scope, look to see if it is + a dependency of the current object. */ + for (n = 0; n < map->l_searchlist.r_nlist; n++) + if (_dl_name_match_p (name, map->l_searchlist.r_list[n])) + return map->l_searchlist.r_list[n]; + + /* Should never happen. */ + return NULL; +} + + +static int +internal_function +match_symbol (const char *name, ElfW(Word) hash, const char *string, + struct link_map *map, int verbose, int weak) +{ + const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + ElfW(Addr) def_offset; + ElfW(Verdef) *def; + /* Initialize to make the compiler happy. */ + const char *errstring = NULL; + int result = 0; + + /* Display information about what we are doing while debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_VERSIONS, 0)) + _dl_debug_printf ("\ +checking for version `%s' in file %s required by file %s\n", + string, map->l_name[0] ? map->l_name : _dl_argv[0], + name); + + if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0)) + { + /* The file has no symbol versioning. I.e., the dependent + object was linked against another version of this file. We + only print a message if verbose output is requested. */ + if (verbose) + { + /* XXX We cannot translate the messages. */ + errstring = make_string ("\ +no version information available (required by ", name, ")"); + goto call_cerror; + } + return 0; + } + + def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr; + assert (def_offset != 0); + + def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset); + while (1) + { + /* Currently the version number of the definition entry is 1. + Make sure all we see is this version. */ + if (__builtin_expect (def->vd_version, 1) != 1) + { + char buf[20]; + buf[sizeof (buf) - 1] = '\0'; + /* XXX We cannot translate the message. */ + errstring = make_string ("unsupported version of Verdef record"); + result = 1; + goto call_cerror; + } + + /* Compare the hash values. */ + if (hash == def->vd_hash) + { + ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux); + + /* To be safe, compare the string as well. */ + if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0) + == 0) + /* Bingo! */ + return 0; + } + + /* If no more definitions we failed to find what we want. */ + if (def->vd_next == 0) + break; + + /* Next definition. */ + def = (ElfW(Verdef) *) ((char *) def + def->vd_next); + } + + /* Symbol not found. If it was a weak reference it is not fatal. */ + if (__builtin_expect (weak, 1)) + { + if (verbose) + { + /* XXX We cannot translate the message. */ + errstring = make_string ("weak version `", string, + "' not found (required by ", name, ")"); + goto call_cerror; + } + return 0; + } + + /* XXX We cannot translate the message. */ + errstring = make_string ("version `", string, "' not found (required by ", + name, ")"); + result = 1; + call_cerror: + _dl_signal_cerror (0, map->l_name[0] ? map->l_name : _dl_argv[0], NULL, + errstring); + return result; +} + + +int +internal_function +_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) +{ + int result = 0; + const char *strtab; + /* Pointer to section with needed versions. */ + ElfW(Dyn) *dyn; + /* Pointer to dynamic section with definitions. */ + ElfW(Dyn) *def; + /* We need to find out which is the highest version index used + in a dependecy. */ + unsigned int ndx_high = 0; + /* Initialize to make the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* If we don't have a string table, we must be ok. */ + if (map->l_info[DT_STRTAB] == NULL) + return 0; + strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + + dyn = map->l_info[VERSYMIDX (DT_VERNEED)]; + def = map->l_info[VERSYMIDX (DT_VERDEF)]; + + if (dyn != NULL) + { + /* This file requires special versions from its dependencies. */ + ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); + + /* Currently the version number of the needed entry is 1. + Make sure all we see is this version. */ + if (__builtin_expect (ent->vn_version, 1) != 1) + { + char buf[20]; + buf[sizeof (buf) - 1] = '\0'; + /* XXX We cannot translate the message. */ + errstring = make_string ("unsupported version of Verneed record\n"); + call_error: + _dl_signal_error (errval, (*map->l_name ? map->l_name : _dl_argv[0]), + NULL, errstring); + } + + while (1) + { + ElfW(Vernaux) *aux; + struct link_map *needed = find_needed (strtab + ent->vn_file, map); + + /* If NEEDED is NULL this means a dependency was not found + and no stub entry was created. This should never happen. */ + assert (needed != NULL); + + /* Make sure this is no stub we created because of a missing + dependency. */ + if (__builtin_expect (! trace_mode, 1) + || ! __builtin_expect (needed->l_faked, 0)) + { + /* NEEDED is the map for the file we need. Now look for the + dependency symbols. */ + aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); + while (1) + { + /* Match the symbol. */ + result |= match_symbol ((*map->l_name + ? map->l_name : _dl_argv[0]), + aux->vna_hash, + strtab + aux->vna_name, + needed, verbose, + aux->vna_flags & VER_FLG_WEAK); + + /* Compare the version index. */ + if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high) + ndx_high = aux->vna_other & 0x7fff; + + if (aux->vna_next == 0) + /* No more symbols. */ + break; + + /* Next symbol. */ + aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next); + } + } + + if (ent->vn_next == 0) + /* No more dependencies. */ + break; + + /* Next dependency. */ + ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next); + } + } + + /* We also must store the names of the defined versions. Determine + the maximum index here as well. + + XXX We could avoid the loop by just taking the number of definitions + as an upper bound of new indeces. */ + if (def != NULL) + { + ElfW(Verdef) *ent; + ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr); + while (1) + { + if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high) + ndx_high = ent->vd_ndx & 0x7fff; + + if (ent->vd_next == 0) + /* No more definitions. */ + break; + + ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next); + } + } + + if (ndx_high > 0) + { + /* Now we are ready to build the array with the version names + which can be indexed by the version index in the VERSYM + section. */ + map->l_versions = (struct r_found_version *) + calloc (ndx_high + 1, sizeof (*map->l_versions)); + if (__builtin_expect (map->l_versions == NULL, 0)) + { + errstring = N_("cannot allocate version reference table"); + errval = ENOMEM; + goto call_error; + } + + /* Store the number of available symbols. */ + map->l_nversions = ndx_high + 1; + + /* Compute the pointer to the version symbols. */ + map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + + if (dyn != NULL) + { + ElfW(Verneed) *ent; + ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); + while (1) + { + ElfW(Vernaux) *aux; + aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); + while (1) + { + ElfW(Half) ndx = aux->vna_other & 0x7fff; + map->l_versions[ndx].hash = aux->vna_hash; + map->l_versions[ndx].hidden = aux->vna_other & 0x8000; + map->l_versions[ndx].name = &strtab[aux->vna_name]; + map->l_versions[ndx].filename = &strtab[ent->vn_file]; + + if (aux->vna_next == 0) + /* No more symbols. */ + break; + + /* Advance to next symbol. */ + aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next); + } + + if (ent->vn_next == 0) + /* No more dependencies. */ + break; + + /* Advance to next dependency. */ + ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next); + } + } + + /* And insert the defined versions. */ + if (def != NULL) + { + ElfW(Verdef) *ent; + ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr); + while (1) + { + ElfW(Verdaux) *aux; + aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux); + + if ((ent->vd_flags & VER_FLG_BASE) == 0) + { + /* The name of the base version should not be + available for matching a versioned symbol. */ + ElfW(Half) ndx = ent->vd_ndx & 0x7fff; + map->l_versions[ndx].hash = ent->vd_hash; + map->l_versions[ndx].name = &strtab[aux->vda_name]; + map->l_versions[ndx].filename = NULL; + } + + if (ent->vd_next == 0) + /* No more definitions. */ + break; + + ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next); + } + } + } + + return result; +} + + +int +internal_function +_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode) +{ + struct link_map *l; + int result = 0; + + for (l = map; l != NULL; l = l->l_next) + result |= ! l->l_faked && _dl_check_map_versions (l, verbose, trace_mode); + + return result; +}
dl-version.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dynamic-link.h =================================================================== --- dynamic-link.h (nonexistent) +++ dynamic-link.h (revision 158) @@ -0,0 +1,257 @@ +/* Inline functions for dynamic linking. + Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef __DYNAMIC_LINK_H__ +#define __DYNAMIC_LINK_H__ + +#include +#include +#include + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + + +/* Global read-only variable defined in rtld.c which is nonzero if we + shall give more warning messages. */ +extern int _dl_verbose __attribute__ ((unused)); + + +/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ + +static void __attribute__ ((unused)) +elf_get_dynamic_info (struct link_map *l) +{ + ElfW(Dyn) *dyn = l->l_ld; + ElfW(Addr) l_addr; + ElfW(Dyn) **info; + + if (! dyn) + return; + + l_addr = l->l_addr; + info = l->l_info; + + while (dyn->d_tag != DT_NULL) + { + if (dyn->d_tag < DT_NUM) + info[dyn->d_tag] = dyn; + else if (dyn->d_tag >= DT_LOPROC && + dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) + info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; + else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) + info[VERSYMIDX (dyn->d_tag)] = dyn; + else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) + info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM] = dyn; + else + assert (! "bad dynamic tag"); + ++dyn; + } +#ifndef DL_RO_DYN_SECTION + if (info[DT_PLTGOT] != NULL) + info[DT_PLTGOT]->d_un.d_ptr += l_addr; + if (info[DT_STRTAB] != NULL) + info[DT_STRTAB]->d_un.d_ptr += l_addr; + if (info[DT_SYMTAB] != NULL) + info[DT_SYMTAB]->d_un.d_ptr += l_addr; +# if ! ELF_MACHINE_NO_RELA + if (info[DT_RELA] != NULL) + { + assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela))); + info[DT_RELA]->d_un.d_ptr += l_addr; + } +# endif +# if ! ELF_MACHINE_NO_REL + if (info[DT_REL] != NULL) + { + assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); + info[DT_REL]->d_un.d_ptr += l_addr; + } +# endif +#endif + if (info[DT_PLTREL] != NULL) + { +# if ELF_MACHINE_NO_RELA + assert (info[DT_PLTREL]->d_un.d_val == DT_REL); +# elif ELF_MACHINE_NO_REL + assert (info[DT_PLTREL]->d_un.d_val == DT_RELA); +# else + assert (info[DT_PLTREL]->d_un.d_val == DT_REL + || info[DT_PLTREL]->d_un.d_val == DT_RELA); +# endif + } +#ifndef DL_RO_DYN_SECTION + if (info[DT_JMPREL] != NULL) + info[DT_JMPREL]->d_un.d_ptr += l_addr; + if (info[VERSYMIDX (DT_VERSYM)] != NULL) + info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr; +#endif + if (info[DT_FLAGS] != NULL) + { + /* Flags are used. Translate to the old form where available. + Since these l_info entries are only tested for NULL pointers it + is ok if they point to the DT_FLAGS entry. */ + ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val; + if (flags & DF_SYMBOLIC) + info[DT_SYMBOLIC] = info[DT_FLAGS]; + if (flags & DF_TEXTREL) + info[DT_TEXTREL] = info[DT_FLAGS]; + if (flags & DF_BIND_NOW) + info[DT_BIND_NOW] = info[DT_FLAGS]; + } + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; + if (info[DT_RUNPATH] != NULL) + /* If both RUNPATH and RPATH are given, the latter is ignored. */ + info[DT_RPATH] = NULL; +} + +# if ! ELF_MACHINE_NO_REL +# include "do-rel.h" +# endif + +# if ! ELF_MACHINE_NO_RELA +# define DO_RELA +# include "do-rel.h" +# endif + +#endif /* __DYNAMIC_LINK_H__ */ + +#ifdef RESOLVE + +/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. + These functions are almost identical, so we use cpp magic to avoid + duplicating their code. It cannot be done in a more general function + because we must be able to completely inline. */ + +/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its + range. Note that according to the ELF spec, this is completely legal! + But conditionally define things so that on machines we know this will + not happen we do something more optimal. */ + +# ifdef ELF_MACHINE_PLTREL_OVERLAP +# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ + do { \ + struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \ + int ranges_index; \ + \ + ranges[0].lazy = ranges[2].lazy = 0; \ + ranges[1].lazy = 1; \ + ranges[0].size = ranges[1].size = ranges[2].size = 0; \ + \ + if ((map)->l_info[DT_##RELOC]) \ + { \ + ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ + ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + } \ + \ + if ((do_lazy) \ + && (map)->l_info[DT_PLTREL] \ + && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ + { \ + ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \ + ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + ranges[2].start = ranges[1].start + ranges[1].size; \ + ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \ + ranges[0].size = ranges[1].start - ranges[0].start; \ + } \ + \ + for (ranges_index = 0; ranges_index < 3; ++ranges_index) \ + elf_dynamic_do_##reloc ((map), \ + ranges[ranges_index].start, \ + ranges[ranges_index].size, \ + ranges[ranges_index].lazy, \ + scope); \ + } while (0) +# else +# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ + do { \ + struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \ + int ranges_index; \ + ranges[0].lazy = 0; \ + ranges[0].size = ranges[1].size = 0; \ + ranges[0].start = 0; \ + \ + if ((map)->l_info[DT_##RELOC]) \ + { \ + ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ + ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + } \ + if ((map)->l_info[DT_PLTREL] \ + && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ + { \ + ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \ + \ + if ((do_lazy) \ + /* This test does not only detect whether the relocation \ + sections are in the right order, it also checks whether \ + there is a DT_REL/DT_RELA section. */ \ + || ranges[0].start + ranges[0].size != start) \ + { \ + ranges[1].start = start; \ + ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + ranges[1].lazy = (do_lazy); \ + } \ + else \ + /* Combine processing the sections. */ \ + ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + } \ + \ + for (ranges_index = 0; ranges_index < 2; ++ranges_index) \ + elf_dynamic_do_##reloc ((map), \ + ranges[ranges_index].start, \ + ranges[ranges_index].size, \ + ranges[ranges_index].lazy, \ + scope); \ + } while (0) +# endif + +# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA +# define _ELF_CHECK_REL 0 +# else +# define _ELF_CHECK_REL 1 +# endif + +# if ! ELF_MACHINE_NO_REL +# define ELF_DYNAMIC_DO_REL(map, lazy) \ + _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL) +# else +# define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */ +# endif + +# if ! ELF_MACHINE_NO_RELA +# define ELF_DYNAMIC_DO_RELA(map, lazy) \ + _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL) +# else +# define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */ +# endif + +/* This can't just be an inline function because GCC is too dumb + to inline functions containing inlines themselves. */ +# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \ + do { \ + int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \ + (consider_profile)); \ + ELF_DYNAMIC_DO_REL ((map), edr_lazy); \ + ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \ + } while (0) + +#endif
dynamic-link.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: do-rel.h =================================================================== --- do-rel.h (nonexistent) +++ do-rel.h (revision 158) @@ -0,0 +1,120 @@ +/* Do relocations for ELF dynamic linking. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file may be included twice, to define both + `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ + +#include + +#ifdef DO_RELA +# define elf_dynamic_do_rel elf_dynamic_do_rela +# define RELCOUNT_IDX VERSYMIDX (DT_RELACOUNT) +# define Rel Rela +# define elf_machine_rel elf_machine_rela +# define elf_machine_rel_relative elf_machine_rela_relative +#else +# define RELCOUNT_IDX VERSYMIDX (DT_RELCOUNT) +#endif + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + +/* Perform the relocations in MAP on the running program image as specified + by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT + relocations; they should be set up to call _dl_runtime_resolve, rather + than fully resolved now. */ + +static inline void +elf_dynamic_do_rel (struct link_map *map, + ElfW(Addr) reladdr, ElfW(Addr) relsize, + int lazy, + struct r_scope_elem *scope[]) +{ + const ElfW(Rel) *r = (const void *) reladdr; + const ElfW(Rel) *end = (const void *) (reladdr + relsize); + ElfW(Addr) l_addr = map->l_addr; + +#ifndef RTLD_BOOTSTRAP + /* We never bind lazily during ld.so bootstrap. Unfortunately gcc is + not clever enough to see through all the function calls to realize + that. */ + if (lazy) + { + /* Doing lazy PLT relocations; they need very little info. */ + for (; r < end; ++r) + elf_machine_lazy_rel (map, l_addr, r); + } + else +#endif + { + const ElfW(Sym) *const symtab = + (const void *) D_PTR (map, l_info[DT_SYMTAB]); + ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL + ? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val); + const ElfW(Rel) *relative = r; + r = MIN (r + nrelative, end); + +#ifndef RTLD_BOOTSTRAP + /* This is defined in rtld.c, but nowhere in the static libc.a; make + the reference weak so static programs can still link. This + declaration cannot be done when compiling rtld.c (i.e. #ifdef + RTLD_BOOTSTRAP) because rtld.c contains the common defn for + _dl_rtld_map, which is incompatible with a weak decl in the same + file. */ + #pragma weak _dl_rtld_map + if (map != &_dl_rtld_map) /* Already done in rtld itself. */ +# ifndef DO_RELA + /* Rela platforms get the offset from r_addend and this must + be copied in the relocation address. Therefore we can skip + the relative relocations only if this is for rel + relocations. */ + if (l_addr != 0) +# endif +#endif + for (; relative < r; ++relative) + elf_machine_rel_relative (l_addr, relative, + (void *) (l_addr + relative->r_offset)); + + if (map->l_info[VERSYMIDX (DT_VERSYM)]) + { + const ElfW(Half) *const version = + (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + + for (; r < end; ++r) + { + ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)]; + elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], + &map->l_versions[ndx], + (void *) (l_addr + r->r_offset), + scope); + } + } + else + for (; r < end; ++r) + elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, + (void *) (l_addr + r->r_offset), scope); + } +} + +#undef elf_dynamic_do_rel +#undef Rel +#undef elf_machine_rel +#undef elf_machine_rel_relative +#undef RELCOUNT_IDX
do-rel.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-dst.h =================================================================== --- dl-dst.h (nonexistent) +++ dl-dst.h (revision 158) @@ -0,0 +1,45 @@ +/* Handling of dynamic sring tokens. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Determine the number of DST elements in the name. Only if IS_PATH is + nonzero paths are recognized (i.e., multiple, ':' separated filenames). */ +#define DL_DST_COUNT(name, is_path) \ + ({ \ + size_t __cnt = 0; \ + const char *__sf = strchr (name, '$'); \ + \ + if (__builtin_expect (__sf != NULL, 0)) \ + __cnt = _dl_dst_count (__sf, is_path); \ + \ + __cnt; }) + +/* Prototype for used function. */ +extern size_t _dl_dst_count (const char *name, int is_path); + + +/* Guess from the number of DSTs the length of the result string. */ +#define DL_DST_REQUIRED(l, name, len, cnt) 1024 + +/* Perform the DST substitution. */ +#define DL_DST_SUBSTITUTE(l, name, res, is_path) \ + _dl_dst_substitute (l, name, res, is_path) + +/* Prototype for used function. */ +extern char *_dl_dst_substitute (struct link_map *l, const char *name, + char *result, int is_path);
dl-dst.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-profile.c =================================================================== --- dl-profile.c (nonexistent) +++ dl-profile.c (revision 158) @@ -0,0 +1,539 @@ +/* Profiling of shared libraries. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + Based on the BSD mcount implementation. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The LD_PROFILE feature has to be implemented different to the + normal profiling using the gmon/ functions. The problem is that an + arbitrary amount of processes simulataneously can be run using + profiling and all write the results in the same file. To provide + this mechanism one could implement a complicated mechanism to merge + the content of two profiling runs or one could extend the file + format to allow more than one data set. For the second solution we + would have the problem that the file can grow in size beyond any + limit and both solutions have the problem that the concurrency of + writing the results is a big problem. + + Another much simpler method is to use mmap to map the same file in + all using programs and modify the data in the mmap'ed area and so + also automatically on the disk. Using the MAP_SHARED option of + mmap(2) this can be done without big problems in more than one + file. + + This approach is very different from the normal profiling. We have + to use the profiling data in exactly the way they are expected to + be written to disk. But the normal format used by gprof is not usable + to do this. It is optimized for size. It writes the tags as single + bytes but this means that the following 32/64 bit values are + unaligned. + + Therefore we use a new format. This will look like this + + 0 1 2 3 <- byte is 32 bit word + 0000 g m o n + 0004 *version* <- GMON_SHOBJ_VERSION + 0008 00 00 00 00 + 000c 00 00 00 00 + 0010 00 00 00 00 + + 0014 *tag* <- GMON_TAG_TIME_HIST + 0018 ?? ?? ?? ?? + ?? ?? ?? ?? <- 32/64 bit LowPC + 0018+A ?? ?? ?? ?? + ?? ?? ?? ?? <- 32/64 bit HighPC + 0018+2*A *histsize* + 001c+2*A *profrate* + 0020+2*A s e c o + 0024+2*A n d s \0 + 0028+2*A \0 \0 \0 \0 + 002c+2*A \0 \0 \0 + 002f+2*A s + + 0030+2*A ?? ?? ?? ?? <- Count data + ... ... + 0030+2*A+K ?? ?? ?? ?? + + 0030+2*A+K *tag* <- GMON_TAG_CG_ARC + 0034+2*A+K *lastused* + 0038+2*A+K ?? ?? ?? ?? + ?? ?? ?? ?? <- FromPC#1 + 0038+3*A+K ?? ?? ?? ?? + ?? ?? ?? ?? <- ToPC#1 + 0038+4*A+K ?? ?? ?? ?? <- Count#1 + ... ... ... + 0038+(2*(CN-1)+2)*A+(CN-1)*4+K ?? ?? ?? ?? + ?? ?? ?? ?? <- FromPC#CGN + 0038+(2*(CN-1)+3)*A+(CN-1)*4+K ?? ?? ?? ?? + ?? ?? ?? ?? <- ToPC#CGN + 0038+(2*CN+2)*A+(CN-1)*4+K ?? ?? ?? ?? <- Count#CGN + + We put (for now?) no basic block information in the file since this would + introduce rase conditions among all the processes who want to write them. + + `K' is the number of count entries which is computed as + + textsize / HISTFRACTION + + `CG' in the above table is the number of call graph arcs. Normally, + the table is sparse and the profiling code writes out only the those + entries which are really used in the program run. But since we must + not extend this table (the profiling file) we'll keep them all here. + So CN can be executed in advance as + + MINARCS <= textsize*(ARCDENSITY/100) <= MAXARCS + + Now the remaining question is: how to build the data structures we can + work with from this data. We need the from set and must associate the + froms with all the associated tos. We will do this by constructing this + data structures at the program start. To do this we'll simply visit all + entries in the call graph table and add it to the appropriate list. */ + +extern int __profile_frequency (void); + +/* We define a special type to address the elements of the arc table. + This is basically the `gmon_cg_arc_record' format but it includes + the room for the tag and it uses real types. */ +struct here_cg_arc_record + { + uintptr_t from_pc; + uintptr_t self_pc; + uint32_t count; + } __attribute__ ((packed)); + +static struct here_cg_arc_record *data; + +/* Nonzero if profiling is under way. */ +static int running; + +/* This is the number of entry which have been incorporated in the toset. */ +static uint32_t narcs; +/* This is a pointer to the object representing the number of entries + currently in the mmaped file. At no point of time this has to be the + same as NARCS. If it is equal all entries from the file are in our + lists. */ +static volatile uint32_t *narcsp; + +static volatile uint16_t *kcount; +static size_t kcountsize; + +struct here_fromstruct + { + struct here_cg_arc_record volatile *here; + uint16_t link; + }; + +static volatile uint16_t *tos; + +static struct here_fromstruct *froms; +static uint32_t fromlimit; +static volatile uint32_t fromidx; + +static uintptr_t lowpc; +static size_t textsize; +static unsigned int hashfraction; +static unsigned int log_hashfraction; + + + +/* Set up profiling data to profile object desribed by MAP. The output + file is found (or created) in OUTPUT_DIR. */ +void +internal_function +_dl_start_profile (struct link_map *map, const char *output_dir) +{ + char *filename; + int fd; + struct stat64 st; + const ElfW(Phdr) *ph; + ElfW(Addr) mapstart = ~((ElfW(Addr)) 0); + ElfW(Addr) mapend = 0; + struct gmon_hdr gmon_hdr; + struct gmon_hist_hdr hist_hdr; + char *hist, *cp, *tmp; + size_t idx; + size_t tossize; + size_t fromssize; + uintptr_t highpc; + struct gmon_hdr *addr = NULL; + off_t expected_size; + /* See profil(2) where this is described. */ + int s_scale; +#define SCALE_1_TO_1 0x10000L + + /* Compute the size of the sections which contain program code. */ + for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X)) + { + ElfW(Addr) start = (ph->p_vaddr & ~(_dl_pagesize - 1)); + ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + + if (start < mapstart) + mapstart = start; + if (end > mapend) + mapend = end; + } + + /* Now we can compute the size of the profiling data. This is done + with the same formulars as in `monstartup' (see gmon.c). */ + running = 0; + lowpc = ROUNDDOWN (mapstart + map->l_addr, + HISTFRACTION * sizeof (HISTCOUNTER)); + highpc = ROUNDUP (mapend + map->l_addr, + HISTFRACTION * sizeof (HISTCOUNTER)); + textsize = highpc - lowpc; + kcountsize = textsize / HISTFRACTION; + hashfraction = HASHFRACTION; + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) + /* If HASHFRACTION is a power of two, mcount can use shifting + instead of integer division. Precompute shift amount. */ + log_hashfraction = ffs (hashfraction * sizeof (*froms)) - 1; + else + log_hashfraction = -1; + tossize = textsize / HASHFRACTION; + fromlimit = textsize * ARCDENSITY / 100; + if (fromlimit < MINARCS) + fromlimit = MINARCS; + if (fromlimit > MAXARCS) + fromlimit = MAXARCS; + fromssize = fromlimit * sizeof (struct here_fromstruct); + + expected_size = (sizeof (struct gmon_hdr) + + 4 + sizeof (struct gmon_hist_hdr) + kcountsize + + 4 + 4 + fromssize * sizeof (struct here_cg_arc_record)); + + /* Create the gmon_hdr we expect or write. */ + memset (&gmon_hdr, '\0', sizeof (struct gmon_hdr)); + memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie)); + *(int32_t *) gmon_hdr.version = GMON_SHOBJ_VERSION; + + /* Create the hist_hdr we expect or write. */ + *(char **) hist_hdr.low_pc = (char *) mapstart; + *(char **) hist_hdr.high_pc = (char *) mapend; + *(int32_t *) hist_hdr.hist_size = kcountsize / sizeof (HISTCOUNTER); + *(int32_t *) hist_hdr.prof_rate = __profile_frequency (); + strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen)); + hist_hdr.dimen_abbrev = 's'; + + /* First determine the output name. We write in the directory + OUTPUT_DIR and the name is composed from the shared objects + soname (or the file name) and the ending ".profile". */ + filename = (char *) alloca (strlen (output_dir) + 1 + strlen (_dl_profile) + + sizeof ".profile"); + cp = strcpy (filename, output_dir); + cp += strlen (output_dir); + *cp++ = '/'; + tmp = strcpy (cp, _dl_profile); + tmp += strlen (_dl_profile); + strcpy (tmp, ".profile"); + +#ifdef O_NOFOLLOW +# define EXTRA_FLAGS | O_NOFOLLOW +#else +# define EXTRA_FLAGS +#endif + fd = __open (filename, O_RDWR | O_CREAT EXTRA_FLAGS); + if (fd == -1) + { + /* We cannot write the profiling data so don't do anything. */ + char buf[400]; + _dl_error_printf ("%s: cannot open file: %s\n", filename, + __strerror_r (errno, buf, sizeof buf)); + return; + } + + if (fstat64 (fd, &st) < 0 || !S_ISREG (st.st_mode)) + { + /* Not stat'able or not a regular file => don't use it. */ + char buf[400]; + int errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot stat file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + /* Test the size. If it does not match what we expect from the size + values in the map MAP we don't use it and warn the user. */ + if (st.st_size == 0) + { + /* We have to create the file. */ + char buf[_dl_pagesize]; + + memset (buf, '\0', _dl_pagesize); + + if (__lseek (fd, expected_size & ~(_dl_pagesize - 1), SEEK_SET) == -1) + { + char buf[400]; + int errnum; + cannot_create: + errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot create file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size + & (_dl_pagesize - 1)))) + < 0) + goto cannot_create; + } + else if (st.st_size != expected_size) + { + __close (fd); + wrong_format: + + if (addr != NULL) + __munmap ((void *) addr, expected_size); + + _dl_error_printf ("%s: file is no correct profile data file for `%s'\n", + filename, _dl_profile); + return; + } + + addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FILE, fd, 0); + if (addr == (struct gmon_hdr *) MAP_FAILED) + { + char buf[400]; + int errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot map file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + /* We don't need the file desriptor anymore. */ + __close (fd); + + /* Pointer to data after the header. */ + hist = (char *) (addr + 1); + kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t) + + sizeof (struct gmon_hist_hdr)); + + /* Compute pointer to array of the arc information. */ + narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t)); + data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t)); + + if (st.st_size == 0) + { + /* Create the signature. */ + memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr)); + + *(uint32_t *) hist = GMON_TAG_TIME_HIST; + memcpy (hist + sizeof (uint32_t), &hist_hdr, + sizeof (struct gmon_hist_hdr)); + + narcsp[-1] = GMON_TAG_CG_ARC; + } + else + { + /* Test the signature in the file. */ + if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0 + || *(uint32_t *) hist != GMON_TAG_TIME_HIST + || memcmp (hist + sizeof (uint32_t), &hist_hdr, + sizeof (struct gmon_hist_hdr)) != 0 + || narcsp[-1] != GMON_TAG_CG_ARC) + goto wrong_format; + } + + /* Allocate memory for the froms data and the pointer to the tos records. */ + tos = (uint16_t *) calloc (tossize + fromssize, 1); + if (tos == NULL) + { + __munmap ((void *) addr, expected_size); + _dl_fatal_printf ("Out of memory while initializing profiler\n"); + /* NOTREACHED */ + } + + froms = (struct here_fromstruct *) ((char *) tos + tossize); + fromidx = 0; + + /* Now we have to process all the arc count entries. BTW: it is + not critical whether the *NARCSP value changes meanwhile. Before + we enter a new entry in to toset we will check that everything is + available in TOS. This happens in _dl_mcount. + + Loading the entries in reverse order should help to get the most + frequently used entries at the front of the list. */ + for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; ) + { + size_t to_index; + size_t newfromidx; + --idx; + to_index = (data[idx].self_pc / (hashfraction * sizeof (*tos))); + newfromidx = fromidx++; + froms[newfromidx].here = &data[idx]; + froms[newfromidx].link = tos[to_index]; + tos[to_index] = newfromidx; + } + + /* Setup counting data. */ + if (kcountsize < highpc - lowpc) + { +#if 0 + s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1; +#else + size_t range = highpc - lowpc; + size_t quot = range / kcountsize; + + if (quot >= SCALE_1_TO_1) + s_scale = 1; + else if (quot >= SCALE_1_TO_1 / 256) + s_scale = SCALE_1_TO_1 / quot; + else if (range > ULONG_MAX / 256) + s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256)); + else + s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize); +#endif + } + else + s_scale = SCALE_1_TO_1; + + /* Start the profiler. */ + profil ((void *) kcount, kcountsize, lowpc, s_scale); + + /* Turn on profiling. */ + running = 1; +} + + +void +_dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc) +{ + volatile uint16_t *topcindex; + size_t i, fromindex; + struct here_fromstruct *fromp; + + if (! running) + return; + + /* Compute relative addresses. The shared object can be loaded at + any address. The value of frompc could be anything. We cannot + restrict it in any way, just set to a fixed value (0) in case it + is outside the allowed range. These calls show up as calls from + in the gprof output. */ + frompc -= lowpc; + if (frompc >= textsize) + frompc = 0; + selfpc -= lowpc; + if (selfpc >= textsize) + goto done; + + /* Getting here we now have to find out whether the location was + already used. If yes we are lucky and only have to increment a + counter (this also has to be atomic). If the entry is new things + are getting complicated... */ + + /* Avoid integer divide if possible. */ + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) + i = selfpc >> log_hashfraction; + else + i = selfpc / (hashfraction * sizeof (*tos)); + + topcindex = &tos[i]; + fromindex = *topcindex; + + if (fromindex == 0) + goto check_new_or_add; + + fromp = &froms[fromindex]; + + /* We have to look through the chain of arcs whether there is already + an entry for our arc. */ + while (fromp->here->from_pc != frompc) + { + if (fromp->link != 0) + do + fromp = &froms[fromp->link]; + while (fromp->link != 0 && fromp->here->from_pc != frompc); + + if (fromp->here->from_pc != frompc) + { + topcindex = &fromp->link; + + check_new_or_add: + /* Our entry is not among the entries we read so far from the + data file. Now see whether we have to update the list. */ + while (narcs != *narcsp && narcs < fromlimit) + { + size_t to_index; + size_t newfromidx; + to_index = (data[narcs].self_pc + / (hashfraction * sizeof (*tos))); + newfromidx = exchange_and_add (&fromidx, 1) + 1; + froms[newfromidx].here = &data[narcs]; + froms[newfromidx].link = tos[to_index]; + tos[to_index] = newfromidx; + atomic_add (&narcs, 1); + } + + /* If we still have no entry stop searching and insert. */ + if (*topcindex == 0) + { + uint32_t newarc = exchange_and_add (narcsp, 1); + + /* In rare cases it could happen that all entries in FROMS are + occupied. So we cannot count this anymore. */ + if (newarc >= fromlimit) + goto done; + + *topcindex = exchange_and_add (&fromidx, 1) + 1; + fromp = &froms[*topcindex]; + + fromp->here = &data[newarc]; + data[newarc].from_pc = frompc; + data[newarc].self_pc = selfpc; + data[newarc].count = 0; + fromp->link = 0; + atomic_add (&narcs, 1); + + break; + } + + fromp = &froms[*topcindex]; + } + else + /* Found in. */ + break; + } + + /* Increment the counter. */ + atomic_add (&fromp->here->count, 1); + + done: + ; +}
dl-profile.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: trusted-dirs.h =================================================================== --- trusted-dirs.h (nonexistent) +++ trusted-dirs.h (revision 158) @@ -0,0 +1,7 @@ +#define SYSTEM_DIRS \ + "/usr/local/lib/" + +#define SYSTEM_DIRS_LEN \ + 15 + +#define SYSTEM_DIRS_MAX_LEN 15
trusted-dirs.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-librecon.h =================================================================== --- dl-librecon.h (nonexistent) +++ dl-librecon.h (revision 158) @@ -0,0 +1,87 @@ +/* Optional code to distinguish library flavours. + Copyright (C) 1998, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_LIBRECON_H +#define _DL_LIBRECON_H 1 + +#define DISTINGUISH_LIB_VERSIONS \ + do \ + { \ + /* We have to find out whether the binary is linked against \ + libc 5 or glibc. We do this by looking at all the DT_NEEDED \ + entries. If one is libc.so.5 this is a libc 5 linked binary. */ \ + if (_dl_loaded->l_info[DT_NEEDED]) \ + { \ + /* We have dependencies. */ \ + const ElfW(Dyn) *d; \ + const char *strtab; \ + \ + strtab = (const char *) D_PTR (_dl_loaded, l_info[DT_STRTAB]); \ + \ + for (d = _dl_loaded->l_ld; d->d_tag != DT_NULL; ++d) \ + if (d->d_tag == DT_NEEDED \ + && strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \ + break; \ + \ + /* We print a `5' or `6' depending on the outcome. */ \ + _dl_printf (d->d_tag != DT_NULL ? "5\n" : "6\n"); \ + } \ + } \ + while (0) + +/* Recognizing extra environment variables. */ +#define EXTRA_LD_ENVVARS \ + case 13: \ + if (memcmp (envline, "ASSUME_KERNEL", 13) == 0) \ + { \ + unsigned long int i, j, osversion = 0; \ + char *p = &envline[14], *q; \ + \ + for (i = 0; i < 3; i++, p = q + 1) \ + { \ + j = __strtoul_internal (p, &q, 0, 0); \ + if (j >= 255 || p == q || (i < 2 && *q && *q != '.')) \ + { \ + osversion = 0; \ + break; \ + } \ + osversion |= j << (16 - 8 * i); \ + if (!*q) \ + break; \ + } \ + if (osversion) \ + _dl_osversion = osversion; \ + break; \ + } \ + \ + case 15: \ + if (memcmp (envline, "LIBRARY_VERSION", 15) == 0) \ + { \ + _dl_correct_cache_id = envline[16] == '5' ? 2 : 3; \ + break; \ + } + +/* Extra unsecure variables. The names are all stuffed in a single + string which means they have to be terminated with a '\0' explicitly. */ +#define EXTRA_UNSECURE_ENVVARS \ + "LD_AOUT_LIBRARY_PATH\0" \ + "LD_AOUT_PRELOAD\0" + +#endif /* dl-librecon.h */
dl-librecon.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-osinfo.h =================================================================== --- dl-osinfo.h (nonexistent) +++ dl-osinfo.h (revision 158) @@ -0,0 +1,108 @@ +/* Operating system specific code for generic dynamic loader functions. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include "kernel-features.h" + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifdef SHARED +/* This is the function used in the dynamic linker to print the fatal error + message. */ +static inline void +__attribute__ ((__noreturn__)) +dl_fatal (const char *str) +{ + _dl_dprintf (2, str); + _exit (1); +} +#endif + + +#define DL_SYSDEP_OSCHECK(FATAL) \ + do { \ + /* Test whether the kernel is new enough. This test is only \ + performed if the library is not compiled to run on all \ + kernels. */ \ + if (__LINUX_KERNEL_VERSION > 0) \ + { \ + char bufmem[64]; \ + char *buf = bufmem; \ + unsigned int version; \ + int parts; \ + char *cp; \ + struct utsname uts; \ + \ + /* Try the uname syscall */ \ + if (__uname (&uts)) \ + { \ + /* This was not successful. Now try reading the /proc \ + filesystem. */ \ + ssize_t reslen; \ + int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \ + if (fd == -1 \ + || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \ + /* This also didn't work. We give up since we cannot \ + make sure the library can actually work. */ \ + FATAL ("FATAL: cannot determine library version\n"); \ + __close (fd); \ + buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \ + } \ + else \ + buf = uts.release; \ + \ + /* Now convert it into a number. The string consists of at most \ + three parts. */ \ + version = 0; \ + parts = 0; \ + cp = buf; \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + unsigned int here = *cp++ - '0'; \ + \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + here *= 10; \ + here += *cp++ - '0'; \ + } \ + \ + ++parts; \ + version <<= 8; \ + version |= here; \ + \ + if (*cp++ != '.') \ + /* Another part following? */ \ + break; \ + } \ + \ + if (parts < 3) \ + version <<= 8 * (3 - parts); \ + \ + /* Now we can test with the required version. */ \ + if (version < __LINUX_KERNEL_VERSION) \ + /* Not sufficent. */ \ + FATAL ("FATAL: kernel too old\n"); \ + \ + _dl_osversion = version; \ + } \ + } while (0)
dl-osinfo.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: kernel-features.h =================================================================== --- kernel-features.h (nonexistent) +++ kernel-features.h (revision 158) @@ -0,0 +1,193 @@ +/* Set flags signalling availability of kernel features based on given + kernel version number. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file must not contain any C code. At least it must be protected + to allow using the file also in assembler files. */ + +#ifndef __LINUX_KERNEL_VERSION +/* We assume the worst; all kernels should be supported. */ +# define __LINUX_KERNEL_VERSION 0 +#endif + +/* We assume for __LINUX_KERNEL_VERSION the same encoding used in + linux/version.h. I.e., the major, minor, and subminor all get a + byte with the major number being in the highest byte. This means + we can do numeric comparisons. + + In the following we will define certain symbols depending on + whether the describes kernel feature is available in the kernel + version given by __LINUX_KERNEL_VERSION. We are not always exactly + recording the correct versions in which the features were + introduced. If somebody cares these values can afterwards be + corrected. Most of the numbers here are set corresponding to + 2.2.0. */ + +/* `getcwd' system call. */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_GETCWD_SYSCALL 1 +#endif + +/* Real-time signal became usable in 2.1.70. */ +#if __LINUX_KERNEL_VERSION >= 131398 +# define __ASSUME_REALTIME_SIGNALS 1 +#endif + +/* When were the `pread'/`pwrite' syscalls introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_PREAD_SYSCALL 1 +# define __ASSUME_PWRITE_SYSCALL 1 +#endif + +/* When was `poll' introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_POLL_SYSCALL 1 +#endif + +/* The `lchown' syscall was introduced in 2.1.80. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_LCHOWN_SYSCALL 1 +#endif + +/* When did the `setresuid' sysall became available? */ +#if __LINUX_KERNEL_VERSION >= 131584 && !defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +#endif + +/* The SIOCGIFNAME ioctl is available starting with 2.1.50. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_SIOCGIFNAME 1 +#endif + +/* On x86 another `getrlimit' syscall was added in 2.3.25. */ +#if __LINUX_KERNEL_VERSION >= 131865 && defined __i386__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* On x86 the truncate64/ftruncate64 syscalls were introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +#endif + +/* On x86 the mmap2 syscall was introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* On x86 the stat64/lstat64/fstat64 syscalls were introduced in 2.3.34. */ +#if __LINUX_KERNEL_VERSION >= 131874 && defined __i386__ +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* On sparc and ARM the truncate64/ftruncate64/mmap2/stat64/lstat64/fstat64 + syscalls were introduced in 2.3.35. */ +#if __LINUX_KERNEL_VERSION >= 131875 && (defined __sparc__ || defined __arm__) +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* I know for sure that these are in 2.3.35 on powerpc. */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* Linux 2.3.39 introduced 32bit UID/GIDs and IPC64. Some platforms had 32 + bit type all along. */ +#if __LINUX_KERNEL_VERSION >= 131879 || defined __powerpc__ || defined __mips__ +# define __ASSUME_32BITUIDS 1 +# ifndef __powerpc__ +# define __ASSUME_IPC64 1 +# endif +# ifdef __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +# endif +#endif + +/* Linux 2.4.0 on PPC introduced a correct IPC64. */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __powerpc__ +# define __ASSUME_IPC64 1 +#endif + +/* We can use the LDTs for threading with Linux 2.3.99 and newer. */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_LDT_WORKS 1 +#endif + +/* The changed st_ino field appeared in 2.4.0-test6. But we cannot + distinguish this version from other 2.4.0 releases. Therefore play + save and assume it available is for 2.4.1 and up. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_ST_INO_64_BIT 1 +#endif + +/* To support locking of large files a new fcntl() syscall was introduced + in 2.4.0-test7. We test for 2.4.1 for the earliest version we know + the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__) +# define __ASSUME_FCNTL64 1 +#endif + +/* Arm got fcntl64 in 2.4.4, PowerPC and SH have it also in 2.4.4 (I + don't know when it got introduced). */ +#if __LINUX_KERNEL_VERSION >= 132100 \ + && (defined __arm__ || defined __powerpc__ || defined __sh__) +# define __ASSUME_FCNTL64 1 +#endif + +/* The getdents64 syscall was introduced in 2.4.0-test7. We test for + 2.4.1 for the earliest version we know the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif + +/* When did O_DIRECTORY became available? Early in 2.3 but when? + Be safe, use 2.3.99. */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_O_DIRECTORY 1 +#endif + +/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes + up the page size information. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_PAGESIZE 1 +#endif + +/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way + and the mmap2 syscall made it into the official kernel. */ +#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ +# define __ASSUME_STD_AUXV 1 +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* There are an infinite number of PA-RISC kernel versions numbered + 2.4.0. But they've not really been released as such. We require + and expect the final version here. */ +#ifdef __hppa__ +# define __ASSUME_32BITUIDS 1 +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +# define __ASSUME_IPC64 1 +# define __ASSUME_ST_INO_64_BIT 1 +# define __ASSUME_FCNTL64 1 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif
kernel-features.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-profstub.c =================================================================== --- dl-profstub.c (nonexistent) +++ dl-profstub.c (revision 158) @@ -0,0 +1,43 @@ +/* Helper definitions for profiling of shared libraries. + Copyright (C) 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + +/* This is the map for the shared object we profile. It is defined here + only because we test for this value being NULL or not. */ +extern struct link_map *_dl_profile_map; + + +void +_dl_mcount_wrapper (void *selfpc) +{ + _dl_mcount ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc); +} + + +void +_dl_mcount_wrapper_check (void *selfpc) +{ + if (_dl_profile_map != NULL) + _dl_mcount ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc); +}
dl-profstub.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-close.c =================================================================== --- dl-close.c (nonexistent) +++ dl-close.c (revision 158) @@ -0,0 +1,334 @@ +/* Close a shared object opened by `_dl_open'. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + +void +internal_function +_dl_close (void *_map) +{ + struct reldep_list + { + struct link_map **rellist; + unsigned int nrellist; + struct reldep_list *next; + } *reldeps = NULL; + struct link_map **list; + struct link_map *map = _map; + unsigned int i; + unsigned int *new_opencount; + + /* First see whether we can remove the object at all. */ + if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0) + && map->l_init_called) + /* Nope. Do nothing. */ + return; + + if (__builtin_expect (map->l_opencount, 1) == 0) + _dl_signal_error (0, map->l_name, NULL, N_("shared object not open")); + + /* Acquire the lock. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + /* Decrement the reference count. */ + if (map->l_opencount > 1 || map->l_type != lt_loaded) + { + /* There are still references to this object. Do nothing more. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("\nclosing file=%s; opencount == %u\n", + map->l_name, map->l_opencount); + + /* One decrement the object itself, not the dependencies. */ + --map->l_opencount; + +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + return; + } + + list = map->l_initfini; + + /* Compute the new l_opencount values. */ + i = map->l_searchlist.r_nlist; + if (__builtin_expect (i == 0, 0)) + /* This can happen if we handle relocation dependencies for an + object which wasn't loaded directly. */ + for (i = 1; list[i] != NULL; ++i) + ; + + new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int)); + + for (i = 0; list[i] != NULL; ++i) + { + list[i]->l_idx = i; + new_opencount[i] = list[i]->l_opencount; + } + --new_opencount[0]; + for (i = 1; list[i] != NULL; ++i) + if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called) + /* Decrement counter. */ + && --new_opencount[i] == 0 + /* Test whether this object was also loaded directly. */ + && list[i]->l_searchlist.r_list != NULL) + { + /* In this case we have the decrement all the dependencies of + this object. They are all in MAP's dependency list. */ + unsigned int j; + struct link_map **dep_list = list[i]->l_searchlist.r_list; + + for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j) + if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE) + || ! dep_list[j]->l_init_called) + { + assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist); + --new_opencount[dep_list[j]->l_idx]; + } + } + assert (new_opencount[0] == 0); + + /* Call all termination functions at once. */ + for (i = 0; list[i] != NULL; ++i) + { + struct link_map *imap = list[i]; + if (new_opencount[i] == 0 && imap->l_type == lt_loaded + && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY]) + && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called) + /* Skip any half-cooked objects that were never initialized. */ + && imap->l_init_called) + { + /* When debugging print a message first. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name); + + /* Call its termination function. */ + if (imap->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (imap->l_addr + + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (imap->l_addr + array[cnt])) (); + } + + /* Next try the old-style destructor. */ + if (imap->l_info[DT_FINI] != NULL) + (*(void (*) (void)) DL_DT_FINI_ADDRESS + (imap, (void *) imap->l_addr + + imap->l_info[DT_FINI]->d_un.d_ptr)) (); + } + else if (new_opencount[i] != 0 && imap->l_type == lt_loaded) + { + /* The object is still used. But the object we are unloading + right now is responsible for loading it and therefore we + have the search list of the current object in its scope. + Remove it. */ + struct r_scope_elem **runp = imap->l_scope; + + while (*runp != NULL) + if (*runp == &map->l_searchlist) + { + /* Copy all later elements. */ + while ((runp[0] = runp[1]) != NULL) + ++runp; + break; + } + else + ++runp; + } + + /* Store the new l_opencount value. */ + imap->l_opencount = new_opencount[i]; + /* Just a sanity check. */ + assert (imap->l_type == lt_loaded || imap->l_opencount > 0); + } + + /* Notify the debugger we are about to remove some loaded objects. */ + _r_debug.r_state = RT_DELETE; + _dl_debug_state (); + + /* Check each element of the search list to see if all references to + it are gone. */ + for (i = 0; list[i] != NULL; ++i) + { + struct link_map *imap = list[i]; + if (imap->l_opencount == 0 && imap->l_type == lt_loaded) + { + struct libname_list *lnp; + + /* That was the last reference, and this was a dlopen-loaded + object. We can unmap it. */ + if (__builtin_expect (imap->l_global, 0)) + { + /* This object is in the global scope list. Remove it. */ + unsigned int cnt = _dl_main_searchlist->r_nlist; + + do + --cnt; + while (_dl_main_searchlist->r_list[cnt] != imap); + + /* The object was already correctly registered. */ + while (++cnt < _dl_main_searchlist->r_nlist) + _dl_main_searchlist->r_list[cnt - 1] + = _dl_main_searchlist->r_list[cnt]; + + --_dl_main_searchlist->r_nlist; + } + + /* We can unmap all the maps at once. We determined the + start address and length when we loaded the object and + the `munmap' call does the rest. */ + DL_UNMAP (imap); + + /* Finally, unlink the data structure and free it. */ +#ifdef SHARED + /* We will unlink the first object only if this is a statically + linked program. */ + assert (imap->l_prev != NULL); + imap->l_prev->l_next = imap->l_next; +#else + if (imap->l_prev != NULL) + imap->l_prev->l_next = imap->l_next; + else + _dl_loaded = imap->l_next; +#endif + --_dl_nloaded; + if (imap->l_next) + imap->l_next->l_prev = imap->l_prev; + + if (imap->l_versions != NULL) + free (imap->l_versions); + if (imap->l_origin != NULL && imap->l_origin != (char *) -1) + free ((char *) imap->l_origin); + + /* If the object has relocation dependencies save this + information for latter. */ + if (__builtin_expect (imap->l_reldeps != NULL, 0)) + { + struct reldep_list *newrel; + + newrel = (struct reldep_list *) alloca (sizeof (*reldeps)); + newrel->rellist = imap->l_reldeps; + newrel->nrellist = imap->l_reldepsact; + newrel->next = reldeps; + + reldeps = newrel; + } + + /* This name always is allocated. */ + free (imap->l_name); + /* Remove the list with all the names of the shared object. */ + lnp = imap->l_libname; + do + { + struct libname_list *this = lnp; + lnp = lnp->next; + if (!this->dont_free) + free (this); + } + while (lnp != NULL); + + /* Remove the searchlists. */ + if (imap != map) + free (imap->l_initfini); + + /* Remove the scope array if we allocated it. */ + if (imap->l_scope != imap->l_scope_mem) + free (imap->l_scope); + + if (imap->l_phdr_allocated) + free ((void *) imap->l_phdr); + + if (imap->l_rpath_dirs.dirs != (void *) -1) + free (imap->l_rpath_dirs.dirs); + if (imap->l_runpath_dirs.dirs != (void *) -1) + free (imap->l_runpath_dirs.dirs); + + free (imap); + } + } + + /* Notify the debugger those objects are finalized and gone. */ + _r_debug.r_state = RT_CONSISTENT; + _dl_debug_state (); + + /* Now we can perhaps also remove the modules for which we had + dependencies because of symbol lookup. */ + while (__builtin_expect (reldeps != NULL, 0)) + { + while (reldeps->nrellist-- > 0) + _dl_close (reldeps->rellist[reldeps->nrellist]); + + free (reldeps->rellist); + + reldeps = reldeps->next; + } + + free (list); + + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + +} + + +static void +free_mem (void) +{ + if (__builtin_expect (_dl_global_scope_alloc, 0) != 0 + && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist) + { + /* All object dynamically loaded by the program are unloaded. Free + the memory allocated for the global scope variable. */ + struct link_map **old = _dl_main_searchlist->r_list; + + /* Put the old map in. */ + _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list; + /* Signal that the original map is used. */ + _dl_global_scope_alloc = 0; + + /* Now free the old map. */ + free (old); + } +} +text_set_element (__libc_subfreeres, free_mem);
dl-close.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-sym.c =================================================================== --- dl-sym.c (nonexistent) +++ dl-sym.c (revision 158) @@ -0,0 +1,158 @@ +/* Look up a symbol in a shared object loaded by `dlopen'. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +#include +#include +#include + +void * +internal_function +_dl_sym (void *handle, const char *name, void *who) +{ + const ElfW(Sym) *ref = NULL; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope as seen in the caller object. */ + result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, 0); + else + { + if (handle != RTLD_NEXT) + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + + result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope, + 0, 1); + } + else + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_symbol_skip (name, l, &ref, l->l_local_scope, + match); + } + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +} + +void * +internal_function +_dl_vsym (void *handle, const char *name, const char *version, void *who) +{ + const ElfW(Sym) *ref = NULL; + struct r_found_version vers; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* Compute hash value to the version string. */ + vers.name = version; + vers.hidden = 1; + vers.hash = _dl_elf_hash (version); + /* We don't have a specific file where the symbol can be found. */ + vers.filename = NULL; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope. */ + result = _dl_lookup_versioned_symbol (name, match, &ref, match->l_scope, + &vers, 0, 0); + else if (handle == RTLD_NEXT) + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_versioned_symbol_skip (name, l, &ref, + l->l_local_scope, + &vers, match); + } + else + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + result = _dl_lookup_versioned_symbol (name, map, &ref, + map->l_local_scope, &vers, 0, 1); + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +}
dl-sym.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-libc.c =================================================================== --- dl-libc.c (nonexistent) +++ dl-libc.c (revision 158) @@ -0,0 +1,156 @@ +/* Handle loading and unloading shared objects for internal libc purposes. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Zack Weinberg , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +/* The purpose of this file is to provide wrappers around the dynamic + linker error mechanism (similar to dlopen() et al in libdl) which + are usable from within libc. Generally we want to throw away the + string that dlerror() would return and just pass back a null pointer + for errors. This also lets the rest of libc not know about the error + handling mechanism. + + Much of this code came from gconv_dl.c with slight modifications. */ + +static int +internal_function +dlerror_run (void (*operate) (void *), void *args) +{ + const char *objname; + const char *last_errstring = NULL; + int result; + + (void) _dl_catch_error (&objname, &last_errstring, operate, args); + + result = last_errstring != NULL; + if (result && last_errstring != _dl_out_of_memory) + free ((char *) last_errstring); + + return result; +} + +/* These functions are called by dlerror_run... */ + +struct do_dlopen_args +{ + /* Argument to do_dlopen. */ + const char *name; + + /* Return from do_dlopen. */ + struct link_map *map; +}; + +struct do_dlsym_args +{ + /* Arguments to do_dlsym. */ + struct link_map *map; + const char *name; + + /* Return values of do_dlsym. */ + lookup_t loadbase; + const ElfW(Sym) *ref; +}; + +static void +do_dlopen (void *ptr) +{ + struct do_dlopen_args *args = (struct do_dlopen_args *) ptr; + /* Open and relocate the shared object. */ + args->map = _dl_open (args->name, RTLD_LAZY, NULL); +} + +static void +do_dlsym (void *ptr) +{ + struct do_dlsym_args *args = (struct do_dlsym_args *) ptr; + args->ref = NULL; + args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref, + args->map->l_local_scope, 0, 1); +} + +static void +do_dlclose (void *ptr) +{ + _dl_close ((struct link_map *) ptr); +} + +/* ... and these functions call dlerror_run. */ + +void * +__libc_dlopen (const char *__name) +{ + struct do_dlopen_args args; + args.name = __name; + + return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map); +} + +void * +__libc_dlsym (void *__map, const char *__name) +{ + struct do_dlsym_args args; + args.map = __map; + args.name = __name; + + return (dlerror_run (do_dlsym, &args) ? NULL + : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref))); +} + +int +__libc_dlclose (void *__map) +{ + return dlerror_run (do_dlclose, __map); +} + + +static void +free_mem (void) +{ + struct link_map *l; + struct r_search_path_elem *d; + + /* Remove all search directories. */ + d = _dl_all_dirs; + while (d != _dl_init_all_dirs) + { + struct r_search_path_elem *old = d; + d = d->next; + free (old); + } + + /* Remove all additional names added to the objects. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + { + struct libname_list *lnp = l->l_libname->next; + + l->l_libname->next = NULL; + + while (lnp != NULL) + { + struct libname_list *old = lnp; + lnp = lnp->next; + if (! old->dont_free) + free (old); + } + } +} +text_set_element (__libc_subfreeres, free_mem);
dl-libc.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-lookup.c =================================================================== --- dl-lookup.c (nonexistent) +++ dl-lookup.c (revision 158) @@ -0,0 +1,654 @@ +/* Look up a symbol in the loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include "dl-hash.h" +#include +#include + +#include + +#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) + +/* We need this string more than once. */ +static const char undefined_msg[] = "undefined symbol: "; + + +struct sym_val + { + const ElfW(Sym) *s; + struct link_map *m; + }; + + +#define make_string(string, rest...) \ + ({ \ + const char *all[] = { string, ## rest }; \ + size_t len, cnt; \ + char *result, *cp; \ + \ + len = 1; \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + len += strlen (all[cnt]); \ + \ + cp = result = alloca (len); \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + { \ + cp = strcpy (cp, all[cnt]); \ + cp += strlen(all[cnt]); \ + } \ + \ + result; \ + }) + +/* Statistics function. */ +unsigned long int _dl_num_relocations; + + +/* We have two different situations when looking up a simple: with or + without versioning. gcc is not able to optimize a single function + definition serving for both purposes so we define two functions. */ +#define VERSIONED 0 +#include "do-lookup.h" + +#define VERSIONED 1 +#include "do-lookup.h" + + +/* Add extra dependency on MAP to UNDEF_MAP. */ +static int +internal_function +add_dependency (struct link_map *undef_map, struct link_map *map) +{ + struct link_map **list; + struct link_map *runp; + unsigned int act; + unsigned int i; + int result = 0; + + /* Avoid self-references. */ + if (undef_map == map) + return 0; + + /* Make sure nobody can unload the object while we are at it. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + /* Determine whether UNDEF_MAP already has a reference to MAP. First + look in the normal dependencies. */ + if (undef_map->l_searchlist.r_list != NULL) + { + list = undef_map->l_initfini; + + for (i = 0; list[i] != NULL; ++i) + if (list[i] == map) + goto out; + } + + /* No normal dependency. See whether we already had to add it + to the special list of dynamic dependencies. */ + list = undef_map->l_reldeps; + act = undef_map->l_reldepsact; + + for (i = 0; i < act; ++i) + if (list[i] == map) + goto out; + + /* The object is not yet in the dependency list. Before we add + it make sure just one more time the object we are about to + reference is still available. There is a brief period in + which the object could have been removed since we found the + definition. */ + runp = _dl_loaded; + while (runp != NULL && runp != map) + runp = runp->l_next; + + if (runp != NULL) + { + /* The object is still available. Add the reference now. */ + if (__builtin_expect (act >= undef_map->l_reldepsmax, 0)) + { + /* Allocate more memory for the dependency list. Since this + can never happen during the startup phase we can use + `realloc'. */ + void *newp; + + undef_map->l_reldepsmax += 5; + newp = realloc (undef_map->l_reldeps, + undef_map->l_reldepsmax + * sizeof (struct link_map *)); + + if (__builtin_expect (newp != NULL, 1)) + undef_map->l_reldeps = (struct link_map **) newp; + else + /* Correct the addition. */ + undef_map->l_reldepsmax -= 5; + } + + /* If we didn't manage to allocate memory for the list this is + no fatal mistake. We simply increment the use counter of the + referenced object and don't record the dependencies. This + means this increment can never be reverted and the object + will never be unloaded. This is semantically the correct + behaviour. */ + if (__builtin_expect (act < undef_map->l_reldepsmax, 1)) + undef_map->l_reldeps[undef_map->l_reldepsact++] = map; + + if (map->l_searchlist.r_list != NULL) + /* And increment the counter in the referenced object. */ + ++map->l_opencount; + else + /* We have to bump the counts for all dependencies since so far + this object was only a normal or transitive dependency. + Now it might be closed with _dl_close() directly. */ + for (list = map->l_initfini; *list != NULL; ++list) + ++(*list)->l_opencount; + + /* Display information if we are debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("\ +\nfile=%s; needed by %s (relocation dependency)\n\n", + map->l_name[0] ? map->l_name : _dl_argv[0], + undef_map->l_name[0] + ? undef_map->l_name : _dl_argv[0]); + } + else + /* Whoa, that was bad luck. We have to search again. */ + result = -1; + + out: + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + + return result; +} + +static int +internal_function +_dl_do_lookup (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + struct link_map *skip, int type_class); +static int +internal_function +_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + const struct r_found_version *const version, + struct link_map *skip, int type_class); + + +/* Search loaded objects' symbol tables for a definition of the symbol + UNDEF_NAME. */ + +lookup_t +internal_function +_dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, + const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], + int type_class, int explicit) +{ + unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + for (scope = symbol_scope; *scope; ++scope) + if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, NULL, + type_class)) + { + /* We have to check whether this would bind UNDEF_MAP to an object + in the global scope which was dynamically loaded. In this case + we have to prevent the latter from being unloaded unless the + UNDEF_MAP object is also unloaded. */ + if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && ! explicit + /* Add UNDEF_MAP to the dependencies. */ + && add_dependency (undef_map, current_value.m) < 0) + /* Something went wrong. Perhaps the object we tried to reference + was just removed. Try finding another definition. */ + return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope, + type_class, 0); + + break; + } + + if (__builtin_expect (current_value.s == NULL, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + /* We could find no value for a strong reference. */ + /* XXX We cannot translate the messages. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + N_("relocation error"), + make_string (undefined_msg, undef_name)); + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", undef_name); + } + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + for (scope = symbol_scope; *scope; ++scope) + if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + 0, NULL, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* This function is nearly the same as `_dl_lookup_symbol' but it + skips in the first list all objects until SKIP_MAP is found. I.e., + it only considers objects which were loaded after the described + object. If there are more search lists the object described by + SKIP_MAP is only skipped. */ +lookup_t +internal_function +_dl_lookup_symbol_skip (const char *undef_name, + struct link_map *undef_map, const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + struct link_map *skip_map) +{ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + const unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + size_t i; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + scope = symbol_scope; + for (i = 0; (*scope)->r_list[i] != skip_map; ++i) + assert (i < (*scope)->r_nlist); + + if (! _dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, i, + skip_map, 0)) + while (*++scope) + if (_dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, + skip_map, 0)) + break; + + if (__builtin_expect (current_value.s == NULL, 0)) + { + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", undef_name); + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol. */ + struct sym_val protected_value = { NULL, NULL }; + + if (i >= (*scope)->r_nlist + || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + i, skip_map, ELF_RTYPE_CLASS_PLT)) + while (*++scope) + if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + 0, skip_map, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* This function works like _dl_lookup_symbol but it takes an + additional arguement with the version number of the requested + symbol. + + XXX We'll see whether we need this separate function. */ +lookup_t +internal_function +_dl_lookup_versioned_symbol (const char *undef_name, + struct link_map *undef_map, const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + int type_class, int explicit) +{ + unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + for (scope = symbol_scope; *scope; ++scope) + { + int res = do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, 0, version, NULL, type_class); + if (res > 0) + { + /* We have to check whether this would bind UNDEF_MAP to an object + in the global scope which was dynamically loaded. In this case + we have to prevent the latter from being unloaded unless the + UNDEF_MAP object is also unloaded. */ + if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && ! explicit + /* Add UNDEF_MAP to the dependencies. */ + && add_dependency (undef_map, current_value.m) < 0) + /* Something went wrong. Perhaps the object we tried to reference + was just removed. Try finding another definition. */ + return _dl_lookup_versioned_symbol (undef_name, undef_map, ref, + symbol_scope, version, + type_class, 0); + + break; + } + + if (__builtin_expect (res, 0) < 0) + { + /* Oh, oh. The file named in the relocation entry does not + contain the needed symbol. */ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + /* XXX We cannot translate the message. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + N_("relocation error"), + make_string ("symbol ", undef_name, ", version ", + version->name, + " not defined in file ", + version->filename, + " with link time reference", + res == -2 + ? " (no version symbols)" : "")); + *ref = NULL; + return 0; + } + } + + if (__builtin_expect (current_value.s == NULL, 0)) + { + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + { + /* We could find no value for a strong reference. */ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + /* XXX We cannot translate the message. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), NULL, + make_string (undefined_msg, undef_name, + ", version ", + version->name ?: NULL)); + } + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", + undef_name, version->name); + } + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + for (scope = symbol_scope; *scope; ++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, &protected_value, + *scope, 0, version, NULL, + ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* Similar to _dl_lookup_symbol_skip but takes an additional argument + with the version we are looking for. */ +lookup_t +internal_function +_dl_lookup_versioned_symbol_skip (const char *undef_name, + struct link_map *undef_map, + const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + struct link_map *skip_map) +{ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + const unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + size_t i; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + scope = symbol_scope; + for (i = 0; (*scope)->r_list[i] != skip_map; ++i) + assert (i < (*scope)->r_nlist); + + if (! _dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, i, version, skip_map, 0)) + while (*++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, 0, version, skip_map, 0)) + break; + + if (__builtin_expect (current_value.s == NULL, 0)) + { + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + { + /* We could find no value for a strong reference. */ + const size_t len = strlen (undef_name); + char buf[sizeof undefined_msg + len]; + char *tmp; + tmp = memcpy (buf, undefined_msg, sizeof undefined_msg - 1); + tmp += (sizeof undefined_msg - 1); + + memcpy (tmp, undef_name, len + 1); + + /* XXX We cannot translate the messages. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + NULL, buf); + } + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", + undef_name, version->name); + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + if (i >= (*scope)->r_nlist + || !_dl_do_lookup_versioned (undef_name, hash, *ref, + &protected_value, *scope, i, version, + skip_map, ELF_RTYPE_CLASS_PLT)) + while (*++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, + &protected_value, *scope, 0, version, + skip_map, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* Cache the location of MAP's hash table. */ + +void +internal_function +_dl_setup_hash (struct link_map *map) +{ + Elf_Symndx *hash; + Elf_Symndx nchain; + + if (!map->l_info[DT_HASH]) + return; + hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr); + + map->l_nbuckets = *hash++; + nchain = *hash++; + map->l_buckets = hash; + hash += map->l_nbuckets; + map->l_chain = hash; +} + +/* These are here so that we only inline do_lookup{,_versioned} in the common + case, not everywhere. */ +static int +internal_function +_dl_do_lookup (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + struct link_map *skip, int type_class) +{ + return do_lookup (undef_name, hash, ref, result, scope, i, skip, + type_class); +} + +static int +internal_function +_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + const struct r_found_version *const version, + struct link_map *skip, int type_class) +{ + return do_lookup_versioned (undef_name, hash, ref, result, scope, i, + version, skip, type_class); +}
dl-lookup.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: atomicity.h =================================================================== --- atomicity.h (nonexistent) +++ atomicity.h (revision 158) @@ -0,0 +1,56 @@ +/* Low-level functions for atomic operations. ix86 version, x >= 4. + Copyright (C) 1997, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _ATOMICITY_H +#define _ATOMICITY_H 1 + + + +static inline uint32_t +__attribute__ ((unused)) +exchange_and_add (volatile uint32_t *mem, uint32_t val) +{ + register uint32_t result; + __asm__ __volatile__ ("lock; xaddl %0,%1" + : "=r" (result), "=m" (*mem) : "m" (val), "1" (*mem)); + return result; +} + +static inline void +__attribute__ ((unused)) +atomic_add (volatile uint32_t *mem, int val) +{ + __asm__ __volatile__ ("lock; addl %1,%0" + : "=m" (*mem) : "ir" (val), "m" (*mem)); +} + +static inline char +__attribute__ ((unused)) +compare_and_swap (volatile long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "1" (*p), "a" (oldval)); + return ret; +} + +#endif /* atomicity.h */
atomicity.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-support.c =================================================================== --- dl-support.c (nonexistent) +++ dl-support.c (revision 158) @@ -0,0 +1,184 @@ +/* Support for dynamic linking code in static libc. + Copyright (C) 1996, 97, 98, 99, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file defines some things that for the dynamic linker are defined in + rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *__progname = "newlib"; +char **_dl_argv = &__progname; /* This is checked for some error messages. */ + +/* Name of the architecture. */ +const char *_dl_platform; +size_t _dl_platformlen; + +int _dl_debug_mask; +int _dl_lazy; +/* XXX I know about at least one case where we depend on the old weak + behavior (it has to do with librt). Until we get DSO groups implemented + we have to make this the default. Bummer. --drepper */ +#if 0 +int _dl_dynamic_weak; +#else +int _dl_dynamic_weak = 1; +#endif + +/* If nonzero print warnings about problematic situations. */ +int _dl_verbose; + +/* Structure to store information about search paths. */ +struct r_search_path *_dl_search_paths; + +/* We never do profiling. */ +const char *_dl_profile; + +/* Names of shared object for which the RUNPATHs and RPATHs should be + ignored. */ +const char *_dl_inhibit_rpath; + +/* The map for the object we will profile. */ +struct link_map *_dl_profile_map; + +/* This is the address of the last stack address ever used. */ +void *__libc_stack_end; + +/* Path where the binary is found. */ +const char *_dl_origin_path; + +/* Nonzero if runtime lookup should not update the .got/.plt. */ +int _dl_bind_not; + +/* Initially empty list of loaded objects. */ +struct link_map *_dl_loaded; +/* Number of object in the _dl_loaded list. */ +unsigned int _dl_nloaded; + +/* Fake scope. In dynamically linked binaries this is the scope of the + main application but here we don't have something like this. So + create a fake scope containing nothing. */ +struct r_scope_elem _dl_initial_searchlist; +/* Variable which can be used in lookup to process the global scope. */ +struct r_scope_elem *_dl_global_scope[2] = { &_dl_initial_searchlist, NULL }; +/* This is a global pointer to this structure which is public. It is + used by dlopen/dlclose to add and remove objects from what is regarded + to be the global scope. */ +struct r_scope_elem *_dl_main_searchlist = &_dl_initial_searchlist; + +/* Nonzero during startup. */ +int _dl_starting_up = 1; + +/* We expect less than a second for relocation. */ +#ifdef HP_SMALL_TIMING_AVAIL +# undef HP_TIMING_AVAIL +# define HP_TIMING_AVAIL HP_SMALL_TIMING_AVAIL +#endif + +/* Initial value of the CPU clock. */ +#ifndef HP_TIMING_NONAVAIL +hp_timing_t _dl_cpuclock_offset; +#endif + +/* During the program run we must not modify the global data of + loaded shared object simultanously in two threads. Therefore we + protect `_dl_open' and `_dl_close' in dl-close.c. + + This must be a recursive lock since the initializer function of + the loaded object might as well require a call to this function. + At this time it is not anymore a problem to modify the tables. */ +__LOCK_INIT_RECURSIVE(, _dl_load_lock) + + +#ifdef HAVE_AUX_VECTOR +extern int _dl_clktck; + +void +internal_function +_dl_aux_init (ElfW(auxv_t) *av) +{ + for (; av->a_type != AT_NULL; ++av) + switch (av->a_type) + { + case AT_PAGESZ: + _dl_pagesize = av->a_un.a_val; + break; + case AT_CLKTCK: + _dl_clktck = av->a_un.a_val; + break; + } +} +#endif + +void non_dynamic_init (void) __attribute__ ((unused)); + +void +non_dynamic_init (void) +{ + if (HP_TIMING_AVAIL) + HP_TIMING_NOW (_dl_cpuclock_offset); + + if (!_dl_pagesize) + _dl_pagesize = __getpagesize (); + + _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + + /* Initialize the data structures for the search paths for shared + objects. */ + _dl_init_paths (getenv ("LD_LIBRARY_PATH")); + + _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; + + _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; + + _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; + +#ifdef DL_PLATFORM_INIT + DL_PLATFORM_INIT; +#endif + + /* Now determine the length of the platform string. */ + if (_dl_platform != NULL) + _dl_platformlen = strlen (_dl_platform); +} +text_set_element (__libc_subinit, non_dynamic_init); + +const struct r_strlenpair * +internal_function +_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + size_t *max_capstrlen) +{ + static struct r_strlenpair result; + static char buf[1]; + + result.str = buf; /* Does not really matter. */ + result.len = 0; + + *sz = 1; + return &result; +}
dl-support.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: abi-tag.h =================================================================== --- abi-tag.h (nonexistent) +++ abi-tag.h (revision 158) @@ -0,0 +1,4 @@ +#define __ABI_TAG_OS 0 +#ifndef __ABI_TAG_VERSION +# define __ABI_TAG_VERSION 2,0,0 +#endif
abi-tag.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-runtime.c =================================================================== --- dl-runtime.c (nonexistent) +++ dl-runtime.c (revision 158) @@ -0,0 +1,233 @@ +/* On-demand PLT fixup for shared objects. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include "dynamic-link.h" + +#ifndef __attribute_used__ +#define __attribute_used__ +#endif + +#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL +# define PLTREL ElfW(Rela) +#else +# define PLTREL ElfW(Rel) +#endif + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + + +/* This function is called through a special trampoline from the PLT the + first time each PLT entry is called. We must perform the relocation + specified in the PLT of the given shared object, and return the resolved + function address to the trampoline, which will restart the original call + to that address. Future calls will bounce directly from the PLT to the + function. */ + +#ifndef ELF_MACHINE_NO_PLT +static ElfW(Addr) __attribute__ ((regparm (2), used)) +fixup ( +# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +# endif + /* GKM FIXME: Fix trampoline to pass bounds so we can do + without the `__unbounded' qualifier. */ + struct link_map *__unbounded l, ElfW(Word) reloc_offset) +{ + const ElfW(Sym) *const symtab + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + const PLTREL *const reloc + = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); + const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); + lookup_t result; + ElfW(Addr) value; + + /* The use of `alloca' here looks ridiculous but it helps. The goal is + to prevent the function from being inlined and thus optimized out. + There is no official way to do this so we use this trick. gcc never + inlines functions which use `alloca'. */ + alloca (sizeof (int)); + + /* Sanity check that we're really looking at a PLT relocation. */ + assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); + + /* Look up the target symbol. If the normal lookup rules are not + used don't look in the global scope. */ + if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) + { + switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) + { + default: + { + const ElfW(Half) *vernum = + (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); + ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; + const struct r_found_version *version = &l->l_versions[ndx]; + + if (version->hash != 0) + { + result = _dl_lookup_versioned_symbol (strtab + sym->st_name, + l, &sym, l->l_scope, + version, + ELF_RTYPE_CLASS_PLT, 0); + break; + } + } + case 0: + result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, + l->l_scope, ELF_RTYPE_CLASS_PLT, 0); + } + + /* Currently result contains the base load address (or link map) + of the object that defines sym. Now add in the symbol + offset. */ + value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0); + } + else + { + /* We already found the symbol. The module (and therefore its load + address) is also known. */ + value = l->l_addr + sym->st_value; +#ifdef DL_LOOKUP_RETURNS_MAP + result = l; +#endif + } + + /* And now perhaps the relocation addend. */ + value = elf_machine_plt_value (l, reloc, value); + + /* Finally, fix up the plt itself. */ + if (__builtin_expect (_dl_bind_not, 0)) + return value; + + return elf_machine_fixup_plt (l, result, reloc, rel_addr, value); +} +#endif + +#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__ + +static ElfW(Addr) __attribute__ ((regparm (3), used)) +profile_fixup ( +#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +#endif + struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr) +{ + void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount; + ElfW(Addr) *resultp; + lookup_t result; + ElfW(Addr) value; + + /* The use of `alloca' here looks ridiculous but it helps. The goal is + to prevent the function from being inlined, and thus optimized out. + There is no official way to do this so we use this trick. gcc never + inlines functions which use `alloca'. */ + alloca (sizeof (int)); + + /* This is the address in the array where we store the result of previous + relocations. */ + resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)]; + + value = *resultp; + if (value == 0) + { + /* This is the first time we have to relocate this object. */ + const ElfW(Sym) *const symtab + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + const PLTREL *const reloc + = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); + const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + + /* Sanity check that we're really looking at a PLT relocation. */ + assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); + + /* Look up the target symbol. If the symbol is marked STV_PROTECTED + don't look in the global scope. */ + if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) + { + switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) + { + default: + { + const ElfW(Half) *vernum = + (const void *) D_PTR (l,l_info[VERSYMIDX (DT_VERSYM)]); + ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; + const struct r_found_version *version = &l->l_versions[ndx]; + + if (version->hash != 0) + { + result = _dl_lookup_versioned_symbol(strtab + sym->st_name, + l, &sym, l->l_scope, + version, + ELF_RTYPE_CLASS_PLT, + 0); + break; + } + } + case 0: + result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, + l->l_scope, ELF_RTYPE_CLASS_PLT, 0); + } + + /* Currently result contains the base load address (or link map) + of the object that defines sym. Now add in the symbol + offset. */ + value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0); + } + else + { + /* We already found the symbol. The module (and therefore its load + address) is also known. */ + value = l->l_addr + sym->st_value; +#ifdef DL_LOOKUP_RETURNS_MAP + result = l; +#endif + } + /* And now perhaps the relocation addend. */ + value = elf_machine_plt_value (l, reloc, value); + + /* Store the result for later runs. */ + if (__builtin_expect (! _dl_bind_not, 1)) + *resultp = value; + } + + (*mcount_fct) (retaddr, value); + + return value; +} + +#endif /* PROF && ELF_MACHINE_NO_PLT */ + + +/* This macro is defined in dl-machine.h to define the entry point called + by the PLT. The `fixup' function above does the real work, but a little + more twiddling is needed to get the stack right and jump to the address + finally resolved. */ + +ELF_MACHINE_RUNTIME_TRAMPOLINE
dl-runtime.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-fini.c =================================================================== --- dl-fini.c (nonexistent) +++ dl-fini.c (revision 158) @@ -0,0 +1,172 @@ +/* Call the termination functions of loaded shared objects. + Copyright (C) 1995,96,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + + +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + +void +internal_function +_dl_fini (void) +{ + /* Lots of fun ahead. We have to call the destructors for all still + loaded objects. The problem is that the ELF specification now + demands that dependencies between the modules are taken into account. + I.e., the destructor for a module is called before the ones for any + of its dependencies. + + To make things more complicated, we cannot simply use the reverse + order of the constructors. Since the user might have loaded objects + using `dlopen' there are possibly several other modules with its + dependencies to be taken into account. Therefore we have to start + determining the order of the modules once again from the beginning. */ + unsigned int i; + struct link_map *l; + struct link_map **maps; + + /* XXX Could it be (in static binaries) that there is no object loaded? */ + assert (_dl_nloaded > 0); + + /* Now we can allocate an array to hold all the pointers and copy + the pointers in. */ + maps = (struct link_map **) alloca (_dl_nloaded + * sizeof (struct link_map *)); + for (l = _dl_loaded, i = 0; l != NULL; l = l->l_next) + { + assert (i < _dl_nloaded); + + maps[i++] = l; + + /* Bump l_opencount of all objects so that they are not dlclose()ed + from underneath us. */ + ++l->l_opencount; + } + assert (i == _dl_nloaded); + + /* Now we have to do the sorting. */ + for (l = _dl_loaded->l_next; l != NULL; l = l->l_next) + { + unsigned int j; + unsigned int k; + + /* Find the place in the `maps' array. */ + for (j = 1; maps[j] != l; ++j) + ; + + /* Find all object for which the current one is a dependency and + move the found object (if necessary) in front. */ + for (k = j + 1; k < _dl_nloaded; ++k) + { + struct link_map **runp; + + runp = maps[k]->l_initfini; + if (runp != NULL) + { + while (*runp != NULL) + if (*runp == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j++] = here; + + break; + } + else + ++runp; + } + + if (__builtin_expect (maps[k]->l_reldeps != NULL, 0)) + { + unsigned int m = maps[k]->l_reldepsact; + struct link_map **relmaps = maps[k]->l_reldeps; + + while (m-- > 0) + { + if (relmaps[m] == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j] = here; + + break; + } + + } + } + } + } + + /* `maps' now contains the objects in the right order. Now call the + destructors. We have to process this array from the front. */ + for (i = 0; i < _dl_nloaded; ++i) + { + l = maps[i]; + + if (l->l_init_called) + { + /* Make sure nothing happens if we are called twice. */ + l->l_init_called = 0; + + /* Don't call the destructors for objects we are not supposed to. */ + if (l->l_name[0] == '\0' && l->l_type == lt_executable) + continue; + + /* Is there a destructor function? */ + if (l->l_info[DT_FINI_ARRAY] == NULL && l->l_info[DT_FINI] == NULL) + continue; + + /* When debugging print a message first. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling fini: %s\n\n", + l->l_name[0] ? l->l_name : _dl_argv[0]); + + /* First see whether an array is given. */ + if (l->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (l->l_addr + + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (l->l_addr + array[cnt])) (); + } + + /* Next try the old-style destructor. */ + if (l->l_info[DT_FINI] != NULL) + ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + } + } +}
dl-fini.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-debug.c =================================================================== --- dl-debug.c (nonexistent) +++ dl-debug.c (revision 158) @@ -0,0 +1,57 @@ +/* Communicate dynamic linker state to the debugger at runtime. + Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +/* This structure communicates dl state to the debugger. The debugger + normally finds it via the DT_DEBUG entry in the dynamic section, but in + a statically-linked program there is no dynamic section for the debugger + to examine and it looks for this particular symbol name. */ +struct r_debug _r_debug; + + +/* Initialize _r_debug if it has not already been done. The argument is + the run-time load address of the dynamic linker, to be put in + _r_debug.r_ldbase. Returns the address of _r_debug. */ + +struct r_debug * +internal_function +_dl_debug_initialize (ElfW(Addr) ldbase) +{ + if (_r_debug.r_brk == 0) + { + /* Tell the debugger where to find the map of loaded objects. */ + _r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; + _r_debug.r_ldbase = ldbase; + _r_debug.r_map = _dl_loaded; + _r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state; + } + + return &_r_debug; +} + + +/* This function exists solely to have a breakpoint set on it by the + debugger. The debugger is supposed to find this function's address by + examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks + for this particular symbol name in the PT_INTERP file. */ +void +_dl_debug_state (void) +{ +}
dl-debug.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-minimal.c =================================================================== --- dl-minimal.c (nonexistent) +++ dl-minimal.c (revision 158) @@ -0,0 +1,250 @@ +/* Minimal replacements for basic facilities used in the dynamic linker. + Copyright (C) 1995,96,97,98,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Minimal `malloc' allocator for use while loading shared libraries. + No block is ever freed. */ + +static void *alloc_ptr, *alloc_end, *alloc_last_block; + +/* Declarations of global functions. */ +extern void weak_function free (void *ptr); +extern void * weak_function realloc (void *ptr, size_t n); +extern unsigned long int weak_function __strtoul_internal +(const char *nptr, char **endptr, int base, int group); +extern unsigned long int weak_function strtoul (const char *nptr, + char **endptr, int base); + + +void * weak_function +malloc (size_t n) +{ +#ifdef MAP_ANON +#define _dl_zerofd (-1) +#else + extern int _dl_zerofd; + + if (_dl_zerofd == -1) + _dl_zerofd = _dl_sysdep_open_zero_fill (); +#define MAP_ANON 0 +#endif + + if (alloc_end == 0) + { + /* Consume any unused space in the last page of our data segment. */ + extern int _end; + alloc_ptr = &_end; + alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + } + + /* Make sure the allocation pointer is ideally aligned. */ + alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + sizeof (double) - 1) + & ~(sizeof (double) - 1)); + + if (alloc_ptr + n >= alloc_end) + { + /* Insufficient space left; allocate another page. */ + caddr_t page; + size_t nup = (n + _dl_pagesize - 1) & ~(_dl_pagesize - 1); + page = __mmap (0, nup, PROT_READ|PROT_WRITE, + MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0); + assert (page != MAP_FAILED); + if (page != alloc_end) + alloc_ptr = page; + alloc_end = page + nup; + } + + alloc_last_block = (void *) alloc_ptr; + alloc_ptr += n; + return alloc_last_block; +} + +/* We use this function occasionally since the real implementation may + be optimized when it can assume the memory it returns already is + set to NUL. */ +void * weak_function +calloc (size_t nmemb, size_t size) +{ + size_t total = nmemb * size; + void *result = malloc (total); + return memset (result, '\0', total); +} + +/* This will rarely be called. */ +void weak_function +free (void *ptr) +{ + /* We can free only the last block allocated. */ + if (ptr == alloc_last_block) + alloc_ptr = alloc_last_block; +} + +/* This is only called with the most recent block returned by malloc. */ +void * weak_function +realloc (void *ptr, size_t n) +{ + void *new; + if (ptr == NULL) + return malloc (n); + assert (ptr == alloc_last_block); + alloc_ptr = alloc_last_block; + new = malloc (n); + assert (new == ptr); + return new; +} + + +/* Define our own version of the internal function used by strerror. We + only provide the messages for some common errors. This avoids pulling + in the whole error list. */ + +char * weak_function +__strerror_r (int errnum, char *buf, size_t buflen) +{ + char *msg; + + switch (errnum) + { + case ENOMEM: + msg = (char *) "Cannot allocate memory"; + break; + case EINVAL: + msg = (char *) "Invalid argument"; + break; + case ENOENT: + msg = (char *) "No such file or directory"; + break; + case EPERM: + msg = (char *) "Operation not permitted"; + break; + case EIO: + msg = (char *) "Input/output error"; + break; + case EACCES: + msg = (char *) "Permission denied"; + break; + default: + /* No need to check buffer size, all calls in the dynamic linker + provide enough space. */ + msg = (char *) "Error"; + break; + } + + return msg; +} + +#ifndef NDEBUG + +/* Define (weakly) our own assert failure function which doesn't use stdio. + If we are linked into the user program (-ldl), the normal __assert_fail + defn can override this one. */ + +void weak_function +__assert_fail (const char *assertion, + const char *file, unsigned int line, const char *function) +{ + _dl_fatal_printf ("\ +Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n", + file, line, function ?: "", function ? ": " : "", + assertion); + +} + +void weak_function +__assert_perror_fail (int errnum, + const char *file, unsigned int line, + const char *function) +{ + char errbuf[64]; + _dl_fatal_printf ("\ +Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s\n", + file, line, function ?: "", function ? ": " : "", + __strerror_r (errnum, errbuf, sizeof (errbuf))); +} + +#endif + +unsigned long int weak_function +__strtoul_internal (const char *nptr, char **endptr, int base, int group) +{ + unsigned long int result = 0; + long int sign = 1; + + while (*nptr == ' ' || *nptr == '\t') + ++nptr; + + if (*nptr == '-') + { + sign = -1; + ++nptr; + } + else if (*nptr == '+') + ++nptr; + + if (*nptr < '0' || *nptr > '9') + { + if (endptr != NULL) + *endptr = (char *) nptr; + return 0UL; + } + + assert (base == 0); + base = 10; + if (*nptr == '0') + { + if (nptr[1] == 'x' || nptr[1] == 'X') + { + base = 16; + nptr += 2; + } + else + base = 8; + } + + while (*nptr >= '0' && *nptr <= '9') + { + unsigned long int digval = *nptr - '0'; + if (result > LONG_MAX / 10 + || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10)) + { + errno = ERANGE; + if (endptr != NULL) + *endptr = (char *) nptr; + return ULONG_MAX; + } + result *= base; + result += digval; + ++nptr; + } + + if (endptr != NULL) + *endptr = (char *) nptr; + return result * sign; +}
dl-minimal.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-error.c =================================================================== --- dl-error.c (nonexistent) +++ dl-error.c (revision 158) @@ -0,0 +1,189 @@ +/* Error handling for runtime dynamic linker. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + +/* This structure communicates state between _dl_catch_error and + _dl_signal_error. */ +struct catch + { + const char *objname; /* Object/File name. */ + const char *errstring; /* Error detail filled in here. */ + jmp_buf env; /* longjmp here on error. */ + }; + +/* Multiple threads at once can use the `_dl_catch_error' function. The + calls can come from `_dl_map_object_deps', `_dlerror_run', or from + any of the libc functionality which loads dynamic objects (NSS, iconv). + Therefore we have to be prepared to save the state in thread-local + memory. */ + +__libc_tsd_define (static, DL_ERROR) +#define tsd_getspecific() __libc_tsd_get (DL_ERROR) +#define tsd_setspecific(data) __libc_tsd_set (DL_ERROR, (data)) + + +/* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable + a pointer comparison. See below and in dlfcn/dlerror.c. */ +const char _dl_out_of_memory[] = "out of memory"; + + +/* This points to a function which is called when an continuable error is + received. Unlike the handling of `catch' this function may return. + The arguments will be the `errstring' and `objname'. + + Since this functionality is not used in normal programs (only in ld.so) + we do not care about multi-threaded programs here. We keep this as a + global variable. */ +static receiver_fct receiver; + + +void +internal_function +_dl_signal_error (int errcode, const char *objname, const char *occation, + const char *errstring) +{ + struct catch *lcatch; + + if (! errstring) + errstring = N_("DYNAMIC LINKER BUG!!!"); + + lcatch = tsd_getspecific (); + if (objname == NULL) + objname = ""; + if (lcatch != NULL) + { + /* We are inside _dl_catch_error. Return to it. We have to + duplicate the error string since it might be allocated on the + stack. The object name is always a string constant. */ + size_t len_objname = strlen (objname) + 1; + size_t len_errstring = strlen (errstring) + 1; + + lcatch->errstring = (char *) malloc (len_objname + len_errstring); + if (lcatch->errstring != NULL) + { + char *tmp; + /* Make a copy of the object file name and the error string. */ + tmp = memcpy ((char *) lcatch->errstring, + errstring, len_errstring); + tmp += len_errstring; + lcatch->objname = memcpy (tmp, + objname, len_objname); + } + else + { + /* This is better than nothing. */ + lcatch->objname = ""; + lcatch->errstring = _dl_out_of_memory; + } + longjmp (lcatch->env, errcode ?: -1); + } + else + { + /* Lossage while resolving the program's own symbols is always fatal. */ + char buffer[1024]; + _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", + _dl_argv[0] ?: "", + occation ?: N_("error while loading shared libraries"), + objname, *objname ? ": " : "", + errstring, errcode ? ": " : "", + (errcode + ? __strerror_r (errcode, buffer, sizeof buffer) + : "")); + } +} + + +void +internal_function +_dl_signal_cerror (int errcode, const char *objname, const char *occation, + const char *errstring) +{ + if (receiver) + { + /* We are inside _dl_receive_error. Call the user supplied + handler and resume the work. The receiver will still be + installed. */ + (*receiver) (errcode, objname, errstring); + } + else + _dl_signal_error (errcode, objname, occation, errstring); +} + + +int +internal_function +_dl_catch_error (const char **objname, const char **errstring, + void (*operate) (void *), void *args) +{ + int errcode; + struct catch *volatile old; + struct catch c; + /* We need not handle `receiver' since setting a `catch' is handled + before it. */ + + /* Some systems (e.g., SPARC) handle constructors to local variables + inefficient. So we initialize `c' by hand. */ + c.errstring = NULL; + + old = tsd_getspecific (); + errcode = setjmp (c.env); + if (__builtin_expect (errcode, 0) == 0) + { + tsd_setspecific (&c); + (*operate) (args); + tsd_setspecific (old); + *objname = NULL; + *errstring = NULL; + return 0; + } + + /* We get here only if we longjmp'd out of OPERATE. */ + tsd_setspecific (old); + *objname = c.objname; + *errstring = c.errstring; + return errcode == -1 ? 0 : errcode; +} + +void +internal_function +_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) +{ + struct catch *old_catch; + receiver_fct old_receiver; + + old_catch = tsd_getspecific (); + old_receiver = receiver; + + /* Set the new values. */ + tsd_setspecific (NULL); + receiver = fct; + + (*operate) (args); + + tsd_setspecific (old_catch); + receiver = old_receiver; +}
dl-error.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-deps.c =================================================================== --- dl-deps.c (nonexistent) +++ dl-deps.c (revision 158) @@ -0,0 +1,561 @@ +/* Load the dependencies of a mapped object. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Whether an shared object references one or more auxiliary objects + is signaled by the AUXTAG entry in l_info. */ +#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRATAGIDX (DT_AUXILIARY)) +/* Whether an shared object references one or more auxiliary objects + is signaled by the AUXTAG entry in l_info. */ +#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRATAGIDX (DT_FILTER)) + +/* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +size_t _dl_global_scope_alloc; + +extern size_t _dl_platformlen; + +/* When loading auxiliary objects we must ignore errors. It's ok if + an object is missing. */ +struct openaux_args + { + /* The arguments to openaux. */ + struct link_map *map; + int trace_mode; + const char *strtab; + const char *name; + + /* The return value of openaux. */ + struct link_map *aux; + }; + +static void +openaux (void *a) +{ + struct openaux_args *args = (struct openaux_args *) a; + + args->aux = _dl_map_object (args->map, args->name, 0, + (args->map->l_type == lt_executable + ? lt_library : args->map->l_type), + args->trace_mode, 0); +} + + + +/* We use a very special kind of list to track the path + through the list of loaded shared objects. We have to + produce a flat list with unique members of all involved objects. +*/ +struct list + { + int done; /* Nonzero if this map was processed. */ + struct link_map *map; /* The data. */ + struct list *next; /* Elements for normal list. */ + }; + + +/* Macro to expand DST. It is an macro since we use `alloca'. */ +#define expand_dst(l, str, fatal) \ + ({ \ + const char *__str = (str); \ + const char *__result = __str; \ + size_t __cnt = DL_DST_COUNT(__str, 0); \ + \ + if (__cnt != 0) \ + { \ + char *__newp; \ + \ + __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \ + __cnt)); \ + \ + __result = DL_DST_SUBSTITUTE (l, __str, __newp, 0); \ + \ + if (*__result == '\0') \ + { \ + /* The replacement for the DST is not known. We can't \ + processed. */ \ + if (fatal) \ + _dl_signal_error (0, __str, NULL, N_("\ +empty dynamics string token substitution")); \ + else \ + { \ + /* This is for DT_AUXILIARY. */ \ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) \ + _dl_debug_printf ("cannot load auxiliary `%s' because of" \ + "empty dynamic string token " \ + "substitution\n", __str); \ + continue; \ + } \ + } \ + } \ + \ + __result; }) + + +void +internal_function +_dl_map_object_deps (struct link_map *map, + struct link_map **preloads, unsigned int npreloads, + int trace_mode) +{ + struct list known[1 + npreloads + 1]; + struct list *runp, *tail; + unsigned int nlist, i; + /* Object name. */ + const char *name; + int errno_saved; + int errno_reason; + const char *errstring; + const char *objname; + + auto inline void preload (struct link_map *map); + + inline void preload (struct link_map *map) + { + known[nlist].done = 0; + known[nlist].map = map; + known[nlist].next = &known[nlist + 1]; + + ++nlist; + /* We use `l_reserved' as a mark bit to detect objects we have + already put in the search list and avoid adding duplicate + elements later in the list. */ + map->l_reserved = 1; + } + + /* No loaded object so far. */ + nlist = 0; + + /* First load MAP itself. */ + preload (map); + + /* Add the preloaded items after MAP but before any of its dependencies. */ + for (i = 0; i < npreloads; ++i) + preload (preloads[i]); + + /* Terminate the lists. */ + known[nlist - 1].next = NULL; + + /* Pointer to last unique object. */ + tail = &known[nlist - 1]; + + /* Process each element of the search list, loading each of its + auxiliary objects and immediate dependencies. Auxiliary objects + will be added in the list before the object itself and + dependencies will be appended to the list as we step through it. + This produces a flat, ordered list that represents a + breadth-first search of the dependency tree. + + The whole process is complicated by the fact that we better + should use alloca for the temporary list elements. But using + alloca means we cannot use recursive function calls. */ + errno_saved = errno; + errno_reason = 0; + errstring = NULL; + errno = 0; + name = NULL; + for (runp = known; runp; ) + { + struct link_map *l = runp->map; + struct link_map **needed = NULL; + unsigned int nneeded = 0; + + /* Unless otherwise stated, this object is handled. */ + runp->done = 1; + + /* Allocate a temporary record to contain the references to the + dependencies of this object. */ + if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL + && l != map && l->l_ldnum > 0) + needed = (struct link_map **) alloca (l->l_ldnum + * sizeof (struct link_map *)); + + if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG]) + { + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + struct openaux_args args; + struct list *orig; + const ElfW(Dyn) *d; + + args.strtab = strtab; + args.map = l; + args.trace_mode = trace_mode; + orig = runp; + + for (d = l->l_ld; d->d_tag != DT_NULL; ++d) + if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED) + { + /* Map in the needed object. */ + struct link_map *dep; + int err; + + /* Recognize DSTs. */ + name = expand_dst (l, strtab + d->d_un.d_val, 0); + /* Store the tag in the argument structure. */ + args.name = name; + + err = _dl_catch_error (&objname, &errstring, openaux, &args); + if (__builtin_expect (errstring != NULL, 0)) + { + if (err) + errno_reason = err; + else + errno_reason = -1; + goto out; + } + else + dep = args.aux; + + if (! dep->l_reserved) + { + /* Allocate new entry. */ + struct list *newp; + + newp = alloca (sizeof (struct list)); + + /* Append DEP to the list. */ + newp->map = dep; + newp->done = 0; + newp->next = NULL; + tail->next = newp; + tail = newp; + ++nlist; + /* Set the mark bit that says it's already in the list. */ + dep->l_reserved = 1; + } + + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = dep; + } + else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER) + { + struct list *newp; + + /* Recognize DSTs. */ + name = expand_dst (l, strtab + d->d_un.d_val, + d->d_tag == DT_AUXILIARY); + /* Store the tag in the argument structure. */ + args.name = name; + + if (d->d_tag == DT_AUXILIARY) + { + int err; + + /* Say that we are about to load an auxiliary library. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("load auxiliary object=%s" + " requested by file=%s\n", name, + l->l_name[0] + ? l->l_name : _dl_argv[0]); + + /* We must be prepared that the addressed shared + object is not available. */ + err = _dl_catch_error (&objname, &errstring, openaux, + &args); + if (__builtin_expect (errstring != NULL, 0)) + { + /* We are not interested in the error message. */ + assert (errstring != NULL); + if (errstring != _dl_out_of_memory) + free ((char *) errstring); + + /* Simply ignore this error and continue the work. */ + continue; + } + } + else + { + int err; + + /* Say that we are about to load an auxiliary library. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("load filtered object=%s" + " requested by file=%s\n", name, + l->l_name[0] + ? l->l_name : _dl_argv[0]); + + /* For filter objects the dependency must be available. */ + err = _dl_catch_error (&objname, &errstring, openaux, + &args); + if (__builtin_expect (errstring != NULL, 0)) + { + if (err) + errno_reason = err; + else + errno_reason = -1; + goto out; + } + } + + /* The auxiliary object is actually available. + Incorporate the map in all the lists. */ + + /* Allocate new entry. This always has to be done. */ + newp = alloca (sizeof (struct list)); + + /* We want to insert the new map before the current one, + but we have no back links. So we copy the contents of + the current entry over. Note that ORIG and NEWP now + have switched their meanings. */ + memcpy (newp, orig, sizeof (*newp)); + + /* Initialize new entry. */ + orig->done = 0; + orig->map = args.aux; + + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = args.aux; + + /* We must handle two situations here: the map is new, + so we must add it in all three lists. If the map + is already known, we have two further possibilities: + - if the object is before the current map in the + search list, we do nothing. It is already found + early + - if the object is after the current one, we must + move it just before the current map to make sure + the symbols are found early enough + */ + if (args.aux->l_reserved) + { + /* The object is already somewhere in the list. + Locate it first. */ + struct list *late; + + /* This object is already in the search list we + are building. Don't add a duplicate pointer. + Just added by _dl_map_object. */ + for (late = newp; late->next != NULL; late = late->next) + if (late->next->map == args.aux) + break; + + if (late->next != NULL) + { + /* The object is somewhere behind the current + position in the search path. We have to + move it to this earlier position. */ + orig->next = newp; + + /* Now remove the later entry from the list + and adjust the tail pointer. */ + if (tail == late->next) + tail = late; + late->next = late->next->next; + + /* We must move the object earlier in the chain. */ + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux->l_next; + if (args.aux->l_next != NULL) + args.aux->l_next->l_prev = args.aux->l_prev; + + args.aux->l_prev = newp->map->l_prev; + newp->map->l_prev = args.aux; + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux; + args.aux->l_next = newp->map; + } + else + { + /* The object must be somewhere earlier in the + list. Undo to the current list element what + we did above. */ + memcpy (orig, newp, sizeof (*newp)); + continue; + } + } + else + { + /* This is easy. We just add the symbol right here. */ + orig->next = newp; + ++nlist; + /* Set the mark bit that says it's already in the list. */ + args.aux->l_reserved = 1; + + /* The only problem is that in the double linked + list of all objects we don't have this new + object at the correct place. Correct this here. */ + if (args.aux->l_prev) + args.aux->l_prev->l_next = args.aux->l_next; + if (args.aux->l_next) + args.aux->l_next->l_prev = args.aux->l_prev; + + args.aux->l_prev = newp->map->l_prev; + newp->map->l_prev = args.aux; + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux; + args.aux->l_next = newp->map; + } + + /* Move the tail pointer if necessary. */ + if (orig == tail) + tail = newp; + + /* Move on the insert point. */ + orig = newp; + } + } + + /* Terminate the list of dependencies and store the array address. */ + if (needed != NULL) + { + needed[nneeded++] = NULL; + + l->l_initfini = (struct link_map **) + malloc ((nneeded + 1) * sizeof needed[0]); + if (l->l_initfini == NULL) + _dl_signal_error (ENOMEM, map->l_name, NULL, + N_("cannot allocate dependency list")); + l->l_initfini[0] = l; + memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]); + } + + /* If we have no auxiliary objects just go on to the next map. */ + if (runp->done) + do + runp = runp->next; + while (runp != NULL && runp->done); + } + + out: + if (errno == 0 && errno_saved != 0) + __set_errno (errno_saved); + + if (map->l_initfini != NULL && map->l_type == lt_loaded) + { + /* This object was previously loaded as a dependency and we have + a separate l_initfini list. We don't need it anymore. */ + assert (map->l_searchlist.r_list == NULL); + free (map->l_initfini); + } + + /* Store the search list we built in the object. It will be used for + searches in the scope of this object. */ + map->l_initfini = + (struct link_map **) malloc ((2 * nlist + 1) + * sizeof (struct link_map *)); + if (map->l_initfini == NULL) + _dl_signal_error (ENOMEM, map->l_name, NULL, + N_("cannot allocate symbol search list")); + + + map->l_searchlist.r_list = &map->l_initfini[nlist + 1]; + map->l_searchlist.r_nlist = nlist; + + for (nlist = 0, runp = known; runp; runp = runp->next) + { + if (__builtin_expect (trace_mode, 0) && runp->map->l_faked) + /* This can happen when we trace the loading. */ + --map->l_searchlist.r_nlist; + else + map->l_searchlist.r_list[nlist++] = runp->map; + + /* Now clear all the mark bits we set in the objects on the search list + to avoid duplicates, so the next call starts fresh. */ + runp->map->l_reserved = 0; + } + + /* Maybe we can remove some relocation dependencies now. */ + assert (map->l_searchlist.r_list[0] == map); + for (i = 0; i < map->l_reldepsact; ++i) + { + unsigned int j; + + for (j = 1; j < nlist; ++j) + if (map->l_searchlist.r_list[j] == map->l_reldeps[i]) + { + /* A direct or transitive dependency is also on the list + of relocation dependencies. Remove the latter. */ + --map->l_reldeps[i]->l_opencount; + + for (j = i + 1; j < map->l_reldepsact; ++j) + map->l_reldeps[j - 1] = map->l_reldeps[j]; + + --map->l_reldepsact; + + /* Account for the '++i' performed by the 'for'. */ + --i; + break; + } + } + + /* Now determine the order in which the initialization has to happen. */ + memcpy (map->l_initfini, map->l_searchlist.r_list, + nlist * sizeof (struct link_map *)); + /* We can skip looking for the binary itself which is at the front + of the search list. Look through the list backward so that circular + dependencies are not changing the order. */ + for (i = 1; i < nlist; ++i) + { + struct link_map *l = map->l_searchlist.r_list[i]; + unsigned int j; + unsigned int k; + + /* Find the place in the initfini list where the map is currently + located. */ + for (j = 1; map->l_initfini[j] != l; ++j) + ; + + /* Find all object for which the current one is a dependency and + move the found object (if necessary) in front. */ + for (k = j + 1; k < nlist; ++k) + { + struct link_map **runp; + + runp = map->l_initfini[k]->l_initfini; + if (runp != NULL) + { + while (*runp != NULL) + if (__builtin_expect (*runp++ == l, 0)) + { + struct link_map *here = map->l_initfini[k]; + + /* Move it now. */ + memmove (&map->l_initfini[j] + 1, + &map->l_initfini[j], + (k - j) * sizeof (struct link_map *)); + map->l_initfini[j] = here; + + break; + } + } + } + } + /* Terminate the list of dependencies. */ + map->l_initfini[nlist] = NULL; + + if (errno_reason) + _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, + objname, NULL, errstring); +}
dl-deps.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-misc.c =================================================================== --- dl-misc.c (nonexistent) +++ dl-misc.c (revision 158) @@ -0,0 +1,277 @@ +/* Miscellaneous support functions for dynamic linker + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_ANON +/* This is the only dl-sysdep.c function that is actually needed at run-time + by _dl_map_object. */ + +int +_dl_sysdep_open_zero_fill (void) +{ + return __open ("/dev/zero", O_RDONLY); +} +#endif + +/* Read the whole contents of FILE into new mmap'd space with given + protections. *SIZEP gets the size of the file. On error MAP_FAILED + is returned. */ + +void * +internal_function +_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot) +{ + void *result = MAP_FAILED; + struct stat64 st; + int fd = __open (file, O_RDONLY); + if (fd >= 0) + { + if (fstat64 (fd, &st) >= 0) + { + *sizep = st.st_size; + + /* No need to map the file if it is empty. */ + if (*sizep != 0) + /* Map a copy of the file contents. */ + result = mmap (NULL, *sizep, prot, +#ifdef MAP_COPY + MAP_COPY +#else + MAP_PRIVATE +#endif +#ifdef MAP_FILE + | MAP_FILE +#endif + , fd, 0); + } + close (fd); + } + return result; +} + + +/* Descriptor to write debug messages to. */ +int _dl_debug_fd = 2; + + +/* Bare-bone printf implementation. This function only knows about + the formats and flags needed and can handle only up to 64 stripes in + the output. */ +static void +_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) +{ + const int niovmax = 64; + struct iovec iov[niovmax]; + int niov = 0; + pid_t pid = 0; + char pidbuf[7]; + + while (*fmt != '\0') + { + const char *startp = fmt; + + if (tag_p > 0) + { + /* Generate the tag line once. It consists of the PID and a + colon followed by a tab. */ + if (pid == 0) + { + char *p = "0"; + pid = __getpid (); + assert (pid >= 0 && pid < 100000); + while (p > pidbuf) + *--p = '0'; + pidbuf[5] = ':'; + pidbuf[6] = '\t'; + } + + /* Append to the output. */ + assert (niov < niovmax); + iov[niov].iov_len = 7; + iov[niov++].iov_base = pidbuf; + + /* No more tags until we see the next newline. */ + tag_p = -1; + } + + /* Skip everything except % and \n (if tags are needed). */ + while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n')) + ++fmt; + + /* Append constant string. */ + assert (niov < niovmax); + if ((iov[niov].iov_len = fmt - startp) != 0) + iov[niov++].iov_base = (char *) startp; + + if (*fmt == '%') + { + /* It is a format specifier. */ + char fill = ' '; + int width = -1; +#if LONG_MAX != INT_MAX + int long_mod = 0; +#endif + + /* Recognize zero-digit fill flag. */ + if (*++fmt == '0') + { + fill = '0'; + ++fmt; + } + + /* See whether with comes from a parameter. Note that no other + way to specify the width is implemented. */ + if (*fmt == '*') + { + width = va_arg (arg, int); + ++fmt; + } + + /* Recognize the l modifier. It is only important on some + platforms where long and int have a different size. We + can use the same code for size_t. */ + if (*fmt == 'l' || *fmt == 'Z') + { +#if LONG_MAX != INT_MAX + long_mod = 1; +#endif + ++fmt; + } + + switch (*fmt) + { + /* Integer formatting. */ + case 'u': + case 'x': + { + /* We have to make a difference if long and int have a + different size. */ +#if LONG_MAX != INT_MAX + unsigned long int num = (long_mod + ? va_arg (arg, unsigned long int) + : va_arg (arg, unsigned int)); +#else + unsigned long int num = va_arg (arg, unsigned int); +#endif + /* We use alloca() to allocate the buffer with the most + pessimistic guess for the size. Using alloca() allows + having more than one integer formatting in a call. */ + char *buf = (char *) alloca (3 * sizeof (unsigned long int)); + char *endp = &buf[3 * sizeof (unsigned long int)]; + char *cp = "0"; + + /* Pad to the width the user specified. */ + if (width != -1) + while (endp - cp < width) + *--cp = fill; + + iov[niov].iov_base = cp; + iov[niov].iov_len = endp - cp; + ++niov; + } + break; + + case 's': + /* Get the string argument. */ + iov[niov].iov_base = va_arg (arg, char *); + iov[niov].iov_len = strlen (iov[niov].iov_base); + ++niov; + break; + + case '%': + iov[niov].iov_base = (void *) fmt; + iov[niov].iov_len = 1; + ++niov; + break; + + default: + assert (! "invalid format specifier"); + } + ++fmt; + } + else if (*fmt == '\n') + { + /* See whether we have to print a single newline character. */ + if (fmt == startp) + { + iov[niov].iov_base = (char *) startp; + iov[niov++].iov_len = 1; + } + else + /* No, just add it to the rest of the string. */ + ++iov[niov - 1].iov_len; + + /* Next line, print a tag again. */ + tag_p = 1; + ++fmt; + } + } + + /* Finally write the result. */ + writev (fd, iov, niov); +} + + +/* Write to debug file. */ +void +_dl_debug_printf (const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (_dl_debug_fd, 1, fmt, arg); + va_end (arg); +} + + +/* Write to debug file but don't start with a tag. */ +void +_dl_debug_printf_c (const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (_dl_debug_fd, -1, fmt, arg); + va_end (arg); +} + + +/* Write the given file descriptor. */ +void +_dl_dprintf (int fd, const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (fd, 0, fmt, arg); + va_end (arg); +}
dl-misc.c Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 158) @@ -0,0 +1,26 @@ +## Process this file with automake to generate Makefile.in + +AUTOMAKE_OPTIONS = cygnus + +INCLUDES = -DSHARED -D_GNU_SOURCE $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -I$(srcdir)/.. + +LIB_SOURCES = \ + dl-addr.c dl-deps.c dl-init.c dl-load.c dl-misc.c dl-profile.c dl-runtime.c dl-version.c \ + dl-close.c dl-error.c dl-iteratephdr.c dl-lookup.c dl-object.c dl-profstub.c dl-support.c \ + dl-debug.c dl-fini.c dl-libc.c dl-open.c dl-reloc.c dl-sym.c dl-cache.c + +AM_CFLAGS = -D_GNU_SOURCE -D__strerror_r=strerror_r +libdl_la_LDFLAGS = -Xcompiler -nostdlib + +if USE_LIBTOOL +noinst_LTLIBRARIES = libdl.la +libdl_la_SOURCES = $(LIB_SOURCES) +noinst_DATA = objectlist.awk.in +else +noinst_LIBRARIES = lib.a +lib_a_SOURCES = $(LIB_SOURCES) +lib_a_CFLAGS = $(AM_CFLAGS) +noinst_DATA = +endif # USE_LIBTOOL + +include $(srcdir)/../../../../Makefile.shared
Makefile.am Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-lookupcfg.h =================================================================== --- dl-lookupcfg.h (nonexistent) +++ dl-lookupcfg.h (revision 158) @@ -0,0 +1,22 @@ +/* Configuration of lookup functions. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Some platforms need more information from the symbol lookup function + than just the address. But this is not generally the case. */ +#undef DL_LOOKUP_RETURNS_MAP
dl-lookupcfg.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property Index: dl-local.h =================================================================== --- dl-local.h (nonexistent) +++ dl-local.h (revision 158) @@ -0,0 +1,65 @@ +#ifndef _LOCAL_H +#include + +#define internal_function + +/* Internally used flag. */ +#define __RTLD_DLOPEN 0x80000000 +#define __RTLD_SPROF 0x40000000 + +/* Now define the internal interfaces. */ +extern void *__dlvsym (void *__handle, __const char *__name, + __const char *__version); + +extern void *__libc_dlopen (__const char *__name); +extern void *__libc_dlsym (void *__map, __const char *__name); +extern int __libc_dlclose (void *__map); + +/* Locate shared object containing the given address. */ +extern int _dl_addr (const void *address, Dl_info *info) + internal_function; + +/* Open the shared object NAME, relocate it, and run its initializer if it + hasn't already been run. MODE is as for `dlopen' (see ). If + the object is already opened, returns its existing map. */ +extern void *_dl_open (const char *name, int mode, const void *caller) + internal_function; + +/* Close an object previously opened by _dl_open. */ +extern void _dl_close (void *map) + internal_function; + +/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or + RTLD_NEXT). WHO is the calling function, for RTLD_NEXT. Returns + the symbol value, which may be NULL. */ +extern void *_dl_sym (void *handle, const char *name, void *who) + internal_function; + +/* Look up version VERSION of symbol NAME in shared object HANDLE + (which may be RTLD_DEFAULT or RTLD_NEXT). WHO is the calling + function, for RTLD_NEXT. Returns the symbol value, which may be + NULL. */ +extern void *_dl_vsym (void *handle, const char *name, const char *version, + void *who) + internal_function; + +/* Call OPERATE, catching errors from `dl_signal_error'. If there is no + error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is + set to a string constructed from the strings passed to _dl_signal_error, + and the error code passed is the return value and *OBJNAME is set to + the object name which experienced the problems. ERRSTRING if nonzero + points to a malloc'ed string which the caller has to free after use. + ARGS is passed as argument to OPERATE. */ +extern int _dl_catch_error (const char **objname, const char **errstring, + void (*operate) (void *), + void *args) + internal_function; + +/* Helper function for functions. Runs the OPERATE function via + _dl_catch_error. Returns zero for success, nonzero for failure; and + arranges for `dlerror' to return the error details. + ARGS is passed as argument to OPERATE. */ +extern int _dlerror_run (void (*operate) (void *), void *args) + internal_function; + +#endif
dl-local.h Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Id \ No newline at end of property

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.