From 86d2c878acad4d2f16d0af6fe6a030b90815362d Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 7 Nov 1995 21:46:52 +0000 Subject: Tue Nov 7 12:29:46 1995 Roland McGrath * elf/linux-compat.c: New file. * elf/Makefile (distribute): Add linux-compat.c. (generated): Add librtld.so. [$(config-os)=linux*] (extra-objs): Add linux-compat.so. [$(config-os)=linux*] (extra-objs): Add ld-linux.so.1. (librtld.so): New target. (ld.so, ld-linux.so.1): Make from librtld.so. * elf/rtld.c (dl_main): Instead of weak call to _dl_compat_init, call our own DT_INIT if we have one (and then clear it). (__dgettext): New weak function. * intl/localealias.c (read_alias_file): Avoid sprintf; use memcpy by hand instead. * sysdeps/generic/_strerror.c (_strerror_internal): Use _itoa instead of snprintf. * sysdeps/mach/_strerror.c (_strerror_internal): Don't write BUF[BUFLEN]. * elf/rtld.c (rtld_map): New static variable. (_dl_start): Use a differently named local BOOTSTRAP_MAP for the bootstrapping. Then copy data into `rtld_map'. (dl_main): Finish filling in rtld_map and link it into the chain, instead of allocating a new structure. (dl_main): Call _dl_compat_init if it is defined (use weak ref). * elf/dlsym.c: Fix last change: move REF out of `doit'. control. using it. and cwdir ports. functions. these. $(libdir)(rtld-installed-name). leading zeroes. in the rhs. pattern rule. never know. (fork): Use symbol_set_* macros for _hurd_fork_locks. * sysdeps/unix/sysv/sysv4/linux/i386/sysdep.S (__syscall_error): instead of unix/sysv. -dynamic-linker. (__printf_fp): Last arg ARGS is now `const void **const'; locale/C-ctype.c. * sysdeps/mach/hurd/sigsuspend.c: Likewise. * sysdeps/mach/hurd/mips/sigreturn.c: Likewise. alias gethostname. setitmr setpgrp (_S_msg_get_exec_flags, _S_msg_set_exec_flags, (abort_thread, abort_rpcs): Take same new arg and pass it through. --- elf/Makefile | 28 ++++++++++++++++---- elf/dlsym.c | 2 +- elf/linux-compat.c | 40 ++++++++++++++++++++++++++++ elf/rtld.c | 76 ++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 120 insertions(+), 26 deletions(-) create mode 100644 elf/linux-compat.c (limited to 'elf') 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 +#include + +/* 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, + "", + 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. -- cgit v1.1