From 4a5a81ac165c040935a8807a580db49d381dc443 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Thu, 2 May 2002 13:36:53 +0000 Subject: Patch from Steven J. Hill : I am very pleased to announce that the MIPS dynamic linker/loader for uClibc is now working. It works on big and little endian platforms. A few minor changes were needed to avoid breaking ldd, and since this makes some non-trivial changes, I have tested on x86, arm, and powerpc to be sure thoese arches didn't get broken. Excellent work Steven! --- ldso/ldso/arm/elfinterp.c | 6 +- ldso/ldso/arm/resolve.S | 2 - ldso/ldso/dl-elf.c | 85 +++++++++++++++----- ldso/ldso/dl-hash.c | 2 +- ldso/ldso/hash.c | 2 +- ldso/ldso/i386/elfinterp.c | 6 +- ldso/ldso/ld_hash.h | 10 ++- ldso/ldso/ldso.c | 102 ++++++++++++------------ ldso/ldso/linuxelf.h | 16 ++-- ldso/ldso/m68k/elfinterp.c | 6 +- ldso/ldso/mips/README | 35 +++++---- ldso/ldso/mips/boot1_arch.h | 12 ++- ldso/ldso/mips/dl-startup.h | 12 ++- ldso/ldso/mips/dl-sysdep.h | 175 ++++++++++++++++++++++++++++-------------- ldso/ldso/mips/elfinterp.c | 105 +++++++++++++++++++++++-- ldso/ldso/mips/ld_sysdep.h | 175 ++++++++++++++++++++++++++++-------------- ldso/ldso/mips/resolve.S | 23 ++---- ldso/ldso/powerpc/elfinterp.c | 6 +- ldso/ldso/readelflib1.c | 85 +++++++++++++++----- ldso/ldso/sparc/elfinterp.c | 6 +- ldso/libdl/dlib.c | 6 +- ldso/libdl/libdl.c | 6 +- 22 files changed, 601 insertions(+), 282 deletions(-) diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index bd08944d7..7ca0b80cb 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/ldso/ldso/arm/elfinterp.c @@ -89,7 +89,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) /* Get the address of the GOT entry */ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (unsigned long) got_addr, tpnt, 0); + tpnt->symbol_scope, tpnt, 0); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -221,7 +221,7 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, continue; symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (unsigned long) reloc_addr, + tpnt->symbol_scope, (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), 0); /* @@ -350,7 +350,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, xpnt->next, - (unsigned long) reloc_addr, NULL, 1); + NULL, 1); if (!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); diff --git a/ldso/ldso/arm/resolve.S b/ldso/ldso/arm/resolve.S index 514ecb64e..96c84fc3a 100644 --- a/ldso/ldso/arm/resolve.S +++ b/ldso/ldso/arm/resolve.S @@ -13,8 +13,6 @@ * where the jump symbol is _really_ supposed to have jumped to and returns * that to us. Once we have that, we overwrite tpnt with this fixed up * address. We then clean up after ourselves, put all the registers back how we - * found them, then we jump to where the fixed up address, which is where the - * jump symbol that got us here really wanted to jump to in the first place. * found them, then we jump to the fixed up address, which is where the jump * symbol that got us here really wanted to jump to in the first place. * -Erik Andersen diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 913ac8778..b758df2d6 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -108,14 +108,14 @@ int _dl_unmap_cache(void) /* This function's behavior must exactly match that * in uClibc/ldso/util/ldd.c */ static struct elf_resolve * -search_for_named_library(char *name, int secure, const char *path_list) +search_for_named_library(char *name, int secure, const char *path_list, + struct dyn_elf **rpnt) { int i, count = 1; char *path, *path_n; char mylibname[2050]; struct elf_resolve *tpnt1; - /* We need a writable copy of this string */ path = _dl_strdup(path_list); if (!path) { @@ -140,8 +140,11 @@ search_for_named_library(char *name, int secure, const char *path_list) _dl_strcpy(mylibname, path_n); _dl_strcat(mylibname, "/"); _dl_strcat(mylibname, name); - if ((tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0)) != NULL) - return tpnt1; + if ((tpnt1 = _dl_load_elf_shared_library(secure, rpnt, + mylibname, 0)) != NULL) + { + return tpnt1; + } path_n += (_dl_strlen(path_n) + 1); } return NULL; @@ -156,7 +159,7 @@ unsigned long _dl_error_number; unsigned long _dl_internal_error_number; extern char *_dl_ldsopath; -struct elf_resolve *_dl_load_shared_library(int secure, +struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname) { char *pnt; @@ -185,7 +188,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, /usr/i486-sysv4/lib for /usr/lib in library names. */ if (libname != full_libname) { - tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); + tpnt1 = _dl_load_elf_shared_library(secure, rpnt, full_libname, 0); if (tpnt1) return tpnt1; goto goof; @@ -204,7 +207,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching RPATH: '%s'\n", pnt); #endif - if ((tpnt1 = search_for_named_library(libname, secure, pnt)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL) { return tpnt1; } @@ -217,7 +220,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching _dl_library_path: '%s'\n", _dl_library_path); #endif - if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL) { return tpnt1; } @@ -240,7 +243,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, 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))) + rpnt, strs + libent[i].liboffset, 0))) return tpnt1; } } @@ -251,7 +254,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching in ldso dir: %s\n", _dl_ldsopath); #endif - if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL) { return tpnt1; } @@ -268,7 +271,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, UCLIBC_DEVEL_PREFIX "/lib:" UCLIBC_BUILD_DIR "/lib:" "/usr/lib:" - "/lib") + "/lib", rpnt) ) != NULL) { return tpnt1; @@ -286,16 +289,15 @@ goof: return NULL; } + /* * Read one ELF library into memory, mmap it into the correct locations and * add the symbol info to the symbol chain. Perform any relocations that * are required. */ -//extern _elf_rtbndr(void); - -struct elf_resolve *_dl_load_elf_shared_library(int secure, - char *libname, int flag) +struct elf_resolve *_dl_load_elf_shared_library(int secure, + struct dyn_elf **rpnt, char *libname, int flag) { elfhdr *epnt; unsigned long dynamic_addr = 0; @@ -311,14 +313,27 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, unsigned long *lpnt; unsigned long libaddr; unsigned long minvma = 0xffffffff, maxvma = 0; - int i; int infile; +#if defined(__mips__) + unsigned long mips_gotsym = 0; + unsigned long mips_local_gotno = 0; + unsigned long mips_symtabno = 0; +#endif /* If this file is already loaded, skip this step */ tpnt = _dl_check_hashed_files(libname); - if (tpnt) + if (tpnt) { + (*rpnt)->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + *rpnt = (*rpnt)->next; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt->libtype = elf_lib; + (*rpnt)->dyn = 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. */ @@ -514,7 +529,22 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, dynamic_size = dynamic_size / sizeof(Elf32_Dyn); _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); +#if defined(__mips__) + /* + * The program header file size for the dynamic section is + * calculated differently for MIPS. We look for a null tag + * value instead. + */ + while(dpnt->d_tag) { + if (dpnt->d_tag == DT_MIPS_GOTSYM) + mips_gotsym = (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) + mips_local_gotno = (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_SYMTABNO) + mips_symtabno = (unsigned long) dpnt->d_un.d_val; +#else for (i = 0; i < dynamic_size; i++) { +#endif if (dpnt->d_tag > DT_JMPREL) { dpnt++; continue; @@ -526,8 +556,8 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, }; /* 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. */ + 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]; @@ -547,6 +577,18 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, tpnt->ppnt = (elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); tpnt->n_phent = epnt->e_phnum; + /* + * Add this object into the symbol chain + */ + (*rpnt)->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + *rpnt = (*rpnt)->next; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt->libtype = elf_lib; + (*rpnt)->dyn = tpnt; + /* * 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 @@ -558,6 +600,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, if (lpnt) { lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); +#if defined(__mips__) + tpnt->mips_gotsym = mips_gotsym; + tpnt->mips_local_gotno = mips_local_gotno; + tpnt->mips_symtabno = mips_symtabno; +#endif INIT_GOT(lpnt, tpnt); }; diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index 15dfc3ab6..c6c77e748 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(char *libname, */ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, - unsigned long instr_addr, struct elf_resolve *f_tpnt, int copyrel) + struct elf_resolve *f_tpnt, int copyrel) { struct elf_resolve *tpnt; int si; diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c index 15dfc3ab6..c6c77e748 100644 --- a/ldso/ldso/hash.c +++ b/ldso/ldso/hash.c @@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(char *libname, */ char *_dl_find_hash(char *name, struct dyn_elf *rpnt1, - unsigned long instr_addr, struct elf_resolve *f_tpnt, int copyrel) + struct elf_resolve *f_tpnt, int copyrel) { struct elf_resolve *tpnt; int si; diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index bf955b685..fb2201376 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/ldso/ldso/i386/elfinterp.c @@ -81,7 +81,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) /* Get the address of the GOT entry */ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (unsigned long) got_addr, tpnt, 0); + tpnt->symbol_scope, tpnt, 0); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -188,7 +188,7 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, continue; symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (unsigned long) reloc_addr, + tpnt->symbol_scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0); /* @@ -294,7 +294,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, xpnt->next, - (unsigned long) reloc_addr, NULL, 1); + NULL, 1); if (!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h index c0b3e0409..639ae4510 100644 --- a/ldso/ldso/ld_hash.h +++ b/ldso/ldso/ld_hash.h @@ -71,6 +71,13 @@ struct elf_resolve{ unsigned long n_phent; Elf32_Phdr * ppnt; +#if defined(__mips__) + /* Needed for MIPS relocation */ + unsigned long mips_gotsym; + unsigned long mips_local_gotno; + unsigned long mips_symtabno; +#endif + #ifdef __powerpc__ /* this is used to store the address of relocation data words, so * we don't have to calculate it every time, which requires a divide */ @@ -107,8 +114,7 @@ extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, char * loadaddr, unsigned long * dynamic_info, unsigned long dynamic_addr, unsigned long dynamic_size); extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, - unsigned long instr_addr, struct elf_resolve * f_tpnt, - int copyrel); + struct elf_resolve * f_tpnt, int copyrel); extern int _dl_linux_dynamic_link(void); extern char * _dl_library_path; diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index 2674ca429..f9029006c 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -211,11 +211,6 @@ DL_BOOT(unsigned long args) struct r_debug *debug_addr; int indx; int status; -#if defined(__mips__) - unsigned long mips_gotsym = 0; - unsigned long mips_local_gotno = 0; - unsigned long mips_symtabno = 0; -#endif /* WARNING! -- we cannot make _any_ funtion calls until we have @@ -381,11 +376,11 @@ DL_BOOT(unsigned long args) } #if defined(__mips__) if (dpnt->d_tag == DT_MIPS_GOTSYM) - mips_gotsym = (unsigned long) dpnt->d_un.d_val; + tpnt->mips_gotsym = (unsigned long) dpnt->d_un.d_val; if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) - mips_local_gotno = (unsigned long) dpnt->d_un.d_val; + tpnt->mips_local_gotno = (unsigned long) dpnt->d_un.d_val; if (dpnt->d_tag == DT_MIPS_SYMTABNO) - mips_symtabno = (unsigned long) dpnt->d_un.d_val; + tpnt->mips_symtabno = (unsigned long) dpnt->d_un.d_val; #endif dpnt++; } @@ -399,6 +394,17 @@ DL_BOOT(unsigned long args) if (ppnt->p_type == PT_DYNAMIC) { dpnt = (Elf32_Dyn *) ppnt->p_vaddr; while (dpnt->d_tag) { +#if defined(__mips__) + if (dpnt->d_tag == DT_MIPS_GOTSYM) + app_tpnt->mips_gotsym = + (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) + app_tpnt->mips_local_gotno = + (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_SYMTABNO) + app_tpnt->mips_symtabno = + (unsigned long) dpnt->d_un.d_val; +#endif if (dpnt->d_tag > DT_JMPREL) { dpnt++; continue; @@ -524,7 +530,6 @@ DL_BOOT(unsigned long args) if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue; symbol_addr = load_addr + symtab[symtab_index].st_value; - //SEND_NUMBER_STDERR(symbol_addr,1); if (!symbol_addr) { /* This will segfault - you cannot call a function until @@ -580,7 +585,6 @@ DL_BOOT(unsigned long args) - /* OK we are done here. Turn out the lights, and lock up. */ _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn; @@ -608,6 +612,11 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a struct elf_resolve *tpnt1; unsigned long brk_addr, *lpnt; int (*_dl_atexit) (void *); +#ifdef __mips__ + unsigned long mips_gotsym = 0; + unsigned long mips_local_gotno = 0; + unsigned long mips_symtabno = 0; +#endif /* Now we have done the mandatory linking of some things. We are now @@ -615,6 +624,13 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a fixed up by now. Still no function calls outside of this library , since the dynamic resolver is not yet ready. */ lpnt = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); + + tpnt->chains = hash_addr; + tpnt->next = 0; + tpnt->libname = 0; + tpnt->libtype = program_interpreter; + tpnt->loadaddr = (char *) load_addr; + INIT_GOT(lpnt, tpnt); #ifdef DL_DEBUG _dl_dprintf(2, "GOT found at %x\n", tpnt); @@ -622,10 +638,6 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a /* 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; @@ -642,9 +654,6 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } } - tpnt->chains = hash_addr; - tpnt->loadaddr = (char *) load_addr; - brk_addr = 0; rpnt = NULL; @@ -665,11 +674,21 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a continue; #endif /* OK, we have what we need - slip this one into the list. */ +#ifdef __mips__ + mips_gotsym = app_tpnt->mips_gotsym; + mips_local_gotno = app_tpnt->mips_local_gotno; + mips_symtabno = app_tpnt->mips_symtabno; +#endif 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 *) auxvt[AT_PHDR].a_un.a_ptr; _dl_loaded_modules->n_phent = auxvt[AT_PHNUM].a_un.a_val; +#ifdef __mips__ + _dl_loaded_modules->mips_gotsym = mips_gotsym; + _dl_loaded_modules->mips_local_gotno = mips_local_gotno; + _dl_loaded_modules->mips_symtabno = mips_symtabno; +#endif _dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset(rpnt, 0, sizeof(*rpnt)); rpnt->dyn = _dl_loaded_modules; @@ -774,7 +793,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a *str2 = '\0'; if (!_dl_secure || _dl_strchr(str, '/') == NULL) { - tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str); + tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str); if (!tpnt1) { #ifdef DL_TRACE if (_dl_trace_loaded_objects) @@ -793,7 +812,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a #endif #ifdef DL_TRACE if (_dl_trace_loaded_objects - && !tpnt1->usage_count) { + && tpnt1->usage_count==1) { /* 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) @@ -801,14 +820,6 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a (unsigned) tpnt1->loadaddr); } #endif - 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; @@ -861,7 +872,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a c = *cp; *cp = '\0'; - tpnt1 = _dl_load_shared_library(0, NULL, cp2); + tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2); if (!tpnt1) { #ifdef DL_TRACE if (_dl_trace_loaded_objects) @@ -880,20 +891,11 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a #endif #ifdef DL_TRACE if (_dl_trace_loaded_objects - && !tpnt1->usage_count) { + && tpnt1->usage_count==1) { _dl_dprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname, (unsigned) tpnt1->loadaddr); } #endif - 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 */ @@ -924,7 +926,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a struct elf_resolve *ttmp; #ifdef DL_TRACE - if (_dl_trace_loaded_objects && !tpnt->usage_count) { + if (_dl_trace_loaded_objects && tpnt->usage_count==1) { _dl_dprintf(1, "\t%s => %s (0x%x)\n", lpntstr, tpnt->libname, (unsigned) tpnt->loadaddr); } @@ -945,7 +947,8 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a tpnt = NULL; continue; } - if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpntstr))) { + if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) + { #ifdef DL_TRACE if (_dl_trace_loaded_objects) _dl_dprintf(1, "\t%s => not found\n", lpntstr); @@ -962,18 +965,10 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_dprintf(2, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname); #endif #ifdef DL_TRACE - if (_dl_trace_loaded_objects && !tpnt1->usage_count) + if (_dl_trace_loaded_objects && tpnt1->usage_count==1) _dl_dprintf(1, "\t%s => %s (0x%x)\n", lpntstr, tpnt1->libname, (unsigned) tpnt1->loadaddr); #endif - 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; } } } @@ -1069,12 +1064,12 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a _dl_brkp = - (unsigned long *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); + (unsigned long *) _dl_find_hash("___brk_addr", NULL, NULL, 0); if (_dl_brkp) { *_dl_brkp = brk_addr; } _dl_envp = - (unsigned long *) _dl_find_hash("__environ", NULL, 1, NULL, 0); + (unsigned long *) _dl_find_hash("__environ", NULL, NULL, 0); if (_dl_envp) { *_dl_envp = (unsigned long) envp; @@ -1098,7 +1093,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a } #endif - _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, NULL, 0); /* * OK, fix one more thing - set up the debug_addr structure to point @@ -1209,8 +1204,9 @@ void *_dl_malloc(int size) void *retval; #if 0 -//#ifdef DL_DEBUG +#ifdef DL_DEBUG _dl_dprintf(2, "malloc: request for %d bytes\n", size); +#endif #endif if (_dl_malloc_function) diff --git a/ldso/ldso/linuxelf.h b/ldso/ldso/linuxelf.h index 6d044a7ae..a1c9903d0 100644 --- a/ldso/ldso/linuxelf.h +++ b/ldso/ldso/linuxelf.h @@ -16,16 +16,16 @@ extern void * _dl_malloc(int size); extern int _dl_map_cache(void); extern int _dl_unmap_cache(void); int _dl_copy_fixups(struct dyn_elf * tpnt); -extern int _dl_parse_relocation_information(struct elf_resolve * tpnt, unsigned long rel_addr, - unsigned long rel_size, int type); -extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, unsigned long rel_addr, - unsigned long rel_size, int type); +extern int _dl_parse_copy_information(struct dyn_elf *rpnt, + unsigned long rel_addr, unsigned long rel_size, int type); +extern void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type); +extern int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type); extern struct elf_resolve * _dl_load_shared_library(int secure, - struct elf_resolve *, char * libname); + struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname); extern struct elf_resolve * _dl_load_elf_shared_library(int secure, - char * libname, int flag); -extern int _dl_parse_copy_information(struct dyn_elf * rpnt, unsigned long rel_addr, - unsigned long rel_size, int type); + struct dyn_elf **rpnt, char *libname, int flag); extern int _dl_linux_resolve(void); #define ELF_CLASS ELFCLASS32 diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index e8a942836..93968acfa 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -90,7 +90,7 @@ unsigned int _dl_linux_resolver (int dummy1, int dummy2, /* 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); + tpnt->symbol_scope, tpnt, 0); if (!new_addr) { _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", @@ -201,7 +201,7 @@ _dl_parse_relocation_information (struct elf_resolve *tpnt, { symbol_addr = (unsigned int) _dl_find_hash (strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (int) reloc_addr, + tpnt->symbol_scope, reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, 0); /* We want to allow undefined references to weak symbols - @@ -327,7 +327,7 @@ _dl_parse_copy_information (struct dyn_elf *xpnt, unsigned long rel_addr, { symbol_addr = (unsigned int) _dl_find_hash (strtab + symtab[symtab_index].st_name, - xpnt->next, (int) reloc_addr, NULL, 1); + xpnt->next, NULL, 1); if (!symbol_addr) { _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", diff --git a/ldso/ldso/mips/README b/ldso/ldso/mips/README index b54e25183..520a5eeb6 100644 --- a/ldso/ldso/mips/README +++ b/ldso/ldso/mips/README @@ -1,28 +1,29 @@ Almost all of the code present in these source files was taken from GLIBC. In the descriptions below, all files mentioned are with respect to the top level GLIBC source directory accept for -the code taken from the Linux kernel. +code taken from the Linux kernel. boot1_arch.h ------------ Contains code to fix up the stack pointer so that the dynamic linker can find argc, argv and Auxillary Vector Table (AVT). -The codes is taken from the function 'RTLD_START' in the -file 'sysdeps/mips/dl-machine.h'. +The code is taken from the function 'RTLD_START' in the file +'sysdeps/mips/dl-machine.h'. elfinterp.c ----------- -Contains '_dl_init_got' which initializes the GOT for the -application being dynamically linked and loaded. The code is -taken from the functions 'elf_machine_runtime_setup' and -'elf_machine_got_rel' in the file 'sysdeps/mips/dl-machine.h'. +Contains the runtime resolver code taken from the function +'__dl_runtime_resolve' in 'sysdeps/mips/dl-machine.h'. Also +contains the function to perform relocations for objects +other than the linker itself. The code was taken from the +function 'elf_machine_rel' in 'sysdeps/mips/dl-machine.h'. ld_syscalls.h ------------- -Contains all the macro function prototypes for the system calls -as well as the list of system calls supported. The macros were -taken from the Linux kernel source 2.4.17 found in the file -'include/asm-mips/unistd.h'. +Contains all the macro functions for the system calls as well +as the list of system calls supported. The functions were taken +from the Linux kernel source 2.4.17 and can be found in the +file 'include/asm-mips/unistd.h'. ld_sysdep.h ----------- @@ -31,13 +32,19 @@ for detecting MIPS target types and some macros. The macro function 'PERFORM_BOOTSTRAP_GOT' is used to relocate the dynamic linker's GOT so that function calls can be made. The code is taken from the function 'ELF_MACHINE_BEFORE_RTLD_RELOC' in the -file 'sysdep/mips/dl-machine.h'. The other macro function +file 'sysdeps/mips/dl-machine.h'. The other macro function 'PERFORM_BOOTSTRAP_RELOC' is used to do the relocations for the dynamic loader. The code is taken from the function -'elf_machine_rel' in the file 'sysdep/mips/dl-machine.h'. +'elf_machine_rel' in the file 'sysdeps/mips/dl-machine.h'. The +final macro function is 'INIT_GOT' which initializes the GOT +for the application being dynamically linked and loaded. The +code is taken from the functions 'elf_machine_runtime_setup' +and 'elf_machine_got_rel' in 'sysdeps/mips/dl-machine.h'. resolve.S --------- Contains the low-level assembly code for the dynamic runtime resolver. The code is taken from the assembly code function -'_dl_runtime_resolve' in the file 'sysdesp/mips/dl-machine.h'. +'_dl_runtime_resolve' in the file 'sysdeps/mips/dl-machine.h'. +The code looks a bit different since we only need to pass the +symbol index and the old GP register. diff --git a/ldso/ldso/mips/boot1_arch.h b/ldso/ldso/mips/boot1_arch.h index f439ee4bc..05aaf9ebb 100644 --- a/ldso/ldso/mips/boot1_arch.h +++ b/ldso/ldso/mips/boot1_arch.h @@ -1,7 +1,6 @@ /* Any assmbly language/system dependent hacks needed to setup boot1.c so it * will work as expected and cope with whatever platform specific wierdness is - * needed for this architecture. See arm/boot1_arch.h for an example of what - * can be done. + * needed for this architecture. */ asm(" @@ -13,7 +12,6 @@ _dl_boot: nop 0: .cpload $31 .set reorder - # Store offset of DYNAMIC section in first entry of GOT la $4, _DYNAMIC sw $4, -0x7ff0($28) move $4, $29 @@ -23,6 +21,14 @@ coff: subu $8, $31, $8 la $25, _dl_boot2 addu $25, $8 jalr $25 + lw $4, 0($29) + la $5, 4($29) + sll $6, $4, 2 + addu $6, $6, $5 + addu $6, $6, 4 + la $7, _dl_elf_main + lw $25, 0($7) + jr $25 "); #define _dl_boot _dl_boot2 diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h index f439ee4bc..05aaf9ebb 100644 --- a/ldso/ldso/mips/dl-startup.h +++ b/ldso/ldso/mips/dl-startup.h @@ -1,7 +1,6 @@ /* Any assmbly language/system dependent hacks needed to setup boot1.c so it * will work as expected and cope with whatever platform specific wierdness is - * needed for this architecture. See arm/boot1_arch.h for an example of what - * can be done. + * needed for this architecture. */ asm(" @@ -13,7 +12,6 @@ _dl_boot: nop 0: .cpload $31 .set reorder - # Store offset of DYNAMIC section in first entry of GOT la $4, _DYNAMIC sw $4, -0x7ff0($28) move $4, $29 @@ -23,6 +21,14 @@ coff: subu $8, $31, $8 la $25, _dl_boot2 addu $25, $8 jalr $25 + lw $4, 0($29) + la $5, 4($29) + sll $6, $4, 2 + addu $6, $6, $5 + addu $6, $6, 4 + la $7, _dl_elf_main + lw $25, 0($7) + jr $25 "); #define _dl_boot _dl_boot2 diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h index 8bc6aaccd..f54e812b7 100644 --- a/ldso/ldso/mips/dl-sysdep.h +++ b/ldso/ldso/mips/dl-sysdep.h @@ -1,5 +1,7 @@ +/* vi: set sw=4 ts=4: */ + /* - * Various assmbly language/system dependent hacks that are required + * Various assmbly language/system dependent hacks that are required * so that we can minimize the amount of platform specific code. */ @@ -20,46 +22,102 @@ /* * Initialization sequence for the application GOT. */ -#define INIT_GOT(GOT_BASE,MODULE) _dl_init_got(GOT_BASE,MODULE) +#define INIT_GOT(GOT_BASE,MODULE) \ +do { \ + Elf32_Sym *sym; \ + char *strtab; \ + unsigned long i; \ + \ + /* Check if this is the dynamic linker itself */ \ + if (MODULE->libtype == program_interpreter) \ + continue; \ + \ + /* Fill in first two GOT entries according to the ABI */ \ + GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) MODULE; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < MODULE->mips_local_gotno) \ + GOT_BASE[i++] += (unsigned long) MODULE->loadaddr; \ + \ + /* Handle global GOT entries */ \ + GOT_BASE += MODULE->mips_local_gotno; \ + sym = (Elf32_Sym *) (MODULE->dynamic_info[DT_SYMTAB] + \ + (unsigned long) MODULE->loadaddr) + MODULE->mips_gotsym; \ + strtab = (char *) (MODULE->dynamic_info[DT_STRTAB] + \ + (unsigned long) MODULE->loadaddr); \ + i = MODULE->mips_symtabno - MODULE->mips_gotsym; \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF) { \ + if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + sym->st_value) \ + *GOT_BASE = sym->st_value + \ + (unsigned long) MODULE->loadaddr; \ + else { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + } \ + else if (sym->st_shndx == SHN_COMMON) { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *GOT_BASE != sym->st_value) \ + *GOT_BASE += (unsigned long) MODULE->loadaddr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *GOT_BASE += (unsigned long) MODULE->loadaddr; \ + } \ + else { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + \ + ++GOT_BASE; \ + ++sym; \ + } \ +} while (0) /* - * Here is a macro to perform the GOT relocation. This is only + * Here is a macro to perform the GOT relocation. This is only * used when bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_GOT(got) \ -do { \ - Elf32_Sym *sym; \ - unsigned long i; \ - \ - /* Add load address displacement to all local GOT entries */ \ - i = 2; \ - while (i < mips_local_gotno) \ - got[i++] += load_addr; \ - \ - /* Handle global GOT entries */ \ - got += mips_local_gotno; \ - sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ - load_addr) + mips_gotsym; \ - i = mips_symtabno - mips_gotsym; \ - \ - while (i--) { \ - if (sym->st_shndx == SHN_UNDEF || \ - sym->st_shndx == SHN_COMMON) \ - *got = load_addr + sym->st_value; \ - else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ - *got != sym->st_value) \ - *got += load_addr; \ - else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ - if (sym->st_other == 0) \ - *got += load_addr; \ - } \ - else \ - *got = load_addr + sym->st_value; \ - \ - got++; \ - sym++; \ - } \ +#define PERFORM_BOOTSTRAP_GOT(got) \ +do { \ + Elf32_Sym *sym; \ + unsigned long i; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < tpnt->mips_local_gotno) \ + got[i++] += load_addr; \ + \ + /* Handle global GOT entries */ \ + got += tpnt->mips_local_gotno; \ + sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ + load_addr) + tpnt->mips_gotsym; \ + i = tpnt->mips_symtabno - tpnt->mips_gotsym; \ + \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF || \ + sym->st_shndx == SHN_COMMON) \ + *got = load_addr + sym->st_value; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *got != sym->st_value) \ + *got += load_addr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *got += load_addr; \ + } \ + else \ + *got = load_addr + sym->st_value; \ + \ + got++; \ + sym++; \ + } \ } while (0) @@ -67,31 +125,33 @@ do { \ * Here is a macro to perform a relocation. This is only used when * bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ - switch(ELF32_R_TYPE((RELP)->r_info)) { \ - case R_MIPS_REL32: \ - if (symtab_index) { \ - if (symtab_index < mips_gotsym) \ - *REL += SYMBOL + LOAD; \ - } \ - else { \ - *REL += LOAD; \ - } \ - break; \ - case R_MIPS_NONE: \ - break; \ - default: \ - SEND_STDERR("Aiieeee!"); \ - _dl_exit(1); \ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)) { \ + case R_MIPS_REL32: \ + if (symtab_index) { \ + if (symtab_index < tpnt->mips_gotsym) \ + *REL += SYMBOL; \ + } \ + else { \ + *REL += LOAD; \ + } \ + break; \ + case R_MIPS_NONE: \ + break; \ + default: \ + SEND_STDERR("Aiieeee!"); \ + _dl_exit(1); \ } /* * Transfer control to the user's application, once the dynamic loader * is done. This routine has to exit the current function, then - * call the _dl_elf_main function. + * call the _dl_elf_main function. For MIPS, we do it in assembly + * because the stack doesn't get properly restored otherwise. Got look + * at boot1_arch.h */ -#define START() return (void) _dl_elf_main; +#define START() /* Here we define the magic numbers that this dynamic loader should accept */ @@ -103,9 +163,8 @@ do { \ #define ELF_TARGET "MIPS" -struct elf_resolve; -extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, - int reloc_entry); -void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt); +unsigned long _dl_linux_resolver(unsigned long sym_index, + unsigned long old_gpreg); + #define do_rem(result, n, base) result = (n % base) diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index c38a7ffa2..e6c3781b8 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -1,6 +1,7 @@ +/* vi: set sw=4 ts=4: */ + /* Run an ELF binary on a linux system. - Copyright (C) 1993, Eric Youngdale. Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com) This program is free software; you can redistribute it and/or modify @@ -32,18 +33,112 @@ extern int _dl_linux_resolve(void); -void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt) +#define OFFSET_GP_GOT 0x7ff0 + +unsigned long _dl_linux_resolver(unsigned long sym_index, + unsigned long old_gpreg) { + unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT); + struct elf_resolve *tpnt = (struct elf_resolve *) got[1]; + Elf32_Sym *sym; + char *strtab; + unsigned long local_gotno; + unsigned long gotsym; + unsigned long value; + + gotsym = tpnt->mips_gotsym; + local_gotno = tpnt->mips_local_gotno; + + sym = ((Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr)) + + sym_index; + + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + value = (unsigned long) _dl_find_hash(strtab + sym->st_name, + tpnt->symbol_scope, tpnt, 1); + + *(got + local_gotno + sym_index - gotsym) = value; + +#ifdef DL_DEBUG + _dl_dprintf(2, "---RESOLVER---\n"); + _dl_dprintf(2, "SYMTAB INDEX: %i\n", sym_index); + _dl_dprintf(2, " GOTSYM: %i\n", gotsym); + _dl_dprintf(2, " LOCAL GOTNO: %i\n", local_gotno); + _dl_dprintf(2, " VALUE: %x\n", value); + _dl_dprintf(2, " SYMBOL: %s\n\n", strtab + sym->st_name); +#endif + + return value; +} + +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + /* Nothing to do */ return; } -unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) { + /* Nothing to do */ return 0; } - + int _dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, unsigned long rel_size, int type) { - return 1; + Elf32_Sym *symtab; + Elf32_Rel *rpnt; + char *strtab; + unsigned long *got; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int i, reloc_type, symtab_index; + + /* Now parse the relocation information */ + rel_size = rel_size / sizeof(Elf32_Rel); + rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + got = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + reloc_addr = (unsigned long *) (tpnt->loadaddr + + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + + switch (reloc_type) { + case R_MIPS_REL32: + if (symtab_index) { + if (symtab_index < tpnt->mips_gotsym) + *reloc_addr += + symtab[symtab_index].st_value + + (unsigned long) tpnt->loadaddr; + else { + *reloc_addr += got[symtab_index + tpnt->mips_local_gotno - + tpnt->mips_gotsym]; + } + } + else { + *reloc_addr += (unsigned long) tpnt->loadaddr; + } + break; + case R_MIPS_NONE: + break; + default: + _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname); + if (symtab_index) + _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); + _dl_exit(1); + }; + + }; + return 0; } diff --git a/ldso/ldso/mips/ld_sysdep.h b/ldso/ldso/mips/ld_sysdep.h index 8bc6aaccd..f54e812b7 100644 --- a/ldso/ldso/mips/ld_sysdep.h +++ b/ldso/ldso/mips/ld_sysdep.h @@ -1,5 +1,7 @@ +/* vi: set sw=4 ts=4: */ + /* - * Various assmbly language/system dependent hacks that are required + * Various assmbly language/system dependent hacks that are required * so that we can minimize the amount of platform specific code. */ @@ -20,46 +22,102 @@ /* * Initialization sequence for the application GOT. */ -#define INIT_GOT(GOT_BASE,MODULE) _dl_init_got(GOT_BASE,MODULE) +#define INIT_GOT(GOT_BASE,MODULE) \ +do { \ + Elf32_Sym *sym; \ + char *strtab; \ + unsigned long i; \ + \ + /* Check if this is the dynamic linker itself */ \ + if (MODULE->libtype == program_interpreter) \ + continue; \ + \ + /* Fill in first two GOT entries according to the ABI */ \ + GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) MODULE; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < MODULE->mips_local_gotno) \ + GOT_BASE[i++] += (unsigned long) MODULE->loadaddr; \ + \ + /* Handle global GOT entries */ \ + GOT_BASE += MODULE->mips_local_gotno; \ + sym = (Elf32_Sym *) (MODULE->dynamic_info[DT_SYMTAB] + \ + (unsigned long) MODULE->loadaddr) + MODULE->mips_gotsym; \ + strtab = (char *) (MODULE->dynamic_info[DT_STRTAB] + \ + (unsigned long) MODULE->loadaddr); \ + i = MODULE->mips_symtabno - MODULE->mips_gotsym; \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF) { \ + if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + sym->st_value) \ + *GOT_BASE = sym->st_value + \ + (unsigned long) MODULE->loadaddr; \ + else { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + } \ + else if (sym->st_shndx == SHN_COMMON) { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *GOT_BASE != sym->st_value) \ + *GOT_BASE += (unsigned long) MODULE->loadaddr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *GOT_BASE += (unsigned long) MODULE->loadaddr; \ + } \ + else { \ + *GOT_BASE = (unsigned long) _dl_find_hash(strtab + \ + sym->st_name, MODULE->symbol_scope, NULL, 0); \ + } \ + \ + ++GOT_BASE; \ + ++sym; \ + } \ +} while (0) /* - * Here is a macro to perform the GOT relocation. This is only + * Here is a macro to perform the GOT relocation. This is only * used when bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_GOT(got) \ -do { \ - Elf32_Sym *sym; \ - unsigned long i; \ - \ - /* Add load address displacement to all local GOT entries */ \ - i = 2; \ - while (i < mips_local_gotno) \ - got[i++] += load_addr; \ - \ - /* Handle global GOT entries */ \ - got += mips_local_gotno; \ - sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ - load_addr) + mips_gotsym; \ - i = mips_symtabno - mips_gotsym; \ - \ - while (i--) { \ - if (sym->st_shndx == SHN_UNDEF || \ - sym->st_shndx == SHN_COMMON) \ - *got = load_addr + sym->st_value; \ - else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ - *got != sym->st_value) \ - *got += load_addr; \ - else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ - if (sym->st_other == 0) \ - *got += load_addr; \ - } \ - else \ - *got = load_addr + sym->st_value; \ - \ - got++; \ - sym++; \ - } \ +#define PERFORM_BOOTSTRAP_GOT(got) \ +do { \ + Elf32_Sym *sym; \ + unsigned long i; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < tpnt->mips_local_gotno) \ + got[i++] += load_addr; \ + \ + /* Handle global GOT entries */ \ + got += tpnt->mips_local_gotno; \ + sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ + load_addr) + tpnt->mips_gotsym; \ + i = tpnt->mips_symtabno - tpnt->mips_gotsym; \ + \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF || \ + sym->st_shndx == SHN_COMMON) \ + *got = load_addr + sym->st_value; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *got != sym->st_value) \ + *got += load_addr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *got += load_addr; \ + } \ + else \ + *got = load_addr + sym->st_value; \ + \ + got++; \ + sym++; \ + } \ } while (0) @@ -67,31 +125,33 @@ do { \ * Here is a macro to perform a relocation. This is only used when * bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ - switch(ELF32_R_TYPE((RELP)->r_info)) { \ - case R_MIPS_REL32: \ - if (symtab_index) { \ - if (symtab_index < mips_gotsym) \ - *REL += SYMBOL + LOAD; \ - } \ - else { \ - *REL += LOAD; \ - } \ - break; \ - case R_MIPS_NONE: \ - break; \ - default: \ - SEND_STDERR("Aiieeee!"); \ - _dl_exit(1); \ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)) { \ + case R_MIPS_REL32: \ + if (symtab_index) { \ + if (symtab_index < tpnt->mips_gotsym) \ + *REL += SYMBOL; \ + } \ + else { \ + *REL += LOAD; \ + } \ + break; \ + case R_MIPS_NONE: \ + break; \ + default: \ + SEND_STDERR("Aiieeee!"); \ + _dl_exit(1); \ } /* * Transfer control to the user's application, once the dynamic loader * is done. This routine has to exit the current function, then - * call the _dl_elf_main function. + * call the _dl_elf_main function. For MIPS, we do it in assembly + * because the stack doesn't get properly restored otherwise. Got look + * at boot1_arch.h */ -#define START() return (void) _dl_elf_main; +#define START() /* Here we define the magic numbers that this dynamic loader should accept */ @@ -103,9 +163,8 @@ do { \ #define ELF_TARGET "MIPS" -struct elf_resolve; -extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, - int reloc_entry); -void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt); +unsigned long _dl_linux_resolver(unsigned long sym_index, + unsigned long old_gpreg); + #define do_rem(result, n, base) result = (n % base) diff --git a/ldso/ldso/mips/resolve.S b/ldso/ldso/mips/resolve.S index b160b1cfb..b6dda82d7 100644 --- a/ldso/ldso/mips/resolve.S +++ b/ldso/ldso/mips/resolve.S @@ -1,4 +1,4 @@ -/* + /* * Linux dynamic resolving code for MIPS. Fixes up the GOT entry as * indicated in register t8 and jumps to the resolved address. Shamelessly * ripped from 'sysdeps/mips/dl-machine.h' in glibc-2.2.5. @@ -23,26 +23,19 @@ _dl_linux_resolve: addu $25, 8 # t9 ($25) now points at .cpload instruction .cpload $25 # Compute GP .set reorder - move $2, $31 # Save slot call pc - subu $29, 40 # Save arguments and sp value in stack - .cprestore 32 - sw $15, 36($29) + subu $29, 32 + .cprestore 28 sw $4, 16($29) sw $5, 20($29) - sw $6, 24($29) - sw $7, 28($29) + sw $15, 24($29) move $4, $24 - move $5, $15 - move $6, $3 - move $7, $2 + move $5, $3 jal _dl_linux_resolver - lw $31, 36($29) + lw $31, 24($29) lw $4, 16($29) lw $5, 20($29) - lw $6, 24($29) - lw $7, 28($29) - addu $29, 40 + addu $29, 32 move $25, $2 - jr $25 + jr $25 .size _dl_linux_resolve,.-_dl_linux_resolve .end _dl_linux_resolve diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c index 430afc014..e2854836a 100644 --- a/ldso/ldso/powerpc/elfinterp.c +++ b/ldso/ldso/powerpc/elfinterp.c @@ -161,7 +161,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) /* Get the address of the GOT entry */ targ_addr = (unsigned long) _dl_find_hash( strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, insn_addr, tpnt, 0); + tpnt->symbol_scope, tpnt, 0); if (!targ_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -337,7 +337,7 @@ int _dl_parse_relocation_information(struct elf_resolve *tpnt, continue; symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (unsigned long) reloc_addr, + tpnt->symbol_scope, (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), 0); /* @@ -499,7 +499,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, xpnt->next, - (unsigned long) reloc_addr, NULL, 1); + NULL, 1); if (!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c index 913ac8778..b758df2d6 100644 --- a/ldso/ldso/readelflib1.c +++ b/ldso/ldso/readelflib1.c @@ -108,14 +108,14 @@ int _dl_unmap_cache(void) /* This function's behavior must exactly match that * in uClibc/ldso/util/ldd.c */ static struct elf_resolve * -search_for_named_library(char *name, int secure, const char *path_list) +search_for_named_library(char *name, int secure, const char *path_list, + struct dyn_elf **rpnt) { int i, count = 1; char *path, *path_n; char mylibname[2050]; struct elf_resolve *tpnt1; - /* We need a writable copy of this string */ path = _dl_strdup(path_list); if (!path) { @@ -140,8 +140,11 @@ search_for_named_library(char *name, int secure, const char *path_list) _dl_strcpy(mylibname, path_n); _dl_strcat(mylibname, "/"); _dl_strcat(mylibname, name); - if ((tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0)) != NULL) - return tpnt1; + if ((tpnt1 = _dl_load_elf_shared_library(secure, rpnt, + mylibname, 0)) != NULL) + { + return tpnt1; + } path_n += (_dl_strlen(path_n) + 1); } return NULL; @@ -156,7 +159,7 @@ unsigned long _dl_error_number; unsigned long _dl_internal_error_number; extern char *_dl_ldsopath; -struct elf_resolve *_dl_load_shared_library(int secure, +struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname) { char *pnt; @@ -185,7 +188,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, /usr/i486-sysv4/lib for /usr/lib in library names. */ if (libname != full_libname) { - tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0); + tpnt1 = _dl_load_elf_shared_library(secure, rpnt, full_libname, 0); if (tpnt1) return tpnt1; goto goof; @@ -204,7 +207,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching RPATH: '%s'\n", pnt); #endif - if ((tpnt1 = search_for_named_library(libname, secure, pnt)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL) { return tpnt1; } @@ -217,7 +220,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching _dl_library_path: '%s'\n", _dl_library_path); #endif - if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL) { return tpnt1; } @@ -240,7 +243,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, 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))) + rpnt, strs + libent[i].liboffset, 0))) return tpnt1; } } @@ -251,7 +254,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, #ifdef DL_DEBUG _dl_dprintf(2, "searching in ldso dir: %s\n", _dl_ldsopath); #endif - if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath)) != NULL) + if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL) { return tpnt1; } @@ -268,7 +271,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, UCLIBC_DEVEL_PREFIX "/lib:" UCLIBC_BUILD_DIR "/lib:" "/usr/lib:" - "/lib") + "/lib", rpnt) ) != NULL) { return tpnt1; @@ -286,16 +289,15 @@ goof: return NULL; } + /* * Read one ELF library into memory, mmap it into the correct locations and * add the symbol info to the symbol chain. Perform any relocations that * are required. */ -//extern _elf_rtbndr(void); - -struct elf_resolve *_dl_load_elf_shared_library(int secure, - char *libname, int flag) +struct elf_resolve *_dl_load_elf_shared_library(int secure, + struct dyn_elf **rpnt, char *libname, int flag) { elfhdr *epnt; unsigned long dynamic_addr = 0; @@ -311,14 +313,27 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, unsigned long *lpnt; unsigned long libaddr; unsigned long minvma = 0xffffffff, maxvma = 0; - int i; int infile; +#if defined(__mips__) + unsigned long mips_gotsym = 0; + unsigned long mips_local_gotno = 0; + unsigned long mips_symtabno = 0; +#endif /* If this file is already loaded, skip this step */ tpnt = _dl_check_hashed_files(libname); - if (tpnt) + if (tpnt) { + (*rpnt)->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + *rpnt = (*rpnt)->next; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt->libtype = elf_lib; + (*rpnt)->dyn = 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. */ @@ -514,7 +529,22 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, dynamic_size = dynamic_size / sizeof(Elf32_Dyn); _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); +#if defined(__mips__) + /* + * The program header file size for the dynamic section is + * calculated differently for MIPS. We look for a null tag + * value instead. + */ + while(dpnt->d_tag) { + if (dpnt->d_tag == DT_MIPS_GOTSYM) + mips_gotsym = (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) + mips_local_gotno = (unsigned long) dpnt->d_un.d_val; + if (dpnt->d_tag == DT_MIPS_SYMTABNO) + mips_symtabno = (unsigned long) dpnt->d_un.d_val; +#else for (i = 0; i < dynamic_size; i++) { +#endif if (dpnt->d_tag > DT_JMPREL) { dpnt++; continue; @@ -526,8 +556,8 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, }; /* 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. */ + 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]; @@ -547,6 +577,18 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, tpnt->ppnt = (elf_phdr *) (tpnt->loadaddr + epnt->e_phoff); tpnt->n_phent = epnt->e_phnum; + /* + * Add this object into the symbol chain + */ + (*rpnt)->next = (struct dyn_elf *) + _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset((*rpnt)->next, 0, sizeof(*((*rpnt)->next))); + *rpnt = (*rpnt)->next; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt->libtype = elf_lib; + (*rpnt)->dyn = tpnt; + /* * 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 @@ -558,6 +600,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, if (lpnt) { lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); +#if defined(__mips__) + tpnt->mips_gotsym = mips_gotsym; + tpnt->mips_local_gotno = mips_local_gotno; + tpnt->mips_symtabno = mips_symtabno; +#endif INIT_GOT(lpnt, tpnt); }; diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c index f87fa58ff..f7c9aa4d7 100644 --- a/ldso/ldso/sparc/elfinterp.c +++ b/ldso/ldso/sparc/elfinterp.c @@ -98,7 +98,7 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt) /* 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); + tpnt->symbol_scope, tpnt, 0); if(!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); @@ -201,7 +201,7 @@ int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr, symbol_addr = (unsigned int) _dl_find_hash(strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, (int) reloc_addr, + tpnt->symbol_scope, (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), 0); if(!symbol_addr && @@ -319,7 +319,7 @@ int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr, symbol_addr = (unsigned int) _dl_find_hash(strtab + symtab[symtab_index].st_name, - xpnt->next, (int) reloc_addr, NULL, 1); + xpnt->next, NULL, 1); if(!symbol_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name); diff --git a/ldso/libdl/dlib.c b/ldso/libdl/dlib.c index 901613f30..1977e635c 100644 --- a/ldso/libdl/dlib.c +++ b/ldso/libdl/dlib.c @@ -108,7 +108,7 @@ void *_dlopen(char *libname, int flag) tfrom = tpnt; } - if (!(tpnt = _dl_load_shared_library(0, tfrom, libname))) { + if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, libname))) { #ifdef USE_CACHE _dl_unmap_cache(); #endif @@ -145,7 +145,7 @@ void *_dlopen(char *libname, int flag) { lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val; - if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) + if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt))) goto oops; rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); @@ -304,7 +304,7 @@ void *_dlsym(void *vhandle, char *name) } } - ret = _dl_find_hash(name, handle, 1, NULL, 1); + ret = _dl_find_hash(name, handle, NULL, 1); /* * Nothing found. diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 901613f30..1977e635c 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -108,7 +108,7 @@ void *_dlopen(char *libname, int flag) tfrom = tpnt; } - if (!(tpnt = _dl_load_shared_library(0, tfrom, libname))) { + if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, libname))) { #ifdef USE_CACHE _dl_unmap_cache(); #endif @@ -145,7 +145,7 @@ void *_dlopen(char *libname, int flag) { lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val; - if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) + if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt))) goto oops; rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); @@ -304,7 +304,7 @@ void *_dlsym(void *vhandle, char *name) } } - ret = _dl_find_hash(name, handle, 1, NULL, 1); + ret = _dl_find_hash(name, handle, NULL, 1); /* * Nothing found. -- cgit v1.2.3