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