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