1 1.25 gutterid /* $NetBSD: elf2aout.c,v 1.25 2024/11/01 00:35:53 gutteridge Exp $ */ 2 1.2 jonathan 3 1.1 jonathan /* 4 1.1 jonathan * Copyright (c) 1995 5 1.1 jonathan * Ted Lemon (hereinafter referred to as the author) 6 1.1 jonathan * 7 1.1 jonathan * Redistribution and use in source and binary forms, with or without 8 1.1 jonathan * modification, are permitted provided that the following conditions 9 1.1 jonathan * are met: 10 1.1 jonathan * 1. Redistributions of source code must retain the above copyright 11 1.1 jonathan * notice, this list of conditions and the following disclaimer. 12 1.1 jonathan * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jonathan * notice, this list of conditions and the following disclaimer in the 14 1.1 jonathan * documentation and/or other materials provided with the distribution. 15 1.1 jonathan * 3. The name of the author may not be used to endorse or promote products 16 1.1 jonathan * derived from this software without specific prior written permission. 17 1.1 jonathan * 18 1.1 jonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 19 1.1 jonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 jonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 jonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 22 1.1 jonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 jonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 jonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 jonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 jonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 jonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 jonathan * SUCH DAMAGE. 29 1.1 jonathan */ 30 1.1 jonathan 31 1.1 jonathan /* elf2aout.c 32 1.1 jonathan 33 1.1 jonathan This program converts an elf executable to a NetBSD a.out executable. 34 1.1 jonathan The minimal symbol table is copied, but the debugging symbols and 35 1.1 jonathan other informational sections are not. */ 36 1.1 jonathan 37 1.15 tsutsui #if HAVE_NBTOOL_CONFIG_H 38 1.15 tsutsui #include "nbtool_config.h" 39 1.15 tsutsui #endif 40 1.15 tsutsui 41 1.15 tsutsui #ifndef TARGET_BYTE_ORDER 42 1.15 tsutsui #define TARGET_BYTE_ORDER BYTE_ORDER 43 1.15 tsutsui #endif 44 1.15 tsutsui 45 1.1 jonathan #include <sys/types.h> 46 1.25 gutterid #include <sys/endian.h> 47 1.5 lukem #include <sys/exec_aout.h> 48 1.5 lukem #include <sys/exec_elf.h> 49 1.5 lukem 50 1.5 lukem #include <a.out.h> 51 1.5 lukem #include <err.h> 52 1.5 lukem #include <errno.h> 53 1.1 jonathan #include <fcntl.h> 54 1.5 lukem #include <limits.h> 55 1.1 jonathan #include <stdio.h> 56 1.5 lukem #include <stdlib.h> 57 1.1 jonathan #include <string.h> 58 1.5 lukem #include <unistd.h> 59 1.1 jonathan 60 1.3 jonathan 61 1.1 jonathan struct sect { 62 1.15 tsutsui /* should be unsigned long, but assume no a.out binaries on LP64 */ 63 1.15 tsutsui uint32_t vaddr; 64 1.15 tsutsui uint32_t len; 65 1.1 jonathan }; 66 1.1 jonathan 67 1.22 christos static void combine(struct sect *, struct sect *, int); 68 1.22 christos static int phcmp(const void *, const void *); 69 1.22 christos static void *saveRead(int file, off_t offset, size_t len, const char *name); 70 1.22 christos static void copy(int, int, off_t, off_t); 71 1.22 christos static void translate_syms(int, int, off_t, off_t, off_t, off_t); 72 1.5 lukem 73 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 74 1.22 christos static void bswap32_region(int32_t* , int); 75 1.15 tsutsui #endif 76 1.15 tsutsui 77 1.22 christos static int *symTypeTable; 78 1.22 christos static int debug; 79 1.22 christos 80 1.22 christos static __dead void 81 1.22 christos usage(void) 82 1.22 christos { 83 1.23 wiz fprintf(stderr, "Usage: %s [-Os] <elf executable> <a.out executable>\n", 84 1.22 christos getprogname()); 85 1.22 christos exit(EXIT_FAILURE); 86 1.22 christos } 87 1.22 christos 88 1.22 christos static const struct { 89 1.22 christos const char *n; 90 1.22 christos int v; 91 1.22 christos } nv[] = { 92 1.22 christos { ".text", N_TEXT }, 93 1.22 christos { ".rodata", N_TEXT }, 94 1.22 christos { ".data", N_DATA }, 95 1.22 christos { ".sdata", N_DATA }, 96 1.22 christos { ".lit4", N_DATA }, 97 1.22 christos { ".lit8", N_DATA }, 98 1.22 christos { ".bss", N_BSS }, 99 1.22 christos { ".sbss", N_BSS }, 100 1.22 christos }; 101 1.22 christos 102 1.22 christos static int 103 1.22 christos get_symtab_type(const char *name) 104 1.22 christos { 105 1.22 christos size_t i; 106 1.22 christos for (i = 0; i < __arraycount(nv); i++) { 107 1.22 christos if (strcmp(name, nv[i].n) == 0) 108 1.22 christos return nv[i].v; 109 1.22 christos } 110 1.22 christos if (debug) 111 1.22 christos warnx("section `%s' is not handled\n", name); 112 1.22 christos return 0; 113 1.22 christos } 114 1.22 christos 115 1.22 christos static uint32_t 116 1.22 christos get_mid(const Elf32_Ehdr *ex) 117 1.22 christos { 118 1.22 christos switch (ex->e_machine) { 119 1.22 christos #ifdef notyet 120 1.22 christos case EM_AARCH64: 121 1.22 christos return MID_AARCH64; 122 1.22 christos case EM_ALPHA: 123 1.22 christos return MID_ALPHA; 124 1.22 christos #endif 125 1.22 christos case EM_ARM: 126 1.22 christos return MID_ARM6; 127 1.22 christos #ifdef notyet 128 1.22 christos case EM_PARISC: 129 1.22 christos return MID_HPPA; 130 1.22 christos #endif 131 1.22 christos case EM_386: 132 1.22 christos return MID_I386; 133 1.22 christos case EM_68K: 134 1.22 christos return MID_M68K; 135 1.22 christos case EM_OR1K: 136 1.22 christos return MID_OR1K; 137 1.22 christos case EM_MIPS: 138 1.22 christos if (ex->e_ident[EI_DATA] == ELFDATA2LSB) 139 1.22 christos return MID_PMAX; 140 1.22 christos else 141 1.22 christos return MID_MIPS; 142 1.22 christos case EM_PPC: 143 1.22 christos return MID_POWERPC; 144 1.22 christos #ifdef notyet 145 1.22 christos case EM_PPC64: 146 1.22 christos return MID_POWERPC64; 147 1.22 christos break; 148 1.22 christos #endif 149 1.22 christos case EM_RISCV: 150 1.22 christos return MID_RISCV; 151 1.22 christos case EM_SH: 152 1.22 christos return MID_SH3; 153 1.22 christos case EM_SPARC: 154 1.22 christos case EM_SPARC32PLUS: 155 1.22 christos case EM_SPARCV9: 156 1.22 christos if (ex->e_ident[EI_CLASS] == ELFCLASS32) 157 1.22 christos return MID_SPARC; 158 1.22 christos #ifdef notyet 159 1.22 christos return MID_SPARC64; 160 1.22 christos case EM_X86_64: 161 1.22 christos return MID_X86_64; 162 1.22 christos #else 163 1.22 christos break; 164 1.22 christos #endif 165 1.22 christos case EM_VAX: 166 1.22 christos return MID_VAX; 167 1.22 christos case EM_NONE: 168 1.22 christos return MID_ZERO; 169 1.22 christos default: 170 1.22 christos break; 171 1.22 christos } 172 1.22 christos if (debug) 173 1.22 christos warnx("Unsupported machine `%d'", ex->e_machine); 174 1.22 christos return MID_ZERO; 175 1.22 christos } 176 1.22 christos 177 1.22 christos static unsigned char 178 1.22 christos get_type(Elf32_Half shndx) 179 1.22 christos { 180 1.22 christos switch (shndx) { 181 1.22 christos case SHN_UNDEF: 182 1.22 christos return N_UNDF; 183 1.22 christos case SHN_ABS: 184 1.22 christos return N_ABS; 185 1.22 christos case SHN_COMMON: 186 1.22 christos case SHN_MIPS_ACOMMON: 187 1.22 christos return N_COMM; 188 1.22 christos default: 189 1.22 christos return (unsigned char)symTypeTable[shndx]; 190 1.22 christos } 191 1.22 christos } 192 1.5 lukem 193 1.5 lukem int 194 1.5 lukem main(int argc, char **argv) 195 1.1 jonathan { 196 1.5 lukem Elf32_Ehdr ex; 197 1.5 lukem Elf32_Phdr *ph; 198 1.5 lukem Elf32_Shdr *sh; 199 1.5 lukem char *shstrtab; 200 1.17 christos ssize_t i, strtabix, symtabix; 201 1.5 lukem struct sect text, data, bss; 202 1.5 lukem struct exec aex; 203 1.5 lukem int infile, outfile; 204 1.15 tsutsui uint32_t cur_vma = UINT32_MAX; 205 1.15 tsutsui uint32_t mid; 206 1.22 christos int symflag = 0, c; 207 1.22 christos unsigned long magic = ZMAGIC; 208 1.5 lukem 209 1.5 lukem strtabix = symtabix = 0; 210 1.5 lukem text.len = data.len = bss.len = 0; 211 1.5 lukem text.vaddr = data.vaddr = bss.vaddr = 0; 212 1.5 lukem 213 1.22 christos while ((c = getopt(argc, argv, "dOs")) != -1) { 214 1.22 christos switch (c) { 215 1.22 christos case 'd': 216 1.22 christos debug++; 217 1.22 christos break; 218 1.22 christos case 's': 219 1.22 christos symflag = 1; 220 1.22 christos break; 221 1.22 christos case 'O': 222 1.22 christos magic = OMAGIC; 223 1.22 christos break; 224 1.22 christos case '?': 225 1.22 christos default: 226 1.22 christos usage: 227 1.22 christos usage(); 228 1.22 christos } 229 1.22 christos } 230 1.22 christos 231 1.22 christos argc -= optind; 232 1.22 christos argv += optind; 233 1.22 christos 234 1.5 lukem /* Check args... */ 235 1.22 christos if (argc != 2) 236 1.22 christos goto usage; 237 1.22 christos 238 1.22 christos 239 1.5 lukem /* Try the input file... */ 240 1.22 christos if ((infile = open(argv[0], O_RDONLY)) < 0) 241 1.22 christos err(EXIT_FAILURE, "Can't open `%s' for read", argv[0]); 242 1.17 christos 243 1.5 lukem /* Read the header, which is at the beginning of the file... */ 244 1.5 lukem i = read(infile, &ex, sizeof ex); 245 1.5 lukem if (i != sizeof ex) { 246 1.17 christos if (i == -1) 247 1.17 christos err(EXIT_FAILURE, "Error reading `%s'", argv[1]); 248 1.17 christos else 249 1.17 christos errx(EXIT_FAILURE, "End of file reading `%s'", argv[1]); 250 1.5 lukem } 251 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 252 1.15 tsutsui ex.e_type = bswap16(ex.e_type); 253 1.15 tsutsui ex.e_machine = bswap16(ex.e_machine); 254 1.15 tsutsui ex.e_version = bswap32(ex.e_version); 255 1.15 tsutsui ex.e_entry = bswap32(ex.e_entry); 256 1.15 tsutsui ex.e_phoff = bswap32(ex.e_phoff); 257 1.15 tsutsui ex.e_shoff = bswap32(ex.e_shoff); 258 1.15 tsutsui ex.e_flags = bswap32(ex.e_flags); 259 1.15 tsutsui ex.e_ehsize = bswap16(ex.e_ehsize); 260 1.15 tsutsui ex.e_phentsize = bswap16(ex.e_phentsize); 261 1.15 tsutsui ex.e_phnum = bswap16(ex.e_phnum); 262 1.15 tsutsui ex.e_shentsize = bswap16(ex.e_shentsize); 263 1.15 tsutsui ex.e_shnum = bswap16(ex.e_shnum); 264 1.15 tsutsui ex.e_shstrndx = bswap16(ex.e_shstrndx); 265 1.15 tsutsui #endif 266 1.22 christos // Not yet 267 1.22 christos if (ex.e_ident[EI_CLASS] == ELFCLASS64) 268 1.22 christos errx(EXIT_FAILURE, "Only 32 bit is supported"); 269 1.22 christos 270 1.5 lukem /* Read the program headers... */ 271 1.17 christos ph = saveRead(infile, ex.e_phoff, 272 1.17 christos (size_t)ex.e_phnum * sizeof(Elf32_Phdr), "ph"); 273 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 274 1.15 tsutsui bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum); 275 1.15 tsutsui #endif 276 1.5 lukem /* Read the section headers... */ 277 1.17 christos sh = saveRead(infile, ex.e_shoff, 278 1.17 christos (size_t)ex.e_shnum * sizeof(Elf32_Shdr), "sh"); 279 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 280 1.15 tsutsui bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum); 281 1.15 tsutsui #endif 282 1.5 lukem /* Read in the section string table. */ 283 1.5 lukem shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset, 284 1.17 christos (size_t)sh[ex.e_shstrndx].sh_size, "shstrtab"); 285 1.5 lukem 286 1.5 lukem /* Find space for a table matching ELF section indices to a.out symbol 287 1.5 lukem * types. */ 288 1.13 tsutsui symTypeTable = malloc(ex.e_shnum * sizeof(int)); 289 1.17 christos if (symTypeTable == NULL) 290 1.17 christos err(EXIT_FAILURE, "symTypeTable: can't allocate"); 291 1.5 lukem memset(symTypeTable, 0, ex.e_shnum * sizeof(int)); 292 1.5 lukem 293 1.5 lukem /* Look for the symbol table and string table... Also map section 294 1.5 lukem * indices to symbol types for a.out */ 295 1.5 lukem for (i = 0; i < ex.e_shnum; i++) { 296 1.5 lukem char *name = shstrtab + sh[i].sh_name; 297 1.5 lukem if (!strcmp(name, ".symtab")) 298 1.5 lukem symtabix = i; 299 1.22 christos else if (!strcmp(name, ".strtab")) 300 1.22 christos strtabix = i; 301 1.5 lukem else 302 1.22 christos symTypeTable[i] = get_symtab_type(name); 303 1.5 lukem } 304 1.5 lukem 305 1.5 lukem /* Figure out if we can cram the program header into an a.out 306 1.5 lukem * header... Basically, we can't handle anything but loadable 307 1.5 lukem * segments, but we can ignore some kinds of segments. We can't 308 1.5 lukem * handle holes in the address space, and we handle start addresses 309 1.5 lukem * other than 0x1000 by hoping that the loader will know where to load 310 1.5 lukem * - a.out doesn't have an explicit load address. Segments may be 311 1.5 lukem * out of order, so we sort them first. */ 312 1.5 lukem qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp); 313 1.5 lukem for (i = 0; i < ex.e_phnum; i++) { 314 1.5 lukem /* Section types we can ignore... */ 315 1.7 drochner if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE || 316 1.7 drochner ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO) 317 1.5 lukem continue; 318 1.5 lukem /* Section types we can't handle... */ 319 1.22 christos if (ph[i].p_type == PT_TLS) { 320 1.22 christos if (debug) 321 1.22 christos warnx("Can't handle TLS section"); 322 1.22 christos continue; 323 1.22 christos } 324 1.22 christos if (ph[i].p_type != PT_LOAD) 325 1.22 christos errx(EXIT_FAILURE, "Program header %zd " 326 1.22 christos "type %d can't be converted.", i, ph[i].p_type); 327 1.5 lukem /* Writable (data) segment? */ 328 1.5 lukem if (ph[i].p_flags & PF_W) { 329 1.5 lukem struct sect ndata, nbss; 330 1.5 lukem 331 1.5 lukem ndata.vaddr = ph[i].p_vaddr; 332 1.5 lukem ndata.len = ph[i].p_filesz; 333 1.5 lukem nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; 334 1.5 lukem nbss.len = ph[i].p_memsz - ph[i].p_filesz; 335 1.5 lukem 336 1.5 lukem combine(&data, &ndata, 0); 337 1.5 lukem combine(&bss, &nbss, 1); 338 1.5 lukem } else { 339 1.5 lukem struct sect ntxt; 340 1.5 lukem 341 1.5 lukem ntxt.vaddr = ph[i].p_vaddr; 342 1.5 lukem ntxt.len = ph[i].p_filesz; 343 1.5 lukem 344 1.5 lukem combine(&text, &ntxt, 0); 345 1.1 jonathan } 346 1.5 lukem /* Remember the lowest segment start address. */ 347 1.5 lukem if (ph[i].p_vaddr < cur_vma) 348 1.5 lukem cur_vma = ph[i].p_vaddr; 349 1.5 lukem } 350 1.5 lukem 351 1.5 lukem /* Sections must be in order to be converted... */ 352 1.5 lukem if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 353 1.17 christos text.vaddr + text.len > data.vaddr || 354 1.17 christos data.vaddr + data.len > bss.vaddr) 355 1.17 christos errx(EXIT_FAILURE, "Sections ordering prevents a.out " 356 1.17 christos "conversion."); 357 1.5 lukem /* If there's a data section but no text section, then the loader 358 1.5 lukem * combined everything into one section. That needs to be the text 359 1.5 lukem * section, so just make the data section zero length following text. */ 360 1.13 tsutsui if (data.len && text.len == 0) { 361 1.5 lukem text = data; 362 1.5 lukem data.vaddr = text.vaddr + text.len; 363 1.5 lukem data.len = 0; 364 1.5 lukem } 365 1.5 lukem /* If there is a gap between text and data, we'll fill it when we copy 366 1.5 lukem * the data, so update the length of the text segment as represented 367 1.5 lukem * in a.out to reflect that, since a.out doesn't allow gaps in the 368 1.5 lukem * program address space. */ 369 1.5 lukem if (text.vaddr + text.len < data.vaddr) 370 1.5 lukem text.len = data.vaddr - text.vaddr; 371 1.5 lukem 372 1.5 lukem /* We now have enough information to cons up an a.out header... */ 373 1.22 christos mid = get_mid(&ex); 374 1.25 gutterid aex.a_midmag = (u_long)htobe32(((u_long)symflag << 26) 375 1.22 christos | ((u_long)mid << 16) | magic); 376 1.13 tsutsui 377 1.5 lukem aex.a_text = text.len; 378 1.5 lukem aex.a_data = data.len; 379 1.5 lukem aex.a_bss = bss.len; 380 1.5 lukem aex.a_entry = ex.e_entry; 381 1.5 lukem aex.a_syms = (sizeof(struct nlist) * 382 1.22 christos (symtabix != -1 ? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0)); 383 1.5 lukem aex.a_trsize = 0; 384 1.5 lukem aex.a_drsize = 0; 385 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 386 1.15 tsutsui aex.a_text = bswap32(aex.a_text); 387 1.15 tsutsui aex.a_data = bswap32(aex.a_data); 388 1.15 tsutsui aex.a_bss = bswap32(aex.a_bss); 389 1.15 tsutsui aex.a_entry = bswap32(aex.a_entry); 390 1.15 tsutsui aex.a_syms = bswap32(aex.a_syms); 391 1.15 tsutsui aex.a_trsize = bswap32(aex.a_trsize); 392 1.15 tsutsui aex.a_drsize = bswap32(aex.a_drsize); 393 1.15 tsutsui #endif 394 1.5 lukem 395 1.5 lukem /* Make the output file... */ 396 1.22 christos if ((outfile = open(argv[1], O_WRONLY | O_CREAT, 0777)) < 0) 397 1.22 christos err(EXIT_FAILURE, "Unable to create `%s'", argv[1]); 398 1.6 simonb /* Truncate file... */ 399 1.6 simonb if (ftruncate(outfile, 0)) { 400 1.22 christos warn("ftruncate %s", argv[1]); 401 1.6 simonb } 402 1.5 lukem /* Write the header... */ 403 1.5 lukem i = write(outfile, &aex, sizeof aex); 404 1.17 christos if (i != sizeof aex) 405 1.22 christos err(EXIT_FAILURE, "Can't write `%s'", argv[1]); 406 1.5 lukem /* Copy the loadable sections. Zero-fill any gaps less than 64k; 407 1.5 lukem * complain about any zero-filling, and die if we're asked to 408 1.5 lukem * zero-fill more than 64k. */ 409 1.5 lukem for (i = 0; i < ex.e_phnum; i++) { 410 1.5 lukem /* Unprocessable sections were handled above, so just verify 411 1.5 lukem * that the section can be loaded before copying. */ 412 1.7 drochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { 413 1.5 lukem if (cur_vma != ph[i].p_vaddr) { 414 1.15 tsutsui uint32_t gap = ph[i].p_vaddr - cur_vma; 415 1.5 lukem char obuf[1024]; 416 1.5 lukem if (gap > 65536) 417 1.17 christos errx(EXIT_FAILURE, 418 1.17 christos "Intersegment gap (%u bytes) too large", gap); 419 1.22 christos if (debug) 420 1.22 christos warnx("%u byte intersegment gap", gap); 421 1.5 lukem memset(obuf, 0, sizeof obuf); 422 1.5 lukem while (gap) { 423 1.17 christos ssize_t count = write(outfile, obuf, 424 1.17 christos (gap > sizeof obuf 425 1.17 christos ? sizeof obuf : gap)); 426 1.17 christos if (count < 0) 427 1.17 christos err(EXIT_FAILURE, 428 1.17 christos "Error writing gap"); 429 1.17 christos gap -= (uint32_t)count; 430 1.5 lukem } 431 1.5 lukem } 432 1.5 lukem copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz); 433 1.5 lukem cur_vma = ph[i].p_vaddr + ph[i].p_filesz; 434 1.1 jonathan } 435 1.5 lukem } 436 1.5 lukem 437 1.5 lukem /* Copy and translate the symbol table... */ 438 1.5 lukem translate_syms(outfile, infile, 439 1.5 lukem sh[symtabix].sh_offset, sh[symtabix].sh_size, 440 1.5 lukem sh[strtabix].sh_offset, sh[strtabix].sh_size); 441 1.1 jonathan 442 1.17 christos free(ph); 443 1.17 christos free(sh); 444 1.17 christos free(shstrtab); 445 1.17 christos free(symTypeTable); 446 1.5 lukem /* Looks like we won... */ 447 1.17 christos return EXIT_SUCCESS; 448 1.1 jonathan } 449 1.1 jonathan /* translate_syms (out, in, offset, size) 450 1.1 jonathan 451 1.1 jonathan Read the ELF symbol table from in at offset; translate it into a.out 452 1.1 jonathan nlist format and write it to out. */ 453 1.1 jonathan 454 1.5 lukem void 455 1.13 tsutsui translate_syms(int out, int in, off_t symoff, off_t symsize, 456 1.13 tsutsui off_t stroff, off_t strsize) 457 1.1 jonathan { 458 1.5 lukem #define SYMS_PER_PASS 64 459 1.5 lukem Elf32_Sym inbuf[64]; 460 1.5 lukem struct nlist outbuf[64]; 461 1.17 christos ssize_t i, remaining, cur; 462 1.5 lukem char *oldstrings; 463 1.5 lukem char *newstrings, *nsp; 464 1.20 skrll size_t newstringsize; 465 1.20 skrll uint32_t stringsizebuf; 466 1.5 lukem 467 1.5 lukem /* Zero the unused fields in the output buffer.. */ 468 1.5 lukem memset(outbuf, 0, sizeof outbuf); 469 1.5 lukem 470 1.5 lukem /* Find number of symbols to process... */ 471 1.19 martin remaining = (ssize_t)(symsize / (off_t)sizeof(Elf32_Sym)); 472 1.5 lukem 473 1.5 lukem /* Suck in the old string table... */ 474 1.17 christos oldstrings = saveRead(in, stroff, (size_t)strsize, "string table"); 475 1.5 lukem 476 1.20 skrll /* 477 1.20 skrll * Allocate space for the new one. We will increase the space if 478 1.20 skrll * this is too small 479 1.20 skrll */ 480 1.17 christos newstringsize = (size_t)(strsize + remaining); 481 1.13 tsutsui newstrings = malloc(newstringsize); 482 1.17 christos if (newstrings == NULL) 483 1.17 christos err(EXIT_FAILURE, "No memory for new string table!"); 484 1.5 lukem /* Initialize the table pointer... */ 485 1.5 lukem nsp = newstrings; 486 1.5 lukem 487 1.10 soren /* Go the start of the ELF symbol table... */ 488 1.17 christos if (lseek(in, symoff, SEEK_SET) < 0) 489 1.17 christos err(EXIT_FAILURE, "Can't seek"); 490 1.5 lukem /* Translate and copy symbols... */ 491 1.20 skrll for (; remaining; remaining -= cur) { 492 1.5 lukem cur = remaining; 493 1.5 lukem if (cur > SYMS_PER_PASS) 494 1.5 lukem cur = SYMS_PER_PASS; 495 1.17 christos if ((i = read(in, inbuf, (size_t)cur * sizeof(Elf32_Sym))) 496 1.15 tsutsui != cur * (ssize_t)sizeof(Elf32_Sym)) { 497 1.5 lukem if (i < 0) 498 1.17 christos err(EXIT_FAILURE, "%s: read error", __func__); 499 1.5 lukem else 500 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file", 501 1.17 christos __func__); 502 1.5 lukem } 503 1.5 lukem /* Do the translation... */ 504 1.5 lukem for (i = 0; i < cur; i++) { 505 1.5 lukem int binding, type; 506 1.20 skrll size_t off, len; 507 1.5 lukem 508 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 509 1.15 tsutsui inbuf[i].st_name = bswap32(inbuf[i].st_name); 510 1.15 tsutsui inbuf[i].st_value = bswap32(inbuf[i].st_value); 511 1.15 tsutsui inbuf[i].st_size = bswap32(inbuf[i].st_size); 512 1.15 tsutsui inbuf[i].st_shndx = bswap16(inbuf[i].st_shndx); 513 1.15 tsutsui #endif 514 1.20 skrll off = (size_t)(nsp - newstrings); 515 1.20 skrll 516 1.20 skrll /* length of this symbol with leading '_' and trailing '\0' */ 517 1.20 skrll len = strlen(oldstrings + inbuf[i].st_name) + 1 + 1; 518 1.20 skrll 519 1.20 skrll /* Does it fit? If not make more space */ 520 1.20 skrll if (newstringsize - off < len) { 521 1.20 skrll char *nns; 522 1.20 skrll 523 1.20 skrll newstringsize += (size_t)(remaining) * len; 524 1.20 skrll nns = realloc(newstrings, newstringsize); 525 1.20 skrll if (nns == NULL) 526 1.20 skrll err(EXIT_FAILURE, "No memory for new string table!"); 527 1.20 skrll newstrings = nns; 528 1.20 skrll nsp = newstrings + off; 529 1.20 skrll } 530 1.5 lukem /* Copy the symbol into the new table, but prepend an 531 1.5 lukem * underscore. */ 532 1.5 lukem *nsp = '_'; 533 1.5 lukem strcpy(nsp + 1, oldstrings + inbuf[i].st_name); 534 1.5 lukem outbuf[i].n_un.n_strx = nsp - newstrings + 4; 535 1.20 skrll nsp += len; 536 1.5 lukem 537 1.7 drochner type = ELF32_ST_TYPE(inbuf[i].st_info); 538 1.7 drochner binding = ELF32_ST_BIND(inbuf[i].st_info); 539 1.5 lukem 540 1.5 lukem /* Convert ELF symbol type/section/etc info into a.out 541 1.5 lukem * type info. */ 542 1.7 drochner if (type == STT_FILE) 543 1.5 lukem outbuf[i].n_type = N_FN; 544 1.5 lukem else 545 1.22 christos outbuf[i].n_type = get_type(inbuf[i].st_shndx); 546 1.7 drochner if (binding == STB_GLOBAL) 547 1.5 lukem outbuf[i].n_type |= N_EXT; 548 1.5 lukem /* Symbol values in executables should be compatible. */ 549 1.5 lukem outbuf[i].n_value = inbuf[i].st_value; 550 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 551 1.15 tsutsui outbuf[i].n_un.n_strx = bswap32(outbuf[i].n_un.n_strx); 552 1.15 tsutsui outbuf[i].n_desc = bswap16(outbuf[i].n_desc); 553 1.15 tsutsui outbuf[i].n_value = bswap32(outbuf[i].n_value); 554 1.15 tsutsui #endif 555 1.5 lukem } 556 1.5 lukem /* Write out the symbols... */ 557 1.17 christos if ((i = write(out, outbuf, (size_t)cur * sizeof(struct nlist))) 558 1.17 christos != cur * (ssize_t)sizeof(struct nlist)) 559 1.17 christos err(EXIT_FAILURE, "%s: write failed", __func__); 560 1.5 lukem } 561 1.5 lukem /* Write out the string table length... */ 562 1.21 skrll stringsizebuf = (uint32_t)newstringsize; 563 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 564 1.15 tsutsui stringsizebuf = bswap32(stringsizebuf); 565 1.15 tsutsui #endif 566 1.15 tsutsui if (write(out, &stringsizebuf, sizeof stringsizebuf) 567 1.17 christos != sizeof stringsizebuf) 568 1.17 christos err(EXIT_FAILURE, "%s: newstringsize: write failed", __func__); 569 1.5 lukem /* Write out the string table... */ 570 1.17 christos if (write(out, newstrings, newstringsize) != (ssize_t)newstringsize) 571 1.17 christos err(EXIT_FAILURE, "%s: newstrings: write failed", __func__); 572 1.17 christos free(newstrings); 573 1.16 martin free(oldstrings); 574 1.1 jonathan } 575 1.5 lukem 576 1.22 christos static void 577 1.13 tsutsui copy(int out, int in, off_t offset, off_t size) 578 1.1 jonathan { 579 1.5 lukem char ibuf[4096]; 580 1.17 christos ssize_t remaining, cur, count; 581 1.1 jonathan 582 1.20 skrll /* Go to the start of the segment... */ 583 1.17 christos if (lseek(in, offset, SEEK_SET) < 0) 584 1.17 christos err(EXIT_FAILURE, "%s: lseek failed", __func__); 585 1.18 martin if (size > SSIZE_MAX) 586 1.18 martin err(EXIT_FAILURE, "%s: can not copy this much", __func__); 587 1.18 martin remaining = (ssize_t)size; 588 1.5 lukem while (remaining) { 589 1.5 lukem cur = remaining; 590 1.15 tsutsui if (cur > (int)sizeof ibuf) 591 1.5 lukem cur = sizeof ibuf; 592 1.5 lukem remaining -= cur; 593 1.17 christos if ((count = read(in, ibuf, (size_t)cur)) != cur) { 594 1.17 christos if (count < 0) 595 1.17 christos err(EXIT_FAILURE, "%s: read error", __func__); 596 1.17 christos else 597 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file", 598 1.17 christos __func__); 599 1.5 lukem } 600 1.17 christos if ((count = write(out, ibuf, (size_t)cur)) != cur) 601 1.17 christos err(EXIT_FAILURE, "%s: write failed", __func__); 602 1.1 jonathan } 603 1.1 jonathan } 604 1.22 christos 605 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's 606 1.1 jonathan okay for there to be padding between. */ 607 1.22 christos static void 608 1.13 tsutsui combine(struct sect *base, struct sect *new, int pad) 609 1.1 jonathan { 610 1.13 tsutsui 611 1.13 tsutsui if (base->len == 0) 612 1.5 lukem *base = *new; 613 1.5 lukem else 614 1.5 lukem if (new->len) { 615 1.5 lukem if (base->vaddr + base->len != new->vaddr) { 616 1.5 lukem if (pad) 617 1.5 lukem base->len = new->vaddr - base->vaddr; 618 1.17 christos else 619 1.17 christos errx(EXIT_FAILURE, "Non-contiguous " 620 1.17 christos "data can't be converted"); 621 1.5 lukem } 622 1.5 lukem base->len += new->len; 623 1.5 lukem } 624 1.1 jonathan } 625 1.1 jonathan 626 1.22 christos static int 627 1.13 tsutsui phcmp(const void *vh1, const void *vh2) 628 1.1 jonathan { 629 1.12 dogcow const Elf32_Phdr *h1, *h2; 630 1.13 tsutsui 631 1.13 tsutsui h1 = (const Elf32_Phdr *)vh1; 632 1.13 tsutsui h2 = (const Elf32_Phdr *)vh2; 633 1.5 lukem 634 1.5 lukem if (h1->p_vaddr > h2->p_vaddr) 635 1.5 lukem return 1; 636 1.5 lukem else 637 1.5 lukem if (h1->p_vaddr < h2->p_vaddr) 638 1.5 lukem return -1; 639 1.5 lukem else 640 1.5 lukem return 0; 641 1.1 jonathan } 642 1.1 jonathan 643 1.22 christos static void * 644 1.17 christos saveRead(int file, off_t offset, size_t len, const char *name) 645 1.1 jonathan { 646 1.5 lukem char *tmp; 647 1.17 christos ssize_t count; 648 1.5 lukem off_t off; 649 1.17 christos 650 1.17 christos if ((off = lseek(file, offset, SEEK_SET)) < 0) 651 1.17 christos errx(EXIT_FAILURE, "%s: seek failed", name); 652 1.13 tsutsui if ((tmp = malloc(len)) == NULL) 653 1.17 christos errx(EXIT_FAILURE, 654 1.17 christos "%s: Can't allocate %jd bytes.", name, (intmax_t)len); 655 1.5 lukem count = read(file, tmp, len); 656 1.17 christos if ((size_t)count != len) { 657 1.17 christos if (count < 0) 658 1.17 christos err(EXIT_FAILURE, "%s: read error", name); 659 1.17 christos else 660 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file", 661 1.17 christos name); 662 1.5 lukem } 663 1.5 lukem return tmp; 664 1.1 jonathan } 665 1.15 tsutsui 666 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 667 1.15 tsutsui /* swap a 32bit region */ 668 1.22 christos static void 669 1.15 tsutsui bswap32_region(int32_t* p, int len) 670 1.15 tsutsui { 671 1.15 tsutsui size_t i; 672 1.15 tsutsui 673 1.15 tsutsui for (i = 0; i < len / sizeof(int32_t); i++, p++) 674 1.15 tsutsui *p = bswap32(*p); 675 1.15 tsutsui } 676 1.15 tsutsui #endif 677