diff options
author | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-09-11 02:36:38 +0000 |
---|---|---|
committer | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-09-11 02:36:38 +0000 |
commit | dc054feed4dd1591c58aa1447c73a38dba77f6d4 (patch) | |
tree | a73435ac60e5ceb6d475d87f96f4754f4da6217f /libexec/ld.so | |
parent | bdefb08c423d5d41fd2f35e0f1b7a38affd18764 (diff) |
ldd compatibility (if we had ldd for this ld.so)
respect the LD_TRACE_LOADED_OBJECTS environment variable,
print loaded libraries and exit, do not execute program.
Diffstat (limited to 'libexec/ld.so')
-rw-r--r-- | libexec/ld.so/loader.c | 502 |
1 files changed, 394 insertions, 108 deletions
diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index b351bbc7403..5d059d15782 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.1 2000/06/13 03:34:06 rahnds Exp $ */ +/* $OpenBSD: loader.c,v 1.2 2000/09/11 02:36:37 rahnds Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -36,6 +36,7 @@ #include <sys/types.h> #include <sys/mman.h> +#include <nlist.h> #include <link.h> #include "syscall.h" @@ -45,7 +46,7 @@ /* * Local decls. */ -static char *_dl_getenv(const char *var, const char **env); +/* static */ char *_dl_getenv(const char *var, const char **env); /* * Static vars usable after bootsrapping. @@ -66,6 +67,7 @@ char *_dl_debug; char *_dl_showmap; struct r_debug *_dl_debug_map; +void _dl_unmaphints(); void _dl_debug_state(void) @@ -73,120 +75,75 @@ _dl_debug_state(void) /* Debugger stub */ } + +#if 1 +static inline void +put_x(unsigned int x) +{ + char string[8]; + char *pchr; + unsigned int rem; + int len = 0; + string[19] = '\0'; + pchr = &string[7]; + do { + rem = x % 16; + x = x / 16; + if (rem < 10) { + *pchr = rem + '0'; + } else { + *pchr = rem - 10 + 'a'; + } + pchr--; + len++; + } while (len < 8); + _dl_write(1, string, len); + +} + +static inline int +putstring(char *string, unsigned int off) +{ + int len = 0; + char * str1; + if ((unsigned int) string < 0x10000000) { + string += off; + } + for ( str1 = string; len < 30 && *str1++ != '\0'; len++); + return _dl_write(1, string, len); + +} +static inline int +putc(char c) +{ + return _dl_write(1, &c, 1); + +} +#endif + /* * This is the dynamic loader entrypoint. When entering here, depending * on architecture type, the stack and registers are set up according * to the architectures ABI specification. The first thing requiered * to do is to dig out all information we need to accomplish out task. */ - int -_dl_boot(const int sp, const int loff) +_dl_boot(const char **argv, const char **envp, const int loff, + Elf32_Dyn *dynp, int *dl_data) { - int argc; int n; int brk_addr; - const char **argv, **envp; - int *stack, execstack = sp; - AuxInfo *auxstack; - int dl_data[AUX_entry + 1]; - Elf32_Dyn *dynp; Elf32_Phdr *phdp; - elf_object_t *dynobj; char *us = ""; - - struct elf_object dynld; /* Resolver data for the loader */ + elf_object_t *dynobj; struct elf_object *exe_obj; /* Pointer to executable object */ struct elf_object *dyn_obj; /* Pointer to executable object */ - struct r_debug *debug_map; /* Dynamic objects map for gdb */ - struct r_debug **map_link; /* Where to put pointer for gdb */ - - /* - * Scan argument and environment vectors. Find dynamic - * data vector put after them. - */ - stack = (int *)execstack; - argc = *stack++; - argv = (const char **)stack; - envp = &argv[argc + 1]; - stack = (int *)envp; - while(*stack++ != NULL) {}; - - /* - * Dig out auxilary data set up by exec call. Move all known - * tags to an indexed local table for easy access. - */ - - auxstack = (AuxInfo *)stack; - while(auxstack->au_id != AUX_null) { - if(auxstack->au_id <= AUX_entry) { - dl_data[auxstack->au_id] = auxstack->au_v; - } - auxstack++; - } - - /* - * We need to do 'selfreloc' in case the code were'nt - * loaded at the address it was linked to. - * - * Scan the DYNAMIC section for the loader. - * Cache the data for easier access. - */ - - dynp = (Elf32_Dyn *)((int)_DYNAMIC + loff); - while(dynp->d_tag != DT_NULL) { - if(dynp->d_tag < DT_PROCNUM) { - dynld.Dyn.info[dynp->d_tag] = dynp->d_un.d_val; - } - else if(dynp->d_tag >= DT_LOPROC && dynp->d_tag < DT_LOPROC + DT_PROCNUM) { - dynld.Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = dynp->d_un.d_val; - } - if(dynp->d_tag == DT_TEXTREL) - dynld.dyn.textrel = 1; - dynp++; - } - - /* - * Do the 'bootstrap relocation'. This is really only needed if - * the code was loaded at another location than it was linked to. - * We don't do undefined symbols resolving (to difficult..) - */ - for(n = 0; n < 2; n++) { - int i; - u_int32_t rs; - RELTYPE *rp; - - if(n == 0) { - rp = (RELTYPE *)(dynld.Dyn.info[DT_REL] + loff); - rs = dynld.dyn.relsz; - } - else { - rp = (RELTYPE *)(dynld.Dyn.info[DT_JMPREL] + loff); - rs = dynld.dyn.pltrelsz; - } - - for(i = 0; i < rs; i += RELSIZE) { - Elf32_Addr *ra; - const Elf32_Sym *sp; - - sp = dynld.dyn.symtab + loff; - sp += ELF32_R_SYM(rp->r_info); - if(ELF32_R_SYM(rp->r_info) && sp->st_value == 0) { - _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); - _dl_wrstderr("Undefined symbol: "); - _dl_wrstderr((char *)dynld.dyn.strtab + loff + sp->st_name); - _dl_exit(4); - } - - ra = (Elf32_Addr *)(rp->r_offset + loff); - SIMPLE_RELOC(rp, sp, ra, loff); - } - - } + struct r_debug * debug_map; /* * Get paths to various things we are going to use. */ + _dl_libpath = _dl_getenv("LD_LIBRARY_PATH", envp); _dl_preload = _dl_getenv("LD_PRELOAD", envp); _dl_bindnow = _dl_getenv("LD_BIND_NOW", envp); @@ -268,7 +225,7 @@ _dl_boot(const int sp, const int loff) * so we can use the _dl_ code when serving dl.... calls. */ - dynp = (Elf32_Dyn *)((int)_DYNAMIC + loff); + dynp = (Elf32_Dyn *)((int)_DYNAMIC); dyn_obj = _dl_add_object(us, dynp, 0, OBJTYPE_LDR, dl_data[AUX_base], loff); dyn_obj->status |= STAT_RELOC_DONE; @@ -283,6 +240,33 @@ _dl_boot(const int sp, const int loff) /* * Finally make something to help gdb when poking around in the code. */ +#ifdef __powerpc__ + { + int done = 0; + + debug_map = (struct r_debug *)_dl_malloc(sizeof(*debug_map)); + debug_map->r_version = 1; + debug_map->r_map = (struct link_map *)_dl_objects; + debug_map->r_brk = (Elf32_Addr)_dl_debug_state; + debug_map->r_state = RT_CONSISTENT; + debug_map->r_ldbase = loff; + _dl_debug_map = debug_map; + + /* picks up the first object, the executable itself */ + dynobj = _dl_objects; + + for(dynp = dynobj->load_dyn; dynp->d_tag; dynp++) { + if (dynp->d_tag == DT_DEBUG) { + dynp->d_un.d_ptr = (Elf32_Addr) debug_map; + done = 1; + break; + } + } + if (done == 0) { + _dl_printf("failed to mark DTDEBUG\n"); + } + } +#endif #ifdef __mips__ map_link = (struct r_debug **)(exe_obj->Dyn.info[DT_MIPS_RLD_MAP - DT_LOPROC + DT_NUM]); @@ -300,16 +284,240 @@ _dl_boot(const int sp, const int loff) _dl_debug_state(); - if(_dl_debug) { + if(_dl_debug || _dl_traceld) { + void _dl_show_objects(); /* remove -Wall warning */ _dl_show_objects(); _dl_printf("dynamic loading done.\n"); } - + _dl_unmaphints(); + if (_dl_traceld) { + _dl_exit(0); + } return(dl_data[AUX_entry]); } void +_dl_boot_bind(const int sp, const int loff, int argc, const char **argv, + const char **envp, Elf32_Dyn *dynamicp, int *dl_data) +{ + Elf32_Dyn *dynp; + int n; + int *stack; + AuxInfo *auxstack; + + struct elf_object dynld; /* Resolver data for the loader */ +#ifdef __mips__ + struct r_debug *debug_map; /* Dynamic objects map for gdb */ + struct r_debug **map_link; /* Where to put pointer for gdb */ +#endif /* __mips__ */ + + /* + * Scan argument and environment vectors. Find dynamic + * data vector put after them. + */ +#ifdef _mips_ + stack = (int *)sp; + argc = *stack++; + argv = (const char **)stack; + envp = &argv[argc + 1]; +#endif /* _mips_ */ + stack = (int *)envp; + while(*stack++ != NULL) {}; + + /* + * Dig out auxilary data set up by exec call. Move all known + * tags to an indexed local table for easy access. + */ + + auxstack = (AuxInfo *)stack; + + while(auxstack->au_id != AUX_null) { + if(auxstack->au_id <= AUX_entry) { + dl_data[auxstack->au_id] = auxstack->au_v; + } + auxstack++; + } + + /* + * We need to do 'selfreloc' in case the code were'nt + * loaded at the address it was linked to. + * + * Scan the DYNAMIC section for the loader. + * Cache the data for easier access. + */ + +#ifdef __powerpc__ + dynp = dynamicp; +#else + dynp = (Elf32_Dyn *)((int)_DYNAMIC + loff); +#endif + while(dynp != NULL && dynp->d_tag != DT_NULL) { + if(dynp->d_tag < DT_LOPROC) { + dynld.Dyn.info[dynp->d_tag] = dynp->d_un.d_val; + } + else if(dynp->d_tag >= DT_LOPROC && dynp->d_tag < DT_LOPROC + DT_NUM) { + dynld.Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = dynp->d_un.d_val; + } + if(dynp->d_tag == DT_TEXTREL) + dynld.dyn.textrel = 1; + dynp++; + } + + /* + * Do the 'bootstrap relocation'. This is really only needed if + * the code was loaded at another location than it was linked to. + * We don't do undefined symbols resolving (to difficult..) + */ + + /* "relocate" dyn.X values if they represent addresses */ + { + int i, val; + /* must be code, not pic data */ + int table[20]; + i = 0; + table[i++] = DT_PLTGOT; + table[i++] = DT_HASH; + table[i++] = DT_STRTAB; + table[i++] = DT_SYMTAB; + table[i++] = DT_RELA; + table[i++] = DT_INIT; + table[i++] = DT_FINI; + table[i++] = DT_REL; + table[i++] = DT_JMPREL; + /* other processors insert there extras here */ + table[i++] = DT_NULL; +#if 0 + = { + DT_PLTGOT, + DT_HASH, + DT_STRTAB, + DT_SYMTAB, + DT_RELA, + DT_INIT, + DT_FINI, + DT_REL, + DT_JMPREL, + /* other processors insert there extras here */ + DT_NULL + }; +#endif + for (i = 0; table[i] != DT_NULL; i++) + { + val = table[i]; + if ( val > DT_HIPROC) { + /* ??? */ + continue; + } + if ( val > DT_LOPROC) { + val -= DT_LOPROC + DT_NUM; + } + if ( dynld.Dyn.info[val] != 0 ) { + dynld.Dyn.info[val] += loff; + } + } + + } + + { + int i; + u_int32_t rs; + Elf32_Rel *rp; + + rp = (Elf32_Rel *)(dynld.Dyn.info[DT_REL]); + rs = dynld.dyn.relsz; + + for(i = 0; i < rs; i += sizeof (Elf32_Rel)) { + Elf32_Addr *ra; + const Elf32_Sym *sp; + + sp = dynld.dyn.symtab; + sp += ELF32_R_SYM(rp->r_info); +#if 1 + putstring("reloc ", loff); + putstring(((char *)dynld.dyn.strtab) + sp->st_name, 0); + putstring(" ", loff); +#endif + + if(ELF32_R_SYM(rp->r_info) && sp->st_value == 0) { +#if 0 +/* cannot printf in this function */ + _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); + _dl_wrstderr("Undefined symbol: "); + _dl_wrstderr((char *)dynld.dyn.strtab + + sp->st_name); +#endif + _dl_exit(5); + } + + ra = (Elf32_Addr *)(rp->r_offset + loff); +#if 0 + put_x((unsigned int)ra); + putstring("\n", loff); +#endif + /* + RELOC_REL(rp, sp, ra, loff); + */ + rp++; + } + + } + for(n = 0; n < 2; n++) { + int i; + u_int32_t rs; + Elf32_Rela *rp; + + switch (n) { + case 0: + rp = (Elf32_Rela *)(dynld.Dyn.info[DT_JMPREL]); + rs = dynld.dyn.pltrelsz; + break; + case 1: + rp = (Elf32_Rela *)(dynld.Dyn.info[DT_RELA]); + rs = dynld.dyn.relasz; + + break; + default: + rp = NULL; + rs = 0; + ; + } + for(i = 0; i < rs; i += sizeof (Elf32_Rela)) { + Elf32_Addr *ra; + const Elf32_Sym *sp; + + sp = dynld.dyn.symtab; + sp += ELF32_R_SYM(rp->r_info); + if(ELF32_R_SYM(rp->r_info) && sp->st_value == 0) { +#if 0 + _dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n"); + _dl_wrstderr("Undefined symbol: "); + _dl_wrstderr((char *)dynld.dyn.strtab + + sp->st_name); +#endif + _dl_exit(6); + } + + ra = (Elf32_Addr *)(rp->r_offset + loff); + + RELOC_RELA(rp, sp, ra, loff); + /* + */ + + /* + */ + rp++; + } + + } + /* we have been fully relocated here, so most things no longer + * need the loff adjustment + */ + return; +} + + +void _dl_rtld(elf_object_t *object) { if(object->next) { @@ -320,7 +528,10 @@ _dl_rtld(elf_object_t *object) * Do relocation information first, then GOT. */ _dl_md_reloc(object, DT_REL, DT_RELSZ); + _dl_md_reloc(object, DT_RELA, DT_RELASZ); + /* _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + */ if(_dl_bindnow) { /* XXX Perhaps more checking ? */ _dl_md_reloc_got(object, 1); } @@ -333,7 +544,8 @@ void _dl_call_init(elf_object_t *object) { Elf32_Addr ooff; - Elf32_Sym *sym; + const Elf32_Sym *sym; + static void (*_dl_atexit)(Elf32_Addr) = NULL; if(object->next) { _dl_call_init(object->next); @@ -343,11 +555,82 @@ _dl_call_init(elf_object_t *object) return; } +#if 0 + ooff = _dl_find_symbol("_GLOBAL_.I.__1A", object, &sym, 1, 0); + if (sym) { + if(_dl_debug) + _dl_printf("ctor func %x of %x\n", sym->st_value, ooff); + (*(void (*)(void))(sym->st_value + ooff))(); + } + ooff = _dl_find_symbol("_GLOBAL_.D.__1A", object, &sym, 1, 1); + if (sym) { + Elf32_Addr dtor_func = sym->st_value + ooff; + + /* cannot call atexit directly from ld.so ?? */ + ooff = _dl_find_symbol("atexit", _dl_objects, &sym, 0, 0); + (*(void (*)(Elf32_Addr))(sym->st_value + ooff))(dtor_func); + } +#endif + +#ifdef __powerpc__ +/* For powerpc, the ctors/dtors section is a list of function pointers + * to be called at the appropriate time. These have been relocated + * by the dynamic relocations before as necessary. At this time, + * it is just necessary to call all of the ctors functions + * and set up the dtors functions to be called at exit (using atexit). + * Is requiring libc for atexit a problem? + */ + sym = 0; + ooff = _dl_find_symbol("__CTOR_LIST__", object, &sym, 1, 1); + if(sym) { + int i = 1; + typedef void *voidfunc(void) ; + voidfunc **func; + func = (voidfunc **)(sym->st_value + ooff); + for (i=1; func[i] != NULL; i++) { + if(_dl_debug) { + _dl_printf("ctor func %x\n", func[i]); + } + (func[i])(); + } + } + /* Once atexit() is found, do not bother to look it up again. + * the same atexit() should be used for all libraries. + */ + if (_dl_atexit == NULL) { + ooff = _dl_find_symbol("atexit", _dl_objects, &sym, 0, 0); + if (sym) { + _dl_atexit = (void (*)(Elf32_Addr)) + (sym->st_value + ooff); + if(_dl_debug) { + _dl_printf("_dl_atexit at %x\n", _dl_atexit); + } + } + } + /* if atexit() is not found, dtors cannot be run */ + if (_dl_atexit != NULL) { + sym = 0; + ooff = _dl_find_symbol("__DTOR_LIST__", object, &sym, 1, 1); + if(sym) { + int i = 1; + typedef void *voidfunc(void) ; + voidfunc **func; + func = (voidfunc **)(sym->st_value + ooff); + for (i=1; func[i] != NULL; i++) { + if(_dl_debug) { + _dl_printf("dtor func %x\n", func[i]); + } + (*_dl_atexit)((Elf32_Addr)func[i]); + } + } + } +#endif +#ifndef __powerpc__ /* XXX We perform relocation of DTOR/CTOR. This is a ld bug problem * XXX that should be fixed. */ sym = 0; - ooff = _dl_find_symbol("__CTOR_LIST__", object, &sym, 1); + ooff = _dl_find_symbol("__CTOR_LIST__", object, &sym, 1, 1); if(sym) { int i = *(int *)(sym->st_value + ooff); while(i--) { @@ -355,7 +638,7 @@ _dl_call_init(elf_object_t *object) } } sym = 0; - ooff = _dl_find_symbol("__DTOR_LIST__", object, &sym, 1); + ooff = _dl_find_symbol("__DTOR_LIST__", object, &sym, 1, 1); if(sym) { int i = *(int *)(sym->st_value + ooff); while(i--) { @@ -368,7 +651,7 @@ _dl_call_init(elf_object_t *object) * XXX Instead we rely on a symbol named '.init' and call it if it exists. */ sym = 0; - ooff = _dl_find_symbol(".init", object, &sym, 1); + ooff = _dl_find_symbol(".init", object, &sym, 1, 1); if(sym) { if(_dl_debug) _dl_printf("calling .init in '%s'\n",object->load_name); @@ -379,10 +662,11 @@ _dl_call_init(elf_object_t *object) (*object->dyn.init)(); } #endif +#endif /* ! __powerpc__ */ object->status |= STAT_INIT_DONE; } -static char * +/* static */ char * _dl_getenv(const char *var, const char **env) { const char *ep; @@ -435,9 +719,11 @@ _dl_malloc(int size) _dl_malloc_pool = (void *)_dl_mmap((void *)0, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_COPY, -1, 0); - if(_dl_malloc_pool == 0) { + if(_dl_malloc_pool == 0 || + _dl_malloc_pool == (void*)0xffffffff ) + { _dl_printf("Dynamic loader failure: malloc.\n"); - _dl_exit(4); + _dl_exit(7); } _dl_malloc_base = _dl_malloc_pool; } |