* 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:
Roland McGrath 1995-05-02 06:35:55 +00:00
parent 08162fa888
commit d66e34cd42
23 changed files with 2379 additions and 12 deletions

View File

@ -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>

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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)
{
}

View 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
View 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
View 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
View 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. */

View File

@ -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
View 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
View 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);
}