📄 dlib.c
字号:
/* * libdl.c * * Functions required for dlopen et. al. */#include <stdlib.h>#include <features.h>#include "dlfcn.h"#include "sysdep.h"#include "syscall.h"#include "hash.h"#include "string.h"#include "linuxelf.h"extern int _dl_error_number;extern struct r_debug *_dl_debug_addr;extern void *(*_dl_malloc_function) (size_t size);static int do_fixup(struct elf_resolve *tpnt, int flag);static int do_dlclose(void *, int need_fini);void *_dlopen(char *filename, int flag);const char *_dlerror(void);void *_dlsym(void *, char *);int _dlclose(void *);int _dladdr(void *__address, Dl_info * __dlip);static const char *dl_error_names[] = { "", "File not found", "Unable to open /dev/zero", "Not an ELF file",#if defined (__i386__) "Not i386 binary",#elif defined (__sparc__) "Not sparc binary",#elif defined (__mc68000__) "Not m68k binary",#else "Unrecognized binary type",#endif "Not an ELF shared library", "Unable to mmap file", "No dynamic section",#ifdef ELF_USES_RELOCA "Unable to process REL relocs",#else "Unable to process RELA relocs",#endif "Bad handle", "Unable to resolve symbol"};static void dl_cleanup(void) __attribute__ ((destructor));static void dl_cleanup(void){ struct dyn_elf *d; for (d = _dl_handles; d; d = d->next_handle) if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI]) { (* ((int (*)(void)) (d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI]))) (); d->dyn->dynamic_info[DT_FINI] = 0; }}void *_dlopen(char *libname, int flag){ struct elf_resolve *tpnt, *tfrom; struct dyn_elf *rpnt; struct dyn_elf *dyn_chain; struct dyn_elf *dpnt; static int dl_init = 0; char *from; void (*dl_brk) (void); int (*dl_elf_init) (void); from = __builtin_return_address(0); /* Have the dynamic linker use the regular malloc function now */ if (!dl_init) { dl_init++; _dl_malloc_function = malloc; } /* Cover the trivial case first */ if (!libname) return _dl_symbol_tables;#ifdef USE_CACHE _dl_map_cache();#endif /* * Try and locate the module we were called from - we * need this so that we get the correct RPATH. Note that * this is the current behavior under Solaris, but the * ABI+ specifies that we should only use the RPATH from * the application. Thus this may go away at some time * in the future. */ tfrom = NULL; for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) { tpnt = dpnt->dyn; if (tpnt->loadaddr < from && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) tfrom = tpnt; } if (!(tpnt = _dl_load_shared_library(0, tfrom, libname))) {#ifdef USE_CACHE _dl_unmap_cache();#endif return NULL; } tpnt->usage_count++; dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); _dl_memset(rpnt, 0, sizeof(*rpnt)); rpnt->dyn = tpnt; rpnt->flags = flag; if (!tpnt->symbol_scope) tpnt->symbol_scope = dyn_chain; rpnt->next_handle = _dl_handles; _dl_handles = rpnt; /* * OK, we have the requested file in memory. Now check for * any other requested files that may also be required. */ { struct elf_resolve *tcurr; struct elf_resolve * tpnt1; Elf32_Dyn * dpnt; char * lpnt; tcurr = tpnt; do{ 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(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt))) goto oops; rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); rpnt = rpnt->next; tpnt1->usage_count++; if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain; rpnt->dyn = tpnt1; }; } tcurr = tcurr->next; } while(tcurr); } /* * OK, now attach the entire chain at the end */ rpnt->next = _dl_symbol_tables; if (do_fixup(tpnt, flag)) { _dl_error_number = DL_NO_SYMBOL; goto oops; } dl_brk = (void (*)()) _dl_debug_addr->r_brk; if (dl_brk != NULL) { _dl_debug_addr->r_state = RT_ADD; (*dl_brk) (); _dl_debug_addr->r_state = RT_CONSISTENT; (*dl_brk) (); } for (rpnt = dyn_chain; rpnt; rpnt = rpnt->next) { tpnt = rpnt->dyn; /* Apparently crt1 for the application is responsible for handling this. * We only need to run the init/fini for shared libraries */ if (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) (); } }#ifdef USE_CACHE _dl_unmap_cache();#endif return (void *) dyn_chain; oops: /* Something went wrong. Clean up and return NULL. */#ifdef USE_CACHE _dl_unmap_cache();#endif do_dlclose(dyn_chain, 0); return NULL;}static int do_fixup(struct elf_resolve *tpnt, int flag){ int goof = 0; if (tpnt->next) goof += do_fixup(tpnt->next, flag); if (tpnt->dynamic_info[DT_REL]) {#ifdef ELF_USES_RELOCA goof++;#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);#endif } 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);#else goof++;#endif } if (tpnt->dynamic_info[DT_JMPREL]) { if (tpnt->init_flag & JMP_RELOCS_DONE) return goof; tpnt->init_flag |= JMP_RELOCS_DONE; if (flag == RTLD_LAZY) _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 *_dlsym(void *vhandle, char *name){ struct elf_resolve *tpnt, *tfrom; struct dyn_elf *handle; char *from; struct dyn_elf *rpnt; void *ret; handle = (struct dyn_elf *) vhandle; /* First of all verify that we have a real handle of some kind. Return NULL if not a valid handle. */ if (handle == NULL) handle = _dl_symbol_tables; else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) { for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) if (rpnt == handle) break; if (!rpnt) { _dl_error_number = DL_BAD_HANDLE; return NULL; } } else if (handle == RTLD_NEXT) { /* * Try and locate the module we were called from - we * need this so that we know where to start searching * from. We never pass RTLD_NEXT down into the actual * dynamic loader itself, as it doesn't know * how to properly treat it. */ from = __builtin_return_address(0); tfrom = NULL; for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) { tpnt = rpnt->dyn; if (tpnt->loadaddr < from && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) { tfrom = tpnt; handle = rpnt->next; } } } ret = _dl_find_hash(name, handle, 1, NULL, 1); /* * Nothing found. */ if (!ret) _dl_error_number = DL_NO_SYMBOL; return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -