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