From b7bc129184a23d4c9c70774362f4eeaa5e0b44c8 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Tue, 1 May 2001 14:20:45 +0000 Subject: Yet another major rework. This time around, rework it to no longer use linux kernel header files. -Erik --- ldso/ldso/readelflib1.c | 990 +++++++++++++++++++++++++----------------------- 1 file changed, 508 insertions(+), 482 deletions(-) (limited to 'ldso/ldso/readelflib1.c') 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 -#include -#include +#include +#include "elf.h" #include "string.h" -/*#include */ -#include -#include #include "hash.h" -#include "linuxelf.h" #include "sysdep.h" -#include #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/-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/-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; } - -- cgit v1.2.3