load.c (6029B)
1 /* $Id: //depot/blt/lib/libdl/load.c#8 $ 2 ** 3 ** Copyright 1999 Sidney Cammeresi 4 ** All rights reserved. 5 ** 6 ** Redistribution and use in source and binary forms, with or without 7 ** modification, are permitted provided that the following conditions 8 ** are met: 9 ** 1. Redistributions of source code must retain the above copyright 10 ** notice, this list of conditions, and the following disclaimer. 11 ** 2. Redistributions in binary form must reproduce the above copyright 12 ** notice, this list of conditions, and the following disclaimer in the 13 ** documentation and/or other materials provided with the distribution. 14 ** 3. The name of the author may not be used to endorse or promote products 15 ** derived from this software without specific prior written permission. 16 ** 17 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <errno.h> 35 #include <dlfcn.h> 36 #include <sys/stat.h> 37 #include <blt/libsyms.h> 38 #include <blt/syscall.h> 39 #include "dl-int.h" 40 41 weak_alias (_dlopen, dlopen) 42 weak_alias (_dlclose, dlclose) 43 weak_alias (_dlerror, dlerror) 44 45 const char *__dl_error = NULL; 46 static volatile char initialised = 0; 47 lib_t *file; 48 49 /* 50 * Initialise the list of loaded images with our binary. 51 * 52 * XXX this will break when the executable is at least partially 53 * dynamically linked. 54 */ 55 void __dlinit (void) 56 { 57 initialised = 1; 58 file = malloc (sizeof (lib_t)); 59 file->hdr = (elf32_hdr_t *) 0x1000; 60 file->strtab = elf_find_section_hdr (file->hdr, ".strtab"); 61 file->strtab_data = elf_find_section_data (file->hdr, ".strtab"); 62 file->strtab_size = elf_section_size (file->hdr, ".strtab"); 63 file->symtab = elf_find_section_hdr (file->hdr, ".symtab"); 64 file->symtab_data = elf_find_section_data (file->hdr, ".symtab"); 65 file->symtab_size = elf_section_size (file->hdr, ".symtab"); 66 /* 67 file->dynstr = elf_find_section_hdr (file->hdr, ".dynstr"); 68 file->dynstr_data = elf_find_section_data (file->hdr, ".dynstr"); 69 file->dynstr_size = elf_section_size (file->hdr, ".dynstr"); 70 file->dynsym = elf_find_section_hdr (file->hdr, ".dynsym"); 71 file->dynsym_data = elf_find_section_data (file->hdr, ".dynsym"); 72 file->dynsym_size = elf_section_size (file->hdr, ".dynsym"); 73 */ 74 file->next = NULL; 75 } 76 77 /* 78 * Loading is not completely straightforward. There is only one hack here, 79 * in that we guess that we will only need one page more memory than the 80 * size of the library. This seems to work on all libraries I can get my 81 * hands on (both OpenBLT and Linux shared libraries). 82 * 83 * The memmove loop may look like a hack because you might think I'm not 84 * completely parsing the program headers. It's not because file offsets 85 * and virtual addresses in an ELF file are equal, modulo 4k or larger 86 * powers of two. Read page 2-7 of the ELF specification for more 87 * information. 88 */ 89 void *_dlopen (const char *filename, int flag) 90 { 91 char *c; 92 int i, size, fd, res, len; 93 struct stat buf; 94 lib_t *lib, *p; 95 elf32_pgm_hdr_t *pgm; 96 int (*fn)(void); 97 98 if (!initialised) 99 __dlinit (); 100 101 __dl_error = NULL; 102 if (_stat (filename, &buf)) 103 { 104 errno = ENOENT; 105 return NULL; 106 } 107 size = buf.st_size; 108 size = (size & ~3) ? (size & ~3) + 0x1000 : size; 109 fd = _open (filename, O_RDONLY, 0); 110 if (fd < 0) 111 return NULL; 112 lib = malloc (sizeof (lib_t)); 113 lib->area = area_create (size, 0, (void **) &c, 0); 114 len = 0; 115 while ((res = _read (fd, c + len, 0x2000)) > 0) 116 len += res; 117 _close (fd); 118 119 lib->hdr = (elf32_hdr_t *) c; 120 pgm = (elf32_pgm_hdr_t *) ((unsigned int) lib->hdr + lib->hdr->e_phoff); 121 for (i = lib->hdr->e_phnum - 1; i >= 0; i--) 122 memmove ((void *) ((unsigned int) lib->hdr + pgm[i].p_vaddr), 123 (void *) ((unsigned int) lib->hdr + pgm[i].p_offset), 124 pgm[i].p_filesz); 125 lib->strtab = elf_find_section_hdr (lib->hdr, ".strtab"); 126 lib->strtab_data = elf_find_section_data (lib->hdr, ".strtab"); 127 lib->strtab_size = elf_section_size (lib->hdr, ".strtab"); 128 lib->symtab = elf_find_section_hdr (lib->hdr, ".symtab"); 129 lib->symtab_data = elf_find_section_data (lib->hdr, ".symtab"); 130 lib->symtab_size = elf_section_size (lib->hdr, ".symtab"); 131 lib->dynstr = elf_find_section_hdr (lib->hdr, ".dynstr"); 132 lib->dynstr_data = elf_find_section_data (lib->hdr, ".dynstr"); 133 lib->dynstr_size = elf_section_size (file->hdr, ".dynstr"); 134 lib->dynsym = elf_find_section_hdr (lib->hdr, ".dynsym"); 135 lib->dynsym_data = elf_find_section_data (lib->hdr, ".dynsym"); 136 lib->dynsym_size = elf_section_size (file->hdr, ".dynsym"); 137 138 if (__dl_patchup (lib)) 139 { 140 area_destroy (lib->area); 141 free (lib); 142 return NULL; 143 } 144 if ((fn = (int (*)(void)) (__dl_lookup_sym (lib, "_init") + 145 (unsigned int) lib->hdr))) 146 res = (*fn) (); 147 if ((flag & ~RTLD_GLOBAL) || res) 148 { 149 p = file; 150 while (p->next != NULL) 151 p = p->next; 152 p->next = lib; 153 lib->next = NULL; 154 } 155 else 156 lib->next = NULL; 157 return lib; 158 } 159 160 int _dlclose (void *handle) 161 { 162 lib_t *lib, *p; 163 void (*fn)(void); 164 165 lib = handle; 166 if (file == lib) 167 file = file->next; 168 else 169 { 170 p = file; 171 while ((p->next != lib) && (p->next != NULL)) 172 p = p->next; 173 if (p->next != NULL) 174 p->next = lib->next; 175 } 176 if ((fn = (void (*)(void)) (__dl_lookup_sym (lib, "_fini") + 177 (unsigned int) lib->hdr))) 178 (*fn) (); 179 area_destroy (lib->area); 180 free (handle); 181 return 0; 182 } 183 184 const char *_dlerror (void) 185 { 186 return __dl_error; 187 } 188