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 static const char rcsid[] = 37 "$FreeBSD$"; 38 #endif 39 40 #ifndef ELFSIZE 41 #define ELFSIZE 32 42 #endif 43 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 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 #elif (ELFSIZE == 64) 62 #include <sys/elf64.h> 63 #endif 64 #include <sys/elf_generic.h> 65 66 #define CONCAT(x,y) __CONCAT(x,y) 67 #define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) 68 #define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) 69 #define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) 70 #define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) 71 72 struct listelem { 73 struct listelem *next; 74 void *mem; 75 off_t file; 76 size_t size; 77 }; 78 79 static ssize_t 80 xreadatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 81 { 82 ssize_t rv; 83 84 if (lseek(fd, off, SEEK_SET) != off) { 85 perror(fn); 86 return -1; 87 } 88 if ((rv = read(fd, buf, size)) != size) { 89 fprintf(stderr, "%s: read error: %s\n", fn, 90 rv == -1 ? strerror(errno) : "short read"); 91 return -1; 92 } 93 return size; 94 } 95 96 static ssize_t 97 xwriteatoff(int fd, void *buf, off_t off, size_t size, const char *fn) 98 { 99 ssize_t rv; 100 101 if (lseek(fd, off, SEEK_SET) != off) { 102 perror(fn); 103 return -1; 104 } 105 if ((rv = write(fd, buf, size)) != size) { 106 fprintf(stderr, "%s: write error: %s\n", fn, 107 rv == -1 ? strerror(errno) : "short write"); 108 return -1; 109 } 110 return size; 111 } 112 113 static void * 114 xmalloc(size_t size, const char *fn, const char *use) 115 { 116 void *rv; 117 118 rv = malloc(size); 119 if (rv == NULL) 120 fprintf(stderr, "%s: out of memory (allocating for %s)\n", 121 fn, use); 122 return (rv); 123 } 124 125 int 126 ELFNAMEEND(check)(int fd, const char *fn) 127 { 128 Elf_Ehdr eh; 129 struct stat sb; 130 131 /* 132 * Check the header to maek sure it's an ELF file (of the 133 * appropriate size). 134 */ 135 if (fstat(fd, &sb) == -1) 136 return 0; 137 if (sb.st_size < sizeof eh) 138 return 0; 139 if (read(fd, &eh, sizeof eh) != sizeof eh) 140 return 0; 141 142 if (IS_ELF(eh) == 0) 143 return 0; 144 145 switch (eh.e_machine) { 146 case EM_386: break; 147 case EM_ALPHA: break; 148 /* ELFDEFNNAME(MACHDEP_ID_CASES) */ 149 150 default: 151 return 0; 152 } 153 154 return 1; 155 } 156 157 int 158 ELFNAMEEND(hide)(int fd, const char *fn) 159 { 160 Elf_Ehdr ehdr; 161 Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr; 162 Elf_Sym *symtabp = NULL; 163 char *strtabp = NULL; 164 Elf_Word *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi; 165 struct listelem *relalist = NULL, *rellist = NULL, *tmpl; 166 ssize_t shdrsize; 167 int rv, i, weird; 168 169 rv = 0; 170 if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr) 171 goto bad; 172 173 shdrsize = ehdr.e_shnum * ehdr.e_shentsize; 174 if ((shdrp = xmalloc(shdrsize, fn, "section header table")) == NULL) 175 goto bad; 176 if (xreadatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 177 goto bad; 178 179 symtabshdr = strtabshdr = NULL; 180 weird = 0; 181 for (i = 0; i < ehdr.e_shnum; i++) { 182 switch (shdrp[i].sh_type) { 183 case SHT_SYMTAB: 184 if (symtabshdr != NULL) 185 weird = 1; 186 symtabshdr = &shdrp[i]; 187 strtabshdr = &shdrp[shdrp[i].sh_link]; 188 break; 189 case SHT_RELA: 190 tmpl = xmalloc(sizeof *tmpl, fn, "rela list element"); 191 if (tmpl == NULL) 192 goto bad; 193 tmpl->mem = NULL; 194 tmpl->file = shdrp[i].sh_offset; 195 tmpl->size = shdrp[i].sh_size; 196 tmpl->next = relalist; 197 relalist = tmpl; 198 break; 199 case SHT_REL: 200 tmpl = xmalloc(sizeof *tmpl, fn, "rel list element"); 201 if (tmpl == NULL) 202 goto bad; 203 tmpl->mem = NULL; 204 tmpl->file = shdrp[i].sh_offset; 205 tmpl->size = shdrp[i].sh_size; 206 tmpl->next = rellist; 207 rellist = tmpl; 208 break; 209 } 210 } 211 if (symtabshdr == NULL) 212 goto out; 213 if (strtabshdr == NULL) 214 weird = 1; 215 if (weird) { 216 fprintf(stderr, "%s: weird executable (unsupported)\n", fn); 217 goto bad; 218 } 219 220 /* 221 * load up everything we need 222 */ 223 224 /* symbol table */ 225 if ((symtabp = xmalloc(symtabshdr->sh_size, fn, "symbol table")) 226 == NULL) 227 goto bad; 228 if (xreadatoff(fd, symtabp, symtabshdr->sh_offset, symtabshdr->sh_size, 229 fn) != symtabshdr->sh_size) 230 goto bad; 231 232 /* string table */ 233 if ((strtabp = xmalloc(strtabshdr->sh_size, fn, "string table")) 234 == NULL) 235 goto bad; 236 if (xreadatoff(fd, strtabp, strtabshdr->sh_offset, strtabshdr->sh_size, 237 fn) != strtabshdr->sh_size) 238 goto bad; 239 240 /* any rela tables */ 241 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 242 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table")) 243 == NULL) 244 goto bad; 245 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 246 tmpl->size) 247 goto bad; 248 } 249 250 /* any rel tables */ 251 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 252 if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table")) 253 == NULL) 254 goto bad; 255 if (xreadatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 256 tmpl->size) 257 goto bad; 258 } 259 260 /* Prepare data structures for symbol movement. */ 261 nsyms = symtabshdr->sh_size / symtabshdr->sh_entsize; 262 nlocalsyms = symtabshdr->sh_info; 263 if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 264 "symbol forward mapping table")) == NULL) 265 goto bad; 266 if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Word), fn, 267 "symbol reverse mapping table")) == NULL) 268 goto bad; 269 270 /* init location -> symbol # table */ 271 for (ewi = 0; ewi < nsyms; ewi++) 272 symrvmap[ewi] = ewi; 273 274 /* move symbols, making them local */ 275 for (ewi = nlocalsyms; ewi < nsyms; ewi++) { 276 Elf_Sym *sp, symswap; 277 Elf_Word mapswap; 278 279 sp = &symtabp[ewi]; 280 281 /* if it's on our keep list, don't move it */ 282 if (in_keep_list(strtabp + sp->st_name)) 283 continue; 284 285 /* if it's an undefined symbol, keep it */ 286 if (sp->st_shndx == SHN_UNDEF) 287 continue; 288 289 /* adjust the symbol so that it's local */ 290 sp->st_info = 291 ELF_ST_INFO(STB_LOCAL, sp->st_info); 292 /* (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */ 293 294 /* 295 * move the symbol to its new location 296 */ 297 298 /* note that symbols in those locations have been swapped */ 299 mapswap = symrvmap[ewi]; 300 symrvmap[ewi] = symrvmap[nlocalsyms]; 301 symrvmap[nlocalsyms] = mapswap; 302 303 /* and swap the symbols */ 304 symswap = *sp; 305 *sp = symtabp[nlocalsyms]; 306 symtabp[nlocalsyms] = symswap; 307 308 nlocalsyms++; /* note new local sym */ 309 } 310 symtabshdr->sh_info = nlocalsyms; 311 312 /* set up symbol # -> location mapping table */ 313 for (ewi = 0; ewi < nsyms; ewi++) 314 symfwmap[symrvmap[ewi]] = ewi; 315 316 /* any rela tables */ 317 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 318 Elf_Rela *relap = tmpl->mem; 319 320 for (ewi = 0; ewi < tmpl->size / sizeof(*relap); ewi++) { 321 relap[ewi].r_info = 322 #if (ELFSIZE == 32) /* XXX */ 323 symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 8 | 324 ELF_R_TYPE(relap[ewi].r_info); 325 #elif (ELFSIZE == 64) /* XXX */ 326 symfwmap[ELF_R_SYM(relap[ewi].r_info)] << 32 | 327 ELF_R_TYPE(relap[ewi].r_info); 328 #endif /* XXX */ 329 } 330 } 331 332 /* any rel tables */ 333 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 334 Elf_Rel *relp = tmpl->mem; 335 336 for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) { 337 relp[ewi].r_info = 338 #if (ELFSIZE == 32) /* XXX */ 339 symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 8 | 340 ELF_R_TYPE(relp[ewi].r_info); 341 #elif (ELFSIZE == 64) /* XXX */ 342 symfwmap[ELF_R_SYM(relp[ewi].r_info)] << 32 | 343 ELF_R_TYPE(relp[ewi].r_info); 344 #endif /* XXX */ 345 } 346 } 347 348 /* 349 * write new tables to the file 350 */ 351 if (xwriteatoff(fd, shdrp, ehdr.e_shoff, shdrsize, fn) != shdrsize) 352 goto bad; 353 if (xwriteatoff(fd, symtabp, symtabshdr->sh_offset, 354 symtabshdr->sh_size, fn) != symtabshdr->sh_size) 355 goto bad; 356 for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { 357 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 358 tmpl->size) 359 goto bad; 360 } 361 for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { 362 if (xwriteatoff(fd, tmpl->mem, tmpl->file, tmpl->size, fn) != 363 tmpl->size) 364 goto bad; 365 } 366 367 out: 368 if (shdrp != NULL) 369 free(shdrp); 370 if (symtabp != NULL) 371 free(symtabp); 372 if (strtabp != NULL) 373 free(strtabp); 374 if (symfwmap != NULL) 375 free(symfwmap); 376 if (symrvmap != NULL) 377 free(symrvmap); 378 while ((tmpl = relalist) != NULL) { 379 relalist = tmpl->next; 380 if (tmpl->mem != NULL) 381 free(tmpl->mem); 382 free(tmpl); 383 } 384 while ((tmpl = rellist) != NULL) { 385 rellist = tmpl->next; 386 if (tmpl->mem != NULL) 387 free(tmpl->mem); 388 free(tmpl); 389 } 390 return (rv); 391 392 bad: 393 rv = 1; 394 goto out; 395 } 396 397 #endif /* include this size of ELF */ 398