/* Load a shared object at runtime, relocate it, and run its initializer.
Copyright (C) 1996-2007, 2009, 2010, 2011, 2012 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, see
<http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <libintl.h>
#include <stdio.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 <bits/libc-lock.h>
#include <ldsodefs.h>
#include <bp-sym.h>
#include <caller.h>
#include <sysdep-cancel.h>
#include <tls.h>
#include <dl-dst.h>
extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
void (*dl_main) (const ElfW(Phdr) *phdr,
ElfW(Word) phnum,
ElfW(Addr) *user_entry,
ElfW(auxv_t) *auxv));
weak_extern (BP_SYM (_dl_sysdep_start))
extern int __libc_multiple_libcs; /* Defined in init-first.c. */
/* 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;
/* This is the caller of the dlopen() function. */
const void *caller_dlopen;
/* This is the caller if _dl_open(). */
const void *caller_dl_open;
struct link_map *map;
/* Namespace ID. */
Lmid_t nsid;
/* Original parameters to the program and the current environment. */
int argc;
char **argv;
char **env;
};
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. */
struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
if (ns->_ns_global_scope_alloc == 0)
{
/* This is the first dynamic object given global scope. */
ns->_ns_global_scope_alloc
=