aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile28
-rw-r--r--elf/dlsym.c2
-rw-r--r--elf/linux-compat.c40
-rw-r--r--elf/rtld.c76
4 files changed, 120 insertions, 26 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 21d2fc5..314289b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -31,24 +31,42 @@ libdl-inhibit-o = $(filter-out .so,$(object-suffixes)) # Build only shared.
rtld-routines := rtld $(addprefix dl-,load lookup object reloc \
runtime sysdep error init fini)
distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h \
- soinit.c sofini.c ldd.sh.in
+ soinit.c sofini.c ldd.sh.in linux-compat.c
include ../Makeconfig
ifeq (yes,$(build-shared))
extra-objs = $(rtld-routines:=.so) soinit.so sofini.so
+generated = librtld.so
install-others = $(libdir)/$(rtld-installed-name)
install-bin = ldd
+
+ifneq (,$(filter linux%,$(config-os)))
+extra-objs += linux-compat.so
+install-lib += ld-linux.so.1
+endif
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 -nostartfiles -shared -o $@ \
+
+# Link together the dynamic linker into a single relocatable object.
+# We use this to produce both the ABI-compliant and Linux-compatible
+# dynamic linker shared objects below.
+$(objpfx)librtld.so: $(rtld-routines:%=$(objpfx)%.so) \
+ $(patsubst %,$(common-objpfx)lib%_pic.a,\
+ elf c $(LDLIBS-c.so:-l%=%))
+ $(LINK.o) -nostdlib -nostartfiles -r -o $@ \
'-Wl,-(' $^ -lgcc '-Wl,-)'
+$(objpfx)ld.so $(objpfx)ld-linux.so.1: $(objpfx)librtld.so
+ $(LINK.o) -nostdlib -nostartfiles -shared -o $@ $^
+
+# The Linux-compatible dynamic linker shared object is just the same
+# with one object file of compatibility initialization code added.
+$(objpfx)ld-linux.so.1: $(objpfx)linux-compat.so
+
+
$(objpfx)libdl.so: $(objpfx)libdl_pic.a $(common-objpfx)libc.so $(objpfx)ld.so
$(patsubst %/,cd %;,$(objpfx)) \
$(LINK.o) -shared -o $(@:$(objpfx)%=%) \
diff --git a/elf/dlsym.c b/elf/dlsym.c
index 8277ca3..0441e54 100644
--- a/elf/dlsym.c
+++ b/elf/dlsym.c
@@ -29,10 +29,10 @@ dlsym (void *handle, const char *name)
struct link_map *map = handle;
struct link_map *real_next;
Elf32_Addr loadbase;
+ const Elf32_Sym *ref = NULL;
int lose;
void doit (void)
{
- const Elf32_Sym *ref = NULL;
loadbase = _dl_lookup_symbol (name, &ref, map, map->l_name, 1);
}
diff --git a/elf/linux-compat.c b/elf/linux-compat.c
new file mode 100644
index 0000000..ed1595e
--- /dev/null
+++ b/elf/linux-compat.c
@@ -0,0 +1,40 @@
+/* Initializer for Linux-compatible dynamic linker `/lib/ld-linux.so.1'.
+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 <stdlib.h>
+
+/* This function will be the DT_INIT initializer for the ld-linux.so.1
+ shared object. This is called from rtld.c before shlib initializers.
+
+ The old Linux ELF startup code expects the dynamic linker to magically
+ call atexit to arrange for shared object finalizers to run. (The
+ ABI-compliant startup code does this itself.) We build a compatible
+ version of the dynamic linker to install as /lib/ld-linux.so.1, the
+ name old Linux ELF binaries use. */
+
+void
+_init (void)
+{
+ const Elf32_Sym *ref = NULL;
+ Elf32_Addr loadbase = _dl_lookup_symbol ("atexit", &ref, _dl_loaded,
+ "<ld-linux.so.1 initialization>",
+ 1);
+ (*(__typeof (atexit) *) (loadbase + ref->st_value)) (&_dl_fini);
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index 19f5439..9a822a8 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -50,22 +50,24 @@ static void dl_main (const Elf32_Phdr *phdr,
Elf32_Word phent,
Elf32_Addr *user_entry);
+static struct link_map rtld_map;
+
Elf32_Addr
_dl_start (void *arg)
{
- struct link_map rtld_map;
+ struct link_map bootstrap_map;
/* Figure out the run-time load address of the dynamic linker itself. */
- rtld_map.l_addr = elf_machine_load_address ();
+ bootstrap_map.l_addr = 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. */
- rtld_map.l_ld = (void *) rtld_map.l_addr + *elf_machine_got ();
- elf_get_dynamic_info (rtld_map.l_ld, rtld_map.l_info);
+ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + *elf_machine_got ();
+ elf_get_dynamic_info (bootstrap_map.l_ld, bootstrap_map.l_info);
#ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
- ELF_MACHINE_BEFORE_RTLD_RELOC (rtld_map.l_info);
+ ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
#endif
/* Relocate ourselves so we can do normal function calls and
@@ -77,8 +79,8 @@ _dl_start (void *arg)
bootstrapping, so it must anti-perform each bootstrapping relocation
before applying the final relocation when ld.so is linked in as
normal a shared library. */
- rtld_map.l_type = lt_library;
- ELF_DYNAMIC_RELOCATE (&rtld_map, 0, NULL);
+ bootstrap_map.l_type = lt_library;
+ ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, NULL);
/* Now life is sane; we can call functions and access global data.
@@ -86,7 +88,12 @@ _dl_start (void *arg)
the operating system's program loader where to find the program
header table in core. */
- dl_r_debug.r_ldbase = rtld_map.l_addr; /* Record our load address. */
+
+ /* Transfer data about ourselves to the permanent link_map structure. */
+ rtld_map.l_addr = bootstrap_map.l_addr;
+ rtld_map.l_ld = bootstrap_map.l_ld;
+ memcpy (rtld_map.l_info, bootstrap_map.l_info, sizeof rtld_map.l_info);
+
/* 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
@@ -122,9 +129,9 @@ dl_main (const Elf32_Phdr *phdr,
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
@@ -228,8 +235,14 @@ of this helper program; chances are you did not intend to run this program.\n",
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);
+ /* Put the link_map for ourselves on the chain so it can be found by
+ name. */
+ rtld_map.l_name = (char *) rtld_map.l_libname = interpreter_name;
+ rtld_map.l_type = lt_interpreter;
+ while (l->l_next)
+ l = l->l_next;
+ l->l_next = &rtld_map;
+ rtld_map.l_prev = l;
/* 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
@@ -248,16 +261,13 @@ of this helper program; chances are you did not intend to run this program.\n",
l->l_deps_loaded = 1;
}
- l = _dl_loaded->l_next;
- while (l->l_type != lt_interpreter)
- l = l->l_next;
- if (l->l_opencount == 0)
+ if (rtld_map.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;
+ rtld_map.l_prev->l_next = rtld_map.l_next;
+ if (rtld_map.l_next)
+ rtld_map.l_next->l_prev = rtld_map.l_prev;
}
lazy = !_dl_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';
@@ -276,6 +286,7 @@ of this helper program; chances are you did not intend to run this program.\n",
/* 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_ldbase = rtld_map.l_addr; /* Record our load address. */
dl_r_debug.r_map = _dl_loaded;
dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
@@ -301,6 +312,19 @@ of this helper program; chances are you did not intend to run this program.\n",
_exit (0);
}
+
+ if (rtld_map.l_info[DT_INIT])
+ {
+ /* Call the initializer for the compatibility version of the
+ dynamic linker. There is no additional initialization
+ required for the ABI-compliant dynamic linker. */
+
+ (*(void (*) (void)) (rtld_map.l_addr +
+ rtld_map.l_info[DT_INIT]->d_un.d_ptr)) ();
+
+ /* Clear the field so a future dlopen won't run it again. */
+ rtld_map.l_info[DT_INIT] = NULL;
+ }
}
const char *errstring;
const char *errobj;
@@ -318,13 +342,25 @@ of this helper program; chances are you did not intend to run this program.\n",
the DT_INIT functions and then *USER_ENTRY. */
}
-/* This function exists solely to have a breakpoint set on it by the
+/* This function exists solely to have a breakpoint set on it by the
debugger. */
void
_dl_r_debug_state (void)
{
}
+/* Define our own stub for the localization function used by strerror.
+ English-only in the dynamic linker keeps it smaller. */
+
+char *
+__dgettext (const char *domainname, const char *msgid)
+{
+ assert (domainname == _libc_intl_domainname);
+ return (char *) msgid;
+}
+weak_symbol (__dgettext)
+weak_alias (__dgettext, dgettext)
+
#ifndef NDEBUG
/* Define (weakly) our own assert failure function which doesn't use stdio.