162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 1995 362306a36Sopenharmony_ci * Ted Lemon (hereinafter referred to as the author) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 762306a36Sopenharmony_ci * are met: 862306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 962306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1062306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1162306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1262306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1362306a36Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 1462306a36Sopenharmony_ci * derived from this software without specific prior written permission. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 1762306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1862306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1962306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 2062306a36Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2162306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2262306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2362306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2462306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2562306a36Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2662306a36Sopenharmony_ci * SUCH DAMAGE. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* elf2ecoff.c 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci This program converts an elf executable to an ECOFF executable. 3262306a36Sopenharmony_ci No symbol table is retained. This is useful primarily in building 3362306a36Sopenharmony_ci net-bootable kernels for machines (e.g., DECstation and Alpha) which 3462306a36Sopenharmony_ci only support the ECOFF object file format. */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <stdio.h> 3762306a36Sopenharmony_ci#include <string.h> 3862306a36Sopenharmony_ci#include <errno.h> 3962306a36Sopenharmony_ci#include <sys/types.h> 4062306a36Sopenharmony_ci#include <fcntl.h> 4162306a36Sopenharmony_ci#include <unistd.h> 4262306a36Sopenharmony_ci#include <elf.h> 4362306a36Sopenharmony_ci#include <limits.h> 4462306a36Sopenharmony_ci#include <netinet/in.h> 4562306a36Sopenharmony_ci#include <stdlib.h> 4662306a36Sopenharmony_ci#include <stdint.h> 4762306a36Sopenharmony_ci#include <inttypes.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "ecoff.h" 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * Some extra ELF definitions 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ 5562306a36Sopenharmony_ci#define PT_MIPS_ABIFLAGS 0x70000003 /* Records ABI related flags */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* -------------------------------------------------------------------- */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct sect { 6062306a36Sopenharmony_ci uint32_t vaddr; 6162306a36Sopenharmony_ci uint32_t len; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciint *symTypeTable; 6562306a36Sopenharmony_ciint must_convert_endian; 6662306a36Sopenharmony_ciint format_bigendian; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void copy(int out, int in, off_t offset, off_t size) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci char ibuf[4096]; 7162306a36Sopenharmony_ci int remaining, cur, count; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Go to the start of the ELF symbol table... */ 7462306a36Sopenharmony_ci if (lseek(in, offset, SEEK_SET) < 0) { 7562306a36Sopenharmony_ci perror("copy: lseek"); 7662306a36Sopenharmony_ci exit(1); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci remaining = size; 8062306a36Sopenharmony_ci while (remaining) { 8162306a36Sopenharmony_ci cur = remaining; 8262306a36Sopenharmony_ci if (cur > sizeof ibuf) 8362306a36Sopenharmony_ci cur = sizeof ibuf; 8462306a36Sopenharmony_ci remaining -= cur; 8562306a36Sopenharmony_ci if ((count = read(in, ibuf, cur)) != cur) { 8662306a36Sopenharmony_ci fprintf(stderr, "copy: read: %s\n", 8762306a36Sopenharmony_ci count ? strerror(errno) : 8862306a36Sopenharmony_ci "premature end of file"); 8962306a36Sopenharmony_ci exit(1); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci if ((count = write(out, ibuf, cur)) != cur) { 9262306a36Sopenharmony_ci perror("copy: write"); 9362306a36Sopenharmony_ci exit(1); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * Combine two segments, which must be contiguous. If pad is true, it's 10062306a36Sopenharmony_ci * okay for there to be padding between. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_cistatic void combine(struct sect *base, struct sect *new, int pad) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (!base->len) 10562306a36Sopenharmony_ci *base = *new; 10662306a36Sopenharmony_ci else if (new->len) { 10762306a36Sopenharmony_ci if (base->vaddr + base->len != new->vaddr) { 10862306a36Sopenharmony_ci if (pad) 10962306a36Sopenharmony_ci base->len = new->vaddr - base->vaddr; 11062306a36Sopenharmony_ci else { 11162306a36Sopenharmony_ci fprintf(stderr, 11262306a36Sopenharmony_ci "Non-contiguous data can't be converted.\n"); 11362306a36Sopenharmony_ci exit(1); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci base->len += new->len; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int phcmp(const void *v1, const void *v2) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci const Elf32_Phdr *h1 = v1; 12362306a36Sopenharmony_ci const Elf32_Phdr *h2 = v2; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (h1->p_vaddr > h2->p_vaddr) 12662306a36Sopenharmony_ci return 1; 12762306a36Sopenharmony_ci else if (h1->p_vaddr < h2->p_vaddr) 12862306a36Sopenharmony_ci return -1; 12962306a36Sopenharmony_ci else 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic char *saveRead(int file, off_t offset, off_t len, char *name) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci char *tmp; 13662306a36Sopenharmony_ci int count; 13762306a36Sopenharmony_ci off_t off; 13862306a36Sopenharmony_ci if ((off = lseek(file, offset, SEEK_SET)) < 0) { 13962306a36Sopenharmony_ci fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno)); 14062306a36Sopenharmony_ci exit(1); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci if (!(tmp = (char *) malloc(len))) { 14362306a36Sopenharmony_ci fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, 14462306a36Sopenharmony_ci len); 14562306a36Sopenharmony_ci exit(1); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci count = read(file, tmp, len); 14862306a36Sopenharmony_ci if (count != len) { 14962306a36Sopenharmony_ci fprintf(stderr, "%s: read: %s.\n", 15062306a36Sopenharmony_ci name, 15162306a36Sopenharmony_ci count ? strerror(errno) : "End of file reached"); 15262306a36Sopenharmony_ci exit(1); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci return tmp; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#define swab16(x) \ 15862306a36Sopenharmony_ci ((uint16_t)( \ 15962306a36Sopenharmony_ci (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ 16062306a36Sopenharmony_ci (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define swab32(x) \ 16362306a36Sopenharmony_ci ((unsigned int)( \ 16462306a36Sopenharmony_ci (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ 16562306a36Sopenharmony_ci (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ 16662306a36Sopenharmony_ci (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ 16762306a36Sopenharmony_ci (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void convert_elf_hdr(Elf32_Ehdr * e) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci e->e_type = swab16(e->e_type); 17262306a36Sopenharmony_ci e->e_machine = swab16(e->e_machine); 17362306a36Sopenharmony_ci e->e_version = swab32(e->e_version); 17462306a36Sopenharmony_ci e->e_entry = swab32(e->e_entry); 17562306a36Sopenharmony_ci e->e_phoff = swab32(e->e_phoff); 17662306a36Sopenharmony_ci e->e_shoff = swab32(e->e_shoff); 17762306a36Sopenharmony_ci e->e_flags = swab32(e->e_flags); 17862306a36Sopenharmony_ci e->e_ehsize = swab16(e->e_ehsize); 17962306a36Sopenharmony_ci e->e_phentsize = swab16(e->e_phentsize); 18062306a36Sopenharmony_ci e->e_phnum = swab16(e->e_phnum); 18162306a36Sopenharmony_ci e->e_shentsize = swab16(e->e_shentsize); 18262306a36Sopenharmony_ci e->e_shnum = swab16(e->e_shnum); 18362306a36Sopenharmony_ci e->e_shstrndx = swab16(e->e_shstrndx); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic void convert_elf_phdrs(Elf32_Phdr * p, int num) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int i; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for (i = 0; i < num; i++, p++) { 19162306a36Sopenharmony_ci p->p_type = swab32(p->p_type); 19262306a36Sopenharmony_ci p->p_offset = swab32(p->p_offset); 19362306a36Sopenharmony_ci p->p_vaddr = swab32(p->p_vaddr); 19462306a36Sopenharmony_ci p->p_paddr = swab32(p->p_paddr); 19562306a36Sopenharmony_ci p->p_filesz = swab32(p->p_filesz); 19662306a36Sopenharmony_ci p->p_memsz = swab32(p->p_memsz); 19762306a36Sopenharmony_ci p->p_flags = swab32(p->p_flags); 19862306a36Sopenharmony_ci p->p_align = swab32(p->p_align); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void convert_elf_shdrs(Elf32_Shdr * s, int num) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int i; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci for (i = 0; i < num; i++, s++) { 20862306a36Sopenharmony_ci s->sh_name = swab32(s->sh_name); 20962306a36Sopenharmony_ci s->sh_type = swab32(s->sh_type); 21062306a36Sopenharmony_ci s->sh_flags = swab32(s->sh_flags); 21162306a36Sopenharmony_ci s->sh_addr = swab32(s->sh_addr); 21262306a36Sopenharmony_ci s->sh_offset = swab32(s->sh_offset); 21362306a36Sopenharmony_ci s->sh_size = swab32(s->sh_size); 21462306a36Sopenharmony_ci s->sh_link = swab32(s->sh_link); 21562306a36Sopenharmony_ci s->sh_info = swab32(s->sh_info); 21662306a36Sopenharmony_ci s->sh_addralign = swab32(s->sh_addralign); 21762306a36Sopenharmony_ci s->sh_entsize = swab32(s->sh_entsize); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void convert_ecoff_filehdr(struct filehdr *f) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci f->f_magic = swab16(f->f_magic); 22462306a36Sopenharmony_ci f->f_nscns = swab16(f->f_nscns); 22562306a36Sopenharmony_ci f->f_timdat = swab32(f->f_timdat); 22662306a36Sopenharmony_ci f->f_symptr = swab32(f->f_symptr); 22762306a36Sopenharmony_ci f->f_nsyms = swab32(f->f_nsyms); 22862306a36Sopenharmony_ci f->f_opthdr = swab16(f->f_opthdr); 22962306a36Sopenharmony_ci f->f_flags = swab16(f->f_flags); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void convert_ecoff_aouthdr(struct aouthdr *a) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci a->magic = swab16(a->magic); 23562306a36Sopenharmony_ci a->vstamp = swab16(a->vstamp); 23662306a36Sopenharmony_ci a->tsize = swab32(a->tsize); 23762306a36Sopenharmony_ci a->dsize = swab32(a->dsize); 23862306a36Sopenharmony_ci a->bsize = swab32(a->bsize); 23962306a36Sopenharmony_ci a->entry = swab32(a->entry); 24062306a36Sopenharmony_ci a->text_start = swab32(a->text_start); 24162306a36Sopenharmony_ci a->data_start = swab32(a->data_start); 24262306a36Sopenharmony_ci a->bss_start = swab32(a->bss_start); 24362306a36Sopenharmony_ci a->gprmask = swab32(a->gprmask); 24462306a36Sopenharmony_ci a->cprmask[0] = swab32(a->cprmask[0]); 24562306a36Sopenharmony_ci a->cprmask[1] = swab32(a->cprmask[1]); 24662306a36Sopenharmony_ci a->cprmask[2] = swab32(a->cprmask[2]); 24762306a36Sopenharmony_ci a->cprmask[3] = swab32(a->cprmask[3]); 24862306a36Sopenharmony_ci a->gp_value = swab32(a->gp_value); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void convert_ecoff_esecs(struct scnhdr *s, int num) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int i; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci for (i = 0; i < num; i++, s++) { 25662306a36Sopenharmony_ci s->s_paddr = swab32(s->s_paddr); 25762306a36Sopenharmony_ci s->s_vaddr = swab32(s->s_vaddr); 25862306a36Sopenharmony_ci s->s_size = swab32(s->s_size); 25962306a36Sopenharmony_ci s->s_scnptr = swab32(s->s_scnptr); 26062306a36Sopenharmony_ci s->s_relptr = swab32(s->s_relptr); 26162306a36Sopenharmony_ci s->s_lnnoptr = swab32(s->s_lnnoptr); 26262306a36Sopenharmony_ci s->s_nreloc = swab16(s->s_nreloc); 26362306a36Sopenharmony_ci s->s_nlnno = swab16(s->s_nlnno); 26462306a36Sopenharmony_ci s->s_flags = swab32(s->s_flags); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ciint main(int argc, char *argv[]) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci Elf32_Ehdr ex; 27162306a36Sopenharmony_ci Elf32_Phdr *ph; 27262306a36Sopenharmony_ci Elf32_Shdr *sh; 27362306a36Sopenharmony_ci int i, pad; 27462306a36Sopenharmony_ci struct sect text, data, bss; 27562306a36Sopenharmony_ci struct filehdr efh; 27662306a36Sopenharmony_ci struct aouthdr eah; 27762306a36Sopenharmony_ci struct scnhdr esecs[6]; 27862306a36Sopenharmony_ci int infile, outfile; 27962306a36Sopenharmony_ci uint32_t cur_vma = UINT32_MAX; 28062306a36Sopenharmony_ci int addflag = 0; 28162306a36Sopenharmony_ci int nosecs; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci text.len = data.len = bss.len = 0; 28462306a36Sopenharmony_ci text.vaddr = data.vaddr = bss.vaddr = 0; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Check args... */ 28762306a36Sopenharmony_ci if (argc < 3 || argc > 4) { 28862306a36Sopenharmony_ci usage: 28962306a36Sopenharmony_ci fprintf(stderr, 29062306a36Sopenharmony_ci "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n"); 29162306a36Sopenharmony_ci exit(1); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci if (argc == 4) { 29462306a36Sopenharmony_ci if (strcmp(argv[3], "-a")) 29562306a36Sopenharmony_ci goto usage; 29662306a36Sopenharmony_ci addflag = 1; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Try the input file... */ 30062306a36Sopenharmony_ci if ((infile = open(argv[1], O_RDONLY)) < 0) { 30162306a36Sopenharmony_ci fprintf(stderr, "Can't open %s for read: %s\n", 30262306a36Sopenharmony_ci argv[1], strerror(errno)); 30362306a36Sopenharmony_ci exit(1); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Read the header, which is at the beginning of the file... */ 30762306a36Sopenharmony_ci i = read(infile, &ex, sizeof ex); 30862306a36Sopenharmony_ci if (i != sizeof ex) { 30962306a36Sopenharmony_ci fprintf(stderr, "ex: %s: %s.\n", 31062306a36Sopenharmony_ci argv[1], 31162306a36Sopenharmony_ci i ? strerror(errno) : "End of file reached"); 31262306a36Sopenharmony_ci exit(1); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (ex.e_ident[EI_DATA] == ELFDATA2MSB) 31662306a36Sopenharmony_ci format_bigendian = 1; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (ntohs(0xaa55) == 0xaa55) { 31962306a36Sopenharmony_ci if (!format_bigendian) 32062306a36Sopenharmony_ci must_convert_endian = 1; 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci if (format_bigendian) 32362306a36Sopenharmony_ci must_convert_endian = 1; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci if (must_convert_endian) 32662306a36Sopenharmony_ci convert_elf_hdr(&ex); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Read the program headers... */ 32962306a36Sopenharmony_ci ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff, 33062306a36Sopenharmony_ci ex.e_phnum * sizeof(Elf32_Phdr), 33162306a36Sopenharmony_ci "ph"); 33262306a36Sopenharmony_ci if (must_convert_endian) 33362306a36Sopenharmony_ci convert_elf_phdrs(ph, ex.e_phnum); 33462306a36Sopenharmony_ci /* Read the section headers... */ 33562306a36Sopenharmony_ci sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff, 33662306a36Sopenharmony_ci ex.e_shnum * sizeof(Elf32_Shdr), 33762306a36Sopenharmony_ci "sh"); 33862306a36Sopenharmony_ci if (must_convert_endian) 33962306a36Sopenharmony_ci convert_elf_shdrs(sh, ex.e_shnum); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Figure out if we can cram the program header into an ECOFF 34262306a36Sopenharmony_ci header... Basically, we can't handle anything but loadable 34362306a36Sopenharmony_ci segments, but we can ignore some kinds of segments. We can't 34462306a36Sopenharmony_ci handle holes in the address space. Segments may be out of order, 34562306a36Sopenharmony_ci so we sort them first. */ 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci for (i = 0; i < ex.e_phnum; i++) { 35062306a36Sopenharmony_ci /* Section types we can ignore... */ 35162306a36Sopenharmony_ci switch (ph[i].p_type) { 35262306a36Sopenharmony_ci case PT_NULL: 35362306a36Sopenharmony_ci case PT_NOTE: 35462306a36Sopenharmony_ci case PT_PHDR: 35562306a36Sopenharmony_ci case PT_MIPS_REGINFO: 35662306a36Sopenharmony_ci case PT_MIPS_ABIFLAGS: 35762306a36Sopenharmony_ci continue; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci case PT_LOAD: 36062306a36Sopenharmony_ci /* Writable (data) segment? */ 36162306a36Sopenharmony_ci if (ph[i].p_flags & PF_W) { 36262306a36Sopenharmony_ci struct sect ndata, nbss; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ndata.vaddr = ph[i].p_vaddr; 36562306a36Sopenharmony_ci ndata.len = ph[i].p_filesz; 36662306a36Sopenharmony_ci nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; 36762306a36Sopenharmony_ci nbss.len = ph[i].p_memsz - ph[i].p_filesz; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci combine(&data, &ndata, 0); 37062306a36Sopenharmony_ci combine(&bss, &nbss, 1); 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci struct sect ntxt; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ntxt.vaddr = ph[i].p_vaddr; 37562306a36Sopenharmony_ci ntxt.len = ph[i].p_filesz; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci combine(&text, &ntxt, 0); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci /* Remember the lowest segment start address. */ 38062306a36Sopenharmony_ci if (ph[i].p_vaddr < cur_vma) 38162306a36Sopenharmony_ci cur_vma = ph[i].p_vaddr; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci default: 38562306a36Sopenharmony_ci /* Section types we can't handle... */ 38662306a36Sopenharmony_ci fprintf(stderr, 38762306a36Sopenharmony_ci "Program header %d type %d can't be converted.\n", 38862306a36Sopenharmony_ci ex.e_phnum, ph[i].p_type); 38962306a36Sopenharmony_ci exit(1); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Sections must be in order to be converted... */ 39462306a36Sopenharmony_ci if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 39562306a36Sopenharmony_ci text.vaddr + text.len > data.vaddr 39662306a36Sopenharmony_ci || data.vaddr + data.len > bss.vaddr) { 39762306a36Sopenharmony_ci fprintf(stderr, 39862306a36Sopenharmony_ci "Sections ordering prevents a.out conversion.\n"); 39962306a36Sopenharmony_ci exit(1); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* If there's a data section but no text section, then the loader 40362306a36Sopenharmony_ci combined everything into one section. That needs to be the 40462306a36Sopenharmony_ci text section, so just make the data section zero length following 40562306a36Sopenharmony_ci text. */ 40662306a36Sopenharmony_ci if (data.len && !text.len) { 40762306a36Sopenharmony_ci text = data; 40862306a36Sopenharmony_ci data.vaddr = text.vaddr + text.len; 40962306a36Sopenharmony_ci data.len = 0; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* If there is a gap between text and data, we'll fill it when we copy 41362306a36Sopenharmony_ci the data, so update the length of the text segment as represented in 41462306a36Sopenharmony_ci a.out to reflect that, since a.out doesn't allow gaps in the program 41562306a36Sopenharmony_ci address space. */ 41662306a36Sopenharmony_ci if (text.vaddr + text.len < data.vaddr) 41762306a36Sopenharmony_ci text.len = data.vaddr - text.vaddr; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* We now have enough information to cons up an a.out header... */ 42062306a36Sopenharmony_ci eah.magic = OMAGIC; 42162306a36Sopenharmony_ci eah.vstamp = 200; 42262306a36Sopenharmony_ci eah.tsize = text.len; 42362306a36Sopenharmony_ci eah.dsize = data.len; 42462306a36Sopenharmony_ci eah.bsize = bss.len; 42562306a36Sopenharmony_ci eah.entry = ex.e_entry; 42662306a36Sopenharmony_ci eah.text_start = text.vaddr; 42762306a36Sopenharmony_ci eah.data_start = data.vaddr; 42862306a36Sopenharmony_ci eah.bss_start = bss.vaddr; 42962306a36Sopenharmony_ci eah.gprmask = 0xf3fffffe; 43062306a36Sopenharmony_ci memset(&eah.cprmask, '\0', sizeof eah.cprmask); 43162306a36Sopenharmony_ci eah.gp_value = 0; /* unused. */ 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (format_bigendian) 43462306a36Sopenharmony_ci efh.f_magic = MIPSEBMAGIC; 43562306a36Sopenharmony_ci else 43662306a36Sopenharmony_ci efh.f_magic = MIPSELMAGIC; 43762306a36Sopenharmony_ci if (addflag) 43862306a36Sopenharmony_ci nosecs = 6; 43962306a36Sopenharmony_ci else 44062306a36Sopenharmony_ci nosecs = 3; 44162306a36Sopenharmony_ci efh.f_nscns = nosecs; 44262306a36Sopenharmony_ci efh.f_timdat = 0; /* bogus */ 44362306a36Sopenharmony_ci efh.f_symptr = 0; 44462306a36Sopenharmony_ci efh.f_nsyms = 0; 44562306a36Sopenharmony_ci efh.f_opthdr = sizeof eah; 44662306a36Sopenharmony_ci efh.f_flags = 0x100f; /* Stripped, not sharable. */ 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci memset(esecs, 0, sizeof esecs); 44962306a36Sopenharmony_ci strcpy(esecs[0].s_name, ".text"); 45062306a36Sopenharmony_ci strcpy(esecs[1].s_name, ".data"); 45162306a36Sopenharmony_ci strcpy(esecs[2].s_name, ".bss"); 45262306a36Sopenharmony_ci if (addflag) { 45362306a36Sopenharmony_ci strcpy(esecs[3].s_name, ".rdata"); 45462306a36Sopenharmony_ci strcpy(esecs[4].s_name, ".sdata"); 45562306a36Sopenharmony_ci strcpy(esecs[5].s_name, ".sbss"); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start; 45862306a36Sopenharmony_ci esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start; 45962306a36Sopenharmony_ci esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start; 46062306a36Sopenharmony_ci if (addflag) { 46162306a36Sopenharmony_ci esecs[3].s_paddr = esecs[3].s_vaddr = 0; 46262306a36Sopenharmony_ci esecs[4].s_paddr = esecs[4].s_vaddr = 0; 46362306a36Sopenharmony_ci esecs[5].s_paddr = esecs[5].s_vaddr = 0; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci esecs[0].s_size = eah.tsize; 46662306a36Sopenharmony_ci esecs[1].s_size = eah.dsize; 46762306a36Sopenharmony_ci esecs[2].s_size = eah.bsize; 46862306a36Sopenharmony_ci if (addflag) { 46962306a36Sopenharmony_ci esecs[3].s_size = 0; 47062306a36Sopenharmony_ci esecs[4].s_size = 0; 47162306a36Sopenharmony_ci esecs[5].s_size = 0; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci esecs[0].s_scnptr = N_TXTOFF(efh, eah); 47462306a36Sopenharmony_ci esecs[1].s_scnptr = N_DATOFF(efh, eah); 47562306a36Sopenharmony_ci#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10 47662306a36Sopenharmony_ci#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1)) 47762306a36Sopenharmony_ci esecs[2].s_scnptr = esecs[1].s_scnptr + 47862306a36Sopenharmony_ci ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah)); 47962306a36Sopenharmony_ci if (addflag) { 48062306a36Sopenharmony_ci esecs[3].s_scnptr = 0; 48162306a36Sopenharmony_ci esecs[4].s_scnptr = 0; 48262306a36Sopenharmony_ci esecs[5].s_scnptr = 0; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0; 48562306a36Sopenharmony_ci esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0; 48662306a36Sopenharmony_ci esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0; 48762306a36Sopenharmony_ci esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0; 48862306a36Sopenharmony_ci if (addflag) { 48962306a36Sopenharmony_ci esecs[3].s_relptr = esecs[4].s_relptr 49062306a36Sopenharmony_ci = esecs[5].s_relptr = 0; 49162306a36Sopenharmony_ci esecs[3].s_lnnoptr = esecs[4].s_lnnoptr 49262306a36Sopenharmony_ci = esecs[5].s_lnnoptr = 0; 49362306a36Sopenharmony_ci esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc = 49462306a36Sopenharmony_ci 0; 49562306a36Sopenharmony_ci esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci esecs[0].s_flags = 0x20; 49862306a36Sopenharmony_ci esecs[1].s_flags = 0x40; 49962306a36Sopenharmony_ci esecs[2].s_flags = 0x82; 50062306a36Sopenharmony_ci if (addflag) { 50162306a36Sopenharmony_ci esecs[3].s_flags = 0x100; 50262306a36Sopenharmony_ci esecs[4].s_flags = 0x200; 50362306a36Sopenharmony_ci esecs[5].s_flags = 0x400; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Make the output file... */ 50762306a36Sopenharmony_ci if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) { 50862306a36Sopenharmony_ci fprintf(stderr, "Unable to create %s: %s\n", argv[2], 50962306a36Sopenharmony_ci strerror(errno)); 51062306a36Sopenharmony_ci exit(1); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (must_convert_endian) 51462306a36Sopenharmony_ci convert_ecoff_filehdr(&efh); 51562306a36Sopenharmony_ci /* Write the headers... */ 51662306a36Sopenharmony_ci i = write(outfile, &efh, sizeof efh); 51762306a36Sopenharmony_ci if (i != sizeof efh) { 51862306a36Sopenharmony_ci perror("efh: write"); 51962306a36Sopenharmony_ci exit(1); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci for (i = 0; i < nosecs; i++) { 52262306a36Sopenharmony_ci printf 52362306a36Sopenharmony_ci ("Section %d: %s phys %"PRIx32" size %"PRIx32"\t file offset %"PRIx32"\n", 52462306a36Sopenharmony_ci i, esecs[i].s_name, esecs[i].s_paddr, 52562306a36Sopenharmony_ci esecs[i].s_size, esecs[i].s_scnptr); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci fprintf(stderr, "wrote %d byte file header.\n", i); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (must_convert_endian) 53162306a36Sopenharmony_ci convert_ecoff_aouthdr(&eah); 53262306a36Sopenharmony_ci i = write(outfile, &eah, sizeof eah); 53362306a36Sopenharmony_ci if (i != sizeof eah) { 53462306a36Sopenharmony_ci perror("eah: write"); 53562306a36Sopenharmony_ci exit(1); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci fprintf(stderr, "wrote %d byte a.out header.\n", i); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (must_convert_endian) 54062306a36Sopenharmony_ci convert_ecoff_esecs(&esecs[0], nosecs); 54162306a36Sopenharmony_ci i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr)); 54262306a36Sopenharmony_ci if (i != nosecs * sizeof(struct scnhdr)) { 54362306a36Sopenharmony_ci perror("esecs: write"); 54462306a36Sopenharmony_ci exit(1); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci fprintf(stderr, "wrote %d bytes of section headers.\n", i); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15; 54962306a36Sopenharmony_ci if (pad) { 55062306a36Sopenharmony_ci pad = 16 - pad; 55162306a36Sopenharmony_ci i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); 55262306a36Sopenharmony_ci if (i < 0) { 55362306a36Sopenharmony_ci perror("ipad: write"); 55462306a36Sopenharmony_ci exit(1); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci fprintf(stderr, "wrote %d byte pad.\n", i); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * Copy the loadable sections. Zero-fill any gaps less than 64k; 56162306a36Sopenharmony_ci * complain about any zero-filling, and die if we're asked to zero-fill 56262306a36Sopenharmony_ci * more than 64k. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci for (i = 0; i < ex.e_phnum; i++) { 56562306a36Sopenharmony_ci /* Unprocessable sections were handled above, so just verify that 56662306a36Sopenharmony_ci the section can be loaded before copying. */ 56762306a36Sopenharmony_ci if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { 56862306a36Sopenharmony_ci if (cur_vma != ph[i].p_vaddr) { 56962306a36Sopenharmony_ci uint32_t gap = ph[i].p_vaddr - cur_vma; 57062306a36Sopenharmony_ci char obuf[1024]; 57162306a36Sopenharmony_ci if (gap > 65536) { 57262306a36Sopenharmony_ci fprintf(stderr, 57362306a36Sopenharmony_ci "Intersegment gap (%"PRId32" bytes) too large.\n", 57462306a36Sopenharmony_ci gap); 57562306a36Sopenharmony_ci exit(1); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci fprintf(stderr, 57862306a36Sopenharmony_ci "Warning: %d byte intersegment gap.\n", 57962306a36Sopenharmony_ci gap); 58062306a36Sopenharmony_ci memset(obuf, 0, sizeof obuf); 58162306a36Sopenharmony_ci while (gap) { 58262306a36Sopenharmony_ci int count = 58362306a36Sopenharmony_ci write(outfile, obuf, 58462306a36Sopenharmony_ci (gap > 58562306a36Sopenharmony_ci sizeof obuf ? sizeof 58662306a36Sopenharmony_ci obuf : gap)); 58762306a36Sopenharmony_ci if (count < 0) { 58862306a36Sopenharmony_ci fprintf(stderr, 58962306a36Sopenharmony_ci "Error writing gap: %s\n", 59062306a36Sopenharmony_ci strerror(errno)); 59162306a36Sopenharmony_ci exit(1); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci gap -= count; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci fprintf(stderr, "writing %d bytes...\n", 59762306a36Sopenharmony_ci ph[i].p_filesz); 59862306a36Sopenharmony_ci copy(outfile, infile, ph[i].p_offset, 59962306a36Sopenharmony_ci ph[i].p_filesz); 60062306a36Sopenharmony_ci cur_vma = ph[i].p_vaddr + ph[i].p_filesz; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* 60562306a36Sopenharmony_ci * Write a page of padding for boot PROMS that read entire pages. 60662306a36Sopenharmony_ci * Without this, they may attempt to read past the end of the 60762306a36Sopenharmony_ci * data section, incur an error, and refuse to boot. 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ci { 61062306a36Sopenharmony_ci char obuf[4096]; 61162306a36Sopenharmony_ci memset(obuf, 0, sizeof obuf); 61262306a36Sopenharmony_ci if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) { 61362306a36Sopenharmony_ci fprintf(stderr, "Error writing PROM padding: %s\n", 61462306a36Sopenharmony_ci strerror(errno)); 61562306a36Sopenharmony_ci exit(1); 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Looks like we won... */ 62062306a36Sopenharmony_ci exit(0); 62162306a36Sopenharmony_ci} 622