mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
* sysdeps/mach/i386/sysdep.h (SNARF_ARGS, CALL_WITH_SP): Rewritten.
* sysdeps/i386/dl-machine.h: New file. * sysdeps/stub/dl-machine.h: New file. * sysdeps/i386/dl-runtime.c: New file. * sysdeps/stub/dl-runtime.c: New file. * sysdeps/i386/elf/start.S: New file. * sysdeps/generic/dl-sysdep.c: New file. * sysdeps/mach/hurd/dl-sysdep.c: New file.
This commit is contained in:
parent
08162fa888
commit
d66e34cd42
@ -1,5 +1,7 @@
|
||||
Tue May 2 01:52:58 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
* sysdeps/mach/i386/sysdep.h (SNARF_ARGS, CALL_WITH_SP): Rewritten.
|
||||
|
||||
Implemented runtime dynamic linker to support ELF shared libraries.
|
||||
* elf/Makefile: Added rules to make ld.so and libdl.
|
||||
* elf/dl-error.c: New file.
|
||||
@ -16,6 +18,13 @@ Tue May 2 01:52:58 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
* elf/dynamic-link.h: New file.
|
||||
* elf/link.h: New file.
|
||||
* elf/rtld.c: New file.
|
||||
* sysdeps/i386/dl-machine.h: New file.
|
||||
* sysdeps/stub/dl-machine.h: New file.
|
||||
* sysdeps/i386/dl-runtime.c: New file.
|
||||
* sysdeps/stub/dl-runtime.c: New file.
|
||||
* sysdeps/i386/elf/start.S: New file.
|
||||
* sysdeps/generic/dl-sysdep.c: New file.
|
||||
* sysdeps/mach/hurd/dl-sysdep.c: New file.
|
||||
|
||||
Mon May 1 18:48:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
|
32
elf/Makefile
32
elf/Makefile
@ -1,3 +1,5 @@
|
||||
# Makefile for elf subdirectory of GNU C Library.
|
||||
|
||||
# Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
|
||||
@ -16,8 +18,34 @@
|
||||
# not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
# Cambridge, MA 02139, USA.
|
||||
|
||||
subdir := elf
|
||||
subdir := elf
|
||||
|
||||
headers := elf.h # libelf.h
|
||||
headers := elf.h libelf.h link.h dlfcn.h
|
||||
routines := init-first
|
||||
|
||||
extra-libs = libelf libdl
|
||||
libelf-routines := elf_hash
|
||||
libdl-routines := dlopen dlclose dlsym dlerror
|
||||
libdl-inhibit-o = $(filter-out .so,$(object-suffixes)) # Build only shared.
|
||||
LDLIBS-dl.so := -lc -lld
|
||||
|
||||
rtld-routines := rtld $(addprefix dl-,load lookup object reloc \
|
||||
runtime sysdep error init fini)
|
||||
distribute = $(rtld-routines:=.c) dynamic-link.h
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
extra-objs = $(rtld-routines:=.so)
|
||||
install-lib = ld.so
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
$(objpfx)ld.so: $(rtld-routines:%=$(objpfx)%.so) \
|
||||
$(patsubst %,$(common-objpfx)lib%_pic.a,\
|
||||
elf c $(LDLIBS-c.so:-l%=%))
|
||||
$(LINK.o) -nostdlib -shared -o $@ \
|
||||
'-Wl,-(' $^ -lgcc '-Wl,-)'
|
||||
|
||||
$(objpfx)libdl.so: $(common-objpfx)libc.so $(objpfx)ld.so
|
||||
|
43
elf/dl-error.c
Normal file
43
elf/dl-error.c
Normal file
@ -0,0 +1,43 @@
|
||||
/* Error handling for runtime dynamic linker.
|
||||
Copyright (C) 1995 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 <stddef.h>
|
||||
#include <link.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
static jmp_buf catch_env;
|
||||
static const char *signalled_errstring;
|
||||
|
||||
void
|
||||
_dl_signal_error (int errcode, const char *errstring)
|
||||
{
|
||||
signalled_errstring = errstring ?: "DYNAMIC LINKER BUG!!!";
|
||||
longjmp (catch_env, errcode ?: -1);
|
||||
}
|
||||
|
||||
int
|
||||
_dl_catch_error (const char **errstring, void (*operate) (void))
|
||||
{
|
||||
int errcode;
|
||||
|
||||
signalled_errstring = NULL;
|
||||
errcode = setjmp (catch_env);
|
||||
*errstring = signalled_errstring;
|
||||
return *errstring ? errcode : 0;
|
||||
}
|
30
elf/dl-fini.c
Normal file
30
elf/dl-fini.c
Normal file
@ -0,0 +1,30 @@
|
||||
/* Call the termination functions of loaded shared objects.
|
||||
Copyright (C) 1995 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>
|
||||
|
||||
void
|
||||
_dl_fini (void)
|
||||
{
|
||||
struct link_map *l;
|
||||
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (l->l_init_called && l->l_info[DT_FINI])
|
||||
(*(void (*) (void)) l->l_info[DT_FINI]->d_un.d_ptr) ();
|
||||
}
|
86
elf/dl-init.c
Normal file
86
elf/dl-init.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* Return the next shared object initializer function not yet run.
|
||||
Copyright (C) 1995 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 <stddef.h>
|
||||
#include <link.h>
|
||||
|
||||
|
||||
Elf32_Addr
|
||||
_dl_init_next (void)
|
||||
{
|
||||
struct link_map *l;
|
||||
Elf32_Addr init;
|
||||
|
||||
Elf32_Addr next_init (struct link_map *l)
|
||||
{
|
||||
if (l->l_init_called)
|
||||
/* This object is all done. */
|
||||
return 0;
|
||||
if (l->l_init_running)
|
||||
{
|
||||
/* This object's initializer was just running.
|
||||
Now mark it as having run, so this object
|
||||
will be skipped in the future. */
|
||||
l->l_init_called = 1;
|
||||
l->l_init_running = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l->l_info[DT_NEEDED])
|
||||
{
|
||||
/* Find each dependency in order, and see if it
|
||||
needs to run an initializer. */
|
||||
const Elf32_Dyn *d;
|
||||
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
{
|
||||
struct link_map *needed = _dl_map_object
|
||||
(l, (const char *) (l->l_addr + d->d_un.d_ptr), NULL);
|
||||
Elf32_Addr init;
|
||||
--needed->l_opencount;
|
||||
init = next_init (l); /* Recurse on this dependency. */
|
||||
if (init != 0)
|
||||
return init;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->l_info[DT_INIT])
|
||||
{
|
||||
/* Run this object's initializer. */
|
||||
l->l_init_running = 1;
|
||||
return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
|
||||
}
|
||||
|
||||
/* No initializer for this object.
|
||||
Mark it so we will skip it in the future. */
|
||||
l->l_init_called = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look for the first initializer not yet called. */
|
||||
l = _dl_loaded;
|
||||
do
|
||||
{
|
||||
init = next_init (l);
|
||||
l = l->l_next;
|
||||
}
|
||||
while (init == 0 && l);
|
||||
|
||||
return init;
|
||||
}
|
377
elf/dl-load.c
Normal file
377
elf/dl-load.c
Normal file
@ -0,0 +1,377 @@
|
||||
/* _dl_map_object -- Map in a shared object's segments from the file.
|
||||
Copyright (C) 1995 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 <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "dynamic-link.h"
|
||||
|
||||
|
||||
#include <endian.h>
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define byteorder ELFDATA2MSB
|
||||
#define byteorder_name "big-endian"
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define byteorder ELFDATA2LSB
|
||||
#define byteorder_name "little-endian"
|
||||
#else
|
||||
#error "Unknown BYTE_ORDER " BYTE_ORDER
|
||||
#define byteorder ELFDATANONE
|
||||
#endif
|
||||
|
||||
#define STRING(x) #x
|
||||
|
||||
int _dl_zerofd = -1;
|
||||
|
||||
|
||||
/* Try to open NAME in one of the directories in DIRPATH.
|
||||
Return the fd, or -1. If successful, fill in *REALNAME
|
||||
with the malloc'd full directory name. */
|
||||
|
||||
static int
|
||||
open_path (const char *name, size_t namelen,
|
||||
const char *dirpath,
|
||||
char **realname)
|
||||
{
|
||||
char buf[strlen (dirpath) + 1 + namelen];
|
||||
const char *p;
|
||||
int fd;
|
||||
|
||||
p = dirpath;
|
||||
if (p == NULL || *p == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
dirpath = p;
|
||||
p = strpbrk (dirpath, ":;");
|
||||
if (p == NULL)
|
||||
p = strchr (dirpath, '\0');
|
||||
|
||||
if (p == dirpath)
|
||||
/* Two adjacent colons, or a colon at the beginning or the end of
|
||||
the path means to search the current directory. */
|
||||
(void) memcpy (buf, name, namelen);
|
||||
else
|
||||
{
|
||||
/* Construct the pathname to try. */
|
||||
(void) memcpy (buf, dirpath, p - dirpath);
|
||||
buf[p - dirpath] = '/';
|
||||
(void) memcpy (&buf[(p - dirpath) + 1], name, namelen);
|
||||
}
|
||||
|
||||
fd = open (buf, O_RDONLY);
|
||||
if (fd != -1)
|
||||
{
|
||||
*realname = strdup (buf);
|
||||
return fd;
|
||||
}
|
||||
if (errno != ENOENT && errno != EACCES)
|
||||
/* The file exists and is readable, but something went wrong. */
|
||||
return -1;
|
||||
}
|
||||
while (*p++ != '\0');
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Map in the shared object file NAME. */
|
||||
|
||||
struct link_map *
|
||||
_dl_map_object (struct link_map *loader, const char *name,
|
||||
Elf32_Addr *entry_point)
|
||||
{
|
||||
int fd;
|
||||
char *realname;
|
||||
const size_t pagesize = getpagesize ();
|
||||
void *file_mapping = NULL;
|
||||
size_t mapping_size = 0;
|
||||
/* Make sure LOCATION is mapped in. */
|
||||
void *map (off_t location, size_t size)
|
||||
{
|
||||
if ((off_t) mapping_size <= location + (off_t) size)
|
||||
{
|
||||
void *result;
|
||||
if (file_mapping)
|
||||
munmap (file_mapping, mapping_size);
|
||||
mapping_size = (location + size + 1 + pagesize - 1);
|
||||
mapping_size &= ~(pagesize - 1);
|
||||
result = mmap (file_mapping, mapping_size, PROT_READ,
|
||||
MAP_COPY|MAP_FILE, fd, 0);
|
||||
if (result == (void *) -1)
|
||||
return NULL;
|
||||
file_mapping = result;
|
||||
}
|
||||
return file_mapping + location;
|
||||
}
|
||||
|
||||
const Elf32_Ehdr *header;
|
||||
struct link_map *l;
|
||||
|
||||
/* Look for this name among those already loaded. */
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (! strcmp (name, l->l_libname))
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
++l->l_opencount;
|
||||
return l;
|
||||
}
|
||||
|
||||
if (strchr (name, '/') == NULL)
|
||||
{
|
||||
/* Search for NAME in several places. */
|
||||
|
||||
size_t namelen = strlen (name) + 1;
|
||||
|
||||
void trypath (const char *dirpath)
|
||||
{
|
||||
fd = open_path (name, namelen, dirpath, &realname);
|
||||
}
|
||||
|
||||
if (loader && loader->l_info[DT_RPATH])
|
||||
trypath ((const char *) (loader->l_addr +
|
||||
loader->l_info[DT_RPATH]->d_un.d_ptr));
|
||||
if (fd == -1 && ! _dl_secure)
|
||||
trypath (getenv ("LD_LIBRARY_PATH"));
|
||||
if (fd == -1)
|
||||
trypath ("/lib:/usr/lib");
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open (name, O_RDONLY);
|
||||
if (fd != -1)
|
||||
realname = strdup (name);
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
/* Look again to see if the real name matched another already loaded. */
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
if (! strcmp (realname, l->l_name))
|
||||
{
|
||||
/* The object is already loaded.
|
||||
Just bump its reference count and return it. */
|
||||
close (fd);
|
||||
++l->l_opencount;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
/* Map in the first page to read the header. */
|
||||
header = map (0, sizeof *header);
|
||||
if (! header)
|
||||
{
|
||||
lose:
|
||||
(void) close (fd);
|
||||
if (file_mapping)
|
||||
munmap (file_mapping, mapping_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef LOSE
|
||||
#define LOSE(s) _dl_signal_error (0, s)
|
||||
/* Check the header for basic validity. */
|
||||
if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
|
||||
(ELFMAG1 << (EI_MAG1 * 8)) |
|
||||
(ELFMAG2 << (EI_MAG2 * 8)) |
|
||||
(ELFMAG3 << (EI_MAG3 * 8))))
|
||||
LOSE ("invalid ELF header");
|
||||
if (header->e_ident[EI_CLASS] != ELFCLASS32)
|
||||
LOSE ("ELF file class not 32-bit");
|
||||
if (header->e_ident[EI_DATA] != byteorder)
|
||||
LOSE ("ELF file data encoding not " byteorder_name);
|
||||
if (header->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
LOSE ("ELF file version ident not " STRING(EV_CURRENT));
|
||||
if (header->e_version != EV_CURRENT)
|
||||
LOSE ("ELF file version not " STRING(EV_CURRENT));
|
||||
if (! elf_machine_matches_host (header->e_machine))
|
||||
LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME);
|
||||
if (header->e_phentsize != sizeof (Elf32_Phdr))
|
||||
LOSE ("ELF file's phentsize not the expected size");
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, lt_loaded);
|
||||
l->l_opencount = 1;
|
||||
|
||||
if (_dl_zerofd == -1)
|
||||
{
|
||||
_dl_zerofd = _dl_sysdep_open_zero_fill ();
|
||||
if (_dl_zerofd == -1)
|
||||
_dl_signal_error (errno, "cannot open zero fill device");
|
||||
}
|
||||
|
||||
{
|
||||
/* Copy the program header table into stack space so we can then unmap
|
||||
the headers. */
|
||||
Elf32_Phdr phdr[header->e_phnum];
|
||||
const Elf32_Phdr *ph;
|
||||
int anywhere;
|
||||
|
||||
ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
|
||||
if (! ph)
|
||||
goto lose;
|
||||
memcpy (phdr, ph, sizeof phdr);
|
||||
l->l_phnum = header->e_phnum;
|
||||
|
||||
anywhere = header->e_type == ET_DYN || header->e_type == ET_REL;
|
||||
|
||||
if (entry_point)
|
||||
*entry_point = header->e_entry;
|
||||
|
||||
/* We are done reading the file's headers now. Unmap them. */
|
||||
munmap (file_mapping, mapping_size);
|
||||
|
||||
/* Scan the program header table, processing its load commands. */
|
||||
l->l_addr = 0;
|
||||
l->l_ld = 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;
|
||||
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. */
|
||||
if (ph->p_align % pagesize != 0)
|
||||
LOSE ("ELF load command alignment not page-aligned");
|
||||
if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
|
||||
LOSE ("ELF load command address/offset not properly aligned");
|
||||
{
|
||||
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
|
||||
Elf32_Addr mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
|
||||
& ~(ph->p_align - 1));
|
||||
off_t mapoff = ph->p_offset & ~(ph->p_align - 1);
|
||||
caddr_t mapat;
|
||||
int prot = 0;
|
||||
if (ph->p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (ph->p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
if (ph->p_flags & PF_X)
|
||||
prot |= PROT_EXEC;
|
||||
|
||||
if (anywhere)
|
||||
{
|
||||
/* XXX this loses if the first segment mmap call puts
|
||||
it someplace where the later segments cannot fit. */
|
||||
mapat = mmap ((caddr_t) l->l_addr + mapstart, mapend - mapstart,
|
||||
prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
|
||||
/* Let the system choose any convenient
|
||||
location if this is the first segment.
|
||||
Following segments must be contiguous in
|
||||
virtual space with the first. */
|
||||
(l->l_addr == 0 ? 0 : MAP_FIXED),
|
||||
fd, mapoff);
|
||||
if (l->l_addr == 0)
|
||||
/* This was the first segment mapped, so MAPAT is
|
||||
the address the system chose for us. Record it. */
|
||||
l->l_addr = (Elf32_Addr) mapat - mapstart;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapat = mmap ((caddr_t) mapstart, mapend - mapstart,
|
||||
prot, MAP_COPY|MAP_FILE|MAP_INHERIT|MAP_FIXED,
|
||||
fd, mapoff);
|
||||
/* This file refers to absolute addresses. So consider its
|
||||
"load base" to be zero, since that is what we add to the
|
||||
file's addresses to find them in our memory. */
|
||||
l->l_addr = 0;
|
||||
}
|
||||
if (mapat == (caddr_t) -1)
|
||||
_dl_signal_error (errno,
|
||||
"failed to map region from shared object");
|
||||
|
||||
if (ph->p_memsz > ph->p_filesz)
|
||||
{
|
||||
/* Extra zero pages should appear at the end of this segment,
|
||||
after the data mapped from the file. Adjust MAPEND to map
|
||||
only the data from the file. We will later allocate zero
|
||||
pages following the data mapping. */
|
||||
caddr_t zero = mapat - mapstart + ph->p_filesz;
|
||||
caddr_t zeroend = mapat - mapstart + ph->p_memsz;
|
||||
caddr_t zeropage
|
||||
= (caddr_t) ((Elf32_Addr) (zero + pagesize - 1)
|
||||
& ~(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 ((prot & PROT_WRITE) == 0)
|
||||
{
|
||||
/* Dag nab it. */
|
||||
if (mprotect ((caddr_t) ((Elf32_Addr) zero
|
||||
& ~(pagesize - 1)),
|
||||
pagesize,
|
||||
prot|PROT_WRITE) < 0)
|
||||
_dl_signal_error (errno,
|
||||
"cannot change protections");
|
||||
}
|
||||
memset (zero, 0, zeroend - zero);
|
||||
if ((prot & PROT_WRITE) == 0)
|
||||
mprotect ((caddr_t) ((Elf32_Addr) zero
|
||||
& ~(pagesize - 1)),
|
||||
pagesize, prot);
|
||||
}
|
||||
|
||||
if (zeroend > zeropage)
|
||||
/* Map the remaining zero pages in from the zero fill FD. */
|
||||
mapat = mmap (zeropage, zeroend - zeropage,
|
||||
prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
|
||||
_dl_zerofd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l->l_ld == 0)
|
||||
LOSE ("object file has no dynamic section");
|
||||
(Elf32_Addr) l->l_ld += l->l_addr;
|
||||
|
||||
if (l->l_phdr == 0)
|
||||
l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
|
||||
(Elf32_Addr) l->l_phdr += l->l_addr;
|
||||
}
|
||||
|
||||
elf_get_dynamic_info (l->l_ld, l->l_info);
|
||||
if (l->l_info[DT_HASH])
|
||||
_dl_setup_hash (l);
|
||||
|
||||
return l;
|
||||
}
|
129
elf/dl-lookup.c
Normal file
129
elf/dl-lookup.c
Normal file
@ -0,0 +1,129 @@
|
||||
/* Look up a symbol in the loaded objects.
|
||||
Copyright (C) 1995 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 <stddef.h>
|
||||
#include <libelf.h>
|
||||
#include <link.h>
|
||||
|
||||
/* Search loaded objects' symbol tables for a definition of
|
||||
the symbol UNDEF_NAME. Don't use a PLT defn in UNDEF_MAP, since
|
||||
that is the object making the reference. */
|
||||
|
||||
Elf32_Addr
|
||||
_dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
|
||||
struct link_map *symbol_scope)
|
||||
{
|
||||
unsigned long int hash = elf_hash (undef_name);
|
||||
struct link_map *map;
|
||||
struct
|
||||
{
|
||||
Elf32_Addr a;
|
||||
const Elf32_Sym *s;
|
||||
} weak_value = { 0, NULL };
|
||||
|
||||
/* Search the relevant loaded objects for a definition. */
|
||||
for (map = symbol_scope; map; map = map->l_next)
|
||||
{
|
||||
const Elf32_Sym *symtab;
|
||||
const char *strtab;
|
||||
Elf32_Word symidx;
|
||||
|
||||
symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
|
||||
strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
/* 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])
|
||||
{
|
||||
const Elf32_Sym *sym = &symtab[symidx];
|
||||
|
||||
if (sym->st_value == 0)
|
||||
continue;
|
||||
|
||||
switch (ELF32_ST_TYPE (sym->st_info))
|
||||
{
|
||||
case STT_NOTYPE:
|
||||
case STT_FUNC:
|
||||
case STT_OBJECT:
|
||||
break;
|
||||
default:
|
||||
/* Not a code/data definition. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sym == *ref)
|
||||
/* This is the same symbol we are looking for the value for.
|
||||
If it is a PLT entry, it will have a value of its own;
|
||||
but that is not what we are looking for. */
|
||||
continue;
|
||||
|
||||
if (strcmp (strtab + sym->st_name, undef_name))
|
||||
/* Not the symbol we are looking for. */
|
||||
continue;
|
||||
|
||||
switch (ELF32_ST_BIND (sym->st_info))
|
||||
{
|
||||
case STB_GLOBAL:
|
||||
/* Global definition. Just what we need. */
|
||||
*ref = sym;
|
||||
return map->l_addr;
|
||||
case STB_WEAK:
|
||||
/* Weak definition. Use this value if we don't find another. */
|
||||
if (weak_value.a == 0)
|
||||
{
|
||||
weak_value.s = sym;
|
||||
weak_value.a = map->l_addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Local symbols are ignored. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weak_value.s == NULL)
|
||||
{
|
||||
const char msg[] = "undefined symbol: ";
|
||||
char buf[sizeof msg + strlen (undef_name)];
|
||||
memcpy (buf, msg, sizeof msg - 1);
|
||||
memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg);
|
||||
_dl_signal_error (0, msg);
|
||||
}
|
||||
|
||||
*ref = weak_value.s;
|
||||
return weak_value.a;
|
||||
}
|
||||
|
||||
|
||||
/* Cache the location of MAP's hash table. */
|
||||
|
||||
void
|
||||
_dl_setup_hash (struct link_map *map)
|
||||
{
|
||||
Elf32_Word *hash = (void *) map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr;
|
||||
Elf32_Word nchain;
|
||||
map->l_nbuckets = *hash++;
|
||||
nchain = *hash++;
|
||||
map->l_buckets = hash;
|
||||
hash += map->l_nbuckets;
|
||||
map->l_chain = hash;
|
||||
}
|
63
elf/dl-object.c
Normal file
63
elf/dl-object.c
Normal file
@ -0,0 +1,63 @@
|
||||
/* Storage management for the chain of loaded shared objects.
|
||||
Copyright (C) 1995 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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
/* List of objects currently loaded. */
|
||||
struct link_map *_dl_loaded;
|
||||
|
||||
/* Tail of that list which were loaded at startup. */
|
||||
struct link_map *_dl_startup_loaded;
|
||||
|
||||
/* Allocate a `struct link_map' for a new object being loaded,
|
||||
and enter it into the _dl_loaded list. */
|
||||
|
||||
struct link_map *
|
||||
_dl_new_object (char *realname, const char *libname, int type)
|
||||
{
|
||||
struct link_map *new = malloc (sizeof *new);
|
||||
if (! new)
|
||||
_dl_signal_error (ENOMEM, "can't open new object");
|
||||
|
||||
memset (new, 0, sizeof *new);
|
||||
new->l_name = realname;
|
||||
new->l_libname = libname;
|
||||
new->l_type = type;
|
||||
|
||||
if (_dl_loaded == NULL)
|
||||
{
|
||||
new->l_prev = new->l_next = NULL;
|
||||
_dl_loaded = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct link_map *l = _dl_loaded;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
new->l_prev = l;
|
||||
new->l_next = NULL;
|
||||
l->l_next = new;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
115
elf/dl-reloc.c
Normal file
115
elf/dl-reloc.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* Relocate a shared object and resolve its references to other loaded objects.
|
||||
Copyright (C) 1995 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,
|
||||
"cannot make segment writable for relocation");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct link_map *real_next, *scope;
|
||||
|
||||
const char *strtab
|
||||
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
|
||||
Elf32_Addr resolve (const Elf32_Sym **ref)
|
||||
{
|
||||
return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope);
|
||||
}
|
||||
|
||||
real_next = l->l_next;
|
||||
if (l->l_info[DT_SYMBOLIC])
|
||||
{
|
||||
l->l_prev->l_next = real_next;
|
||||
l->l_next = _dl_loaded;
|
||||
scope = l;
|
||||
}
|
||||
else
|
||||
scope = _dl_loaded;
|
||||
|
||||
elf_dynamic_relocate (l->l_info, l->l_addr, lazy, resolve);
|
||||
|
||||
/* Restore list frobnication done above for DT_SYMBOLIC. */
|
||||
l->l_next = real_next;
|
||||
l->l_prev->l_next = l;
|
||||
}
|
||||
|
||||
if (l->l_info[DT_JMPREL] && ! lazy)
|
||||
/* Set up the PLT so its unrelocated entries will
|
||||
jump to _dl_runtime_resolve, which will relocate them. */
|
||||
elf_machine_runtime_setup (l);
|
||||
|
||||
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,
|
||||
"can't restore segment prot after reloc");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
97
elf/dlclose.c
Normal file
97
elf/dlclose.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* dlclose -- Close a handle opened by `dlopen'.
|
||||
Copyright (C) 1995 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 <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
#define LOSE(s) _dl_signal_error (0, s)
|
||||
|
||||
int
|
||||
dlclose (void *handle)
|
||||
{
|
||||
void doit (void)
|
||||
{
|
||||
struct link_map *map = handle;
|
||||
|
||||
if (map->l_opencount == 0)
|
||||
LOSE ("shared object not open");
|
||||
|
||||
/* Decrement the reference count. */
|
||||
--map->l_opencount;
|
||||
|
||||
if (map->l_opencount == 0 && map->l_type == lt_loaded)
|
||||
{
|
||||
/* That was the last reference, and this was a dlopen-loaded
|
||||
object. We can unmap it. */
|
||||
const Elf32_Phdr *ph;
|
||||
|
||||
if (map->l_info[DT_FINI])
|
||||
/* Call its termination function. */
|
||||
(*(void (*) (void)) ((void *) map->l_addr +
|
||||
map->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
|
||||
if (map->l_info[DT_NEEDED])
|
||||
{
|
||||
/* Also close all the dependencies. */
|
||||
const char *strtab
|
||||
= (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr;
|
||||
const Elf32_Dyn *d;
|
||||
for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
{
|
||||
/* It must already be open, since this one needed it;
|
||||
so dlopen will just find us its `struct link_map'
|
||||
and bump its reference count. */
|
||||
struct link_map *o, *dep
|
||||
= dlopen (strtab + d->d_un.d_val, RTLD_LAZY);
|
||||
--dep->l_opencount; /* Lose the ref from that dlopen. */
|
||||
/* Now we have the handle; we can close it for real. */
|
||||
o = map;
|
||||
map = dep;
|
||||
doit ();
|
||||
map = o;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap the segments. */
|
||||
for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
|
||||
Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
|
||||
+ ph->p_align - 1)
|
||||
& ~(ph->p_align - 1));
|
||||
munmap ((caddr_t) mapstart, mapend - mapstart);
|
||||
}
|
||||
|
||||
/* Finally, unlink the data structure and free it. */
|
||||
map->l_prev->l_next = map->l_next;
|
||||
if (map->l_next)
|
||||
map->l_next->l_prev = map->l_prev;
|
||||
free (map);
|
||||
}
|
||||
}
|
||||
|
||||
return _dlerror_run (doit) ? -1 : 0;
|
||||
}
|
||||
|
64
elf/dlerror.c
Normal file
64
elf/dlerror.c
Normal file
@ -0,0 +1,64 @@
|
||||
/* dlerror -- Return error detail for failing <dlfcn.h> functions.
|
||||
Copyright (C) 1995 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 <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int _dl_last_errcode;
|
||||
static const char *_dl_last_errstring;
|
||||
|
||||
char *
|
||||
dlerror (void)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (! _dl_last_errstring)
|
||||
return NULL;
|
||||
|
||||
if (_dl_last_errcode)
|
||||
{
|
||||
static char *buf;
|
||||
if (buf)
|
||||
{
|
||||
free (buf);
|
||||
buf = NULL;
|
||||
}
|
||||
if (asprintf (&buf, "%s: %s",
|
||||
_dl_last_errstring, strerror (_dl_last_errcode)) == -1)
|
||||
return NULL;
|
||||
else
|
||||
ret = buf;
|
||||
}
|
||||
else
|
||||
ret = (char *) _dl_last_errstring;
|
||||
|
||||
/* Reset the error indicator. */
|
||||
_dl_last_errstring = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_dlerror_run (void (*operate) (void))
|
||||
{
|
||||
_dl_last_errcode = _dl_catch_error (&_dl_last_errstring, operate);
|
||||
return _dl_last_errstring != NULL;
|
||||
}
|
62
elf/dlopen.c
Normal file
62
elf/dlopen.c
Normal file
@ -0,0 +1,62 @@
|
||||
/* dlopen -- Load a shared object at run time.
|
||||
Copyright (C) 1995 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 <stddef.h>
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
void *
|
||||
dlopen (const char *file, dl_open_mode mode)
|
||||
{
|
||||
struct link_map *new, *l;
|
||||
|
||||
void doit (void)
|
||||
{
|
||||
Elf32_Addr init;
|
||||
|
||||
new = _dl_map_object (_dl_loaded, file, NULL);
|
||||
|
||||
/* Map in any dependencies. */
|
||||
for (l = new; l; l = l->l_next)
|
||||
if (! l->l_deps_loaded)
|
||||
{
|
||||
if (l->l_info[DT_NEEDED])
|
||||
{
|
||||
const char *strtab
|
||||
= (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
|
||||
const Elf32_Dyn *d;
|
||||
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
_dl_map_object (l, strtab + d->d_un.d_val, NULL);
|
||||
}
|
||||
l->l_deps_loaded = 1;
|
||||
}
|
||||
|
||||
/* Relocate the objects loaded. */
|
||||
for (l = new; l; l = l->l_next)
|
||||
if (! l->l_relocated)
|
||||
_dl_relocate_object (l, mode == RTLD_LAZY);
|
||||
|
||||
/* Run the initializer functions of new objects. */
|
||||
while (init = _dl_init_next ())
|
||||
(*(void (*) (void)) init) ();
|
||||
}
|
||||
|
||||
return _dlerror_run (doit) ? NULL : new;
|
||||
}
|
46
elf/dlsym.c
Normal file
46
elf/dlsym.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* dlsym -- Look up a symbol in a shared object loaded by `dlopen'.
|
||||
Copyright (C) 1995 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 <stddef.h>
|
||||
#include <link.h>
|
||||
#include <dlfcn.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
void *
|
||||
dlsym (void *handle, const char *name)
|
||||
{
|
||||
struct link_map *map = handle;
|
||||
struct link_map *real_next;
|
||||
Elf32_Addr value;
|
||||
int lose;
|
||||
void doit (void)
|
||||
{
|
||||
const Elf32_Sym *ref = NULL;
|
||||
value = _dl_lookup_symbol (name, &ref, map);
|
||||
}
|
||||
|
||||
/* Confine the symbol scope to just this map. */
|
||||
real_next = map->l_next;
|
||||
map->l_next = NULL;
|
||||
lose = _dlerror_run (doit);
|
||||
map->l_next = real_next;
|
||||
|
||||
return lose ? NULL : (void *) value;
|
||||
}
|
119
elf/dynamic-link.h
Normal file
119
elf/dynamic-link.h
Normal file
@ -0,0 +1,119 @@
|
||||
/* Inline functions for dynamic linking.
|
||||
Copyright (C) 1995 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 <elf.h>
|
||||
|
||||
/* This machine-dependent file defines these inline functions. */
|
||||
|
||||
static void elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rel *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
|
||||
static void elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rela *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
|
||||
static Elf32_Addr *elf_machine_got (void);
|
||||
static Elf32_Addr elf_machine_load_address (void);
|
||||
|
||||
#include <dl-machine.h>
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
|
||||
|
||||
static inline void
|
||||
elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < DT_NUM; ++i)
|
||||
info[i] = NULL;
|
||||
|
||||
while (dyn->d_tag != DT_NULL)
|
||||
{
|
||||
assert (dyn->d_tag < DT_NUM);
|
||||
info[dyn->d_tag] = dyn++;
|
||||
}
|
||||
|
||||
if (info[DT_RELA])
|
||||
assert (info[DT_RELAENT]->d_un.d_val == sizeof (Elf32_Rela));
|
||||
if (info[DT_REL])
|
||||
assert (info[DT_RELENT]->d_un.d_val == sizeof (Elf32_Rel));
|
||||
if (info[DT_PLTREL])
|
||||
assert (info[DT_PLTREL]->d_un.d_val == DT_REL ||
|
||||
info[DT_PLTREL]->d_un.d_val == DT_RELA);
|
||||
}
|
||||
|
||||
/* Perform the relocations specified by DYNAMIC on the running program
|
||||
image. If LAZY is nonzero, don't relocate PLT entries. *RESOLVE is
|
||||
called to resolve symbol values; it modifies its argument pointer to
|
||||
point to the defining symbol, and returns the base load address of the
|
||||
defining object. */
|
||||
|
||||
static inline void
|
||||
elf_dynamic_relocate (Elf32_Dyn *dynamic[DT_NUM], Elf32_Addr loadaddr,
|
||||
int lazy, Elf32_Addr (*resolve) (const Elf32_Sym **))
|
||||
{
|
||||
const Elf32_Sym *const symtab
|
||||
= (const Elf32_Sym *) dynamic[DT_SYMTAB]->d_un.d_ptr;
|
||||
|
||||
inline Elf32_Addr symvalue (Elf32_Word info, const Elf32_Sym **definer)
|
||||
{
|
||||
if (ELF32_R_SYM (info) == STN_UNDEF)
|
||||
return 0; /* This value will not be consulted. */
|
||||
*definer = &symtab[ELF32_R_SYM (info)];
|
||||
return (*resolve) (definer);
|
||||
}
|
||||
|
||||
/* Perform Elf32_Rel relocations in the section found by RELTAG, SZTAG. */
|
||||
inline void do_rel (Elf32_Word reltag, Elf32_Word sztag)
|
||||
{
|
||||
const Elf32_Rel *r = (const Elf32_Rel *) dynamic[reltag]->d_un.d_ptr;
|
||||
const Elf32_Rel *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
|
||||
while (r < end)
|
||||
{
|
||||
const Elf32_Sym *definer;
|
||||
Elf32_Addr loadbase = symvalue (r->r_info, &definer);
|
||||
elf_machine_rel (loadaddr, dynamic, r, loadbase, definer);
|
||||
++r;
|
||||
}
|
||||
}
|
||||
/* Perform Elf32_Rela relocations in the section found by RELTAG, SZTAG. */
|
||||
inline void do_rela (Elf32_Word reltag, Elf32_Word sztag)
|
||||
{
|
||||
const Elf32_Rela *r = (const Elf32_Rela *) dynamic[reltag]->d_un.d_ptr;
|
||||
const Elf32_Rela *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
|
||||
while (r < end)
|
||||
{
|
||||
const Elf32_Sym *definer;
|
||||
Elf32_Addr loadbase = symvalue (r->r_info, &definer);
|
||||
elf_machine_rela (loadaddr, dynamic, r, loadbase, definer);
|
||||
++r;
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic[DT_RELA])
|
||||
do_rela (DT_RELA, DT_RELASZ);
|
||||
if (dynamic[DT_REL])
|
||||
do_rel (DT_REL, DT_RELSZ);
|
||||
if (dynamic[DT_JMPREL] && ! lazy)
|
||||
/* Relocate the PLT right now. */
|
||||
(dynamic[DT_PLTREL]->d_un.d_val == DT_REL ? do_rel : do_rela)
|
||||
(DT_JMPREL, DT_PLTRELSZ);
|
||||
}
|
206
elf/link.h
Normal file
206
elf/link.h
Normal file
@ -0,0 +1,206 @@
|
||||
/* Run-time dynamic linker data structures for loaded ELF shared objects.
|
||||
Copyright (C) 1995 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. */
|
||||
|
||||
#ifndef _LINK_H
|
||||
#define _LINK_H 1
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
|
||||
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||
details of shared object loading to the debugger. If the executable's
|
||||
dynamic section has a DT_DEBUG element, the run-time linker sets that
|
||||
element's value to the address where this structure can be found. */
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
int r_version; /* Version number for this protocol. */
|
||||
|
||||
struct link_map *r_map; /* Head of the chain of loaded objects. */
|
||||
|
||||
/* This is the address of a function internal to the run-time linker,
|
||||
that will always be called when the linker begins to map in a
|
||||
library or unmap it, and again when the mapping change is complete.
|
||||
The debugger can set a breakpoint at this address if it wants to
|
||||
notice shared object mapping changes. */
|
||||
Elf32_Addr r_brk;
|
||||
enum
|
||||
{
|
||||
/* This state value describes the mapping change taking place when
|
||||
the `r_brk' address is called. */
|
||||
RT_CONSISTENT, /* Mapping change is complete. */
|
||||
RT_ADD, /* Beginning to add a new object. */
|
||||
RT_DELETE, /* Beginning to remove an object mapping. */
|
||||
} r_state;
|
||||
|
||||
Elf32_Addr r_ldbase; /* Base address the linker is loaded at. */
|
||||
};
|
||||
|
||||
/* This symbol refers to the "dynamic structure" in the `.dynamic' section
|
||||
of whatever module refers to `_DYNAMIC'. So, to find its own
|
||||
`struct r_debug', a program could do:
|
||||
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL)
|
||||
if (dyn->d_tag == DT_DEBUG) r_debug = (struct r_debug) dyn->d_un.d_ptr;
|
||||
*/
|
||||
|
||||
extern Elf32_Dyn _DYNAMIC[];
|
||||
|
||||
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
members form a chain of all the shared objects loaded at startup.
|
||||
|
||||
These data structures exist in space used by the run-time dynamic linker;
|
||||
modifying them may have disastrous results. */
|
||||
|
||||
struct link_map
|
||||
{
|
||||
/* These first few members are part of the protocol with the debugger.
|
||||
This is the same format used in SVR4. */
|
||||
|
||||
Elf32_Addr l_addr; /* Base address shared object is loaded at. */
|
||||
char *l_name; /* Absolute file name object was found in. */
|
||||
Elf32_Dyn *l_ld; /* Dynamic section of the shared object. */
|
||||
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
|
||||
|
||||
/* All following members are internal to the dynamic linker.
|
||||
They may change without notice. */
|
||||
|
||||
const char *l_libname; /* Name requested (before search). */
|
||||
Elf32_Dyn *l_info[DT_NUM]; /* Indexed pointers to dynamic section. */
|
||||
const Elf32_Phdr *l_phdr; /* Pointer to program header table in core. */
|
||||
Elf32_Word l_phnum; /* Number of program header entries. */
|
||||
|
||||
/* Symbol hash table. */
|
||||
Elf32_Word l_nbuckets;
|
||||
const Elf32_Word *l_buckets, *l_chain;
|
||||
|
||||
unsigned int l_opencount; /* Reference count for dlopen/dlclose. */
|
||||
enum /* Where this object came from. */
|
||||
{
|
||||
lt_executable, /* The main executable program. */
|
||||
lt_interpreter, /* The interpreter: the dynamic linker. */
|
||||
lt_library, /* Library needed by main executable. */
|
||||
lt_loaded, /* Extra run-time loaded shared object. */
|
||||
} l_type:2;
|
||||
unsigned int l_deps_loaded:1; /* Nonzero if DT_NEEDED items loaded. */
|
||||
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
|
||||
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
|
||||
unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */
|
||||
};
|
||||
|
||||
/* 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 <dlfcn.h> provide a simple
|
||||
user interface to run-time dynamic linking. */
|
||||
|
||||
|
||||
/* File descriptor referring to the zero-fill device. */
|
||||
extern int _dl_zerofd;
|
||||
|
||||
/* OS-dependent function to open the zero-fill device. */
|
||||
extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */
|
||||
|
||||
/* OS-dependent function to give a fatal error message and exit
|
||||
when the dynamic linker fails before the program is fully linked.
|
||||
All arguments are `const char *'; args until a null pointer
|
||||
are concatenated to form the message to print. */
|
||||
extern void _dl_sysdep_fatal (const char *string, ...)
|
||||
__attribute__ ((__noreturn__));
|
||||
|
||||
/* Nonzero if the program should be "secure" (i.e. it's setuid or somesuch).
|
||||
This tells the dynamic linker to ignore environment variables. */
|
||||
extern int _dl_secure;
|
||||
|
||||
/* This function is called by all the internal dynamic linker functions
|
||||
when they encounter an error. ERRCODE is either an `errno' code
|
||||
or zero; ERRSTRING is a string describing the specific problem. */
|
||||
|
||||
extern void _dl_signal_error (int errcode, const char *errstring)
|
||||
__attribute__ ((__noreturn__));
|
||||
|
||||
/* 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 the string passed to _dl_signal_error, and the error code passed
|
||||
is the return value. */
|
||||
extern int _dl_catch_error (const char **errstring, void (*operate) (void));
|
||||
|
||||
|
||||
/* Helper function for <dlfcn.h> 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. */
|
||||
extern int _dlerror_run (void (*operate) (void));
|
||||
|
||||
|
||||
/* Open the shared object NAME and map in its segments.
|
||||
LOADER's DT_RPATH is used in searching for NAME.
|
||||
If ENTRY_POINT is not null, fill it in with the object's entry point.
|
||||
If the object is already opened, returns its existing map. */
|
||||
extern struct link_map *_dl_map_object (struct link_map *loader,
|
||||
const char *name,
|
||||
Elf32_Addr *entry_point);
|
||||
|
||||
/* Cache the locations of MAP's hash table. */
|
||||
extern void _dl_setup_hash (struct link_map *map);
|
||||
|
||||
|
||||
/* 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 the head of
|
||||
the chain used for searching. */
|
||||
extern Elf32_Addr _dl_lookup_symbol (const char *undef,
|
||||
const Elf32_Sym **sym,
|
||||
struct link_map *symbol_scope);
|
||||
|
||||
|
||||
/* List of objects currently loaded. */
|
||||
extern struct link_map *_dl_loaded;
|
||||
|
||||
/* Tail of that list which were loaded at startup. */
|
||||
extern struct link_map *_dl_startup_loaded;
|
||||
|
||||
/* Allocate a `struct link_map' for a new object being loaded,
|
||||
and enter it into the _dl_loaded list. */
|
||||
extern struct link_map *_dl_new_object (char *realname, const char *libname,
|
||||
int type);
|
||||
|
||||
/* Relocate the given object (if it hasn't already been).
|
||||
If LAZY is nonzero, don't relocate its PLT. */
|
||||
extern void _dl_relocate_object (struct link_map *map, int lazy);
|
||||
|
||||
/* Return the address of the next initializer function not yet run.
|
||||
When there are no more initializers to be run, this returns zero.
|
||||
The functions are returned in the order they should be called. */
|
||||
extern Elf32_Addr _dl_init_next (void);
|
||||
|
||||
/* Call the finalizer functions of all shared objects whose
|
||||
initializer functions have completed. */
|
||||
extern void _dl_fini (void);
|
||||
|
||||
/* 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_r_debug_state (void);
|
||||
|
||||
|
||||
#endif /* link.h */
|
267
elf/rtld.c
Normal file
267
elf/rtld.c
Normal file
@ -0,0 +1,267 @@
|
||||
/* Run time dynamic linker.
|
||||
Copyright (C) 1995 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 "dynamic-link.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#ifdef RTLD_START
|
||||
RTLD_START
|
||||
#else
|
||||
#error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
|
||||
#endif
|
||||
|
||||
/* 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 _dl_secure if we need to be secure (e.g. setuid),
|
||||
and for setting _dl_argc and _dl_argv, and then calling _dl_main. */
|
||||
extern Elf32_Addr _dl_sysdep_start (void **start_argptr,
|
||||
void (*dl_main) (const Elf32_Phdr *phdr,
|
||||
Elf32_Word phent,
|
||||
Elf32_Addr *user_entry));
|
||||
|
||||
int _dl_secure;
|
||||
int _dl_argc;
|
||||
char **_dl_argv;
|
||||
|
||||
struct r_debug dl_r_debug;
|
||||
|
||||
static void dl_main (const Elf32_Phdr *phdr,
|
||||
Elf32_Word phent,
|
||||
Elf32_Addr *user_entry);
|
||||
|
||||
Elf32_Addr
|
||||
_dl_start (void *arg)
|
||||
{
|
||||
Elf32_Addr rtld_loadaddr;
|
||||
Elf32_Dyn *dynamic_section;
|
||||
Elf32_Dyn *dynamic_info[DT_NUM];
|
||||
|
||||
/* Figure out the run-time load address of the dynamic linker itself. */
|
||||
rtld_loadaddr = elf_machine_load_address ();
|
||||
|
||||
/* Read our own dynamic section and fill in the info array.
|
||||
Conveniently, the first element of the GOT contains the
|
||||
offset of _DYNAMIC relative to the run-time load address. */
|
||||
dynamic_section = (void *) rtld_loadaddr + *elf_machine_got ();
|
||||
elf_get_dynamic_info (dynamic_section, dynamic_info);
|
||||
|
||||
#ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
|
||||
ELF_MACHINE_BEFORE_RTLD_RELOC (dynamic_info);
|
||||
#endif
|
||||
|
||||
/* Relocate ourselves so we can do normal function calls and
|
||||
data access using the global offset table. */
|
||||
{
|
||||
Elf32_Addr resolve (const Elf32_Sym **ref)
|
||||
{
|
||||
assert ((*ref)->st_shndx != SHN_UNDEF);
|
||||
return rtld_loadaddr;
|
||||
}
|
||||
elf_dynamic_relocate (dynamic_info, rtld_loadaddr, 0, resolve);
|
||||
}
|
||||
|
||||
/* Now life is sane; we can call functions and access global data.
|
||||
Set up to use the operating system facilities, and find out from
|
||||
the operating system's program loader where to find the program
|
||||
header table in core. */
|
||||
|
||||
dl_r_debug.r_ldbase = rtld_loadaddr; /* Record our load address. */
|
||||
|
||||
/* Call the OS-dependent function to set up life so we can do things like
|
||||
file access. It will call `dl_main' (below) to do all the real work
|
||||
of the dynamic linker, and then unwind our frame and run the user
|
||||
entry point on the same stack we entered on. */
|
||||
return _dl_sysdep_start (&arg, &dl_main);
|
||||
}
|
||||
|
||||
|
||||
/* Now life is peachy; we can do all normal operations.
|
||||
On to the real work. */
|
||||
|
||||
void _start (void);
|
||||
|
||||
static void
|
||||
dl_main (const Elf32_Phdr *phdr,
|
||||
Elf32_Word phent,
|
||||
Elf32_Addr *user_entry)
|
||||
{
|
||||
void doit (void)
|
||||
{
|
||||
const Elf32_Phdr *ph;
|
||||
struct link_map *l;
|
||||
const char *interpreter_name;
|
||||
int lazy;
|
||||
|
||||
if (*user_entry == (Elf32_Addr) &_start)
|
||||
{
|
||||
/* Ho ho. We are not the program interpreter! We are the program
|
||||
itself! This means someone ran ld.so as a command. Well, that
|
||||
might be convenient to do sometimes. We support it by
|
||||
interpreting the args like this:
|
||||
|
||||
ld.so PROGRAM ARGS...
|
||||
|
||||
The first argument is the name of a file containing an ELF
|
||||
executable we will load and run with the following arguments. To
|
||||
simplify life here, PROGRAM is searched for using the normal rules
|
||||
for shared objects, rather than $PATH or anything like that. We
|
||||
just load it and use its entry point; we don't pay attention to
|
||||
its PT_INTERP command (we are the interpreter ourselves). This is
|
||||
an easy way to test a new ld.so before installing it. */
|
||||
if (_dl_argc < 2)
|
||||
_dl_sysdep_fatal ("\
|
||||
Usage: ld.so EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
|
||||
You have invoked `ld.so', the helper program for shared library executables.\n\
|
||||
This program usually lives in the file `/lib/ld.so', and special directives\n\
|
||||
in executable files using ELF shared libraries tell the system's program\n\
|
||||
loader to load the helper program from this file. This helper program loads\n\
|
||||
the shared libraries needed by the program executable, prepares the program\n\
|
||||
to run, and runs it. You may invoke this helper program directly from the\n\
|
||||
command line to load and run an ELF executable file; this is like executing\n\
|
||||
that file itself, but always uses this helper program from the file you\n\
|
||||
specified, instead of the helper program file specified in the executable\n\
|
||||
file you run. This is mostly of use for maintainers to test new versions\n\
|
||||
of this helper program; chances are you did not intend to run this program.\n"
|
||||
);
|
||||
|
||||
interpreter_name = _dl_argv[0];
|
||||
--_dl_argc;
|
||||
++_dl_argv;
|
||||
l = _dl_map_object (NULL, _dl_argv[0], user_entry);
|
||||
phdr = l->l_phdr;
|
||||
phent = l->l_phnum;
|
||||
l->l_type = lt_executable;
|
||||
l->l_libname = (char *) "";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
l = _dl_new_object ((char *) "", "", lt_executable);
|
||||
l->l_phdr = phdr;
|
||||
l->l_phnum = phent;
|
||||
interpreter_name = 0;
|
||||
}
|
||||
|
||||
/* Scan the program header table for the dynamic section. */
|
||||
for (ph = phdr; ph < &phdr[phent]; ++ph)
|
||||
switch (ph->p_type)
|
||||
{
|
||||
case PT_DYNAMIC:
|
||||
/* This tells us where to find the dynamic section,
|
||||
which tells us everything we need to do. */
|
||||
l->l_ld = (void *) ph->p_vaddr;
|
||||
break;
|
||||
case PT_INTERP:
|
||||
/* This "interpreter segment" was used by the program loader to
|
||||
find the program interpreter, which is this program itself, the
|
||||
dynamic linker. We note what name finds us, so that a future
|
||||
dlopen call or DT_NEEDED entry, for something that wants to link
|
||||
against the dynamic linker as a shared library, will know that
|
||||
the shared object is already loaded. */
|
||||
interpreter_name = (void *) ph->p_vaddr;
|
||||
break;
|
||||
}
|
||||
assert (interpreter_name); /* How else did we get here? */
|
||||
|
||||
/* Extract the contents of the dynamic section for easy access. */
|
||||
elf_get_dynamic_info (l->l_ld, l->l_info);
|
||||
/* Set up our cache of pointers into the hash table. */
|
||||
_dl_setup_hash (l);
|
||||
|
||||
if (l->l_info[DT_DEBUG])
|
||||
/* There is a DT_DEBUG entry in the dynamic section. Fill it in
|
||||
with the run-time address of the r_debug structure, which we
|
||||
will set up later to communicate with the debugger. */
|
||||
l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
|
||||
|
||||
l = _dl_new_object ((char *) interpreter_name, interpreter_name,
|
||||
lt_interpreter);
|
||||
|
||||
/* Now process all the DT_NEEDED entries and map in the objects.
|
||||
Each new link_map will go on the end of the chain, so we will
|
||||
come across it later in the loop to map in its dependencies. */
|
||||
for (l = _dl_loaded; l; l = l->l_next)
|
||||
{
|
||||
if (l->l_info[DT_NEEDED])
|
||||
{
|
||||
const char *strtab
|
||||
= (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
|
||||
const Elf32_Dyn *d;
|
||||
for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
|
||||
if (d->d_tag == DT_NEEDED)
|
||||
_dl_map_object (l, strtab + d->d_un.d_val, NULL);
|
||||
}
|
||||
l->l_deps_loaded = 1;
|
||||
}
|
||||
|
||||
l = _dl_loaded->l_next;
|
||||
assert (l->l_type == lt_interpreter);
|
||||
if (l->l_opencount == 0)
|
||||
{
|
||||
/* No DT_NEEDED entry referred to the interpreter object itself.
|
||||
Remove it from the maps we will use for symbol resolution. */
|
||||
l->l_prev->l_next = l->l_next;
|
||||
if (l->l_next)
|
||||
l->l_next->l_prev = l->l_prev;
|
||||
}
|
||||
|
||||
lazy = _dl_secure || *(getenv ("LD_BIND_NOW") ?: "");
|
||||
|
||||
/* Now we have all the objects loaded. Relocate them all.
|
||||
We do this in reverse order so that copy relocs of earlier
|
||||
objects overwrite the data written by later objects. */
|
||||
l = _dl_loaded;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
do
|
||||
{
|
||||
_dl_relocate_object (l, lazy);
|
||||
l = l->l_prev;
|
||||
} while (l);
|
||||
|
||||
/* Tell the debugger where to find the map of loaded objects. */
|
||||
dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||
dl_r_debug.r_map = _dl_loaded;
|
||||
dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
|
||||
}
|
||||
const char *errstring;
|
||||
int err;
|
||||
|
||||
err = _dl_catch_error (&errstring, &doit);
|
||||
if (errstring)
|
||||
_dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>",
|
||||
": error in loading shared libraries\n",
|
||||
errstring, err ? ": " : NULL,
|
||||
err ? strerror (err) : NULL, NULL);
|
||||
|
||||
/* Once we return, _dl_sysdep_start will invoke
|
||||
the DT_INIT functions and then *USER_ENTRY. */
|
||||
}
|
||||
|
||||
/* This function exists solely to have a breakpoint set on it by the
|
||||
debugger. */
|
||||
void
|
||||
_dl_r_debug_state (void)
|
||||
{
|
||||
}
|
98
sysdeps/generic/dl-sysdep.c
Normal file
98
sysdeps/generic/dl-sysdep.c
Normal file
@ -0,0 +1,98 @@
|
||||
/* Operating system support for run-time dynamic linker. Generic Unix version.
|
||||
Copyright (C) 1995 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 <elf.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <link.h>
|
||||
|
||||
Elf32_Addr
|
||||
_dl_sysdep_start (void **start_argptr,
|
||||
void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phnum,
|
||||
Elf32_Addr *user_entry))
|
||||
{
|
||||
const Elf32_Phdr *phdr;
|
||||
Elf32_Word phnum;
|
||||
Elf32_Addr user_entry;
|
||||
Elf32_auxv_t *av;
|
||||
uid_t uid, euid;
|
||||
gid_t gid, egid;
|
||||
|
||||
_dl_argc = *(int *) start_argptr;
|
||||
_dl_argv = start_argptr + 1;
|
||||
_environ = &_dl_argv[_dl_argc + 1];
|
||||
start_argptr = (void **) _environ;
|
||||
while (*start_argptr)
|
||||
++start_argptr;
|
||||
|
||||
for (av = ++start_argptr; av->a_type != AT_NULL; ++av)
|
||||
switch (av->a_type)
|
||||
{
|
||||
case AT_PHDR:
|
||||
phdr = av->a_un.a_ptr;
|
||||
break;
|
||||
case AT_PHNUM:
|
||||
phnum = av->a_un.a_val;
|
||||
break;
|
||||
case AT_ENTRY:
|
||||
user_entry = av->a_un.a_val;
|
||||
case AT_UID:
|
||||
uid = av->a_un.a_val;
|
||||
break;
|
||||
case AT_GID:
|
||||
gid = av->a_un.a_val;
|
||||
break;
|
||||
case AT_EUID:
|
||||
euid = av->a_un.a_val;
|
||||
break;
|
||||
case AT_EGID:
|
||||
egid = av->a_un.a_val;
|
||||
break;
|
||||
}
|
||||
|
||||
_dl_secure = uid != euid || gid != egid;
|
||||
|
||||
(*dl_main) (phdr, phnum, &user_entry);
|
||||
start_argptr[-1] = (void *) user_entry;
|
||||
}
|
||||
|
||||
int
|
||||
_dl_sysdep_open_zero_fill (void)
|
||||
{
|
||||
return open ("/dev/zero", O_RDONLY);
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void
|
||||
_dl_sysdep_fatal (const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, msg);
|
||||
do
|
||||
{
|
||||
size_t len = strlen (msg);
|
||||
write (STDERR_FILENO, msg, len);
|
||||
msg = va_arg (ap, const char *);
|
||||
} while (msg);
|
||||
va_end (ap);
|
||||
|
||||
_exit (127);
|
||||
}
|
169
sysdeps/i386/dl-machine.h
Normal file
169
sysdeps/i386/dl-machine.h
Normal file
@ -0,0 +1,169 @@
|
||||
/* Machine-dependent ELF dynamic relocation inline functions. i386 version.
|
||||
Copyright (C) 1995 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. */
|
||||
|
||||
#define ELF_MACHINE_NAME "i386"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <link.h>
|
||||
|
||||
|
||||
/* Return nonzero iff E_MACHINE is compatible with the running host. */
|
||||
static inline int
|
||||
elf_machine_matches_host (Elf32_Half e_machine)
|
||||
{
|
||||
switch (e_machine)
|
||||
{
|
||||
case EM_386:
|
||||
case EM_486:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the run-time address of the _GLOBAL_OFFSET_TABLE_.
|
||||
Must be inlined in a function which uses global data. */
|
||||
static inline Elf32_Addr *
|
||||
elf_machine_got (void)
|
||||
{
|
||||
register Elf32_Addr *got asm ("%ebx");
|
||||
return got;
|
||||
}
|
||||
|
||||
|
||||
/* Return the run-time load address of the shared object. */
|
||||
static inline Elf32_Addr
|
||||
elf_machine_load_address (void)
|
||||
{
|
||||
Elf32_Addr addr;
|
||||
asm (" call here\n"
|
||||
"here: popl %0\n"
|
||||
" subl $here, %0"
|
||||
: "=r" (addr));
|
||||
return addr;
|
||||
}
|
||||
/* The `subl' insn above will contain an R_386_32 relocation entry
|
||||
intended to insert the run-time address of the label `here'.
|
||||
This will be the first relocation in the text of the dynamic linker;
|
||||
we skip it to avoid trying to modify read-only text in this early stage. */
|
||||
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \
|
||||
++(const Elf32_Rel *) (dynamic_info)[DT_REL]->d_un.d_ptr;
|
||||
|
||||
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
|
||||
LOADADDR is the load address of the object; INFO is an array indexed
|
||||
by DT_* of the .dynamic section info. */
|
||||
|
||||
static inline void
|
||||
elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rel *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
|
||||
{
|
||||
Elf32_Addr *const reloc_addr = (Elf32_Addr *) reloc->r_offset;
|
||||
const Elf32_Addr sym_value = sym_loadaddr + sym->st_value;
|
||||
|
||||
switch (ELF32_R_TYPE (reloc->r_info))
|
||||
{
|
||||
case R_386_COPY:
|
||||
memcpy (reloc_addr, (void *) sym_value, sym->st_size);
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
case R_386_JMP_SLOT:
|
||||
*reloc_addr = sym_value;
|
||||
break;
|
||||
case R_386_32:
|
||||
*reloc_addr += sym_value;
|
||||
break;
|
||||
case R_386_RELATIVE:
|
||||
*reloc_addr += loadaddr;
|
||||
break;
|
||||
case R_386_PC32:
|
||||
*reloc_addr = sym_value - (Elf32_Addr) reloc_addr;
|
||||
break;
|
||||
default:
|
||||
assert (! "unexpected dynamic reloc type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The i386 never uses Elf32_Rela relocations. */
|
||||
static inline void
|
||||
elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rela *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
|
||||
{
|
||||
_dl_signal_error (0, "Elf32_Rela relocation requested -- unused on i386");
|
||||
}
|
||||
|
||||
|
||||
/* Set up the loaded object described by L so its unrelocated PLT
|
||||
entries will jump to the on-demand fixup code in dl-runtime.c. */
|
||||
|
||||
static inline void
|
||||
elf_machine_runtime_setup (struct link_map *l)
|
||||
{
|
||||
extern void _dl_runtime_resolve (Elf32_Word);
|
||||
/* The GOT entries for functions in the PLT have not yet been filled
|
||||
in. Their initial contents will arrange when called to push an
|
||||
offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
|
||||
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
|
||||
Elf32_Addr *got = (Elf32_Addr *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
|
||||
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
|
||||
/* This function will get called to fix up the GOT entry indicated by
|
||||
the offset on the stack, and then jump to the resolved address. */
|
||||
got[2] = (Elf32_Addr) &_dl_runtime_resolve;
|
||||
}
|
||||
|
||||
|
||||
/* Initial entry point code for the dynamic linker.
|
||||
The C function `_dl_start' is the real entry point;
|
||||
its return value is the user program's entry point. */
|
||||
|
||||
#define RTLD_START asm ("\
|
||||
.text\n\
|
||||
.globl _start\n\
|
||||
_start: call _dl_start\n\
|
||||
# Save the user entry point address in %ebx.\n\
|
||||
movl %eax, %ebx\n\
|
||||
# Call _dl_init_next to return the address of an initializer\n\
|
||||
# function to run.\n\
|
||||
0: call _dl_init_next@PLT\n\
|
||||
# Check for zero return, when out of initializers.\n\
|
||||
testl %eax,%eax\n\
|
||||
jz 1f\n\
|
||||
# Call the shared object initializer function.\n\
|
||||
# NOTE: We depend only on the registers (%ebx)\n\
|
||||
# and the return address pushed by this call;\n\
|
||||
# the initializer is called with the stack just\n\
|
||||
# as it appears on entry, and it is free to move\n\
|
||||
# the stack around, as long as it winds up jumping to\n\
|
||||
# the return address on the top of the stack.\n\
|
||||
call *%eax\n\
|
||||
# Loop to call _dl_init_next for the next initializer.\n\
|
||||
jmp 0b\n\
|
||||
# Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
|
||||
1: call 2f\n\
|
||||
2: popl %eax\n\
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-2b], %eax\n\
|
||||
leal _dl_fini@GOT(%eax), %edx\n\
|
||||
# Jump to the user entry point.\n\
|
||||
jmp *%ebx\n\
|
||||
");
|
92
sysdeps/i386/dl-runtime.c
Normal file
92
sysdeps/i386/dl-runtime.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* On-demand PLT fixup for shared objects. i386 version.
|
||||
Copyright (C) 1995 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. */
|
||||
|
||||
register void *sp asm ("%esp");
|
||||
|
||||
#include <link.h>
|
||||
#include "dynamic-link.h"
|
||||
|
||||
/* This function is not called in the normal way. The PLT jumps here, not
|
||||
using a call. The stack looks like this:
|
||||
|
||||
-->8(%esp) address to return to the caller of the function in the PLT
|
||||
4(%esp) relocation offset for this PLT entry
|
||||
0(%esp) identifier for this shared object (struct link_map *)
|
||||
|
||||
The user expects the real function the PLT refers to to be entered
|
||||
8(%esp) as the top of stack. */
|
||||
|
||||
void
|
||||
_dl_runtime_resolve (Elf32_Word reloc_offset)
|
||||
{
|
||||
__label__ return_insn;
|
||||
struct link_map *l = (void *) &(&reloc_offset)[-1];
|
||||
|
||||
const Elf32_Sym *const symtab
|
||||
= (const Elf32_Sym *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
|
||||
const char *strtab
|
||||
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
const Elf32_Rel *const reloc = (void *) (l->l_info[DT_JMPREL]->d_un.d_ptr
|
||||
+ reloc_offset);
|
||||
|
||||
const Elf32_Sym *definer;
|
||||
Elf32_Addr loadbase;
|
||||
struct link_map *scope, *real_next;
|
||||
|
||||
/* Look up the symbol's run-time value. */
|
||||
|
||||
real_next = l->l_next;
|
||||
if (l->l_info[DT_SYMBOLIC])
|
||||
{
|
||||
l->l_prev->l_next = real_next;
|
||||
l->l_next = _dl_loaded;
|
||||
scope = l;
|
||||
}
|
||||
else
|
||||
scope = _dl_loaded;
|
||||
|
||||
definer = &symtab[ELF32_R_SYM (reloc->r_info)];
|
||||
loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, scope);
|
||||
|
||||
/* Restore list frobnication done above for DT_SYMBOLIC. */
|
||||
l->l_next = real_next;
|
||||
l->l_prev->l_next = l;
|
||||
|
||||
/* Apply the relocation with that value. */
|
||||
elf_machine_rel (l->l_addr, l->l_info, reloc, loadbase, definer);
|
||||
|
||||
/* The top of the stack is the word we set L from; but this location
|
||||
holds the address we will return to. Store there the address of a
|
||||
"ret" instruction, which will pop the stack and run the code at the
|
||||
address in the next stack word. */
|
||||
(&reloc_offset)[-1] = (Elf32_Word) &&return_insn;
|
||||
|
||||
/* The next stack word is our argument RELOC_OFFSET; but that "ret" will
|
||||
pop and jump to this location, and the next stack word is the user's
|
||||
return address. So store here the resolved address of the function
|
||||
referred to by this PLT entry; once "ret" pops this address, the
|
||||
function in the shared object will run with the stack arranged just as
|
||||
when the user entered the PLT. */
|
||||
(&reloc_offset)[0] = *(Elf32_Word *) reloc->r_offset;
|
||||
|
||||
return;
|
||||
|
||||
return_insn: asm volatile ("ret");
|
||||
}
|
86
sysdeps/i386/elf/start.S
Normal file
86
sysdeps/i386/elf/start.S
Normal file
@ -0,0 +1,86 @@
|
||||
/* Startup code compliant to the ELF i386 ABI.
|
||||
Copyright (C) 1995 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. */
|
||||
|
||||
/* This is the canonical entry point, usually the first thing in the text
|
||||
segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
|
||||
point runs, most registers' values are unspecified, except for:
|
||||
|
||||
%edx Contains a function pointer to be registered with `atexit'.
|
||||
This is how the dynamic linker arranges to have DT_FINI
|
||||
functions called for shared libraries that have been loaded
|
||||
before this code runs.
|
||||
|
||||
%esp The stack contains the arguments and environment:
|
||||
0(%esp) argc
|
||||
4(%esp) argv[0]
|
||||
...
|
||||
(4*argc)(%esp) NULL
|
||||
(4*(argc+1))(%esp) envp[0]
|
||||
...
|
||||
NULL
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
/* Clear the frame pointer. The ABI suggests this be done, to mark
|
||||
the outermost frame obviously. */
|
||||
movl $0, %ebp
|
||||
|
||||
/* %edx contains the address of the shared library termination
|
||||
function, which we will register with `atexit' to be called by
|
||||
`exit'. I suspect that on some systems, and when statically
|
||||
linked, this will not be set by anything to any function
|
||||
pointer; hopefully it will be zero so we don't try to call
|
||||
random pointers. */
|
||||
testl %edx
|
||||
jeq nofini
|
||||
pushl %edx
|
||||
call atexit
|
||||
addl $4, %esp
|
||||
nofini:
|
||||
|
||||
/* Do essential libc initialization. In statically linked
|
||||
programs under the GNU Hurd, this is what sets up the
|
||||
arguments on the stack for the code below. */
|
||||
call __libc_init_first
|
||||
|
||||
/* Extract the arguments and environment as encoded on the stack
|
||||
and set up the arguments for `main': argc, argv, envp. */
|
||||
popl %esi /* Pop the argument count. */
|
||||
leal 4(%esp,%esi,4), %eax /* envp = &argv[argc + 1] */
|
||||
movl %eax, _environ /* Store it in the global variable. */
|
||||
pushl %eax /* Push third argument: envp. */
|
||||
leal 4(%esp), %eax /* argv starts just above that word. */
|
||||
pushl %eax /* Push second argument: argv. */
|
||||
pushl %esi /* Push first argument: argc. */
|
||||
|
||||
/* Call `_init', which is the entry point to our own `.init'
|
||||
section; and register with `atexit' to have `exit' call
|
||||
`_fini', which is the entry point to our own `.fini' section. */
|
||||
call _init
|
||||
pushl $_fini
|
||||
call atexit
|
||||
addl $4, %esp
|
||||
|
||||
/* Call the user's main function, and exit with its value. */
|
||||
call main
|
||||
pushl %eax
|
||||
call exit /* This should never return. */
|
||||
hlt /* Crash if somehow it does return. */
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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
|
||||
@ -20,15 +20,11 @@ Cambridge, MA 02139, USA. */
|
||||
|
||||
#define LOSE asm volatile ("hlt")
|
||||
|
||||
#define SNARF_ARGS(argc, argv, envp) \
|
||||
#define SNARF_ARGS(entry_sp, argc, argv, envp) \
|
||||
do \
|
||||
{ \
|
||||
int *entry_sp; \
|
||||
register char **p; \
|
||||
\
|
||||
asm ("leal 4(%%ebp), %0" : "=r" (entry_sp)); \
|
||||
\
|
||||
argc = *entry_sp; \
|
||||
argc = (int) *entry_sp; \
|
||||
argv = (char **) (entry_sp + 1); \
|
||||
p = argv; \
|
||||
while (*p++ != NULL) \
|
||||
@ -38,9 +34,15 @@ Cambridge, MA 02139, USA. */
|
||||
envp = p; \
|
||||
} while (0)
|
||||
|
||||
#define CALL_WITH_SP(fn, sp) \
|
||||
asm volatile ("movl %0, %%esp; jmp %1" : : \
|
||||
"g" (sp), "m" (*(long int *) (fn)) : "%esp")
|
||||
#define CALL_WITH_SP(fn, info, sp) \
|
||||
do { \
|
||||
void **ptr = (void **) sp; \
|
||||
*--(__typeof (info) *) ptr = info; \
|
||||
ptr[-1] = ptr; \
|
||||
--ptr; \
|
||||
asm volatile ("movl %0, %%esp; call %1" : : \
|
||||
"g" (ptr), "m" (*(long int *) (fn)) : "%esp"); \
|
||||
} while (0)
|
||||
|
||||
#define STACK_GROWTH_DOWN
|
||||
|
||||
|
115
sysdeps/stub/dl-machine.h
Normal file
115
sysdeps/stub/dl-machine.h
Normal file
@ -0,0 +1,115 @@
|
||||
/* Machine-dependent ELF dynamic relocation inline functions. Stub version.
|
||||
Copyright (C) 1995 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. */
|
||||
|
||||
#define ELF_MACHINE_NAME "stub"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <link.h>
|
||||
|
||||
|
||||
/* Return nonzero iff E_MACHINE is compatible with the running host. */
|
||||
static inline int
|
||||
elf_machine_matches_host (Elf32_Half e_machine)
|
||||
{
|
||||
switch (e_machine)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the run-time address of the _GLOBAL_OFFSET_TABLE_. */
|
||||
static inline Elf32_Addr *
|
||||
elf_machine_got (void)
|
||||
{
|
||||
#error "GOT not got"
|
||||
}
|
||||
|
||||
|
||||
/* Return the run-time load address of the shared object. */
|
||||
static inline Elf32_Addr
|
||||
elf_machine_load_address (void)
|
||||
{
|
||||
#error "Where am I?"
|
||||
}
|
||||
|
||||
/* This can modify DYNAMIC_INFO to avoid relocating code in
|
||||
the functions above if they are doing bizarre magic. */
|
||||
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
|
||||
|
||||
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
|
||||
LOADADDR is the load address of the object; INFO is an array indexed
|
||||
by DT_* of the .dynamic section info. */
|
||||
|
||||
static inline void
|
||||
elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rel *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
|
||||
{
|
||||
Elf32_Addr *const reloc_addr = (Elf32_Addr *) reloc->r_offset;
|
||||
const Elf32_Addr sym_value = sym_loadaddr + sym->st_value;
|
||||
|
||||
switch (ELF32_R_TYPE (reloc->r_info))
|
||||
{
|
||||
case R_MACHINE_COPY:
|
||||
memcpy (reloc_addr, (void *) sym_value, sym->st_size);
|
||||
break;
|
||||
default:
|
||||
assert (! "unexpected dynamic reloc type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
|
||||
const Elf32_Rela *reloc,
|
||||
Elf32_Addr sym_loadaddr, const Elf32_Sym *sym)
|
||||
{
|
||||
_dl_signal_error (0, "Elf32_Rela relocation requested -- unused on "
|
||||
ELF_MACHINE_NAME);
|
||||
}
|
||||
|
||||
|
||||
/* Set up the loaded object described by L so its unrelocated PLT
|
||||
entries will jump to the on-demand fixup code in dl-runtime.c. */
|
||||
|
||||
static inline void
|
||||
elf_machine_runtime_setup (struct link_map *l)
|
||||
{
|
||||
extern void _dl_runtime_resolve (Elf32_Word);
|
||||
/* The GOT entries for functions in the PLT have not yet been filled
|
||||
in. Their initial contents will arrange when called to push an
|
||||
offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
|
||||
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
|
||||
Elf32_Addr *got = (Elf32_Addr *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
|
||||
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
|
||||
/* This function will get called to fix up the GOT entry indicated by
|
||||
the offset on the stack, and then jump to the resolved address. */
|
||||
got[2] = (Elf32_Addr) &_dl_runtime_resolve;
|
||||
}
|
||||
|
||||
|
||||
/* Initial entry point code for the dynamic linker.
|
||||
The C function `_dl_start' is the real entry point;
|
||||
its return value is the user program's entry point. */
|
||||
|
||||
#define RTLD_START #error need some startup code
|
64
sysdeps/stub/dl-runtime.c
Normal file
64
sysdeps/stub/dl-runtime.c
Normal file
@ -0,0 +1,64 @@
|
||||
/* On-demand PLT fixup for shared objects. Stub version.
|
||||
Copyright (C) 1995 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 "dynamic-link.h"
|
||||
|
||||
/* This function is not called in the normal way. The PLT jumps here, not
|
||||
using a call. */
|
||||
void
|
||||
_dl_runtime_resolve ()
|
||||
{
|
||||
struct link_map *l = ???;
|
||||
Elf32_Word reloc_offset = ???;
|
||||
|
||||
const Elf32_Sym *const symtab
|
||||
= (const Elf32_Sym *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
|
||||
const char *strtab
|
||||
= ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
|
||||
|
||||
const Elf32_Rel *const reloc = (void *) (l->l_info[DT_JMPREL]->d_un.d_ptr
|
||||
+ reloc_offset);
|
||||
|
||||
const Elf32_Sym *definer;
|
||||
Elf32_Addr loadbase;
|
||||
struct link_map *scope, *real_next;
|
||||
|
||||
/* Look up the symbol's run-time value. */
|
||||
|
||||
real_next = l->l_next;
|
||||
if (l->l_info[DT_SYMBOLIC])
|
||||
{
|
||||
l->l_prev->l_next = real_next;
|
||||
l->l_next = _dl_loaded;
|
||||
scope = l;
|
||||
}
|
||||
else
|
||||
scope = _dl_loaded;
|
||||
|
||||
definer = &symtab[ELF32_R_SYM (reloc->r_info)];
|
||||
loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, scope);
|
||||
|
||||
/* Restore list frobnication done above for DT_SYMBOLIC. */
|
||||
l->l_next = real_next;
|
||||
l->l_prev->l_next = l;
|
||||
|
||||
/* Apply the relocation with that value. */
|
||||
elf_machine_rel (l->l_addr, l->l_info, reloc, loadbase, definer);
|
||||
}
|
Loading…
Reference in New Issue
Block a user