Home | History | Annotate | Line # | Download | only in elf2ecoff
elf2ecoff.c revision 1.8
      1 /*	$NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 Jonathan Stone
      5  *    All rights reserved.
      6  * Copyright (c) 1995
      7  *	Ted Lemon (hereinafter referred to as the author)
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 /* elf2ecoff.c
     34 
     35    This program converts an elf executable to an ECOFF executable.
     36    No symbol table is retained.   This is useful primarily in building
     37    net-bootable kernels for machines (e.g., DECstation and Alpha) which
     38    only support the ECOFF object file format. */
     39 
     40 #include <sys/types.h>
     41 #include <fcntl.h>
     42 #include <unistd.h>
     43 #include <sys/exec.h>
     44 #include <sys/exec_elf.h>
     45 #include <sys/exec_aout.h>
     46 #include <stdio.h>
     47 #include <sys/exec_ecoff.h>
     48 #include <sys/errno.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <limits.h>
     52 
     53 
     54 /* Elf Program segment permissions, in program header flags field */
     55 
     56 #define PF_X            (1 << 0)        /* Segment is executable */
     57 #define PF_W            (1 << 1)        /* Segment is writable */
     58 #define PF_R            (1 << 2)        /* Segment is readable */
     59 #define PF_MASKPROC     0xF0000000      /* Processor-specific reserved bits */
     60 
     61 
     62 #define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
     63 
     64 struct sect {
     65   unsigned long vaddr;
     66   unsigned long len;
     67 };
     68 
     69 struct elf_syms {
     70 	int nsymbols;
     71 	Elf32_Sym *elf_syms;
     72 	off_t stringsize;
     73 	char *stringtab;
     74 };
     75 
     76 struct ecoff_syms {
     77 	int nsymbols;
     78 	struct ecoff_extsym *ecoff_syms;
     79 	off_t stringsize;
     80 	char *stringtab;
     81 };
     82 
     83 int debug = 0;
     84 
     85 int phcmp (Elf32_Phdr *h1, Elf32_Phdr *h2);
     86 
     87 
     88 char *saveRead (int file, off_t offset, off_t len, char *name);
     89 void safewrite(int outfile, void *buf, off_t len, const char *msg);
     90 void copy (int, int, off_t, off_t);
     91 void combine (struct sect *base, struct sect *new, int paddable);
     92 void translate_syms (struct elf_syms *, struct ecoff_syms *);
     93 void elf_symbol_table_to_ecoff(int out, int in,
     94 	struct ecoff_exechdr *ep,
     95 	off_t symoff, off_t symsize,
     96 	off_t stroff, off_t strsize);
     97 
     98 
     99 int make_ecoff_section_hdrs(struct ecoff_exechdr *ep,
    100 				 struct ecoff_scnhdr *esecs);
    101 
    102 void write_ecoff_symhdr(int outfile, struct ecoff_exechdr *ep,
    103 			struct ecoff_symhdr *symhdrp,
    104 			long nesyms,  long extsymoff, long extstroff,
    105 			long strsize);
    106 
    107 void  pad16(int fd, int size, const char *msg);
    108 
    109 extern int errno;
    110 int *symTypeTable;
    111 
    112 
    113 
    114 
    115 void
    116 elf_read_syms(struct elf_syms *elfsymsp, int infile,
    117 	 off_t symoff, off_t symsize, off_t stroff, off_t strsize);
    118 
    119 
    120 int
    121 main (int argc, char **argv, char **envp)
    122 {
    123   Elf32_Ehdr ex;
    124   Elf32_Phdr *ph;
    125   Elf32_Shdr *sh;
    126   char *shstrtab;
    127   int strtabix, symtabix;
    128   int i, pad;
    129   struct sect text, data, bss;		/* a.out-compatible sections */
    130   struct sect rdata, sdata, sbss; 	/* ECOFF-only sections */
    131 
    132   struct ecoff_exechdr ep;
    133   struct ecoff_scnhdr esecs [6];
    134   struct ecoff_symhdr symhdr;
    135 
    136   int infile, outfile;
    137   unsigned long cur_vma = ULONG_MAX;
    138   int symflag = 0;
    139   int nsecs = 0;
    140 
    141   text.len = data.len = bss.len = 0;
    142   text.vaddr = data.vaddr = bss.vaddr = 0;
    143 
    144   rdata.len = sdata.len = sbss.len = 0;
    145   rdata.vaddr = sdata.vaddr = sbss.vaddr = 0;
    146 
    147   /* Check args... */
    148   if (argc < 3 || argc > 4)
    149     {
    150     usage:
    151       fprintf (stderr,
    152 	       "usage: elf2ecoff <elf executable> <ECOFF executable> [-s]\n");
    153       exit (1);
    154     }
    155   if (argc == 4)
    156     {
    157       if (strcmp (argv [3], "-s"))
    158 	goto usage;
    159       symflag = 1;
    160     }
    161 
    162   /* Try the input file... */
    163   if ((infile = open (argv [1], O_RDONLY)) < 0)
    164     {
    165       fprintf (stderr, "Can't open %s for read: %s\n",
    166 	       argv [1], strerror (errno));
    167       exit (1);
    168     }
    169 
    170   /* Read the header, which is at the beginning of the file... */
    171   i = read (infile, &ex, sizeof ex);
    172   if (i != sizeof ex)
    173     {
    174       fprintf (stderr, "ex: %s: %s.\n",
    175 	       argv [1], i ? strerror (errno) : "End of file reached");
    176       exit (1);
    177     }
    178 
    179   /* Read the program headers... */
    180   ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
    181 				ex.e_phnum * sizeof (Elf32_Phdr), "ph");
    182   /* Read the section headers... */
    183   sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
    184 				ex.e_shnum * sizeof (Elf32_Shdr), "sh");
    185   /* Read in the section string table. */
    186   shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
    187 		       sh [ex.e_shstrndx].sh_size, "shstrtab");
    188   /* Read in the section string table. */
    189   shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
    190 		       sh [ex.e_shstrndx].sh_size, "shstrtab");
    191 
    192 
    193   /* Look for the symbol table and string table...
    194      Also map section indices to symbol types for a.out */
    195   symtabix = 0;
    196   strtabix = 0;
    197   for (i = 0; i < ex.e_shnum; i++)
    198     {
    199       char *name = shstrtab + sh [i].sh_name;
    200       if (!strcmp (name, ".symtab"))
    201 	symtabix = i;
    202       else if (!strcmp (name, ".strtab"))
    203 	strtabix = i;
    204 
    205     }
    206 
    207   /* Figure out if we can cram the program header into an ECOFF
    208      header...  Basically, we can't handle anything but loadable
    209      segments, but we can ignore some kinds of segments.  We can't
    210      handle holes in the address space.  Segments may be out of order,
    211      so we sort them first. */
    212 
    213   qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr),
    214 	( int (*)(const void *, const void *))phcmp);
    215 
    216   for (i = 0; i < ex.e_phnum; i++)
    217     {
    218       /* Section types we can ignore... */
    219       if (ph [i].p_type == Elf_pt_null || ph [i].p_type == Elf_pt_note ||
    220 	  ph [i].p_type == Elf_pt_phdr ||
    221 	  ph [i].p_type == Elf_pt_mips_reginfo) {
    222 
    223 	  if (debug) {
    224 	    fprintf(stderr,"  skipping PH %d type %d flags 0x%x\n",
    225                     i, ph[i].p_type, ph[i].p_flags);
    226 	   }
    227 	   continue;
    228 	}
    229 
    230       /* Section types we can't handle... */
    231       else if (ph [i].p_type != Elf_pt_load)
    232         {
    233 	  fprintf (stderr, "Program header %d type %d can't be converted.\n",
    234 		   i, ph[i].p_type);
    235 	  exit (1);
    236 	}
    237       /* Writable (data) segment? */
    238       if (ph [i].p_flags & PF_W)
    239 	{
    240 	  struct sect ndata, nbss;
    241 
    242 	  ndata.vaddr = ph [i].p_vaddr;
    243 	  ndata.len = ph [i].p_filesz;
    244 	  nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
    245 	  nbss.len = ph [i].p_memsz - ph [i].p_filesz;
    246 
    247 	  if (debug) {
    248 	    fprintf(stderr,
    249 	"  combinining PH %d type %d flags 0x%x with data, ndata = %ld, nbss =%ld\n", i, ph[i].p_type, ph[i].p_flags, ndata.len, nbss.len);
    250 	  }
    251 
    252 	  combine (&data, &ndata, 0);
    253 	  combine (&bss, &nbss, 1);
    254 	}
    255       else
    256 	{
    257 	  struct sect ntxt;
    258 
    259 	  ntxt.vaddr = ph [i].p_vaddr;
    260 	  ntxt.len = ph [i].p_filesz;
    261 	  if (debug) {
    262 
    263 	    fprintf(stderr,
    264 	       "  combinining PH %d type %d flags 0x%x with text, len = %ld\n",
    265 		 i, ph[i].p_type, ph[i].p_flags, ntxt.len);
    266 	  }
    267 
    268 
    269 	  combine (&text, &ntxt, 0);
    270 	}
    271       /* Remember the lowest segment start address. */
    272       if (ph [i].p_vaddr < cur_vma)
    273 	cur_vma = ph [i].p_vaddr;
    274     }
    275 
    276   /* Sections must be in order to be converted... */
    277   if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
    278       text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
    279     {
    280       fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
    281       exit (1);
    282     }
    283 
    284   /* If there's a data section but no text section, then the loader
    285      combined everything into one section.   That needs to be the
    286      text section, so just make the data section zero length following
    287      text. */
    288   if (data.len && !text.len)
    289     {
    290       text = data;
    291       data.vaddr = text.vaddr + text.len;
    292       data.len = 0;
    293     }
    294 
    295   /* If there is a gap between text and data, we'll fill it when we copy
    296      the data, so update the length of the text segment as represented in
    297      a.out to reflect that, since a.out doesn't allow gaps in the program
    298      address space. */
    299   if (text.vaddr + text.len < data.vaddr)
    300     text.len = data.vaddr - text.vaddr;
    301 
    302   /* We now have enough information to cons up an a.out header... */
    303   ep.a.magic = ECOFF_OMAGIC;
    304   ep.a.vstamp =  2 * 256 + 10;	/* compatible with version 2.10 */
    305   ep.a.tsize = text.len;
    306   ep.a.dsize = data.len;
    307   ep.a.bsize = bss.len;
    308   ep.a.entry = ex.e_entry;
    309   ep.a.text_start = text.vaddr;
    310   ep.a.data_start = data.vaddr;
    311   ep.a.bss_start = bss.vaddr;
    312   ep.a.gprmask = 0xf3fffffe;
    313   bzero (&ep.a.cprmask, sizeof ep.a.cprmask);
    314   ep.a.gp_value = 0; /* unused. */
    315 
    316   ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
    317   ep.f.f_nscns = 6;
    318   ep.f.f_timdat = 0;	/* bogus */
    319   ep.f.f_symptr = 0;
    320   ep.f.f_nsyms = sizeof(struct ecoff_symhdr);
    321   ep.f.f_opthdr = sizeof ep.a;
    322   ep.f.f_flags = 0x100f; /* Stripped, not sharable. */
    323 
    324   bzero(esecs, sizeof(esecs));
    325 
    326   /* Make  ECOFF section headers, with empty stubs for .rdata/.sdata/.sbss. */
    327   make_ecoff_section_hdrs(&ep, esecs);
    328 
    329   nsecs = ep.f.f_nscns;
    330 
    331   /* Make the output file... */
    332   if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
    333     {
    334       fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
    335       exit (1);
    336     }
    337 
    338   /* Write the headers... */
    339   safewrite(outfile, &ep.f, sizeof (ep.f), "ep.f: write: %s\n");
    340   fprintf (stderr, "wrote %d byte file header.\n", sizeof(ep.f));
    341 
    342   safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write: %s\n");
    343   fprintf (stderr, "wrote %d byte a.out header.\n", sizeof(ep.a));
    344 
    345   safewrite(outfile, &esecs, sizeof (esecs[0]) * nsecs,
    346 	 "esecs: write: %s\n");
    347   fprintf (stderr, "wrote %d bytes of section headers.\n",
    348 	 sizeof(esecs[0])*nsecs);
    349 
    350 
    351   pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
    352   if (pad) {
    353       pad = 16 - pad;
    354       pad16(outfile, pad, "ipad: write: %s\n");
    355       fprintf (stderr, "wrote %d byte pad.\n", pad);
    356     }
    357 
    358   /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
    359      complain about any zero-filling, and die if we're asked to zero-fill
    360      more than 64k. */
    361   for (i = 0; i < ex.e_phnum; i++)
    362     {
    363       /* Unprocessable sections were handled above, so just verify that
    364 	 the section can be loaded before copying. */
    365       if (ph [i].p_type == Elf_pt_load && ph [i].p_filesz)
    366 	{
    367 	  if (cur_vma != ph [i].p_vaddr)
    368 	    {
    369 	      unsigned long gap = ph [i].p_vaddr - cur_vma;
    370 	      char obuf [1024];
    371 	      if (gap > 65536)
    372 		{
    373 		  fprintf (stderr, "Intersegment gap (%ld bytes) too large.\n",
    374 			   gap);
    375 		  exit (1);
    376 		}
    377 	      fprintf (stderr, "Warning: %ld byte intersegment gap.\n", gap);
    378 	      memset (obuf, 0, sizeof obuf);
    379 	      while (gap)
    380 		{
    381 		  int count = write (outfile, obuf, (gap > sizeof obuf
    382 						     ? sizeof obuf : gap));
    383 		  if (count < 0)
    384 		    {
    385 		      fprintf (stderr, "Error writing gap: %s\n",
    386 			       strerror (errno));
    387 		      exit (1);
    388 		    }
    389 		  gap -= count;
    390 		}
    391 	    }
    392        fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
    393 	  copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
    394 	  cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
    395 	}
    396     }
    397 
    398 
    399   if (debug)
    400        fprintf(stderr, "writing syms at offset 0x%lx\n",
    401 		 (u_long) ep.f.f_symptr + sizeof(symhdr));
    402 
    403   /* Copy and translate the symbol table... */
    404   elf_symbol_table_to_ecoff (outfile, infile, &ep,
    405 		  sh [symtabix].sh_offset, sh [symtabix].sh_size,
    406 		  sh [strtabix].sh_offset, sh [strtabix].sh_size);
    407 
    408   /*
    409    * Write a page of padding for boot PROMS that read entire pages.
    410    * Without this, they may attempt to read past the end of the
    411    * data section, incur an error, and refuse to boot.
    412    */
    413    {
    414      char obuf [4096];
    415      memset (obuf, 0, sizeof obuf);
    416      if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
    417 	fprintf(stderr, "Error writing PROM padding: %s\n",
    418 		strerror(errno));
    419 	exit(1);
    420      }
    421    }
    422 
    423   /* Looks like we won... */
    424   exit (0);
    425 }
    426 
    427 void
    428 copy (out, in, offset, size)
    429      int out, in;
    430      off_t offset, size;
    431 {
    432   char ibuf [4096];
    433   int remaining, cur, count;
    434 
    435   /* Go the the start of the ELF symbol table... */
    436   if (lseek (in, offset, SEEK_SET) < 0)
    437     {
    438       perror ("copy: lseek");
    439       exit (1);
    440     }
    441 
    442   remaining = size;
    443   while (remaining)
    444     {
    445       cur = remaining;
    446       if (cur > sizeof ibuf)
    447 	cur = sizeof ibuf;
    448       remaining -= cur;
    449       if ((count = read (in, ibuf, cur)) != cur)
    450 	{
    451 	  fprintf (stderr, "copy: read: %s\n",
    452 		   count ? strerror (errno) : "premature end of file");
    453 	  exit (1);
    454 	}
    455 
    456       safewrite(out, ibuf, cur, "copy: write: %s\n");
    457     }
    458 }
    459 
    460 /* Combine two segments, which must be contiguous.   If pad is true, it's
    461    okay for there to be padding between. */
    462 void
    463 combine (base, new, pad)
    464      struct sect *base, *new;
    465      int pad;
    466 {
    467   if (!base -> len)
    468     *base = *new;
    469   else if (new -> len)
    470     {
    471       if (base -> vaddr + base -> len != new -> vaddr)
    472 	{
    473 	  if (pad)
    474 	    base -> len = new -> vaddr - base -> vaddr;
    475 	  else
    476 	    {
    477 	      fprintf (stderr,
    478 		       "Non-contiguous data can't be converted.\n");
    479 	      exit (1);
    480 	    }
    481 	}
    482       base -> len += new -> len;
    483     }
    484 }
    485 
    486 int
    487 phcmp (h1, h2)
    488      Elf32_Phdr *h1, *h2;
    489 {
    490   if (h1 -> p_vaddr > h2 -> p_vaddr)
    491     return 1;
    492   else if (h1 -> p_vaddr < h2 -> p_vaddr)
    493     return -1;
    494   else
    495     return 0;
    496 }
    497 
    498 char
    499 *saveRead (int file, off_t offset, off_t len, char *name)
    500 {
    501   char *tmp;
    502   int count;
    503   off_t off;
    504   if ((off = lseek (file, offset, SEEK_SET)) < 0)
    505     {
    506       fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
    507       exit (1);
    508     }
    509   if (!(tmp = (char *)malloc (len)))
    510     {
    511       fprintf (stderr, "%s: Can't allocate %ld bytes.\n", name, (long)len);
    512       exit (1);
    513     }
    514   count = read (file, tmp, len);
    515   if (count != len)
    516     {
    517       fprintf (stderr, "%s: read: %s.\n",
    518 	       name, count ? strerror (errno) : "End of file reached");
    519       exit (1);
    520     }
    521   return tmp;
    522 }
    523 
    524 void
    525 safewrite(int outfile, void *buf,  off_t len, const char *msg)
    526 {
    527 	int written;
    528    	written = write (outfile, (char*)buf, len);
    529 	if (written != len) {
    530 		fprintf (stderr, msg, strerror (errno));
    531 		  exit (1);
    532 	}
    533 }
    534 
    535 
    536 /*
    537  * Output only three ECOFF sections, corresponding to ELF psecs
    538  * for text, data, and bss.
    539  */
    540 int
    541 make_ecoff_section_hdrs(ep, esecs)
    542 	struct ecoff_exechdr *ep;
    543 	struct ecoff_scnhdr *esecs;
    544 
    545 {
    546 	ep->f.f_nscns = 6;	/* XXX */
    547 
    548 	strcpy (esecs [0].s_name, ".text");
    549 	strcpy (esecs [1].s_name, ".data");
    550 	strcpy (esecs [2].s_name, ".bss");
    551 
    552 	esecs [0].s_paddr = esecs [0].s_vaddr = ep->a.text_start;
    553 	esecs [1].s_paddr = esecs [1].s_vaddr = ep->a.data_start;
    554 	esecs [2].s_paddr = esecs [2].s_vaddr = ep->a.bss_start;
    555 	esecs [0].s_size = ep->a.tsize;
    556 	esecs [1].s_size = ep->a.dsize;
    557 	esecs [2].s_size = ep->a.bsize;
    558 
    559 	esecs [0].s_scnptr = ECOFF_TXTOFF (ep);
    560 	esecs [1].s_scnptr = ECOFF_DATOFF (ep);
    561 #if 0
    562 	esecs [2].s_scnptr = esecs [1].s_scnptr +
    563 	      ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (ep));
    564 #endif
    565 
    566 	esecs [0].s_relptr = esecs [1].s_relptr = esecs [2].s_relptr = 0;
    567 	esecs [0].s_lnnoptr = esecs [1].s_lnnoptr = esecs [2].s_lnnoptr = 0;
    568 	esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
    569 	esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
    570 
    571 	esecs[1].s_flags = 0x100;	/* ECOFF rdata */
    572 	esecs[3].s_flags = 0x200;	/* ECOFF sdata */
    573 	esecs[4].s_flags = 0x400;	/* ECOFF sbss */
    574 
    575 	/*
    576 	 * Set the symbol-table offset  to point at the end of any
    577 	 * sections we loaded above, so later code can use it to write
    578 	 * symbol table info..
    579 	 */
    580 	ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
    581 	return(ep->f.f_nscns);
    582 }
    583 
    584 
    585 /*
    586  * Write the ECOFF symbol header.
    587  * Guess at how big the symbol table will be.
    588  * Mark all symbols as EXTERN (for now).
    589  */
    590 void
    591 write_ecoff_symhdr(out, ep, symhdrp, nesyms, extsymoff, extstroff, strsize)
    592 	int out;
    593 	struct ecoff_exechdr *ep;
    594 	struct ecoff_symhdr *symhdrp;
    595 	long nesyms, extsymoff,  extstroff, strsize;
    596 {
    597 	if (debug)
    598 	  fprintf(stderr, "writing symhdr for %ld entries at offset 0x%lx\n",
    599 		 nesyms, (u_long) ep->f.f_symptr);
    600 
    601 	ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
    602 
    603 	bzero(symhdrp, sizeof(*symhdrp));
    604 	symhdrp->esymMax = nesyms;
    605 	symhdrp->magic = 0x7009;	/* XXX */
    606 	symhdrp->cbExtOffset = extsymoff;
    607 	symhdrp->cbSsExtOffset = extstroff;
    608 
    609 	symhdrp->issExtMax = strsize;
    610 	if (debug)
    611 		fprintf(stderr,
    612 		    "ECOFF symhdr: symhdr %x, strsize %lx, symsize %lx\n",
    613 		    sizeof(*symhdrp), strsize,
    614 		    (nesyms * sizeof(struct ecoff_extsym)));
    615 
    616 	safewrite(out, symhdrp, sizeof(*symhdrp),
    617 	    "writing symbol header: %s\n");
    618 }
    619 
    620 
    621 void
    622 elf_read_syms(elfsymsp, in, symoff, symsize, stroff, strsize)
    623 	struct elf_syms *elfsymsp;
    624 	int in;
    625 	off_t symoff, symsize;
    626 	off_t stroff, strsize;
    627 {
    628 	register int nsyms;
    629 	nsyms = symsize / sizeof (Elf32_Sym);
    630 
    631 	/* Suck in the ELF symbol list... */
    632 	elfsymsp->elf_syms = (Elf32_Sym *)
    633 	    saveRead(in, symoff, nsyms * sizeof (Elf32_Sym),
    634 		     "ELF symboltable");
    635 	elfsymsp->nsymbols = nsyms;
    636 
    637 	/* Suck in the ELF string table... */
    638 	elfsymsp->stringtab = (char *)
    639 	     saveRead (in, stroff, strsize, "ELF string table");
    640 	elfsymsp->stringsize = strsize;
    641 }
    642 
    643 
    644 /*
    645  *
    646  */
    647 void
    648 elf_symbol_table_to_ecoff(out, in, ep, symoff, symsize, stroff, strsize)
    649 	int out, in;
    650 	struct ecoff_exechdr *ep;
    651 	off_t symoff, symsize;
    652 	off_t stroff, strsize;
    653 {
    654 
    655 	struct elf_syms elfsymtab;
    656 	struct ecoff_syms ecoffsymtab;
    657 	register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
    658 	register u_long nextoff, symtabsize, ecoff_strsize;
    659 	int nsyms;
    660 	struct ecoff_symhdr symhdr;
    661 	int padding;
    662 
    663 	/* Read in the ELF symbols. */
    664 	elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
    665 
    666 	/* Approximate translation to ECOFF. */
    667 	translate_syms(&elfsymtab, &ecoffsymtab);
    668 	nsyms = ecoffsymtab.nsymbols;
    669 
    670     	/* Compute output ECOFF symbol- and string-table offsets. */
    671 	ecoff_symhdr_off = ep->f.f_symptr;
    672 
    673 	nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
    674 	stringtaboff = nextoff;
    675 	ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
    676 		(ECOFF_SEGMENT_ALIGNMENT(ep)));
    677 
    678 
    679 	nextoff = stringtaboff + ecoff_strsize;
    680 	symtaboff = nextoff;
    681 	symtabsize = nsyms * sizeof(struct ecoff_extsym);
    682 	symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
    683 
    684 	/* Write out the symbol header ... */
    685 	write_ecoff_symhdr(out, ep,  &symhdr, nsyms, symtaboff,
    686 			 stringtaboff, ecoffsymtab.stringsize);
    687 
    688 	/* Write out the string table... */
    689 	padding = ecoff_strsize - ecoffsymtab.stringsize;
    690     	safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
    691 		   "string table: write: %s\n");
    692 	if (padding)
    693 		pad16(out, padding, "string table: padding: %s\n");
    694 
    695 
    696 	/* Write out the symbol table... */
    697 	padding = symtabsize  - (nsyms * sizeof(struct ecoff_extsym));
    698     	safewrite (out, ecoffsymtab.ecoff_syms,
    699 	    nsyms * sizeof(struct ecoff_extsym),
    700 	    "symbol table: write: %s\n");
    701 	if (padding)
    702 		pad16(out, padding, "symbols: padding: %s\n");
    703 }
    704 
    705 
    706 
    707 /*
    708  * In-memory translation of ELF symbosl to ECOFF.
    709  */
    710 void
    711 translate_syms (elfp, ecoffp)
    712 	struct elf_syms *elfp;
    713 	struct ecoff_syms *ecoffp;
    714 {
    715 
    716   int i;
    717   char *oldstringbase;
    718   char *newstrings, *nsp;
    719 
    720   int nsyms, idx;
    721 
    722   nsyms = elfp->nsymbols;
    723   oldstringbase = elfp->stringtab;
    724 
    725   /* Allocate space for corresponding ECOFF symbols. */
    726   bzero(ecoffp, sizeof(*ecoffp));
    727 
    728   ecoffp->nsymbols = 0;
    729   ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
    730 
    731   /* we are going to be no bigger than the ELF symbol table. */
    732   ecoffp->stringsize = elfp->stringsize;
    733   ecoffp->stringtab = malloc(elfp->stringsize);
    734 
    735   newstrings = (char *)ecoffp->stringtab;
    736   nsp = (char *)ecoffp->stringtab;
    737   if (!newstrings)
    738     {
    739       fprintf (stderr, "No memory for new string table!\n");
    740       exit (1);
    741     }
    742 
    743   /* Copy and translate  symbols... */
    744   idx = 0;
    745   for (i = 0 ; i < nsyms; i++) {
    746 	  int binding, type;
    747 
    748 	  binding = ELF_SYM_BIND((elfp->elf_syms[i].st_info));
    749 	  type = ELF_SYM_TYPE((elfp->elf_syms[i].st_info));
    750 
    751 	/* skip strange symbols */
    752 	  if  (binding == 0) {
    753 	       continue;
    754 	  }
    755 
    756 	  /* Copy the symbol into the new table */
    757 	  strcpy (nsp, oldstringbase + elfp->elf_syms [i].st_name);
    758 	  ecoffp->ecoff_syms [idx].es_strindex = nsp - newstrings;
    759 	  nsp += strlen (nsp) + 1;
    760 
    761 	   /* translate symbol types to ECOFF XXX */
    762 	   ecoffp->ecoff_syms[idx].es_type = 1;
    763 	   ecoffp->ecoff_syms[idx].es_class = 5;
    764 
    765 	  /* Symbol values in executables should be compatible. */
    766 	  ecoffp->ecoff_syms [idx].es_value = elfp->elf_syms [i].st_value;
    767 	  ecoffp->ecoff_syms [idx].es_symauxindex = 0xfffff;
    768 
    769 	  idx++;
    770 	}
    771 
    772     ecoffp->nsymbols = idx;
    773     ecoffp->stringsize = nsp - newstrings;
    774 }
    775 
    776 /*
    777  * pad to a 16-byte boundary
    778  */
    779 void
    780 pad16(int fd, int size, const char *msg)
    781 {
    782   	safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size,  msg);
    783 }
    784