📄 readelflib1.c
字号:
/* Load an ELF sharable library into memory. Copyright (C) 1993-1996, Eric Youngdale. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* This file contains the helper routines to load an ELF sharable library into memory and add the symbol table info to the chain. */#include <elf.h>#include "linuxelf.h"#include "string.h"#include "hash.h"#include "sysdep.h"#include "syscall.h"#include <sys/mman.h>#ifdef USE_CACHE#include "../config.h"#endifextern char *_dl_progname;#ifdef USE_CACHEstatic caddr_t _dl_cache_addr = NULL;static size_t _dl_cache_size = 0;int _dl_map_cache(void){ int fd; struct 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_dprintf(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_dprintf(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_dprintf(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_dprintf(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 1 _dl_munmap(_dl_cache_addr, _dl_cache_size); _dl_cache_addr = NULL;#endif return 0;}#endif/* 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){ int i, count = 0; 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) { _dl_dprintf(2, "Out of memory!\n"); _dl_exit(0); } /* Unlike ldd.c, don't bother to eliminate double //s */ /* Replace colons with zeros in path_list and count them */ for(i=_dl_strlen(path); i > 0; i--) { if (path[i]==':') { path[i]=0; count++; } } path_n = path; for (i = 0; i < count; i++) { _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; path_n += (_dl_strlen(path_n) + 1); } return NULL;}/* * Used to return error codes back to dlopen et. al. */unsigned long _dl_error_number;unsigned long _dl_internal_error_number;struct elf_resolve *_dl_load_shared_library(int secure, struct elf_resolve *tpnt, char *full_libname){ char *pnt; struct elf_resolve *tpnt1; 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) { pnt = (char *) tpnt->dynamic_info[DT_RPATH]; if (pnt) { pnt += (unsigned long) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB]; if ((tpnt1 = search_for_named_library(libname, secure, pnt)) != NULL) { return tpnt1; } } } } /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */ if (_dl_library_path) { if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path)) != NULL) { return tpnt1; } } /* * 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 hard coded paths that follow (i.e before /lib and /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; } }#endif /* Lastly, search the standard list of paths for the library. This list must exactly match the list in uClibc/ldso/util/ldd.c */ if ((tpnt1 = search_for_named_library(libname, secure, UCLIBC_TARGET_PREFIX "/usr/lib:" UCLIBC_TARGET_PREFIX "/lib:" UCLIBC_DEVEL_PREFIX "/lib:" UCLIBC_BUILD_DIR "/lib:" "/usr/lib:" "/lib") ) != NULL) { return tpnt1; } 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;}/* * 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){ elfhdr *epnt; unsigned long dynamic_addr = 0; unsigned long dynamic_size = 0; Elf32_Dyn *dpnt; struct elf_resolve *tpnt; elf_phdr *ppnt; int piclib; char *status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -