summaryrefslogtreecommitdiff
path: root/libexec/ld.so
diff options
context:
space:
mode:
authorDale S. Rahn <rahnds@cvs.openbsd.org>2000-09-11 02:36:38 +0000
committerDale S. Rahn <rahnds@cvs.openbsd.org>2000-09-11 02:36:38 +0000
commitdc054feed4dd1591c58aa1447c73a38dba77f6d4 (patch)
treea73435ac60e5ceb6d475d87f96f4754f4da6217f /libexec/ld.so
parentbdefb08c423d5d41fd2f35e0f1b7a38affd18764 (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.c502
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;
}