diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-05-01 14:20:45 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-05-01 14:20:45 +0000 |
commit | b7bc129184a23d4c9c70774362f4eeaa5e0b44c8 (patch) | |
tree | f42053a86d7e4f8c156663b4c9c791deef7e2ef5 | |
parent | 22a9e5bbdf43e1086d80341480d0601ee9c6f898 (diff) |
Yet another major rework. This time around, rework it to no longer
use linux kernel header files.
-Erik
-rw-r--r-- | ldso/ldso/boot1.c | 1579 | ||||
-rw-r--r-- | ldso/ldso/dl-elf.c | 990 | ||||
-rw-r--r-- | ldso/ldso/dl-hash.c | 400 | ||||
-rw-r--r-- | ldso/ldso/hash.c | 400 | ||||
-rw-r--r-- | ldso/ldso/hash.h | 2 | ||||
-rw-r--r-- | ldso/ldso/i386/dl-syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/i386/elfinterp.c | 475 | ||||
-rw-r--r-- | ldso/ldso/i386/ld_syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/i386/syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/ld-uClibc.c | 1579 | ||||
-rw-r--r-- | ldso/ldso/ld_hash.h | 2 | ||||
-rw-r--r-- | ldso/ldso/ld_string.h | 2 | ||||
-rw-r--r-- | ldso/ldso/ld_syscall.h | 2 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 1579 | ||||
-rw-r--r-- | ldso/ldso/linuxelf.h | 200 | ||||
-rw-r--r-- | ldso/ldso/m68k/dl-syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/m68k/elfinterp.c | 54 | ||||
-rw-r--r-- | ldso/ldso/m68k/ld_syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/m68k/syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/readelflib1.c | 990 | ||||
-rw-r--r-- | ldso/ldso/sparc/dl-syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/sparc/elfinterp.c | 58 | ||||
-rw-r--r-- | ldso/ldso/sparc/ld_syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/sparc/syscalls.h | 1 | ||||
-rw-r--r-- | ldso/ldso/string.h | 2 | ||||
-rw-r--r-- | ldso/ldso/syscall.h | 2 | ||||
-rw-r--r-- | ldso/ldso/vsprintf.c | 1 |
27 files changed, 4165 insertions, 4161 deletions
diff --git a/ldso/ldso/boot1.c b/ldso/ldso/boot1.c index 3b613fb87..948a6e159 100644 --- a/ldso/ldso/boot1.c +++ b/ldso/ldso/boot1.c @@ -92,17 +92,12 @@ * can transfer control to the user's application. */ +#include <sys/mman.h> // For MAP_ANONYMOUS -- differs between platforms #include <stdarg.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/unistd.h> -#include <linux/elf.h> -#include <linux/mman.h> +#include "elf.h" #include "link.h" - #include "sysdep.h" #include "hash.h" -#include "linuxelf.h" #include "syscall.h" #include "string.h" @@ -110,24 +105,24 @@ #define ALLOW_ZERO_PLTGOT -static char * _dl_malloc_addr, *_dl_mmap_zero; -char * _dl_library_path = 0; /* Where we look for libraries */ -char *_dl_preload = 0; /* Things to be loaded before the libs. */ +static char *_dl_malloc_addr, *_dl_mmap_zero; +char *_dl_library_path = 0; /* Where we look for libraries */ +char *_dl_preload = 0; /* Things to be loaded before the libs. */ char *_dl_progname = "/lib/ld-linux-uclibc.so.1"; -static char * _dl_not_lazy = 0; -static char * _dl_warn = 0; /* Used by ldd */ -static char * _dl_trace_loaded_objects = 0; -static int (*_dl_elf_main)(int, char **, char**); +static char *_dl_not_lazy = 0; +static char *_dl_warn = 0; /* Used by ldd */ +static char *_dl_trace_loaded_objects = 0; +static int (*_dl_elf_main) (int, char **, char **); -static int (*_dl_elf_init)(void); +static int (*_dl_elf_init) (void); -void * (*_dl_malloc_function)(int size) = NULL; +void *(*_dl_malloc_function) (int size) = NULL; -struct r_debug * _dl_debug_addr = NULL; +struct r_debug *_dl_debug_addr = NULL; -unsigned int * _dl_brkp; +unsigned int *_dl_brkp; -unsigned int * _dl_envp; +unsigned int *_dl_envp; #define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) /* @@ -151,19 +146,10 @@ unsigned int * _dl_envp; RESULT = hash; \ } extern int _dl_linux_resolve(void); -extern char * _dl_strdup(const char *); -extern char * _dl_getenv(char * symbol, char ** envp); -extern void _dl_unsetenv(char * symbol, char ** envp); -extern int _dl_fixup(struct elf_resolve * tpnt); - -/* - * Datatype of a relocation on this platform - */ -#ifdef ELF_USES_RELOCA -typedef struct elf32_rela ELF_RELOC; -#else -typedef struct elf32_rel ELF_RELOC; -#endif +extern char *_dl_strdup(const char *); +extern char *_dl_getenv(char *symbol, char **envp); +extern void _dl_unsetenv(char *symbol, char **envp); +extern int _dl_fixup(struct elf_resolve *tpnt); /* * This stub function is used by some debuggers. The idea is that they @@ -172,71 +158,72 @@ typedef struct elf32_rel ELF_RELOC; */ void _dl_debug_state() { - return; + return; } void _dl_boot(int args); -void _dl_boot(int args){ - unsigned int argc; - char ** argv, ** envp; - int status; - - unsigned int load_addr; - unsigned int * got; - unsigned int * aux_dat; - int goof = 0; - struct elfhdr * header; - struct elf_resolve * tpnt; - struct dyn_elf * rpnt; - struct elf_resolve * app_tpnt; - unsigned int brk_addr; - unsigned int dl_data[AT_EGID+1]; - unsigned char * malloc_buffer, *mmap_zero; - int (*_dl_atexit)(void *); - int * lpnt; - struct dynamic * dpnt; - unsigned int *hash_addr; - struct r_debug * debug_addr; - unsigned int *chains; - int indx; - int _dl_secure; - - /* First obtain the information on the stack that tells us more about - what binary is loaded, where it is loaded, etc, etc */ - - GET_ARGV(aux_dat, args); - argc = *(aux_dat - 1); - argv = (char **) aux_dat; - aux_dat += argc; /* Skip over the argv pointers */ - aux_dat++; /* Skip over NULL at end of argv */ - envp = (char **) aux_dat; - while(*aux_dat) aux_dat++; /* Skip over the envp pointers */ - aux_dat++; /* Skip over NULL at end of envp */ - dl_data[AT_UID] = -1; /* check later to see if it is changed */ - while(*aux_dat) - { - unsigned int * ad1; - ad1 = aux_dat + 1; - if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1; - aux_dat += 2; - } - - /* Next, locate the GOT */ - - load_addr = dl_data[AT_BASE]; - - GET_GOT(got); - dpnt = (struct dynamic *) (*got + load_addr); - - /* OK, time for another hack. Now call mmap to get a page of writable - memory that can be used for a temporary malloc. We do not know brk - yet, so we cannot use real malloc. */ - - { - /* This hack is to work around a suspected asm bug in gcc-2.7.0 */ - //int zfileno; -//#define ZFILENO ((-1 & (~zfileno)) | zfileno) +void _dl_boot(int args) +{ + unsigned int argc; + char **argv, **envp; + int status; + + unsigned int load_addr; + unsigned int *got; + unsigned int *aux_dat; + int goof = 0; + elfhdr *header; + struct elf_resolve *tpnt; + struct dyn_elf *rpnt; + struct elf_resolve *app_tpnt; + unsigned int brk_addr; + unsigned int dl_data[AT_EGID + 1]; + unsigned char *malloc_buffer, *mmap_zero; + int (*_dl_atexit) (void *); + int *lpnt; + Elf32_Dyn *dpnt; + unsigned int *hash_addr; + struct r_debug *debug_addr; + unsigned int *chains; + int indx; + int _dl_secure; + + /* First obtain the information on the stack that tells us more about + what binary is loaded, where it is loaded, etc, etc */ + + GET_ARGV(aux_dat, args); + argc = *(aux_dat - 1); + argv = (char **) aux_dat; + aux_dat += argc; /* Skip over the argv pointers */ + aux_dat++; /* Skip over NULL at end of argv */ + envp = (char **) aux_dat; + while (*aux_dat) + aux_dat++; /* Skip over the envp pointers */ + aux_dat++; /* Skip over NULL at end of envp */ + dl_data[AT_UID] = -1; /* check later to see if it is changed */ + while (*aux_dat) + { + unsigned int *ad1; + + ad1 = aux_dat + 1; + if (*aux_dat <= AT_EGID) + dl_data[*aux_dat] = *ad1; + aux_dat += 2; + } + + /* Next, locate the GOT */ + + load_addr = dl_data[AT_BASE]; + + GET_GOT(got); + dpnt = (Elf32_Dyn *) (*got + load_addr); + + /* OK, time for another hack. Now call mmap to get a page of writable + memory that can be used for a temporary malloc. We do not know brk + yet, so we cannot use real malloc. */ + + { #define ZFILENO -1 #ifndef MAP_ANONYMOUS @@ -247,178 +234,195 @@ void _dl_boot(int args){ #endif #endif - /* See if we need to relocate this address */ - mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); - if(_dl_mmap_check_error(mmap_zero)) { - SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); - _dl_exit(13); - } - } - - tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _dl_memset (tpnt, 0, sizeof (*tpnt)); - app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _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)); - REALIGN(); - _dl_memset (debug_addr, 0, sizeof (*debug_addr)); - - /* OK, that was easy. Next scan the DYNAMIC section of the image. - We are only doing ourself right now - we will have to do the rest later */ - - while(dpnt->d_tag) - { - tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) - if(ppnt->p_type == PT_DYNAMIC) { - dpnt = (struct dynamic *) ppnt->p_vaddr; - while(dpnt->d_tag) - { - if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; } - app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - } - } - - /* Get some more of the information that we will need to dynamicly link - this module to itself */ - - hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr); - tpnt->nbucket = *hash_addr++; - tpnt->nchain = *hash_addr++; - tpnt->elf_buckets = hash_addr; - hash_addr += tpnt->nbucket; - chains = hash_addr; - - /* Ugly, ugly. We need to call mprotect to change the protection of - the text pages so that we can do the dynamic linking. We can set the - protection back again once we are done */ - - { - struct elf_phdr * ppnt; - int i; - - /* First cover the shared library/dynamic linker. */ - if(tpnt->dynamic_info[DT_TEXTREL]) { - header = (struct elfhdr *) dl_data[AT_BASE]; - ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); - for(i=0; i<header->e_phnum ; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - - /* Now cover the application program. */ - if(app_tpnt->dynamic_info[DT_TEXTREL]) { - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - } - - /* OK, now do the relocations. We do not do a lazy binding here, so - that once we are done, we have considerably more flexibility. */ - - goof = 0; - for(indx=0; indx < 2; indx++) - { - int i; - ELF_RELOC * rpnt; - unsigned int * reloc_addr; - unsigned int symbol_addr; - int symtab_index; - unsigned int rel_addr, rel_size; - - -#ifdef ELF_USES_RELOCA - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]); -#else - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]); -#endif + /* See if we need to relocate this address */ + mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void *) 0, 4096, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); + if (_dl_mmap_check_error(mmap_zero)) { + SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); + _dl_exit(13); + } + } + tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(tpnt, 0, sizeof(*tpnt)); + app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(app_tpnt, 0, sizeof(*app_tpnt)); - if(!rel_addr) continue; + /* + * This is used by gdb to locate the chain of shared libraries that are currently loaded. + */ + debug_addr = DL_MALLOC(sizeof(struct r_debug)); + REALIGN(); + _dl_memset(debug_addr, 0, sizeof(*debug_addr)); + + /* OK, that was easy. Next scan the DYNAMIC section of the image. + We are only doing ourself right now - we will have to do the rest later */ + + while (dpnt->d_tag) { + tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } - /* Now parse the relocation information */ - rpnt = (ELF_RELOC *) (rel_addr + load_addr); - for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){ - reloc_addr = (int *) (load_addr + (int)rpnt->r_offset); - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - if(symtab_index) { - char * strtab; - struct elf32_sym * symtab; + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) + if (ppnt->p_type == PT_DYNAMIC) { + dpnt = (Elf32_Dyn *) ppnt->p_vaddr; + while (dpnt->d_tag) { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_DEBUG) + dpnt->d_un.d_val = (int) debug_addr; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + app_tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + } + } - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr); + /* Get some more of the information that we will need to dynamicly link + this module to itself */ - /* We only do a partial dynamic linking right now. The user - is not supposed to redefine any symbols that start with - a '_', so we can do this with confidence. */ + hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH] + load_addr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + chains = hash_addr; - if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue; + /* Ugly, ugly. We need to call mprotect to change the protection of + the text pages so that we can do the dynamic linking. We can set the + protection back again once we are done */ - symbol_addr = load_addr + symtab[symtab_index].st_value; + { + elf_phdr *ppnt; + int i; + + /* First cover the shared library/dynamic linker. */ + if (tpnt->dynamic_info[DT_TEXTREL]) { + header = (elfhdr *) dl_data[AT_BASE]; + ppnt = (elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); + for (i = 0; i < header->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (load_addr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } - if(!symbol_addr) { - /* - * This will segfault - you cannot call a function until - * we have finished the relocations. - */ - SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol "); - SEND_STDERR(strtab + symtab[symtab_index].st_name); - SEND_STDERR(" undefined.\n"); - goof++; - } + /* Now cover the application program. */ + if (app_tpnt->dynamic_info[DT_TEXTREL]) { + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } } - /* - * Use this machine-specific macro to perform the actual relocation. - */ - PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); - } - } - if (goof) _dl_exit(14); + /* OK, now do the relocations. We do not do a lazy binding here, so + that once we are done, we have considerably more flexibility. */ + + goof = 0; + for (indx = 0; indx < 2; indx++) { + int i; + ELF_RELOC *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + int symtab_index; + unsigned int rel_addr, rel_size; + + +#ifdef ELF_USES_RELOCA + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_RELA]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELASZ]); +#else + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_REL]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELSZ]); +#endif + - /* OK, at this point we have a crude malloc capability. Start to build - the tables of the modules that are required for this beast to run. - We start with the basic executable, and then go from there. Eventually - we will run across ourself, and we will need to properly deal with that - as well. */ + if (!rel_addr) + continue; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) (rel_addr + load_addr); + for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) { + reloc_addr = (int *) (load_addr + (int) rpnt->r_offset); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + if (symtab_index) { + char *strtab; + Elf32_Sym *symtab; + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + + load_addr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr); + + /* We only do a partial dynamic linking right now. The user + is not supposed to redefine any symbols that start with + a '_', so we can do this with confidence. */ + + if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + + symbol_addr = load_addr + symtab[symtab_index].st_value; + + if (!symbol_addr) { + /* + * This will segfault - you cannot call a function until + * we have finished the relocations. + */ + SEND_STDERR("ELF dynamic loader - unable to " + "self-bootstrap - symbol "); + SEND_STDERR(strtab + symtab[symtab_index].st_name); + SEND_STDERR(" undefined.\n"); + goof++; + } + } + /* + * Use this machine-specific macro to perform the actual relocation. + */ + PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); + } + } + + if (goof) { + _dl_exit(14); + } - _dl_malloc_addr = malloc_buffer; + /* OK, at this point we have a crude malloc capability. Start to build + the tables of the modules that are required for this beast to run. + We start with the basic executable, and then go from there. Eventually + we will run across ourself, and we will need to properly deal with that + as well. */ - _dl_mmap_zero = mmap_zero; + _dl_malloc_addr = malloc_buffer; + + _dl_mmap_zero = mmap_zero; /* tpnt = _dl_malloc(sizeof(struct elf_resolve)); */ /* Now we have done the mandatory linking of some things. We are now @@ -426,573 +430,594 @@ void _dl_boot(int args){ fixed up by now. Still no function calls outside of this library , since the dynamic resolver is not yet ready. */ - lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); - INIT_GOT(lpnt, tpnt); - - /* OK, this was a big step, now we need to scan all of the user images - and load them properly. */ - - tpnt->next = 0; - tpnt->libname = 0; - tpnt->libtype = program_interpreter; - - { struct elfhdr * epnt; - struct elf_phdr * ppnt; - int i; - - epnt = (struct elfhdr *) dl_data[AT_BASE]; - tpnt->n_phent = epnt->e_phnum; - tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff); - for(i=0;i < epnt->e_phnum; i++, ppnt++){ - if(ppnt->p_type == PT_DYNAMIC) { - tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; - tpnt->dynamic_size = ppnt->p_filesz; - } - } - } - - tpnt->chains = chains; - tpnt->loadaddr = (char *) load_addr; - - brk_addr = 0; - rpnt = NULL; - - /* At this point we are now free to examine the user application, - and figure out which libraries are supposed to be called. Until - we have this list, we will not be completely ready for dynamic linking */ - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD) { - if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) - brk_addr = ppnt->p_vaddr + ppnt->p_memsz; - } - if(ppnt->p_type == PT_DYNAMIC) { + lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); + INIT_GOT(lpnt, tpnt); + + /* OK, this was a big step, now we need to scan all of the user images + and load them properly. */ + + tpnt->next = 0; + tpnt->libname = 0; + tpnt->libtype = program_interpreter; + + { + elfhdr *epnt; + elf_phdr *ppnt; + int i; + + epnt = (elfhdr *) dl_data[AT_BASE]; + tpnt->n_phent = epnt->e_phnum; + tpnt->ppnt = ppnt = (elf_phdr *) (load_addr + epnt->e_phoff); + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_DYNAMIC) { + tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; + tpnt->dynamic_size = ppnt->p_filesz; + } + } + } + + tpnt->chains = chains; + tpnt->loadaddr = (char *) load_addr; + + brk_addr = 0; + rpnt = NULL; + + /* At this point we are now free to examine the user application, + and figure out which libraries are supposed to be called. Until + we have this list, we will not be completely ready for dynamic linking */ + + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD) { + if (ppnt->p_vaddr + ppnt->p_memsz > brk_addr) + brk_addr = ppnt->p_vaddr + ppnt->p_memsz; + } + if (ppnt->p_type == PT_DYNAMIC) { #ifndef ALLOW_ZERO_PLTGOT - /* make sure it's really there. */ - if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue; + /* make sure it's really there. */ + if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) + continue; #endif - /* OK, we have what we need - slip this one into the list. */ - app_tpnt = _dl_add_elf_hash_table("", 0, - app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); - _dl_loaded_modules->libtype = elf_executable; - _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; - _dl_symbol_tables = rpnt = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*rpnt)); - rpnt->dyn = _dl_loaded_modules; - app_tpnt->usage_count++; - app_tpnt->symbol_scope = _dl_symbol_tables; - lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); + /* OK, we have what we need - slip this one into the list. */ + app_tpnt = _dl_add_elf_hash_table("", 0, + app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); + _dl_loaded_modules->libtype = elf_executable; + _dl_loaded_modules->ppnt = (elf_phdr *) dl_data[AT_PHDR]; + _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; + _dl_symbol_tables = rpnt = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*rpnt)); + rpnt->dyn = _dl_loaded_modules; + app_tpnt->usage_count++; + app_tpnt->symbol_scope = _dl_symbol_tables; + lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); #ifdef ALLOW_ZERO_PLTGOT - if (lpnt) + if (lpnt) #endif - INIT_GOT(lpnt, _dl_loaded_modules); - } - if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have - this before */ - tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000)); - } - } - } - - if (argv[0]) - _dl_progname = argv[0]; - - /* Now we need to figure out what kind of options are selected. - Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ - { - _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp); - - if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) || - (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] && - dl_data[AT_GID] == dl_data[AT_EGID])) - { - _dl_secure = 0; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp); - } - else - { - _dl_secure = 1; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_unsetenv("LD_AOUT_PRELOAD", envp); - _dl_unsetenv("LD_LIBRARY_PATH", envp); - _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); - _dl_library_path = NULL; - } - } - - _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); - - /* OK, we now have the application in the list, and we have some - basic stuff in place. Now search through the list for other shared - libraries that should be loaded, and insert them on the list in the - correct order. */ + INIT_GOT(lpnt, _dl_loaded_modules); + } + if (ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not + have this before */ + tpnt->libname = _dl_strdup((char *) ppnt->p_offset + + (dl_data[AT_PHDR] & 0xfffff000)); + } + } + } + + if (argv[0]) { + _dl_progname = argv[0]; + } + + /* Now we need to figure out what kind of options are selected. + Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ + { + _dl_not_lazy = _dl_getenv("LD_BIND_NOW", envp); + + if ((dl_data[AT_UID] == -1 && _dl_suid_ok()) || + (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] + && dl_data[AT_GID] == dl_data[AT_EGID])) { + _dl_secure = 0; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp); + } else { + _dl_secure = 1; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_unsetenv("LD_AOUT_PRELOAD", envp); + _dl_unsetenv("LD_LIBRARY_PATH", envp); + _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); + _dl_library_path = NULL; + } + } + + _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); + + /* OK, we now have the application in the list, and we have some + basic stuff in place. Now search through the list for other shared + libraries that should be loaded, and insert them on the list in the + correct order. */ + +#ifdef USE_CACHE + _dl_map_cache(); +#endif + + { + struct elf_resolve *tcurr; + struct elf_resolve *tpnt1; + char *lpnt; + + if (_dl_preload) + { + char c, *str, *str2; + + str = _dl_preload; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + while (*str) + { + str2 = str; + while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') + str2++; + c = *str2; + *str2 = '\0'; + if (!_dl_secure || _dl_strchr(str, '/') == NULL) + { + tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", str); + else { + _dl_fdprintf(2, "%s: can't load " + "library '%s'\n", _dl_progname, str); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + /* this is a real hack to make ldd not print + * the library itself when run on a library. */ + if (_dl_strcmp(_dl_progname, str) != 0) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", + str, tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + *str2 = c; + str = str2; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + } + } + + { + int fd; + struct kernel_stat st; + char *preload; + + if (!_dl_stat(LDSO_PRELOAD, &st)) { + if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { + _dl_fdprintf(2, "%s: can't open file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + preload = (caddr_t) _dl_mmap(0, st.st_size + 1, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + _dl_close(fd); + if (preload == (caddr_t) - 1) { + _dl_fdprintf(2, "%s: can't map file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + char c, *cp, *cp2; + + /* convert all separators and comments to spaces */ + for (cp = preload; *cp; /*nada */ ) { + if (*cp == ':' || *cp == '\t' || *cp == '\n') { + *cp++ = ' '; + } else if (*cp == '#') { + do + *cp++ = ' '; + while (*cp != '\n' && *cp != '\0'); + } else { + cp++; + } + } + + /* find start of first library */ + for (cp = preload; *cp && *cp == ' '; cp++) + /*nada */ ; + + while (*cp) { + /* find end of library */ + for (cp2 = cp; *cp && *cp != ' '; cp++) + /*nada */ ; + c = *cp; + *cp = '\0'; + + tpnt1 = _dl_load_shared_library(0, NULL, cp2); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not " + "found\n", cp2); + else { + _dl_fdprintf(2, "%s: can't " + "load library '%s'\n", + _dl_progname, cp2); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + _dl_fdprintf(1, "\t%s => %s " + "(0x%x)\n", cp2, + tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, + sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + + /* find start of next library */ + *cp = c; + for ( /*nada */ ; *cp && *cp == ' '; cp++) + /*nada */ ; + } + + _dl_munmap(preload, st.st_size + 1); + } + } + } + } + + for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) { + for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; + dpnt++) { + if (dpnt->d_tag == DT_NEEDED) { + lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + + dpnt->d_un.d_val; + if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) { + struct elf_resolve *ttmp; + + ttmp = _dl_loaded_modules; + while (ttmp->next) + ttmp = ttmp->next; + ttmp->next = tpnt; + tpnt->prev = ttmp; + tpnt->next = NULL; + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + rpnt->dyn = tpnt; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt = NULL; + continue; + } + if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", lpnt); + else { + _dl_fdprintf(2, "%s: can't load library '%s'\n", + _dl_progname, lpnt); + _dl_exit(16); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, + tpnt1->libname, (unsigned) tpnt1->loadaddr); + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + } + } + } #ifdef USE_CACHE - _dl_map_cache(); + _dl_unmap_cache(); #endif - { - struct elf_resolve *tcurr; - struct elf_resolve *tpnt1; - char *lpnt; - - if (_dl_preload) { - char c, *str, *str2; - - str = _dl_preload; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - while (*str) { - str2 = str; - while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') - str2++; - c = *str2; - *str2 = '\0'; - if (!_dl_secure || _dl_strchr(str, '/') == NULL) { - tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", str); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, str); - _dl_exit(15); - } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) { - /* this is a real hack to make ldd not print the - library itself when run on a library. */ - if (_dl_strcmp(_dl_progname, str) != 0) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - } - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + /* ldd uses uses this. I am not sure how you pick up the other flags */ + if (_dl_trace_loaded_objects) { + _dl_warn = _dl_getenv("LD_WARN", envp); + if (!_dl_warn) + _dl_exit(0); } - *str2 = c; - str = str2; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - } - } - - { - int fd; - struct kernel_stat st; - char *preload; - - if (!_dl_stat(LDSO_PRELOAD, &st)) { - if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { - _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fd, 0); - _dl_close (fd); - if (preload == (caddr_t)-1) { - _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - char c, *cp, *cp2; - - /* convert all separators and comments to spaces */ - for (cp = preload; *cp; /*nada*/) { - if (*cp == ':' || *cp == '\t' || *cp == '\n') { - *cp++ = ' '; - } else if (*cp == '#') { - do - *cp++ = ' '; - while (*cp != '\n' && *cp != '\0'); - } else { - cp++; - } - } - - /* find start of first library */ - for (cp = preload; *cp && *cp == ' '; cp++) - /*nada*/; - - while (*cp) { - /* find end of library */ - for (cp2 = cp; *cp && *cp != ' '; cp++) - /*nada*/; - c = *cp; - *cp = '\0'; - - tpnt1 = _dl_load_shared_library(0, NULL, cp2); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", cp2); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, cp2); - _dl_exit(15); + + /* + * If the program interpreter is not in the module chain, add it. This will + * be required for dlopen to be able to access the internal functions in the + * dynamic linker. + */ + if (tpnt) { + struct elf_resolve *tcurr; + + tcurr = _dl_loaded_modules; + if (tcurr) + while (tcurr->next) + tcurr = tcurr->next; + tpnt->next = NULL; + tpnt->usage_count++; + + if (tcurr) { + tcurr->next = tpnt; + tpnt->prev = tcurr; + } else { + _dl_loaded_modules = tpnt; + tpnt->prev = NULL; } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } - - /* find start of next library */ - *cp = c; - for (/*nada*/; *cp && *cp == ' '; cp++) - /*nada*/; - } - - _dl_munmap(preload, st.st_size+1); - } + if (rpnt) { + rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + } else { + rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*(rpnt->next))); + } + rpnt->dyn = tpnt; + tpnt = NULL; } - } - } - - for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) - { - for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++) - { - if(dpnt->d_tag == DT_NEEDED) + + /* + * OK, now all of the kids are tucked into bed in their proper addresses. + * Now we go through and look for REL and RELA records that indicate fixups + * to the GOT tables. We need to do this in reverse order so that COPY + * directives work correctly */ + + + goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; + + + /* Some flavors of SVr4 do not generate the R_*_COPY directive, + and we have to manually search for entries that require fixups. + Solaris gets this one right, from what I understand. */ + + + if (_dl_symbol_tables) + goof += _dl_copy_fixups(_dl_symbol_tables); + + if (goof || _dl_trace_loaded_objects) + _dl_exit(0); + + /* OK, at this point things are pretty much ready to run. Now we + need to touch up a few items that are required, and then + we can let the user application have at it. Note that + the dynamic linker itself is not guaranteed to be fully + dynamicly linked if we are using ld.so.1, so we have to look + up each symbol individually. */ + + + _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); + if (_dl_brkp) + *_dl_brkp = brk_addr; + _dl_envp = + (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); + + if (_dl_envp) + *_dl_envp = (unsigned int) envp; + { - lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + - dpnt->d_un.d_val; - if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) - { - struct elf_resolve * ttmp; - ttmp = _dl_loaded_modules; - while (ttmp->next) - ttmp = ttmp->next; - ttmp->next = tpnt; - tpnt->prev = ttmp; - tpnt->next = NULL; - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - rpnt->dyn = tpnt; - tpnt->usage_count++; - tpnt->symbol_scope = _dl_symbol_tables; - tpnt = NULL; - continue; - } - if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) - { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", lpnt); - else - { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, lpnt); - _dl_exit(16); - } - } - else - { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + int i; + elf_phdr *ppnt; + + /* We had to set the protections of all pages to R/W for dynamic linking. + Set text pages back to R/O */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) + for (ppnt = tpnt->ppnt, i = 0; i < tpnt->n_phent; i++, ppnt++) + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && + tpnt->dynamic_info[DT_TEXTREL]) + _dl_mprotect((void *) (tpnt->loadaddr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + LXFLAGS(ppnt->p_flags)); + } - } - } - } -#ifdef USE_CACHE - _dl_unmap_cache(); -#endif + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - /* ldd uses uses this. I am not sure how you pick up the other flags */ - if(_dl_trace_loaded_objects) - { - _dl_warn = _dl_getenv("LD_WARN", envp); - if (!_dl_warn) _dl_exit(0); - } - - /* - * If the program interpreter is not in the module chain, add it. This will - * be required for dlopen to be able to access the internal functions in the - * dynamic linker. - */ - if(tpnt) { - struct elf_resolve * tcurr; - - tcurr = _dl_loaded_modules; - if (tcurr) - while(tcurr->next) tcurr = tcurr->next; - tpnt->next = NULL; - tpnt->usage_count++; - - if (tcurr) { - tcurr->next = tpnt; - tpnt->prev = tcurr; - } - else { - _dl_loaded_modules = tpnt; - tpnt->prev = NULL; - } - if (rpnt) { - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - } else { - rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*(rpnt->next))); - } - rpnt->dyn = tpnt; - tpnt = NULL; - } - - /* - * OK, now all of the kids are tucked into bed in their proper addresses. - * Now we go through and look for REL and RELA records that indicate fixups - * to the GOT tables. We need to do this in reverse order so that COPY - * directives work correctly */ - - - goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; - - - /* Some flavors of SVr4 do not generate the R_*_COPY directive, - and we have to manually search for entries that require fixups. - Solaris gets this one right, from what I understand. */ - - - if (_dl_symbol_tables) - goof += _dl_copy_fixups(_dl_symbol_tables); - - if(goof || _dl_trace_loaded_objects) _dl_exit(0); - - /* OK, at this point things are pretty much ready to run. Now we - need to touch up a few items that are required, and then - we can let the user application have at it. Note that - the dynamic linker itself is not guaranteed to be fully - dynamicly linked if we are using ld.so.1, so we have to look - up each symbol individually. */ - - - _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); - if (_dl_brkp) *_dl_brkp = brk_addr; - _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); - - if (_dl_envp) *_dl_envp = (unsigned int) envp; - - { - int i; - struct elf_phdr * ppnt; - - /* We had to set the protections of all pages to R/W for dynamic linking. - Set text pages back to R/O */ - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++) - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && - tpnt->dynamic_info[DT_TEXTREL]) - _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - LXFLAGS(ppnt->p_flags)); - - } - - _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - - /* - * OK, fix one more thing - set up the debug_addr structure to point - * to our chain. Later we may need to fill in more fields, but this - * should be enough for now. - */ - debug_addr->r_map = (struct link_map *) _dl_loaded_modules; - debug_addr->r_version = 1; - debug_addr->r_ldbase = load_addr; - debug_addr->r_brk = (unsigned long) &_dl_debug_state; - _dl_debug_addr = debug_addr; - debug_addr->r_state = RT_CONSISTENT; - /* This is written in this funny way to keep gcc from inlining the - function call. */ - ((void (*)(void))debug_addr->r_brk)(); - - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - { - /* Apparently crt1 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->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]); - (*_dl_elf_init)(); - } - if(_dl_atexit && tpnt->dynamic_info[DT_FINI]) - { - (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); - } + /* + * OK, fix one more thing - set up the debug_addr structure to point + * to our chain. Later we may need to fill in more fields, but this + * should be enough for now. + */ + debug_addr->r_map = (struct link_map *) _dl_loaded_modules; + debug_addr->r_version = 1; + debug_addr->r_ldbase = load_addr; + debug_addr->r_brk = (unsigned long) &_dl_debug_state; + _dl_debug_addr = debug_addr; + debug_addr->r_state = RT_CONSISTENT; + /* This is written in this funny way to keep gcc from inlining the + function call. */ + ((void (*)(void)) debug_addr->r_brk) (); + + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + /* Apparently crt1 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->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]); + (*_dl_elf_init) (); + } + if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) { + (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); + } #undef DL_DEBUG #ifdef DL_DEBUG - else - { - _dl_fdprintf(2, tpnt->libname); - _dl_fdprintf(2, ": "); - if (!_dl_atexit) - _dl_fdprintf(2, "The address is atexit () is 0x0."); - if (!tpnt->dynamic_info[DT_FINI]) - _dl_fdprintf(2, "Invalid .fini section."); - _dl_fdprintf(2, "\n"); - } + else { + _dl_fdprintf(2, tpnt->libname); + _dl_fdprintf(2, ": "); + if (!_dl_atexit) + _dl_fdprintf(2, "The address is atexit () is 0x0."); + if (!tpnt->dynamic_info[DT_FINI]) + _dl_fdprintf(2, "Invalid .fini section."); + _dl_fdprintf(2, "\n"); + } #endif #undef DL_DEBUG - } + } - /* OK we are done here. Turn out the lights, and lock up. */ - _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY]; + /* OK we are done here. Turn out the lights, and lock up. */ + _dl_elf_main = (int (*)(int, char **, char **)) dl_data[AT_ENTRY]; - /* - * Transfer control to the application. - */ - START(); + /* + * Transfer control to the application. + */ + START(); } -int _dl_fixup(struct elf_resolve * tpnt) +int _dl_fixup(struct elf_resolve *tpnt) { - int goof = 0; - if(tpnt->next) goof += _dl_fixup(tpnt->next); + int goof = 0; + + if (tpnt->next) + goof += _dl_fixup(tpnt->next); - if(tpnt->dynamic_info[DT_REL]) { + if (tpnt->dynamic_info[DT_REL]) { #ifdef ELF_USES_RELOCA - _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname); - _dl_exit(17); + _dl_fdprintf(2, "%s: can't handle REL relocation records\n", + _dl_progname); + _dl_exit(17); #else - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL], - tpnt->dynamic_info[DT_RELSZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_REL], tpnt->dynamic_info[DT_RELSZ], 0); #endif - } - if(tpnt->dynamic_info[DT_RELA]) { + } + if (tpnt->dynamic_info[DT_RELA]) { #ifdef ELF_USES_RELOCA - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA], - tpnt->dynamic_info[DT_RELASZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); #else - _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname); - _dl_exit(18); + _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", + _dl_progname); + _dl_exit(18); #endif - } - if(tpnt->dynamic_info[DT_JMPREL]) - { - if (tpnt->init_flag & JMP_RELOCS_DONE) return goof; - tpnt->init_flag |= JMP_RELOCS_DONE; - - if(! _dl_not_lazy || *_dl_not_lazy == 0) - _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - else - goof += _dl_parse_relocation_information(tpnt, - tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - } - return goof; + } + if (tpnt->dynamic_info[DT_JMPREL]) { + if (tpnt->init_flag & JMP_RELOCS_DONE) + return goof; + tpnt->init_flag |= JMP_RELOCS_DONE; + + if (!_dl_not_lazy || *_dl_not_lazy == 0) + _dl_parse_lazy_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + else + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + } + return goof; } -void * _dl_malloc(int size) { - void * retval; - - if(_dl_malloc_function) - return (*_dl_malloc_function)(size); - - if(_dl_malloc_addr-_dl_mmap_zero+size>4096) { - _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(_dl_mmap_check_error(_dl_mmap_zero)) { - _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); - _dl_exit(20); - } - } - retval = _dl_malloc_addr; - _dl_malloc_addr += size; - - /* - * Align memory to 4 byte boundary. Some platforms require this, others - * simply get better performance. - */ - _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); - return retval; +void *_dl_malloc(int size) +{ + void *retval; + + if (_dl_malloc_function) + return (*_dl_malloc_function) (size); + + if (_dl_malloc_addr - _dl_mmap_zero + size > 4096) { + _dl_mmap_zero = _dl_malloc_addr = + (unsigned char *) _dl_mmap((void *) 0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(_dl_mmap_zero)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_exit(20); + } + } + retval = _dl_malloc_addr; + _dl_malloc_addr += size; + + /* + * Align memory to 4 byte boundary. Some platforms require this, others + * simply get better performance. + */ + _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); + return retval; } -char * _dl_getenv(char *symbol, char **envp) +char *_dl_getenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - while ((pnt = *envp++)) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if (!*pnt || *pnt != '=' || *pnt1) - continue; - return pnt+1; - } - return 0; + char *pnt; + char *pnt1; + + while ((pnt = *envp++)) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + continue; + return pnt + 1; + } + return 0; } void _dl_unsetenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - char **newenvp = envp; - for (pnt = *envp; pnt; pnt = *++envp) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if(!*pnt || *pnt != '=' || *pnt1) - *newenvp++ = *envp; - } - *newenvp++ = *envp; - return; + char *pnt; + char *pnt1; + char **newenvp = envp; + + for (pnt = *envp; pnt; pnt = *++envp) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + *newenvp++ = *envp; + } + *newenvp++ = *envp; + return; } -char * _dl_strdup(const char * string){ - char * retval; - int len; +char *_dl_strdup(const char *string) +{ + char *retval; + int len; - len = _dl_strlen(string); - retval = _dl_malloc(len + 1); - _dl_strcpy(retval, string); - return retval; + len = _dl_strlen(string); + retval = _dl_malloc(len + 1); + _dl_strcpy(retval, string); + return retval; } - diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 9d1cd0ff5..d9b900809 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -21,17 +21,11 @@ /* This file contains the helper routines to load an ELF sharable library into memory and add the symbol table info to the chain. */ -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/errno.h> +#include <asm/mman.h> +#include "elf.h" #include "string.h" -/*#include <stdlib.h>*/ -#include <linux/mman.h> -#include <linux/stat.h> #include "hash.h" -#include "linuxelf.h" #include "sysdep.h" -#include <linux/unistd.h> #include "syscall.h" #ifdef USE_CACHE #include "../config.h" @@ -46,80 +40,79 @@ static size_t _dl_cache_size = 0; int _dl_map_cache(void) { - int fd; - struct kernel_stat st; - header_t *header; - libentry_t *libent; - int i, strtabsize; - - if (_dl_cache_addr == (caddr_t)-1) - return -1; - else if (_dl_cache_addr != NULL) - return 0; - - if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) - { - _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE); - _dl_cache_addr = (caddr_t)-1; /* so we won't try again */ - return -1; - } - - _dl_cache_size = st.st_size; - _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ, - MAP_SHARED, fd, 0); - _dl_close (fd); - if (_dl_cache_addr == (caddr_t)-1) - { - _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE); - return -1; - } - - header = (header_t *)_dl_cache_addr; - - if (_dl_cache_size < sizeof (header_t) || - _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) || - _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) || - _dl_cache_size < - (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) || - _dl_cache_addr[_dl_cache_size-1] != '\0') - { - _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); - goto fail; - } - - strtabsize = _dl_cache_size - sizeof (header_t) - - header->nlibs * sizeof (libentry_t); - libent = (libentry_t *)&header[1]; - - for (i = 0; i < header->nlibs; i++) - { - if (libent[i].sooffset >= strtabsize || - libent[i].liboffset >= strtabsize) - { - _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); - goto fail; - } - } - - return 0; - -fail: - _dl_munmap(_dl_cache_addr, _dl_cache_size); - _dl_cache_addr = (caddr_t)-1; - return -1; + int fd; + struct kernel_stat st; + header_t *header; + libentry_t *libent; + int i, strtabsize; + + if (_dl_cache_addr == (caddr_t) - 1) + return -1; + else if (_dl_cache_addr != NULL) + return 0; + + if (_dl_stat(LDSO_CACHE, &st) + || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) { + _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE); + _dl_cache_addr = (caddr_t) - 1; /* so we won't try again */ + return -1; + } + + _dl_cache_size = st.st_size; + _dl_cache_addr = (caddr_t) _dl_mmap(0, _dl_cache_size, PROT_READ, MAP_SHARED, fd, 0); + _dl_close(fd); + if (_dl_cache_addr == (caddr_t) - 1) { + _dl_fdprintf(2, "%s: can't map cache '%s'\n", + _dl_progname, LDSO_CACHE); + return -1; + } + + header = (header_t *) _dl_cache_addr; + + if (_dl_cache_size < sizeof(header_t) || + _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) + || _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) + || _dl_cache_size < + (sizeof(header_t) + header->nlibs * sizeof(libentry_t)) + || _dl_cache_addr[_dl_cache_size - 1] != '\0') + { + _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, + LDSO_CACHE); + goto fail; + } + + strtabsize = _dl_cache_size - sizeof(header_t) - + header->nlibs * sizeof(libentry_t); + libent = (libentry_t *) & header[1]; + + for (i = 0; i < header->nlibs; i++) { + if (libent[i].sooffset >= strtabsize || + libent[i].liboffset >= strtabsize) + { + _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); + goto fail; + } + } + + return 0; + + fail: + _dl_munmap(_dl_cache_addr, _dl_cache_size); + _dl_cache_addr = (caddr_t) - 1; + return -1; } int _dl_unmap_cache(void) { - if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1) - return -1; + if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t) - 1) + return -1; #if 1 - _dl_munmap (_dl_cache_addr, _dl_cache_size); - _dl_cache_addr = NULL; + _dl_munmap(_dl_cache_addr, _dl_cache_size); + _dl_cache_addr = NULL; #endif - return 0; + return 0; } #endif @@ -131,160 +124,182 @@ int _dl_unmap_cache(void) unsigned int _dl_error_number; unsigned int _dl_internal_error_number; -struct elf_resolve * _dl_load_shared_library(int secure, - struct elf_resolve * tpnt, char * full_libname) { - char * pnt, *pnt1, *pnt2; - struct elf_resolve *tpnt1 = NULL; - char mylibname[2050]; - char * libname; - - _dl_internal_error_number = 0; - - /* quick hack to ensure mylibname buffer doesn't overflow. don't - allow full_libname or any directory to be longer than 1024. */ - if (_dl_strlen(full_libname) > 1024) - goto goof; - - pnt = libname = full_libname; - while (*pnt) { - if(*pnt == '/') libname = pnt+1; - pnt++; - } - - /* If the filename has any '/', try it straight and leave it at that. - For IBCS2 compatibility under linux, we substitute the string - /usr/i486-sysv4/lib for /usr/lib in library names. */ - - if (libname != full_libname) { - tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); - if (tpnt1) - return tpnt1; - goto goof; - } - - /* - * The ABI specifies that RPATH is searched before LD_*_PATH or - * the default path of /usr/lib. - * Check in rpath directories - */ - for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { - if (tpnt->libtype == elf_executable) { - pnt1 = (char *)tpnt->dynamic_info[DT_RPATH]; - if(pnt1) { - pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB]; - while(*pnt1){ - pnt2 = mylibname; - while(*pnt1 && *pnt1 != ':') { - if (pnt2 - mylibname < 1024) - *pnt2++ = *pnt1++; - else - pnt1++; - } - if (pnt2 - mylibname >= 1024) - break; - if(pnt2[-1] != '/') *pnt2++ = '/'; - pnt = libname; - while(*pnt) *pnt2++ = *pnt++; - *pnt2++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if(tpnt1) return tpnt1; - if(*pnt1 == ':') pnt1++; +struct elf_resolve *_dl_load_shared_library(int secure, + struct elf_resolve *tpnt, char *full_libname) +{ + char *pnt, *pnt1, *pnt2; + struct elf_resolve *tpnt1 = NULL; + char mylibname[2050]; + char *libname; + + _dl_internal_error_number = 0; + + /* quick hack to ensure mylibname buffer doesn't overflow. don't + allow full_libname or any directory to be longer than 1024. */ + if (_dl_strlen(full_libname) > 1024) + goto goof; + + pnt = libname = full_libname; + while (*pnt) { + if (*pnt == '/') + libname = pnt + 1; + pnt++; } - } - } - } - - - /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ - pnt1 = _dl_library_path; - if (pnt1 && *pnt1) { - while (*pnt1) { - pnt2 = mylibname; - while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') { - if (pnt2 - mylibname < 1024) - *pnt2++ = *pnt1++; - else - pnt1++; - } - if (pnt2 - mylibname >= 1024) - break; - if(pnt2[-1] != '/') *pnt2++ = '/'; - pnt = libname; - while(*pnt) *pnt2++ = *pnt++; - *pnt2++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if(tpnt1) return tpnt1; - if(*pnt1 == ':' || *pnt1 == ';') pnt1++; - } - } - - - /* - * Where should the cache be searched? There is no such concept in the - * ABI, so we have some flexibility here. For now, search it before - * the default path of /usr/lib. - */ + + /* If the filename has any '/', try it straight and leave it at that. + For IBCS2 compatibility under linux, we substitute the string + /usr/i486-sysv4/lib for /usr/lib in library names. */ + + if (libname != full_libname) { + tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); + if (tpnt1) + return tpnt1; + goto goof; + } + + /* + * The ABI specifies that RPATH is searched before LD_*_PATH or + * the default path of /usr/lib. + * Check in rpath directories + */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (tpnt->libtype == elf_executable) { + pnt1 = (char *) tpnt->dynamic_info[DT_RPATH]; + if (pnt1) { + pnt1 += (unsigned int) tpnt->loadaddr + + tpnt->dynamic_info[DT_STRTAB]; + while (*pnt1) { + pnt2 = mylibname; + while (*pnt1 && *pnt1 != ':') { + if (pnt2 - mylibname < 1024) + *pnt2++ = *pnt1++; + else + pnt1++; + } + if (pnt2 - mylibname >= 1024) + break; + if (pnt2[-1] != '/') + *pnt2++ = '/'; + pnt = libname; + while (*pnt) + *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = + _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + if (*pnt1 == ':') + pnt1++; + } + } + } + } + + + /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ + pnt1 = _dl_library_path; + if (pnt1 && *pnt1) { + while (*pnt1) { + pnt2 = mylibname; + while (*pnt1 && *pnt1 != ':' && *pnt1 != ';') { + if (pnt2 - mylibname < 1024) + *pnt2++ = *pnt1++; + else + pnt1++; + } + if (pnt2 - mylibname >= 1024) + break; + if (pnt2[-1] != '/') + *pnt2++ = '/'; + pnt = libname; + while (*pnt) + *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + if (*pnt1 == ':' || *pnt1 == ';') + pnt1++; + } + } + + + /* + * Where should the cache be searched? There is no such concept in the + * ABI, so we have some flexibility here. For now, search it before + * the default path of /usr/lib. + */ #ifdef USE_CACHE - if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1) - { - int i; - header_t *header = (header_t *)_dl_cache_addr; - libentry_t *libent = (libentry_t *)&header[1]; - char *strs = (char *)&libent[header->nlibs]; - - for (i = 0; i < header->nlibs; i++) - { - if ((libent[i].flags == LIB_ELF || - libent[i].flags == LIB_ELF_LIBC5) && - _dl_strcmp(libname, strs+libent[i].sooffset) == 0 && - (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0))) - return tpnt1; - } - } + if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t) - 1) { + int i; + header_t *header = (header_t *) _dl_cache_addr; + libentry_t *libent = (libentry_t *) & header[1]; + char *strs = (char *) &libent[header->nlibs]; + + for (i = 0; i < header->nlibs; i++) { + if ((libent[i].flags == LIB_ELF || + libent[i].flags == LIB_ELF_LIBC5) && + _dl_strcmp(libname, strs + libent[i].sooffset) == 0 && + (tpnt1 = _dl_load_elf_shared_library(secure, + strs + libent[i].liboffset, 0))) + return tpnt1; + } + } #endif #ifdef UCLIBC_DEVEL - /* Check in /usr/<arch>-linux-uclibc/lib */ - pnt1 = UCLIBC_INSTALL_DIR"/lib"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; - + /* Check in /usr/<arch>-linux-uclibc/lib */ + pnt1 = UCLIBC_INSTALL_DIR "/lib"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + #else /* UCLIBC_DEVEL */ - /* Check in /usr/lib */ - pnt1 = "/usr/lib/"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; - - /* Check in /lib */ - /* try "/lib/". */ - pnt1 = "/lib/"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; + /* Check in /usr/lib */ + pnt1 = "/usr/lib/"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + + /* Check in /lib */ + /* try "/lib/". */ + pnt1 = "/lib/"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; #endif /* UCLIBC_DEVEL */ -goof: - /* Well, we shot our wad on that one. All we can do now is punt */ - if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number; - else _dl_error_number = DL_ERROR_NOFILE; - return NULL; + goof: + /* Well, we shot our wad on that one. All we can do now is punt */ + if (_dl_internal_error_number) + _dl_error_number = _dl_internal_error_number; + else + _dl_error_number = DL_ERROR_NOFILE; + return NULL; } /* @@ -295,264 +310,273 @@ goof: //extern _elf_rtbndr(void); -struct elf_resolve * _dl_load_elf_shared_library(int secure, - char * libname, int flag) { - struct elfhdr * epnt; - unsigned int dynamic_addr = 0; - unsigned int dynamic_size = 0; - struct dynamic * dpnt; - struct elf_resolve * tpnt; - struct elf_phdr * ppnt; - int piclib; - char * status; - int flags; - char header[4096]; - int dynamic_info[24]; - int * lpnt; - unsigned int libaddr; - unsigned int minvma=0xffffffff, maxvma=0; - - int i; - int infile; - - /* If this file is already loaded, skip this step */ - tpnt = _dl_check_hashed_files(libname); - if(tpnt) return tpnt; - - /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD), - we don't load the library if it isn't setuid. */ - - if (secure) { - struct kernel_stat st; - if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID)) - return NULL; - } - - libaddr = 0; - infile = _dl_open(libname, O_RDONLY); - if(infile < 0) - { +struct elf_resolve *_dl_load_elf_shared_library(int secure, + char *libname, int flag) +{ + elfhdr *epnt; + unsigned int dynamic_addr = 0; + unsigned int dynamic_size = 0; + Elf32_Dyn *dpnt; + struct elf_resolve *tpnt; + elf_phdr *ppnt; + int piclib; + char *status; + int flags; + char header[4096]; + int dynamic_info[24]; + int *lpnt; + unsigned int libaddr; + unsigned int minvma = 0xffffffff, maxvma = 0; + + int i; + int infile; + + /* If this file is already loaded, skip this step */ + tpnt = _dl_check_hashed_files(libname); + if (tpnt) + return tpnt; + + /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD), + we don't load the library if it isn't setuid. */ + + if (secure) { + struct kernel_stat st; + + if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID)) + return NULL; + } + + libaddr = 0; + infile = _dl_open(libname, O_RDONLY); + if (infile < 0) { #if 0 - /* - * NO! When we open shared libraries we may search several paths. - * it is inappropriate to generate an error here. - */ - _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); + /* + * NO! When we open shared libraries we may search several paths. + * it is inappropriate to generate an error here. + */ + _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); #endif - _dl_internal_error_number = DL_ERROR_NOFILE; - return NULL; - } - - _dl_read(infile, header, sizeof(header)); - epnt = (struct elfhdr *) header; - if (epnt->e_ident[0] != 0x7f || - epnt->e_ident[1] != 'E' || - epnt->e_ident[2] != 'L' || - epnt->e_ident[3] != 'F') { - _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_NOTELF; - _dl_close(infile); - return NULL; - }; - - if((epnt->e_type != ET_DYN) || - (epnt->e_machine != MAGIC1 + _dl_internal_error_number = DL_ERROR_NOFILE; + return NULL; + } + + _dl_read(infile, header, sizeof(header)); + epnt = (elfhdr *) header; + if (epnt->e_ident[0] != 0x7f || + epnt->e_ident[1] != 'E' || + epnt->e_ident[2] != 'L' || + epnt->e_ident[3] != 'F') + { + _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, + libname); + _dl_internal_error_number = DL_ERROR_NOTELF; + _dl_close(infile); + return NULL; + }; + + if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1 #ifdef MAGIC2 - && epnt->e_machine != MAGIC2 + && epnt->e_machine != MAGIC2 #endif - )){ - _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); - _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n", - _dl_progname, libname); - _dl_close(infile); - return NULL; - }; - - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - - piclib = 1; - for(i=0;i < epnt->e_phnum; i++){ - - if(ppnt->p_type == PT_DYNAMIC) { - if (dynamic_addr) - _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n", - _dl_progname, libname); - dynamic_addr = ppnt->p_vaddr; - dynamic_size = ppnt->p_filesz; - }; - - if(ppnt->p_type == PT_LOAD) { - /* See if this is a PIC library. */ - if(i == 0 && ppnt->p_vaddr > 0x1000000) { - piclib = 0; - minvma=ppnt->p_vaddr; + )) + { + _dl_internal_error_number = + (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); + _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET + "\n", _dl_progname, libname); + _dl_close(infile); + return NULL; + }; + + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + + piclib = 1; + for (i = 0; i < epnt->e_phnum; i++) { + + if (ppnt->p_type == PT_DYNAMIC) { + if (dynamic_addr) + _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n", + _dl_progname, libname); + dynamic_addr = ppnt->p_vaddr; + dynamic_size = ppnt->p_filesz; + }; + + if (ppnt->p_type == PT_LOAD) { + /* See if this is a PIC library. */ + if (i == 0 && ppnt->p_vaddr > 0x1000000) { + piclib = 0; + minvma = ppnt->p_vaddr; + } + if (piclib && ppnt->p_vaddr < minvma) { + minvma = ppnt->p_vaddr; + } + if (((unsigned int) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { + maxvma = ppnt->p_vaddr + ppnt->p_memsz; + } + } + ppnt++; + }; + + maxvma = (maxvma + 0xfffU) & ~0xfffU; + minvma = minvma & ~0xffffU; + + flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ; + if (!piclib) + flags |= MAP_FIXED; + + status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma), + maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_close(infile); + return NULL; + }; + libaddr = (unsigned int) status; + flags |= MAP_FIXED; + + /* Get the memory to store the library */ + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + + for (i = 0; i < epnt->e_phnum; i++) { + if (ppnt->p_type == PT_LOAD) { + + /* See if this is a PIC library. */ + if (i == 0 && ppnt->p_vaddr > 0x1000000) { + piclib = 0; + /* flags |= MAP_FIXED; */ + } + + + + if (ppnt->p_flags & PF_W) { + unsigned int map_size; + char *cpnt; + + status = (char *) _dl_mmap((char *) ((piclib ? libaddr : 0) + + (ppnt->p_vaddr & 0xfffff000)), (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile, + ppnt->p_offset & 0x7ffff000); + + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '%s'\n", + _dl_progname, libname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_munmap((char *) libaddr, maxvma - minvma); + _dl_close(infile); + return NULL; + }; + + /* Pad the last page with zeroes. */ + cpnt = (char *) (status + (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz); + while (((unsigned int) cpnt) & 0xfff) + *cpnt++ = 0; + + /* I am not quite sure if this is completely + * correct to do or not, but the basic way that + * we handle bss segments is that we mmap + * /dev/zero if there are any pages left over + * that are not mapped as part of the file */ + + map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000; + if (map_size < ppnt->p_vaddr + ppnt->p_memsz) + status = (char *) _dl_mmap((char *) map_size + + (piclib ? libaddr : 0), + ppnt->p_vaddr + ppnt->p_memsz - map_size, + LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS, -1, 0); + } else + status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + + (piclib ? libaddr : 0), (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, + infile, ppnt->p_offset & 0x7ffff000); + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_munmap((char *) libaddr, maxvma - minvma); + _dl_close(infile); + return NULL; + }; + + /* if(libaddr == 0 && piclib) { + libaddr = (unsigned int) status; + flags |= MAP_FIXED; + }; */ + }; + ppnt++; + }; + _dl_close(infile); + + /* For a non-PIC library, the addresses are all absolute */ + if (piclib) { + dynamic_addr += (unsigned int) libaddr; } - if(piclib && ppnt->p_vaddr < minvma) { - minvma = ppnt->p_vaddr; + + /* + * OK, the ELF library is now loaded into VM in the correct locations + * The next step is to go through and do the dynamic linking (if needed). + */ + + /* Start by scanning the dynamic section to get all of the pointers */ + + if (!dynamic_addr) { + _dl_internal_error_number = DL_ERROR_NODYNAMIC; + _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", + _dl_progname, libname); + return NULL; } - if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { - maxvma = ppnt->p_vaddr + ppnt->p_memsz; + + dpnt = (Elf32_Dyn *) dynamic_addr; + + dynamic_size = dynamic_size / sizeof(Elf32_Dyn); + _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); + for (i = 0; i < dynamic_size; i++) { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + dynamic_info[DT_TEXTREL] = 1; + dpnt++; + }; + + /* If the TEXTREL is set, this means that we need to make the pages + writable before we perform relocations. Do this now. They get set back + again later. */ + + if (dynamic_info[DT_TEXTREL]) { + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) ((piclib ? libaddr : 0) + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } } - } - ppnt++; - }; - - maxvma=(maxvma+0xfffU)&~0xfffU; - minvma=minvma&~0xffffU; - - flags = MAP_PRIVATE /*| MAP_DENYWRITE*/; - if(!piclib) flags |= MAP_FIXED; - - status = (char *) _dl_mmap((char *) (piclib?0:minvma), - maxvma-minvma, - PROT_NONE, - flags | MAP_ANONYMOUS, -1, - 0); - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_close(infile); - return NULL; - }; - libaddr=(unsigned int)status; - flags|=MAP_FIXED; - - /* Get the memory to store the library */ - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - - for(i=0;i < epnt->e_phnum; i++){ - if(ppnt->p_type == PT_LOAD) { - - /* See if this is a PIC library. */ - if(i == 0 && ppnt->p_vaddr > 0x1000000) { - piclib = 0; - /* flags |= MAP_FIXED; */ - } - - - - if(ppnt->p_flags & PF_W) { - unsigned int map_size; - char * cpnt; - - status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) + - (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, - LXFLAGS(ppnt->p_flags), - flags, infile, - ppnt->p_offset & 0x7ffff000); - - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_munmap((char *)libaddr, maxvma-minvma); - _dl_close(infile); - return NULL; + + + tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, + dynamic_addr, dynamic_size); + + tpnt->ppnt = (elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); + tpnt->n_phent = epnt->e_phnum; + + /* + * OK, the next thing we need to do is to insert the dynamic linker into + * the proper entry in the GOT so that the PLT symbols can be properly + * resolved. + */ + + lpnt = (int *) dynamic_info[DT_PLTGOT]; + + if (lpnt) { + lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); + INIT_GOT(lpnt, tpnt); }; - - /* Pad the last page with zeroes. */ - cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz); - while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0; - -/* I am not quite sure if this is completely correct to do or not, but - the basic way that we handle bss segments is that we mmap /dev/zero if - there are any pages left over that are not mapped as part of the file */ - - map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000; - if(map_size < ppnt->p_vaddr + ppnt->p_memsz) - status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0), - ppnt->p_vaddr + ppnt->p_memsz - map_size, - LXFLAGS(ppnt->p_flags), - flags | MAP_ANONYMOUS, -1, 0); - } else - status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + - (piclib?libaddr:0), - (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, - LXFLAGS(ppnt->p_flags), - flags, infile, - ppnt->p_offset & 0x7ffff000); - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_munmap((char *)libaddr, maxvma-minvma); - _dl_close(infile); - return NULL; - }; - /* if(libaddr == 0 && piclib) { - libaddr = (unsigned int) status; - flags |= MAP_FIXED; - }; */ - }; - ppnt++; - }; - _dl_close(infile); - - /* For a non-PIC library, the addresses are all absolute */ - if(piclib) { - dynamic_addr += (unsigned int) libaddr; - } - - /* - * OK, the ELF library is now loaded into VM in the correct locations - * The next step is to go through and do the dynamic linking (if needed). - */ - - /* Start by scanning the dynamic section to get all of the pointers */ - - if(!dynamic_addr) { - _dl_internal_error_number = DL_ERROR_NODYNAMIC; - _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); - return NULL; - } - - dpnt = (struct dynamic *) dynamic_addr; - - dynamic_size = dynamic_size / sizeof(struct dynamic); - _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); - for(i=0; i< dynamic_size; i++){ - if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; } - dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1; - dpnt++; - }; - - /* If the TEXTREL is set, this means that we need to make the pages - writable before we perform relocations. Do this now. They get set back - again later. */ - - if (dynamic_info[DT_TEXTREL]) { - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - for(i=0;i < epnt->e_phnum; i++, ppnt++){ - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - - - tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr, - dynamic_size); - - tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); - tpnt->n_phent = epnt->e_phnum; - - /* - * OK, the next thing we need to do is to insert the dynamic linker into - * the proper entry in the GOT so that the PLT symbols can be properly - * resolved. - */ - - lpnt = (int *) dynamic_info[DT_PLTGOT]; - - if(lpnt) { - lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); - INIT_GOT(lpnt, tpnt); - }; - - return tpnt; + return tpnt; } /* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY @@ -561,28 +585,30 @@ struct elf_resolve * _dl_load_elf_shared_library(int secure, are guaranteed to be generated by a trustworthy linker, then this step can be skipped. */ -int _dl_copy_fixups(struct dyn_elf * rpnt) +int _dl_copy_fixups(struct dyn_elf *rpnt) { - int goof = 0; - struct elf_resolve * tpnt; + int goof = 0; + struct elf_resolve *tpnt; - if(rpnt->next) goof += _dl_copy_fixups(rpnt->next); - else return 0; + if (rpnt->next) + goof += _dl_copy_fixups(rpnt->next); + else + return 0; + + tpnt = rpnt->dyn; + + if (tpnt->init_flag & COPY_RELOCS_DONE) + return goof; + tpnt->init_flag |= COPY_RELOCS_DONE; - tpnt = rpnt->dyn; - - if (tpnt->init_flag & COPY_RELOCS_DONE) return goof; - tpnt->init_flag |= COPY_RELOCS_DONE; - #ifdef ELF_USES_RELOCA - goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA], - tpnt->dynamic_info[DT_RELASZ], 0); + goof += _dl_parse_copy_information(rpnt, + tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); #else - goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL], - tpnt->dynamic_info[DT_RELSZ], 0); + goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL], + tpnt->dynamic_info[DT_RELSZ], 0); #endif - return goof; + return goof; } - diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index 048c27738..fa610e012 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -20,11 +20,7 @@ /* Various symbol table handling functions, including symbol lookup */ -/*#include <stdlib.h>*/ #include "string.h" -#include <linux/unistd.h> -#include <linux/elf.h> - #include "dlfcn.h" #include "hash.h" #include "linuxelf.h" @@ -38,20 +34,20 @@ * as well as all of the other good stuff in the binary. */ -struct elf_resolve * _dl_loaded_modules = NULL; +struct elf_resolve *_dl_loaded_modules = NULL; /* * This is the list of modules that are loaded when the image is first * started. As we add more via dlopen, they get added into other * chains. */ -struct dyn_elf * _dl_symbol_tables = NULL; +struct dyn_elf *_dl_symbol_tables = NULL; /* * This is the list of modules that are loaded via dlopen. We may need * to search these for RTLD_GLOBAL files. */ -struct dyn_elf * _dl_handles = NULL; +struct dyn_elf *_dl_handles = NULL; /* @@ -60,32 +56,35 @@ struct dyn_elf * _dl_handles = NULL; * have. We need it to decode the hash table. */ -unsigned long _dl_elf_hash(const char * name){ - unsigned long hash = 0; - unsigned long tmp; +unsigned long _dl_elf_hash(const char *name) +{ + unsigned long hash = 0; + unsigned long tmp; - while (*name){ - hash = (hash << 4) + *name++; - if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; - hash &= ~tmp; - }; - return hash; + while (*name) { + hash = (hash << 4) + *name++; + if ((tmp = hash & 0xf0000000)) + hash ^= tmp >> 24; + hash &= ~tmp; + }; + return hash; } /* * Check to see if a library has already been added to the hash chain. */ -struct elf_resolve * _dl_check_hashed_files(char * libname){ - struct elf_resolve * tpnt; - int len = _dl_strlen(libname); +struct elf_resolve *_dl_check_hashed_files(char *libname) +{ + struct elf_resolve *tpnt; + int len = _dl_strlen(libname); - for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { - if (_dl_strncmp(tpnt->libname, libname, len) == 0 && - (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.')) - return tpnt; - } + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (_dl_strncmp(tpnt->libname, libname, len) == 0 && + (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.')) + return tpnt; + } - return NULL; + return NULL; } /* @@ -94,48 +93,47 @@ struct elf_resolve * _dl_check_hashed_files(char * libname){ * externals properly. */ -struct elf_resolve * _dl_add_elf_hash_table(char * libname, - char * loadaddr, - unsigned int * dynamic_info, - unsigned int dynamic_addr, - unsigned int dynamic_size){ - unsigned int * hash_addr; - struct elf_resolve * tpnt; - int i; - - if (!_dl_loaded_modules) { - tpnt = _dl_loaded_modules = - (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); - _dl_memset (tpnt, 0, sizeof (*tpnt)); - } - else { - tpnt = _dl_loaded_modules; - while(tpnt->next) tpnt = tpnt->next; - tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); - _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next))); - tpnt->next->prev = tpnt; - tpnt = tpnt->next; - }; - - tpnt->next = NULL; - tpnt->init_flag = 0; - tpnt->libname = _dl_strdup(libname); - tpnt->dynamic_addr = dynamic_addr; - tpnt->dynamic_size = dynamic_size; - tpnt->libtype = loaded_file; - - if( dynamic_info[DT_HASH] != 0 ) - { - hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr); - tpnt->nbucket = *hash_addr++; - tpnt->nchain = *hash_addr++; - tpnt->elf_buckets = hash_addr; - hash_addr += tpnt->nbucket; - tpnt->chains = hash_addr; - } - tpnt->loadaddr = loadaddr; - for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i]; - return tpnt; +struct elf_resolve *_dl_add_elf_hash_table(char *libname, + char *loadaddr, unsigned int *dynamic_info, unsigned int dynamic_addr, + unsigned int dynamic_size) +{ + unsigned int *hash_addr; + struct elf_resolve *tpnt; + int i; + + if (!_dl_loaded_modules) { + tpnt = _dl_loaded_modules = + (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); + _dl_memset(tpnt, 0, sizeof(*tpnt)); + } else { + tpnt = _dl_loaded_modules; + while (tpnt->next) + tpnt = tpnt->next; + tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); + _dl_memset(tpnt->next, 0, sizeof(*(tpnt->next))); + tpnt->next->prev = tpnt; + tpnt = tpnt->next; + }; + + tpnt->next = NULL; + tpnt->init_flag = 0; + tpnt->libname = _dl_strdup(libname); + tpnt->dynamic_addr = dynamic_addr; + tpnt->dynamic_size = dynamic_size; + tpnt->libtype = loaded_file; + + if (dynamic_info[DT_HASH] != 0) { + hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + tpnt->chains = hash_addr; + } + tpnt->loadaddr = loadaddr; + for (i = 0; i < 24; i++) + tpnt->dynamic_info[i] = dynamic_info[i]; + return tpnt; } @@ -144,141 +142,145 @@ struct elf_resolve * _dl_add_elf_hash_table(char * libname, * relocations or when we call an entry in the PLT table for the first time. */ -char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, - unsigned int instr_addr, struct elf_resolve * f_tpnt, - int copyrel){ - struct elf_resolve * tpnt; - int si; - char * pnt; - int pass; - char * strtab; - struct elf32_sym * symtab; - unsigned int elf_hash_number, hn; - char * weak_result; - struct elf_resolve * first_def; - struct dyn_elf * rpnt, first; - char * data_result = 0; /* nakao */ - - weak_result = 0; - elf_hash_number = _dl_elf_hash(name); - - /* A quick little hack to make sure that any symbol in the executable - will be preferred to one in a shared library. This is necessary so - 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) { - first=(*_dl_symbol_tables); - first.next=rpnt1; - rpnt1=(&first); - } - - /* - * The passes are so that we can first search the regular symbols - * for whatever module was specified, and then search anything - * loaded with RTLD_GLOBAL. When pass is 1, it means we are just - * starting the first dlopened module, and anything above that - * is just the next one in the chain. - */ - for(pass = 0; (1==1); pass++) - { - - /* - * If we are just starting to search for RTLD_GLOBAL, setup - * the pointer for the start of the search. - */ - if( pass == 1) { - rpnt1 = _dl_handles; - } - - /* - * Anything after this, we need to skip to the next module. - */ - else if( pass >= 2) { - rpnt1 = rpnt1->next_handle; - } - - /* - * Make sure we still have a module, and make sure that this - * module was loaded with RTLD_GLOBAL. - */ - if( pass != 0 ) - { - if( rpnt1 == NULL ) break; - if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue; +char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, + unsigned int instr_addr, struct elf_resolve *f_tpnt, int copyrel) +{ + struct elf_resolve *tpnt; + int si; + char *pnt; + int pass; + char *strtab; + Elf32_Sym *symtab; + unsigned int elf_hash_number, hn; + char *weak_result; + struct elf_resolve *first_def; + struct dyn_elf *rpnt, first; + char *data_result = 0; /* nakao */ + + weak_result = 0; + elf_hash_number = _dl_elf_hash(name); + + /* A quick little hack to make sure that any symbol in the executable + will be preferred to one in a shared library. This is necessary so + 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) { + first = (*_dl_symbol_tables); + first.next = rpnt1; + rpnt1 = (&first); } - for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); - rpnt; rpnt = rpnt->next) { - tpnt = rpnt->dyn; - - /* - * The idea here is that if we are using dlsym, we want to - * first search the entire chain loaded from dlopen, and - * return a result from that if we found anything. If this - * fails, then we continue the search into the stuff loaded - * when the image was activated. For normal lookups, we start - * with rpnt == NULL, so we should never hit this. - */ - if( tpnt->libtype == elf_executable - && weak_result != 0 ) - { - break; - } - - /* - * Avoid calling .urem here. - */ - do_rem(hn, elf_hash_number, tpnt->nbucket); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + - tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); /* - * This crap is required because the first instance of a - * symbol on the chain will be used for all symbol references. - * Thus this instance must be resolved to an address that - * contains the actual function, + * The passes are so that we can first search the regular symbols + * for whatever module was specified, and then search anything + * loaded with RTLD_GLOBAL. When pass is 1, it means we are just + * starting the first dlopened module, and anything above that + * is just the next one in the chain. */ - - first_def = NULL; - - for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){ - 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) { - - /* Here we make sure that we find a module where the symbol is - * actually defined. - */ - - if(f_tpnt) { - if(!first_def) first_def = tpnt; - if(first_def == f_tpnt && symtab[si].st_shndx == 0) - continue; - } - - switch(ELF32_ST_BIND(symtab[si].st_info)){ - case STB_GLOBAL: - if ( tpnt->libtype != elf_executable - && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */ - data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */ - break; /* nakao */ - } else /* nakao */ - return tpnt->loadaddr + symtab[si].st_value; - case STB_WEAK: - if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value; - break; - default: /* Do local symbols need to be examined? */ - break; - } - } + for (pass = 0; (1 == 1); pass++) { + + /* + * If we are just starting to search for RTLD_GLOBAL, setup + * the pointer for the start of the search. + */ + if (pass == 1) { + rpnt1 = _dl_handles; + } + + /* + * Anything after this, we need to skip to the next module. + */ + else if (pass >= 2) { + rpnt1 = rpnt1->next_handle; + } + + /* + * Make sure we still have a module, and make sure that this + * module was loaded with RTLD_GLOBAL. + */ + if (pass != 0) { + if (rpnt1 == NULL) + break; + if ((rpnt1->flags & RTLD_GLOBAL) == 0) + continue; + } + + for (rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); rpnt; rpnt = rpnt->next) { + tpnt = rpnt->dyn; + + /* + * The idea here is that if we are using dlsym, we want to + * first search the entire chain loaded from dlopen, and + * return a result from that if we found anything. If this + * fails, then we continue the search into the stuff loaded + * when the image was activated. For normal lookups, we start + * with rpnt == NULL, so we should never hit this. + */ + if (tpnt->libtype == elf_executable && weak_result != 0) { + break; + } + + /* + * Avoid calling .urem here. + */ + do_rem(hn, elf_hash_number, tpnt->nbucket); + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + /* + * This crap is required because the first instance of a + * symbol on the chain will be used for all symbol references. + * Thus this instance must be resolved to an address that + * contains the actual function, + */ + + first_def = NULL; + + for (si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]) { + 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) { + + /* Here we make sure that we find a module where the symbol is + * actually defined. + */ + + if (f_tpnt) { + if (!first_def) + first_def = tpnt; + if (first_def == f_tpnt + && symtab[si].st_shndx == 0) + continue; + } + + switch (ELF32_ST_BIND(symtab[si].st_info)) { + case STB_GLOBAL: + if (tpnt->libtype != elf_executable && + ELF32_ST_TYPE(symtab[si].st_info) + == STT_NOTYPE) + { /* nakao */ + data_result = tpnt->loadaddr + + symtab[si].st_value; /* nakao */ + break; /* nakao */ + } else /* nakao */ + return tpnt->loadaddr + symtab[si].st_value; + case STB_WEAK: + if (!weak_result) + weak_result = + tpnt->loadaddr + symtab[si].st_value; + break; + default: /* Do local symbols need to be examined? */ + break; + } + } + } + } } - } - } - if (data_result) return data_result; /* nakao */ - return weak_result; + if (data_result) + return data_result; /* nakao */ + return weak_result; } diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c index 048c27738..fa610e012 100644 --- a/ldso/ldso/hash.c +++ b/ldso/ldso/hash.c @@ -20,11 +20,7 @@ /* Various symbol table handling functions, including symbol lookup */ -/*#include <stdlib.h>*/ #include "string.h" -#include <linux/unistd.h> -#include <linux/elf.h> - #include "dlfcn.h" #include "hash.h" #include "linuxelf.h" @@ -38,20 +34,20 @@ * as well as all of the other good stuff in the binary. */ -struct elf_resolve * _dl_loaded_modules = NULL; +struct elf_resolve *_dl_loaded_modules = NULL; /* * This is the list of modules that are loaded when the image is first * started. As we add more via dlopen, they get added into other * chains. */ -struct dyn_elf * _dl_symbol_tables = NULL; +struct dyn_elf *_dl_symbol_tables = NULL; /* * This is the list of modules that are loaded via dlopen. We may need * to search these for RTLD_GLOBAL files. */ -struct dyn_elf * _dl_handles = NULL; +struct dyn_elf *_dl_handles = NULL; /* @@ -60,32 +56,35 @@ struct dyn_elf * _dl_handles = NULL; * have. We need it to decode the hash table. */ -unsigned long _dl_elf_hash(const char * name){ - unsigned long hash = 0; - unsigned long tmp; +unsigned long _dl_elf_hash(const char *name) +{ + unsigned long hash = 0; + unsigned long tmp; - while (*name){ - hash = (hash << 4) + *name++; - if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; - hash &= ~tmp; - }; - return hash; + while (*name) { + hash = (hash << 4) + *name++; + if ((tmp = hash & 0xf0000000)) + hash ^= tmp >> 24; + hash &= ~tmp; + }; + return hash; } /* * Check to see if a library has already been added to the hash chain. */ -struct elf_resolve * _dl_check_hashed_files(char * libname){ - struct elf_resolve * tpnt; - int len = _dl_strlen(libname); +struct elf_resolve *_dl_check_hashed_files(char *libname) +{ + struct elf_resolve *tpnt; + int len = _dl_strlen(libname); - for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { - if (_dl_strncmp(tpnt->libname, libname, len) == 0 && - (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.')) - return tpnt; - } + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (_dl_strncmp(tpnt->libname, libname, len) == 0 && + (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.')) + return tpnt; + } - return NULL; + return NULL; } /* @@ -94,48 +93,47 @@ struct elf_resolve * _dl_check_hashed_files(char * libname){ * externals properly. */ -struct elf_resolve * _dl_add_elf_hash_table(char * libname, - char * loadaddr, - unsigned int * dynamic_info, - unsigned int dynamic_addr, - unsigned int dynamic_size){ - unsigned int * hash_addr; - struct elf_resolve * tpnt; - int i; - - if (!_dl_loaded_modules) { - tpnt = _dl_loaded_modules = - (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); - _dl_memset (tpnt, 0, sizeof (*tpnt)); - } - else { - tpnt = _dl_loaded_modules; - while(tpnt->next) tpnt = tpnt->next; - tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); - _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next))); - tpnt->next->prev = tpnt; - tpnt = tpnt->next; - }; - - tpnt->next = NULL; - tpnt->init_flag = 0; - tpnt->libname = _dl_strdup(libname); - tpnt->dynamic_addr = dynamic_addr; - tpnt->dynamic_size = dynamic_size; - tpnt->libtype = loaded_file; - - if( dynamic_info[DT_HASH] != 0 ) - { - hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr); - tpnt->nbucket = *hash_addr++; - tpnt->nchain = *hash_addr++; - tpnt->elf_buckets = hash_addr; - hash_addr += tpnt->nbucket; - tpnt->chains = hash_addr; - } - tpnt->loadaddr = loadaddr; - for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i]; - return tpnt; +struct elf_resolve *_dl_add_elf_hash_table(char *libname, + char *loadaddr, unsigned int *dynamic_info, unsigned int dynamic_addr, + unsigned int dynamic_size) +{ + unsigned int *hash_addr; + struct elf_resolve *tpnt; + int i; + + if (!_dl_loaded_modules) { + tpnt = _dl_loaded_modules = + (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); + _dl_memset(tpnt, 0, sizeof(*tpnt)); + } else { + tpnt = _dl_loaded_modules; + while (tpnt->next) + tpnt = tpnt->next; + tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve)); + _dl_memset(tpnt->next, 0, sizeof(*(tpnt->next))); + tpnt->next->prev = tpnt; + tpnt = tpnt->next; + }; + + tpnt->next = NULL; + tpnt->init_flag = 0; + tpnt->libname = _dl_strdup(libname); + tpnt->dynamic_addr = dynamic_addr; + tpnt->dynamic_size = dynamic_size; + tpnt->libtype = loaded_file; + + if (dynamic_info[DT_HASH] != 0) { + hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + tpnt->chains = hash_addr; + } + tpnt->loadaddr = loadaddr; + for (i = 0; i < 24; i++) + tpnt->dynamic_info[i] = dynamic_info[i]; + return tpnt; } @@ -144,141 +142,145 @@ struct elf_resolve * _dl_add_elf_hash_table(char * libname, * relocations or when we call an entry in the PLT table for the first time. */ -char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, - unsigned int instr_addr, struct elf_resolve * f_tpnt, - int copyrel){ - struct elf_resolve * tpnt; - int si; - char * pnt; - int pass; - char * strtab; - struct elf32_sym * symtab; - unsigned int elf_hash_number, hn; - char * weak_result; - struct elf_resolve * first_def; - struct dyn_elf * rpnt, first; - char * data_result = 0; /* nakao */ - - weak_result = 0; - elf_hash_number = _dl_elf_hash(name); - - /* A quick little hack to make sure that any symbol in the executable - will be preferred to one in a shared library. This is necessary so - 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) { - first=(*_dl_symbol_tables); - first.next=rpnt1; - rpnt1=(&first); - } - - /* - * The passes are so that we can first search the regular symbols - * for whatever module was specified, and then search anything - * loaded with RTLD_GLOBAL. When pass is 1, it means we are just - * starting the first dlopened module, and anything above that - * is just the next one in the chain. - */ - for(pass = 0; (1==1); pass++) - { - - /* - * If we are just starting to search for RTLD_GLOBAL, setup - * the pointer for the start of the search. - */ - if( pass == 1) { - rpnt1 = _dl_handles; - } - - /* - * Anything after this, we need to skip to the next module. - */ - else if( pass >= 2) { - rpnt1 = rpnt1->next_handle; - } - - /* - * Make sure we still have a module, and make sure that this - * module was loaded with RTLD_GLOBAL. - */ - if( pass != 0 ) - { - if( rpnt1 == NULL ) break; - if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue; +char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, + unsigned int instr_addr, struct elf_resolve *f_tpnt, int copyrel) +{ + struct elf_resolve *tpnt; + int si; + char *pnt; + int pass; + char *strtab; + Elf32_Sym *symtab; + unsigned int elf_hash_number, hn; + char *weak_result; + struct elf_resolve *first_def; + struct dyn_elf *rpnt, first; + char *data_result = 0; /* nakao */ + + weak_result = 0; + elf_hash_number = _dl_elf_hash(name); + + /* A quick little hack to make sure that any symbol in the executable + will be preferred to one in a shared library. This is necessary so + 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) { + first = (*_dl_symbol_tables); + first.next = rpnt1; + rpnt1 = (&first); } - for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); - rpnt; rpnt = rpnt->next) { - tpnt = rpnt->dyn; - - /* - * The idea here is that if we are using dlsym, we want to - * first search the entire chain loaded from dlopen, and - * return a result from that if we found anything. If this - * fails, then we continue the search into the stuff loaded - * when the image was activated. For normal lookups, we start - * with rpnt == NULL, so we should never hit this. - */ - if( tpnt->libtype == elf_executable - && weak_result != 0 ) - { - break; - } - - /* - * Avoid calling .urem here. - */ - do_rem(hn, elf_hash_number, tpnt->nbucket); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + - tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); /* - * This crap is required because the first instance of a - * symbol on the chain will be used for all symbol references. - * Thus this instance must be resolved to an address that - * contains the actual function, + * The passes are so that we can first search the regular symbols + * for whatever module was specified, and then search anything + * loaded with RTLD_GLOBAL. When pass is 1, it means we are just + * starting the first dlopened module, and anything above that + * is just the next one in the chain. */ - - first_def = NULL; - - for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){ - 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) { - - /* Here we make sure that we find a module where the symbol is - * actually defined. - */ - - if(f_tpnt) { - if(!first_def) first_def = tpnt; - if(first_def == f_tpnt && symtab[si].st_shndx == 0) - continue; - } - - switch(ELF32_ST_BIND(symtab[si].st_info)){ - case STB_GLOBAL: - if ( tpnt->libtype != elf_executable - && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */ - data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */ - break; /* nakao */ - } else /* nakao */ - return tpnt->loadaddr + symtab[si].st_value; - case STB_WEAK: - if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value; - break; - default: /* Do local symbols need to be examined? */ - break; - } - } + for (pass = 0; (1 == 1); pass++) { + + /* + * If we are just starting to search for RTLD_GLOBAL, setup + * the pointer for the start of the search. + */ + if (pass == 1) { + rpnt1 = _dl_handles; + } + + /* + * Anything after this, we need to skip to the next module. + */ + else if (pass >= 2) { + rpnt1 = rpnt1->next_handle; + } + + /* + * Make sure we still have a module, and make sure that this + * module was loaded with RTLD_GLOBAL. + */ + if (pass != 0) { + if (rpnt1 == NULL) + break; + if ((rpnt1->flags & RTLD_GLOBAL) == 0) + continue; + } + + for (rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); rpnt; rpnt = rpnt->next) { + tpnt = rpnt->dyn; + + /* + * The idea here is that if we are using dlsym, we want to + * first search the entire chain loaded from dlopen, and + * return a result from that if we found anything. If this + * fails, then we continue the search into the stuff loaded + * when the image was activated. For normal lookups, we start + * with rpnt == NULL, so we should never hit this. + */ + if (tpnt->libtype == elf_executable && weak_result != 0) { + break; + } + + /* + * Avoid calling .urem here. + */ + do_rem(hn, elf_hash_number, tpnt->nbucket); + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + /* + * This crap is required because the first instance of a + * symbol on the chain will be used for all symbol references. + * Thus this instance must be resolved to an address that + * contains the actual function, + */ + + first_def = NULL; + + for (si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]) { + 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) { + + /* Here we make sure that we find a module where the symbol is + * actually defined. + */ + + if (f_tpnt) { + if (!first_def) + first_def = tpnt; + if (first_def == f_tpnt + && symtab[si].st_shndx == 0) + continue; + } + + switch (ELF32_ST_BIND(symtab[si].st_info)) { + case STB_GLOBAL: + if (tpnt->libtype != elf_executable && + ELF32_ST_TYPE(symtab[si].st_info) + == STT_NOTYPE) + { /* nakao */ + data_result = tpnt->loadaddr + + symtab[si].st_value; /* nakao */ + break; /* nakao */ + } else /* nakao */ + return tpnt->loadaddr + symtab[si].st_value; + case STB_WEAK: + if (!weak_result) + weak_result = + tpnt->loadaddr + symtab[si].st_value; + break; + default: /* Do local symbols need to be examined? */ + break; + } + } + } + } } - } - } - if (data_result) return data_result; /* nakao */ - return weak_result; + if (data_result) + return data_result; /* nakao */ + return weak_result; } diff --git a/ldso/ldso/hash.h b/ldso/ldso/hash.h index 2eeda2d46..f7c6eebd5 100644 --- a/ldso/ldso/hash.h +++ b/ldso/ldso/hash.h @@ -35,7 +35,7 @@ struct elf_resolve{ unsigned int dynamic_size; unsigned int n_phent; - struct elf_phdr * ppnt; + Elf32_Phdr * ppnt; }; #if 0 diff --git a/ldso/ldso/i386/dl-syscalls.h b/ldso/ldso/i386/dl-syscalls.h index a9adb2361..30544290f 100644 --- a/ldso/ldso/i386/dl-syscalls.h +++ b/ldso/ldso/i386/dl-syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index 359018a51..e0d3505f9 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/ldso/ldso/i386/elfinterp.c @@ -20,15 +20,17 @@ #define VERBOSE_DLINKER #endif #ifdef VERBOSE_DLINKER -static 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"}; +static 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" +}; #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. */ + 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 @@ -39,214 +41,219 @@ an ELF sharable library or a linux style of shared library. */ #include <sys/types.h> #include <errno.h> -#include <fcntl.h> -#include <linux/elf.h> - +#include "elf.h" #include "hash.h" -#include "linuxelf.h" #include "syscall.h" -#include "../string.h" - -#define SVR4_COMPATIBILITY +#include "string.h" +#include "sysdep.h" extern char *_dl_progname; extern int _dl_linux_resolve(void); -unsigned int _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry) +unsigned int _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { - int reloc_type; - struct elf32_rel * this_reloc; - char * strtab; - struct elf32_sym * symtab; - struct elf32_rel * rel_addr; - int symtab_index; - char * new_addr; - char ** got_addr; - unsigned int instr_addr; + int reloc_type; + Elf32_Rel *this_reloc; + char *strtab; + Elf32_Sym *symtab; + Elf32_Rel *rel_addr; + int symtab_index; + char *new_addr; + char **got_addr; + unsigned int instr_addr; - rel_addr = (struct elf32_rel *) (tpnt->dynamic_info[DT_JMPREL] + - tpnt->loadaddr); + rel_addr = (Elf32_Rel *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); - this_reloc = rel_addr + (reloc_entry >> 3); - reloc_type = ELF32_R_TYPE(this_reloc->r_info); - symtab_index = ELF32_R_SYM(this_reloc->r_info); + this_reloc = rel_addr + (reloc_entry >> 3); + reloc_type = ELF32_R_TYPE(this_reloc->r_info); + symtab_index = ELF32_R_SYM(this_reloc->r_info); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); - if (reloc_type != R_386_JMP_SLOT) { - _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n", - _dl_progname); - _dl_exit(1); - }; + if (reloc_type != R_386_JMP_SLOT) { + _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n", + _dl_progname); + _dl_exit(1); + }; - /* Address of jump instruction to fix up */ - instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr); - got_addr = (char **) instr_addr; + /* Address of jump instruction to fix up */ + instr_addr = ((int) this_reloc->r_offset + (int) tpnt->loadaddr); + got_addr = (char **) instr_addr; #ifdef DEBUG - _dl_fdprintf(2, "Resolving symbol %s\n", - strtab + symtab[symtab_index].st_name); + _dl_fdprintf(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, (int) got_addr, tpnt, 0); - if(!new_addr) { - _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; + /* Get the address of the GOT entry */ + new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, + tpnt->symbol_scope, (int) got_addr, tpnt, 0); + if (!new_addr) { + _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_exit(1); + }; /* #define DEBUG_LIBRARY */ #ifdef DEBUG_LIBRARY - if((unsigned int) got_addr < 0x40000000) { - _dl_fdprintf(2, "Calling library function: %s\n", - strtab + symtab[symtab_index].st_name); - } else { - *got_addr = new_addr; - } + if ((unsigned int) got_addr < 0x40000000) { + _dl_fdprintf(2, "Calling library function: %s\n", + strtab + symtab[symtab_index].st_name); + } else { + *got_addr = new_addr; + } #else - *got_addr = new_addr; + *got_addr = new_addr; #endif - return (unsigned int) new_addr; + return (unsigned int) new_addr; } -void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr, - int rel_size, int type){ - int i; - char * strtab; - int reloc_type; - int symtab_index; - struct elf32_sym * symtab; - struct elf32_rel * rpnt; - unsigned int * reloc_addr; - - /* Now parse the relocation information */ - rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(struct elf32_rel); - - symtab = (struct 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 = (int *) (tpnt->loadaddr + (int)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - 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; - - switch(reloc_type){ - case R_386_NONE: break; - case R_386_JMP_SLOT: - *reloc_addr += (unsigned int) tpnt->loadaddr; - break; - default: - _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname); +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + int rel_addr, int rel_size, int type) +{ + int i; + char *strtab; + int reloc_type; + int symtab_index; + Elf32_Sym *symtab; + Elf32_Rel *rpnt; + unsigned int *reloc_addr; + + /* 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); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + 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; + + switch (reloc_type) { + case R_386_NONE: + break; + case R_386_JMP_SLOT: + *reloc_addr += (unsigned int) tpnt->loadaddr; + break; + default: + _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", + _dl_progname); #ifdef VERBOSE_DLINKER - _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]); + _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]); #endif - if(symtab_index) _dl_fdprintf(2, "'%s'\n", - strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; - }; + if (symtab_index) + _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); + _dl_exit(1); + }; + }; } -int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, - int rel_size, int type){ - int i; - char * strtab; - int reloc_type; - int goof = 0; - struct elf32_sym * symtab; - struct elf32_rel * rpnt; - unsigned int * reloc_addr; - unsigned int symbol_addr; - int symtab_index; - /* Now parse the relocation information */ - - rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(struct elf32_rel); - - symtab = (struct 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 = (int *) (tpnt->loadaddr + (int)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 && 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 int) - _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (int) reloc_addr, - (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_fdprintf(2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - goof++; - } - } - 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 int) 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 int) tpnt->loadaddr; - break; - case R_386_COPY: -#if 0 /* Do this later */ - _dl_fdprintf(2, "Doing copy for symbol "); - if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name); - _dl_fdprintf(2, "\n"); - _dl_memcpy((void *) symtab[symtab_index].st_value, - (void *) symbol_addr, - symtab[symtab_index].st_size); +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + int rel_addr, int rel_size, int type) +{ + int i; + char *strtab; + int reloc_type; + int goof = 0; + Elf32_Sym *symtab; + Elf32_Rel *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + 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); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + reloc_addr = (int *) (tpnt->loadaddr + (int) 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 && 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 int) + _dl_find_hash(strtab + symtab[symtab_index].st_name, + tpnt->symbol_scope, (int) reloc_addr, + (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_fdprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symtab[symtab_index].st_name); + goof++; + } + } + 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 int) 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 int) tpnt->loadaddr; + break; + case R_386_COPY: +#if 0 + /* Do this later */ + _dl_fdprintf(2, "Doing copy for symbol "); + if (symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name); + _dl_fdprintf(2, "\n"); + _dl_memcpy((void *) symtab[symtab_index].st_value, + (void *) symbol_addr, symtab[symtab_index].st_size); #endif - break; - default: - _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname); + break; + default: + _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname); #ifdef VERBOSE_DLINKER - _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]); + _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]); #endif - if (symtab_index) - _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); - _dl_exit(1); - }; + if (symtab_index) + _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); + _dl_exit(1); + }; - }; - return goof; + }; + return goof; } @@ -259,57 +266,57 @@ int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, /* No, there are cases where the SVr4 linker fails to emit COPY relocs at all */ -int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr, - int rel_size, int type) +int _dl_parse_copy_information(struct dyn_elf *xpnt, int rel_addr, + int rel_size, int type) { - int i; - char * strtab; - int reloc_type; - int goof = 0; - struct elf32_sym * symtab; - struct elf32_rel * rpnt; - unsigned int * reloc_addr; - unsigned int symbol_addr; - struct elf_resolve *tpnt; - int symtab_index; - /* Now parse the relocation information */ - - tpnt = xpnt->dyn; - - rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(struct elf32_rel); - - symtab = (struct 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 = (int *) (tpnt->loadaddr + (int)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 int) - _dl_find_hash(strtab + symtab[symtab_index].st_name, - xpnt->next, (int) reloc_addr, NULL, 1); - if(!symbol_addr) { - _dl_fdprintf(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 i; + char *strtab; + int reloc_type; + int goof = 0; + Elf32_Sym *symtab; + Elf32_Rel *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + struct elf_resolve *tpnt; + int symtab_index; + + /* Now parse the relocation information */ + + tpnt = xpnt->dyn; + + rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof(Elf32_Rel); + + 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 = (int *) (tpnt->loadaddr + (int) 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 int) _dl_find_hash(strtab + symtab[symtab_index].st_name, + xpnt->next, (int) reloc_addr, NULL, 1); + if (!symbol_addr) { + _dl_fdprintf(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; } - - diff --git a/ldso/ldso/i386/ld_syscalls.h b/ldso/ldso/i386/ld_syscalls.h index a9adb2361..30544290f 100644 --- a/ldso/ldso/i386/ld_syscalls.h +++ b/ldso/ldso/i386/ld_syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/i386/syscalls.h b/ldso/ldso/i386/syscalls.h index a9adb2361..30544290f 100644 --- a/ldso/ldso/i386/syscalls.h +++ b/ldso/ldso/i386/syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/ld-uClibc.c b/ldso/ldso/ld-uClibc.c index 3b613fb87..948a6e159 100644 --- a/ldso/ldso/ld-uClibc.c +++ b/ldso/ldso/ld-uClibc.c @@ -92,17 +92,12 @@ * can transfer control to the user's application. */ +#include <sys/mman.h> // For MAP_ANONYMOUS -- differs between platforms #include <stdarg.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/unistd.h> -#include <linux/elf.h> -#include <linux/mman.h> +#include "elf.h" #include "link.h" - #include "sysdep.h" #include "hash.h" -#include "linuxelf.h" #include "syscall.h" #include "string.h" @@ -110,24 +105,24 @@ #define ALLOW_ZERO_PLTGOT -static char * _dl_malloc_addr, *_dl_mmap_zero; -char * _dl_library_path = 0; /* Where we look for libraries */ -char *_dl_preload = 0; /* Things to be loaded before the libs. */ +static char *_dl_malloc_addr, *_dl_mmap_zero; +char *_dl_library_path = 0; /* Where we look for libraries */ +char *_dl_preload = 0; /* Things to be loaded before the libs. */ char *_dl_progname = "/lib/ld-linux-uclibc.so.1"; -static char * _dl_not_lazy = 0; -static char * _dl_warn = 0; /* Used by ldd */ -static char * _dl_trace_loaded_objects = 0; -static int (*_dl_elf_main)(int, char **, char**); +static char *_dl_not_lazy = 0; +static char *_dl_warn = 0; /* Used by ldd */ +static char *_dl_trace_loaded_objects = 0; +static int (*_dl_elf_main) (int, char **, char **); -static int (*_dl_elf_init)(void); +static int (*_dl_elf_init) (void); -void * (*_dl_malloc_function)(int size) = NULL; +void *(*_dl_malloc_function) (int size) = NULL; -struct r_debug * _dl_debug_addr = NULL; +struct r_debug *_dl_debug_addr = NULL; -unsigned int * _dl_brkp; +unsigned int *_dl_brkp; -unsigned int * _dl_envp; +unsigned int *_dl_envp; #define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) /* @@ -151,19 +146,10 @@ unsigned int * _dl_envp; RESULT = hash; \ } extern int _dl_linux_resolve(void); -extern char * _dl_strdup(const char *); -extern char * _dl_getenv(char * symbol, char ** envp); -extern void _dl_unsetenv(char * symbol, char ** envp); -extern int _dl_fixup(struct elf_resolve * tpnt); - -/* - * Datatype of a relocation on this platform - */ -#ifdef ELF_USES_RELOCA -typedef struct elf32_rela ELF_RELOC; -#else -typedef struct elf32_rel ELF_RELOC; -#endif +extern char *_dl_strdup(const char *); +extern char *_dl_getenv(char *symbol, char **envp); +extern void _dl_unsetenv(char *symbol, char **envp); +extern int _dl_fixup(struct elf_resolve *tpnt); /* * This stub function is used by some debuggers. The idea is that they @@ -172,71 +158,72 @@ typedef struct elf32_rel ELF_RELOC; */ void _dl_debug_state() { - return; + return; } void _dl_boot(int args); -void _dl_boot(int args){ - unsigned int argc; - char ** argv, ** envp; - int status; - - unsigned int load_addr; - unsigned int * got; - unsigned int * aux_dat; - int goof = 0; - struct elfhdr * header; - struct elf_resolve * tpnt; - struct dyn_elf * rpnt; - struct elf_resolve * app_tpnt; - unsigned int brk_addr; - unsigned int dl_data[AT_EGID+1]; - unsigned char * malloc_buffer, *mmap_zero; - int (*_dl_atexit)(void *); - int * lpnt; - struct dynamic * dpnt; - unsigned int *hash_addr; - struct r_debug * debug_addr; - unsigned int *chains; - int indx; - int _dl_secure; - - /* First obtain the information on the stack that tells us more about - what binary is loaded, where it is loaded, etc, etc */ - - GET_ARGV(aux_dat, args); - argc = *(aux_dat - 1); - argv = (char **) aux_dat; - aux_dat += argc; /* Skip over the argv pointers */ - aux_dat++; /* Skip over NULL at end of argv */ - envp = (char **) aux_dat; - while(*aux_dat) aux_dat++; /* Skip over the envp pointers */ - aux_dat++; /* Skip over NULL at end of envp */ - dl_data[AT_UID] = -1; /* check later to see if it is changed */ - while(*aux_dat) - { - unsigned int * ad1; - ad1 = aux_dat + 1; - if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1; - aux_dat += 2; - } - - /* Next, locate the GOT */ - - load_addr = dl_data[AT_BASE]; - - GET_GOT(got); - dpnt = (struct dynamic *) (*got + load_addr); - - /* OK, time for another hack. Now call mmap to get a page of writable - memory that can be used for a temporary malloc. We do not know brk - yet, so we cannot use real malloc. */ - - { - /* This hack is to work around a suspected asm bug in gcc-2.7.0 */ - //int zfileno; -//#define ZFILENO ((-1 & (~zfileno)) | zfileno) +void _dl_boot(int args) +{ + unsigned int argc; + char **argv, **envp; + int status; + + unsigned int load_addr; + unsigned int *got; + unsigned int *aux_dat; + int goof = 0; + elfhdr *header; + struct elf_resolve *tpnt; + struct dyn_elf *rpnt; + struct elf_resolve *app_tpnt; + unsigned int brk_addr; + unsigned int dl_data[AT_EGID + 1]; + unsigned char *malloc_buffer, *mmap_zero; + int (*_dl_atexit) (void *); + int *lpnt; + Elf32_Dyn *dpnt; + unsigned int *hash_addr; + struct r_debug *debug_addr; + unsigned int *chains; + int indx; + int _dl_secure; + + /* First obtain the information on the stack that tells us more about + what binary is loaded, where it is loaded, etc, etc */ + + GET_ARGV(aux_dat, args); + argc = *(aux_dat - 1); + argv = (char **) aux_dat; + aux_dat += argc; /* Skip over the argv pointers */ + aux_dat++; /* Skip over NULL at end of argv */ + envp = (char **) aux_dat; + while (*aux_dat) + aux_dat++; /* Skip over the envp pointers */ + aux_dat++; /* Skip over NULL at end of envp */ + dl_data[AT_UID] = -1; /* check later to see if it is changed */ + while (*aux_dat) + { + unsigned int *ad1; + + ad1 = aux_dat + 1; + if (*aux_dat <= AT_EGID) + dl_data[*aux_dat] = *ad1; + aux_dat += 2; + } + + /* Next, locate the GOT */ + + load_addr = dl_data[AT_BASE]; + + GET_GOT(got); + dpnt = (Elf32_Dyn *) (*got + load_addr); + + /* OK, time for another hack. Now call mmap to get a page of writable + memory that can be used for a temporary malloc. We do not know brk + yet, so we cannot use real malloc. */ + + { #define ZFILENO -1 #ifndef MAP_ANONYMOUS @@ -247,178 +234,195 @@ void _dl_boot(int args){ #endif #endif - /* See if we need to relocate this address */ - mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); - if(_dl_mmap_check_error(mmap_zero)) { - SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); - _dl_exit(13); - } - } - - tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _dl_memset (tpnt, 0, sizeof (*tpnt)); - app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _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)); - REALIGN(); - _dl_memset (debug_addr, 0, sizeof (*debug_addr)); - - /* OK, that was easy. Next scan the DYNAMIC section of the image. - We are only doing ourself right now - we will have to do the rest later */ - - while(dpnt->d_tag) - { - tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) - if(ppnt->p_type == PT_DYNAMIC) { - dpnt = (struct dynamic *) ppnt->p_vaddr; - while(dpnt->d_tag) - { - if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; } - app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - } - } - - /* Get some more of the information that we will need to dynamicly link - this module to itself */ - - hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr); - tpnt->nbucket = *hash_addr++; - tpnt->nchain = *hash_addr++; - tpnt->elf_buckets = hash_addr; - hash_addr += tpnt->nbucket; - chains = hash_addr; - - /* Ugly, ugly. We need to call mprotect to change the protection of - the text pages so that we can do the dynamic linking. We can set the - protection back again once we are done */ - - { - struct elf_phdr * ppnt; - int i; - - /* First cover the shared library/dynamic linker. */ - if(tpnt->dynamic_info[DT_TEXTREL]) { - header = (struct elfhdr *) dl_data[AT_BASE]; - ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); - for(i=0; i<header->e_phnum ; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - - /* Now cover the application program. */ - if(app_tpnt->dynamic_info[DT_TEXTREL]) { - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - } - - /* OK, now do the relocations. We do not do a lazy binding here, so - that once we are done, we have considerably more flexibility. */ - - goof = 0; - for(indx=0; indx < 2; indx++) - { - int i; - ELF_RELOC * rpnt; - unsigned int * reloc_addr; - unsigned int symbol_addr; - int symtab_index; - unsigned int rel_addr, rel_size; - - -#ifdef ELF_USES_RELOCA - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]); -#else - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]); -#endif + /* See if we need to relocate this address */ + mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void *) 0, 4096, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); + if (_dl_mmap_check_error(mmap_zero)) { + SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); + _dl_exit(13); + } + } + tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(tpnt, 0, sizeof(*tpnt)); + app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(app_tpnt, 0, sizeof(*app_tpnt)); - if(!rel_addr) continue; + /* + * This is used by gdb to locate the chain of shared libraries that are currently loaded. + */ + debug_addr = DL_MALLOC(sizeof(struct r_debug)); + REALIGN(); + _dl_memset(debug_addr, 0, sizeof(*debug_addr)); + + /* OK, that was easy. Next scan the DYNAMIC section of the image. + We are only doing ourself right now - we will have to do the rest later */ + + while (dpnt->d_tag) { + tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } - /* Now parse the relocation information */ - rpnt = (ELF_RELOC *) (rel_addr + load_addr); - for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){ - reloc_addr = (int *) (load_addr + (int)rpnt->r_offset); - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - if(symtab_index) { - char * strtab; - struct elf32_sym * symtab; + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) + if (ppnt->p_type == PT_DYNAMIC) { + dpnt = (Elf32_Dyn *) ppnt->p_vaddr; + while (dpnt->d_tag) { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_DEBUG) + dpnt->d_un.d_val = (int) debug_addr; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + app_tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + } + } - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr); + /* Get some more of the information that we will need to dynamicly link + this module to itself */ - /* We only do a partial dynamic linking right now. The user - is not supposed to redefine any symbols that start with - a '_', so we can do this with confidence. */ + hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH] + load_addr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + chains = hash_addr; - if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue; + /* Ugly, ugly. We need to call mprotect to change the protection of + the text pages so that we can do the dynamic linking. We can set the + protection back again once we are done */ - symbol_addr = load_addr + symtab[symtab_index].st_value; + { + elf_phdr *ppnt; + int i; + + /* First cover the shared library/dynamic linker. */ + if (tpnt->dynamic_info[DT_TEXTREL]) { + header = (elfhdr *) dl_data[AT_BASE]; + ppnt = (elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); + for (i = 0; i < header->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (load_addr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } - if(!symbol_addr) { - /* - * This will segfault - you cannot call a function until - * we have finished the relocations. - */ - SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol "); - SEND_STDERR(strtab + symtab[symtab_index].st_name); - SEND_STDERR(" undefined.\n"); - goof++; - } + /* Now cover the application program. */ + if (app_tpnt->dynamic_info[DT_TEXTREL]) { + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } } - /* - * Use this machine-specific macro to perform the actual relocation. - */ - PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); - } - } - if (goof) _dl_exit(14); + /* OK, now do the relocations. We do not do a lazy binding here, so + that once we are done, we have considerably more flexibility. */ + + goof = 0; + for (indx = 0; indx < 2; indx++) { + int i; + ELF_RELOC *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + int symtab_index; + unsigned int rel_addr, rel_size; + + +#ifdef ELF_USES_RELOCA + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_RELA]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELASZ]); +#else + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_REL]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELSZ]); +#endif + - /* OK, at this point we have a crude malloc capability. Start to build - the tables of the modules that are required for this beast to run. - We start with the basic executable, and then go from there. Eventually - we will run across ourself, and we will need to properly deal with that - as well. */ + if (!rel_addr) + continue; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) (rel_addr + load_addr); + for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) { + reloc_addr = (int *) (load_addr + (int) rpnt->r_offset); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + if (symtab_index) { + char *strtab; + Elf32_Sym *symtab; + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + + load_addr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr); + + /* We only do a partial dynamic linking right now. The user + is not supposed to redefine any symbols that start with + a '_', so we can do this with confidence. */ + + if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + + symbol_addr = load_addr + symtab[symtab_index].st_value; + + if (!symbol_addr) { + /* + * This will segfault - you cannot call a function until + * we have finished the relocations. + */ + SEND_STDERR("ELF dynamic loader - unable to " + "self-bootstrap - symbol "); + SEND_STDERR(strtab + symtab[symtab_index].st_name); + SEND_STDERR(" undefined.\n"); + goof++; + } + } + /* + * Use this machine-specific macro to perform the actual relocation. + */ + PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); + } + } + + if (goof) { + _dl_exit(14); + } - _dl_malloc_addr = malloc_buffer; + /* OK, at this point we have a crude malloc capability. Start to build + the tables of the modules that are required for this beast to run. + We start with the basic executable, and then go from there. Eventually + we will run across ourself, and we will need to properly deal with that + as well. */ - _dl_mmap_zero = mmap_zero; + _dl_malloc_addr = malloc_buffer; + + _dl_mmap_zero = mmap_zero; /* tpnt = _dl_malloc(sizeof(struct elf_resolve)); */ /* Now we have done the mandatory linking of some things. We are now @@ -426,573 +430,594 @@ void _dl_boot(int args){ fixed up by now. Still no function calls outside of this library , since the dynamic resolver is not yet ready. */ - lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); - INIT_GOT(lpnt, tpnt); - - /* OK, this was a big step, now we need to scan all of the user images - and load them properly. */ - - tpnt->next = 0; - tpnt->libname = 0; - tpnt->libtype = program_interpreter; - - { struct elfhdr * epnt; - struct elf_phdr * ppnt; - int i; - - epnt = (struct elfhdr *) dl_data[AT_BASE]; - tpnt->n_phent = epnt->e_phnum; - tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff); - for(i=0;i < epnt->e_phnum; i++, ppnt++){ - if(ppnt->p_type == PT_DYNAMIC) { - tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; - tpnt->dynamic_size = ppnt->p_filesz; - } - } - } - - tpnt->chains = chains; - tpnt->loadaddr = (char *) load_addr; - - brk_addr = 0; - rpnt = NULL; - - /* At this point we are now free to examine the user application, - and figure out which libraries are supposed to be called. Until - we have this list, we will not be completely ready for dynamic linking */ - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD) { - if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) - brk_addr = ppnt->p_vaddr + ppnt->p_memsz; - } - if(ppnt->p_type == PT_DYNAMIC) { + lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); + INIT_GOT(lpnt, tpnt); + + /* OK, this was a big step, now we need to scan all of the user images + and load them properly. */ + + tpnt->next = 0; + tpnt->libname = 0; + tpnt->libtype = program_interpreter; + + { + elfhdr *epnt; + elf_phdr *ppnt; + int i; + + epnt = (elfhdr *) dl_data[AT_BASE]; + tpnt->n_phent = epnt->e_phnum; + tpnt->ppnt = ppnt = (elf_phdr *) (load_addr + epnt->e_phoff); + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_DYNAMIC) { + tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; + tpnt->dynamic_size = ppnt->p_filesz; + } + } + } + + tpnt->chains = chains; + tpnt->loadaddr = (char *) load_addr; + + brk_addr = 0; + rpnt = NULL; + + /* At this point we are now free to examine the user application, + and figure out which libraries are supposed to be called. Until + we have this list, we will not be completely ready for dynamic linking */ + + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD) { + if (ppnt->p_vaddr + ppnt->p_memsz > brk_addr) + brk_addr = ppnt->p_vaddr + ppnt->p_memsz; + } + if (ppnt->p_type == PT_DYNAMIC) { #ifndef ALLOW_ZERO_PLTGOT - /* make sure it's really there. */ - if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue; + /* make sure it's really there. */ + if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) + continue; #endif - /* OK, we have what we need - slip this one into the list. */ - app_tpnt = _dl_add_elf_hash_table("", 0, - app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); - _dl_loaded_modules->libtype = elf_executable; - _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; - _dl_symbol_tables = rpnt = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*rpnt)); - rpnt->dyn = _dl_loaded_modules; - app_tpnt->usage_count++; - app_tpnt->symbol_scope = _dl_symbol_tables; - lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); + /* OK, we have what we need - slip this one into the list. */ + app_tpnt = _dl_add_elf_hash_table("", 0, + app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); + _dl_loaded_modules->libtype = elf_executable; + _dl_loaded_modules->ppnt = (elf_phdr *) dl_data[AT_PHDR]; + _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; + _dl_symbol_tables = rpnt = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*rpnt)); + rpnt->dyn = _dl_loaded_modules; + app_tpnt->usage_count++; + app_tpnt->symbol_scope = _dl_symbol_tables; + lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); #ifdef ALLOW_ZERO_PLTGOT - if (lpnt) + if (lpnt) #endif - INIT_GOT(lpnt, _dl_loaded_modules); - } - if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have - this before */ - tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000)); - } - } - } - - if (argv[0]) - _dl_progname = argv[0]; - - /* Now we need to figure out what kind of options are selected. - Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ - { - _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp); - - if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) || - (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] && - dl_data[AT_GID] == dl_data[AT_EGID])) - { - _dl_secure = 0; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp); - } - else - { - _dl_secure = 1; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_unsetenv("LD_AOUT_PRELOAD", envp); - _dl_unsetenv("LD_LIBRARY_PATH", envp); - _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); - _dl_library_path = NULL; - } - } - - _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); - - /* OK, we now have the application in the list, and we have some - basic stuff in place. Now search through the list for other shared - libraries that should be loaded, and insert them on the list in the - correct order. */ + INIT_GOT(lpnt, _dl_loaded_modules); + } + if (ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not + have this before */ + tpnt->libname = _dl_strdup((char *) ppnt->p_offset + + (dl_data[AT_PHDR] & 0xfffff000)); + } + } + } + + if (argv[0]) { + _dl_progname = argv[0]; + } + + /* Now we need to figure out what kind of options are selected. + Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ + { + _dl_not_lazy = _dl_getenv("LD_BIND_NOW", envp); + + if ((dl_data[AT_UID] == -1 && _dl_suid_ok()) || + (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] + && dl_data[AT_GID] == dl_data[AT_EGID])) { + _dl_secure = 0; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp); + } else { + _dl_secure = 1; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_unsetenv("LD_AOUT_PRELOAD", envp); + _dl_unsetenv("LD_LIBRARY_PATH", envp); + _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); + _dl_library_path = NULL; + } + } + + _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); + + /* OK, we now have the application in the list, and we have some + basic stuff in place. Now search through the list for other shared + libraries that should be loaded, and insert them on the list in the + correct order. */ + +#ifdef USE_CACHE + _dl_map_cache(); +#endif + + { + struct elf_resolve *tcurr; + struct elf_resolve *tpnt1; + char *lpnt; + + if (_dl_preload) + { + char c, *str, *str2; + + str = _dl_preload; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + while (*str) + { + str2 = str; + while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') + str2++; + c = *str2; + *str2 = '\0'; + if (!_dl_secure || _dl_strchr(str, '/') == NULL) + { + tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", str); + else { + _dl_fdprintf(2, "%s: can't load " + "library '%s'\n", _dl_progname, str); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + /* this is a real hack to make ldd not print + * the library itself when run on a library. */ + if (_dl_strcmp(_dl_progname, str) != 0) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", + str, tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + *str2 = c; + str = str2; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + } + } + + { + int fd; + struct kernel_stat st; + char *preload; + + if (!_dl_stat(LDSO_PRELOAD, &st)) { + if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { + _dl_fdprintf(2, "%s: can't open file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + preload = (caddr_t) _dl_mmap(0, st.st_size + 1, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + _dl_close(fd); + if (preload == (caddr_t) - 1) { + _dl_fdprintf(2, "%s: can't map file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + char c, *cp, *cp2; + + /* convert all separators and comments to spaces */ + for (cp = preload; *cp; /*nada */ ) { + if (*cp == ':' || *cp == '\t' || *cp == '\n') { + *cp++ = ' '; + } else if (*cp == '#') { + do + *cp++ = ' '; + while (*cp != '\n' && *cp != '\0'); + } else { + cp++; + } + } + + /* find start of first library */ + for (cp = preload; *cp && *cp == ' '; cp++) + /*nada */ ; + + while (*cp) { + /* find end of library */ + for (cp2 = cp; *cp && *cp != ' '; cp++) + /*nada */ ; + c = *cp; + *cp = '\0'; + + tpnt1 = _dl_load_shared_library(0, NULL, cp2); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not " + "found\n", cp2); + else { + _dl_fdprintf(2, "%s: can't " + "load library '%s'\n", + _dl_progname, cp2); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + _dl_fdprintf(1, "\t%s => %s " + "(0x%x)\n", cp2, + tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, + sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + + /* find start of next library */ + *cp = c; + for ( /*nada */ ; *cp && *cp == ' '; cp++) + /*nada */ ; + } + + _dl_munmap(preload, st.st_size + 1); + } + } + } + } + + for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) { + for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; + dpnt++) { + if (dpnt->d_tag == DT_NEEDED) { + lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + + dpnt->d_un.d_val; + if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) { + struct elf_resolve *ttmp; + + ttmp = _dl_loaded_modules; + while (ttmp->next) + ttmp = ttmp->next; + ttmp->next = tpnt; + tpnt->prev = ttmp; + tpnt->next = NULL; + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + rpnt->dyn = tpnt; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt = NULL; + continue; + } + if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", lpnt); + else { + _dl_fdprintf(2, "%s: can't load library '%s'\n", + _dl_progname, lpnt); + _dl_exit(16); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, + tpnt1->libname, (unsigned) tpnt1->loadaddr); + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + } + } + } #ifdef USE_CACHE - _dl_map_cache(); + _dl_unmap_cache(); #endif - { - struct elf_resolve *tcurr; - struct elf_resolve *tpnt1; - char *lpnt; - - if (_dl_preload) { - char c, *str, *str2; - - str = _dl_preload; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - while (*str) { - str2 = str; - while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') - str2++; - c = *str2; - *str2 = '\0'; - if (!_dl_secure || _dl_strchr(str, '/') == NULL) { - tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", str); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, str); - _dl_exit(15); - } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) { - /* this is a real hack to make ldd not print the - library itself when run on a library. */ - if (_dl_strcmp(_dl_progname, str) != 0) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - } - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + /* ldd uses uses this. I am not sure how you pick up the other flags */ + if (_dl_trace_loaded_objects) { + _dl_warn = _dl_getenv("LD_WARN", envp); + if (!_dl_warn) + _dl_exit(0); } - *str2 = c; - str = str2; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - } - } - - { - int fd; - struct kernel_stat st; - char *preload; - - if (!_dl_stat(LDSO_PRELOAD, &st)) { - if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { - _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fd, 0); - _dl_close (fd); - if (preload == (caddr_t)-1) { - _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - char c, *cp, *cp2; - - /* convert all separators and comments to spaces */ - for (cp = preload; *cp; /*nada*/) { - if (*cp == ':' || *cp == '\t' || *cp == '\n') { - *cp++ = ' '; - } else if (*cp == '#') { - do - *cp++ = ' '; - while (*cp != '\n' && *cp != '\0'); - } else { - cp++; - } - } - - /* find start of first library */ - for (cp = preload; *cp && *cp == ' '; cp++) - /*nada*/; - - while (*cp) { - /* find end of library */ - for (cp2 = cp; *cp && *cp != ' '; cp++) - /*nada*/; - c = *cp; - *cp = '\0'; - - tpnt1 = _dl_load_shared_library(0, NULL, cp2); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", cp2); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, cp2); - _dl_exit(15); + + /* + * If the program interpreter is not in the module chain, add it. This will + * be required for dlopen to be able to access the internal functions in the + * dynamic linker. + */ + if (tpnt) { + struct elf_resolve *tcurr; + + tcurr = _dl_loaded_modules; + if (tcurr) + while (tcurr->next) + tcurr = tcurr->next; + tpnt->next = NULL; + tpnt->usage_count++; + + if (tcurr) { + tcurr->next = tpnt; + tpnt->prev = tcurr; + } else { + _dl_loaded_modules = tpnt; + tpnt->prev = NULL; } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } - - /* find start of next library */ - *cp = c; - for (/*nada*/; *cp && *cp == ' '; cp++) - /*nada*/; - } - - _dl_munmap(preload, st.st_size+1); - } + if (rpnt) { + rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + } else { + rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*(rpnt->next))); + } + rpnt->dyn = tpnt; + tpnt = NULL; } - } - } - - for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) - { - for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++) - { - if(dpnt->d_tag == DT_NEEDED) + + /* + * OK, now all of the kids are tucked into bed in their proper addresses. + * Now we go through and look for REL and RELA records that indicate fixups + * to the GOT tables. We need to do this in reverse order so that COPY + * directives work correctly */ + + + goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; + + + /* Some flavors of SVr4 do not generate the R_*_COPY directive, + and we have to manually search for entries that require fixups. + Solaris gets this one right, from what I understand. */ + + + if (_dl_symbol_tables) + goof += _dl_copy_fixups(_dl_symbol_tables); + + if (goof || _dl_trace_loaded_objects) + _dl_exit(0); + + /* OK, at this point things are pretty much ready to run. Now we + need to touch up a few items that are required, and then + we can let the user application have at it. Note that + the dynamic linker itself is not guaranteed to be fully + dynamicly linked if we are using ld.so.1, so we have to look + up each symbol individually. */ + + + _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); + if (_dl_brkp) + *_dl_brkp = brk_addr; + _dl_envp = + (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); + + if (_dl_envp) + *_dl_envp = (unsigned int) envp; + { - lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + - dpnt->d_un.d_val; - if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) - { - struct elf_resolve * ttmp; - ttmp = _dl_loaded_modules; - while (ttmp->next) - ttmp = ttmp->next; - ttmp->next = tpnt; - tpnt->prev = ttmp; - tpnt->next = NULL; - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - rpnt->dyn = tpnt; - tpnt->usage_count++; - tpnt->symbol_scope = _dl_symbol_tables; - tpnt = NULL; - continue; - } - if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) - { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", lpnt); - else - { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, lpnt); - _dl_exit(16); - } - } - else - { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + int i; + elf_phdr *ppnt; + + /* We had to set the protections of all pages to R/W for dynamic linking. + Set text pages back to R/O */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) + for (ppnt = tpnt->ppnt, i = 0; i < tpnt->n_phent; i++, ppnt++) + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && + tpnt->dynamic_info[DT_TEXTREL]) + _dl_mprotect((void *) (tpnt->loadaddr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + LXFLAGS(ppnt->p_flags)); + } - } - } - } -#ifdef USE_CACHE - _dl_unmap_cache(); -#endif + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - /* ldd uses uses this. I am not sure how you pick up the other flags */ - if(_dl_trace_loaded_objects) - { - _dl_warn = _dl_getenv("LD_WARN", envp); - if (!_dl_warn) _dl_exit(0); - } - - /* - * If the program interpreter is not in the module chain, add it. This will - * be required for dlopen to be able to access the internal functions in the - * dynamic linker. - */ - if(tpnt) { - struct elf_resolve * tcurr; - - tcurr = _dl_loaded_modules; - if (tcurr) - while(tcurr->next) tcurr = tcurr->next; - tpnt->next = NULL; - tpnt->usage_count++; - - if (tcurr) { - tcurr->next = tpnt; - tpnt->prev = tcurr; - } - else { - _dl_loaded_modules = tpnt; - tpnt->prev = NULL; - } - if (rpnt) { - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - } else { - rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*(rpnt->next))); - } - rpnt->dyn = tpnt; - tpnt = NULL; - } - - /* - * OK, now all of the kids are tucked into bed in their proper addresses. - * Now we go through and look for REL and RELA records that indicate fixups - * to the GOT tables. We need to do this in reverse order so that COPY - * directives work correctly */ - - - goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; - - - /* Some flavors of SVr4 do not generate the R_*_COPY directive, - and we have to manually search for entries that require fixups. - Solaris gets this one right, from what I understand. */ - - - if (_dl_symbol_tables) - goof += _dl_copy_fixups(_dl_symbol_tables); - - if(goof || _dl_trace_loaded_objects) _dl_exit(0); - - /* OK, at this point things are pretty much ready to run. Now we - need to touch up a few items that are required, and then - we can let the user application have at it. Note that - the dynamic linker itself is not guaranteed to be fully - dynamicly linked if we are using ld.so.1, so we have to look - up each symbol individually. */ - - - _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); - if (_dl_brkp) *_dl_brkp = brk_addr; - _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); - - if (_dl_envp) *_dl_envp = (unsigned int) envp; - - { - int i; - struct elf_phdr * ppnt; - - /* We had to set the protections of all pages to R/W for dynamic linking. - Set text pages back to R/O */ - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++) - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && - tpnt->dynamic_info[DT_TEXTREL]) - _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - LXFLAGS(ppnt->p_flags)); - - } - - _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - - /* - * OK, fix one more thing - set up the debug_addr structure to point - * to our chain. Later we may need to fill in more fields, but this - * should be enough for now. - */ - debug_addr->r_map = (struct link_map *) _dl_loaded_modules; - debug_addr->r_version = 1; - debug_addr->r_ldbase = load_addr; - debug_addr->r_brk = (unsigned long) &_dl_debug_state; - _dl_debug_addr = debug_addr; - debug_addr->r_state = RT_CONSISTENT; - /* This is written in this funny way to keep gcc from inlining the - function call. */ - ((void (*)(void))debug_addr->r_brk)(); - - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - { - /* Apparently crt1 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->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]); - (*_dl_elf_init)(); - } - if(_dl_atexit && tpnt->dynamic_info[DT_FINI]) - { - (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); - } + /* + * OK, fix one more thing - set up the debug_addr structure to point + * to our chain. Later we may need to fill in more fields, but this + * should be enough for now. + */ + debug_addr->r_map = (struct link_map *) _dl_loaded_modules; + debug_addr->r_version = 1; + debug_addr->r_ldbase = load_addr; + debug_addr->r_brk = (unsigned long) &_dl_debug_state; + _dl_debug_addr = debug_addr; + debug_addr->r_state = RT_CONSISTENT; + /* This is written in this funny way to keep gcc from inlining the + function call. */ + ((void (*)(void)) debug_addr->r_brk) (); + + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + /* Apparently crt1 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->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]); + (*_dl_elf_init) (); + } + if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) { + (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); + } #undef DL_DEBUG #ifdef DL_DEBUG - else - { - _dl_fdprintf(2, tpnt->libname); - _dl_fdprintf(2, ": "); - if (!_dl_atexit) - _dl_fdprintf(2, "The address is atexit () is 0x0."); - if (!tpnt->dynamic_info[DT_FINI]) - _dl_fdprintf(2, "Invalid .fini section."); - _dl_fdprintf(2, "\n"); - } + else { + _dl_fdprintf(2, tpnt->libname); + _dl_fdprintf(2, ": "); + if (!_dl_atexit) + _dl_fdprintf(2, "The address is atexit () is 0x0."); + if (!tpnt->dynamic_info[DT_FINI]) + _dl_fdprintf(2, "Invalid .fini section."); + _dl_fdprintf(2, "\n"); + } #endif #undef DL_DEBUG - } + } - /* OK we are done here. Turn out the lights, and lock up. */ - _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY]; + /* OK we are done here. Turn out the lights, and lock up. */ + _dl_elf_main = (int (*)(int, char **, char **)) dl_data[AT_ENTRY]; - /* - * Transfer control to the application. - */ - START(); + /* + * Transfer control to the application. + */ + START(); } -int _dl_fixup(struct elf_resolve * tpnt) +int _dl_fixup(struct elf_resolve *tpnt) { - int goof = 0; - if(tpnt->next) goof += _dl_fixup(tpnt->next); + int goof = 0; + + if (tpnt->next) + goof += _dl_fixup(tpnt->next); - if(tpnt->dynamic_info[DT_REL]) { + if (tpnt->dynamic_info[DT_REL]) { #ifdef ELF_USES_RELOCA - _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname); - _dl_exit(17); + _dl_fdprintf(2, "%s: can't handle REL relocation records\n", + _dl_progname); + _dl_exit(17); #else - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL], - tpnt->dynamic_info[DT_RELSZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_REL], tpnt->dynamic_info[DT_RELSZ], 0); #endif - } - if(tpnt->dynamic_info[DT_RELA]) { + } + if (tpnt->dynamic_info[DT_RELA]) { #ifdef ELF_USES_RELOCA - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA], - tpnt->dynamic_info[DT_RELASZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); #else - _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname); - _dl_exit(18); + _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", + _dl_progname); + _dl_exit(18); #endif - } - if(tpnt->dynamic_info[DT_JMPREL]) - { - if (tpnt->init_flag & JMP_RELOCS_DONE) return goof; - tpnt->init_flag |= JMP_RELOCS_DONE; - - if(! _dl_not_lazy || *_dl_not_lazy == 0) - _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - else - goof += _dl_parse_relocation_information(tpnt, - tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - } - return goof; + } + if (tpnt->dynamic_info[DT_JMPREL]) { + if (tpnt->init_flag & JMP_RELOCS_DONE) + return goof; + tpnt->init_flag |= JMP_RELOCS_DONE; + + if (!_dl_not_lazy || *_dl_not_lazy == 0) + _dl_parse_lazy_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + else + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + } + return goof; } -void * _dl_malloc(int size) { - void * retval; - - if(_dl_malloc_function) - return (*_dl_malloc_function)(size); - - if(_dl_malloc_addr-_dl_mmap_zero+size>4096) { - _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(_dl_mmap_check_error(_dl_mmap_zero)) { - _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); - _dl_exit(20); - } - } - retval = _dl_malloc_addr; - _dl_malloc_addr += size; - - /* - * Align memory to 4 byte boundary. Some platforms require this, others - * simply get better performance. - */ - _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); - return retval; +void *_dl_malloc(int size) +{ + void *retval; + + if (_dl_malloc_function) + return (*_dl_malloc_function) (size); + + if (_dl_malloc_addr - _dl_mmap_zero + size > 4096) { + _dl_mmap_zero = _dl_malloc_addr = + (unsigned char *) _dl_mmap((void *) 0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(_dl_mmap_zero)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_exit(20); + } + } + retval = _dl_malloc_addr; + _dl_malloc_addr += size; + + /* + * Align memory to 4 byte boundary. Some platforms require this, others + * simply get better performance. + */ + _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); + return retval; } -char * _dl_getenv(char *symbol, char **envp) +char *_dl_getenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - while ((pnt = *envp++)) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if (!*pnt || *pnt != '=' || *pnt1) - continue; - return pnt+1; - } - return 0; + char *pnt; + char *pnt1; + + while ((pnt = *envp++)) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + continue; + return pnt + 1; + } + return 0; } void _dl_unsetenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - char **newenvp = envp; - for (pnt = *envp; pnt; pnt = *++envp) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if(!*pnt || *pnt != '=' || *pnt1) - *newenvp++ = *envp; - } - *newenvp++ = *envp; - return; + char *pnt; + char *pnt1; + char **newenvp = envp; + + for (pnt = *envp; pnt; pnt = *++envp) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + *newenvp++ = *envp; + } + *newenvp++ = *envp; + return; } -char * _dl_strdup(const char * string){ - char * retval; - int len; +char *_dl_strdup(const char *string) +{ + char *retval; + int len; - len = _dl_strlen(string); - retval = _dl_malloc(len + 1); - _dl_strcpy(retval, string); - return retval; + len = _dl_strlen(string); + retval = _dl_malloc(len + 1); + _dl_strcpy(retval, string); + return retval; } - diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h index 2eeda2d46..f7c6eebd5 100644 --- a/ldso/ldso/ld_hash.h +++ b/ldso/ldso/ld_hash.h @@ -35,7 +35,7 @@ struct elf_resolve{ unsigned int dynamic_size; unsigned int n_phent; - struct elf_phdr * ppnt; + Elf32_Phdr * ppnt; }; #if 0 diff --git a/ldso/ldso/ld_string.h b/ldso/ldso/ld_string.h index 1ea8fd7ae..be0de45b1 100644 --- a/ldso/ldso/ld_string.h +++ b/ldso/ldso/ld_string.h @@ -1,7 +1,7 @@ #ifndef _LINUX_STRING_H_ #define _LINUX_STRING_H_ -#include <linux/types.h> /* for size_t */ +#include <sys/types.h> /* for size_t */ #ifndef NULL #define NULL ((void *) 0) diff --git a/ldso/ldso/ld_syscall.h b/ldso/ldso/ld_syscall.h index 4e4d4c118..6678e2c74 100644 --- a/ldso/ldso/ld_syscall.h +++ b/ldso/ldso/ld_syscall.h @@ -41,6 +41,7 @@ static inline void * _dl_mmap(void * addr, unsigned long size, int prot, #define __NR__dl_open __NR_open +#define O_RDONLY 0x0000 static inline _syscall2(int, _dl_open, const char *, fn, int, flags); #define __NR__dl_write __NR_write @@ -66,6 +67,7 @@ static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, le #include <asm/stat.h> #undef new_stat #undef stat +#define S_ISUID 04000 /* Set user ID on execution. */ static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf); diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index 3b613fb87..948a6e159 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -92,17 +92,12 @@ * can transfer control to the user's application. */ +#include <sys/mman.h> // For MAP_ANONYMOUS -- differs between platforms #include <stdarg.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/unistd.h> -#include <linux/elf.h> -#include <linux/mman.h> +#include "elf.h" #include "link.h" - #include "sysdep.h" #include "hash.h" -#include "linuxelf.h" #include "syscall.h" #include "string.h" @@ -110,24 +105,24 @@ #define ALLOW_ZERO_PLTGOT -static char * _dl_malloc_addr, *_dl_mmap_zero; -char * _dl_library_path = 0; /* Where we look for libraries */ -char *_dl_preload = 0; /* Things to be loaded before the libs. */ +static char *_dl_malloc_addr, *_dl_mmap_zero; +char *_dl_library_path = 0; /* Where we look for libraries */ +char *_dl_preload = 0; /* Things to be loaded before the libs. */ char *_dl_progname = "/lib/ld-linux-uclibc.so.1"; -static char * _dl_not_lazy = 0; -static char * _dl_warn = 0; /* Used by ldd */ -static char * _dl_trace_loaded_objects = 0; -static int (*_dl_elf_main)(int, char **, char**); +static char *_dl_not_lazy = 0; +static char *_dl_warn = 0; /* Used by ldd */ +static char *_dl_trace_loaded_objects = 0; +static int (*_dl_elf_main) (int, char **, char **); -static int (*_dl_elf_init)(void); +static int (*_dl_elf_init) (void); -void * (*_dl_malloc_function)(int size) = NULL; +void *(*_dl_malloc_function) (int size) = NULL; -struct r_debug * _dl_debug_addr = NULL; +struct r_debug *_dl_debug_addr = NULL; -unsigned int * _dl_brkp; +unsigned int *_dl_brkp; -unsigned int * _dl_envp; +unsigned int *_dl_envp; #define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) /* @@ -151,19 +146,10 @@ unsigned int * _dl_envp; RESULT = hash; \ } extern int _dl_linux_resolve(void); -extern char * _dl_strdup(const char *); -extern char * _dl_getenv(char * symbol, char ** envp); -extern void _dl_unsetenv(char * symbol, char ** envp); -extern int _dl_fixup(struct elf_resolve * tpnt); - -/* - * Datatype of a relocation on this platform - */ -#ifdef ELF_USES_RELOCA -typedef struct elf32_rela ELF_RELOC; -#else -typedef struct elf32_rel ELF_RELOC; -#endif +extern char *_dl_strdup(const char *); +extern char *_dl_getenv(char *symbol, char **envp); +extern void _dl_unsetenv(char *symbol, char **envp); +extern int _dl_fixup(struct elf_resolve *tpnt); /* * This stub function is used by some debuggers. The idea is that they @@ -172,71 +158,72 @@ typedef struct elf32_rel ELF_RELOC; */ void _dl_debug_state() { - return; + return; } void _dl_boot(int args); -void _dl_boot(int args){ - unsigned int argc; - char ** argv, ** envp; - int status; - - unsigned int load_addr; - unsigned int * got; - unsigned int * aux_dat; - int goof = 0; - struct elfhdr * header; - struct elf_resolve * tpnt; - struct dyn_elf * rpnt; - struct elf_resolve * app_tpnt; - unsigned int brk_addr; - unsigned int dl_data[AT_EGID+1]; - unsigned char * malloc_buffer, *mmap_zero; - int (*_dl_atexit)(void *); - int * lpnt; - struct dynamic * dpnt; - unsigned int *hash_addr; - struct r_debug * debug_addr; - unsigned int *chains; - int indx; - int _dl_secure; - - /* First obtain the information on the stack that tells us more about - what binary is loaded, where it is loaded, etc, etc */ - - GET_ARGV(aux_dat, args); - argc = *(aux_dat - 1); - argv = (char **) aux_dat; - aux_dat += argc; /* Skip over the argv pointers */ - aux_dat++; /* Skip over NULL at end of argv */ - envp = (char **) aux_dat; - while(*aux_dat) aux_dat++; /* Skip over the envp pointers */ - aux_dat++; /* Skip over NULL at end of envp */ - dl_data[AT_UID] = -1; /* check later to see if it is changed */ - while(*aux_dat) - { - unsigned int * ad1; - ad1 = aux_dat + 1; - if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1; - aux_dat += 2; - } - - /* Next, locate the GOT */ - - load_addr = dl_data[AT_BASE]; - - GET_GOT(got); - dpnt = (struct dynamic *) (*got + load_addr); - - /* OK, time for another hack. Now call mmap to get a page of writable - memory that can be used for a temporary malloc. We do not know brk - yet, so we cannot use real malloc. */ - - { - /* This hack is to work around a suspected asm bug in gcc-2.7.0 */ - //int zfileno; -//#define ZFILENO ((-1 & (~zfileno)) | zfileno) +void _dl_boot(int args) +{ + unsigned int argc; + char **argv, **envp; + int status; + + unsigned int load_addr; + unsigned int *got; + unsigned int *aux_dat; + int goof = 0; + elfhdr *header; + struct elf_resolve *tpnt; + struct dyn_elf *rpnt; + struct elf_resolve *app_tpnt; + unsigned int brk_addr; + unsigned int dl_data[AT_EGID + 1]; + unsigned char *malloc_buffer, *mmap_zero; + int (*_dl_atexit) (void *); + int *lpnt; + Elf32_Dyn *dpnt; + unsigned int *hash_addr; + struct r_debug *debug_addr; + unsigned int *chains; + int indx; + int _dl_secure; + + /* First obtain the information on the stack that tells us more about + what binary is loaded, where it is loaded, etc, etc */ + + GET_ARGV(aux_dat, args); + argc = *(aux_dat - 1); + argv = (char **) aux_dat; + aux_dat += argc; /* Skip over the argv pointers */ + aux_dat++; /* Skip over NULL at end of argv */ + envp = (char **) aux_dat; + while (*aux_dat) + aux_dat++; /* Skip over the envp pointers */ + aux_dat++; /* Skip over NULL at end of envp */ + dl_data[AT_UID] = -1; /* check later to see if it is changed */ + while (*aux_dat) + { + unsigned int *ad1; + + ad1 = aux_dat + 1; + if (*aux_dat <= AT_EGID) + dl_data[*aux_dat] = *ad1; + aux_dat += 2; + } + + /* Next, locate the GOT */ + + load_addr = dl_data[AT_BASE]; + + GET_GOT(got); + dpnt = (Elf32_Dyn *) (*got + load_addr); + + /* OK, time for another hack. Now call mmap to get a page of writable + memory that can be used for a temporary malloc. We do not know brk + yet, so we cannot use real malloc. */ + + { #define ZFILENO -1 #ifndef MAP_ANONYMOUS @@ -247,178 +234,195 @@ void _dl_boot(int args){ #endif #endif - /* See if we need to relocate this address */ - mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); - if(_dl_mmap_check_error(mmap_zero)) { - SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); - _dl_exit(13); - } - } - - tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _dl_memset (tpnt, 0, sizeof (*tpnt)); - app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); - REALIGN(); - _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)); - REALIGN(); - _dl_memset (debug_addr, 0, sizeof (*debug_addr)); - - /* OK, that was easy. Next scan the DYNAMIC section of the image. - We are only doing ourself right now - we will have to do the rest later */ - - while(dpnt->d_tag) - { - tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) - if(ppnt->p_type == PT_DYNAMIC) { - dpnt = (struct dynamic *) ppnt->p_vaddr; - while(dpnt->d_tag) - { - if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; } - app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1; - dpnt++; - } - } - } - - /* Get some more of the information that we will need to dynamicly link - this module to itself */ - - hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr); - tpnt->nbucket = *hash_addr++; - tpnt->nchain = *hash_addr++; - tpnt->elf_buckets = hash_addr; - hash_addr += tpnt->nbucket; - chains = hash_addr; - - /* Ugly, ugly. We need to call mprotect to change the protection of - the text pages so that we can do the dynamic linking. We can set the - protection back again once we are done */ - - { - struct elf_phdr * ppnt; - int i; - - /* First cover the shared library/dynamic linker. */ - if(tpnt->dynamic_info[DT_TEXTREL]) { - header = (struct elfhdr *) dl_data[AT_BASE]; - ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); - for(i=0; i<header->e_phnum ; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - - /* Now cover the application program. */ - if(app_tpnt->dynamic_info[DT_TEXTREL]) { - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - } - - /* OK, now do the relocations. We do not do a lazy binding here, so - that once we are done, we have considerably more flexibility. */ - - goof = 0; - for(indx=0; indx < 2; indx++) - { - int i; - ELF_RELOC * rpnt; - unsigned int * reloc_addr; - unsigned int symbol_addr; - int symtab_index; - unsigned int rel_addr, rel_size; - - -#ifdef ELF_USES_RELOCA - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]); -#else - rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]); - rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]); -#endif + /* See if we need to relocate this address */ + mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void *) 0, 4096, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0); + if (_dl_mmap_check_error(mmap_zero)) { + SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n"); + _dl_exit(13); + } + } + tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(tpnt, 0, sizeof(*tpnt)); + app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset(app_tpnt, 0, sizeof(*app_tpnt)); - if(!rel_addr) continue; + /* + * This is used by gdb to locate the chain of shared libraries that are currently loaded. + */ + debug_addr = DL_MALLOC(sizeof(struct r_debug)); + REALIGN(); + _dl_memset(debug_addr, 0, sizeof(*debug_addr)); + + /* OK, that was easy. Next scan the DYNAMIC section of the image. + We are only doing ourself right now - we will have to do the rest later */ + + while (dpnt->d_tag) { + tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } - /* Now parse the relocation information */ - rpnt = (ELF_RELOC *) (rel_addr + load_addr); - for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){ - reloc_addr = (int *) (load_addr + (int)rpnt->r_offset); - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - if(symtab_index) { - char * strtab; - struct elf32_sym * symtab; + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) + if (ppnt->p_type == PT_DYNAMIC) { + dpnt = (Elf32_Dyn *) ppnt->p_vaddr; + while (dpnt->d_tag) { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_DEBUG) + dpnt->d_un.d_val = (int) debug_addr; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + app_tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + } + } - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr); + /* Get some more of the information that we will need to dynamicly link + this module to itself */ - /* We only do a partial dynamic linking right now. The user - is not supposed to redefine any symbols that start with - a '_', so we can do this with confidence. */ + hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH] + load_addr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + chains = hash_addr; - if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue; + /* Ugly, ugly. We need to call mprotect to change the protection of + the text pages so that we can do the dynamic linking. We can set the + protection back again once we are done */ - symbol_addr = load_addr + symtab[symtab_index].st_value; + { + elf_phdr *ppnt; + int i; + + /* First cover the shared library/dynamic linker. */ + if (tpnt->dynamic_info[DT_TEXTREL]) { + header = (elfhdr *) dl_data[AT_BASE]; + ppnt = (elf_phdr *) (dl_data[AT_BASE] + header->e_phoff); + for (i = 0; i < header->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (load_addr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } - if(!symbol_addr) { - /* - * This will segfault - you cannot call a function until - * we have finished the relocations. - */ - SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol "); - SEND_STDERR(strtab + symtab[symtab_index].st_name); - SEND_STDERR(" undefined.\n"); - goof++; - } + /* Now cover the application program. */ + if (app_tpnt->dynamic_info[DT_TEXTREL]) { + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } } - /* - * Use this machine-specific macro to perform the actual relocation. - */ - PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); - } - } - if (goof) _dl_exit(14); + /* OK, now do the relocations. We do not do a lazy binding here, so + that once we are done, we have considerably more flexibility. */ + + goof = 0; + for (indx = 0; indx < 2; indx++) { + int i; + ELF_RELOC *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + int symtab_index; + unsigned int rel_addr, rel_size; + + +#ifdef ELF_USES_RELOCA + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_RELA]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELASZ]); +#else + rel_addr = + (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt-> + dynamic_info[DT_REL]); + rel_size = + (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt-> + dynamic_info[DT_RELSZ]); +#endif + - /* OK, at this point we have a crude malloc capability. Start to build - the tables of the modules that are required for this beast to run. - We start with the basic executable, and then go from there. Eventually - we will run across ourself, and we will need to properly deal with that - as well. */ + if (!rel_addr) + continue; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) (rel_addr + load_addr); + for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) { + reloc_addr = (int *) (load_addr + (int) rpnt->r_offset); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + if (symtab_index) { + char *strtab; + Elf32_Sym *symtab; + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + + load_addr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr); + + /* We only do a partial dynamic linking right now. The user + is not supposed to redefine any symbols that start with + a '_', so we can do this with confidence. */ + + if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + + symbol_addr = load_addr + symtab[symtab_index].st_value; + + if (!symbol_addr) { + /* + * This will segfault - you cannot call a function until + * we have finished the relocations. + */ + SEND_STDERR("ELF dynamic loader - unable to " + "self-bootstrap - symbol "); + SEND_STDERR(strtab + symtab[symtab_index].st_name); + SEND_STDERR(" undefined.\n"); + goof++; + } + } + /* + * Use this machine-specific macro to perform the actual relocation. + */ + PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr); + } + } + + if (goof) { + _dl_exit(14); + } - _dl_malloc_addr = malloc_buffer; + /* OK, at this point we have a crude malloc capability. Start to build + the tables of the modules that are required for this beast to run. + We start with the basic executable, and then go from there. Eventually + we will run across ourself, and we will need to properly deal with that + as well. */ - _dl_mmap_zero = mmap_zero; + _dl_malloc_addr = malloc_buffer; + + _dl_mmap_zero = mmap_zero; /* tpnt = _dl_malloc(sizeof(struct elf_resolve)); */ /* Now we have done the mandatory linking of some things. We are now @@ -426,573 +430,594 @@ void _dl_boot(int args){ fixed up by now. Still no function calls outside of this library , since the dynamic resolver is not yet ready. */ - lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); - INIT_GOT(lpnt, tpnt); - - /* OK, this was a big step, now we need to scan all of the user images - and load them properly. */ - - tpnt->next = 0; - tpnt->libname = 0; - tpnt->libtype = program_interpreter; - - { struct elfhdr * epnt; - struct elf_phdr * ppnt; - int i; - - epnt = (struct elfhdr *) dl_data[AT_BASE]; - tpnt->n_phent = epnt->e_phnum; - tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff); - for(i=0;i < epnt->e_phnum; i++, ppnt++){ - if(ppnt->p_type == PT_DYNAMIC) { - tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; - tpnt->dynamic_size = ppnt->p_filesz; - } - } - } - - tpnt->chains = chains; - tpnt->loadaddr = (char *) load_addr; - - brk_addr = 0; - rpnt = NULL; - - /* At this point we are now free to examine the user application, - and figure out which libraries are supposed to be called. Until - we have this list, we will not be completely ready for dynamic linking */ - - { - struct elf_phdr * ppnt; - int i; - - ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) { - if(ppnt->p_type == PT_LOAD) { - if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) - brk_addr = ppnt->p_vaddr + ppnt->p_memsz; - } - if(ppnt->p_type == PT_DYNAMIC) { + lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); + INIT_GOT(lpnt, tpnt); + + /* OK, this was a big step, now we need to scan all of the user images + and load them properly. */ + + tpnt->next = 0; + tpnt->libname = 0; + tpnt->libtype = program_interpreter; + + { + elfhdr *epnt; + elf_phdr *ppnt; + int i; + + epnt = (elfhdr *) dl_data[AT_BASE]; + tpnt->n_phent = epnt->e_phnum; + tpnt->ppnt = ppnt = (elf_phdr *) (load_addr + epnt->e_phoff); + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_DYNAMIC) { + tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; + tpnt->dynamic_size = ppnt->p_filesz; + } + } + } + + tpnt->chains = chains; + tpnt->loadaddr = (char *) load_addr; + + brk_addr = 0; + rpnt = NULL; + + /* At this point we are now free to examine the user application, + and figure out which libraries are supposed to be called. Until + we have this list, we will not be completely ready for dynamic linking */ + + { + elf_phdr *ppnt; + int i; + + ppnt = (elf_phdr *) dl_data[AT_PHDR]; + for (i = 0; i < dl_data[AT_PHNUM]; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD) { + if (ppnt->p_vaddr + ppnt->p_memsz > brk_addr) + brk_addr = ppnt->p_vaddr + ppnt->p_memsz; + } + if (ppnt->p_type == PT_DYNAMIC) { #ifndef ALLOW_ZERO_PLTGOT - /* make sure it's really there. */ - if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue; + /* make sure it's really there. */ + if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) + continue; #endif - /* OK, we have what we need - slip this one into the list. */ - app_tpnt = _dl_add_elf_hash_table("", 0, - app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); - _dl_loaded_modules->libtype = elf_executable; - _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR]; - _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; - _dl_symbol_tables = rpnt = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*rpnt)); - rpnt->dyn = _dl_loaded_modules; - app_tpnt->usage_count++; - app_tpnt->symbol_scope = _dl_symbol_tables; - lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); + /* OK, we have what we need - slip this one into the list. */ + app_tpnt = _dl_add_elf_hash_table("", 0, + app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); + _dl_loaded_modules->libtype = elf_executable; + _dl_loaded_modules->ppnt = (elf_phdr *) dl_data[AT_PHDR]; + _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; + _dl_symbol_tables = rpnt = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*rpnt)); + rpnt->dyn = _dl_loaded_modules; + app_tpnt->usage_count++; + app_tpnt->symbol_scope = _dl_symbol_tables; + lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); #ifdef ALLOW_ZERO_PLTGOT - if (lpnt) + if (lpnt) #endif - INIT_GOT(lpnt, _dl_loaded_modules); - } - if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have - this before */ - tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000)); - } - } - } - - if (argv[0]) - _dl_progname = argv[0]; - - /* Now we need to figure out what kind of options are selected. - Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ - { - _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp); - - if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) || - (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] && - dl_data[AT_GID] == dl_data[AT_EGID])) - { - _dl_secure = 0; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp); - } - else - { - _dl_secure = 1; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); - _dl_unsetenv("LD_AOUT_PRELOAD", envp); - _dl_unsetenv("LD_LIBRARY_PATH", envp); - _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); - _dl_library_path = NULL; - } - } - - _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); - - /* OK, we now have the application in the list, and we have some - basic stuff in place. Now search through the list for other shared - libraries that should be loaded, and insert them on the list in the - correct order. */ + INIT_GOT(lpnt, _dl_loaded_modules); + } + if (ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not + have this before */ + tpnt->libname = _dl_strdup((char *) ppnt->p_offset + + (dl_data[AT_PHDR] & 0xfffff000)); + } + } + } + + if (argv[0]) { + _dl_progname = argv[0]; + } + + /* Now we need to figure out what kind of options are selected. + Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ + { + _dl_not_lazy = _dl_getenv("LD_BIND_NOW", envp); + + if ((dl_data[AT_UID] == -1 && _dl_suid_ok()) || + (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] + && dl_data[AT_GID] == dl_data[AT_EGID])) { + _dl_secure = 0; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp); + } else { + _dl_secure = 1; + _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_unsetenv("LD_AOUT_PRELOAD", envp); + _dl_unsetenv("LD_LIBRARY_PATH", envp); + _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); + _dl_library_path = NULL; + } + } + + _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); + + /* OK, we now have the application in the list, and we have some + basic stuff in place. Now search through the list for other shared + libraries that should be loaded, and insert them on the list in the + correct order. */ + +#ifdef USE_CACHE + _dl_map_cache(); +#endif + + { + struct elf_resolve *tcurr; + struct elf_resolve *tpnt1; + char *lpnt; + + if (_dl_preload) + { + char c, *str, *str2; + + str = _dl_preload; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + while (*str) + { + str2 = str; + while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') + str2++; + c = *str2; + *str2 = '\0'; + if (!_dl_secure || _dl_strchr(str, '/') == NULL) + { + tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", str); + else { + _dl_fdprintf(2, "%s: can't load " + "library '%s'\n", _dl_progname, str); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + /* this is a real hack to make ldd not print + * the library itself when run on a library. */ + if (_dl_strcmp(_dl_progname, str) != 0) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", + str, tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + *str2 = c; + str = str2; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + } + } + + { + int fd; + struct kernel_stat st; + char *preload; + + if (!_dl_stat(LDSO_PRELOAD, &st)) { + if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { + _dl_fdprintf(2, "%s: can't open file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + preload = (caddr_t) _dl_mmap(0, st.st_size + 1, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + _dl_close(fd); + if (preload == (caddr_t) - 1) { + _dl_fdprintf(2, "%s: can't map file '%s'\n", + _dl_progname, LDSO_PRELOAD); + } else { + char c, *cp, *cp2; + + /* convert all separators and comments to spaces */ + for (cp = preload; *cp; /*nada */ ) { + if (*cp == ':' || *cp == '\t' || *cp == '\n') { + *cp++ = ' '; + } else if (*cp == '#') { + do + *cp++ = ' '; + while (*cp != '\n' && *cp != '\0'); + } else { + cp++; + } + } + + /* find start of first library */ + for (cp = preload; *cp && *cp == ' '; cp++) + /*nada */ ; + + while (*cp) { + /* find end of library */ + for (cp2 = cp; *cp && *cp != ' '; cp++) + /*nada */ ; + c = *cp; + *cp = '\0'; + + tpnt1 = _dl_load_shared_library(0, NULL, cp2); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not " + "found\n", cp2); + else { + _dl_fdprintf(2, "%s: can't " + "load library '%s'\n", + _dl_progname, cp2); + _dl_exit(15); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) { + _dl_fdprintf(1, "\t%s => %s " + "(0x%x)\n", cp2, + tpnt1->libname, + (unsigned) tpnt1->loadaddr); + } + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, + sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + + /* find start of next library */ + *cp = c; + for ( /*nada */ ; *cp && *cp == ' '; cp++) + /*nada */ ; + } + + _dl_munmap(preload, st.st_size + 1); + } + } + } + } + + for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) { + for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; + dpnt++) { + if (dpnt->d_tag == DT_NEEDED) { + lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + + dpnt->d_un.d_val; + if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) { + struct elf_resolve *ttmp; + + ttmp = _dl_loaded_modules; + while (ttmp->next) + ttmp = ttmp->next; + ttmp->next = tpnt; + tpnt->prev = ttmp; + tpnt->next = NULL; + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + rpnt->dyn = tpnt; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt = NULL; + continue; + } + if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", lpnt); + else { + _dl_fdprintf(2, "%s: can't load library '%s'\n", + _dl_progname, lpnt); + _dl_exit(16); + } + } else { + if (_dl_trace_loaded_objects + && !tpnt1->usage_count) + _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, + tpnt1->libname, (unsigned) tpnt1->loadaddr); + rpnt->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + } + } + } #ifdef USE_CACHE - _dl_map_cache(); + _dl_unmap_cache(); #endif - { - struct elf_resolve *tcurr; - struct elf_resolve *tpnt1; - char *lpnt; - - if (_dl_preload) { - char c, *str, *str2; - - str = _dl_preload; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - while (*str) { - str2 = str; - while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') - str2++; - c = *str2; - *str2 = '\0'; - if (!_dl_secure || _dl_strchr(str, '/') == NULL) { - tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", str); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, str); - _dl_exit(15); - } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) { - /* this is a real hack to make ldd not print the - library itself when run on a library. */ - if (_dl_strcmp(_dl_progname, str) != 0) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - } - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + /* ldd uses uses this. I am not sure how you pick up the other flags */ + if (_dl_trace_loaded_objects) { + _dl_warn = _dl_getenv("LD_WARN", envp); + if (!_dl_warn) + _dl_exit(0); } - *str2 = c; - str = str2; - while (*str == ':' || *str == ' ' || *str == '\t') - str++; - } - } - - { - int fd; - struct kernel_stat st; - char *preload; - - if (!_dl_stat(LDSO_PRELOAD, &st)) { - if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) { - _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, - MAP_PRIVATE, fd, 0); - _dl_close (fd); - if (preload == (caddr_t)-1) { - _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, - LDSO_PRELOAD); - } else { - char c, *cp, *cp2; - - /* convert all separators and comments to spaces */ - for (cp = preload; *cp; /*nada*/) { - if (*cp == ':' || *cp == '\t' || *cp == '\n') { - *cp++ = ' '; - } else if (*cp == '#') { - do - *cp++ = ' '; - while (*cp != '\n' && *cp != '\0'); - } else { - cp++; - } - } - - /* find start of first library */ - for (cp = preload; *cp && *cp == ' '; cp++) - /*nada*/; - - while (*cp) { - /* find end of library */ - for (cp2 = cp; *cp && *cp != ' '; cp++) - /*nada*/; - c = *cp; - *cp = '\0'; - - tpnt1 = _dl_load_shared_library(0, NULL, cp2); - if (!tpnt1) { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", cp2); - else { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, cp2); - _dl_exit(15); + + /* + * If the program interpreter is not in the module chain, add it. This will + * be required for dlopen to be able to access the internal functions in the + * dynamic linker. + */ + if (tpnt) { + struct elf_resolve *tcurr; + + tcurr = _dl_loaded_modules; + if (tcurr) + while (tcurr->next) + tcurr = tcurr->next; + tpnt->next = NULL; + tpnt->usage_count++; + + if (tcurr) { + tcurr->next = tpnt; + tpnt->prev = tcurr; + } else { + _dl_loaded_modules = tpnt; + tpnt->prev = NULL; } - } else { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } - - /* find start of next library */ - *cp = c; - for (/*nada*/; *cp && *cp == ' '; cp++) - /*nada*/; - } - - _dl_munmap(preload, st.st_size+1); - } + if (rpnt) { + rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt->next, 0, sizeof(*(rpnt->next))); + rpnt = rpnt->next; + } else { + rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset(rpnt, 0, sizeof(*(rpnt->next))); + } + rpnt->dyn = tpnt; + tpnt = NULL; } - } - } - - for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) - { - for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++) - { - if(dpnt->d_tag == DT_NEEDED) + + /* + * OK, now all of the kids are tucked into bed in their proper addresses. + * Now we go through and look for REL and RELA records that indicate fixups + * to the GOT tables. We need to do this in reverse order so that COPY + * directives work correctly */ + + + goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; + + + /* Some flavors of SVr4 do not generate the R_*_COPY directive, + and we have to manually search for entries that require fixups. + Solaris gets this one right, from what I understand. */ + + + if (_dl_symbol_tables) + goof += _dl_copy_fixups(_dl_symbol_tables); + + if (goof || _dl_trace_loaded_objects) + _dl_exit(0); + + /* OK, at this point things are pretty much ready to run. Now we + need to touch up a few items that are required, and then + we can let the user application have at it. Note that + the dynamic linker itself is not guaranteed to be fully + dynamicly linked if we are using ld.so.1, so we have to look + up each symbol individually. */ + + + _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); + if (_dl_brkp) + *_dl_brkp = brk_addr; + _dl_envp = + (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); + + if (_dl_envp) + *_dl_envp = (unsigned int) envp; + { - lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + - dpnt->d_un.d_val; - if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) - { - struct elf_resolve * ttmp; - ttmp = _dl_loaded_modules; - while (ttmp->next) - ttmp = ttmp->next; - ttmp->next = tpnt; - tpnt->prev = ttmp; - tpnt->next = NULL; - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - rpnt->dyn = tpnt; - tpnt->usage_count++; - tpnt->symbol_scope = _dl_symbol_tables; - tpnt = NULL; - continue; - } - if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) - { - if (_dl_trace_loaded_objects) - _dl_fdprintf(1, "\t%s => not found\n", lpnt); - else - { - _dl_fdprintf(2, "%s: can't load library '%s'\n", - _dl_progname, lpnt); - _dl_exit(16); - } - } - else - { - if (_dl_trace_loaded_objects && !tpnt1->usage_count) - _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname, - (unsigned)tpnt1->loadaddr); - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - tpnt1->usage_count++; - tpnt1->symbol_scope = _dl_symbol_tables; - tpnt1->libtype = elf_lib; - rpnt->dyn = tpnt1; - } + int i; + elf_phdr *ppnt; + + /* We had to set the protections of all pages to R/W for dynamic linking. + Set text pages back to R/O */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) + for (ppnt = tpnt->ppnt, i = 0; i < tpnt->n_phent; i++, ppnt++) + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && + tpnt->dynamic_info[DT_TEXTREL]) + _dl_mprotect((void *) (tpnt->loadaddr + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + + (unsigned int) ppnt->p_filesz, + LXFLAGS(ppnt->p_flags)); + } - } - } - } -#ifdef USE_CACHE - _dl_unmap_cache(); -#endif + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - /* ldd uses uses this. I am not sure how you pick up the other flags */ - if(_dl_trace_loaded_objects) - { - _dl_warn = _dl_getenv("LD_WARN", envp); - if (!_dl_warn) _dl_exit(0); - } - - /* - * If the program interpreter is not in the module chain, add it. This will - * be required for dlopen to be able to access the internal functions in the - * dynamic linker. - */ - if(tpnt) { - struct elf_resolve * tcurr; - - tcurr = _dl_loaded_modules; - if (tcurr) - while(tcurr->next) tcurr = tcurr->next; - tpnt->next = NULL; - tpnt->usage_count++; - - if (tcurr) { - tcurr->next = tpnt; - tpnt->prev = tcurr; - } - else { - _dl_loaded_modules = tpnt; - tpnt->prev = NULL; - } - if (rpnt) { - rpnt->next = - (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); - rpnt = rpnt->next; - } else { - rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); - _dl_memset (rpnt, 0, sizeof (*(rpnt->next))); - } - rpnt->dyn = tpnt; - tpnt = NULL; - } - - /* - * OK, now all of the kids are tucked into bed in their proper addresses. - * Now we go through and look for REL and RELA records that indicate fixups - * to the GOT tables. We need to do this in reverse order so that COPY - * directives work correctly */ - - - goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0; - - - /* Some flavors of SVr4 do not generate the R_*_COPY directive, - and we have to manually search for entries that require fixups. - Solaris gets this one right, from what I understand. */ - - - if (_dl_symbol_tables) - goof += _dl_copy_fixups(_dl_symbol_tables); - - if(goof || _dl_trace_loaded_objects) _dl_exit(0); - - /* OK, at this point things are pretty much ready to run. Now we - need to touch up a few items that are required, and then - we can let the user application have at it. Note that - the dynamic linker itself is not guaranteed to be fully - dynamicly linked if we are using ld.so.1, so we have to look - up each symbol individually. */ - - - _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); - if (_dl_brkp) *_dl_brkp = brk_addr; - _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); - - if (_dl_envp) *_dl_envp = (unsigned int) envp; - - { - int i; - struct elf_phdr * ppnt; - - /* We had to set the protections of all pages to R/W for dynamic linking. - Set text pages back to R/O */ - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++) - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) && - tpnt->dynamic_info[DT_TEXTREL]) - _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - LXFLAGS(ppnt->p_flags)); - - } - - _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); - - /* - * OK, fix one more thing - set up the debug_addr structure to point - * to our chain. Later we may need to fill in more fields, but this - * should be enough for now. - */ - debug_addr->r_map = (struct link_map *) _dl_loaded_modules; - debug_addr->r_version = 1; - debug_addr->r_ldbase = load_addr; - debug_addr->r_brk = (unsigned long) &_dl_debug_state; - _dl_debug_addr = debug_addr; - debug_addr->r_state = RT_CONSISTENT; - /* This is written in this funny way to keep gcc from inlining the - function call. */ - ((void (*)(void))debug_addr->r_brk)(); - - for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) - { - /* Apparently crt1 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->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]); - (*_dl_elf_init)(); - } - if(_dl_atexit && tpnt->dynamic_info[DT_FINI]) - { - (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); - } + /* + * OK, fix one more thing - set up the debug_addr structure to point + * to our chain. Later we may need to fill in more fields, but this + * should be enough for now. + */ + debug_addr->r_map = (struct link_map *) _dl_loaded_modules; + debug_addr->r_version = 1; + debug_addr->r_ldbase = load_addr; + debug_addr->r_brk = (unsigned long) &_dl_debug_state; + _dl_debug_addr = debug_addr; + debug_addr->r_state = RT_CONSISTENT; + /* This is written in this funny way to keep gcc from inlining the + function call. */ + ((void (*)(void)) debug_addr->r_brk) (); + + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + /* Apparently crt1 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->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]); + (*_dl_elf_init) (); + } + if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) { + (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); + } #undef DL_DEBUG #ifdef DL_DEBUG - else - { - _dl_fdprintf(2, tpnt->libname); - _dl_fdprintf(2, ": "); - if (!_dl_atexit) - _dl_fdprintf(2, "The address is atexit () is 0x0."); - if (!tpnt->dynamic_info[DT_FINI]) - _dl_fdprintf(2, "Invalid .fini section."); - _dl_fdprintf(2, "\n"); - } + else { + _dl_fdprintf(2, tpnt->libname); + _dl_fdprintf(2, ": "); + if (!_dl_atexit) + _dl_fdprintf(2, "The address is atexit () is 0x0."); + if (!tpnt->dynamic_info[DT_FINI]) + _dl_fdprintf(2, "Invalid .fini section."); + _dl_fdprintf(2, "\n"); + } #endif #undef DL_DEBUG - } + } - /* OK we are done here. Turn out the lights, and lock up. */ - _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY]; + /* OK we are done here. Turn out the lights, and lock up. */ + _dl_elf_main = (int (*)(int, char **, char **)) dl_data[AT_ENTRY]; - /* - * Transfer control to the application. - */ - START(); + /* + * Transfer control to the application. + */ + START(); } -int _dl_fixup(struct elf_resolve * tpnt) +int _dl_fixup(struct elf_resolve *tpnt) { - int goof = 0; - if(tpnt->next) goof += _dl_fixup(tpnt->next); + int goof = 0; + + if (tpnt->next) + goof += _dl_fixup(tpnt->next); - if(tpnt->dynamic_info[DT_REL]) { + if (tpnt->dynamic_info[DT_REL]) { #ifdef ELF_USES_RELOCA - _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname); - _dl_exit(17); + _dl_fdprintf(2, "%s: can't handle REL relocation records\n", + _dl_progname); + _dl_exit(17); #else - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL], - tpnt->dynamic_info[DT_RELSZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_REL], tpnt->dynamic_info[DT_RELSZ], 0); #endif - } - if(tpnt->dynamic_info[DT_RELA]) { + } + if (tpnt->dynamic_info[DT_RELA]) { #ifdef ELF_USES_RELOCA - if (tpnt->init_flag & RELOCS_DONE) return goof; - tpnt->init_flag |= RELOCS_DONE; - - goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA], - tpnt->dynamic_info[DT_RELASZ], 0); + if (tpnt->init_flag & RELOCS_DONE) + return goof; + tpnt->init_flag |= RELOCS_DONE; + + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); #else - _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname); - _dl_exit(18); + _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", + _dl_progname); + _dl_exit(18); #endif - } - if(tpnt->dynamic_info[DT_JMPREL]) - { - if (tpnt->init_flag & JMP_RELOCS_DONE) return goof; - tpnt->init_flag |= JMP_RELOCS_DONE; - - if(! _dl_not_lazy || *_dl_not_lazy == 0) - _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - else - goof += _dl_parse_relocation_information(tpnt, - tpnt->dynamic_info[DT_JMPREL], - tpnt->dynamic_info[DT_PLTRELSZ], 0); - } - return goof; + } + if (tpnt->dynamic_info[DT_JMPREL]) { + if (tpnt->init_flag & JMP_RELOCS_DONE) + return goof; + tpnt->init_flag |= JMP_RELOCS_DONE; + + if (!_dl_not_lazy || *_dl_not_lazy == 0) + _dl_parse_lazy_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + else + goof += _dl_parse_relocation_information(tpnt, + tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ], 0); + } + return goof; } -void * _dl_malloc(int size) { - void * retval; - - if(_dl_malloc_function) - return (*_dl_malloc_function)(size); - - if(_dl_malloc_addr-_dl_mmap_zero+size>4096) { - _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(_dl_mmap_check_error(_dl_mmap_zero)) { - _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); - _dl_exit(20); - } - } - retval = _dl_malloc_addr; - _dl_malloc_addr += size; - - /* - * Align memory to 4 byte boundary. Some platforms require this, others - * simply get better performance. - */ - _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); - return retval; +void *_dl_malloc(int size) +{ + void *retval; + + if (_dl_malloc_function) + return (*_dl_malloc_function) (size); + + if (_dl_malloc_addr - _dl_mmap_zero + size > 4096) { + _dl_mmap_zero = _dl_malloc_addr = + (unsigned char *) _dl_mmap((void *) 0, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(_dl_mmap_zero)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_exit(20); + } + } + retval = _dl_malloc_addr; + _dl_malloc_addr += size; + + /* + * Align memory to 4 byte boundary. Some platforms require this, others + * simply get better performance. + */ + _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); + return retval; } -char * _dl_getenv(char *symbol, char **envp) +char *_dl_getenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - while ((pnt = *envp++)) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if (!*pnt || *pnt != '=' || *pnt1) - continue; - return pnt+1; - } - return 0; + char *pnt; + char *pnt1; + + while ((pnt = *envp++)) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + continue; + return pnt + 1; + } + return 0; } void _dl_unsetenv(char *symbol, char **envp) { - char *pnt; - char *pnt1; - char **newenvp = envp; - for (pnt = *envp; pnt; pnt = *++envp) { - pnt1 = symbol; - while (*pnt && *pnt == *pnt1) - pnt1++, pnt++; - if(!*pnt || *pnt != '=' || *pnt1) - *newenvp++ = *envp; - } - *newenvp++ = *envp; - return; + char *pnt; + char *pnt1; + char **newenvp = envp; + + for (pnt = *envp; pnt; pnt = *++envp) { + pnt1 = symbol; + while (*pnt && *pnt == *pnt1) + pnt1++, pnt++; + if (!*pnt || *pnt != '=' || *pnt1) + *newenvp++ = *envp; + } + *newenvp++ = *envp; + return; } -char * _dl_strdup(const char * string){ - char * retval; - int len; +char *_dl_strdup(const char *string) +{ + char *retval; + int len; - len = _dl_strlen(string); - retval = _dl_malloc(len + 1); - _dl_strcpy(retval, string); - return retval; + len = _dl_strlen(string); + retval = _dl_malloc(len + 1); + _dl_strcpy(retval, string); + return retval; } - diff --git a/ldso/ldso/linuxelf.h b/ldso/ldso/linuxelf.h index e90a8c3a4..bab9cd47a 100644 --- a/ldso/ldso/linuxelf.h +++ b/ldso/ldso/linuxelf.h @@ -1,181 +1,69 @@ -/* This should eventually appear in the distribution version of linux/elf.h */ -#ifndef R_SPARC_NONE -#define R_SPARC_NONE 0 -#define R_SPARC_8 1 -#define R_SPARC_16 2 -#define R_SPARC_32 3 -#define R_SPARC_DISP8 4 -#define R_SPARC_DISP16 5 -#define R_SPARC_DISP32 6 -#define R_SPARC_WDISP30 7 -#define R_SPARC_WDISP22 8 -#define R_SPARC_HI22 9 -#define R_SPARC_22 10 -#define R_SPARC_13 11 -#define R_SPARC_LO10 12 -#define R_SPARC_GOT10 13 -#define R_SPARC_GOT13 14 -#define R_SPARC_GOT22 15 -#define R_SPARC_PC10 16 -#define R_SPARC_PC22 17 -#define R_SPARC_WPLT30 18 -#define R_SPARC_COPY 19 -#define R_SPARC_GLOB_DAT 20 -#define R_SPARC_JMP_SLOT 21 -#define R_SPARC_RELATIVE 22 -#define R_SPARC_UA32 23 -#endif - -#ifndef R_68K_NONE -#define R_68K_NONE 0 -#define R_68K_32 1 -#define R_68K_16 2 -#define R_68K_8 3 -#define R_68K_PC32 4 -#define R_68K_PC16 5 -#define R_68K_PC8 6 -#define R_68K_GOT32 7 -#define R_68K_GOT16 8 -#define R_68K_GOT8 9 -#define R_68K_GOT32O 10 -#define R_68K_GOT16O 11 -#define R_68K_GOT8O 12 -#define R_68K_PLT32 13 -#define R_68K_PLT16 14 -#define R_68K_PLT8 15 -#define R_68K_PLT32O 16 -#define R_68K_PLT16O 17 -#define R_68K_PLT8O 18 -#define R_68K_COPY 19 -#define R_68K_GLOB_DAT 20 -#define R_68K_JMP_SLOT 21 -#define R_68K_RELATIVE 22 -#define R_68K_NUM 23 -#endif - - -/* ARM relocs. */ -#ifndef R_ARM_NONE -#define R_ARM_NONE 0 /* No reloc */ -#define R_ARM_PC24 1 /* PC relative 26 bit branch */ -#define R_ARM_ABS32 2 /* Direct 32 bit */ -#define R_ARM_REL32 3 /* PC relative 32 bit */ -#define R_ARM_PC13 4 -#define R_ARM_ABS16 5 /* Direct 16 bit */ -#define R_ARM_ABS12 6 /* Direct 12 bit */ -#define R_ARM_THM_ABS5 7 -#define R_ARM_ABS8 8 /* Direct 8 bit */ -#define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 -#define R_ARM_THM_PC8 11 -#define R_ARM_AMP_VCALL9 12 -#define R_ARM_SWI24 13 -#define R_ARM_THM_SWI8 14 -#define R_ARM_XPC25 15 -#define R_ARM_THM_XPC22 16 -#define R_ARM_COPY 20 /* Copy symbol at runtime */ -#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ -#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ -#define R_ARM_RELATIVE 23 /* Adjust by program base */ -#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ -#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ -#define R_ARM_GOT32 26 /* 32 bit GOT entry */ -#define R_ARM_PLT32 27 /* 32 bit PLT address */ -#define R_ARM_GNU_VTENTRY 100 -#define R_ARM_GNU_VTINHERIT 101 -#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ -#define R_ARM_THM_PC9 103 /* thumb conditional branch */ -#define R_ARM_RXPC25 249 -#define R_ARM_RSBREL32 250 -#define R_ARM_THM_RPC22 251 -#define R_ARM_RREL32 252 -#define R_ARM_RABS22 253 -#define R_ARM_RPC24 254 -#define R_ARM_RBASE 255 -/* Keep this the last entry. */ -#define R_ARM_NUM 256 -#endif +#ifndef LINUXELF_H +#define LINUXELF_H +/* Forward declarations for stuff defined in hash.h */ +struct dyn_elf; +struct elf_resolve; -/* - * These constants define the elements of the auxiliary vector used to - * pass additional information from the kernel to an ELF application. - */ - -#ifndef AT_NULL -typedef struct -{ - int a_type; - union{ - long a_val; - void *p_ptr; - void (*a_fcn)(); - } a_un; -} auxv_t; -/* - * Values of a_type... These often appear in the file /usr/include/sys/auxv.h - * on SVr4 systems. - */ -#define AT_NULL 0 -#define AT_IGNORE 1 -#define AT_EXECFD 2 -#define AT_PHDR 3 -#define AT_PHENT 4 -#define AT_PHNUM 5 -#define AT_PAGESZ 6 -#define AT_BASE 7 -#define AT_FLAGS 8 -#define AT_ENTRY 9 -#endif -#ifndef AT_NOTELF -#define AT_NOTELF 10 /* program is not ELF */ -#define AT_UID 11 /* real uid */ -#define AT_EUID 12 /* effective uid */ -#define AT_GID 13 /* real gid */ -#define AT_EGID 14 /* effective gid */ -#endif - -extern int _dl_linux_resolve(void); -extern struct elf_resolve * _dl_load_shared_library(int secure, - struct elf_resolve *, char * libname); +/* Some function prototypes */ extern void * _dl_malloc(int size); extern int _dl_map_cache(void); extern int _dl_unmap_cache(void); - -extern struct elf_resolve * _dl_load_elf_shared_library(int secure, - char * libname, int); int _dl_copy_fixups(struct dyn_elf * tpnt); - -extern int linux_run(int argc, char * argv[]); - -extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr, - int rel_size, int type); - extern int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, int rel_size, int type); +extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr, + int rel_size, int type); +extern struct elf_resolve * _dl_load_shared_library(int secure, + struct elf_resolve *, char * libname); +extern struct elf_resolve * _dl_load_elf_shared_library(int secure, + char * libname, int); extern int _dl_parse_copy_information(struct dyn_elf * rpnt, int rel_addr, int rel_size, int type); +extern int _dl_linux_resolve(void); +#define ELF_CLASS ELFCLASS32 -/* This means that we may be forced to manually search for copy fixups - which were omitted by the linker. We cannot depend upon the DT_TEXTREL - to tell us whether there are fixups in a text section or not. */ - #ifndef SVR4_BUGCOMPAT #define SVR4_BUGCOMPAT 1 #endif -#ifndef PF_R -#define PF_R 4 -#define PF_W 2 -#define PF_X 1 +#if ELF_CLASS == ELFCLASS32 + +#define elfhdr Elf32_Ehdr +#define elf_phdr Elf32_Phdr +#define elf_note Elf32_Nhdr +/* + * Datatype of a relocation on this platform + */ +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf32_Rela +#else +# define ELF_RELOC Elf32_Rel +#endif + +#else + +#define elfhdr Elf64_Ehdr +#define elf_phdr Elf64_Phdr +#define elf_note Elf64_Nhdr +/* + * Datatype of a relocation on this platform + */ +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf64_Rela +#else +# define ELF_RELOC Elf64_Rel +#endif + #endif + /* Convert between the Linux flags for page protections and the ones specified in the ELF standard. */ - #define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \ (((X) & PF_W) ? PROT_WRITE : 0) | \ (((X) & PF_X) ? PROT_EXEC : 0)) +#endif /* LINUXELF_H */ diff --git a/ldso/ldso/m68k/dl-syscalls.h b/ldso/ldso/m68k/dl-syscalls.h index 6b1624b8f..df7e36776 100644 --- a/ldso/ldso/m68k/dl-syscalls.h +++ b/ldso/ldso/m68k/dl-syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index 9b73efd3f..b3bfeee1a 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -48,20 +48,12 @@ static char *_dl_reltypes[] = a more than adequate job of explaining everything required to get this working. */ -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/unistd.h> -/*#include <stdlib.h>*/ -#include "string.h" -#include <linux/unistd.h> -#include <linux/fcntl.h> -#include <linux/elf.h> - +#include <sys/types.h> +#include "elf.h" #include "hash.h" -#include "linuxelf.h" +#include "syscall.h" +#include "string.h" #include "sysdep.h" -#include "../syscall.h" -#include "../string.h" extern char *_dl_progname; @@ -70,9 +62,9 @@ _dl_linux_resolver (int dummy1, int dummy2, struct elf_resolve *tpnt, int reloc_entry) { int reloc_type; - struct elf32_rela *this_reloc; + Elf32_Rela *this_reloc; char *strtab; - struct elf32_sym *symtab; + Elf32_Sym *symtab; char *rel_addr; int symtab_index; char *new_addr; @@ -80,11 +72,11 @@ _dl_linux_resolver (int dummy1, int dummy2, unsigned int instr_addr; rel_addr = tpnt->loadaddr + tpnt->dynamic_info[DT_JMPREL]; - this_reloc = (struct elf32_rela *) (rel_addr + reloc_entry); + this_reloc = (Elf32_Rela *) (rel_addr + reloc_entry); reloc_type = ELF32_R_TYPE (this_reloc->r_info); symtab_index = ELF32_R_SYM (this_reloc->r_info); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); @@ -133,15 +125,15 @@ _dl_parse_lazy_relocation_information (struct elf_resolve *tpnt, int rel_addr, char *strtab; int reloc_type; int symtab_index; - struct elf32_sym *symtab; - struct elf32_rela *rpnt; + Elf32_Sym *symtab; + Elf32_Rela *rpnt; unsigned int *reloc_addr; /* Now parse the relocation information. */ - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof (struct elf32_rela); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof (Elf32_Rela); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); @@ -186,17 +178,17 @@ _dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr, char *strtab; int reloc_type; int goof = 0; - struct elf32_sym *symtab; - struct elf32_rela *rpnt; + Elf32_Sym *symtab; + Elf32_Rela *rpnt; unsigned int *reloc_addr; unsigned int symbol_addr; int symtab_index; /* Now parse the relocation information */ - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof (struct elf32_rela); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof (Elf32_Rela); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); @@ -309,8 +301,8 @@ _dl_parse_copy_information (struct dyn_elf *xpnt, int rel_addr, char *strtab; int reloc_type; int goof = 0; - struct elf32_sym *symtab; - struct elf32_rela *rpnt; + Elf32_Sym *symtab; + Elf32_Rela *rpnt; unsigned int *reloc_addr; unsigned int symbol_addr; struct elf_resolve *tpnt; @@ -319,10 +311,10 @@ _dl_parse_copy_information (struct dyn_elf *xpnt, int rel_addr, tpnt = xpnt->dyn; - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof (struct elf32_rela); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof (Elf32_Rela); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); diff --git a/ldso/ldso/m68k/ld_syscalls.h b/ldso/ldso/m68k/ld_syscalls.h index 6b1624b8f..df7e36776 100644 --- a/ldso/ldso/m68k/ld_syscalls.h +++ b/ldso/ldso/m68k/ld_syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/m68k/syscalls.h b/ldso/ldso/m68k/syscalls.h index 6b1624b8f..df7e36776 100644 --- a/ldso/ldso/m68k/syscalls.h +++ b/ldso/ldso/m68k/syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c index 9d1cd0ff5..d9b900809 100644 --- a/ldso/ldso/readelflib1.c +++ b/ldso/ldso/readelflib1.c @@ -21,17 +21,11 @@ /* This file contains the helper routines to load an ELF sharable library into memory and add the symbol table info to the chain. */ -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/errno.h> +#include <asm/mman.h> +#include "elf.h" #include "string.h" -/*#include <stdlib.h>*/ -#include <linux/mman.h> -#include <linux/stat.h> #include "hash.h" -#include "linuxelf.h" #include "sysdep.h" -#include <linux/unistd.h> #include "syscall.h" #ifdef USE_CACHE #include "../config.h" @@ -46,80 +40,79 @@ static size_t _dl_cache_size = 0; int _dl_map_cache(void) { - int fd; - struct kernel_stat st; - header_t *header; - libentry_t *libent; - int i, strtabsize; - - if (_dl_cache_addr == (caddr_t)-1) - return -1; - else if (_dl_cache_addr != NULL) - return 0; - - if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) - { - _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE); - _dl_cache_addr = (caddr_t)-1; /* so we won't try again */ - return -1; - } - - _dl_cache_size = st.st_size; - _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ, - MAP_SHARED, fd, 0); - _dl_close (fd); - if (_dl_cache_addr == (caddr_t)-1) - { - _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE); - return -1; - } - - header = (header_t *)_dl_cache_addr; - - if (_dl_cache_size < sizeof (header_t) || - _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) || - _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) || - _dl_cache_size < - (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) || - _dl_cache_addr[_dl_cache_size-1] != '\0') - { - _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); - goto fail; - } - - strtabsize = _dl_cache_size - sizeof (header_t) - - header->nlibs * sizeof (libentry_t); - libent = (libentry_t *)&header[1]; - - for (i = 0; i < header->nlibs; i++) - { - if (libent[i].sooffset >= strtabsize || - libent[i].liboffset >= strtabsize) - { - _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); - goto fail; - } - } - - return 0; - -fail: - _dl_munmap(_dl_cache_addr, _dl_cache_size); - _dl_cache_addr = (caddr_t)-1; - return -1; + int fd; + struct kernel_stat st; + header_t *header; + libentry_t *libent; + int i, strtabsize; + + if (_dl_cache_addr == (caddr_t) - 1) + return -1; + else if (_dl_cache_addr != NULL) + return 0; + + if (_dl_stat(LDSO_CACHE, &st) + || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) { + _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE); + _dl_cache_addr = (caddr_t) - 1; /* so we won't try again */ + return -1; + } + + _dl_cache_size = st.st_size; + _dl_cache_addr = (caddr_t) _dl_mmap(0, _dl_cache_size, PROT_READ, MAP_SHARED, fd, 0); + _dl_close(fd); + if (_dl_cache_addr == (caddr_t) - 1) { + _dl_fdprintf(2, "%s: can't map cache '%s'\n", + _dl_progname, LDSO_CACHE); + return -1; + } + + header = (header_t *) _dl_cache_addr; + + if (_dl_cache_size < sizeof(header_t) || + _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) + || _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) + || _dl_cache_size < + (sizeof(header_t) + header->nlibs * sizeof(libentry_t)) + || _dl_cache_addr[_dl_cache_size - 1] != '\0') + { + _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, + LDSO_CACHE); + goto fail; + } + + strtabsize = _dl_cache_size - sizeof(header_t) - + header->nlibs * sizeof(libentry_t); + libent = (libentry_t *) & header[1]; + + for (i = 0; i < header->nlibs; i++) { + if (libent[i].sooffset >= strtabsize || + libent[i].liboffset >= strtabsize) + { + _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); + goto fail; + } + } + + return 0; + + fail: + _dl_munmap(_dl_cache_addr, _dl_cache_size); + _dl_cache_addr = (caddr_t) - 1; + return -1; } int _dl_unmap_cache(void) { - if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1) - return -1; + if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t) - 1) + return -1; #if 1 - _dl_munmap (_dl_cache_addr, _dl_cache_size); - _dl_cache_addr = NULL; + _dl_munmap(_dl_cache_addr, _dl_cache_size); + _dl_cache_addr = NULL; #endif - return 0; + return 0; } #endif @@ -131,160 +124,182 @@ int _dl_unmap_cache(void) unsigned int _dl_error_number; unsigned int _dl_internal_error_number; -struct elf_resolve * _dl_load_shared_library(int secure, - struct elf_resolve * tpnt, char * full_libname) { - char * pnt, *pnt1, *pnt2; - struct elf_resolve *tpnt1 = NULL; - char mylibname[2050]; - char * libname; - - _dl_internal_error_number = 0; - - /* quick hack to ensure mylibname buffer doesn't overflow. don't - allow full_libname or any directory to be longer than 1024. */ - if (_dl_strlen(full_libname) > 1024) - goto goof; - - pnt = libname = full_libname; - while (*pnt) { - if(*pnt == '/') libname = pnt+1; - pnt++; - } - - /* If the filename has any '/', try it straight and leave it at that. - For IBCS2 compatibility under linux, we substitute the string - /usr/i486-sysv4/lib for /usr/lib in library names. */ - - if (libname != full_libname) { - tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); - if (tpnt1) - return tpnt1; - goto goof; - } - - /* - * The ABI specifies that RPATH is searched before LD_*_PATH or - * the default path of /usr/lib. - * Check in rpath directories - */ - for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { - if (tpnt->libtype == elf_executable) { - pnt1 = (char *)tpnt->dynamic_info[DT_RPATH]; - if(pnt1) { - pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB]; - while(*pnt1){ - pnt2 = mylibname; - while(*pnt1 && *pnt1 != ':') { - if (pnt2 - mylibname < 1024) - *pnt2++ = *pnt1++; - else - pnt1++; - } - if (pnt2 - mylibname >= 1024) - break; - if(pnt2[-1] != '/') *pnt2++ = '/'; - pnt = libname; - while(*pnt) *pnt2++ = *pnt++; - *pnt2++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if(tpnt1) return tpnt1; - if(*pnt1 == ':') pnt1++; +struct elf_resolve *_dl_load_shared_library(int secure, + struct elf_resolve *tpnt, char *full_libname) +{ + char *pnt, *pnt1, *pnt2; + struct elf_resolve *tpnt1 = NULL; + char mylibname[2050]; + char *libname; + + _dl_internal_error_number = 0; + + /* quick hack to ensure mylibname buffer doesn't overflow. don't + allow full_libname or any directory to be longer than 1024. */ + if (_dl_strlen(full_libname) > 1024) + goto goof; + + pnt = libname = full_libname; + while (*pnt) { + if (*pnt == '/') + libname = pnt + 1; + pnt++; } - } - } - } - - - /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ - pnt1 = _dl_library_path; - if (pnt1 && *pnt1) { - while (*pnt1) { - pnt2 = mylibname; - while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') { - if (pnt2 - mylibname < 1024) - *pnt2++ = *pnt1++; - else - pnt1++; - } - if (pnt2 - mylibname >= 1024) - break; - if(pnt2[-1] != '/') *pnt2++ = '/'; - pnt = libname; - while(*pnt) *pnt2++ = *pnt++; - *pnt2++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if(tpnt1) return tpnt1; - if(*pnt1 == ':' || *pnt1 == ';') pnt1++; - } - } - - - /* - * Where should the cache be searched? There is no such concept in the - * ABI, so we have some flexibility here. For now, search it before - * the default path of /usr/lib. - */ + + /* If the filename has any '/', try it straight and leave it at that. + For IBCS2 compatibility under linux, we substitute the string + /usr/i486-sysv4/lib for /usr/lib in library names. */ + + if (libname != full_libname) { + tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); + if (tpnt1) + return tpnt1; + goto goof; + } + + /* + * The ABI specifies that RPATH is searched before LD_*_PATH or + * the default path of /usr/lib. + * Check in rpath directories + */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (tpnt->libtype == elf_executable) { + pnt1 = (char *) tpnt->dynamic_info[DT_RPATH]; + if (pnt1) { + pnt1 += (unsigned int) tpnt->loadaddr + + tpnt->dynamic_info[DT_STRTAB]; + while (*pnt1) { + pnt2 = mylibname; + while (*pnt1 && *pnt1 != ':') { + if (pnt2 - mylibname < 1024) + *pnt2++ = *pnt1++; + else + pnt1++; + } + if (pnt2 - mylibname >= 1024) + break; + if (pnt2[-1] != '/') + *pnt2++ = '/'; + pnt = libname; + while (*pnt) + *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = + _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + if (*pnt1 == ':') + pnt1++; + } + } + } + } + + + /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ + pnt1 = _dl_library_path; + if (pnt1 && *pnt1) { + while (*pnt1) { + pnt2 = mylibname; + while (*pnt1 && *pnt1 != ':' && *pnt1 != ';') { + if (pnt2 - mylibname < 1024) + *pnt2++ = *pnt1++; + else + pnt1++; + } + if (pnt2 - mylibname >= 1024) + break; + if (pnt2[-1] != '/') + *pnt2++ = '/'; + pnt = libname; + while (*pnt) + *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + if (*pnt1 == ':' || *pnt1 == ';') + pnt1++; + } + } + + + /* + * Where should the cache be searched? There is no such concept in the + * ABI, so we have some flexibility here. For now, search it before + * the default path of /usr/lib. + */ #ifdef USE_CACHE - if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1) - { - int i; - header_t *header = (header_t *)_dl_cache_addr; - libentry_t *libent = (libentry_t *)&header[1]; - char *strs = (char *)&libent[header->nlibs]; - - for (i = 0; i < header->nlibs; i++) - { - if ((libent[i].flags == LIB_ELF || - libent[i].flags == LIB_ELF_LIBC5) && - _dl_strcmp(libname, strs+libent[i].sooffset) == 0 && - (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0))) - return tpnt1; - } - } + if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t) - 1) { + int i; + header_t *header = (header_t *) _dl_cache_addr; + libentry_t *libent = (libentry_t *) & header[1]; + char *strs = (char *) &libent[header->nlibs]; + + for (i = 0; i < header->nlibs; i++) { + if ((libent[i].flags == LIB_ELF || + libent[i].flags == LIB_ELF_LIBC5) && + _dl_strcmp(libname, strs + libent[i].sooffset) == 0 && + (tpnt1 = _dl_load_elf_shared_library(secure, + strs + libent[i].liboffset, 0))) + return tpnt1; + } + } #endif #ifdef UCLIBC_DEVEL - /* Check in /usr/<arch>-linux-uclibc/lib */ - pnt1 = UCLIBC_INSTALL_DIR"/lib"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; - + /* Check in /usr/<arch>-linux-uclibc/lib */ + pnt1 = UCLIBC_INSTALL_DIR "/lib"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + #else /* UCLIBC_DEVEL */ - /* Check in /usr/lib */ - pnt1 = "/usr/lib/"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; - - /* Check in /lib */ - /* try "/lib/". */ - pnt1 = "/lib/"; - pnt = mylibname; - while(*pnt1) *pnt++ = *pnt1++; - pnt1 = libname; - while(*pnt1) *pnt++ = *pnt1++; - *pnt++ = 0; - tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); - if (tpnt1) return tpnt1; + /* Check in /usr/lib */ + pnt1 = "/usr/lib/"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; + + /* Check in /lib */ + /* try "/lib/". */ + pnt1 = "/lib/"; + pnt = mylibname; + while (*pnt1) + *pnt++ = *pnt1++; + pnt1 = libname; + while (*pnt1) + *pnt++ = *pnt1++; + *pnt++ = 0; + tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0); + if (tpnt1) + return tpnt1; #endif /* UCLIBC_DEVEL */ -goof: - /* Well, we shot our wad on that one. All we can do now is punt */ - if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number; - else _dl_error_number = DL_ERROR_NOFILE; - return NULL; + goof: + /* Well, we shot our wad on that one. All we can do now is punt */ + if (_dl_internal_error_number) + _dl_error_number = _dl_internal_error_number; + else + _dl_error_number = DL_ERROR_NOFILE; + return NULL; } /* @@ -295,264 +310,273 @@ goof: //extern _elf_rtbndr(void); -struct elf_resolve * _dl_load_elf_shared_library(int secure, - char * libname, int flag) { - struct elfhdr * epnt; - unsigned int dynamic_addr = 0; - unsigned int dynamic_size = 0; - struct dynamic * dpnt; - struct elf_resolve * tpnt; - struct elf_phdr * ppnt; - int piclib; - char * status; - int flags; - char header[4096]; - int dynamic_info[24]; - int * lpnt; - unsigned int libaddr; - unsigned int minvma=0xffffffff, maxvma=0; - - int i; - int infile; - - /* If this file is already loaded, skip this step */ - tpnt = _dl_check_hashed_files(libname); - if(tpnt) return tpnt; - - /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD), - we don't load the library if it isn't setuid. */ - - if (secure) { - struct kernel_stat st; - if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID)) - return NULL; - } - - libaddr = 0; - infile = _dl_open(libname, O_RDONLY); - if(infile < 0) - { +struct elf_resolve *_dl_load_elf_shared_library(int secure, + char *libname, int flag) +{ + elfhdr *epnt; + unsigned int dynamic_addr = 0; + unsigned int dynamic_size = 0; + Elf32_Dyn *dpnt; + struct elf_resolve *tpnt; + elf_phdr *ppnt; + int piclib; + char *status; + int flags; + char header[4096]; + int dynamic_info[24]; + int *lpnt; + unsigned int libaddr; + unsigned int minvma = 0xffffffff, maxvma = 0; + + int i; + int infile; + + /* If this file is already loaded, skip this step */ + tpnt = _dl_check_hashed_files(libname); + if (tpnt) + return tpnt; + + /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD), + we don't load the library if it isn't setuid. */ + + if (secure) { + struct kernel_stat st; + + if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID)) + return NULL; + } + + libaddr = 0; + infile = _dl_open(libname, O_RDONLY); + if (infile < 0) { #if 0 - /* - * NO! When we open shared libraries we may search several paths. - * it is inappropriate to generate an error here. - */ - _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); + /* + * NO! When we open shared libraries we may search several paths. + * it is inappropriate to generate an error here. + */ + _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname); #endif - _dl_internal_error_number = DL_ERROR_NOFILE; - return NULL; - } - - _dl_read(infile, header, sizeof(header)); - epnt = (struct elfhdr *) header; - if (epnt->e_ident[0] != 0x7f || - epnt->e_ident[1] != 'E' || - epnt->e_ident[2] != 'L' || - epnt->e_ident[3] != 'F') { - _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_NOTELF; - _dl_close(infile); - return NULL; - }; - - if((epnt->e_type != ET_DYN) || - (epnt->e_machine != MAGIC1 + _dl_internal_error_number = DL_ERROR_NOFILE; + return NULL; + } + + _dl_read(infile, header, sizeof(header)); + epnt = (elfhdr *) header; + if (epnt->e_ident[0] != 0x7f || + epnt->e_ident[1] != 'E' || + epnt->e_ident[2] != 'L' || + epnt->e_ident[3] != 'F') + { + _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, + libname); + _dl_internal_error_number = DL_ERROR_NOTELF; + _dl_close(infile); + return NULL; + }; + + if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1 #ifdef MAGIC2 - && epnt->e_machine != MAGIC2 + && epnt->e_machine != MAGIC2 #endif - )){ - _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); - _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n", - _dl_progname, libname); - _dl_close(infile); - return NULL; - }; - - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - - piclib = 1; - for(i=0;i < epnt->e_phnum; i++){ - - if(ppnt->p_type == PT_DYNAMIC) { - if (dynamic_addr) - _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n", - _dl_progname, libname); - dynamic_addr = ppnt->p_vaddr; - dynamic_size = ppnt->p_filesz; - }; - - if(ppnt->p_type == PT_LOAD) { - /* See if this is a PIC library. */ - if(i == 0 && ppnt->p_vaddr > 0x1000000) { - piclib = 0; - minvma=ppnt->p_vaddr; + )) + { + _dl_internal_error_number = + (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC); + _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET + "\n", _dl_progname, libname); + _dl_close(infile); + return NULL; + }; + + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + + piclib = 1; + for (i = 0; i < epnt->e_phnum; i++) { + + if (ppnt->p_type == PT_DYNAMIC) { + if (dynamic_addr) + _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n", + _dl_progname, libname); + dynamic_addr = ppnt->p_vaddr; + dynamic_size = ppnt->p_filesz; + }; + + if (ppnt->p_type == PT_LOAD) { + /* See if this is a PIC library. */ + if (i == 0 && ppnt->p_vaddr > 0x1000000) { + piclib = 0; + minvma = ppnt->p_vaddr; + } + if (piclib && ppnt->p_vaddr < minvma) { + minvma = ppnt->p_vaddr; + } + if (((unsigned int) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { + maxvma = ppnt->p_vaddr + ppnt->p_memsz; + } + } + ppnt++; + }; + + maxvma = (maxvma + 0xfffU) & ~0xfffU; + minvma = minvma & ~0xffffU; + + flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ; + if (!piclib) + flags |= MAP_FIXED; + + status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma), + maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_close(infile); + return NULL; + }; + libaddr = (unsigned int) status; + flags |= MAP_FIXED; + + /* Get the memory to store the library */ + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + + for (i = 0; i < epnt->e_phnum; i++) { + if (ppnt->p_type == PT_LOAD) { + + /* See if this is a PIC library. */ + if (i == 0 && ppnt->p_vaddr > 0x1000000) { + piclib = 0; + /* flags |= MAP_FIXED; */ + } + + + + if (ppnt->p_flags & PF_W) { + unsigned int map_size; + char *cpnt; + + status = (char *) _dl_mmap((char *) ((piclib ? libaddr : 0) + + (ppnt->p_vaddr & 0xfffff000)), (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile, + ppnt->p_offset & 0x7ffff000); + + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '%s'\n", + _dl_progname, libname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_munmap((char *) libaddr, maxvma - minvma); + _dl_close(infile); + return NULL; + }; + + /* Pad the last page with zeroes. */ + cpnt = (char *) (status + (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz); + while (((unsigned int) cpnt) & 0xfff) + *cpnt++ = 0; + + /* I am not quite sure if this is completely + * correct to do or not, but the basic way that + * we handle bss segments is that we mmap + * /dev/zero if there are any pages left over + * that are not mapped as part of the file */ + + map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000; + if (map_size < ppnt->p_vaddr + ppnt->p_memsz) + status = (char *) _dl_mmap((char *) map_size + + (piclib ? libaddr : 0), + ppnt->p_vaddr + ppnt->p_memsz - map_size, + LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS, -1, 0); + } else + status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + + (piclib ? libaddr : 0), (ppnt->p_vaddr & 0xfff) + + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, + infile, ppnt->p_offset & 0x7ffff000); + if (_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_munmap((char *) libaddr, maxvma - minvma); + _dl_close(infile); + return NULL; + }; + + /* if(libaddr == 0 && piclib) { + libaddr = (unsigned int) status; + flags |= MAP_FIXED; + }; */ + }; + ppnt++; + }; + _dl_close(infile); + + /* For a non-PIC library, the addresses are all absolute */ + if (piclib) { + dynamic_addr += (unsigned int) libaddr; } - if(piclib && ppnt->p_vaddr < minvma) { - minvma = ppnt->p_vaddr; + + /* + * OK, the ELF library is now loaded into VM in the correct locations + * The next step is to go through and do the dynamic linking (if needed). + */ + + /* Start by scanning the dynamic section to get all of the pointers */ + + if (!dynamic_addr) { + _dl_internal_error_number = DL_ERROR_NODYNAMIC; + _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", + _dl_progname, libname); + return NULL; } - if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { - maxvma = ppnt->p_vaddr + ppnt->p_memsz; + + dpnt = (Elf32_Dyn *) dynamic_addr; + + dynamic_size = dynamic_size / sizeof(Elf32_Dyn); + _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); + for (i = 0; i < dynamic_size; i++) { + if (dpnt->d_tag > DT_JMPREL) { + dpnt++; + continue; + } + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT) + dynamic_info[DT_TEXTREL] = 1; + dpnt++; + }; + + /* If the TEXTREL is set, this means that we need to make the pages + writable before we perform relocations. Do this now. They get set back + again later. */ + + if (dynamic_info[DT_TEXTREL]) { + ppnt = (elf_phdr *) & header[epnt->e_phoff]; + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) + _dl_mprotect((void *) ((piclib ? libaddr : 0) + + (ppnt->p_vaddr & 0xfffff000)), + (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } } - } - ppnt++; - }; - - maxvma=(maxvma+0xfffU)&~0xfffU; - minvma=minvma&~0xffffU; - - flags = MAP_PRIVATE /*| MAP_DENYWRITE*/; - if(!piclib) flags |= MAP_FIXED; - - status = (char *) _dl_mmap((char *) (piclib?0:minvma), - maxvma-minvma, - PROT_NONE, - flags | MAP_ANONYMOUS, -1, - 0); - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_close(infile); - return NULL; - }; - libaddr=(unsigned int)status; - flags|=MAP_FIXED; - - /* Get the memory to store the library */ - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - - for(i=0;i < epnt->e_phnum; i++){ - if(ppnt->p_type == PT_LOAD) { - - /* See if this is a PIC library. */ - if(i == 0 && ppnt->p_vaddr > 0x1000000) { - piclib = 0; - /* flags |= MAP_FIXED; */ - } - - - - if(ppnt->p_flags & PF_W) { - unsigned int map_size; - char * cpnt; - - status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) + - (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, - LXFLAGS(ppnt->p_flags), - flags, infile, - ppnt->p_offset & 0x7ffff000); - - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_munmap((char *)libaddr, maxvma-minvma); - _dl_close(infile); - return NULL; + + + tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, + dynamic_addr, dynamic_size); + + tpnt->ppnt = (elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); + tpnt->n_phent = epnt->e_phnum; + + /* + * OK, the next thing we need to do is to insert the dynamic linker into + * the proper entry in the GOT so that the PLT symbols can be properly + * resolved. + */ + + lpnt = (int *) dynamic_info[DT_PLTGOT]; + + if (lpnt) { + lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); + INIT_GOT(lpnt, tpnt); }; - - /* Pad the last page with zeroes. */ - cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz); - while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0; - -/* I am not quite sure if this is completely correct to do or not, but - the basic way that we handle bss segments is that we mmap /dev/zero if - there are any pages left over that are not mapped as part of the file */ - - map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000; - if(map_size < ppnt->p_vaddr + ppnt->p_memsz) - status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0), - ppnt->p_vaddr + ppnt->p_memsz - map_size, - LXFLAGS(ppnt->p_flags), - flags | MAP_ANONYMOUS, -1, 0); - } else - status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + - (piclib?libaddr:0), - (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, - LXFLAGS(ppnt->p_flags), - flags, infile, - ppnt->p_offset & 0x7ffff000); - if(_dl_mmap_check_error(status)) { - _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); - _dl_internal_error_number = DL_ERROR_MMAP_FAILED; - _dl_munmap((char *)libaddr, maxvma-minvma); - _dl_close(infile); - return NULL; - }; - /* if(libaddr == 0 && piclib) { - libaddr = (unsigned int) status; - flags |= MAP_FIXED; - }; */ - }; - ppnt++; - }; - _dl_close(infile); - - /* For a non-PIC library, the addresses are all absolute */ - if(piclib) { - dynamic_addr += (unsigned int) libaddr; - } - - /* - * OK, the ELF library is now loaded into VM in the correct locations - * The next step is to go through and do the dynamic linking (if needed). - */ - - /* Start by scanning the dynamic section to get all of the pointers */ - - if(!dynamic_addr) { - _dl_internal_error_number = DL_ERROR_NODYNAMIC; - _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); - return NULL; - } - - dpnt = (struct dynamic *) dynamic_addr; - - dynamic_size = dynamic_size / sizeof(struct dynamic); - _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); - for(i=0; i< dynamic_size; i++){ - if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; } - dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; - if(dpnt->d_tag == DT_TEXTREL || - SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1; - dpnt++; - }; - - /* If the TEXTREL is set, this means that we need to make the pages - writable before we perform relocations. Do this now. They get set back - again later. */ - - if (dynamic_info[DT_TEXTREL]) { - ppnt = (struct elf_phdr *) &header[epnt->e_phoff]; - for(i=0;i < epnt->e_phnum; i++, ppnt++){ - if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) - _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)), - (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - } - - - tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr, - dynamic_size); - - tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); - tpnt->n_phent = epnt->e_phnum; - - /* - * OK, the next thing we need to do is to insert the dynamic linker into - * the proper entry in the GOT so that the PLT symbols can be properly - * resolved. - */ - - lpnt = (int *) dynamic_info[DT_PLTGOT]; - - if(lpnt) { - lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); - INIT_GOT(lpnt, tpnt); - }; - - return tpnt; + return tpnt; } /* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY @@ -561,28 +585,30 @@ struct elf_resolve * _dl_load_elf_shared_library(int secure, are guaranteed to be generated by a trustworthy linker, then this step can be skipped. */ -int _dl_copy_fixups(struct dyn_elf * rpnt) +int _dl_copy_fixups(struct dyn_elf *rpnt) { - int goof = 0; - struct elf_resolve * tpnt; + int goof = 0; + struct elf_resolve *tpnt; - if(rpnt->next) goof += _dl_copy_fixups(rpnt->next); - else return 0; + if (rpnt->next) + goof += _dl_copy_fixups(rpnt->next); + else + return 0; + + tpnt = rpnt->dyn; + + if (tpnt->init_flag & COPY_RELOCS_DONE) + return goof; + tpnt->init_flag |= COPY_RELOCS_DONE; - tpnt = rpnt->dyn; - - if (tpnt->init_flag & COPY_RELOCS_DONE) return goof; - tpnt->init_flag |= COPY_RELOCS_DONE; - #ifdef ELF_USES_RELOCA - goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA], - tpnt->dynamic_info[DT_RELASZ], 0); + goof += _dl_parse_copy_information(rpnt, + tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0); #else - goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL], - tpnt->dynamic_info[DT_RELSZ], 0); + goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL], + tpnt->dynamic_info[DT_RELSZ], 0); #endif - return goof; + return goof; } - diff --git a/ldso/ldso/sparc/dl-syscalls.h b/ldso/ldso/sparc/dl-syscalls.h index f62e64158..0fe431809 100644 --- a/ldso/ldso/sparc/dl-syscalls.h +++ b/ldso/ldso/sparc/dl-syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c index 6f0d9f8fd..c69ef86f0 100644 --- a/ldso/ldso/sparc/elfinterp.c +++ b/ldso/ldso/sparc/elfinterp.c @@ -41,20 +41,12 @@ an ELF sharable library or a linux style of shared library. */ a more than adequate job of explaining everything required to get this working. */ -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/unistd.h> -/*#include <stdlib.h>*/ -#include "string.h" -#include <linux/unistd.h> -#include <linux/fcntl.h> +#include <sys/types.h> +#include "elf.h" #include "hash.h" -#include "linuxelf.h" +#include "syscall.h" +#include "string.h" #include "sysdep.h" -#include "../syscall.h" -#include "../string.h" - -#define SVR4_COMPATIBILITY extern char *_dl_progname; @@ -63,10 +55,10 @@ extern _dl_linux_resolve(void); unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt) { int reloc_type; - struct elf32_rela * this_reloc; + Elf32_Rela * this_reloc; char * strtab; - struct elf32_sym * symtab; - struct elf32_rela * rel_addr; + Elf32_Sym * symtab; + Elf32_Rela * rel_addr; struct elf_resolve * tpnt; int symtab_index; char * new_addr; @@ -74,7 +66,7 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt) unsigned int instr_addr; tpnt = (struct elf_resolve *) plt[2]; - rel_addr = (struct elf32_rela *) (tpnt->dynamic_info[DT_JMPREL] + + rel_addr = (Elf32_Rela *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); /* @@ -82,12 +74,12 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt) */ reloc_entry = (reloc_entry >> 12) - 0xc; - this_reloc = (struct elf32_rela *) ((char *) rel_addr + reloc_entry); + this_reloc = (Elf32_Rela *) ((char *) rel_addr + reloc_entry); reloc_type = ELF32_R_TYPE(this_reloc->r_info); symtab_index = ELF32_R_SYM(this_reloc->r_info); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); _dl_fdprintf(2, "tpnt = %x\n", tpnt); @@ -146,17 +138,17 @@ void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_ad char * strtab; int reloc_type; int symtab_index; - struct elf32_sym * symtab; - struct elf32_rela * rpnt; + Elf32_Sym * symtab; + Elf32_Rela * rpnt; unsigned int * reloc_addr; /* Now parse the relocation information */ - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + 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 += sizeof(struct elf32_rela), rpnt++){ + for(i=0; i< rel_size; i += sizeof(Elf32_Rela), rpnt++){ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset); reloc_type = ELF32_R_TYPE(rpnt->r_info); symtab_index = ELF32_R_SYM(rpnt->r_info); @@ -191,19 +183,19 @@ int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, char * strtab; int reloc_type; int goof = 0; - struct elf32_sym * symtab; - struct elf32_rela * rpnt; + Elf32_Sym * symtab; + Elf32_Rela * rpnt; unsigned int * reloc_addr; unsigned int symbol_addr; int symtab_index; /* Now parse the relocation information */ - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + 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+= sizeof(struct elf32_rela), rpnt++){ + for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset); reloc_type = ELF32_R_TYPE(rpnt->r_info); symtab_index = ELF32_R_SYM(rpnt->r_info); @@ -307,8 +299,8 @@ int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr, char * strtab; int reloc_type; int goof = 0; - struct elf32_sym * symtab; - struct elf32_rela * rpnt; + Elf32_Sym * symtab; + Elf32_Rela * rpnt; unsigned int * reloc_addr; unsigned int symbol_addr; struct elf_resolve *tpnt; @@ -317,12 +309,12 @@ int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr, tpnt = xpnt->dyn; - rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr); + rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr); - symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + 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+= sizeof(struct elf32_rela), rpnt++){ + for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset); reloc_type = ELF32_R_TYPE(rpnt->r_info); if(reloc_type != R_SPARC_COPY) continue; diff --git a/ldso/ldso/sparc/ld_syscalls.h b/ldso/ldso/sparc/ld_syscalls.h index f62e64158..0fe431809 100644 --- a/ldso/ldso/sparc/ld_syscalls.h +++ b/ldso/ldso/sparc/ld_syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/sparc/syscalls.h b/ldso/ldso/sparc/syscalls.h index f62e64158..0fe431809 100644 --- a/ldso/ldso/sparc/syscalls.h +++ b/ldso/ldso/sparc/syscalls.h @@ -1,4 +1,3 @@ -#include <linux/types.h> #include <asm/unistd.h> /* Here are the macros which define how this platform makes diff --git a/ldso/ldso/string.h b/ldso/ldso/string.h index 1ea8fd7ae..be0de45b1 100644 --- a/ldso/ldso/string.h +++ b/ldso/ldso/string.h @@ -1,7 +1,7 @@ #ifndef _LINUX_STRING_H_ #define _LINUX_STRING_H_ -#include <linux/types.h> /* for size_t */ +#include <sys/types.h> /* for size_t */ #ifndef NULL #define NULL ((void *) 0) diff --git a/ldso/ldso/syscall.h b/ldso/ldso/syscall.h index 4e4d4c118..6678e2c74 100644 --- a/ldso/ldso/syscall.h +++ b/ldso/ldso/syscall.h @@ -41,6 +41,7 @@ static inline void * _dl_mmap(void * addr, unsigned long size, int prot, #define __NR__dl_open __NR_open +#define O_RDONLY 0x0000 static inline _syscall2(int, _dl_open, const char *, fn, int, flags); #define __NR__dl_write __NR_write @@ -66,6 +67,7 @@ static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, le #include <asm/stat.h> #undef new_stat #undef stat +#define S_ISUID 04000 /* Set user ID on execution. */ static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf); diff --git a/ldso/ldso/vsprintf.c b/ldso/ldso/vsprintf.c index 48c44e38f..4ca1acffc 100644 --- a/ldso/ldso/vsprintf.c +++ b/ldso/ldso/vsprintf.c @@ -12,7 +12,6 @@ #include <stdarg.h> #include "string.h" #include "hash.h" -#include <linux/unistd.h> #include "syscall.h" /* we use this so that we can do without the ctype library */ |