Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 1995
0003  *  Ted Lemon (hereinafter referred to as the author)
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions
0007  * are met:
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  * 3. The name of the author may not be used to endorse or promote products
0014  *    derived from this software without specific prior written permission.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
0017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0019  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
0020  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0021  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0022  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0026  * SUCH DAMAGE.
0027  */
0028 
0029 /* elf2ecoff.c
0030 
0031    This program converts an elf executable to an ECOFF executable.
0032    No symbol table is retained.   This is useful primarily in building
0033    net-bootable kernels for machines (e.g., DECstation and Alpha) which
0034    only support the ECOFF object file format. */
0035 
0036 #include <stdio.h>
0037 #include <string.h>
0038 #include <errno.h>
0039 #include <sys/types.h>
0040 #include <fcntl.h>
0041 #include <unistd.h>
0042 #include <elf.h>
0043 #include <limits.h>
0044 #include <netinet/in.h>
0045 #include <stdlib.h>
0046 #include <stdint.h>
0047 #include <inttypes.h>
0048 
0049 #include "ecoff.h"
0050 
0051 /*
0052  * Some extra ELF definitions
0053  */
0054 #define PT_MIPS_REGINFO     0x70000000  /* Register usage information */
0055 #define PT_MIPS_ABIFLAGS    0x70000003  /* Records ABI related flags  */
0056 
0057 /* -------------------------------------------------------------------- */
0058 
0059 struct sect {
0060     uint32_t vaddr;
0061     uint32_t len;
0062 };
0063 
0064 int *symTypeTable;
0065 int must_convert_endian;
0066 int format_bigendian;
0067 
0068 static void copy(int out, int in, off_t offset, off_t size)
0069 {
0070     char ibuf[4096];
0071     int remaining, cur, count;
0072 
0073     /* Go to the start of the ELF symbol table... */
0074     if (lseek(in, offset, SEEK_SET) < 0) {
0075         perror("copy: lseek");
0076         exit(1);
0077     }
0078 
0079     remaining = size;
0080     while (remaining) {
0081         cur = remaining;
0082         if (cur > sizeof ibuf)
0083             cur = sizeof ibuf;
0084         remaining -= cur;
0085         if ((count = read(in, ibuf, cur)) != cur) {
0086             fprintf(stderr, "copy: read: %s\n",
0087                 count ? strerror(errno) :
0088                 "premature end of file");
0089             exit(1);
0090         }
0091         if ((count = write(out, ibuf, cur)) != cur) {
0092             perror("copy: write");
0093             exit(1);
0094         }
0095     }
0096 }
0097 
0098 /*
0099  * Combine two segments, which must be contiguous.   If pad is true, it's
0100  * okay for there to be padding between.
0101  */
0102 static void combine(struct sect *base, struct sect *new, int pad)
0103 {
0104     if (!base->len)
0105         *base = *new;
0106     else if (new->len) {
0107         if (base->vaddr + base->len != new->vaddr) {
0108             if (pad)
0109                 base->len = new->vaddr - base->vaddr;
0110             else {
0111                 fprintf(stderr,
0112                     "Non-contiguous data can't be converted.\n");
0113                 exit(1);
0114             }
0115         }
0116         base->len += new->len;
0117     }
0118 }
0119 
0120 static int phcmp(const void *v1, const void *v2)
0121 {
0122     const Elf32_Phdr *h1 = v1;
0123     const Elf32_Phdr *h2 = v2;
0124 
0125     if (h1->p_vaddr > h2->p_vaddr)
0126         return 1;
0127     else if (h1->p_vaddr < h2->p_vaddr)
0128         return -1;
0129     else
0130         return 0;
0131 }
0132 
0133 static char *saveRead(int file, off_t offset, off_t len, char *name)
0134 {
0135     char *tmp;
0136     int count;
0137     off_t off;
0138     if ((off = lseek(file, offset, SEEK_SET)) < 0) {
0139         fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
0140         exit(1);
0141     }
0142     if (!(tmp = (char *) malloc(len))) {
0143         fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
0144             len);
0145         exit(1);
0146     }
0147     count = read(file, tmp, len);
0148     if (count != len) {
0149         fprintf(stderr, "%s: read: %s.\n",
0150             name,
0151             count ? strerror(errno) : "End of file reached");
0152         exit(1);
0153     }
0154     return tmp;
0155 }
0156 
0157 #define swab16(x) \
0158     ((uint16_t)( \
0159         (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
0160         (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
0161 
0162 #define swab32(x) \
0163     ((unsigned int)( \
0164         (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
0165         (((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) | \
0166         (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) | \
0167         (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
0168 
0169 static void convert_elf_hdr(Elf32_Ehdr * e)
0170 {
0171     e->e_type = swab16(e->e_type);
0172     e->e_machine = swab16(e->e_machine);
0173     e->e_version = swab32(e->e_version);
0174     e->e_entry = swab32(e->e_entry);
0175     e->e_phoff = swab32(e->e_phoff);
0176     e->e_shoff = swab32(e->e_shoff);
0177     e->e_flags = swab32(e->e_flags);
0178     e->e_ehsize = swab16(e->e_ehsize);
0179     e->e_phentsize = swab16(e->e_phentsize);
0180     e->e_phnum = swab16(e->e_phnum);
0181     e->e_shentsize = swab16(e->e_shentsize);
0182     e->e_shnum = swab16(e->e_shnum);
0183     e->e_shstrndx = swab16(e->e_shstrndx);
0184 }
0185 
0186 static void convert_elf_phdrs(Elf32_Phdr * p, int num)
0187 {
0188     int i;
0189 
0190     for (i = 0; i < num; i++, p++) {
0191         p->p_type = swab32(p->p_type);
0192         p->p_offset = swab32(p->p_offset);
0193         p->p_vaddr = swab32(p->p_vaddr);
0194         p->p_paddr = swab32(p->p_paddr);
0195         p->p_filesz = swab32(p->p_filesz);
0196         p->p_memsz = swab32(p->p_memsz);
0197         p->p_flags = swab32(p->p_flags);
0198         p->p_align = swab32(p->p_align);
0199     }
0200 
0201 }
0202 
0203 static void convert_elf_shdrs(Elf32_Shdr * s, int num)
0204 {
0205     int i;
0206 
0207     for (i = 0; i < num; i++, s++) {
0208         s->sh_name = swab32(s->sh_name);
0209         s->sh_type = swab32(s->sh_type);
0210         s->sh_flags = swab32(s->sh_flags);
0211         s->sh_addr = swab32(s->sh_addr);
0212         s->sh_offset = swab32(s->sh_offset);
0213         s->sh_size = swab32(s->sh_size);
0214         s->sh_link = swab32(s->sh_link);
0215         s->sh_info = swab32(s->sh_info);
0216         s->sh_addralign = swab32(s->sh_addralign);
0217         s->sh_entsize = swab32(s->sh_entsize);
0218     }
0219 }
0220 
0221 static void convert_ecoff_filehdr(struct filehdr *f)
0222 {
0223     f->f_magic = swab16(f->f_magic);
0224     f->f_nscns = swab16(f->f_nscns);
0225     f->f_timdat = swab32(f->f_timdat);
0226     f->f_symptr = swab32(f->f_symptr);
0227     f->f_nsyms = swab32(f->f_nsyms);
0228     f->f_opthdr = swab16(f->f_opthdr);
0229     f->f_flags = swab16(f->f_flags);
0230 }
0231 
0232 static void convert_ecoff_aouthdr(struct aouthdr *a)
0233 {
0234     a->magic = swab16(a->magic);
0235     a->vstamp = swab16(a->vstamp);
0236     a->tsize = swab32(a->tsize);
0237     a->dsize = swab32(a->dsize);
0238     a->bsize = swab32(a->bsize);
0239     a->entry = swab32(a->entry);
0240     a->text_start = swab32(a->text_start);
0241     a->data_start = swab32(a->data_start);
0242     a->bss_start = swab32(a->bss_start);
0243     a->gprmask = swab32(a->gprmask);
0244     a->cprmask[0] = swab32(a->cprmask[0]);
0245     a->cprmask[1] = swab32(a->cprmask[1]);
0246     a->cprmask[2] = swab32(a->cprmask[2]);
0247     a->cprmask[3] = swab32(a->cprmask[3]);
0248     a->gp_value = swab32(a->gp_value);
0249 }
0250 
0251 static void convert_ecoff_esecs(struct scnhdr *s, int num)
0252 {
0253     int i;
0254 
0255     for (i = 0; i < num; i++, s++) {
0256         s->s_paddr = swab32(s->s_paddr);
0257         s->s_vaddr = swab32(s->s_vaddr);
0258         s->s_size = swab32(s->s_size);
0259         s->s_scnptr = swab32(s->s_scnptr);
0260         s->s_relptr = swab32(s->s_relptr);
0261         s->s_lnnoptr = swab32(s->s_lnnoptr);
0262         s->s_nreloc = swab16(s->s_nreloc);
0263         s->s_nlnno = swab16(s->s_nlnno);
0264         s->s_flags = swab32(s->s_flags);
0265     }
0266 }
0267 
0268 int main(int argc, char *argv[])
0269 {
0270     Elf32_Ehdr ex;
0271     Elf32_Phdr *ph;
0272     Elf32_Shdr *sh;
0273     int i, pad;
0274     struct sect text, data, bss;
0275     struct filehdr efh;
0276     struct aouthdr eah;
0277     struct scnhdr esecs[6];
0278     int infile, outfile;
0279     uint32_t cur_vma = UINT32_MAX;
0280     int addflag = 0;
0281     int nosecs;
0282 
0283     text.len = data.len = bss.len = 0;
0284     text.vaddr = data.vaddr = bss.vaddr = 0;
0285 
0286     /* Check args... */
0287     if (argc < 3 || argc > 4) {
0288           usage:
0289         fprintf(stderr,
0290             "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
0291         exit(1);
0292     }
0293     if (argc == 4) {
0294         if (strcmp(argv[3], "-a"))
0295             goto usage;
0296         addflag = 1;
0297     }
0298 
0299     /* Try the input file... */
0300     if ((infile = open(argv[1], O_RDONLY)) < 0) {
0301         fprintf(stderr, "Can't open %s for read: %s\n",
0302             argv[1], strerror(errno));
0303         exit(1);
0304     }
0305 
0306     /* Read the header, which is at the beginning of the file... */
0307     i = read(infile, &ex, sizeof ex);
0308     if (i != sizeof ex) {
0309         fprintf(stderr, "ex: %s: %s.\n",
0310             argv[1],
0311             i ? strerror(errno) : "End of file reached");
0312         exit(1);
0313     }
0314 
0315     if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
0316         format_bigendian = 1;
0317 
0318     if (ntohs(0xaa55) == 0xaa55) {
0319         if (!format_bigendian)
0320             must_convert_endian = 1;
0321     } else {
0322         if (format_bigendian)
0323             must_convert_endian = 1;
0324     }
0325     if (must_convert_endian)
0326         convert_elf_hdr(&ex);
0327 
0328     /* Read the program headers... */
0329     ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
0330                      ex.e_phnum * sizeof(Elf32_Phdr),
0331                      "ph");
0332     if (must_convert_endian)
0333         convert_elf_phdrs(ph, ex.e_phnum);
0334     /* Read the section headers... */
0335     sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
0336                      ex.e_shnum * sizeof(Elf32_Shdr),
0337                      "sh");
0338     if (must_convert_endian)
0339         convert_elf_shdrs(sh, ex.e_shnum);
0340 
0341     /* Figure out if we can cram the program header into an ECOFF
0342        header...  Basically, we can't handle anything but loadable
0343        segments, but we can ignore some kinds of segments.  We can't
0344        handle holes in the address space.  Segments may be out of order,
0345        so we sort them first. */
0346 
0347     qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
0348 
0349     for (i = 0; i < ex.e_phnum; i++) {
0350         /* Section types we can ignore... */
0351         switch (ph[i].p_type) {
0352         case PT_NULL:
0353         case PT_NOTE:
0354         case PT_PHDR:
0355         case PT_MIPS_REGINFO:
0356         case PT_MIPS_ABIFLAGS:
0357             continue;
0358 
0359         case PT_LOAD:
0360             /* Writable (data) segment? */
0361             if (ph[i].p_flags & PF_W) {
0362                 struct sect ndata, nbss;
0363 
0364                 ndata.vaddr = ph[i].p_vaddr;
0365                 ndata.len = ph[i].p_filesz;
0366                 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
0367                 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
0368 
0369                 combine(&data, &ndata, 0);
0370                 combine(&bss, &nbss, 1);
0371             } else {
0372                 struct sect ntxt;
0373 
0374                 ntxt.vaddr = ph[i].p_vaddr;
0375                 ntxt.len = ph[i].p_filesz;
0376 
0377                 combine(&text, &ntxt, 0);
0378             }
0379             /* Remember the lowest segment start address. */
0380             if (ph[i].p_vaddr < cur_vma)
0381                 cur_vma = ph[i].p_vaddr;
0382             break;
0383 
0384         default:
0385             /* Section types we can't handle... */
0386             fprintf(stderr,
0387                 "Program header %d type %d can't be converted.\n",
0388                 ex.e_phnum, ph[i].p_type);
0389             exit(1);
0390         }
0391     }
0392 
0393     /* Sections must be in order to be converted... */
0394     if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
0395         text.vaddr + text.len > data.vaddr
0396         || data.vaddr + data.len > bss.vaddr) {
0397         fprintf(stderr,
0398             "Sections ordering prevents a.out conversion.\n");
0399         exit(1);
0400     }
0401 
0402     /* If there's a data section but no text section, then the loader
0403        combined everything into one section.   That needs to be the
0404        text section, so just make the data section zero length following
0405        text. */
0406     if (data.len && !text.len) {
0407         text = data;
0408         data.vaddr = text.vaddr + text.len;
0409         data.len = 0;
0410     }
0411 
0412     /* If there is a gap between text and data, we'll fill it when we copy
0413        the data, so update the length of the text segment as represented in
0414        a.out to reflect that, since a.out doesn't allow gaps in the program
0415        address space. */
0416     if (text.vaddr + text.len < data.vaddr)
0417         text.len = data.vaddr - text.vaddr;
0418 
0419     /* We now have enough information to cons up an a.out header... */
0420     eah.magic = OMAGIC;
0421     eah.vstamp = 200;
0422     eah.tsize = text.len;
0423     eah.dsize = data.len;
0424     eah.bsize = bss.len;
0425     eah.entry = ex.e_entry;
0426     eah.text_start = text.vaddr;
0427     eah.data_start = data.vaddr;
0428     eah.bss_start = bss.vaddr;
0429     eah.gprmask = 0xf3fffffe;
0430     memset(&eah.cprmask, '\0', sizeof eah.cprmask);
0431     eah.gp_value = 0;   /* unused. */
0432 
0433     if (format_bigendian)
0434         efh.f_magic = MIPSEBMAGIC;
0435     else
0436         efh.f_magic = MIPSELMAGIC;
0437     if (addflag)
0438         nosecs = 6;
0439     else
0440         nosecs = 3;
0441     efh.f_nscns = nosecs;
0442     efh.f_timdat = 0;   /* bogus */
0443     efh.f_symptr = 0;
0444     efh.f_nsyms = 0;
0445     efh.f_opthdr = sizeof eah;
0446     efh.f_flags = 0x100f;   /* Stripped, not sharable. */
0447 
0448     memset(esecs, 0, sizeof esecs);
0449     strcpy(esecs[0].s_name, ".text");
0450     strcpy(esecs[1].s_name, ".data");
0451     strcpy(esecs[2].s_name, ".bss");
0452     if (addflag) {
0453         strcpy(esecs[3].s_name, ".rdata");
0454         strcpy(esecs[4].s_name, ".sdata");
0455         strcpy(esecs[5].s_name, ".sbss");
0456     }
0457     esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
0458     esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
0459     esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
0460     if (addflag) {
0461         esecs[3].s_paddr = esecs[3].s_vaddr = 0;
0462         esecs[4].s_paddr = esecs[4].s_vaddr = 0;
0463         esecs[5].s_paddr = esecs[5].s_vaddr = 0;
0464     }
0465     esecs[0].s_size = eah.tsize;
0466     esecs[1].s_size = eah.dsize;
0467     esecs[2].s_size = eah.bsize;
0468     if (addflag) {
0469         esecs[3].s_size = 0;
0470         esecs[4].s_size = 0;
0471         esecs[5].s_size = 0;
0472     }
0473     esecs[0].s_scnptr = N_TXTOFF(efh, eah);
0474     esecs[1].s_scnptr = N_DATOFF(efh, eah);
0475 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
0476 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
0477     esecs[2].s_scnptr = esecs[1].s_scnptr +
0478         ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
0479     if (addflag) {
0480         esecs[3].s_scnptr = 0;
0481         esecs[4].s_scnptr = 0;
0482         esecs[5].s_scnptr = 0;
0483     }
0484     esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
0485     esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
0486     esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
0487     esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
0488     if (addflag) {
0489         esecs[3].s_relptr = esecs[4].s_relptr
0490             = esecs[5].s_relptr = 0;
0491         esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
0492             = esecs[5].s_lnnoptr = 0;
0493         esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
0494             0;
0495         esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
0496     }
0497     esecs[0].s_flags = 0x20;
0498     esecs[1].s_flags = 0x40;
0499     esecs[2].s_flags = 0x82;
0500     if (addflag) {
0501         esecs[3].s_flags = 0x100;
0502         esecs[4].s_flags = 0x200;
0503         esecs[5].s_flags = 0x400;
0504     }
0505 
0506     /* Make the output file... */
0507     if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
0508         fprintf(stderr, "Unable to create %s: %s\n", argv[2],
0509             strerror(errno));
0510         exit(1);
0511     }
0512 
0513     if (must_convert_endian)
0514         convert_ecoff_filehdr(&efh);
0515     /* Write the headers... */
0516     i = write(outfile, &efh, sizeof efh);
0517     if (i != sizeof efh) {
0518         perror("efh: write");
0519         exit(1);
0520 
0521         for (i = 0; i < nosecs; i++) {
0522             printf
0523                 ("Section %d: %s phys %"PRIx32"  size %"PRIx32"\t file offset %"PRIx32"\n",
0524                  i, esecs[i].s_name, esecs[i].s_paddr,
0525                  esecs[i].s_size, esecs[i].s_scnptr);
0526         }
0527     }
0528     fprintf(stderr, "wrote %d byte file header.\n", i);
0529 
0530     if (must_convert_endian)
0531         convert_ecoff_aouthdr(&eah);
0532     i = write(outfile, &eah, sizeof eah);
0533     if (i != sizeof eah) {
0534         perror("eah: write");
0535         exit(1);
0536     }
0537     fprintf(stderr, "wrote %d byte a.out header.\n", i);
0538 
0539     if (must_convert_endian)
0540         convert_ecoff_esecs(&esecs[0], nosecs);
0541     i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
0542     if (i != nosecs * sizeof(struct scnhdr)) {
0543         perror("esecs: write");
0544         exit(1);
0545     }
0546     fprintf(stderr, "wrote %d bytes of section headers.\n", i);
0547 
0548     pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
0549     if (pad) {
0550         pad = 16 - pad;
0551         i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
0552         if (i < 0) {
0553             perror("ipad: write");
0554             exit(1);
0555         }
0556         fprintf(stderr, "wrote %d byte pad.\n", i);
0557     }
0558 
0559     /*
0560      * Copy the loadable sections.   Zero-fill any gaps less than 64k;
0561      * complain about any zero-filling, and die if we're asked to zero-fill
0562      * more than 64k.
0563      */
0564     for (i = 0; i < ex.e_phnum; i++) {
0565         /* Unprocessable sections were handled above, so just verify that
0566            the section can be loaded before copying. */
0567         if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
0568             if (cur_vma != ph[i].p_vaddr) {
0569                 uint32_t gap = ph[i].p_vaddr - cur_vma;
0570                 char obuf[1024];
0571                 if (gap > 65536) {
0572                     fprintf(stderr,
0573                         "Intersegment gap (%"PRId32" bytes) too large.\n",
0574                         gap);
0575                     exit(1);
0576                 }
0577                 fprintf(stderr,
0578                     "Warning: %d byte intersegment gap.\n",
0579                     gap);
0580                 memset(obuf, 0, sizeof obuf);
0581                 while (gap) {
0582                     int count =
0583                         write(outfile, obuf,
0584                           (gap >
0585                            sizeof obuf ? sizeof
0586                            obuf : gap));
0587                     if (count < 0) {
0588                         fprintf(stderr,
0589                             "Error writing gap: %s\n",
0590                             strerror(errno));
0591                         exit(1);
0592                     }
0593                     gap -= count;
0594                 }
0595             }
0596             fprintf(stderr, "writing %d bytes...\n",
0597                 ph[i].p_filesz);
0598             copy(outfile, infile, ph[i].p_offset,
0599                  ph[i].p_filesz);
0600             cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
0601         }
0602     }
0603 
0604     /*
0605      * Write a page of padding for boot PROMS that read entire pages.
0606      * Without this, they may attempt to read past the end of the
0607      * data section, incur an error, and refuse to boot.
0608      */
0609     {
0610         char obuf[4096];
0611         memset(obuf, 0, sizeof obuf);
0612         if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
0613             fprintf(stderr, "Error writing PROM padding: %s\n",
0614                 strerror(errno));
0615             exit(1);
0616         }
0617     }
0618 
0619     /* Looks like we won... */
0620     exit(0);
0621 }