glibc/elf/dl-reloc.c
Roland McGrath efec1d0c47 Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
* elf/linux-compat.c (_init): Pass reloc_addr arg to _dl_lookup_symbol.

	* elf/dl-lookup.c (_dl_lookup_symbol): Use l_searchlist.

	* elf/dl-deps.c: New file.
	* elf/Makefile (rtld-routines): Add dl-deps.
	* elf/link.h: Declare _dl_map_object_deps, _dl_open.
	* elf/rtld.c (dl_main): Use _dl_map_object_deps.
	* elf/dlopen.c: Use _dl_open.

	* elf/rtld.c (dl_main): Remove BEFORE_RTLD variable and list
	frobnication based on its value.  Detach RTLD_MAP from the chain if
	its l_opencount is zero after loading deps.

	* elf/dlfcn.h (RTLD_BINDING_MASK): New macro.

	* elf/link.h (struct link_map): Replace l_deps_loaded flag member with
	`struct link_map **l_searchlist' and `unsigned int l_nsearchlist'.
	* elf/dl-lookup.c (_dl_lookup_symbol): Make SYMBOL_SCOPE arg an array
	of two link_map ptrs.  Search the maps in the l_searchlist of each
	elt that is not null.
	* elf/dl-reloc.c (_dl_relocate_object): Pass proper SCOPE array.
	* elf/dl-runtime.c: Likewise.
	* elf/dlsym.c: Likewise.
	* elf/rtld.c (dl_main): Likewise.

	* elf/dl-minimal.c (realloc): Support realloc of the block most
	recently returned by the minimal malloc.

	* intl/localealias.c, intl/dcgettext.c [_LIBC]: Define HAVE_ALLOCA.
1996-06-04 05:18:15 +00:00

121 lines
3.6 KiB
C

/* Relocate a shared object and resolve its references to other loaded objects.
Copyright (C) 1995, 1996 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 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., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include <link.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include "dynamic-link.h"
void
_dl_relocate_object (struct link_map *l, int lazy)
{
const size_t pagesize = getpagesize ();
if (l->l_relocated)
return;
if (l->l_info[DT_TEXTREL])
{
/* Bletch. We must make read-only segments writable
long enough to relocate them. */
const Elf32_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)
{
caddr_t mapstart = ((caddr_t) l->l_addr +
(ph->p_vaddr & ~(pagesize - 1)));
caddr_t mapend = ((caddr_t) l->l_addr +
((ph->p_vaddr + ph->p_memsz + pagesize - 1)
& ~(pagesize - 1)));
if (mprotect (mapstart, mapend - mapstart,
PROT_READ|PROT_WRITE) < 0)
_dl_signal_error (errno, l->l_name,
"cannot make segment writable for relocation");
}
}
{
struct link_map *scope[2];
const char *strtab
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
Elf32_Addr resolve (const Elf32_Sym **ref,
Elf32_Addr reloc_addr, int noplt)
{
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
l->l_name, reloc_addr, noplt);
}
if (l->l_info[DT_SYMBOLIC])
{
scope[0] = l;
scope[1] = _dl_loaded;
}
else
{
scope[0] = _dl_loaded;
scope[1] = l;
}
if (l->l_type == lt_interpreter)
/* We cannot be lazy when relocating the dynamic linker itself. It
was previously relocated eagerly (allowing us to be running now),
and needs always to be fully relocated so it can run without the
aid of run-time fixups (because it's the one to do them), so we
must always re-relocate its PLT eagerly. */
lazy = 0;
ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
}
/* Set up the PLT so its unrelocated entries will
jump to _dl_runtime_resolve, which will relocate them. */
elf_machine_runtime_setup (l, lazy);
l->l_relocated = 1;
if (l->l_info[DT_TEXTREL])
{
/* Undo the protection change we made before relocating. */
const Elf32_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)
{
caddr_t mapstart = ((caddr_t) l->l_addr +
(ph->p_vaddr & ~(pagesize - 1)));
caddr_t mapend = ((caddr_t) l->l_addr +
((ph->p_vaddr + ph->p_memsz + pagesize - 1)
& ~(pagesize - 1)));
int prot = 0;
if (ph->p_flags & PF_R)
prot |= PROT_READ;
if (ph->p_flags & PF_X)
prot |= PROT_EXEC;
if (mprotect (mapstart, mapend - mapstart, prot) < 0)
_dl_signal_error (errno, l->l_name,
"can't restore segment prot after reloc");
}
}
}