From 9cba52f0aedbb95671e8a14e3fd5ff98381ff2b0 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Thu, 8 Aug 2002 14:35:49 +0000 Subject: Patch from Stefan Allius and Edie C. Dost to add SuperH shared library support. This also adds some cleaner error handling, which I (Erik) then ported over to x86 and arm. In addition Stefan added the following fixes: - in hash.c was the lvalue handling of global library functions wrong. To fix this I had to change the prototype of _dl_find_hash. (==> TIS and ELF spec. Vers. 1.2) - in ldso.c was the order of the .init sections calls wrong. Before we call the initialization code of a library we have to check that all dependend libraries are already initialized. This can easily made by calling it in the revers loading order. For this I added a previous pointer chain. - in ldso.c the ELF magics wasn't checked fo PPC, MIPS and SH architecture --- ldso/ldso/Makefile | 34 ++- ldso/ldso/arm/boot1_arch.h | 2 +- ldso/ldso/arm/dl-startup.h | 2 +- ldso/ldso/arm/elfinterp.c | 468 +++++++++++++++++++++++--------------- ldso/ldso/dl-elf.c | 96 +++++--- ldso/ldso/dl-hash.c | 82 ++++--- ldso/ldso/hash.c | 82 ++++--- ldso/ldso/i386/boot1_arch.h | 2 +- ldso/ldso/i386/dl-startup.h | 2 +- ldso/ldso/i386/elfinterp.c | 494 +++++++++++++++++++++++++---------------- ldso/ldso/ld_hash.h | 26 ++- ldso/ldso/ld_string.h | 26 ++- ldso/ldso/ld_syscall.h | 10 +- ldso/ldso/ldso.c | 288 ++++++++++++++++-------- ldso/ldso/m68k/boot1_arch.h | 2 +- ldso/ldso/m68k/dl-startup.h | 2 +- ldso/ldso/m68k/elfinterp.c | 60 ++--- ldso/ldso/mips/boot1_arch.h | 2 +- ldso/ldso/mips/dl-startup.h | 2 +- ldso/ldso/mips/elfinterp.c | 69 +++--- ldso/ldso/powerpc/boot1_arch.h | 2 +- ldso/ldso/powerpc/dl-startup.h | 2 +- ldso/ldso/powerpc/elfinterp.c | 56 +++-- ldso/ldso/readelflib1.c | 96 +++++--- ldso/ldso/sh/boot1_arch.h | 23 ++ ldso/ldso/sh/dl-startup.h | 23 ++ ldso/ldso/sh/dl-syscalls.h | 7 + ldso/ldso/sh/dl-sysdep.h | 145 ++++++++++++ ldso/ldso/sh/elfinterp.c | 416 ++++++++++++++++++++++++++++++++++ ldso/ldso/sh/ld_syscalls.h | 7 + ldso/ldso/sh/ld_sysdep.h | 145 ++++++++++++ ldso/ldso/sh/resolve.S | 69 ++++++ ldso/ldso/sparc/boot1_arch.h | 2 +- ldso/ldso/sparc/dl-startup.h | 2 +- ldso/ldso/sparc/elfinterp.c | 56 +++-- 35 files changed, 2065 insertions(+), 737 deletions(-) create mode 100644 ldso/ldso/sh/boot1_arch.h create mode 100644 ldso/ldso/sh/dl-startup.h create mode 100644 ldso/ldso/sh/dl-syscalls.h create mode 100644 ldso/ldso/sh/dl-sysdep.h create mode 100644 ldso/ldso/sh/elfinterp.c create mode 100644 ldso/ldso/sh/ld_syscalls.h create mode 100644 ldso/ldso/sh/ld_sysdep.h create mode 100644 ldso/ldso/sh/resolve.S (limited to 'ldso') diff --git a/ldso/ldso/Makefile b/ldso/ldso/Makefile index 4100f82ff..ff1d9ea48 100644 --- a/ldso/ldso/Makefile +++ b/ldso/ldso/Makefile @@ -31,13 +31,35 @@ LDSO_FULLNAME=ld-uClibc-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so # (i.e. where the shared library loader does all the heavy lifting) # Since this currently only saves about 300 bytes, I'm going to leave # it enabled... -XXFLAGS+= -DDL_TRACE +XXFLAGS+= -DLD_TRACE -# Enable this to enable debugging output from ld.so -#XXFLAGS+= -DDL_DEBUG -#XXFLAGS+= -DDL_DEBUG_SYMBOLS -#Enable this to never actually fixup symbols so you can watch each call... -#XXFLAGS+= -DDL_NEVER_FIXUP_SYMBOLS +# Enable this to enable all the code needed for debugging the runtime +# linking of an application using the LD_DEBUG environment variable: +# LD_DEBUG=token1,token2,.. prog +# enables diagnostics to the stderr. +# For now there are these tokens possible: +# bindings displays the resolve processing (function calls); detail shows the relocation patch +# detail provide more information for some options +# move display copy processings +# reloc display relocation processing; detail shows the relocation patch +# symbols display symbol table processing +# +# The additional environment variable: +# LD_DEBUG_OUTPUT=file +# redirects the diagnostics to an output file created using +# the specified name and the process id as a suffix. +# +# try this +# $ LD_DEBUG=binding,move,symbols,reloc,detail LD_DEBUG_OUTPUT=appname ./appname +# +#XXFLAGS+= -DSUPPORT_LD_DEBUG + +# Enable this for the very very early debugging. Really only useful +# for people porting to new architectures. +#XXFLAGS+= -DLD_DEBUG + +# Enable this to never actually fixup symbols... +#XXFLAGS+= -DLD_NEVER_FIXUP_SYMBOLS XXFLAGS+=-DUCLIBC_TARGET_PREFIX=\"$(TARGET_PREFIX)\" \ -DUCLIBC_DEVEL_PREFIX=\"$(DEVEL_PREFIX)\" \ diff --git a/ldso/ldso/arm/boot1_arch.h b/ldso/ldso/arm/boot1_arch.h index e4c9bafb7..af9acc22c 100644 --- a/ldso/ldso/arm/boot1_arch.h +++ b/ldso/ldso/arm/boot1_arch.h @@ -20,7 +20,7 @@ _dl_boot: "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) /* It seems ARM needs an offset here */ diff --git a/ldso/ldso/arm/dl-startup.h b/ldso/ldso/arm/dl-startup.h index e4c9bafb7..af9acc22c 100644 --- a/ldso/ldso/arm/dl-startup.h +++ b/ldso/ldso/arm/dl-startup.h @@ -20,7 +20,7 @@ _dl_boot: "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) /* It seems ARM needs an offset here */ diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index 39f29d634..dd68324a5 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/ldso/ldso/arm/elfinterp.c @@ -1,39 +1,102 @@ -/* Run an ELF binary on a linux system. - - Copyright (C) 1993, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef VERBOSE_DLINKER -#define VERBOSE_DLINKER -#endif -#ifdef VERBOSE_DLINKER -static const char *_dl_reltypes[] = - { "R_ARM_NONE", "R_ARM_PC24", "R_ARM_ABS32", "R_ARM_REL32", - "R_ARM_PC13", "R_ARM_ABS16", "R_ARM_ABS12", "R_ARM_THM_ABS5", - "R_ARM_ABS8", "R_ARM_SBREL32", "R_ARM_THM_PC22", "R_ARM_THM_PC8", - "R_ARM_AMP_VCALL9", "R_ARM_SWI24", "R_ARM_THM_SWI8", "R_ARM_XPC25", - "R_ARM_THM_XPC22", "R_ARM_COPY", "R_ARM_GLOB_DAT", "R_ARM_JUMP_SLOT", - "R_ARM_RELATIVE", "R_ARM_GOTOFF", "R_ARM_GOTPC", "R_ARM_GOT32", - "R_ARM_PLT32", "R_ARM_ALU_PCREL_7_0", "R_ARM_ALU_PCREL_15_8", - "R_ARM_ALU_PCREL_23_15", "R_ARM_LDR_SBREL_11_0", "R_ARM_ALU_SBREL_19_12", - "R_ARM_ALU_SBREL_27_20", "R_ARM_GNU_VTENTRY", "R_ARM_GNU_VTINHERIT", - "R_ARM_THM_PC11", "R_ARM_THM_PC9", "R_ARM_RXPC25", "R_ARM_RSBREL32", - "R_ARM_THM_RPC22", "R_ARM_RREL32", "R_ARM_RABS22", "R_ARM_RPC24", - "R_ARM_RBASE", "R_ARM_NUM" +/* vi: set sw=4 ts=4: */ +/* ARM ELF shared library loader suppport + * + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) +static const char *_dl_reltypes_tab[] = + [0] "R_ARM_NONE", "R_ARM_PC24", "R_ARM_ABS32", "R_ARM_REL32", + [4] "R_ARM_PC13", "R_ARM_ABS16", "R_ARM_ABS12", "R_ARM_THM_ABS5", + [8] "R_ARM_ABS8", "R_ARM_SBREL32","R_ARM_THM_PC22", "R_ARM_THM_PC8", + [12] "R_ARM_AMP_VCALL9", "R_ARM_SWI24", "R_ARM_THM_SWI8", "R_ARM_XPC25", + [16] "R_ARM_THM_XPC22", + [20] "R_ARM_COPY", "R_ARM_GLOB_DAT","R_ARM_JUMP_SLOT", "R_ARM_RELATIVE", + [24] "R_ARM_GOTOFF", "R_ARM_GOTPC", "R_ARM_GOT32", "R_ARM_PLT32", + [32] "R_ARM_ALU_PCREL_7_0","R_ARM_ALU_PCREL_15_8","R_ARM_ALU_PCREL_23_15","R_ARM_LDR_SBREL_11_0", + [36] "R_ARM_ALU_SBREL_19_12","R_ARM_ALU_SBREL_27_20", + [100] "R_ARM_GNU_VTENTRY","R_ARM_GNU_VTINHERIT","R_ARM_THM_PC11","R_ARM_THM_PC9", + [249] "R_ARM_RXPC25", "R_ARM_RSBREL32", "R_ARM_THM_RPC22", "R_ARM_RREL32", + [253] "R_ARM_RABS22", "R_ARM_RPC24", "R_ARM_RBASE", }; + +static const char * +_dl_reltypes(int type) +{ + static char buf[22]; + const char *str; + + if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) || + NULL == (str = _dl_reltypes_tab[type])) + { + str =_dl_simple_ltoa( buf, (unsigned long)(type)); + } + return str; +} + +static +void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index) +{ + if(_dl_debug_symbols) + { + if(symtab_index){ + _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_value, + symtab[symtab_index].st_size, + symtab[symtab_index].st_info, + symtab[symtab_index].st_other, + symtab[symtab_index].st_shndx); + } + } +} + +static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt) +{ + if(_dl_debug_reloc) + { + int symtab_index; + const char *sym; + symtab_index = ELF32_R_SYM(rpnt->r_info); + sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0"; + +#ifdef ELF_USES_RELOCA + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + rpnt->r_addend, + sym); +#else + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + sym); +#endif + } +} #endif /* Program to load an ELF binary on a linux system, and run it. @@ -47,22 +110,21 @@ static const char *_dl_reltypes[] = a more than adequate job of explaining everything required to get this working. */ - extern int _dl_linux_resolve(void); unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { int reloc_type; - Elf32_Rel *this_reloc; + ELF_RELOC *this_reloc; char *strtab; Elf32_Sym *symtab; - Elf32_Rel *rel_addr; + ELF_RELOC *rel_addr; int symtab_index; char *new_addr; char **got_addr; unsigned long instr_addr; - rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); + rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); this_reloc = rel_addr + (reloc_entry >> 3); reloc_type = ELF32_R_TYPE(this_reloc->r_info); @@ -71,92 +133,114 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + if (reloc_type != R_ARM_JUMP_SLOT) { - _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", - _dl_progname); - _dl_exit(1); + _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", + _dl_progname); + _dl_exit(1); }; - + /* Address of jump instruction to fix up */ instr_addr = ((unsigned long) this_reloc->r_offset + - (unsigned long) tpnt->loadaddr); + (unsigned long) tpnt->loadaddr); got_addr = (char **) instr_addr; -#ifdef DL_DEBUG_SYMBOLS - _dl_dprintf(2, "Resolving symbol %s\n", - strtab + symtab[symtab_index].st_name); -#endif - /* Get the address of the GOT entry */ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, 0); + tpnt->symbol_scope, tpnt, resolver); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); _dl_exit(1); }; -#ifdef DL_NEVER_FIXUP_SYMBOLS - if ((unsigned long) got_addr < 0x40000000) { - _dl_dprintf(2, "Calling library function: %s\n", +#if defined (SUPPORT_LD_DEBUG) || defined (LD_NEVER_FIXUP_SYMBOLS) + if ((unsigned long) got_addr < 0x40000000) + { +#ifndef SUPPORT_LD_DEBUG + if (_dl_debug_bindings) + { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", strtab + symtab[symtab_index].st_name); + if(_dl_debug_detail) _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } +#endif +#ifndef LD_NEVER_FIXUP_SYMBOLS + *got_addr = new_addr; +#endif } else { - *got_addr = new_addr; + *got_addr = new_addr; } #else *got_addr = new_addr; #endif + return (unsigned long) new_addr; } -void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, - unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) { int i; char *strtab; - int reloc_type; - int symtab_index; + int goof = 0; Elf32_Sym *symtab; - Elf32_Rel *rpnt; - unsigned long *reloc_addr; - + ELF_RELOC *rpnt; + int symtab_index; /* Now parse the relocation information */ - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); - symtab = - (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + symtab_index = ELF32_R_SYM(rpnt->r_info); - + /* When the dynamic linker bootstrapped itself, it resolved some symbols. Make sure we do not do them again */ if (!symtab_index && tpnt->libtype == program_interpreter) continue; if (symtab_index && tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) + _dl_symbol(strtab + symtab[symtab_index].st_name)) continue; - switch (reloc_type) { - case R_ARM_NONE: - break; - case R_ARM_JUMP_SLOT: - *reloc_addr += (unsigned long) tpnt->loadaddr; - break; - default: - _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", - _dl_progname); -#ifdef VERBOSE_DLINKER - _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]); +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); #endif - if (symtab_index) - _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; - }; + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (SUPPORT_LD_DEBUG) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol '%s'\n"); + goof += res; + } + } + return goof; } static unsigned long @@ -183,58 +267,40 @@ fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value) return (unsigned long)fix_address; } - -int _dl_parse_relocation_information(struct elf_resolve *tpnt, - unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { - int i; - char *strtab; int reloc_type; - int goof = 0; - Elf32_Sym *symtab; - Elf32_Rel *rpnt; + int symtab_index; unsigned long *reloc_addr; unsigned long symbol_addr; - int symtab_index; - - /* Now parse the relocation information */ + int goof = 0; - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; - symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + if (symtab_index) { - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; + symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, + scope, (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), symbolrel); - if (!symtab_index && tpnt->libtype == program_interpreter) - continue; - - if (symtab_index) { - - if (tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) - continue; - - symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, - (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), 0); - - /* - * We want to allow undefined references to weak symbols - this might - * have been intentional. We should not be linking local symbols - * here, so all bases should be covered. - */ - if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - goof++; - } + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { + goof++; } + } + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif switch (reloc_type) { case R_ARM_NONE: break; @@ -286,19 +352,50 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, #endif break; default: - _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname); -#ifdef VERBOSE_DLINKER - _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]); + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + #endif - if (symtab_index) - _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; - }; return goof; } +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + unsigned long *reloc_addr; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_ARM_NONE: + break; + case R_ARM_JUMP_SLOT: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + +#endif + return 0; + +} /* This is done as a separate step, because there are cases where information is first copied and later initialized. This results in @@ -308,59 +405,60 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, /* No, there are cases where the SVr4 linker fails to emit COPY relocs at all */ - -int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, - unsigned long rel_size, int type) +static int +_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { - int i; - char *strtab; - int reloc_type; - int goof = 0; - Elf32_Sym *symtab; - Elf32_Rel *rpnt; + int reloc_type; + int symtab_index; unsigned long *reloc_addr; unsigned long symbol_addr; - struct elf_resolve *tpnt; - int symtab_index; - - /* Now parse the relocation information */ + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + if (reloc_type != R_ARM_COPY) + return 0; + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + symbol_addr = (unsigned long) _dl_find_hash(strtab + + symtab[symtab_index].st_name, scope, + NULL, copyrel); + if (!symbol_addr) goof++; + } + if (!goof) { +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_move) + _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_size, + symbol_addr, symtab[symtab_index].st_value); +#endif + _dl_memcpy((char *) symtab[symtab_index].st_value, + (char *) symbol_addr, symtab[symtab_index].st_size); + } - tpnt = xpnt->dyn; + return goof; +} - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} - symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - if (reloc_type != R_ARM_COPY) - continue; - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - if (!symtab_index && tpnt->libtype == program_interpreter) - continue; - if (symtab_index) { - - if (tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) - continue; - - symbol_addr = (unsigned long) _dl_find_hash(strtab + - symtab[symtab_index].st_name, xpnt->next, - NULL, 1); - if (!symbol_addr) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - goof++; - }; - }; - if (!goof) { - _dl_memcpy((char *) symtab[symtab_index].st_value, - (char *) symbol_addr, symtab[symtab_index].st_size); - } - }; - return goof; +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) +{ + return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy); } + diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index c5e7607e0..8c2314184 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -1,21 +1,34 @@ -/* Load an ELF sharable library into memory. - - Copyright (C) 1993-1996, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +/* vi: set sw=4 ts=4: */ +/* Program to load an ELF binary on a linux system, and run it + * after resolving ELF shared library symbols + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* This file contains the helper routines to load an ELF sharable @@ -180,8 +193,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, pnt++; } -#ifdef DL_DEBUG - _dl_dprintf(2, "searching for library: '%s'\n", libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname); #endif /* If the filename has any '/', try it straight and leave it at that. For IBCS2 compatibility under linux, we substitute the string @@ -204,8 +217,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, if (pnt) { pnt += (unsigned long) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB]; -#ifdef DL_DEBUG - _dl_dprintf(2, "searching RPATH: '%s'\n", pnt); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching RPATH: '%s'\n", pnt); #endif if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL) { @@ -217,8 +230,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ if (_dl_library_path) { -#ifdef DL_DEBUG - _dl_dprintf(2, "searching _dl_library_path: '%s'\n", _dl_library_path); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching _dl_library_path: '%s'\n", _dl_library_path); #endif if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL) { @@ -251,8 +264,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Look for libraries wherever the shared library loader * was installed */ -#ifdef DL_DEBUG - _dl_dprintf(2, "searching in ldso dir: %s\n", _dl_ldsopath); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching in ldso dir: %s\n", _dl_ldsopath); #endif if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL) { @@ -262,8 +275,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Lastly, search the standard list of paths for the library. This list must exactly match the list in uClibc/ldso/util/ldd.c */ -#ifdef DL_DEBUG - _dl_dprintf(2, "searching full lib path list\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching full lib path list\n"); #endif if ((tpnt1 = search_for_named_library(libname, secure, UCLIBC_TARGET_PREFIX "/usr/lib:" @@ -282,8 +295,8 @@ goof: if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number; else - _dl_error_number = DL_ERROR_NOFILE; -#ifdef DL_DEBUG + _dl_error_number = LD_ERROR_NOFILE; +#ifdef LD_DEBUG _dl_dprintf(2, "Bummer: could not find '%s'!\n", libname); #endif return NULL; @@ -323,6 +336,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + (*rpnt)->next->prev = (*rpnt); *rpnt = (*rpnt)->next; (*rpnt)->dyn = tpnt; tpnt->symbol_scope = _dl_symbol_tables; @@ -352,7 +366,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, */ _dl_dprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); #endif - _dl_internal_error_number = DL_ERROR_NOFILE; + _dl_internal_error_number = LD_ERROR_NOFILE; return NULL; } @@ -365,7 +379,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, { _dl_dprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_NOTELF; + _dl_internal_error_number = LD_ERROR_NOTELF; _dl_close(infile); return NULL; }; @@ -377,7 +391,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, )) { _dl_internal_error_number = - (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); + (epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC); _dl_dprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n", _dl_progname, libname); _dl_close(infile); @@ -424,7 +438,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map %s\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_close(infile); return NULL; }; @@ -457,7 +471,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); return NULL; @@ -488,7 +502,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, infile, ppnt->p_offset & OFFS_ALIGN); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); return NULL; @@ -516,7 +530,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, /* Start by scanning the dynamic section to get all of the pointers */ if (!dynamic_addr) { - _dl_internal_error_number = DL_ERROR_NODYNAMIC; + _dl_internal_error_number = LD_ERROR_NODYNAMIC; _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); return NULL; @@ -580,6 +594,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + (*rpnt)->next->prev = (*rpnt); *rpnt = (*rpnt)->next; (*rpnt)->dyn = tpnt; tpnt->symbol_scope = _dl_symbol_tables; @@ -626,6 +641,10 @@ int _dl_copy_fixups(struct dyn_elf *rpnt) return goof; tpnt->init_flag |= COPY_RELOCS_DONE; +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s", tpnt->libname); +#endif + #ifdef ELF_USES_RELOCA goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); @@ -635,5 +654,8 @@ int _dl_copy_fixups(struct dyn_elf *rpnt) tpnt->dynamic_info[DT_RELSZ], 0); #endif +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s; finished\n\n", tpnt->libname); +#endif return goof; } diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index b063d0b79..5711bebaa 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -1,21 +1,34 @@ -/* Run an ELF binary on a linux system. - - Copyright (C) 1993-1996, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +/* vi: set sw=4 ts=4: */ +/* Program to load an ELF binary on a linux system, and run it + * after resolving ELF shared library symbols + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* Various symbol table handling functions, including symbol lookup */ @@ -150,7 +163,7 @@ struct elf_resolve *_dl_add_elf_hash_table(char *libname, */ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, - struct elf_resolve *f_tpnt, int copyrel) + struct elf_resolve *f_tpnt, enum caller_type caller_type) { struct elf_resolve *tpnt; int si; @@ -172,7 +185,7 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, that any shared library data symbols referenced in the executable will be seen at the same address by the executable, shared libraries and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */ - if (!copyrel && rpnt1) { + if (copyrel!=caller_type && rpnt1) { first = (*_dl_symbol_tables); first.next = rpnt1; rpnt1 = (&first); @@ -247,11 +260,12 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, pnt = strtab + symtab[si].st_name; if (_dl_strcmp(pnt, name) == 0 && - (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC || - ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE || - ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) && - symtab[si].st_value != 0 && - symtab[si].st_shndx != 0) { + symtab[si].st_value != 0) + { + if ((ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC || + ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE || + ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) && + symtab[si].st_shndx != SHN_UNDEF) { /* Here we make sure that we find a module where the symbol is * actually defined. @@ -284,6 +298,24 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, default: /* Do local symbols need to be examined? */ break; } + } + /* + * References to the address of a function from an executable file and + * the shared objects associated with it might not resolve to the same + * value. To allow comparisons of function addresses we must resolve + * to the address of the plt entry of the executable instead of the + * real function address. + * see "TIS ELF Specification Version 1.2, Book 3, A-11 (Function + * Adresses) + */ + if (resolver != caller_type && + NULL==f_tpnt && /*trick: don't handle R_??_JMP_SLOT reloc type*/ + tpnt->libtype == elf_executable && + ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC && + symtab[si].st_shndx == SHN_UNDEF) + { + return (char*)symtab[si].st_value; + } } } } diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c index b063d0b79..5711bebaa 100644 --- a/ldso/ldso/hash.c +++ b/ldso/ldso/hash.c @@ -1,21 +1,34 @@ -/* Run an ELF binary on a linux system. - - Copyright (C) 1993-1996, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +/* vi: set sw=4 ts=4: */ +/* Program to load an ELF binary on a linux system, and run it + * after resolving ELF shared library symbols + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* Various symbol table handling functions, including symbol lookup */ @@ -150,7 +163,7 @@ struct elf_resolve *_dl_add_elf_hash_table(char *libname, */ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, - struct elf_resolve *f_tpnt, int copyrel) + struct elf_resolve *f_tpnt, enum caller_type caller_type) { struct elf_resolve *tpnt; int si; @@ -172,7 +185,7 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, that any shared library data symbols referenced in the executable will be seen at the same address by the executable, shared libraries and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */ - if (!copyrel && rpnt1) { + if (copyrel!=caller_type && rpnt1) { first = (*_dl_symbol_tables); first.next = rpnt1; rpnt1 = (&first); @@ -247,11 +260,12 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, pnt = strtab + symtab[si].st_name; if (_dl_strcmp(pnt, name) == 0 && - (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC || - ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE || - ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) && - symtab[si].st_value != 0 && - symtab[si].st_shndx != 0) { + symtab[si].st_value != 0) + { + if ((ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC || + ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE || + ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) && + symtab[si].st_shndx != SHN_UNDEF) { /* Here we make sure that we find a module where the symbol is * actually defined. @@ -284,6 +298,24 @@ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, default: /* Do local symbols need to be examined? */ break; } + } + /* + * References to the address of a function from an executable file and + * the shared objects associated with it might not resolve to the same + * value. To allow comparisons of function addresses we must resolve + * to the address of the plt entry of the executable instead of the + * real function address. + * see "TIS ELF Specification Version 1.2, Book 3, A-11 (Function + * Adresses) + */ + if (resolver != caller_type && + NULL==f_tpnt && /*trick: don't handle R_??_JMP_SLOT reloc type*/ + tpnt->libtype == elf_executable && + ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC && + symtab[si].st_shndx == SHN_UNDEF) + { + return (char*)symtab[si].st_value; + } } } } diff --git a/ldso/ldso/i386/boot1_arch.h b/ldso/ldso/i386/boot1_arch.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/i386/boot1_arch.h +++ b/ldso/ldso/i386/boot1_arch.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/i386/dl-startup.h b/ldso/ldso/i386/dl-startup.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/i386/dl-startup.h +++ b/ldso/ldso/i386/dl-startup.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index 3c9979e49..4bfa349e8 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/ldso/ldso/i386/elfinterp.c @@ -1,31 +1,96 @@ -/* Run an ELF binary on a linux system. - - Copyright (C) 1993, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef VERBOSE_DLINKER -#define VERBOSE_DLINKER -#endif -#ifdef VERBOSE_DLINKER -static const char *_dl_reltypes[] = - { "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32", - "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", - "R_386_JMP_SLOT", "R_386_RELATIVE", "R_386_GOTOFF", - "R_386_GOTPC", "R_386_NUM" +/* vi: set sw=4 ts=4: */ +/* i386 ELF shared library loader suppport + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) +static const char *_dl_reltypes_tab[] = +{ + [0] "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32", + [4] "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT", + [8] "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC", }; + +static const char * +_dl_reltypes(int type) +{ + static char buf[22]; + const char *str; + + if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) || + NULL == (str = _dl_reltypes_tab[type])) + { + str =_dl_simple_ltoa( buf, (unsigned long)(type)); + } + return str; +} + +static +void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index) +{ + if(_dl_debug_symbols) + { + if(symtab_index){ + _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_value, + symtab[symtab_index].st_size, + symtab[symtab_index].st_info, + symtab[symtab_index].st_other, + symtab[symtab_index].st_shndx); + } + } +} + +static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt) +{ + if(_dl_debug_reloc) + { + int symtab_index; + const char *sym; + symtab_index = ELF32_R_SYM(rpnt->r_info); + sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0"; + +#ifdef ELF_USES_RELOCA + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + rpnt->r_addend, + sym); +#else + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + sym); +#endif + } +} #endif /* Program to load an ELF binary on a linux system, and run it. @@ -44,16 +109,16 @@ extern int _dl_linux_resolve(void); unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { int reloc_type; - Elf32_Rel *this_reloc; + ELF_RELOC *this_reloc; char *strtab; Elf32_Sym *symtab; - Elf32_Rel *rel_addr; + ELF_RELOC *rel_addr; int symtab_index; char *new_addr; char **got_addr; unsigned long instr_addr; - rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); + rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); this_reloc = rel_addr + (reloc_entry >> 3); reloc_type = ELF32_R_TYPE(this_reloc->r_info); @@ -74,175 +139,211 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) (unsigned long) tpnt->loadaddr); got_addr = (char **) instr_addr; -#ifdef DL_DEBUG_SYMBOLS - _dl_dprintf(2, "Resolving symbol %s\n", - strtab + symtab[symtab_index].st_name); -#endif - /* Get the address of the GOT entry */ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, 0); + tpnt->symbol_scope, tpnt, resolver); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); _dl_exit(1); }; -#ifdef DL_NEVER_FIXUP_SYMBOLS - if ((unsigned long) got_addr < 0x40000000) { - _dl_dprintf(2, "Calling library function: %s\n", +#if defined (SUPPORT_LD_DEBUG) || defined (LD_NEVER_FIXUP_SYMBOLS) + if ((unsigned long) got_addr < 0x40000000) + { +#ifndef SUPPORT_LD_DEBUG + if (_dl_debug_bindings) + { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", strtab + symtab[symtab_index].st_name); + if(_dl_debug_detail) _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } +#endif +#ifndef LD_NEVER_FIXUP_SYMBOLS + *got_addr = new_addr; +#endif } else { - *got_addr = new_addr; + *got_addr = new_addr; } #else *got_addr = new_addr; #endif + return (unsigned long) new_addr; } -void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, - unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) { int i; char *strtab; - int reloc_type; - int symtab_index; + int goof = 0; Elf32_Sym *symtab; - Elf32_Rel *rpnt; - unsigned long *reloc_addr; - + ELF_RELOC *rpnt; + int symtab_index; /* Now parse the relocation information */ - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); - symtab = - (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + symtab_index = ELF32_R_SYM(rpnt->r_info); - + /* When the dynamic linker bootstrapped itself, it resolved some symbols. Make sure we do not do them again */ if (!symtab_index && tpnt->libtype == program_interpreter) continue; if (symtab_index && tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) + _dl_symbol(strtab + symtab[symtab_index].st_name)) continue; - switch (reloc_type) { - case R_386_NONE: - break; - case R_386_JMP_SLOT: - *reloc_addr += (unsigned long) tpnt->loadaddr; - break; - default: - _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ", - _dl_progname); -#ifdef VERBOSE_DLINKER - _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]); +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); #endif - if (symtab_index) - _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; - }; + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (SUPPORT_LD_DEBUG) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol '%s'\n"); + goof += res; + } + } + return goof; } -int _dl_parse_relocation_information(struct elf_resolve *tpnt, - unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { - int i; - char *strtab; int reloc_type; - int goof = 0; - Elf32_Sym *symtab; - Elf32_Rel *rpnt; + int symtab_index; unsigned long *reloc_addr; unsigned long symbol_addr; - int symtab_index; - - /* Now parse the relocation information */ - - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); + int goof = 0; - symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; + if (symtab_index) { - if (!symtab_index && tpnt->libtype == program_interpreter) - continue; + symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, + scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel); - if (symtab_index) { - - if (tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) - continue; - - symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, - (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0); - - /* - * We want to allow undefined references to weak symbols - this might - * have been intentional. We should not be linking local symbols - * here, so all bases should be covered. - */ - if (!symbol_addr && - ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - goof++; - } + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { + goof++; } + } + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif switch (reloc_type) { - case R_386_NONE: - break; - case R_386_32: - *reloc_addr += symbol_addr; - break; - case R_386_PC32: - *reloc_addr += symbol_addr - (unsigned long) reloc_addr; - break; - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - *reloc_addr = symbol_addr; - break; - case R_386_RELATIVE: - *reloc_addr += (unsigned long) tpnt->loadaddr; - break; - case R_386_COPY: -#if 0 - /* Do this later */ - _dl_dprintf(2, "Doing copy for symbol "); - if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name); - _dl_dprintf(2, "\n"); - _dl_memcpy((void *) symtab[symtab_index].st_value, - (void *) symbol_addr, symtab[symtab_index].st_size); + case R_386_NONE: + break; + case R_386_32: + *reloc_addr += symbol_addr; + break; + case R_386_PC32: + *reloc_addr += symbol_addr - (unsigned long) reloc_addr; + break; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_386_RELATIVE: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + case R_386_COPY: +#if 0 + /* Do this later */ + _dl_dprintf(2, "Doing copy for symbol "); + if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name); + _dl_dprintf(2, "\n"); + _dl_memcpy((void *) symtab[symtab_index].st_value, + (void *) symbol_addr, symtab[symtab_index].st_size); #endif - break; - default: - _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname); -#ifdef VERBOSE_DLINKER - _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]); + break; + + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + #endif - if (symtab_index) - _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; - }; return goof; } +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + unsigned long *reloc_addr; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_386_NONE: + break; + case R_386_JMP_SLOT: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + +#endif + return 0; + +} /* This is done as a separate step, because there are cases where information is first copied and later initialized. This results in @@ -252,59 +353,60 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, /* No, there are cases where the SVr4 linker fails to emit COPY relocs at all */ - -int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, - unsigned long rel_size, int type) +static int +_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { - int i; - char *strtab; - int reloc_type; - int goof = 0; - Elf32_Sym *symtab; - Elf32_Rel *rpnt; + int reloc_type; + int symtab_index; unsigned long *reloc_addr; unsigned long symbol_addr; - struct elf_resolve *tpnt; - int symtab_index; - - /* Now parse the relocation information */ + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + if (reloc_type != R_386_COPY) + return 0; + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + symbol_addr = (unsigned long) _dl_find_hash(strtab + + symtab[symtab_index].st_name, scope, + NULL, copyrel); + if (!symbol_addr) goof++; + } + if (!goof) { +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_move) + _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_size, + symbol_addr, symtab[symtab_index].st_value); +#endif + _dl_memcpy((char *) symtab[symtab_index].st_value, + (char *) symbol_addr, symtab[symtab_index].st_size); + } - tpnt = xpnt->dyn; + return goof; +} - rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(Elf32_Rel); +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} - symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - if (reloc_type != R_386_COPY) - continue; - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - if (!symtab_index && tpnt->libtype == program_interpreter) - continue; - if (symtab_index) { - - if (tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) - continue; - - symbol_addr = (unsigned long) _dl_find_hash(strtab + - symtab[symtab_index].st_name, xpnt->next, - NULL, 1); - if (!symbol_addr) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - goof++; - }; - }; - if (!goof) { - _dl_memcpy((char *) symtab[symtab_index].st_value, - (char *) symbol_addr, symtab[symtab_index].st_size); - } - }; - return goof; +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) +{ + return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy); } + diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h index 639ae4510..b19d680a2 100644 --- a/ldso/ldso/ld_hash.h +++ b/ldso/ldso/ld_hash.h @@ -43,6 +43,7 @@ struct dyn_elf{ struct elf_resolve * dyn; struct dyn_elf * next_handle; /* Used by dlopen et al. */ struct dyn_elf * next; + struct dyn_elf * prev; }; struct elf_resolve{ @@ -113,8 +114,11 @@ extern struct elf_resolve * _dl_check_hashed_files(char * libname); extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, char * loadaddr, unsigned long * dynamic_info, unsigned long dynamic_addr, unsigned long dynamic_size); + +enum caller_type{symbolrel=0,copyrel=1,resolver=2}; extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, - struct elf_resolve * f_tpnt, int copyrel); + struct elf_resolve * f_tpnt, enum caller_type); + extern int _dl_linux_dynamic_link(void); extern char * _dl_library_path; @@ -129,16 +133,16 @@ static inline int _dl_symbol(char * name) } -#define DL_ERROR_NOFILE 1 -#define DL_ERROR_NOZERO 2 -#define DL_ERROR_NOTELF 3 -#define DL_ERROR_NOTMAGIC 4 -#define DL_ERROR_NOTDYN 5 -#define DL_ERROR_MMAP_FAILED 6 -#define DL_ERROR_NODYNAMIC 7 -#define DL_WRONG_RELOCS 8 -#define DL_BAD_HANDLE 9 -#define DL_NO_SYMBOL 10 +#define LD_ERROR_NOFILE 1 +#define LD_ERROR_NOZERO 2 +#define LD_ERROR_NOTELF 3 +#define LD_ERROR_NOTMAGIC 4 +#define LD_ERROR_NOTDYN 5 +#define LD_ERROR_MMAP_FAILED 6 +#define LD_ERROR_NODYNAMIC 7 +#define LD_WRONG_RELOCS 8 +#define LD_BAD_HANDLE 9 +#define LD_NO_SYMBOL 10 diff --git a/ldso/ldso/ld_string.h b/ldso/ldso/ld_string.h index e2b1f28c3..1de9f8d76 100644 --- a/ldso/ldso/ld_string.h +++ b/ldso/ldso/ld_string.h @@ -17,6 +17,7 @@ static int _dl_strcmp(const char * s1,const char * s2); static int _dl_strncmp(const char * s1,const char * s2,size_t len); static char * _dl_strchr(const char * str,int c); static char *_dl_strrchr(const char *str, int c); +static char *_dl_strstr(const char *s1, const char *s2); static void * _dl_memcpy(void * dst, const void * src, size_t len); static int _dl_memcmp(const void * s1,const void * s2,size_t len); static void *_dl_memset(void * str,int c,size_t len); @@ -122,6 +123,29 @@ static inline char *_dl_strrchr(const char *str, int c) return(prev); } + +static inline char *_dl_strstr(const char *s1, const char *s2) +{ + register const char *s = s1; + register const char *p = s2; + + do { + if (!*p) { + return (char *) s1;; + } + if (*p == *s) { + ++p; + ++s; + } else { + p = s2; + if (!*s) { + return NULL; + } + s = ++s1; + } + } while (1); +} + static inline void * _dl_memcpy(void * dst, const void * src, size_t len) { register char *a = dst; @@ -221,7 +245,7 @@ static inline char *_dl_simple_ltoahex(char * local, unsigned long i) } -#if defined mc68000 || defined __arm__ || defined __mips__ +#if defined mc68000 || defined __arm__ || defined __mips__ || defined __sh__ /* On some arches constant strings are referenced through the GOT. */ /* XXX Requires load_addr to be defined. */ #define SEND_STDERR(X) \ diff --git a/ldso/ldso/ld_syscall.h b/ldso/ldso/ld_syscall.h index 386756d05..94048cdbd 100644 --- a/ldso/ldso/ld_syscall.h +++ b/ldso/ldso/ld_syscall.h @@ -51,8 +51,8 @@ static inline _syscall1(void, _dl_exit, int, status); static inline _syscall1(int, _dl_close, int, fd); -#if defined(__powerpc) || defined(__mips__) -/* PowerPC and MIPS have a different calling convention for mmap(). */ +#if defined(__powerpc) || defined(__mips__) || defined(__sh__) +/* PowerPC, MIPS and SuperH have a different calling convention for mmap(). */ #define __NR__dl_mmap __NR_mmap static inline _syscall6(void *, _dl_mmap, void *, start, size_t, length, int, prot, int, flags, int, fd, off_t, offset); @@ -91,6 +91,9 @@ static inline void * _dl_mmap(void * addr, unsigned long size, int prot, #define __NR__dl_open __NR_open #define O_RDONLY 0x0000 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ static inline _syscall2(int, _dl_open, const char *, fn, int, flags); #define __NR__dl_write __NR_write @@ -126,6 +129,9 @@ static inline _syscall0(gid_t, _dl_getgid); #define __NR__dl_getegid __NR_getegid static inline _syscall0(gid_t, _dl_getegid); +#define __NR__dl_getpid __NR_getpid +static inline _syscall0(gid_t, _dl_getpid); + /* * Not an actual syscall, but we need something in assembly to say whether * this is OK or not. diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index ce0b86406..9c94e7e97 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -1,23 +1,33 @@ /* vi: set sw=4 ts=4: */ /* Program to load an ELF binary on a linux system, and run it * after resolving ELF shared library symbols - * - * Copyright (C) 1993-1996, Eric Youngdale. + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza * Copyright (C) 2001-2002, Erik Andersen * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ /* Enable mprotect protection munging. ARM and MIPS Linux needs this @@ -27,21 +37,6 @@ // Support a list of library preloads in /etc/ld.so.preload //#define SUPPORT_LDSO_PRELOAD_FILE -/* Enable ldd library tracing. Just set LD_TRACE_LOADED_OBJECTS=1 in - * the environment and run the app to do the ldd thing. With this - * enabled you can make a simple /usr/bin/ldd shell script as: - * #!/bin/sh - * LD_TRACE_LOADED_OBJECTS=1 $1 - * so you can do stuff like: - * $ ldd ./appname - * libc.so.0 => /lib/libc.so.0 (0x0x40006000) - * ld-uClibc.so.0 => /home/andersen/CVS/uClibc/lib/ld-uClibc.so.0 (0x0x40000000) - * This is off by default since it doesn't work when cross compiling, - * so uClibc provides an ELF header reading ldd instead... - */ -//#define DL_TRACE - - /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have I ever taken any courses on internals. This program was developed using @@ -113,6 +108,12 @@ * housekeeping chores and we can transfer control to the user's * application. */ +#ifdef LD_DEBUG_SYMBOLS +#ifdef SUPPORT_LD_DEBUG +#undef SUPPORT_LD_DEBUG +#endif +#define SUPPORT_LD_DEBUG +#endif #include "ld_syscall.h" #include "linuxelf.h" @@ -127,11 +128,11 @@ #define ELFMAGIC ELFMAG /* This is a poor man's malloc, used prior to resolving our internal poor man's malloc */ -#define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ; REALIGN(); +#define LD_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ; REALIGN(); /* * Make sure that the malloc buffer is aligned on 4 byte boundary. For 64 bit * platforms we may need to increase this to 8, but this is good enough for - * now. This is typically called after DL_MALLOC. + * now. This is typically called after LD_MALLOC. */ #define REALIGN() malloc_buffer = (char *) (((unsigned long) malloc_buffer + 3) & ~(3)) @@ -139,6 +140,17 @@ char *_dl_library_path = 0; /* Where we look for libraries */ char *_dl_preload = 0; /* Things to be loaded before the libs. */ char *_dl_ldsopath = 0; static char *_dl_not_lazy = 0; +#ifdef SUPPORT_LD_DEBUG +static char *_dl_debug = 0; +static char *_dl_debug_symbols = 0; +static char *_dl_debug_move = 0; +static char *_dl_debug_reloc = 0; +static char *_dl_debug_detail = 0; +static char *_dl_debug_bindings = 0; +static int _dl_debug_file = 2; +#else +#define _dl_debug_file 2 +#endif static char *_dl_malloc_addr, *_dl_mmap_zero; static char *_dl_trace_loaded_objects = 0; @@ -171,7 +183,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a auxvt[0...N] Auxiliary Vector Table elements (mixed types) */ -#ifdef DL_DEBUG +#ifdef LD_DEBUG /* Debugging is especially tricky on PowerPC, since string literals * require relocations. Thus, you can't use _dl_dprintf() for * anything until the bootstrap relocations are finished. */ @@ -192,7 +204,7 @@ static inline void hexprint(unsigned long x) } #endif -DL_BOOT(unsigned long args) +LD_BOOT(unsigned long args) { unsigned int argc; char **argv, **envp; @@ -257,14 +269,19 @@ DL_BOOT(unsigned long args) /* Check the ELF header to make sure everything looks ok. */ if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 || header->e_ident[EI_VERSION] != EV_CURRENT -#if !defined(__powerpc__) && !defined(__mips__) +#if !defined(__powerpc__) && !defined(__mips__) && !defined(__sh__) || _dl_strncmp((void *) header, ELFMAGIC, SELFMAG) != 0 +#else + || header->e_ident[EI_MAG0] != ELFMAG0 + || header->e_ident[EI_MAG1] != ELFMAG1 + || header->e_ident[EI_MAG2] != ELFMAG2 + || header->e_ident[EI_MAG3] != ELFMAG3 #endif ) { SEND_STDERR("Invalid ELF header\n"); _dl_exit(0); } -#ifdef DL_DEBUG +#ifdef LD_DEBUG SEND_STDERR("ELF header="); SEND_ADDRESS_STDERR(load_addr, 1); #endif @@ -286,6 +303,16 @@ DL_BOOT(unsigned long args) __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4@local\n\t":"=l"(got)); #elif defined(__mips__) __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got)); +#elif defined(__sh__) + __asm__(" + mov.l 1f, %0 + mova 1f, r0 + bra 2f + add r0, %0 + .balign 4 +1: .long _GLOBAL_OFFSET_TABLE_ +2: +" : "=r" (got) : : "r0"); #else /* Do things the slow way in C */ { @@ -294,7 +321,7 @@ DL_BOOT(unsigned long args) Elf32_Shdr *shdr; Elf32_Phdr *pt_load; -#ifdef DL_DEBUG +#ifdef LD_DEBUG SEND_STDERR("Finding the GOT using C code to read the ELF file\n"); #endif /* Find where the dynamic linking information section is hiding */ @@ -339,7 +366,7 @@ DL_BOOT(unsigned long args) /* Now, finally, fix up the location of the dynamic stuff */ dpnt = (Elf32_Dyn *) (*got + load_addr); -#ifdef DL_DEBUG +#ifdef LD_DEBUG SEND_STDERR("First Dynamic section entry="); SEND_ADDRESS_STDERR(dpnt, 1); #endif @@ -354,15 +381,15 @@ DL_BOOT(unsigned long args) _dl_exit(13); } - tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + tpnt = LD_MALLOC(sizeof(struct elf_resolve)); _dl_memset(tpnt, 0, sizeof(*tpnt)); - app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + app_tpnt = LD_MALLOC(sizeof(struct elf_resolve)); _dl_memset(app_tpnt, 0, sizeof(*app_tpnt)); /* * This is used by gdb to locate the chain of shared libraries that are currently loaded. */ - debug_addr = DL_MALLOC(sizeof(struct r_debug)); + debug_addr = LD_MALLOC(sizeof(struct r_debug)); _dl_memset(debug_addr, 0, sizeof(*debug_addr)); /* OK, that was easy. Next scan the DYNAMIC section of the image. @@ -483,7 +510,7 @@ DL_BOOT(unsigned long args) /* OK, now do the relocations. We do not do a lazy binding here, so that once we are done, we have considerably more flexibility. */ -#ifdef DL_DEBUG +#ifdef LD_DEBUG SEND_STDERR("About to do library loader relocations.\n"); #endif @@ -541,7 +568,7 @@ DL_BOOT(unsigned long args) SEND_STDERR(" undefined.\n"); goof++; } -#ifdef DL_DEBUG_SYMBOLS +#ifdef LD_DEBUG_SYMBOLS SEND_STDERR("About to fixup symbol: "); SEND_STDERR(strtab + symtab[symtab_index].st_name); SEND_STDERR("\n"); @@ -557,9 +584,9 @@ DL_BOOT(unsigned long args) if (goof) { _dl_exit(14); } -#ifdef DL_DEBUG +#ifdef LD_DEBUG /* Wahoo!!! */ - _dl_dprintf(2, "Done relocating library loader, so we can now\n\tuse globals and make function calls!\n"); + _dl_dprintf(_dl_debug_file, "Done relocating library loader, so we can now\n\tuse globals and make function calls!\n"); #endif if (argv[0]) { @@ -594,9 +621,12 @@ DL_BOOT(unsigned long args) * Transfer control to the application. */ status = 0; /* Used on x86, but not on other arches */ -#ifdef DL_DEBUG - _dl_dprintf(2, "Calling application main()\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Calling application main()\n"); #endif +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ntransfering control: %s\n\n", _dl_progname); +#endif START(); } @@ -628,8 +658,8 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a tpnt->loadaddr = (char *) load_addr; INIT_GOT(lpnt, tpnt); -#ifdef DL_DEBUG - _dl_dprintf(2, "GOT found at %x\n", tpnt); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "GOT found at %x\n", lpnt); #endif /* OK, this was a big step, now we need to scan all of the user images and load them properly. */ @@ -728,8 +758,8 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a if (readsize > 0 && readsize < sizeof(buf)-1) { pnt1 = _dl_strrchr(buf, '/'); if (pnt1 && buf != pnt1) { -#ifdef DL_DEBUG - _dl_dprintf(2, "changing tpnt->libname from '%s' to '%s'\n", tpnt->libname, buf); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "changing tpnt->libname from '%s' to '%s'\n", tpnt->libname, buf); #endif tpnt->libname = _dl_strdup(buf); } @@ -745,8 +775,8 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } else { _dl_ldsopath = tpnt->libname; } -#ifdef DL_DEBUG - _dl_dprintf(2, "Lib Loader:\t(%x) %s\n", tpnt->loadaddr, tpnt->libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Lib Loader:\t(%x) %s\n", tpnt->loadaddr, tpnt->libname); #endif } } @@ -774,10 +804,56 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } } +#ifdef SUPPORT_LD_DEBUG + _dl_debug = _dl_getenv("LD_DEBUG", envp); + if (_dl_debug) + { + _dl_debug_detail = _dl_strstr(_dl_debug, "detail"); + _dl_debug_move = _dl_strstr(_dl_debug, "move"); + _dl_debug_symbols = _dl_strstr(_dl_debug, "sym"); + _dl_debug_reloc = _dl_strstr(_dl_debug, "reloc"); + _dl_debug_bindings = _dl_strstr(_dl_debug, "bind"); + } + { + const char *dl_debug_output; + + dl_debug_output = _dl_getenv("LD_DEBUG_OUTPUT", envp); + + if (dl_debug_output) + { + char tmp[22], *tmp1, *filename; + int len1, len2; + + _dl_memset(tmp, 0, sizeof(tmp)); + tmp1=_dl_simple_ltoa( tmp, (unsigned long)_dl_getpid()); + + len1 = _dl_strlen(dl_debug_output); + len2 = _dl_strlen(tmp1); + + filename = _dl_malloc(len1+len2+2); + + if (filename) + { + _dl_strcpy (filename, dl_debug_output); + filename[len1] = '.'; + _dl_strcpy (&filename[len1+1], tmp1); + + _dl_debug_file= _dl_open (filename, O_WRONLY|O_CREAT); + if (_dl_debug_file<0) + { + _dl_debug_file = 2; + _dl_dprintf (2, "can't open file: '%s'\n",filename); + } + } + } + } + + +#endif _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); -#ifndef DL_TRACE +#ifndef LD_TRACE if (_dl_trace_loaded_objects) { - _dl_dprintf(2, "Use the ldd provided by uClibc\n"); + _dl_dprintf(_dl_debug_file, "Use the ldd provided by uClibc\n"); _dl_exit(1); } #endif @@ -809,7 +885,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a { tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str); if (!tpnt1) { -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects) _dl_dprintf(1, "\t%s => not found\n", str); else { @@ -817,14 +893,14 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_dprintf(2, "%s: can't load " "library '%s'\n", _dl_progname, str); _dl_exit(15); -#ifdef DL_TRACE +#ifdef LD_TRACE } #endif } else { -#ifdef DL_DEBUG - _dl_dprintf(2, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); #endif -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects && tpnt1->usage_count==1) { /* this is a real hack to make ldd not print @@ -888,7 +964,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2); if (!tpnt1) { -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects) _dl_dprintf(1, "\t%s => not found\n", cp2); else { @@ -896,14 +972,14 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, cp2); _dl_exit(15); -#ifdef DL_TRACE +#ifdef LD_TRACE } #endif } else { -#ifdef DL_DEBUG - _dl_dprintf(2, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); #endif -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects && tpnt1->usage_count==1) { _dl_dprintf(1, "\t%s => %s (0x%x)\n", cp2, @@ -939,7 +1015,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a if (tpnt && _dl_strcmp(lpntstr, _dl_get_last_path_component(tpnt->libname)) == 0) { struct elf_resolve *ttmp; -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects && tpnt->usage_count==1) { _dl_dprintf(1, "\t%s => %s (0x%x)\n", lpntstr, tpnt->libname, (unsigned) tpnt->loadaddr); @@ -954,6 +1030,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt->next->prev = rpnt; rpnt = rpnt->next; rpnt->dyn = tpnt; tpnt->usage_count++; @@ -963,7 +1040,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) { -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects) _dl_dprintf(1, "\t%s => not found\n", lpntstr); else { @@ -971,14 +1048,14 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, lpntstr); _dl_exit(16); -#ifdef DL_TRACE +#ifdef LD_TRACE } #endif } else { -#ifdef DL_DEBUG - _dl_dprintf(2, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); #endif -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects && tpnt1->usage_count==1) _dl_dprintf(1, "\t%s => %s (0x%x)\n", lpntstr, tpnt1->libname, (unsigned) tpnt1->loadaddr); @@ -993,7 +1070,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_unmap_cache(); #endif /* ldd uses uses this. I am not sure how you pick up the other flags */ -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects) { char *_dl_warn = 0; _dl_warn = _dl_getenv("LD_WARN", envp); @@ -1026,6 +1103,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt->next->prev = rpnt; rpnt = rpnt->next; } else { rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); @@ -1034,7 +1112,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a rpnt->dyn = tpnt; tpnt = NULL; } -#ifdef DL_TRACE +#ifdef LD_TRACE if (_dl_trace_loaded_objects) { _dl_dprintf(1, "\t%s => %s (0x%x)\n", rpnt->dyn->libname + (_dl_strlen(_dl_ldsopath)) + 1, rpnt->dyn->libname, rpnt->dyn->loadaddr); @@ -1050,8 +1128,8 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_perform_mips_global_got_relocations(_dl_loaded_modules); #endif -#ifdef DL_DEBUG - _dl_dprintf(2, "Beginning relocation fixups\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Beginning relocation fixups\n"); #endif /* * OK, now all of the kids are tucked into bed in their proper addresses. @@ -1065,12 +1143,12 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a and we have to manually search for entries that require fixups. Solaris gets this one right, from what I understand. */ -#ifdef DL_DEBUG - _dl_dprintf(2, "Beginning copy fixups\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Beginning copy fixups\n"); #endif if (_dl_symbol_tables) goof += _dl_copy_fixups(_dl_symbol_tables); -#ifdef DL_TRACE +#ifdef LD_TRACE if (goof || _dl_trace_loaded_objects) _dl_exit(0); #endif @@ -1083,13 +1161,13 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a up each symbol individually. */ - _dl_brkp = (unsigned long *) _dl_find_hash("___brk_addr", NULL, NULL, 0); + _dl_brkp = (unsigned long *) _dl_find_hash("___brk_addr", NULL, NULL, symbolrel); if (_dl_brkp) { *_dl_brkp = brk_addr; } _dl_envp = - (unsigned long *) _dl_find_hash("__environ", NULL, NULL, 0); + (unsigned long *) _dl_find_hash("__environ", NULL, NULL, symbolrel); if (_dl_envp) { *_dl_envp = (unsigned long) envp; @@ -1113,7 +1191,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } #endif - _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, NULL, 0); + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, NULL, symbolrel); /* * OK, fix one more thing - set up the debug_addr structure to point @@ -1130,33 +1208,48 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a function call. */ ((void (*)(void)) debug_addr->r_brk) (); -#ifdef DL_DEBUG - _dl_dprintf(2, "Calling init/fini for shared libraries\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "Calling init/fini for shared libraries\n"); #endif - for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { - /* Apparently crt1 for the application is responsible for handling this. + + for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next) + ; + + for (;rpnt!=NULL; rpnt=rpnt->prev) + { + tpnt = rpnt->dyn; + + if (tpnt->libtype == program_interpreter) + continue; + + /* Apparently crt0/1 for the application is responsible for handling this. * We only need to run the init/fini for shared libraries */ - if (tpnt->libtype == program_interpreter || tpnt->libtype == elf_executable) - continue; + if (tpnt->libtype == elf_executable) + break; /* at this point all shared libs are initialized !! */ + if (tpnt->init_flag & INIT_FUNCS_CALLED) continue; tpnt->init_flag |= INIT_FUNCS_CALLED; if (tpnt->dynamic_info[DT_INIT]) { _dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]); + +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ncalling init: %s\n\n", tpnt->libname); +#endif (*_dl_elf_init) (); } if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) { (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); } -#ifdef DL_DEBUG +#ifdef LD_DEBUG else { if (!_dl_atexit) - _dl_dprintf(2, "%s: The address of atexit () is 0x0.\n", tpnt->libname); + _dl_dprintf(_dl_debug_file, "%s: The address of atexit () is 0x0.\n", tpnt->libname); #if 0 if (!tpnt->dynamic_info[DT_FINI]) - _dl_dprintf(2, "%s: Invalid .fini section.\n", tpnt->libname); + _dl_dprintf(_dl_debug_file, "%s: Invalid .fini section.\n", tpnt->libname); #endif } #endif @@ -1179,6 +1272,10 @@ int _dl_fixup(struct elf_resolve *tpnt) if (tpnt->next) goof += _dl_fixup(tpnt->next); +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname); +#endif + if (tpnt->dynamic_info[DT_REL]) { #ifdef ELF_USES_RELOCA _dl_dprintf(2, "%s: can't handle REL relocation records\n", @@ -1216,6 +1313,9 @@ int _dl_fixup(struct elf_resolve *tpnt) goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s; finished\n\n", tpnt->libname); +#endif return goof; } @@ -1224,8 +1324,8 @@ void *_dl_malloc(int size) void *retval; #if 0 -#ifdef DL_DEBUG - _dl_dprintf(2, "malloc: request for %d bytes\n", size); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "malloc: request for %d bytes\n", size); #endif #endif @@ -1233,8 +1333,8 @@ void *_dl_malloc(int size) return (*_dl_malloc_function) (size); if (_dl_malloc_addr - _dl_mmap_zero + size > 4096) { -#ifdef DL_DEBUG - _dl_dprintf(2, "malloc: mmapping more memory\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "malloc: mmapping more memory\n"); #endif _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); diff --git a/ldso/ldso/m68k/boot1_arch.h b/ldso/ldso/m68k/boot1_arch.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/m68k/boot1_arch.h +++ b/ldso/ldso/m68k/boot1_arch.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/m68k/dl-startup.h b/ldso/ldso/m68k/dl-startup.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/m68k/dl-startup.h +++ b/ldso/ldso/m68k/dl-startup.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index 7e9853765..5854899ec 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -1,23 +1,33 @@ -/* Run an ELF binary on a linux system. - - Copyright (C) 1993, Eric Youngdale. - Copyright (C) 1995, Andreas Schwab. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* Adapted to ELF/68k by Andreas Schwab. */ +/* vi: set sw=4 ts=4: */ +/* m68k ELF shared library loader suppport + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Adapted to ELF/68k by Andreas Schwab. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ #ifndef VERBOSE_DLINKER #define VERBOSE_DLINKER @@ -83,21 +93,21 @@ unsigned int _dl_linux_resolver (int dummy1, int dummy2, instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr; got_addr = (char **) instr_addr; -#ifdef DL_DEBUG_SYMBOLS +#ifdef LD_DEBUG_SYMBOLS _dl_dprintf (2, "Resolving symbol %s\n", strtab + symtab[symtab_index].st_name); #endif /* Get the address of the GOT entry. */ new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, 0); + tpnt->symbol_scope, tpnt, resolver); if (!new_addr) { _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); _dl_exit (1); } -#ifdef DL_NEVER_FIXUP_SYMBOLS +#ifdef LD_NEVER_FIXUP_SYMBOLS if ((unsigned int) got_addr < 0x40000000) { _dl_dprintf (2, "Calling library function: %s\n", strtab + symtab[symtab_index].st_name); @@ -202,7 +212,7 @@ _dl_parse_relocation_information (struct elf_resolve *tpnt, symbol_addr = (unsigned int) _dl_find_hash (strtab + symtab[symtab_index].st_name, tpnt->symbol_scope, - reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, 0); + reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, symbolrel); /* We want to allow undefined references to weak symbols - this might have been intentional. We should not be @@ -327,7 +337,7 @@ _dl_parse_copy_information (struct dyn_elf *xpnt, unsigned long rel_addr, { symbol_addr = (unsigned int) _dl_find_hash (strtab + symtab[symtab_index].st_name, - xpnt->next, NULL, 1); + xpnt->next, NULL, copyrel); if (!symbol_addr) { _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", diff --git a/ldso/ldso/mips/boot1_arch.h b/ldso/ldso/mips/boot1_arch.h index 6dda467e8..b4663bcae 100644 --- a/ldso/ldso/mips/boot1_arch.h +++ b/ldso/ldso/mips/boot1_arch.h @@ -35,4 +35,4 @@ coff: subu $8, $31, $8 "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h index 6dda467e8..b4663bcae 100644 --- a/ldso/ldso/mips/dl-startup.h +++ b/ldso/ldso/mips/dl-startup.h @@ -35,4 +35,4 @@ coff: subu $8, $31, $8 "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index 377c8fa61..bac0cf584 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -1,34 +1,31 @@ /* vi: set sw=4 ts=4: */ - -/* Run an ELF binary on a linux system. - +/* mips/mipsel ELF shared library loader suppport + * Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -/* Program to load an ELF binary on a linux system, and run it. - References to symbols in sharable libraries can be resolved by either - an ELF sharable library or a linux style of shared library. */ - -/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have - I ever taken any courses on internals. This program was developed using - information available through the book "UNIX SYSTEM V RELEASE 4, - Programmers guide: Ansi C and Programming Support Tools", which did - a more than adequate job of explaining everything required to get this - working. */ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ extern int _dl_linux_resolve(void); @@ -55,11 +52,11 @@ unsigned long _dl_linux_resolver(unsigned long sym_index, strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); value = (unsigned long) _dl_find_hash(strtab + sym->st_name, - tpnt->symbol_scope, tpnt, 1); + tpnt->symbol_scope, tpnt, resolver); *(got + local_gotno + sym_index - gotsym) = value; -#ifdef DL_DEBUG +#ifdef LD_DEBUG _dl_dprintf(2, "---RESOLVER---\n"); _dl_dprintf(2, "SYMTAB INDEX: %i\n", sym_index); _dl_dprintf(2, " GOTSYM: %i\n", gotsym); @@ -167,7 +164,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt) /* Relocate the global GOT entries for the object */ while(i--) { -#ifdef DL_DEBUG +#ifdef LD_DEBUG _dl_dprintf(2,"BEFORE: %s=%x\n", strtab + sym->st_name, *got_entry); #endif @@ -176,12 +173,12 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt) *got_entry = sym->st_value + (unsigned long) tpnt->loadaddr; else { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, NULL, 1); + sym->st_name, tpnt->symbol_scope, NULL, copyrel); } } else if (sym->st_shndx == SHN_COMMON) { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, NULL, 1); + sym->st_name, tpnt->symbol_scope, NULL, copyrel); } else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && *got_entry != sym->st_value) @@ -192,10 +189,10 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt) } else { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, NULL, 1); + sym->st_name, tpnt->symbol_scope, NULL, copyrel); } -#ifdef DL_DEBUG +#ifdef LD_DEBUG if (*got_entry == 0) _dl_dprintf(2,"ZERO: %s\n", strtab + sym->st_name); else diff --git a/ldso/ldso/powerpc/boot1_arch.h b/ldso/ldso/powerpc/boot1_arch.h index 0e2e1f055..ae7939eb2 100644 --- a/ldso/ldso/powerpc/boot1_arch.h +++ b/ldso/ldso/powerpc/boot1_arch.h @@ -17,5 +17,5 @@ _dl_boot: "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/powerpc/dl-startup.h b/ldso/ldso/powerpc/dl-startup.h index 0e2e1f055..ae7939eb2 100644 --- a/ldso/ldso/powerpc/dl-startup.h +++ b/ldso/ldso/powerpc/dl-startup.h @@ -17,5 +17,5 @@ _dl_boot: "); #define _dl_boot _dl_boot2 -#define DL_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c index 5ecef1a02..4d263df2f 100644 --- a/ldso/ldso/powerpc/elfinterp.c +++ b/ldso/ldso/powerpc/elfinterp.c @@ -1,22 +1,32 @@ -//#define DL_DEBUG -/* Run an ELF binary on a linux system. +/* vi: set sw=4 ts=4: */ +/* i386 ELF shared library loader suppport + * + * Copyright (C) 2001-2002, David A. Schleef + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ - Copyright (C) 1993, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #ifndef VERBOSE_DLINKER #define VERBOSE_DLINKER #endif @@ -49,7 +59,7 @@ static const char *_dl_reltypes[] = working. */ -#ifdef DL_DEBUG_SYMBOLS +#ifdef LD_DEBUG_SYMBOLS static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index); static void debug_reloc(ELF_RELOC *rpnt); #define DPRINTF(fmt,args...) _dl_dprintf(2,fmt,args) @@ -161,7 +171,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) /* Get the address of the GOT entry */ targ_addr = (unsigned long) _dl_find_hash( strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, 0); + tpnt->symbol_scope, tpnt, resolver); if (!targ_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -338,7 +348,7 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, tpnt->symbol_scope, - (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0); + (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel); /* * We want to allow undefined references to weak symbols - this might @@ -499,7 +509,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, xpnt->next, - NULL, 1); + NULL, copyrel); if (!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -551,7 +561,7 @@ static void fixup_jmpslot(unsigned long reloc_addr, unsigned long targ_addr) #endif -#ifdef DL_DEBUG_SYMBOLS +#ifdef LD_DEBUG_SYMBOLS static void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index) { if(symtab_index){ diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c index c5e7607e0..8c2314184 100644 --- a/ldso/ldso/readelflib1.c +++ b/ldso/ldso/readelflib1.c @@ -1,21 +1,34 @@ -/* Load an ELF sharable library into memory. - - Copyright (C) 1993-1996, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +/* vi: set sw=4 ts=4: */ +/* Program to load an ELF binary on a linux system, and run it + * after resolving ELF shared library symbols + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* This file contains the helper routines to load an ELF sharable @@ -180,8 +193,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, pnt++; } -#ifdef DL_DEBUG - _dl_dprintf(2, "searching for library: '%s'\n", libname); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname); #endif /* If the filename has any '/', try it straight and leave it at that. For IBCS2 compatibility under linux, we substitute the string @@ -204,8 +217,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, if (pnt) { pnt += (unsigned long) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB]; -#ifdef DL_DEBUG - _dl_dprintf(2, "searching RPATH: '%s'\n", pnt); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching RPATH: '%s'\n", pnt); #endif if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL) { @@ -217,8 +230,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ if (_dl_library_path) { -#ifdef DL_DEBUG - _dl_dprintf(2, "searching _dl_library_path: '%s'\n", _dl_library_path); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching _dl_library_path: '%s'\n", _dl_library_path); #endif if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL) { @@ -251,8 +264,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Look for libraries wherever the shared library loader * was installed */ -#ifdef DL_DEBUG - _dl_dprintf(2, "searching in ldso dir: %s\n", _dl_ldsopath); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching in ldso dir: %s\n", _dl_ldsopath); #endif if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL) { @@ -262,8 +275,8 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, /* Lastly, search the standard list of paths for the library. This list must exactly match the list in uClibc/ldso/util/ldd.c */ -#ifdef DL_DEBUG - _dl_dprintf(2, "searching full lib path list\n"); +#ifdef LD_DEBUG + _dl_dprintf(_dl_debug_file, "searching full lib path list\n"); #endif if ((tpnt1 = search_for_named_library(libname, secure, UCLIBC_TARGET_PREFIX "/usr/lib:" @@ -282,8 +295,8 @@ goof: if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number; else - _dl_error_number = DL_ERROR_NOFILE; -#ifdef DL_DEBUG + _dl_error_number = LD_ERROR_NOFILE; +#ifdef LD_DEBUG _dl_dprintf(2, "Bummer: could not find '%s'!\n", libname); #endif return NULL; @@ -323,6 +336,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + (*rpnt)->next->prev = (*rpnt); *rpnt = (*rpnt)->next; (*rpnt)->dyn = tpnt; tpnt->symbol_scope = _dl_symbol_tables; @@ -352,7 +366,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, */ _dl_dprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); #endif - _dl_internal_error_number = DL_ERROR_NOFILE; + _dl_internal_error_number = LD_ERROR_NOFILE; return NULL; } @@ -365,7 +379,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, { _dl_dprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_NOTELF; + _dl_internal_error_number = LD_ERROR_NOTELF; _dl_close(infile); return NULL; }; @@ -377,7 +391,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, )) { _dl_internal_error_number = - (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); + (epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC); _dl_dprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n", _dl_progname, libname); _dl_close(infile); @@ -424,7 +438,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map %s\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_close(infile); return NULL; }; @@ -457,7 +471,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); return NULL; @@ -488,7 +502,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, infile, ppnt->p_offset & OFFS_ALIGN); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); return NULL; @@ -516,7 +530,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, /* Start by scanning the dynamic section to get all of the pointers */ if (!dynamic_addr) { - _dl_internal_error_number = DL_ERROR_NODYNAMIC; + _dl_internal_error_number = LD_ERROR_NODYNAMIC; _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); return NULL; @@ -580,6 +594,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + (*rpnt)->next->prev = (*rpnt); *rpnt = (*rpnt)->next; (*rpnt)->dyn = tpnt; tpnt->symbol_scope = _dl_symbol_tables; @@ -626,6 +641,10 @@ int _dl_copy_fixups(struct dyn_elf *rpnt) return goof; tpnt->init_flag |= COPY_RELOCS_DONE; +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s", tpnt->libname); +#endif + #ifdef ELF_USES_RELOCA goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); @@ -635,5 +654,8 @@ int _dl_copy_fixups(struct dyn_elf *rpnt) tpnt->dynamic_info[DT_RELSZ], 0); #endif +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s; finished\n\n", tpnt->libname); +#endif return goof; } diff --git a/ldso/ldso/sh/boot1_arch.h b/ldso/ldso/sh/boot1_arch.h new file mode 100644 index 000000000..798121dc0 --- /dev/null +++ b/ldso/ldso/sh/boot1_arch.h @@ -0,0 +1,23 @@ +/* Any assmbly language/system dependent hacks needed to setup boot1.c so it + * will work as expected and cope with whatever platform specific wierdness is + * needed for this architecture. */ + +asm("\ + .text + .globl _dl_boot +_dl_boot: + mov r15, r4 + mov.l .L_dl_boot2, r1 + mova .L_dl_boot2, r0 + add r1, r0 + jsr @r0 + add #4, r4 + jmp @r0 + mov #0, r4 /* call _start with arg == 0 */ +.L_dl_boot2:\n\ + .long _dl_boot2-.\n\ + .previous\n\ +"); + +#define _dl_boot _dl_boot2 +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/sh/dl-startup.h b/ldso/ldso/sh/dl-startup.h new file mode 100644 index 000000000..798121dc0 --- /dev/null +++ b/ldso/ldso/sh/dl-startup.h @@ -0,0 +1,23 @@ +/* Any assmbly language/system dependent hacks needed to setup boot1.c so it + * will work as expected and cope with whatever platform specific wierdness is + * needed for this architecture. */ + +asm("\ + .text + .globl _dl_boot +_dl_boot: + mov r15, r4 + mov.l .L_dl_boot2, r1 + mova .L_dl_boot2, r0 + add r1, r0 + jsr @r0 + add #4, r4 + jmp @r0 + mov #0, r4 /* call _start with arg == 0 */ +.L_dl_boot2:\n\ + .long _dl_boot2-.\n\ + .previous\n\ +"); + +#define _dl_boot _dl_boot2 +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/sh/dl-syscalls.h b/ldso/ldso/sh/dl-syscalls.h new file mode 100644 index 000000000..793dc9110 --- /dev/null +++ b/ldso/ldso/sh/dl-syscalls.h @@ -0,0 +1,7 @@ +/* Define the __set_errno macro as nothing so that we don't bother + * setting errno, which is important since we make system calls + * before the errno symbol is dynamicly linked. */ + +#define __set_errno(X) +#include "sys/syscall.h" + diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h new file mode 100644 index 000000000..dc1b895b9 --- /dev/null +++ b/ldso/ldso/sh/dl-sysdep.h @@ -0,0 +1,145 @@ +/* + * Various assmbly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + */ + +/* + * Define this if the system uses RELOCA. + */ +#define ELF_USES_RELOCA + +/* + * Get a pointer to the argv array. On many platforms this can be just + * the address if the first argument, on other platforms we need to + * do something a little more subtle here. + */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) + +/* + * Initialization sequence for a GOT. + */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) (MODULE); \ +} + +/* + * Here is a macro to perform a relocation. This is only used when + * bootstrapping the dynamic loader. RELP is the relocation that we + * are performing, REL is the pointer to the address we are relocating. + * SYMBOL is the symbol involved in the relocation, and LOAD is the + * load address. + */ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)){ \ + case R_SH_REL32: \ + *(REL) += (RELP)->r_addend - (LOAD); \ + break; \ + case R_SH_DIR32: \ + *(REL) += (SYMBOL) + (RELP)->r_addend; \ + break; \ + case R_SH_RELATIVE: \ + *(REL) += (LOAD); \ + break; \ + case R_SH_NONE: \ + break; \ + default: \ + SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type "); \ + SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1); \ + SEND_STDERR("REL, SYMBOL, LOAD: "); \ + SEND_ADDRESS_STDERR(REL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(SYMBOL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(LOAD, 1); \ + _dl_exit(1); \ + } + + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. This routine has to exit the current function, then + * call the _dl_elf_main function. + */ + +#define START() return _dl_elf_main; + + + +/* Here we define the magic numbers that this dynamic loader should accept */ + +#define MAGIC1 EM_SH +#undef MAGIC2 +/* Used for error messages */ +#define ELF_TARGET "sh" + +struct elf_resolve; +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +static __inline__ unsigned int +_dl_urem(unsigned int n, unsigned int base) +{ +register unsigned int __r0 __asm__ ("r0"); +register unsigned int __r4 __asm__ ("r4") = n; +register unsigned int __r5 __asm__ ("r5") = base; + + __asm__ (" + mov #0, r0 + div0u + + ! get one bit from the msb of the numerator into the T + ! bit and divide it by whats in %2. Put the answer bit + ! into the T bit so it can come out again at the bottom + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 + mov r4, r0 +" + : "=r" (__r0) + : "r" (__r4), "r" (__r5) + : "r4", "cc"); + + return n - (base * __r0); +} + +#define do_rem(result, n, base) ((result) = _dl_urem((n), (base))) + +/* 4096 bytes alignment */ +#define PAGE_ALIGN 0xfffff000 +#define ADDR_ALIGN 0xfff +#define OFFS_ALIGN 0x7ffff000 diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c new file mode 100644 index 000000000..2a0ab9f7a --- /dev/null +++ b/ldso/ldso/sh/elfinterp.c @@ -0,0 +1,416 @@ +/* vi: set sw=4 ts=4: */ +/* SuperH ELF shared library loader suppport + * + * Copyright (C) 2002, Stefan Allius and + * Eddie C. Dost + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) +static const char *_dl_reltypes_tab[] = +{ + [0] "R_SH_NONE", "R_SH_DIR32", "R_SH_REL32", "R_SH_DIR8WPN", + [4] "R_SH_IND12W", "R_SH_DIR8WPL", "R_SH_DIR8WPZ", "R_SH_DIR8BP", + [8] "R_SH_DIR8W", "R_SH_DIR8L", + [25] "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES", + [28] "R_SH_COUNT", "R_SH_ALIGN", "R_SH_CODE", "R_SH_DATA", + [32] "R_SH_LABEL", "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY", +[160] "R_SH_GOT32", "R_SH_PLT32", "R_SH_COPY", "R_SH_GLOB_DAT", +[164] "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF", "R_SH_GOTPC", +}; + +static const char * +_dl_reltypes(int type) +{ + static char buf[22]; + const char *str; + + if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) || + NULL == (str = _dl_reltypes_tab[type])) + { + str =_dl_simple_ltoa( buf, (unsigned long)(type)); + } + return str; +} + +static +void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index) +{ + if(_dl_debug_symbols) + { + if(symtab_index){ + _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_value, + symtab[symtab_index].st_size, + symtab[symtab_index].st_info, + symtab[symtab_index].st_other, + symtab[symtab_index].st_shndx); + } + } +} + +static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt) +{ + if(_dl_debug_reloc) + { + int symtab_index; + const char *sym; + symtab_index = ELF32_R_SYM(rpnt->r_info); + sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0"; + +#ifdef ELF_USES_RELOCA + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + rpnt->r_addend, + sym); +#else + _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s", + _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), + rpnt->r_offset, + sym); +#endif + } +} +#endif + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have + I ever taken any courses on internals. This program was developed using + information available through the book "UNIX SYSTEM V RELEASE 4, + Programmers guide: Ansi C and Programming Support Tools", which did + a more than adequate job of explaining everything required to get this + working. */ + +extern int _dl_linux_resolve(void); + +unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +{ + int reloc_type; + ELF_RELOC *this_reloc; + char *strtab; + Elf32_Sym *symtab; + int symtab_index; + char *rel_addr; + char *new_addr; + char **got_addr; + unsigned long instr_addr; + + rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); + + this_reloc = (ELF_RELOC *) (rel_addr + reloc_entry); + reloc_type = ELF32_R_TYPE(this_reloc->r_info); + symtab_index = ELF32_R_SYM(this_reloc->r_info); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + if (reloc_type != R_SH_JMP_SLOT) { + _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", + _dl_progname); + _dl_exit(1); + } + + /* Address of jump instruction to fix up */ + instr_addr = ((unsigned long) this_reloc->r_offset + + (unsigned long) tpnt->loadaddr); + got_addr = (char **) instr_addr; + + + /* Get the address of the GOT entry */ + new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, + tpnt->symbol_scope, tpnt, resolver); + if (!new_addr) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_exit(1); + } + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_NEVER_FIXUP_SYMBOLS) + if ((unsigned long) got_addr < 0x20000000) + { +#ifndef SUPPORT_LD_DEBUG + if (_dl_debug_bindings) + { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", + strtab + symtab[symtab_index].st_name); + if(_dl_debug_detail) _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } +#endif +#ifndef LD_NEVER_FIXUP_SYMBOLS + *got_addr = new_addr; +#endif + } else { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + + return (unsigned long) new_addr; +} + + +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) +{ + int i; + char *strtab; + int goof = 0; + Elf32_Sym *symtab; + ELF_RELOC *rpnt; + int symtab_index; + /* Now parse the relocation information */ + + rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF32_R_SYM(rpnt->r_info); + + /* When the dynamic linker bootstrapped itself, it resolved some symbols. + Make sure we do not do them again */ + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + if (symtab_index && tpnt->libtype == program_interpreter && + _dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + +#if defined (SUPPORT_LD_DEBUG) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); +#endif + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (SUPPORT_LD_DEBUG) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol '%s'\n"); + goof += res; + } + } + return goof; +} + + +static int +_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + + symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, + scope, + (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL), symbolrel); + + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { + goof++; + } + } + + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_SH_NONE: + break; + case R_SH_COPY: + /* handled later on */ + break; + case R_SH_DIR32: + *reloc_addr += symbol_addr + rpnt->r_addend; + break; + case R_SH_JMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_SH_REL32: + *reloc_addr += rpnt->r_addend - + (unsigned long) tpnt->loadaddr; + break; + case R_SH_RELATIVE: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + +#endif + + return goof; +} + + +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + unsigned long *reloc_addr; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_SH_NONE: + break; + case R_SH_JMP_SLOT: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + default: + return -1; /*call _dl_exit(1) */ + } +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + } + +#endif + return 0; + +} + +/* This is done as a separate step, because there are cases where + information is first copied and later initialized. This results in + the wrong information being copied. Someone at Sun was complaining about + a bug in the handling of _COPY by SVr4, and this may in fact be what he + was talking about. Sigh. */ + +/* No, there are cases where the SVr4 linker fails to emit COPY relocs + at all */ +static int +_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + if (reloc_type != R_SH_COPY) + return 0; + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + symbol_addr = (unsigned long) _dl_find_hash(strtab + + symtab[symtab_index].st_name, scope, + NULL, copyrel); + if (!symbol_addr) goof++; + } + if (!goof) { +#if defined (SUPPORT_LD_DEBUG) + if(_dl_debug_move) + _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x", + strtab + symtab[symtab_index].st_name, + symtab[symtab_index].st_size, + symbol_addr, symtab[symtab_index].st_value); +#endif + _dl_memcpy((char *) symtab[symtab_index].st_value, + (char *) symbol_addr, symtab[symtab_index].st_size); + } + + return goof; +} + + +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} + +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} + +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) +{ + return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy); +} + + diff --git a/ldso/ldso/sh/ld_syscalls.h b/ldso/ldso/sh/ld_syscalls.h new file mode 100644 index 000000000..793dc9110 --- /dev/null +++ b/ldso/ldso/sh/ld_syscalls.h @@ -0,0 +1,7 @@ +/* Define the __set_errno macro as nothing so that we don't bother + * setting errno, which is important since we make system calls + * before the errno symbol is dynamicly linked. */ + +#define __set_errno(X) +#include "sys/syscall.h" + diff --git a/ldso/ldso/sh/ld_sysdep.h b/ldso/ldso/sh/ld_sysdep.h new file mode 100644 index 000000000..dc1b895b9 --- /dev/null +++ b/ldso/ldso/sh/ld_sysdep.h @@ -0,0 +1,145 @@ +/* + * Various assmbly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + */ + +/* + * Define this if the system uses RELOCA. + */ +#define ELF_USES_RELOCA + +/* + * Get a pointer to the argv array. On many platforms this can be just + * the address if the first argument, on other platforms we need to + * do something a little more subtle here. + */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) + +/* + * Initialization sequence for a GOT. + */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) (MODULE); \ +} + +/* + * Here is a macro to perform a relocation. This is only used when + * bootstrapping the dynamic loader. RELP is the relocation that we + * are performing, REL is the pointer to the address we are relocating. + * SYMBOL is the symbol involved in the relocation, and LOAD is the + * load address. + */ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)){ \ + case R_SH_REL32: \ + *(REL) += (RELP)->r_addend - (LOAD); \ + break; \ + case R_SH_DIR32: \ + *(REL) += (SYMBOL) + (RELP)->r_addend; \ + break; \ + case R_SH_RELATIVE: \ + *(REL) += (LOAD); \ + break; \ + case R_SH_NONE: \ + break; \ + default: \ + SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type "); \ + SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1); \ + SEND_STDERR("REL, SYMBOL, LOAD: "); \ + SEND_ADDRESS_STDERR(REL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(SYMBOL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(LOAD, 1); \ + _dl_exit(1); \ + } + + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. This routine has to exit the current function, then + * call the _dl_elf_main function. + */ + +#define START() return _dl_elf_main; + + + +/* Here we define the magic numbers that this dynamic loader should accept */ + +#define MAGIC1 EM_SH +#undef MAGIC2 +/* Used for error messages */ +#define ELF_TARGET "sh" + +struct elf_resolve; +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +static __inline__ unsigned int +_dl_urem(unsigned int n, unsigned int base) +{ +register unsigned int __r0 __asm__ ("r0"); +register unsigned int __r4 __asm__ ("r4") = n; +register unsigned int __r5 __asm__ ("r5") = base; + + __asm__ (" + mov #0, r0 + div0u + + ! get one bit from the msb of the numerator into the T + ! bit and divide it by whats in %2. Put the answer bit + ! into the T bit so it can come out again at the bottom + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 + mov r4, r0 +" + : "=r" (__r0) + : "r" (__r4), "r" (__r5) + : "r4", "cc"); + + return n - (base * __r0); +} + +#define do_rem(result, n, base) ((result) = _dl_urem((n), (base))) + +/* 4096 bytes alignment */ +#define PAGE_ALIGN 0xfffff000 +#define ADDR_ALIGN 0xfff +#define OFFS_ALIGN 0x7ffff000 diff --git a/ldso/ldso/sh/resolve.S b/ldso/ldso/sh/resolve.S new file mode 100644 index 000000000..4d8eee6c2 --- /dev/null +++ b/ldso/ldso/sh/resolve.S @@ -0,0 +1,69 @@ +/* + * Stolen from glibc-2.2.2 by Eddie C. Dost + */ + + .text + .globl _dl_linux_resolve + .type _dl_linux_resolve, @function + .balign 16 +_dl_linux_resolve: + mov.l r3, @-r15 + mov.l r4, @-r15 + mov.l r5, @-r15 + mov.l r6, @-r15 + mov.l r7, @-r15 + mov.l r12, @-r15 + movt r3 ! Save T flag + mov.l r3, @-r15 + +#ifdef HAVE_FPU + sts.l fpscr, @-r15 + mov #8,r3 + swap.w r3, r3 + lds r3, fpscr + fmov.s fr11, @-r15 + fmov.s fr10, @-r15 + fmov.s fr9, @-r15 + fmov.s fr8, @-r15 + fmov.s fr7, @-r15 + fmov.s fr6, @-r15 + fmov.s fr5, @-r15 + fmov.s fr4, @-r15 +#endif + sts.l pr, @-r15 + + mov r2, r4 ! link map address + + mov.l 3f, r0 + jsr @r0 ! Call resolver + mov r1, r5 ! Reloc offset + + lds.l @r15+, pr ! Get register content back + +#ifdef HAVE_FPU + fmov.s @r15+, fr4 + fmov.s @r15+, fr5 + fmov.s @r15+, fr6 + fmov.s @r15+, fr7 + fmov.s @r15+, fr8 + fmov.s @r15+, fr9 + fmov.s @r15+, fr10 + fmov.s @r15+, fr11 + lds.l @r15+, fpscr +#endif + + mov.l @r15+, r3 + shal r3 ! Load T flag + mov.l @r15+, r12 + mov.l @r15+, r7 + mov.l @r15+, r6 + mov.l @r15+, r5 + mov.l @r15+, r4 + jmp @r0 ! Jump to function address + mov.l @r15+, r3 + + .balign 4 +3: + .long _dl_linux_resolver + .size _dl_linux_resolve, . - _dl_linux_resolve + diff --git a/ldso/ldso/sparc/boot1_arch.h b/ldso/ldso/sparc/boot1_arch.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/sparc/boot1_arch.h +++ b/ldso/ldso/sparc/boot1_arch.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/sparc/dl-startup.h b/ldso/ldso/sparc/dl-startup.h index 2f8fe1357..cd1f016a6 100644 --- a/ldso/ldso/sparc/dl-startup.h +++ b/ldso/ldso/sparc/dl-startup.h @@ -4,4 +4,4 @@ * can be done. */ -#define DL_BOOT(X) void _dl_boot (X) +#define LD_BOOT(X) void _dl_boot (X) diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c index 3270a0821..60ec4b0e8 100644 --- a/ldso/ldso/sparc/elfinterp.c +++ b/ldso/ldso/sparc/elfinterp.c @@ -1,21 +1,33 @@ -/* Run an ELF binary on a linux system. +/* vi: set sw=4 ts=4: */ +/* sparc ELF shared library loader suppport + * + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ - Copyright (C) 1995, Eric Youngdale. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #ifndef VERBOSE_DLINKER #define VERBOSE_DLINKER #endif @@ -91,20 +103,20 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt) _dl_dprintf(2, "symtab_index %d\n", symtab_index); -#ifdef DL_DEBUG_SYMBOLS +#ifdef LD_DEBUG_SYMBOLS _dl_dprintf(2, "Resolving symbol %s\n", strtab + symtab[symtab_index].st_name); #endif /* Get the address of the GOT entry */ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, 0); + tpnt->symbol_scope, tpnt, resolver); if(!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); _dl_exit(31); }; -#ifdef DL_NEVER_FIXUP_SYMBOLS +#ifdef LD_NEVER_FIXUP_SYMBOLS if((unsigned int) got_addr < 0x40000000) { _dl_dprintf(2, "Calling library function: %s\n", strtab + symtab[symtab_index].st_name); @@ -202,7 +214,7 @@ int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, symbol_addr = (unsigned int) _dl_find_hash(strtab + symtab[symtab_index].st_name, tpnt->symbol_scope, - (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), 0); + (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), symbolrel); if(!symbol_addr && ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) { @@ -319,7 +331,7 @@ int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr, symbol_addr = (unsigned int) _dl_find_hash(strtab + symtab[symtab_index].st_name, - xpnt->next, NULL, 1); + xpnt->next, NULL, copyrel); if(!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); -- cgit v1.2.3