Home | History | Annotate | Line # | Download | only in elf2ecoff
elf2ecoff.c revision 1.1
      1 /*
      2  * Copyright (c) 1995
      3  *	Ted Lemon (hereinafter referred to as the author)
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. The name of the author may not be used to endorse or promote products
     14  *    derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 /* elf2ecoff.c
     30 
     31    This program converts an elf executable to an ECOFF executable.
     32    No symbol table is retained.   This is useful primarily in building
     33    net-bootable kernels for machines (e.g., DECstation and Alpha) which
     34    only support the ECOFF object file format. */
     35 
     36 #include <sys/types.h>
     37 #include <fcntl.h>
     38 #include <unistd.h>
     39 #include <machine/elf.h>
     40 #include <stdio.h>
     41 #include <sys/exec_ecoff.h>
     42 #include <sys/errno.h>
     43 #include <string.h>
     44 #include <limits.h>
     45 
     46 struct sect {
     47   unsigned long vaddr;
     48   unsigned long len;
     49 };
     50 
     51 int phcmp ();
     52 char *saveRead (int file, off_t offset, off_t len, char *name);
     53 int copy (int, int, off_t, off_t);
     54 int translate_syms (int, int, off_t, off_t, off_t, off_t);
     55 extern int errno;
     56 int *symTypeTable;
     57 
     58 main (int argc, char **argv, char **envp)
     59 {
     60   struct ehdr ex;
     61   struct phdr *ph;
     62   struct shdr *sh;
     63   struct sym *symtab;
     64   char *shstrtab;
     65   int strtabix, symtabix;
     66   int i, pad;
     67   struct sect text, data, bss;
     68   struct ecoff_filehdr efh;
     69   struct ecoff_aouthdr eah;
     70   struct ecoff_scnhdr esecs [3];
     71   int infile, outfile;
     72   unsigned long cur_vma = ULONG_MAX;
     73   int symflag = 0;
     74 
     75   text.len = data.len = bss.len = 0;
     76   text.vaddr = data.vaddr = bss.vaddr = 0;
     77 
     78   /* Check args... */
     79   if (argc < 3 || argc > 4)
     80     {
     81     usage:
     82       fprintf (stderr,
     83 	       "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
     84       exit (1);
     85     }
     86   if (argc == 4)
     87     {
     88       if (strcmp (argv [3], "-s"))
     89 	goto usage;
     90       symflag = 1;
     91     }
     92 
     93   /* Try the input file... */
     94   if ((infile = open (argv [1], O_RDONLY)) < 0)
     95     {
     96       fprintf (stderr, "Can't open %s for read: %s\n",
     97 	       argv [1], strerror (errno));
     98       exit (1);
     99     }
    100 
    101   /* Read the header, which is at the beginning of the file... */
    102   i = read (infile, &ex, sizeof ex);
    103   if (i != sizeof ex)
    104     {
    105       fprintf (stderr, "ex: %s: %s.\n",
    106 	       argv [1], i ? strerror (errno) : "End of file reached");
    107       exit (1);
    108     }
    109 
    110   /* Read the program headers... */
    111   ph = (struct phdr *)saveRead (infile, ex.phoff,
    112 				ex.phcount * sizeof (struct phdr), "ph");
    113   /* Read the section headers... */
    114   sh = (struct shdr *)saveRead (infile, ex.shoff,
    115 				ex.shcount * sizeof (struct shdr), "sh");
    116   /* Read in the section string table. */
    117   shstrtab = saveRead (infile, sh [ex.shstrndx].offset,
    118 		       sh [ex.shstrndx].size, "shstrtab");
    119 
    120   /* Figure out if we can cram the program header into an ECOFF
    121      header...  Basically, we can't handle anything but loadable
    122      segments, but we can ignore some kinds of segments.  We can't
    123      handle holes in the address space.  Segments may be out of order,
    124      so we sort them first. */
    125 
    126   qsort (ph, ex.phcount, sizeof (struct phdr), phcmp);
    127 
    128   for (i = 0; i < ex.phcount; i++)
    129     {
    130       /* Section types we can ignore... */
    131       if (ph [i].type == PT_NULL || ph [i].type == PT_NOTE ||
    132 	  ph [i].type == PT_PHDR || ph [i].type == PT_MIPS_REGINFO)
    133 	continue;
    134       /* Section types we can't handle... */
    135       else if (ph [i].type != PT_LOAD)
    136         {
    137 	  fprintf (stderr, "Program header %d type %d can't be converted.\n");
    138 	  exit (1);
    139 	}
    140       /* Writable (data) segment? */
    141       if (ph [i].flags & PF_W)
    142 	{
    143 	  struct sect ndata, nbss;
    144 
    145 	  ndata.vaddr = ph [i].vaddr;
    146 	  ndata.len = ph [i].filesz;
    147 	  nbss.vaddr = ph [i].vaddr + ph [i].filesz;
    148 	  nbss.len = ph [i].memsz - ph [i].filesz;
    149 
    150 	  combine (&data, &ndata, 0);
    151 	  combine (&bss, &nbss, 1);
    152 	}
    153       else
    154 	{
    155 	  struct sect ntxt;
    156 
    157 	  ntxt.vaddr = ph [i].vaddr;
    158 	  ntxt.len = ph [i].filesz;
    159 
    160 	  combine (&text, &ntxt);
    161 	}
    162       /* Remember the lowest segment start address. */
    163       if (ph [i].vaddr < cur_vma)
    164 	cur_vma = ph [i].vaddr;
    165     }
    166 
    167   /* Sections must be in order to be converted... */
    168   if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
    169       text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
    170     {
    171       fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
    172       exit (1);
    173     }
    174 
    175   /* If there's a data section but no text section, then the loader
    176      combined everything into one section.   That needs to be the
    177      text section, so just make the data section zero length following
    178      text. */
    179   if (data.len && !text.len)
    180     {
    181       text = data;
    182       data.vaddr = text.vaddr + text.len;
    183       data.len = 0;
    184     }
    185 
    186   /* If there is a gap between text and data, we'll fill it when we copy
    187      the data, so update the length of the text segment as represented in
    188      a.out to reflect that, since a.out doesn't allow gaps in the program
    189      address space. */
    190   if (text.vaddr + text.len < data.vaddr)
    191     text.len = data.vaddr - text.vaddr;
    192 
    193   /* We now have enough information to cons up an a.out header... */
    194   eah.ea_magic = ECOFF_OMAGIC;
    195   eah.ea_vstamp = 200;
    196   eah.ea_tsize = text.len;
    197   eah.ea_dsize = data.len;
    198   eah.ea_bsize = bss.len;
    199   eah.ea_entry = ex.entry;
    200   eah.ea_text_start = text.vaddr;
    201   eah.ea_data_start = data.vaddr;
    202   eah.ea_bss_start = bss.vaddr;
    203   eah.ea_gprmask = 0xf3fffffe;
    204   bzero (&eah.ea_cprmask, sizeof eah.ea_cprmask);
    205   eah.ea_gp_value = 0; /* unused. */
    206 
    207   efh.ef_magic = ECOFF_MAGIC_MIPSEL;
    208   efh.ef_nsecs = 3;
    209   efh.ef_timestamp = 0;	/* bogus */
    210   efh.ef_symptr = 0;
    211   efh.ef_syms = 0;
    212   efh.ef_opthdr = sizeof eah;
    213   efh.ef_flags = 0x100f; /* Stripped, not sharable. */
    214 
    215   strcpy (esecs [0].es_name, ".text");
    216   strcpy (esecs [1].es_name, ".data");
    217   strcpy (esecs [2].es_name, ".bss");
    218   esecs [0].es_physaddr = esecs [0].es_virtaddr = eah.ea_text_start;
    219   esecs [1].es_physaddr = esecs [1].es_virtaddr = eah.ea_data_start;
    220   esecs [2].es_physaddr = esecs [2].es_virtaddr = eah.ea_bss_start;
    221   esecs [0].es_size = eah.ea_tsize;
    222   esecs [1].es_size = eah.ea_dsize;
    223   esecs [2].es_size = eah.ea_bsize;
    224   esecs [0].es_raw_offset = ECOFF_TXTOFF (&efh, &eah);
    225   esecs [1].es_raw_offset = ECOFF_DATOFF (&efh, &eah);
    226   esecs [2].es_raw_offset = esecs [1].es_raw_offset +
    227 	  ECOFF_ROUND (esecs [1].es_size, ECOFF_SEGMENT_ALIGNMENT (&eah));
    228   esecs [0].es_reloc_offset = esecs [1].es_reloc_offset
    229 	  = esecs [2].es_reloc_offset = 0;
    230   esecs [0].es_line_offset = esecs [1].es_line_offset
    231 	  = esecs [2].es_line_offset = 0;
    232   esecs [0].es_nreloc = esecs [1].es_nreloc = esecs [2].es_nreloc = 0;
    233   esecs [0].es_nline = esecs [1].es_nline = esecs [2].es_nline = 0;
    234   esecs [0].es_flags = 0x20;
    235   esecs [1].es_flags = 0x40;
    236   esecs [2].es_flags = 0x82;
    237 
    238   /* Make the output file... */
    239   if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
    240     {
    241       fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
    242       exit (1);
    243     }
    244 
    245   /* Write the headers... */
    246   i = write (outfile, &efh, sizeof efh);
    247   if (i != sizeof efh)
    248     {
    249       perror ("efh: write");
    250       exit (1);
    251 
    252   for (i = 0; i < 6; i++)
    253     {
    254       printf ("Section %d: %s phys %x  size %x  file offset %x\n",
    255 	      i, esecs [i].es_name, esecs [i].es_physaddr,
    256 	      esecs [i].es_size, esecs [i].es_raw_offset);
    257     }
    258     }
    259   fprintf (stderr, "wrote %d byte file header.\n", i);
    260 
    261   i = write (outfile, &eah, sizeof eah);
    262   if (i != sizeof eah)
    263     {
    264       perror ("eah: write");
    265       exit (1);
    266     }
    267   fprintf (stderr, "wrote %d byte a.out header.\n", i);
    268 
    269   i = write (outfile, &esecs, sizeof esecs);
    270   if (i != sizeof esecs)
    271     {
    272       perror ("esecs: write");
    273       exit (1);
    274     }
    275   fprintf (stderr, "wrote %d bytes of section headers.\n", i);
    276 
    277   if (pad = ((sizeof efh + sizeof eah + sizeof esecs) & 15))
    278     {
    279       pad = 16 - pad;
    280       i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
    281       if (i < 0)
    282 	{
    283 	  perror ("ipad: write");
    284 	  exit (1);
    285 	}
    286       fprintf (stderr, "wrote %d byte pad.\n", i);
    287     }
    288 
    289   /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
    290      complain about any zero-filling, and die if we're asked to zero-fill
    291      more than 64k. */
    292   for (i = 0; i < ex.phcount; i++)
    293     {
    294       /* Unprocessable sections were handled above, so just verify that
    295 	 the section can be loaded before copying. */
    296       if (ph [i].type == PT_LOAD && ph [i].filesz)
    297 	{
    298 	  if (cur_vma != ph [i].vaddr)
    299 	    {
    300 	      unsigned long gap = ph [i].vaddr - cur_vma;
    301 	      char obuf [1024];
    302 	      if (gap > 65536)
    303 		{
    304 		  fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
    305 			   gap);
    306 		  exit (1);
    307 		}
    308 	      fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
    309 	      memset (obuf, 0, sizeof obuf);
    310 	      while (gap)
    311 		{
    312 		  int count = write (outfile, obuf, (gap > sizeof obuf
    313 						     ? sizeof obuf : gap));
    314 		  if (count < 0)
    315 		    {
    316 		      fprintf (stderr, "Error writing gap: %s\n",
    317 			       strerror (errno));
    318 		      exit (1);
    319 		    }
    320 		  gap -= count;
    321 		}
    322 	    }
    323 fprintf (stderr, "writing %d bytes...\n", ph [i].filesz);
    324 	  copy (outfile, infile, ph [i].offset, ph [i].filesz);
    325 	  cur_vma = ph [i].vaddr + ph [i].filesz;
    326 	}
    327     }
    328 
    329   /* Looks like we won... */
    330   exit (0);
    331 }
    332 
    333 copy (out, in, offset, size)
    334      int out, in;
    335      off_t offset, size;
    336 {
    337   char ibuf [4096];
    338   int remaining, cur, count;
    339 
    340   /* Go the the start of the ELF symbol table... */
    341   if (lseek (in, offset, SEEK_SET) < 0)
    342     {
    343       perror ("copy: lseek");
    344       exit (1);
    345     }
    346 
    347   remaining = size;
    348   while (remaining)
    349     {
    350       cur = remaining;
    351       if (cur > sizeof ibuf)
    352 	cur = sizeof ibuf;
    353       remaining -= cur;
    354       if ((count = read (in, ibuf, cur)) != cur)
    355 	{
    356 	  fprintf (stderr, "copy: read: %s\n",
    357 		   count ? strerror (errno) : "premature end of file");
    358 	  exit (1);
    359 	}
    360       if ((count = write (out, ibuf, cur)) != cur)
    361 	{
    362 	  perror ("copy: write");
    363 	  exit (1);
    364 	}
    365     }
    366 }
    367 
    368 /* Combine two segments, which must be contiguous.   If pad is true, it's
    369    okay for there to be padding between. */
    370 combine (base, new, pad)
    371      struct sect *base, *new;
    372      int pad;
    373 {
    374   if (!base -> len)
    375     *base = *new;
    376   else if (new -> len)
    377     {
    378       if (base -> vaddr + base -> len != new -> vaddr)
    379 	{
    380 	  if (pad)
    381 	    base -> len = new -> vaddr - base -> vaddr;
    382 	  else
    383 	    {
    384 	      fprintf (stderr,
    385 		       "Non-contiguous data can't be converted.\n");
    386 	      exit (1);
    387 	    }
    388 	}
    389       base -> len += new -> len;
    390     }
    391 }
    392 
    393 phcmp (h1, h2)
    394      struct phdr *h1, *h2;
    395 {
    396   if (h1 -> vaddr > h2 -> vaddr)
    397     return 1;
    398   else if (h1 -> vaddr < h2 -> vaddr)
    399     return -1;
    400   else
    401     return 0;
    402 }
    403 
    404 char *saveRead (int file, off_t offset, off_t len, char *name)
    405 {
    406   char *tmp;
    407   int count;
    408   off_t off;
    409   if ((off = lseek (file, offset, SEEK_SET)) < 0)
    410     {
    411       fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
    412       exit (1);
    413     }
    414   if (!(tmp = (char *)malloc (len)))
    415     {
    416       fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
    417       exit (1);
    418     }
    419   count = read (file, tmp, len);
    420   if (count != len)
    421     {
    422       fprintf (stderr, "%s: read: %s.\n",
    423 	       name, count ? strerror (errno) : "End of file reached");
    424       exit (1);
    425     }
    426   return tmp;
    427 }
    428