diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-error.c | 13 | ||||
-rw-r--r-- | elf/dl-load.c | 38 | ||||
-rw-r--r-- | elf/dl-lookup.c | 5 | ||||
-rw-r--r-- | elf/dl-object.c | 3 | ||||
-rw-r--r-- | elf/dl-reloc.c | 9 | ||||
-rw-r--r-- | elf/dlclose.c | 2 | ||||
-rw-r--r-- | elf/dlerror.c | 57 | ||||
-rw-r--r-- | elf/dlsym.c | 2 | ||||
-rw-r--r-- | elf/do-rel.h | 68 | ||||
-rw-r--r-- | elf/dynamic-link.h | 105 | ||||
-rw-r--r-- | elf/link.h | 26 | ||||
-rw-r--r-- | elf/rtld.c | 268 |
12 files changed, 322 insertions, 274 deletions
diff --git a/elf/dl-error.c b/elf/dl-error.c index b9ee3516b5..5f8e4e4088 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -22,23 +22,28 @@ Cambridge, MA 02139, USA. */ #include <setjmp.h> static jmp_buf catch_env; -static const char *signalled_errstring; +static const char *signalled_errstring, *signalled_objname; void -_dl_signal_error (int errcode, const char *errstring) +_dl_signal_error (int errcode, + const char *objname, + const char *errstring) { signalled_errstring = errstring ?: "DYNAMIC LINKER BUG!!!"; longjmp (catch_env, errcode ?: -1); } int -_dl_catch_error (const char **errstring, void (*operate) (void)) +_dl_catch_error (const char **errstring, + const char **objname, + void (*operate) (void)) { int errcode; - signalled_errstring = NULL; + signalled_errstring = signalled_objname = NULL; errcode = setjmp (catch_env); (*operate) (); *errstring = signalled_errstring; + *objname = signalled_objname; return *errstring ? errcode : 0; } diff --git a/elf/dl-load.c b/elf/dl-load.c index 0de7404a80..f8b37ba346 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -107,10 +107,20 @@ _dl_map_object (struct link_map *loader, const char *name, Elf32_Addr *entry_point) { int fd; + struct link_map *l = NULL; char *realname; const size_t pagesize = getpagesize (); void *file_mapping = NULL; size_t mapping_size = 0; + + void lose (int code, const char *msg) + { + (void) close (fd); + if (file_mapping) + munmap (file_mapping, mapping_size); + _dl_signal_error (code, l ? l->l_name : name, msg); + } + /* Make sure LOCATION is mapped in. */ void *map (off_t location, size_t size) { @@ -124,14 +134,13 @@ _dl_map_object (struct link_map *loader, const char *name, result = mmap (file_mapping, mapping_size, PROT_READ, MAP_COPY|MAP_FILE, fd, 0); if (result == (void *) -1) - return NULL; + lose (errno, "cannot map file data"); 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) @@ -170,7 +179,7 @@ _dl_map_object (struct link_map *loader, const char *name, } if (fd == -1) - return NULL; + lose (errno, "cannot open shared object file"); /* Look again to see if the real name matched another already loaded. */ for (l = _dl_loaded; l; l = l->l_next) @@ -186,17 +195,9 @@ _dl_map_object (struct link_map *loader, const char *name, /* 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) +#define LOSE(s) lose (0, (s)) /* Check the header for basic validity. */ if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) | (ELFMAG1 << (EI_MAG1 * 8)) | @@ -224,7 +225,7 @@ _dl_map_object (struct link_map *loader, const char *name, { _dl_zerofd = _dl_sysdep_open_zero_fill (); if (_dl_zerofd == -1) - _dl_signal_error (errno, "cannot open zero fill device"); + _dl_signal_error (errno, NULL, "cannot open zero fill device"); } { @@ -235,8 +236,6 @@ _dl_map_object (struct link_map *loader, const char *name, 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; @@ -288,7 +287,8 @@ _dl_map_object (struct link_map *loader, const char *name, { /* 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, + 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. @@ -312,8 +312,7 @@ _dl_map_object (struct link_map *loader, const char *name, l->l_addr = 0; } if (mapat == (caddr_t) -1) - _dl_signal_error (errno, - "failed to map region from shared object"); + lose (errno, "failed to map segment from shared object"); if (ph->p_memsz > ph->p_filesz) { @@ -341,8 +340,7 @@ _dl_map_object (struct link_map *loader, const char *name, & ~(pagesize - 1)), pagesize, prot|PROT_WRITE) < 0) - _dl_signal_error (errno, - "cannot change protections"); + lose (errno, "cannot change memory protections"); } memset (zero, 0, zeroend - zero); if ((prot & PROT_WRITE) == 0) diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index b4600b1970..a7afcc79bb 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -27,7 +27,8 @@ Cambridge, MA 02139, USA. */ Elf32_Addr _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref, - struct link_map *symbol_scope) + struct link_map *symbol_scope, + const char *reference_name) { unsigned long int hash = elf_hash (undef_name); struct link_map *map; @@ -106,7 +107,7 @@ _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref, 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); + _dl_signal_error (0, reference_name, msg); } *ref = weak_value.s; diff --git a/elf/dl-object.c b/elf/dl-object.c index e7b1ce3f45..ca4e785be3 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -37,7 +37,8 @@ _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"); + _dl_signal_error (ENOMEM, libname, + "cannot allocate shared object descriptor"); memset (new, 0, sizeof *new); new->l_name = realname; diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 8efb3f04a6..94ffb71759 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -48,7 +48,7 @@ _dl_relocate_object (struct link_map *l, int lazy) & ~(pagesize - 1))); if (mprotect (mapstart, mapend - mapstart, PROT_READ|PROT_WRITE) < 0) - _dl_signal_error (errno, + _dl_signal_error (errno, l->l_name, "cannot make segment writable for relocation"); } } @@ -62,7 +62,8 @@ _dl_relocate_object (struct link_map *l, int lazy) Elf32_Addr resolve (const Elf32_Sym **ref) { - return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope); + return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope, + l->l_name); } real_next = l->l_next; @@ -75,7 +76,7 @@ _dl_relocate_object (struct link_map *l, int lazy) else scope = _dl_loaded; - elf_dynamic_relocate (l->l_info, l->l_addr, lazy, resolve); + ELF_DYNAMIC_RELOCATE (l, lazy, resolve); /* Restore list frobnication done above for DT_SYMBOLIC. */ l->l_next = real_next; @@ -107,7 +108,7 @@ _dl_relocate_object (struct link_map *l, int lazy) if (ph->p_flags & PF_X) prot |= PROT_EXEC; if (mprotect (mapstart, mapend - mapstart, prot) < 0) - _dl_signal_error (errno, + _dl_signal_error (errno, l->l_name, "can't restore segment prot after reloc"); } } diff --git a/elf/dlclose.c b/elf/dlclose.c index 4aa4085f66..06b2d1bdcd 100644 --- a/elf/dlclose.c +++ b/elf/dlclose.c @@ -24,7 +24,7 @@ Cambridge, MA 02139, USA. */ #include <sys/mman.h> -#define LOSE(s) _dl_signal_error (0, s) +#define LOSE(s) _dl_signal_error (0, map->l_name, s) int dlclose (void *handle) diff --git a/elf/dlerror.c b/elf/dlerror.c index 0eed60a45d..4ec5037de4 100644 --- a/elf/dlerror.c +++ b/elf/dlerror.c @@ -23,42 +23,49 @@ Cambridge, MA 02139, USA. */ #include <string.h> #include <stdlib.h> -static int _dl_last_errcode; -static const char *_dl_last_errstring; +static int last_errcode; +static const char *last_errstring; +static const char *last_object_name; char * dlerror (void) { - char *ret; + static char *buf; + char *ret; - if (! _dl_last_errstring) - return NULL; - - if (_dl_last_errcode) + if (buf) { - 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; + free (buf); + buf = NULL; } - else - ret = (char *) _dl_last_errstring; - /* Reset the error indicator. */ - _dl_last_errstring = NULL; - return ret; + if (! last_errstring) + return NULL; + + if (last_errcode == 0 && ! last_object_name) + ret = (char *) last_errstring; + else if (last_errcode == 0) + ret = (asprintf (&buf, "%s: %s", last_object_name, last_errstring) == -1 + ? NULL : buf); + else if (! last_object_name) + ret = (asprintf (&buf, "%s: %s", + last_errstring, strerror (last_errcode)) == -1 + ? NULL : buf); + else + ret = (asprintf (&buf, "%s: %s: %s", + last_object_name, last_errstring, + strerror (last_errcode)) == -1 + ? NULL : buf); + + /* Reset the error indicator. */ + 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; + last_errcode = _dl_catch_error (&last_errstring, &last_object_name, + operate); + return last_errstring != NULL; } diff --git a/elf/dlsym.c b/elf/dlsym.c index 6d8781053b..3e10812da8 100644 --- a/elf/dlsym.c +++ b/elf/dlsym.c @@ -33,7 +33,7 @@ dlsym (void *handle, const char *name) void doit (void) { const Elf32_Sym *ref = NULL; - value = _dl_lookup_symbol (name, &ref, map); + value = _dl_lookup_symbol (name, map->l_name, &ref, map); } /* Confine the symbol scope to just this map. */ diff --git a/elf/do-rel.h b/elf/do-rel.h new file mode 100644 index 0000000000..04643e8fac --- /dev/null +++ b/elf/do-rel.h @@ -0,0 +1,68 @@ +/* Do relocations for ELF 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. */ + +/* This file may be included twice, to define both + `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ + +#ifdef DO_RELA +#define elf_dynamic_do_rel elf_dynamic_do_rela +#define Elf32_Rel Elf32_Rela +#define elf_machine_rel elf_machine_rela +#endif + + +/* Perform the relocations in MAP on the running program image as specified + by RELTAG, SZTAG. *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_do_rel (struct link_map *map, + int reltag, int sztag, + Elf32_Addr (*resolve) (const Elf32_Sym **)) +{ + const Elf32_Sym *const symtab + = (const Elf32_Sym *) map->l_info[DT_SYMTAB]->d_un.d_ptr; + const Elf32_Rel *r = (const Elf32_Rel *) map->l_info[reltag]->d_un.d_ptr; + const Elf32_Rel *end = &r[map->l_info[sztag]->d_un.d_val / sizeof *r]; + + for (; r < end; ++r) + { + const Elf32_Sym *definer = &symtab[ELF32_R_SYM (r->r_info)]; + Elf32_Addr loadbase; + + if (ELF32_R_SYM (r->r_info) == STN_UNDEF) + loadbase = 0; /* This value will not be consulted. */ + else + { + if (resolve) + loadbase = (*resolve) (&definer); + else + { + assert (definer->st_shndx != SHN_UNDEF); + loadbase = map->l_addr; + } + } + elf_machine_rel (map, r, loadbase, definer); + } +} + +#undef elf_dynamic_do_rel +#undef Elf32_Rel +#undef elf_machine_rel diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index 1c3af29d6a..fc5c585356 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -18,23 +18,10 @@ 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 @@ -60,60 +47,36 @@ elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM]) 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); -} +/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. + These functions are almost identical, so we use cpp magic to avoid + duplicating their code. It cannot be done in a more general function + because we must be able to completely inline. */ + +#if ! ELF_MACHINE_NO_REL +#include "do-rel.h" +#define ELF_DYNAMIC_DO_REL(map, lazy, resolve) \ + if ((map)->l_info[DT_REL]) \ + elf_dynamic_do_rel ((map), DT_REL, DT_RELSZ, (resolve)); \ + if (!(lazy) && (map)->l_info[DT_PLTREL]->d_un.d_val == DT_REL) \ + elf_dynamic_do_rel ((map), DT_JMPREL, DT_PLTRELSZ, (resolve)); +#else +#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) /* Nothing to do. */ +#endif + +#if ! ELF_MACHINE_NO_RELA +#define DO_RELA +#include "do-rel.h" +#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) \ + if ((map)->l_info[DT_RELA]) \ + elf_dynamic_do_rela ((map), DT_RELA, DT_RELASZ, (resolve)); \ + if (!(lazy) && (map)->l_info[DT_PLTREL]->d_un.d_val == DT_RELA) \ + elf_dynamic_do_rela ((map), DT_JMPREL, DT_PLTRELSZ, (resolve); +#else +#define ELF_DYNAMIC_DO_RELA(map, lazy, resolve) /* Nothing to do. */ +#endif + +/* This can't just be an inline function because GCC is too dumb + to inline functions containing inlines themselves. */ +#define ELF_DYNAMIC_RELOCATE(map, lazy, resolve) \ + do { ELF_DYNAMIC_DO_REL ((map), (lazy), (resolve)); \ + ELF_DYNAMIC_DO_RELA ((map), (lazy), (resolve)); } while (0) diff --git a/elf/link.h b/elf/link.h index 7b999dc532..66de6d97d7 100644 --- a/elf/link.h +++ b/elf/link.h @@ -131,17 +131,23 @@ extern void _dl_sysdep_fatal (const char *string, ...) 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. */ + when they encounter an error. ERRCODE is either an `errno' code or + zero; OBJECT is the name of the problematical shared object, or null if + it is a general problem; ERRSTRING is a string describing the specific + problem. */ -extern void _dl_signal_error (int errcode, const char *errstring) +extern void _dl_signal_error (int errcode, + const char *object, + 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)); + error, *ERRSTRING is set to null. If there is an error, *ERRSTRING and + *OBJECT are set to the strings passed to _dl_signal_error, and the error + code passed is the return value. */ +extern int _dl_catch_error (const char **errstring, + const char **object, + void (*operate) (void)); /* Helper function for <dlfcn.h> functions. Runs the OPERATE function via @@ -166,10 +172,12 @@ extern void _dl_setup_hash (struct link_map *map); 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. */ + the chain used for searching. REFERENCE_NAME should name the object + containing the reference; it is used in error messages. */ extern Elf32_Addr _dl_lookup_symbol (const char *undef, const Elf32_Sym **sym, - struct link_map *symbol_scope); + struct link_map *symbol_scope, + const char *reference_name); /* List of objects currently loaded. */ diff --git a/elf/rtld.c b/elf/rtld.c index fd75779a01..0605336603 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -52,40 +52,33 @@ static void dl_main (const Elf32_Phdr *phdr, Elf32_Addr _dl_start (void *arg) { - Elf32_Addr rtld_loadaddr; - Elf32_Dyn *dynamic_section; - Elf32_Dyn *dynamic_info[DT_NUM]; + struct link_map rtld_map; /* Figure out the run-time load address of the dynamic linker itself. */ - rtld_loadaddr = elf_machine_load_address (); + rtld_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. */ - dynamic_section = (void *) rtld_loadaddr + *elf_machine_got (); - elf_get_dynamic_info (dynamic_section, dynamic_info); + rtld_map.l_ld = (void *) rtld_map.l_addr + *elf_machine_got (); + elf_get_dynamic_info (rtld_map.l_ld, rtld_map.l_info); #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC - ELF_MACHINE_BEFORE_RTLD_RELOC (dynamic_info); + ELF_MACHINE_BEFORE_RTLD_RELOC (rtld_map.l_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); - } + + ELF_DYNAMIC_RELOCATE (&rtld_map, 0, NULL); + /* 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. */ + dl_r_debug.r_ldbase = rtld_map.l_addr; /* 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 @@ -107,29 +100,30 @@ dl_main (const Elf32_Phdr *phdr, { void doit (void) { - const Elf32_Phdr *ph; - struct link_map *l; - const char *interpreter_name; - int lazy; + 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 ("\ + 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\ @@ -142,116 +136,118 @@ 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; - } + ); + + 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]) + /* 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) { - 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); + 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->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; - } + 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") ?: ""); + 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; -} + /* 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; + const char *errobj; int err; - err = _dl_catch_error (&errstring, &doit); + err = _dl_catch_error (&errstring, &errobj, &doit); if (errstring) _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>", ": error in loading shared libraries\n", + errobj ?: "", errobj ? ": " : "", errstring, err ? ": " : NULL, err ? strerror (err) : NULL, NULL); |