import of elf2aout - required for the pmax and taken from the NetBSD
authorgraichen <graichen@openbsd.org>
Sun, 22 Dec 1996 15:03:32 +0000 (15:03 +0000)
committergraichen <graichen@openbsd.org>
Sun, 22 Dec 1996 15:03:32 +0000 (15:03 +0000)
elftools - adapted to OpenBSD by me

usr.bin/elf2aout/Makefile [new file with mode: 0644]
usr.bin/elf2aout/elf2aout.1 [new file with mode: 0644]
usr.bin/elf2aout/elf2aout.c [new file with mode: 0644]

diff --git a/usr.bin/elf2aout/Makefile b/usr.bin/elf2aout/Makefile
new file mode 100644 (file)
index 0000000..20eae64
--- /dev/null
@@ -0,0 +1,5 @@
+#      $OpenBSD: Makefile,v 1.1.1.1 1996/12/22 15:03:32 graichen Exp $
+
+PROG=  elf2aout
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/elf2aout/elf2aout.1 b/usr.bin/elf2aout/elf2aout.1
new file mode 100644 (file)
index 0000000..f7dc58b
--- /dev/null
@@ -0,0 +1,57 @@
+.\"    $OpenBSD: elf2aout.1,v 1.1.1.1 1996/12/22 15:03:32 graichen Exp $
+.\"
+.\" Copyright (c) 1996 Per Fogelstrom
+.\" 
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed under OpenBSD by
+.\"    Per Fogelstrom.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"
+.Dd Octobert 2, 1996
+.Dt ELF2AOUT 1
+.Os
+.Sh NAME
+.Nm elf2aout
+.Nd convert elf executable to a.out format
+.Sh SYNOPSIS
+.Nm elf2aout
+.Op Ar elfexec
+.Oo
+.Ar ecoffexec
+.Oc
+.Sh DESCRIPTION
+.Nm elf2aout
+reads and convert the file specified as
+.Ar elfexec
+to a.out format, into file
+.Ar ecoffexec
+, suitable for bootstrapping certain
+.Nm MIPS
+systems. Systems requiering this
+conversion is the
+.Nm pmax.
+.Sh DIAGNOSTICS
+If the conversion fails a diagnostic message is printed to explain the cause.
diff --git a/usr.bin/elf2aout/elf2aout.c b/usr.bin/elf2aout/elf2aout.c
new file mode 100644 (file)
index 0000000..09f56a7
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 1995
+ *     Ted Lemon (hereinafter referred to as the author)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf_abi.h>
+#include <machine/elf_abi.h>
+#include <stdio.h>
+#include <a.out.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <limits.h>
+
+#define SHN_MIPS_ACOMMON 0xfff0
+
+extern char *__progname;
+
+struct sect {
+  unsigned long vaddr;
+  unsigned long len;
+};
+int phcmp ();
+char *saveRead (int file, off_t offset, off_t len, char *name);
+int copy (int, int, off_t, off_t);
+int translate_syms (int, int, off_t, off_t, off_t, off_t);
+extern int errno;
+int *symTypeTable;
+
+/* Symbol table entry... */
+struct sym {
+  unsigned long name;           /* Index into strtab of symbol name. */
+  unsigned long value;          /* Section offset, virt addr or common align. */
+  unsigned long size;           /* Size of object referenced. */
+  unsigned type    : 4;         /* Symbol type (e.g., function, data)... */
+  unsigned binding : 4;         /* Symbol binding (e.g., global, local)... */
+  unsigned char other;          /* Unused. */
+  unsigned short shndx;         /* Section containing symbol. */
+};
+
+struct phdr {
+  unsigned long type;           /* Segment type... */
+  unsigned long offset;         /* File offset... */
+  unsigned long vaddr;          /* Virtual address... */
+  unsigned long paddr;          /* Physical address... */
+  unsigned long filesz;         /* Size of segment in file... */
+  unsigned long memsz;          /* Size of segment in memory... */
+  unsigned long flags;          /* Segment flags... */
+  unsigned long align;          /* Alighment, file and memory... */
+};
+
+main (int argc, char **argv, char **envp)
+{
+  Elf32_Ehdr ex;
+  Elf32_Phdr *ph;
+  Elf32_Shdr *sh;
+  struct sym *symtab;
+  char *shstrtab;
+  int strtabix, symtabix;
+  int i;
+  struct sect text, data, bss;
+  struct exec aex;
+  int infile, outfile;
+  unsigned long cur_vma = ULONG_MAX;
+  int symflag = 0;
+
+  text.len = data.len = bss.len = 0;
+  text.vaddr = data.vaddr = bss.vaddr = 0;
+
+  /* Check args... */
+  if (argc < 3 || argc > 4)
+    {
+    usage:
+      fprintf (stderr,
+              "usage: %s <elf executable> <a.out executable>\n", __progname);
+      exit (1);
+    }
+
+  /* Try the input file... */
+  if ((infile = open (argv [1], O_RDONLY)) < 0)
+    {
+      fprintf (stderr, "Can't open %s for read: %s\n",
+              argv [1], strerror (errno));
+      exit (1);
+    }
+
+  /* Read the header, which is at the beginning of the file... */
+  i = read (infile, &ex, sizeof ex);
+  if (i != sizeof ex)
+    {
+      fprintf (stderr, "ex: %s: %s.\n",
+              argv [1], i ? strerror (errno) : "End of file reached");
+      exit (1);
+    }
+
+  /* Read the program headers... */
+  ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
+                               ex.e_phnum * sizeof (Elf32_Phdr), "ph");
+  /* Read the section headers... */
+  sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
+                               ex.e_shnum * sizeof (Elf32_Shdr), "sh");
+  /* Read in the section string table. */
+  shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
+                      sh [ex.e_shstrndx].sh_size, "shstrtab");
+
+  /* Find space for a table matching ELF section indices to a.out symbol
+     types. */
+  symTypeTable = (int *)malloc (ex.e_shnum * sizeof (int));
+  if (!symTypeTable)
+    {
+      fprintf (stderr, "symTypeTable: can't allocate.\n");
+      exit (1);
+    }
+  memset (symTypeTable, 0, ex.e_shnum * sizeof (int));
+
+  /* Look for the symbol table and string table...
+     Also map section indices to symbol types for a.out */
+  for (i = 0; i < ex.e_shnum; i++)
+    {
+      char *name = shstrtab + sh [i].sh_name;
+      if (!strcmp (name, ".symtab"))
+       symtabix = i;
+      else if (!strcmp (name, ".strtab"))
+       strtabix = i;
+      else if (!strcmp (name, ".text") || !strcmp (name, ".rodata"))
+       symTypeTable [i] = N_TEXT;
+      else if (!strcmp (name, ".data") || !strcmp (name, ".sdata") ||
+              !strcmp (name, ".lit4") || !strcmp (name, ".lit8"))
+       symTypeTable [i] = N_DATA;
+      else if (!strcmp (name, ".bss") || !strcmp (name, ".sbss"))
+       symTypeTable [i] = N_BSS;
+    }
+
+  /* Figure out if we can cram the program header into an a.out header...
+     Basically, we can't handle anything but loadable segments, but we
+     can ignore some kinds of segments.   We can't handle holes in the
+     address space, and we handle start addresses other than 0x1000 by
+     hoping that the loader will know where to load - a.out doesn't have
+     an explicit load address.   Segments may be out of order, so we
+     sort them first. */
+  qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
+  for (i = 0; i < ex.e_phnum; i++)
+    {
+      /* Section types we can ignore... */
+      if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE ||
+         ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO)
+       continue;
+      /* Section types we can't handle... */
+      else if (ph [i].p_type != PT_LOAD)
+        {
+         fprintf (stderr, "Program header %d type %d can't be converted.\n");
+         exit (1);
+       }
+      /* Writable (data) segment? */
+      if (ph [i].p_flags & PF_W)
+       {
+         struct sect ndata, nbss;
+
+         ndata.vaddr = ph [i].p_vaddr;
+         ndata.len = ph [i].p_filesz;
+         nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
+         nbss.len = ph [i].p_memsz - ph [i].p_filesz;
+
+         combine (&data, &ndata, 0);
+         combine (&bss, &nbss, 1);
+       }
+      else
+       {
+         struct sect ntxt;
+
+         ntxt.vaddr = ph [i].p_vaddr;
+         ntxt.len = ph [i].p_filesz;
+
+         combine (&text, &ntxt);
+       }
+      /* Remember the lowest segment start address. */
+      if (ph [i].p_vaddr < cur_vma)
+       cur_vma = ph [i].p_vaddr;
+    }
+
+  /* Sections must be in order to be converted... */
+  if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
+      text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
+    {
+      fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
+      exit (1);
+    }
+
+  /* If there's a data section but no text section, then the loader
+     combined everything into one section.   That needs to be the
+     text section, so just make the data section zero length following
+     text. */
+  if (data.len && !text.len)
+    {
+      text = data;
+      data.vaddr = text.vaddr + text.len;
+      data.len = 0;
+    }
+
+  /* If there is a gap between text and data, we'll fill it when we copy
+     the data, so update the length of the text segment as represented in
+     a.out to reflect that, since a.out doesn't allow gaps in the program
+     address space. */
+  if (text.vaddr + text.len < data.vaddr)
+    text.len = data.vaddr - text.vaddr;
+
+  /* We now have enough information to cons up an a.out header... */
+  aex.a_midmag = htonl ((symflag << 26) | (MID_PMAX << 16) | OMAGIC);
+  aex.a_text = text.len;
+  aex.a_data = data.len;
+  aex.a_bss = bss.len;
+  aex.a_entry = ex.e_entry;
+  aex.a_syms = (sizeof (struct nlist) *
+               (symtabix != -1
+                ? sh [symtabix].sh_size / sizeof (struct sym) : 0));
+  aex.a_trsize = 0;
+  aex.a_drsize = 0;
+
+  /* Make the output file... */
+  if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
+    {
+      fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
+      exit (1);
+    }
+  /* Write the header... */
+  i = write (outfile, &aex, sizeof aex);
+  if (i != sizeof aex)
+    {
+      perror ("aex: write");
+      exit (1);
+    }
+
+  /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
+     complain about any zero-filling, and die if we're asked to zero-fill
+     more than 64k. */
+  for (i = 0; i < ex.e_phnum; i++)
+    {
+      /* Unprocessable sections were handled above, so just verify that
+        the section can be loaded before copying. */
+      if (ph [i].p_type == PT_LOAD && ph [i].p_filesz)
+       {
+         if (cur_vma != ph [i].p_vaddr)
+           {
+             unsigned long gap = ph [i].p_vaddr - cur_vma;
+             char obuf [1024];
+             if (gap > 65536)
+               {
+                 fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
+                          gap);
+                 exit (1);
+               }
+             fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
+             memset (obuf, 0, sizeof obuf);
+             while (gap)
+               {
+                 int count = write (outfile, obuf, (gap > sizeof obuf
+                                                    ? sizeof obuf : gap));
+                 if (count < 0)
+                   {
+                     fprintf (stderr, "Error writing gap: %s\n",
+                              strerror (errno));
+                     exit (1);
+                   }
+                 gap -= count;
+               }
+           }
+         copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
+         cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
+       }
+    }
+
+  /* Copy and translate the symbol table... */
+  translate_syms (outfile, infile, sh [symtabix].sh_offset,
+                  sh [symtabix].sh_size,
+                 sh [strtabix].sh_offset, sh [strtabix].sh_size);
+
+  /* Looks like we won... */
+  exit (0);
+}
+
+/* translate_syms (out, in, offset, size)
+
+   Read the ELF symbol table from in at offset; translate it into a.out
+   nlist format and write it to out. */
+
+translate_syms (out, in, symoff, symsize, stroff, strsize)
+     int out, in;
+     off_t symoff, symsize;
+     off_t stroff, strsize;
+{
+# define SYMS_PER_PASS 64
+  struct sym inbuf [64];
+  struct nlist outbuf [64];
+  int i, remaining, cur;
+  char *oldstrings;
+  char *newstrings, *nsp;
+  int newstringsize;
+
+  /* Zero the unused fields in the output buffer.. */
+  memset (outbuf, 0, sizeof outbuf);
+
+  /* Find number of symbols to process... */
+  remaining = symsize / sizeof (struct sym);
+
+  /* Suck in the old string table... */
+  oldstrings = saveRead (in, stroff, strsize, "string table");
+
+  /* Allocate space for the new one.   XXX We make the wild assumption that
+     no two symbol table entries will point at the same place in the
+     string table - if that assumption is bad, this could easily blow up. */
+  newstringsize = strsize + remaining;
+  newstrings = (char *)malloc (newstringsize);
+  if (!newstrings)
+    {
+      fprintf (stderr, "No memory for new string table!\n");
+      exit (1);
+    }
+  /* Initialize the table pointer... */
+  nsp = newstrings;
+
+  /* Go the the start of the ELF symbol table... */
+  if (lseek (in, symoff, SEEK_SET) < 0)
+    {
+      perror ("translate_syms: lseek");
+      exit (1);
+    }
+
+  /* Translate and copy symbols... */
+  while (remaining)
+    {
+      cur = remaining;
+      if (cur > SYMS_PER_PASS)
+       cur = SYMS_PER_PASS;
+      remaining -= cur;
+      if ((i = read (in, inbuf, cur * sizeof (struct sym)))
+         != cur * sizeof (struct sym))
+       {
+         if (i < 0)
+           perror ("translate_syms");
+         else
+           fprintf (stderr, "translate_syms: premature end of file.\n");
+         exit (1);
+       }
+
+      /* Do the translation... */
+      for (i = 0; i < cur; i++)
+       {
+         /* Copy the symbol into the new table, but prepend an underscore. */
+         *nsp = '_';
+         strcpy (nsp + 1, oldstrings + inbuf [i].name);
+         outbuf [i].n_un.n_strx = nsp - newstrings + 4;
+         nsp += strlen (nsp) + 1;
+
+         /* Convert ELF symbol type/section/etc info into a.out type info. */
+         if (inbuf [i].type == STT_FILE)
+           outbuf [i].n_type = N_FN;
+         else if (inbuf [i].shndx == SHN_UNDEF)
+           outbuf [i].n_type = N_UNDF;
+         else if (inbuf [i].shndx == SHN_ABS)
+           outbuf [i].n_type = N_ABS;
+         else if (inbuf [i].shndx == SHN_COMMON ||
+                inbuf [i].shndx == SHN_MIPS_ACOMMON)
+           outbuf [i].n_type = N_COMM;
+         else
+           outbuf [i].n_type = symTypeTable [inbuf [i].shndx];
+         if (inbuf [i].binding == STB_GLOBAL)
+           outbuf [i].n_type |= N_EXT;
+         /* Symbol values in executables should be compatible. */
+         outbuf [i].n_value = inbuf [i].value;
+       }
+      /* Write out the symbols... */
+      if ((i = write (out, outbuf, cur * sizeof (struct nlist)))
+         != cur * sizeof (struct nlist))
+       {
+         fprintf (stderr, "translate_syms: write: %s\n", strerror (errno));
+         exit (1);
+       }
+    }
+  /* Write out the string table length... */
+  if (write (out, &newstringsize, sizeof newstringsize)
+      != sizeof newstringsize)
+    {
+      fprintf (stderr,
+              "translate_syms: newstringsize: %s\n", strerror (errno));
+      exit (1);
+    }
+  /* Write out the string table... */
+  if (write (out, newstrings, newstringsize) != newstringsize)
+    {
+      fprintf (stderr, "translate_syms: newstrings: %s\n", strerror (errno));
+      exit (1);
+    }
+}
+      
+copy (out, in, offset, size)
+     int out, in;
+     off_t offset, size;
+{
+  char ibuf [4096];
+  int remaining, cur, count;
+
+  /* Go the the start of the ELF symbol table... */
+  if (lseek (in, offset, SEEK_SET) < 0)
+    {
+      perror ("copy: lseek");
+      exit (1);
+    }
+
+  remaining = size;
+  while (remaining)
+    {
+      cur = remaining;
+      if (cur > sizeof ibuf)
+       cur = sizeof ibuf;
+      remaining -= cur;
+      if ((count = read (in, ibuf, cur)) != cur)
+       {
+         fprintf (stderr, "copy: read: %s\n",
+                  count ? strerror (errno) : "premature end of file");
+         exit (1);
+       }
+      if ((count = write (out, ibuf, cur)) != cur)
+       {
+         perror ("copy: write");
+         exit (1);
+       }
+    }
+}
+
+/* Combine two segments, which must be contiguous.   If pad is true, it's
+   okay for there to be padding between. */
+combine (base, new, pad)
+     struct sect *base, *new;
+     int pad;
+{
+  if (!base -> len)
+    *base = *new;
+  else if (new -> len)
+    {
+      if (base -> vaddr + base -> len != new -> vaddr)
+       {
+         if (pad)
+           base -> len = new -> vaddr - base -> vaddr;
+         else
+           {
+             fprintf (stderr,
+                      "Non-contiguous data can't be converted.\n");
+             exit (1);
+           }
+       }
+      base -> len += new -> len;
+    }
+}
+
+phcmp (h1, h2)
+     struct phdr *h1, *h2;
+{
+  if (h1 -> vaddr > h2 -> vaddr)
+    return 1;
+  else if (h1 -> vaddr < h2 -> vaddr)
+    return -1;
+  else
+    return 0;
+}
+
+char *saveRead (int file, off_t offset, off_t len, char *name)
+{
+  char *tmp;
+  int count;
+  off_t off;
+  if ((off = lseek (file, offset, SEEK_SET)) < 0)
+    {
+      fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
+      exit (1);
+    }
+  if (!(tmp = (char *)malloc (len)))
+    {
+      fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
+      exit (1);
+    }
+  count = read (file, tmp, len);
+  if (count != len)
+    {
+      fprintf (stderr, "%s: read: %s.\n",
+              name, count ? strerror (errno) : "End of file reached");
+      exit (1);
+    }
+  return tmp;
+}