[BACK]Return to elf2ecoff.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / elf2ecoff

Diff for /src/usr.bin/elf2ecoff/Attic/elf2ecoff.c between version 1.2 and 1.3

version 1.2, 1997/10/13 20:08:21 version 1.3, 2003/04/15 08:33:34
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $OpenBSD$     */
 /*      $NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $   */  /* $NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $         */
   
 /*  /*
  * Copyright (c) 1997 Jonathan Stone   * Copyright (c) 1997 Jonathan Stone
Line 31 
Line 31 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 /* elf2ecoff.c  /*
    * elf2ecoff.c
    *
    * This program converts an elf executable to an ECOFF executable. No symbol
    * table is retained.   This is useful primarily in building net-bootable
    * kernels for machines (e.g., DECstation and Alpha) which only support the
    * ECOFF object file format.
    */
   
    This program converts an elf executable to an ECOFF executable.  
    No symbol table is retained.   This is useful primarily in building  
    net-bootable kernels for machines (e.g., DECstation and Alpha) which  
    only support the ECOFF object file format. */  
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <unistd.h>  #include <unistd.h>
Line 49 
Line 51 
 #include <string.h>  #include <string.h>
 #include <limits.h>  #include <limits.h>
   
 extern char *__progname;  extern char    *__progname;
   
 struct sect {  struct sect {
   unsigned long vaddr;          unsigned long   vaddr;
   unsigned long len;          unsigned long   len;
 };  };
   
 int phcmp ();  int     phcmp();
 char *saveRead (int file, off_t offset, off_t len, char *name);  char    *saveRead(int file, off_t offset, off_t len, char *name);
 int copy (int, int, off_t, off_t);  int     copy(int, int, off_t, off_t);
 int translate_syms (int, int, off_t, off_t, off_t, off_t);  int     translate_syms(int, int, off_t, off_t, off_t, off_t);
 extern int errno;  int     *symTypeTable;
 int *symTypeTable;  
   
 main (int argc, char **argv, char **envp)  int
   main(int argc, char *argv[])
 {  {
   Elf32_Ehdr ex;          Elf32_Ehdr      ex;
   Elf32_Phdr *ph;          Elf32_Phdr     *ph;
   Elf32_Shdr *sh;          Elf32_Shdr     *sh;
   struct sym *symtab;          struct sym     *symtab;
   char *shstrtab;          char       *shstrtab;
   int strtabix, symtabix;          int          strtabix, symtabix;
   int i, pad;          int          i, pad;
   struct sect text, data, bss;          struct sect     text, data, bss;
   struct ecoff_exechdr eh;          struct ecoff_exechdr eh;
   struct ecoff_scnhdr esecs [3];          struct ecoff_scnhdr esecs[3];
   int infile, outfile;          int          infile, outfile;
   unsigned long cur_vma = ULONG_MAX;          unsigned long   cur_vma = ULONG_MAX;
   
   text.len = data.len = bss.len = 0;          text.len = data.len = bss.len = 0;
   text.vaddr = data.vaddr = bss.vaddr = 0;          text.vaddr = data.vaddr = bss.vaddr = 0;
   
   /* Check args... */          /* Check args... */
   if (argc < 3 || argc > 4)          if (argc < 3 || argc > 4) {
     {  usage:
     usage:                  fprintf(stderr,
       fprintf (stderr,                      "usage: %s <elf executable> <ecoff executable>\n", __progname);
                "usage: %s <elf executable> <ecoff executable>\n", __progname);                  exit(1);
       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");
   
   /* Try the input file... */          /*
   if ((infile = open (argv [1], O_RDONLY)) < 0)           * Figure out if we can cram the program header into an ECOFF
     {           * header...  Basically, we can't handle anything but loadable
       fprintf (stderr, "Can't open %s for read: %s\n",           * segments, but we can ignore some kinds of segments.  We can't
                argv [1], strerror (errno));           * handle holes in the address space.  Segments may be out of order,
       exit (1);           * so we sort them first.
     }           */
   
   /* Read the header, which is at the beginning of the file... */          qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
   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... */          for (i = 0; i < ex.e_phnum; i++) {
   ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,                  /* Section types we can ignore... */
                                 ex.e_phnum * sizeof (Elf32_Phdr), "ph");                  if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
   /* Read the section headers... */                      ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
   sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,                          continue;
                                 ex.e_shnum * sizeof (Elf32_Shdr), "sh");                  /* Section types we can't handle... */
   /* Read in the section string table. */                  else if (ph[i].p_type != PT_LOAD) {
   shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,                          fprintf(stderr,
                        sh [ex.e_shstrndx].sh_size, "shstrtab");                              "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;
   
   /* Figure out if we can cram the program header into an ECOFF                          ndata.vaddr = ph[i].p_vaddr;
      header...  Basically, we can't handle anything but loadable                          ndata.len = ph[i].p_filesz;
      segments, but we can ignore some kinds of segments.  We can't                          nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
      handle holes in the address space.  Segments may be out of order,                          nbss.len = ph[i].p_memsz - ph[i].p_filesz;
      so we sort them first. */  
   
   qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);                          combine(&data, &ndata, 0);
                           combine(&bss, &nbss, 1);
                   } else {
                           struct sect     ntxt;
   
   for (i = 0; i < ex.e_phnum; i++)                          ntxt.vaddr = ph[i].p_vaddr;
     {                          ntxt.len = ph[i].p_filesz;
       /* Section types we can ignore... */                          combine(&text, &ntxt);
       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)                  /* Remember the lowest segment start address. */
         continue;                  if (ph[i].p_vaddr < cur_vma)
       /* Section types we can't handle... */                          cur_vma = ph[i].p_vaddr;
       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;          /* Sections must be in order to be converted... */
           ndata.len = ph [i].p_filesz;          if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
           nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;              text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
           nbss.len = ph [i].p_memsz - ph [i].p_filesz;                  fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
                   exit(1);
           combine (&data, &ndata, 0);  
           combine (&bss, &nbss, 1);  
         }          }
       else          /*
         {           * If there's a data section but no text section, then the loader
           struct sect ntxt;           * combined everything into one section.   That needs to be the text
            * section, so just make the data section zero length following text.
           ntxt.vaddr = ph [i].p_vaddr;           */
           ntxt.len = ph [i].p_filesz;          if (data.len && !text.len) {
                   text = data;
           combine (&text, &ntxt);                  data.vaddr = text.vaddr + text.len;
                   data.len = 0;
         }          }
       /* Remember the lowest segment start address. */          /*
       if (ph [i].p_vaddr < cur_vma)           * If there is a gap between text and data, we'll fill it when we
         cur_vma = ph [i].p_vaddr;           * 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;
   
   /* Sections must be in order to be converted... */          /* We now have enough information to cons up an a.out header... */
   if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||          eh.a.magic = ECOFF_OMAGIC;
       text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)          eh.a.vstamp = 200;
     {          eh.a.tsize = text.len;
       fprintf (stderr, "Sections ordering prevents a.out conversion.\n");          eh.a.dsize = data.len;
       exit (1);          eh.a.bsize = bss.len;
     }          eh.a.entry = ex.e_entry;
           eh.a.text_start = text.vaddr;
           eh.a.data_start = data.vaddr;
           eh.a.bss_start = bss.vaddr;
           eh.a.ea_gprmask = 0xf3fffffe;
           bzero(&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);
           eh.a.ea_gp_value = 0;   /* unused. */
   
   /* If there's a data section but no text section, then the loader          eh.f.f_magic = ECOFF_MAGIC_MIPSEL;
      combined everything into one section.   That needs to be the          eh.f.f_nscns = 3;
      text section, so just make the data section zero length following          eh.f.f_timdat = 0;      /* bogus */
      text. */          eh.f.f_symptr = 0;
   if (data.len && !text.len)          eh.f.f_nsyms = 0;
     {          eh.f.f_opthdr = sizeof eh.a;
       text = data;          eh.f.f_flags = 0x100f;  /* Stripped, not sharable. */
       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          strlcpy(esecs[0].s_name, ".text", sizeof(esecs[0].s_name));
      the data, so update the length of the text segment as represented in          strlcpy(esecs[1].s_name, ".data", sizeof(esecs[0].s_name));
      a.out to reflect that, since a.out doesn't allow gaps in the program          strlcpy(esecs[2].s_name, ".bss", sizeof(esecs[0].s_name));
      address space. */          esecs[0].s_paddr = esecs[0].s_vaddr = eh.a.text_start;
   if (text.vaddr + text.len < data.vaddr)          esecs[1].s_paddr = esecs[1].s_vaddr = eh.a.data_start;
     text.len = data.vaddr - text.vaddr;          esecs[2].s_paddr = esecs[2].s_vaddr = eh.a.bss_start;
           esecs[0].s_size = eh.a.tsize;
           esecs[1].s_size = eh.a.dsize;
           esecs[2].s_size = eh.a.bsize;
           esecs[0].s_scnptr = ECOFF_TXTOFF(&eh);
           esecs[1].s_scnptr = ECOFF_DATOFF(&eh);
           esecs[2].s_scnptr = esecs[1].s_scnptr +
               ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eh));
           esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
           esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
           esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
           esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
           esecs[0].s_flags = 0x20;
           esecs[1].s_flags = 0x40;
           esecs[2].s_flags = 0x82;
   
   /* We now have enough information to cons up an a.out header... */          /* Make the output file... */
   eh.a.magic = ECOFF_OMAGIC;          if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
   eh.a.vstamp = 200;                  fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
   eh.a.tsize = text.len;                  exit(1);
   eh.a.dsize = data.len;          }
   eh.a.bsize = bss.len;          /* Write the headers... */
   eh.a.entry = ex.e_entry;          i = write(outfile, &eh.f, sizeof(struct ecoff_filehdr));
   eh.a.text_start = text.vaddr;          if (i != sizeof(struct ecoff_filehdr)) {
   eh.a.data_start = data.vaddr;                  perror("efh: write");
   eh.a.bss_start = bss.vaddr;                  exit(1);
   eh.a.ea_gprmask = 0xf3fffffe;  
   bzero (&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);  
   eh.a.ea_gp_value = 0; /* unused. */  
   
   eh.f.f_magic = ECOFF_MAGIC_MIPSEL;                  for (i = 0; i < 6; i++) {
   eh.f.f_nscns = 3;                          printf("Section %d: %s phys %x  size %x  file offset %x\n",
   eh.f.f_timdat = 0;    /* bogus */                              i, esecs[i].s_name, esecs[i].s_paddr,
   eh.f.f_symptr = 0;                              esecs[i].s_size, esecs[i].s_scnptr);
   eh.f.f_nsyms = 0;                  }
   eh.f.f_opthdr = sizeof eh.a;          }
   eh.f.f_flags = 0x100f; /* Stripped, not sharable. */          fprintf(stderr, "wrote %d byte file header.\n", i);
   
   strcpy (esecs [0].s_name, ".text");          i = write(outfile, &eh.a, sizeof(struct ecoff_aouthdr));
   strcpy (esecs [1].s_name, ".data");          if (i != sizeof(struct ecoff_aouthdr)) {
   strcpy (esecs [2].s_name, ".bss");                  perror("eah: write");
   esecs [0].s_paddr = esecs [0].s_vaddr = eh.a.text_start;                  exit(1);
   esecs [1].s_paddr = esecs [1].s_vaddr = eh.a.data_start;          }
   esecs [2].s_paddr = esecs [2].s_vaddr = eh.a.bss_start;          fprintf(stderr, "wrote %d byte a.out header.\n", i);
   esecs [0].s_size = eh.a.tsize;  
   esecs [1].s_size = eh.a.dsize;  
   esecs [2].s_size = eh.a.bsize;  
   esecs [0].s_scnptr = ECOFF_TXTOFF (&eh);  
   esecs [1].s_scnptr = ECOFF_DATOFF (&eh);  
   esecs [2].s_scnptr = esecs [1].s_scnptr +  
           ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eh));  
   esecs [0].s_relptr = esecs [1].s_relptr = esecs [2].s_relptr = 0;  
   esecs [0].s_lnnoptr = esecs [1].s_lnnoptr = esecs [2].s_lnnoptr = 0;  
   esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;  
   esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;  
   esecs [0].s_flags = 0x20;  
   esecs [1].s_flags = 0x40;  
   esecs [2].s_flags = 0x82;  
   
   /* Make the output file... */          i = write(outfile, &esecs, sizeof esecs);
   if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)          if (i != sizeof esecs) {
     {                  perror("esecs: write");
       fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));                  exit(1);
       exit (1);          }
     }          fprintf(stderr, "wrote %d bytes of section headers.\n", i);
   
   /* Write the headers... */          if (pad = ((sizeof eh + sizeof esecs) & 15)) {
   i = write (outfile, &eh.f, sizeof(struct ecoff_filehdr));                  pad = 16 - pad;
   if (i != sizeof(struct ecoff_filehdr))                  i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
     {                  if (i < 0) {
       perror ("efh: write");                          perror("ipad: write");
       exit (1);                          exit(1);
                   }
   for (i = 0; i < 6; i++)                  fprintf(stderr, "wrote %d byte pad.\n", i);
     {  
       printf ("Section %d: %s phys %x  size %x  file offset %x\n",  
               i, esecs [i].s_name, esecs [i].s_paddr,  
               esecs [i].s_size, esecs [i].s_scnptr);  
     }  
     }  
   fprintf (stderr, "wrote %d byte file header.\n", i);  
   
   i = write (outfile, &eh.a, sizeof(struct ecoff_aouthdr));  
   if (i != sizeof(struct ecoff_aouthdr))  
     {  
       perror ("eah: write");  
       exit (1);  
     }  
   fprintf (stderr, "wrote %d byte a.out header.\n", i);  
   
   i = write (outfile, &esecs, sizeof esecs);  
   if (i != sizeof esecs)  
     {  
       perror ("esecs: write");  
       exit (1);  
     }  
   fprintf (stderr, "wrote %d bytes of section headers.\n", i);  
   
   if (pad = ((sizeof eh + sizeof esecs) & 15))  
     {  
       pad = 16 - pad;  
       i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);  
       if (i < 0)  
         {  
           perror ("ipad: write");  
           exit (1);  
         }          }
       fprintf (stderr, "wrote %d byte pad.\n", i);          /*
     }           * 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;
                                   }
                           }
                           fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
                           copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
                           cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
                   }
           }
   
   /* 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           * Write a page of padding for boot PROMS that read entire pages.
      more than 64k. */           * Without this, they may attempt to read past the end of the
   for (i = 0; i < ex.e_phnum; i++)           * data section, incur an error, and refuse to boot.
     {           */
       /* 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)                  char        obuf[4096];
             {                  memset(obuf, 0, sizeof obuf);
               unsigned long gap = ph [i].p_vaddr - cur_vma;                  if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
               char obuf [1024];                          fprintf(stderr, "Error writing PROM padding: %s\n",
               if (gap > 65536)                                  strerror(errno));
                 {                          exit(1);
                   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;  
                 }  
             }  
 fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);  
           copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);  
           cur_vma = ph [i].p_vaddr + ph [i].p_filesz;  
         }          }
     }  
   
   /*          /* Looks like we won... */
    * Write a page of padding for boot PROMS that read entire pages.          exit(0);
    * Without this, they may attempt to read past the end of the  
    * data section, incur an error, and refuse to boot.  
    */  
    {  
      char obuf [4096];  
      memset (obuf, 0, sizeof obuf);  
      if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {  
         fprintf(stderr, "Error writing PROM padding: %s\n",  
                 strerror(errno));  
         exit(1);  
      }  
    }  
   
   /* Looks like we won... */  
   exit (0);  
 }  }
   
 copy (out, in, offset, size)  copy(out, in, offset, size)
      int out, in;          int          out, in;
      off_t offset, size;          off_t      offset, size;
 {  {
   char ibuf [4096];          char        ibuf[4096];
   int remaining, cur, count;          int         remaining, cur, count;
   
   /* Go the the start of the ELF symbol table... */          /* Go the the start of the ELF symbol table... */
   if (lseek (in, offset, SEEK_SET) < 0)          if (lseek(in, offset, SEEK_SET) < 0) {
     {                  perror("copy: lseek");
       perror ("copy: lseek");                  exit(1);
       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)          remaining = size;
         {          while (remaining) {
           perror ("copy: write");                  cur = remaining;
           exit (1);                  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 two segments, which must be contiguous.   If pad is true, it's
 combine (base, new, pad)   * okay for there to be padding between.
      struct sect *base, *new;   */
      int pad;  combine(base, new, pad)
           struct sect    *base, *new;
           int          pad;
 {  {
   if (!base -> len)          if (!base->len)
     *base = *new;                  *base = *new;
   else if (new -> len)          else if (new->len) {
     {                  if (base->vaddr + base->len != new->vaddr) {
       if (base -> vaddr + base -> len != new -> vaddr)                          if (pad)
         {                                  base->len = new->vaddr - base->vaddr;
           if (pad)                          else {
             base -> len = new -> vaddr - base -> vaddr;                                  fprintf(stderr,
           else                                  "Non-contiguous data can't be converted.\n");
             {                                  exit(1);
               fprintf (stderr,                          }
                        "Non-contiguous data can't be converted.\n");                  }
               exit (1);                  base->len += new->len;
             }  
         }          }
       base -> len += new -> len;  
     }  
 }  }
   
 phcmp (h1, h2)  phcmp(h1, h2)
      Elf32_Phdr *h1, *h2;          Elf32_Phdr     *h1, *h2;
 {  {
   if (h1 -> p_vaddr > h2 -> p_vaddr)          if (h1->p_vaddr > h2->p_vaddr)
     return 1;                  return 1;
   else if (h1 -> p_vaddr < h2 -> p_vaddr)          else if (h1->p_vaddr < h2->p_vaddr)
     return -1;                  return -1;
   else          else
     return 0;                  return 0;
 }  }
   
 char *saveRead (int file, off_t offset, off_t len, char *name)  char       *
   saveRead(int file, off_t offset, off_t len, char *name)
 {  {
   char *tmp;          char       *tmp;
   int count;          int          count;
   off_t off;          off_t      off;
   if ((off = lseek (file, offset, SEEK_SET)) < 0)  
     {          if ((off = lseek(file, offset, SEEK_SET)) < 0) {
       fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));                  fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
       exit (1);                  exit(1);
     }          }
   if (!(tmp = (char *)malloc (len)))          if (!(tmp = (char *) malloc(len))) {
     {                  fprintf(stderr, "%s: Can't allocate %d bytes.\n", name, len);
       fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);                  exit(1);
       exit (1);          }
     }          count = read(file, tmp, len);
   count = read (file, tmp, len);          if (count != len) {
   if (count != len)                  fprintf(stderr, "%s: read: %s.\n",
     {                      name, count ? strerror(errno) : "End of file reached");
       fprintf (stderr, "%s: read: %s.\n",                  exit(1);
                name, count ? strerror (errno) : "End of file reached");          }
       exit (1);          return tmp;
     }  
   return tmp;  
 }  }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3