1*112e865aSgutteridge /* $NetBSD: elf2aout.c,v 1.25 2024/11/01 00:35:53 gutteridge Exp $ */ 2559daf50Sjonathan 355e1f3d7Sjonathan /* 455e1f3d7Sjonathan * Copyright (c) 1995 555e1f3d7Sjonathan * Ted Lemon (hereinafter referred to as the author) 655e1f3d7Sjonathan * 755e1f3d7Sjonathan * Redistribution and use in source and binary forms, with or without 855e1f3d7Sjonathan * modification, are permitted provided that the following conditions 955e1f3d7Sjonathan * are met: 1055e1f3d7Sjonathan * 1. Redistributions of source code must retain the above copyright 1155e1f3d7Sjonathan * notice, this list of conditions and the following disclaimer. 1255e1f3d7Sjonathan * 2. Redistributions in binary form must reproduce the above copyright 1355e1f3d7Sjonathan * notice, this list of conditions and the following disclaimer in the 1455e1f3d7Sjonathan * documentation and/or other materials provided with the distribution. 1555e1f3d7Sjonathan * 3. The name of the author may not be used to endorse or promote products 1655e1f3d7Sjonathan * derived from this software without specific prior written permission. 1755e1f3d7Sjonathan * 1855e1f3d7Sjonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 1955e1f3d7Sjonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2055e1f3d7Sjonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2155e1f3d7Sjonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 2255e1f3d7Sjonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2355e1f3d7Sjonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2455e1f3d7Sjonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2555e1f3d7Sjonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2655e1f3d7Sjonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2755e1f3d7Sjonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2855e1f3d7Sjonathan * SUCH DAMAGE. 2955e1f3d7Sjonathan */ 3055e1f3d7Sjonathan 3155e1f3d7Sjonathan /* elf2aout.c 3255e1f3d7Sjonathan 3355e1f3d7Sjonathan This program converts an elf executable to a NetBSD a.out executable. 3455e1f3d7Sjonathan The minimal symbol table is copied, but the debugging symbols and 3555e1f3d7Sjonathan other informational sections are not. */ 3655e1f3d7Sjonathan 37b578f761Stsutsui #if HAVE_NBTOOL_CONFIG_H 38b578f761Stsutsui #include "nbtool_config.h" 39b578f761Stsutsui #endif 40b578f761Stsutsui 41b578f761Stsutsui #ifndef TARGET_BYTE_ORDER 42b578f761Stsutsui #define TARGET_BYTE_ORDER BYTE_ORDER 43b578f761Stsutsui #endif 44b578f761Stsutsui 4555e1f3d7Sjonathan #include <sys/types.h> 46*112e865aSgutteridge #include <sys/endian.h> 4758e8bd3bSjonathan #include <sys/exec_aout.h> 48ae88474dSlukem #include <sys/exec_elf.h> 49ae88474dSlukem 5055e1f3d7Sjonathan #include <a.out.h> 51ae88474dSlukem #include <err.h> 52ae88474dSlukem #include <errno.h> 53ae88474dSlukem #include <fcntl.h> 5455e1f3d7Sjonathan #include <limits.h> 55ae88474dSlukem #include <stdio.h> 56ae88474dSlukem #include <stdlib.h> 57ae88474dSlukem #include <string.h> 58ae88474dSlukem #include <unistd.h> 5955e1f3d7Sjonathan 6058e8bd3bSjonathan 6155e1f3d7Sjonathan struct sect { 62b578f761Stsutsui /* should be unsigned long, but assume no a.out binaries on LP64 */ 63b578f761Stsutsui uint32_t vaddr; 64b578f761Stsutsui uint32_t len; 6555e1f3d7Sjonathan }; 66ae88474dSlukem 6759e8d36eSchristos static void combine(struct sect *, struct sect *, int); 6859e8d36eSchristos static int phcmp(const void *, const void *); 6959e8d36eSchristos static void *saveRead(int file, off_t offset, size_t len, const char *name); 7059e8d36eSchristos static void copy(int, int, off_t, off_t); 7159e8d36eSchristos static void translate_syms(int, int, off_t, off_t, off_t, off_t); 72ae88474dSlukem 73b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 7459e8d36eSchristos static void bswap32_region(int32_t* , int); 75b578f761Stsutsui #endif 76b578f761Stsutsui 7759e8d36eSchristos static int *symTypeTable; 7859e8d36eSchristos static int debug; 7959e8d36eSchristos 8059e8d36eSchristos static __dead void 8159e8d36eSchristos usage(void) 8259e8d36eSchristos { 834c02e230Swiz fprintf(stderr, "Usage: %s [-Os] <elf executable> <a.out executable>\n", 8459e8d36eSchristos getprogname()); 8559e8d36eSchristos exit(EXIT_FAILURE); 8659e8d36eSchristos } 8759e8d36eSchristos 8859e8d36eSchristos static const struct { 8959e8d36eSchristos const char *n; 9059e8d36eSchristos int v; 9159e8d36eSchristos } nv[] = { 9259e8d36eSchristos { ".text", N_TEXT }, 9359e8d36eSchristos { ".rodata", N_TEXT }, 9459e8d36eSchristos { ".data", N_DATA }, 9559e8d36eSchristos { ".sdata", N_DATA }, 9659e8d36eSchristos { ".lit4", N_DATA }, 9759e8d36eSchristos { ".lit8", N_DATA }, 9859e8d36eSchristos { ".bss", N_BSS }, 9959e8d36eSchristos { ".sbss", N_BSS }, 10059e8d36eSchristos }; 10159e8d36eSchristos 10259e8d36eSchristos static int 10359e8d36eSchristos get_symtab_type(const char *name) 10459e8d36eSchristos { 10559e8d36eSchristos size_t i; 10659e8d36eSchristos for (i = 0; i < __arraycount(nv); i++) { 10759e8d36eSchristos if (strcmp(name, nv[i].n) == 0) 10859e8d36eSchristos return nv[i].v; 10959e8d36eSchristos } 11059e8d36eSchristos if (debug) 11159e8d36eSchristos warnx("section `%s' is not handled\n", name); 11259e8d36eSchristos return 0; 11359e8d36eSchristos } 11459e8d36eSchristos 11559e8d36eSchristos static uint32_t 11659e8d36eSchristos get_mid(const Elf32_Ehdr *ex) 11759e8d36eSchristos { 11859e8d36eSchristos switch (ex->e_machine) { 11959e8d36eSchristos #ifdef notyet 12059e8d36eSchristos case EM_AARCH64: 12159e8d36eSchristos return MID_AARCH64; 12259e8d36eSchristos case EM_ALPHA: 12359e8d36eSchristos return MID_ALPHA; 12459e8d36eSchristos #endif 12559e8d36eSchristos case EM_ARM: 12659e8d36eSchristos return MID_ARM6; 12759e8d36eSchristos #ifdef notyet 12859e8d36eSchristos case EM_PARISC: 12959e8d36eSchristos return MID_HPPA; 13059e8d36eSchristos #endif 13159e8d36eSchristos case EM_386: 13259e8d36eSchristos return MID_I386; 13359e8d36eSchristos case EM_68K: 13459e8d36eSchristos return MID_M68K; 13559e8d36eSchristos case EM_OR1K: 13659e8d36eSchristos return MID_OR1K; 13759e8d36eSchristos case EM_MIPS: 13859e8d36eSchristos if (ex->e_ident[EI_DATA] == ELFDATA2LSB) 13959e8d36eSchristos return MID_PMAX; 14059e8d36eSchristos else 14159e8d36eSchristos return MID_MIPS; 14259e8d36eSchristos case EM_PPC: 14359e8d36eSchristos return MID_POWERPC; 14459e8d36eSchristos #ifdef notyet 14559e8d36eSchristos case EM_PPC64: 14659e8d36eSchristos return MID_POWERPC64; 14759e8d36eSchristos break; 14859e8d36eSchristos #endif 14959e8d36eSchristos case EM_RISCV: 15059e8d36eSchristos return MID_RISCV; 15159e8d36eSchristos case EM_SH: 15259e8d36eSchristos return MID_SH3; 15359e8d36eSchristos case EM_SPARC: 15459e8d36eSchristos case EM_SPARC32PLUS: 15559e8d36eSchristos case EM_SPARCV9: 15659e8d36eSchristos if (ex->e_ident[EI_CLASS] == ELFCLASS32) 15759e8d36eSchristos return MID_SPARC; 15859e8d36eSchristos #ifdef notyet 15959e8d36eSchristos return MID_SPARC64; 16059e8d36eSchristos case EM_X86_64: 16159e8d36eSchristos return MID_X86_64; 16259e8d36eSchristos #else 16359e8d36eSchristos break; 16459e8d36eSchristos #endif 16559e8d36eSchristos case EM_VAX: 16659e8d36eSchristos return MID_VAX; 16759e8d36eSchristos case EM_NONE: 16859e8d36eSchristos return MID_ZERO; 16959e8d36eSchristos default: 17059e8d36eSchristos break; 17159e8d36eSchristos } 17259e8d36eSchristos if (debug) 17359e8d36eSchristos warnx("Unsupported machine `%d'", ex->e_machine); 17459e8d36eSchristos return MID_ZERO; 17559e8d36eSchristos } 17659e8d36eSchristos 17759e8d36eSchristos static unsigned char 17859e8d36eSchristos get_type(Elf32_Half shndx) 17959e8d36eSchristos { 18059e8d36eSchristos switch (shndx) { 18159e8d36eSchristos case SHN_UNDEF: 18259e8d36eSchristos return N_UNDF; 18359e8d36eSchristos case SHN_ABS: 18459e8d36eSchristos return N_ABS; 18559e8d36eSchristos case SHN_COMMON: 18659e8d36eSchristos case SHN_MIPS_ACOMMON: 18759e8d36eSchristos return N_COMM; 18859e8d36eSchristos default: 18959e8d36eSchristos return (unsigned char)symTypeTable[shndx]; 19059e8d36eSchristos } 19159e8d36eSchristos } 19255e1f3d7Sjonathan 193ae88474dSlukem int 194ae88474dSlukem main(int argc, char **argv) 19555e1f3d7Sjonathan { 19658e8bd3bSjonathan Elf32_Ehdr ex; 19758e8bd3bSjonathan Elf32_Phdr *ph; 19858e8bd3bSjonathan Elf32_Shdr *sh; 19955e1f3d7Sjonathan char *shstrtab; 200fd89278aSchristos ssize_t i, strtabix, symtabix; 20155e1f3d7Sjonathan struct sect text, data, bss; 20255e1f3d7Sjonathan struct exec aex; 20355e1f3d7Sjonathan int infile, outfile; 204b578f761Stsutsui uint32_t cur_vma = UINT32_MAX; 205b578f761Stsutsui uint32_t mid; 20659e8d36eSchristos int symflag = 0, c; 20759e8d36eSchristos unsigned long magic = ZMAGIC; 20855e1f3d7Sjonathan 209ae88474dSlukem strtabix = symtabix = 0; 21055e1f3d7Sjonathan text.len = data.len = bss.len = 0; 21155e1f3d7Sjonathan text.vaddr = data.vaddr = bss.vaddr = 0; 21255e1f3d7Sjonathan 21359e8d36eSchristos while ((c = getopt(argc, argv, "dOs")) != -1) { 21459e8d36eSchristos switch (c) { 21559e8d36eSchristos case 'd': 21659e8d36eSchristos debug++; 21759e8d36eSchristos break; 21859e8d36eSchristos case 's': 21955e1f3d7Sjonathan symflag = 1; 22059e8d36eSchristos break; 22159e8d36eSchristos case 'O': 22259e8d36eSchristos magic = OMAGIC; 22359e8d36eSchristos break; 22459e8d36eSchristos case '?': 22559e8d36eSchristos default: 22659e8d36eSchristos usage: 22759e8d36eSchristos usage(); 22855e1f3d7Sjonathan } 22959e8d36eSchristos } 23059e8d36eSchristos 23159e8d36eSchristos argc -= optind; 23259e8d36eSchristos argv += optind; 23359e8d36eSchristos 23459e8d36eSchristos /* Check args... */ 23559e8d36eSchristos if (argc != 2) 23659e8d36eSchristos goto usage; 23759e8d36eSchristos 23859e8d36eSchristos 23955e1f3d7Sjonathan /* Try the input file... */ 24059e8d36eSchristos if ((infile = open(argv[0], O_RDONLY)) < 0) 24159e8d36eSchristos err(EXIT_FAILURE, "Can't open `%s' for read", argv[0]); 242fd89278aSchristos 24355e1f3d7Sjonathan /* Read the header, which is at the beginning of the file... */ 24455e1f3d7Sjonathan i = read(infile, &ex, sizeof ex); 245ae88474dSlukem if (i != sizeof ex) { 246fd89278aSchristos if (i == -1) 247fd89278aSchristos err(EXIT_FAILURE, "Error reading `%s'", argv[1]); 248fd89278aSchristos else 249fd89278aSchristos errx(EXIT_FAILURE, "End of file reading `%s'", argv[1]); 25055e1f3d7Sjonathan } 251b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 252b578f761Stsutsui ex.e_type = bswap16(ex.e_type); 253b578f761Stsutsui ex.e_machine = bswap16(ex.e_machine); 254b578f761Stsutsui ex.e_version = bswap32(ex.e_version); 255b578f761Stsutsui ex.e_entry = bswap32(ex.e_entry); 256b578f761Stsutsui ex.e_phoff = bswap32(ex.e_phoff); 257b578f761Stsutsui ex.e_shoff = bswap32(ex.e_shoff); 258b578f761Stsutsui ex.e_flags = bswap32(ex.e_flags); 259b578f761Stsutsui ex.e_ehsize = bswap16(ex.e_ehsize); 260b578f761Stsutsui ex.e_phentsize = bswap16(ex.e_phentsize); 261b578f761Stsutsui ex.e_phnum = bswap16(ex.e_phnum); 262b578f761Stsutsui ex.e_shentsize = bswap16(ex.e_shentsize); 263b578f761Stsutsui ex.e_shnum = bswap16(ex.e_shnum); 264b578f761Stsutsui ex.e_shstrndx = bswap16(ex.e_shstrndx); 265b578f761Stsutsui #endif 26659e8d36eSchristos // Not yet 26759e8d36eSchristos if (ex.e_ident[EI_CLASS] == ELFCLASS64) 26859e8d36eSchristos errx(EXIT_FAILURE, "Only 32 bit is supported"); 26959e8d36eSchristos 27055e1f3d7Sjonathan /* Read the program headers... */ 271fd89278aSchristos ph = saveRead(infile, ex.e_phoff, 272fd89278aSchristos (size_t)ex.e_phnum * sizeof(Elf32_Phdr), "ph"); 273b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 274b578f761Stsutsui bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum); 275b578f761Stsutsui #endif 27655e1f3d7Sjonathan /* Read the section headers... */ 277fd89278aSchristos sh = saveRead(infile, ex.e_shoff, 278fd89278aSchristos (size_t)ex.e_shnum * sizeof(Elf32_Shdr), "sh"); 279b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 280b578f761Stsutsui bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum); 281b578f761Stsutsui #endif 28255e1f3d7Sjonathan /* Read in the section string table. */ 28358e8bd3bSjonathan shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset, 284fd89278aSchristos (size_t)sh[ex.e_shstrndx].sh_size, "shstrtab"); 28555e1f3d7Sjonathan 28655e1f3d7Sjonathan /* Find space for a table matching ELF section indices to a.out symbol 287ae88474dSlukem * types. */ 28841319be2Stsutsui symTypeTable = malloc(ex.e_shnum * sizeof(int)); 289fd89278aSchristos if (symTypeTable == NULL) 290fd89278aSchristos err(EXIT_FAILURE, "symTypeTable: can't allocate"); 29158e8bd3bSjonathan memset(symTypeTable, 0, ex.e_shnum * sizeof(int)); 29255e1f3d7Sjonathan 293ae88474dSlukem /* Look for the symbol table and string table... Also map section 294ae88474dSlukem * indices to symbol types for a.out */ 295ae88474dSlukem for (i = 0; i < ex.e_shnum; i++) { 29658e8bd3bSjonathan char *name = shstrtab + sh[i].sh_name; 29755e1f3d7Sjonathan if (!strcmp(name, ".symtab")) 29855e1f3d7Sjonathan symtabix = i; 29959e8d36eSchristos else if (!strcmp(name, ".strtab")) 30055e1f3d7Sjonathan strtabix = i; 301ae88474dSlukem else 30259e8d36eSchristos symTypeTable[i] = get_symtab_type(name); 30355e1f3d7Sjonathan } 30455e1f3d7Sjonathan 305ae88474dSlukem /* Figure out if we can cram the program header into an a.out 306ae88474dSlukem * header... Basically, we can't handle anything but loadable 307ae88474dSlukem * segments, but we can ignore some kinds of segments. We can't 308ae88474dSlukem * handle holes in the address space, and we handle start addresses 309ae88474dSlukem * other than 0x1000 by hoping that the loader will know where to load 310ae88474dSlukem * - a.out doesn't have an explicit load address. Segments may be 311ae88474dSlukem * out of order, so we sort them first. */ 31258e8bd3bSjonathan qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp); 313ae88474dSlukem for (i = 0; i < ex.e_phnum; i++) { 31455e1f3d7Sjonathan /* Section types we can ignore... */ 3151899563cSdrochner if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE || 3161899563cSdrochner ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO) 31755e1f3d7Sjonathan continue; 31855e1f3d7Sjonathan /* Section types we can't handle... */ 31959e8d36eSchristos if (ph[i].p_type == PT_TLS) { 32059e8d36eSchristos if (debug) 32159e8d36eSchristos warnx("Can't handle TLS section"); 32259e8d36eSchristos continue; 32359e8d36eSchristos } 3241899563cSdrochner if (ph[i].p_type != PT_LOAD) 325fd89278aSchristos errx(EXIT_FAILURE, "Program header %zd " 32659e8d36eSchristos "type %d can't be converted.", i, ph[i].p_type); 32755e1f3d7Sjonathan /* Writable (data) segment? */ 328ae88474dSlukem if (ph[i].p_flags & PF_W) { 32955e1f3d7Sjonathan struct sect ndata, nbss; 33055e1f3d7Sjonathan 33158e8bd3bSjonathan ndata.vaddr = ph[i].p_vaddr; 33258e8bd3bSjonathan ndata.len = ph[i].p_filesz; 33358e8bd3bSjonathan nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; 33458e8bd3bSjonathan nbss.len = ph[i].p_memsz - ph[i].p_filesz; 33555e1f3d7Sjonathan 33655e1f3d7Sjonathan combine(&data, &ndata, 0); 33755e1f3d7Sjonathan combine(&bss, &nbss, 1); 338ae88474dSlukem } else { 33955e1f3d7Sjonathan struct sect ntxt; 34055e1f3d7Sjonathan 34158e8bd3bSjonathan ntxt.vaddr = ph[i].p_vaddr; 34258e8bd3bSjonathan ntxt.len = ph[i].p_filesz; 34355e1f3d7Sjonathan 344ae88474dSlukem combine(&text, &ntxt, 0); 34555e1f3d7Sjonathan } 34655e1f3d7Sjonathan /* Remember the lowest segment start address. */ 34758e8bd3bSjonathan if (ph[i].p_vaddr < cur_vma) 34858e8bd3bSjonathan cur_vma = ph[i].p_vaddr; 34955e1f3d7Sjonathan } 35055e1f3d7Sjonathan 35155e1f3d7Sjonathan /* Sections must be in order to be converted... */ 35255e1f3d7Sjonathan if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 353fd89278aSchristos text.vaddr + text.len > data.vaddr || 354fd89278aSchristos data.vaddr + data.len > bss.vaddr) 355fd89278aSchristos errx(EXIT_FAILURE, "Sections ordering prevents a.out " 356fd89278aSchristos "conversion."); 35755e1f3d7Sjonathan /* If there's a data section but no text section, then the loader 358ae88474dSlukem * combined everything into one section. That needs to be the text 359ae88474dSlukem * section, so just make the data section zero length following text. */ 36041319be2Stsutsui if (data.len && text.len == 0) { 36155e1f3d7Sjonathan text = data; 36255e1f3d7Sjonathan data.vaddr = text.vaddr + text.len; 36355e1f3d7Sjonathan data.len = 0; 36455e1f3d7Sjonathan } 36555e1f3d7Sjonathan /* If there is a gap between text and data, we'll fill it when we copy 366ae88474dSlukem * the data, so update the length of the text segment as represented 367ae88474dSlukem * in a.out to reflect that, since a.out doesn't allow gaps in the 368ae88474dSlukem * program address space. */ 36955e1f3d7Sjonathan if (text.vaddr + text.len < data.vaddr) 37055e1f3d7Sjonathan text.len = data.vaddr - text.vaddr; 37155e1f3d7Sjonathan 37255e1f3d7Sjonathan /* We now have enough information to cons up an a.out header... */ 37359e8d36eSchristos mid = get_mid(&ex); 374*112e865aSgutteridge aex.a_midmag = (u_long)htobe32(((u_long)symflag << 26) 37559e8d36eSchristos | ((u_long)mid << 16) | magic); 376ee9bf4dcSis 37755e1f3d7Sjonathan aex.a_text = text.len; 37855e1f3d7Sjonathan aex.a_data = data.len; 37955e1f3d7Sjonathan aex.a_bss = bss.len; 38058e8bd3bSjonathan aex.a_entry = ex.e_entry; 38155e1f3d7Sjonathan aex.a_syms = (sizeof(struct nlist) * 38259e8d36eSchristos (symtabix != -1 ? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0)); 38355e1f3d7Sjonathan aex.a_trsize = 0; 38455e1f3d7Sjonathan aex.a_drsize = 0; 385b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 386b578f761Stsutsui aex.a_text = bswap32(aex.a_text); 387b578f761Stsutsui aex.a_data = bswap32(aex.a_data); 388b578f761Stsutsui aex.a_bss = bswap32(aex.a_bss); 389b578f761Stsutsui aex.a_entry = bswap32(aex.a_entry); 390b578f761Stsutsui aex.a_syms = bswap32(aex.a_syms); 391b578f761Stsutsui aex.a_trsize = bswap32(aex.a_trsize); 392b578f761Stsutsui aex.a_drsize = bswap32(aex.a_drsize); 393b578f761Stsutsui #endif 39455e1f3d7Sjonathan 39555e1f3d7Sjonathan /* Make the output file... */ 39659e8d36eSchristos if ((outfile = open(argv[1], O_WRONLY | O_CREAT, 0777)) < 0) 39759e8d36eSchristos err(EXIT_FAILURE, "Unable to create `%s'", argv[1]); 398552d6a2aSsimonb /* Truncate file... */ 399552d6a2aSsimonb if (ftruncate(outfile, 0)) { 40059e8d36eSchristos warn("ftruncate %s", argv[1]); 401552d6a2aSsimonb } 40255e1f3d7Sjonathan /* Write the header... */ 40355e1f3d7Sjonathan i = write(outfile, &aex, sizeof aex); 404fd89278aSchristos if (i != sizeof aex) 40559e8d36eSchristos err(EXIT_FAILURE, "Can't write `%s'", argv[1]); 40655e1f3d7Sjonathan /* Copy the loadable sections. Zero-fill any gaps less than 64k; 407ae88474dSlukem * complain about any zero-filling, and die if we're asked to 408ae88474dSlukem * zero-fill more than 64k. */ 409ae88474dSlukem for (i = 0; i < ex.e_phnum; i++) { 410ae88474dSlukem /* Unprocessable sections were handled above, so just verify 411ae88474dSlukem * that the section can be loaded before copying. */ 4121899563cSdrochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { 413ae88474dSlukem if (cur_vma != ph[i].p_vaddr) { 414b578f761Stsutsui uint32_t gap = ph[i].p_vaddr - cur_vma; 41555e1f3d7Sjonathan char obuf[1024]; 41655e1f3d7Sjonathan if (gap > 65536) 417fd89278aSchristos errx(EXIT_FAILURE, 418fd89278aSchristos "Intersegment gap (%u bytes) too large", gap); 41959e8d36eSchristos if (debug) 420fd89278aSchristos warnx("%u byte intersegment gap", gap); 42155e1f3d7Sjonathan memset(obuf, 0, sizeof obuf); 422ae88474dSlukem while (gap) { 423fd89278aSchristos ssize_t count = write(outfile, obuf, 424fd89278aSchristos (gap > sizeof obuf 42555e1f3d7Sjonathan ? sizeof obuf : gap)); 426fd89278aSchristos if (count < 0) 427fd89278aSchristos err(EXIT_FAILURE, 428fd89278aSchristos "Error writing gap"); 429fd89278aSchristos gap -= (uint32_t)count; 43055e1f3d7Sjonathan } 43155e1f3d7Sjonathan } 43258e8bd3bSjonathan copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz); 43358e8bd3bSjonathan cur_vma = ph[i].p_vaddr + ph[i].p_filesz; 43455e1f3d7Sjonathan } 43555e1f3d7Sjonathan } 43655e1f3d7Sjonathan 43755e1f3d7Sjonathan /* Copy and translate the symbol table... */ 43858e8bd3bSjonathan translate_syms(outfile, infile, 43958e8bd3bSjonathan sh[symtabix].sh_offset, sh[symtabix].sh_size, 44058e8bd3bSjonathan sh[strtabix].sh_offset, sh[strtabix].sh_size); 44155e1f3d7Sjonathan 442fd89278aSchristos free(ph); 443fd89278aSchristos free(sh); 444fd89278aSchristos free(shstrtab); 445fd89278aSchristos free(symTypeTable); 44655e1f3d7Sjonathan /* Looks like we won... */ 447fd89278aSchristos return EXIT_SUCCESS; 44855e1f3d7Sjonathan } 44955e1f3d7Sjonathan /* translate_syms (out, in, offset, size) 45055e1f3d7Sjonathan 45155e1f3d7Sjonathan Read the ELF symbol table from in at offset; translate it into a.out 45255e1f3d7Sjonathan nlist format and write it to out. */ 45355e1f3d7Sjonathan 454ae88474dSlukem void 45541319be2Stsutsui translate_syms(int out, int in, off_t symoff, off_t symsize, 45641319be2Stsutsui off_t stroff, off_t strsize) 45755e1f3d7Sjonathan { 45855e1f3d7Sjonathan #define SYMS_PER_PASS 64 45958e8bd3bSjonathan Elf32_Sym inbuf[64]; 46055e1f3d7Sjonathan struct nlist outbuf[64]; 461fd89278aSchristos ssize_t i, remaining, cur; 46255e1f3d7Sjonathan char *oldstrings; 46355e1f3d7Sjonathan char *newstrings, *nsp; 4646e604a19Sskrll size_t newstringsize; 4656e604a19Sskrll uint32_t stringsizebuf; 46655e1f3d7Sjonathan 46755e1f3d7Sjonathan /* Zero the unused fields in the output buffer.. */ 46855e1f3d7Sjonathan memset(outbuf, 0, sizeof outbuf); 46955e1f3d7Sjonathan 47055e1f3d7Sjonathan /* Find number of symbols to process... */ 471212399f8Smartin remaining = (ssize_t)(symsize / (off_t)sizeof(Elf32_Sym)); 47255e1f3d7Sjonathan 47355e1f3d7Sjonathan /* Suck in the old string table... */ 474fd89278aSchristos oldstrings = saveRead(in, stroff, (size_t)strsize, "string table"); 47555e1f3d7Sjonathan 4766e604a19Sskrll /* 4776e604a19Sskrll * Allocate space for the new one. We will increase the space if 4786e604a19Sskrll * this is too small 4796e604a19Sskrll */ 480fd89278aSchristos newstringsize = (size_t)(strsize + remaining); 48141319be2Stsutsui newstrings = malloc(newstringsize); 482fd89278aSchristos if (newstrings == NULL) 483fd89278aSchristos err(EXIT_FAILURE, "No memory for new string table!"); 48455e1f3d7Sjonathan /* Initialize the table pointer... */ 48555e1f3d7Sjonathan nsp = newstrings; 48655e1f3d7Sjonathan 48789c5a767Ssoren /* Go the start of the ELF symbol table... */ 488fd89278aSchristos if (lseek(in, symoff, SEEK_SET) < 0) 489fd89278aSchristos err(EXIT_FAILURE, "Can't seek"); 49055e1f3d7Sjonathan /* Translate and copy symbols... */ 4916e604a19Sskrll for (; remaining; remaining -= cur) { 49255e1f3d7Sjonathan cur = remaining; 49355e1f3d7Sjonathan if (cur > SYMS_PER_PASS) 49455e1f3d7Sjonathan cur = SYMS_PER_PASS; 495fd89278aSchristos if ((i = read(in, inbuf, (size_t)cur * sizeof(Elf32_Sym))) 496b578f761Stsutsui != cur * (ssize_t)sizeof(Elf32_Sym)) { 49755e1f3d7Sjonathan if (i < 0) 498fd89278aSchristos err(EXIT_FAILURE, "%s: read error", __func__); 49955e1f3d7Sjonathan else 500fd89278aSchristos errx(EXIT_FAILURE, "%s: premature end of file", 501fd89278aSchristos __func__); 50255e1f3d7Sjonathan } 50355e1f3d7Sjonathan /* Do the translation... */ 504ae88474dSlukem for (i = 0; i < cur; i++) { 50558e8bd3bSjonathan int binding, type; 5066e604a19Sskrll size_t off, len; 50758e8bd3bSjonathan 508b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 509b578f761Stsutsui inbuf[i].st_name = bswap32(inbuf[i].st_name); 510b578f761Stsutsui inbuf[i].st_value = bswap32(inbuf[i].st_value); 511b578f761Stsutsui inbuf[i].st_size = bswap32(inbuf[i].st_size); 512b578f761Stsutsui inbuf[i].st_shndx = bswap16(inbuf[i].st_shndx); 513b578f761Stsutsui #endif 5146e604a19Sskrll off = (size_t)(nsp - newstrings); 5156e604a19Sskrll 5166e604a19Sskrll /* length of this symbol with leading '_' and trailing '\0' */ 5176e604a19Sskrll len = strlen(oldstrings + inbuf[i].st_name) + 1 + 1; 5186e604a19Sskrll 5196e604a19Sskrll /* Does it fit? If not make more space */ 5206e604a19Sskrll if (newstringsize - off < len) { 5216e604a19Sskrll char *nns; 5226e604a19Sskrll 5236e604a19Sskrll newstringsize += (size_t)(remaining) * len; 5246e604a19Sskrll nns = realloc(newstrings, newstringsize); 5256e604a19Sskrll if (nns == NULL) 5266e604a19Sskrll err(EXIT_FAILURE, "No memory for new string table!"); 5276e604a19Sskrll newstrings = nns; 5286e604a19Sskrll nsp = newstrings + off; 5296e604a19Sskrll } 530ae88474dSlukem /* Copy the symbol into the new table, but prepend an 531ae88474dSlukem * underscore. */ 53255e1f3d7Sjonathan *nsp = '_'; 53358e8bd3bSjonathan strcpy(nsp + 1, oldstrings + inbuf[i].st_name); 53455e1f3d7Sjonathan outbuf[i].n_un.n_strx = nsp - newstrings + 4; 5356e604a19Sskrll nsp += len; 53655e1f3d7Sjonathan 5371899563cSdrochner type = ELF32_ST_TYPE(inbuf[i].st_info); 5381899563cSdrochner binding = ELF32_ST_BIND(inbuf[i].st_info); 53958e8bd3bSjonathan 540ae88474dSlukem /* Convert ELF symbol type/section/etc info into a.out 541ae88474dSlukem * type info. */ 5421899563cSdrochner if (type == STT_FILE) 54355e1f3d7Sjonathan outbuf[i].n_type = N_FN; 544ae88474dSlukem else 54559e8d36eSchristos outbuf[i].n_type = get_type(inbuf[i].st_shndx); 5461899563cSdrochner if (binding == STB_GLOBAL) 54755e1f3d7Sjonathan outbuf[i].n_type |= N_EXT; 54855e1f3d7Sjonathan /* Symbol values in executables should be compatible. */ 54958e8bd3bSjonathan outbuf[i].n_value = inbuf[i].st_value; 550b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 551b578f761Stsutsui outbuf[i].n_un.n_strx = bswap32(outbuf[i].n_un.n_strx); 552b578f761Stsutsui outbuf[i].n_desc = bswap16(outbuf[i].n_desc); 553b578f761Stsutsui outbuf[i].n_value = bswap32(outbuf[i].n_value); 554b578f761Stsutsui #endif 55555e1f3d7Sjonathan } 55655e1f3d7Sjonathan /* Write out the symbols... */ 557fd89278aSchristos if ((i = write(out, outbuf, (size_t)cur * sizeof(struct nlist))) 558fd89278aSchristos != cur * (ssize_t)sizeof(struct nlist)) 559fd89278aSchristos err(EXIT_FAILURE, "%s: write failed", __func__); 56055e1f3d7Sjonathan } 56155e1f3d7Sjonathan /* Write out the string table length... */ 5624402b4d2Sskrll stringsizebuf = (uint32_t)newstringsize; 563b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 564b578f761Stsutsui stringsizebuf = bswap32(stringsizebuf); 565b578f761Stsutsui #endif 566b578f761Stsutsui if (write(out, &stringsizebuf, sizeof stringsizebuf) 567fd89278aSchristos != sizeof stringsizebuf) 568fd89278aSchristos err(EXIT_FAILURE, "%s: newstringsize: write failed", __func__); 56955e1f3d7Sjonathan /* Write out the string table... */ 570fd89278aSchristos if (write(out, newstrings, newstringsize) != (ssize_t)newstringsize) 571fd89278aSchristos err(EXIT_FAILURE, "%s: newstrings: write failed", __func__); 572fd89278aSchristos free(newstrings); 573bf186f94Smartin free(oldstrings); 57455e1f3d7Sjonathan } 57555e1f3d7Sjonathan 57659e8d36eSchristos static void 57741319be2Stsutsui copy(int out, int in, off_t offset, off_t size) 57855e1f3d7Sjonathan { 57955e1f3d7Sjonathan char ibuf[4096]; 580fd89278aSchristos ssize_t remaining, cur, count; 58155e1f3d7Sjonathan 5826e604a19Sskrll /* Go to the start of the segment... */ 583fd89278aSchristos if (lseek(in, offset, SEEK_SET) < 0) 584fd89278aSchristos err(EXIT_FAILURE, "%s: lseek failed", __func__); 585cb0ca8ddSmartin if (size > SSIZE_MAX) 586cb0ca8ddSmartin err(EXIT_FAILURE, "%s: can not copy this much", __func__); 587cb0ca8ddSmartin remaining = (ssize_t)size; 588ae88474dSlukem while (remaining) { 58955e1f3d7Sjonathan cur = remaining; 590b578f761Stsutsui if (cur > (int)sizeof ibuf) 59155e1f3d7Sjonathan cur = sizeof ibuf; 59255e1f3d7Sjonathan remaining -= cur; 593fd89278aSchristos if ((count = read(in, ibuf, (size_t)cur)) != cur) { 594fd89278aSchristos if (count < 0) 595fd89278aSchristos err(EXIT_FAILURE, "%s: read error", __func__); 596fd89278aSchristos else 597fd89278aSchristos errx(EXIT_FAILURE, "%s: premature end of file", 598fd89278aSchristos __func__); 59955e1f3d7Sjonathan } 600fd89278aSchristos if ((count = write(out, ibuf, (size_t)cur)) != cur) 601fd89278aSchristos err(EXIT_FAILURE, "%s: write failed", __func__); 60255e1f3d7Sjonathan } 60355e1f3d7Sjonathan } 60459e8d36eSchristos 60555e1f3d7Sjonathan /* Combine two segments, which must be contiguous. If pad is true, it's 60655e1f3d7Sjonathan okay for there to be padding between. */ 60759e8d36eSchristos static void 60841319be2Stsutsui combine(struct sect *base, struct sect *new, int pad) 60955e1f3d7Sjonathan { 61041319be2Stsutsui 61141319be2Stsutsui if (base->len == 0) 61255e1f3d7Sjonathan *base = *new; 613ae88474dSlukem else 614ae88474dSlukem if (new->len) { 615ae88474dSlukem if (base->vaddr + base->len != new->vaddr) { 61655e1f3d7Sjonathan if (pad) 61755e1f3d7Sjonathan base->len = new->vaddr - base->vaddr; 618fd89278aSchristos else 619fd89278aSchristos errx(EXIT_FAILURE, "Non-contiguous " 620fd89278aSchristos "data can't be converted"); 62155e1f3d7Sjonathan } 62255e1f3d7Sjonathan base->len += new->len; 62355e1f3d7Sjonathan } 62455e1f3d7Sjonathan } 62555e1f3d7Sjonathan 62659e8d36eSchristos static int 62741319be2Stsutsui phcmp(const void *vh1, const void *vh2) 62855e1f3d7Sjonathan { 6297aaa51f5Sdogcow const Elf32_Phdr *h1, *h2; 63041319be2Stsutsui 6317aaa51f5Sdogcow h1 = (const Elf32_Phdr *)vh1; 6327aaa51f5Sdogcow h2 = (const Elf32_Phdr *)vh2; 633ae88474dSlukem 63458e8bd3bSjonathan if (h1->p_vaddr > h2->p_vaddr) 63555e1f3d7Sjonathan return 1; 636ae88474dSlukem else 637ae88474dSlukem if (h1->p_vaddr < h2->p_vaddr) 63855e1f3d7Sjonathan return -1; 63955e1f3d7Sjonathan else 64055e1f3d7Sjonathan return 0; 64155e1f3d7Sjonathan } 64255e1f3d7Sjonathan 64359e8d36eSchristos static void * 644fd89278aSchristos saveRead(int file, off_t offset, size_t len, const char *name) 64555e1f3d7Sjonathan { 64655e1f3d7Sjonathan char *tmp; 647fd89278aSchristos ssize_t count; 64855e1f3d7Sjonathan off_t off; 649fd89278aSchristos 650fd89278aSchristos if ((off = lseek(file, offset, SEEK_SET)) < 0) 651fd89278aSchristos errx(EXIT_FAILURE, "%s: seek failed", name); 65241319be2Stsutsui if ((tmp = malloc(len)) == NULL) 653fd89278aSchristos errx(EXIT_FAILURE, 654fd89278aSchristos "%s: Can't allocate %jd bytes.", name, (intmax_t)len); 65555e1f3d7Sjonathan count = read(file, tmp, len); 656fd89278aSchristos if ((size_t)count != len) { 657fd89278aSchristos if (count < 0) 658fd89278aSchristos err(EXIT_FAILURE, "%s: read error", name); 659fd89278aSchristos else 660fd89278aSchristos errx(EXIT_FAILURE, "%s: premature end of file", 661fd89278aSchristos name); 66255e1f3d7Sjonathan } 66355e1f3d7Sjonathan return tmp; 66455e1f3d7Sjonathan } 665b578f761Stsutsui 666b578f761Stsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER 667b578f761Stsutsui /* swap a 32bit region */ 66859e8d36eSchristos static void 669b578f761Stsutsui bswap32_region(int32_t* p, int len) 670b578f761Stsutsui { 671b578f761Stsutsui size_t i; 672b578f761Stsutsui 673b578f761Stsutsui for (i = 0; i < len / sizeof(int32_t); i++, p++) 674b578f761Stsutsui *p = bswap32(*p); 675b578f761Stsutsui } 676b578f761Stsutsui #endif 677