1 /* $NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Christopher G. Demetriou. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 __RCSID("$NetBSD: exec_elf32.c,v 1.4 1997/08/12 06:07:24 mikel Exp $"); 36 #endif 37 38 #ifndef ELFSIZE 39 #define ELFSIZE 32 40 #endif 41 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "extern.h" 52 53 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \ 54 (defined(NLIST_ELF64) && (ELFSIZE == 64)) 55 56 #include <elf.h> 57 58 #define CONCAT(x,y) __CONCAT(x,y) 59 #define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) 60 #define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) 61 #define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) 62 #define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) 63 64 struct listelem { 65 struct listelem *next; 66 void *mem; 67 off_t file; 68 size_t size; 69 }; 70 71 static ssize_t 72 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 73 { 74 ssize_t rv; 75 76 if (lseek(fd, off, SEEK_SET) != off) { 77 perror(fn); 78 return -1; 79 } 80 if ((rv = read(fd, buf, size)) != size) { 81 fprintf(stderr, "%s: read error: %s\n", fn, 82 rv == -1 ? strerror(errno) : "short read"); 83 return -1; 84 } 85 return size; 86 } 87 88 static ssize_t 89 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 90 { 91 ssize_t rv; 92 93 if (lseek(fd, off, SEEK_SET) != off) { 94 perror(fn); 95 return -1; 96 } 97 if ((rv = write(fd, buf, size)) != size) { 98 fprintf(stderr, "%s: write error: %s\n", fn, 99 rv == -1 ? strerror(errno) : "short write"); 100 return -1; 101 } 102 return size; 103 } 104 105 static void * 106 xmalloc(size_t size, const char *fn, const char *use) 107 { 108 void *rv; 109 110 rv = malloc(size); 111 if (rv == NULL) 112 fprintf(stderr, "%s: out of memory (allocating for %s)\n", 113 fn, use); 114 return (rv); 115 } 116 117 int 118 ELFNAMEEND(check)(int fd, const char *fn) 119 { 120 Elf_Ehdr eh; 121 struct stat sb; 122 123 /* 124 * Check the header to maek sure it's an ELF file (of the 125 * appropriate size). 126 */ 127 if (fstat(fd, &sb) == -1) 128 return 0; 129 if (sb.st_size < sizeof eh) 130 return 0; 131 if (read(fd, &eh, sizeof eh) != sizeof eh) 132 return 0; 133 134 if (IS_ELF(eh) == 0) 135 return 0; 136 137 switch (eh.e_machine) { 138 case EM_386: break; 139 case EM_ALPHA: break; 140 /* ELFDEFNNAME(MACHDEP_ID_CASES) */ 141 142 default: 143 return 0; 144 } 145 146 return 1; 147 } 148 149 int 150 ELFNAMEEND(hide)(int fd, const char *fn) 151 { 152 Elf_Ehdr ehdr; 153 Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr; 154 Elf_Sym *symtabp = NULL; 155 char *strtabp = NULL; 156 Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi; 157 struct listelem *relalist = NULL, *rellist = NULL, *tmpl; 158 ssize_t shdrsize; 159 int rv, i, weird; 160 161 rv = 0; 162 if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr) 163 goto bad; 164 165 shdrsize = ehdr.e_shnum * ehdr.e_shentsize; 166 if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL) 167 goto bad; 168 if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 169 goto bad; 170 171 symtabshdr = strtabshdr = NULL; 172 weird = 0; 173 for (i = 0; i < ehdr.e_shnum; i++) { 174 switch (shdrp[i].sh_type) { 175 case SHT_SYMTAB: 176 if (symtabshdr != NULL) 177 weird = 1; 178 symtabshdr = &shdrp[i]; 179 strtabshdr = &shdrp[shdrp[i].sh_link]; 180 break; 181 case SHT_RELA: 182 tmpl = xmalloc(sizeof *tmpl, fn, "rela list element"); 183 if (tmpl == NULL) 184 goto bad; 185 tmpl->mem = NULL; 186 tmpl->file = shdrp[i].sh_offset; 187 tmpl->size = shdrp[i].sh_size; 188 tmpl->next = relalist; 189 relalist = tmpl; 190 break; 191 case SHT_REL: 192 tmpl = xmalloc(sizeof *tmpl, fn, "rel list element"); 193 if (tmpl == NULL) 194 goto bad; 195 tmpl->mem = NULL; 196 tmpl->file = shdrp[i].sh_offset; 197 tmpl->size = shdrp[i].sh_size; 198 tmpl->next = rellist; 199 rellist = tmpl; 200 break; 201 } 202 } 203 if (symtabshdr == NULL) 204 goto out; 205 if (strtabshdr == NULL) 206 weird = 1; 207 if (weird) { 208 fprintf(stderr, "%s: weird executable (unsupported)\n", fn); 209 goto bad; 210 } 211 212 /* 213 * load up everything we need 214 */ 215 216 /* symbol table */ 217 if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table")) 218 == NULL) 219 goto bad; 220 if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size, 221 fn) != symtabshdr->sh_size) 222 goto bad; 223 224 /* string table */ 225 if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table")) 226 == NULL) 227 goto bad; 228 if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size, 229 fn) != strtabshdr->sh_size) 230 goto bad; 231 232 /* any rela tables */ 233 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 234 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table")) 235 == NULL) 236 goto bad; 237 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 238 tmpl->size) 239 goto bad; 240 } 241 242 /* any rel tables */ 243 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 244 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table")) 245 == NULL) 246 goto bad; 247 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 248 tmpl->size) 249 goto bad; 250 } 251 252 /* Prepare data structures for symbol movement. */ 253 nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize; 254 nlocalsyms = symtabshdr->sh_info; 255 if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 256 "symbol forward mapping table")) == NULL) 257 goto bad; 258 if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 259 "symbol reverse mapping table")) == NULL) 260 goto bad; 261 262 /* init location -> symbol # table */ 263 for (ewi = 0; ewi < nsyms; ewi++) 264 symrvmap[ewi] = ewi; 265 266 /* move symbols, making them local */ 267 for (ewi = nlocalsyms; ewi < nsyms; ewi++) { 268 Elf_Sym *sp, symswap; 269 Elf_Word mapswap; 270 271 sp = &symtabp[ewi]; 272 273 /* if it's on our keep list, don't move it */ 274 if (in_keep_list(strtabp + sp->st_name)) 275 continue; 276 277 /* if it's an undefined symbol, keep it */ 278 if (sp->st_shndx == SHN_UNDEF) 279 continue; 280 281 /* adjust the symbol so that it's local */ 282 sp->st_info = 283 ELF_ST_INFO(STB_LOCAL, sp->st_info); 284 /* (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */ 285 286 /* 287 * move the symbol to its new location 288 */ 289 290 /* note that symbols in those locations have been swapped */ 291 mapswap = symrvmap[ewi]; 292 symrvmap[ewi] = symrvmap[nlocalsyms]; 293 symrvmap[nlocalsyms] = mapswap; 294 295 /* and swap the symbols */ 296 symswap = *sp; 297 *sp = symtabp[nlocalsyms]; 298 symtabp[nlocalsyms] = symswap; 299 300 nlocalsyms++; /* note new local sym */ 301 } 302 symtabshdr->sh_info = nlocalsyms; 303 304 /* set up symbol # -> location mapping table */ 305 for (ewi = 0; ewi < nsyms; ewi++) 306 symfwmap[symrvmap[ewi]] = ewi; 307 308 /* any rela tables */ 309 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 310 Elf_Rela *relap = tmpl->mem; 311 312 for (ewi = 0; ewi < tmpl->size / sizeof(*relap); ewi++) { 313 relap[ewi].r_info = 314 #if (ELFSIZE == 32) /* XXX */ 315 symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 | 316 ELF_R_TYPE(relap[ewi].r_info); 317 #elif (ELFSIZE == 64) /* XXX */ 318 symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 | 319 ELF_R_TYPE(relap[ewi].r_info); 320 #endif /* XXX */ 321 } 322 } 323 324 /* any rel tables */ 325 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 326 Elf_Rel *relp = tmpl->mem; 327 328 for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) { 329 relp[ewi].r_info = 330 #if (ELFSIZE == 32) /* XXX */ 331 symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 | 332 ELF_R_TYPE(relp[ewi].r_info); 333 #elif (ELFSIZE == 64) /* XXX */ 334 symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 | 335 ELF_R_TYPE(relp[ewi].r_info); 336 #endif /* XXX */ 337 } 338 } 339 340 /* 341 * write new tables to the file 342 */ 343 if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 344 goto bad; 345 if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset, 346 symtabshdr->sh_size, fn) != symtabshdr->sh_size) 347 goto bad; 348 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 349 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 350 tmpl->size) 351 goto bad; 352 } 353 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 354 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 355 tmpl->size) 356 goto bad; 357 } 358 359 out: 360 if (shdrp != NULL) 361 free(shdrp); 362 if (symtabp != NULL) 363 free(symtabp); 364 if (strtabp != NULL) 365 free(strtabp); 366 if (symfwmap != NULL) 367 free(symfwmap); 368 if (symrvmap != NULL) 369 free(symrvmap); 370 while ((tmpl = relalist) != NULL) { 371 relalist = tmpl->next; 372 if (tmpl->mem != NULL) 373 free(tmpl->mem); 374 free(tmpl); 375 } 376 while ((tmpl = rellist) != NULL) { 377 rellist = tmpl->next; 378 if (tmpl->mem != NULL) 379 free(tmpl->mem); 380 free(tmpl); 381 } 382 return (rv); 383 384 bad: 385 rv = 1; 386 goto out; 387 } 388 389 #endif /* include this size of ELF */ 390