linux/arch/mips/boot/elf2ecoff.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 1995
   3 *      Ted Lemon (hereinafter referred to as the author)
   4 *
   5 * Redistribution and use in source and binary forms, with or without
   6 * modification, are permitted provided that the following conditions
   7 * are met:
   8 * 1. Redistributions of source code must retain the above copyright
   9 *    notice, this list of conditions and the following disclaimer.
  10 * 2. Redistributions in binary form must reproduce the above copyright
  11 *    notice, this list of conditions and the following disclaimer in the
  12 *    documentation and/or other materials provided with the distribution.
  13 * 3. The name of the author may not be used to endorse or promote products
  14 *    derived from this software without specific prior written permission.
  15 *
  16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
  17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26 * SUCH DAMAGE.
  27 */
  28
  29/* elf2ecoff.c
  30
  31   This program converts an elf executable to an ECOFF executable.
  32   No symbol table is retained.   This is useful primarily in building
  33   net-bootable kernels for machines (e.g., DECstation and Alpha) which
  34   only support the ECOFF object file format. */
  35
  36#include <stdio.h>
  37#include <string.h>
  38#include <errno.h>
  39#include <sys/types.h>
  40#include <fcntl.h>
  41#include <unistd.h>
  42#include <elf.h>
  43#include <limits.h>
  44#include <netinet/in.h>
  45#include <stdlib.h>
  46
  47#include "ecoff.h"
  48
  49/*
  50 * Some extra ELF definitions
  51 */
  52#define PT_MIPS_REGINFO 0x70000000      /* Register usage information */
  53
  54/* -------------------------------------------------------------------- */
  55
  56struct sect {
  57        unsigned long vaddr;
  58        unsigned long len;
  59};
  60
  61int *symTypeTable;
  62int must_convert_endian;
  63int format_bigendian;
  64
  65static void copy(int out, int in, off_t offset, off_t size)
  66{
  67        char ibuf[4096];
  68        int remaining, cur, count;
  69
  70        /* Go to the start of the ELF symbol table... */
  71        if (lseek(in, offset, SEEK_SET) < 0) {
  72                perror("copy: lseek");
  73                exit(1);
  74        }
  75
  76        remaining = size;
  77        while (remaining) {
  78                cur = remaining;
  79                if (cur > sizeof ibuf)
  80                        cur = sizeof ibuf;
  81                remaining -= cur;
  82                if ((count = read(in, ibuf, cur)) != cur) {
  83                        fprintf(stderr, "copy: read: %s\n",
  84                                count ? strerror(errno) :
  85                                "premature end of file");
  86                        exit(1);
  87                }
  88                if ((count = write(out, ibuf, cur)) != cur) {
  89                        perror("copy: write");
  90                        exit(1);
  91                }
  92        }
  93}
  94
  95/*
  96 * Combine two segments, which must be contiguous.   If pad is true, it's
  97 * okay for there to be padding between.
  98 */
  99static void combine(struct sect *base, struct sect *new, int pad)
 100{
 101        if (!base->len)
 102                *base = *new;
 103        else if (new->len) {
 104                if (base->vaddr + base->len != new->vaddr) {
 105                        if (pad)
 106                                base->len = new->vaddr - base->vaddr;
 107                        else {
 108                                fprintf(stderr,
 109                                        "Non-contiguous data can't be converted.\n");
 110                                exit(1);
 111                        }
 112                }
 113                base->len += new->len;
 114        }
 115}
 116
 117static int phcmp(const void *v1, const void *v2)
 118{
 119        const Elf32_Phdr *h1 = v1;
 120        const Elf32_Phdr *h2 = v2;
 121
 122        if (h1->p_vaddr > h2->p_vaddr)
 123                return 1;
 124        else if (h1->p_vaddr < h2->p_vaddr)
 125                return -1;
 126        else
 127                return 0;
 128}
 129
 130static char *saveRead(int file, off_t offset, off_t len, char *name)
 131{
 132        char *tmp;
 133        int count;
 134        off_t off;
 135        if ((off = lseek(file, offset, SEEK_SET)) < 0) {
 136                fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
 137                exit(1);
 138        }
 139        if (!(tmp = (char *) malloc(len))) {
 140                fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
 141                        len);
 142                exit(1);
 143        }
 144        count = read(file, tmp, len);
 145        if (count != len) {
 146                fprintf(stderr, "%s: read: %s.\n",
 147                        name,
 148                        count ? strerror(errno) : "End of file reached");
 149                exit(1);
 150        }
 151        return tmp;
 152}
 153
 154#define swab16(x) \
 155        ((unsigned short)( \
 156                (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
 157                (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
 158
 159#define swab32(x) \
 160        ((unsigned int)( \
 161                (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
 162                (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
 163                (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
 164                (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
 165
 166static void convert_elf_hdr(Elf32_Ehdr * e)
 167{
 168        e->e_type = swab16(e->e_type);
 169        e->e_machine = swab16(e->e_machine);
 170        e->e_version = swab32(e->e_version);
 171        e->e_entry = swab32(e->e_entry);
 172        e->e_phoff = swab32(e->e_phoff);
 173        e->e_shoff = swab32(e->e_shoff);
 174        e->e_flags = swab32(e->e_flags);
 175        e->e_ehsize = swab16(e->e_ehsize);
 176        e->e_phentsize = swab16(e->e_phentsize);
 177        e->e_phnum = swab16(e->e_phnum);
 178        e->e_shentsize = swab16(e->e_shentsize);
 179        e->e_shnum = swab16(e->e_shnum);
 180        e->e_shstrndx = swab16(e->e_shstrndx);
 181}
 182
 183static void convert_elf_phdrs(Elf32_Phdr * p, int num)
 184{
 185        int i;
 186
 187        for (i = 0; i < num; i++, p++) {
 188                p->p_type = swab32(p->p_type);
 189                p->p_offset = swab32(p->p_offset);
 190                p->p_vaddr = swab32(p->p_vaddr);
 191                p->p_paddr = swab32(p->p_paddr);
 192                p->p_filesz = swab32(p->p_filesz);
 193                p->p_memsz = swab32(p->p_memsz);
 194                p->p_flags = swab32(p->p_flags);
 195                p->p_align = swab32(p->p_align);
 196        }
 197
 198}
 199
 200static void convert_elf_shdrs(Elf32_Shdr * s, int num)
 201{
 202        int i;
 203
 204        for (i = 0; i < num; i++, s++) {
 205                s->sh_name = swab32(s->sh_name);
 206                s->sh_type = swab32(s->sh_type);
 207                s->sh_flags = swab32(s->sh_flags);
 208                s->sh_addr = swab32(s->sh_addr);
 209                s->sh_offset = swab32(s->sh_offset);
 210                s->sh_size = swab32(s->sh_size);
 211                s->sh_link = swab32(s->sh_link);
 212                s->sh_info = swab32(s->sh_info);
 213                s->sh_addralign = swab32(s->sh_addralign);
 214                s->sh_entsize = swab32(s->sh_entsize);
 215        }
 216}
 217
 218static void convert_ecoff_filehdr(struct filehdr *f)
 219{
 220        f->f_magic = swab16(f->f_magic);
 221        f->f_nscns = swab16(f->f_nscns);
 222        f->f_timdat = swab32(f->f_timdat);
 223        f->f_symptr = swab32(f->f_symptr);
 224        f->f_nsyms = swab32(f->f_nsyms);
 225        f->f_opthdr = swab16(f->f_opthdr);
 226        f->f_flags = swab16(f->f_flags);
 227}
 228
 229static void convert_ecoff_aouthdr(struct aouthdr *a)
 230{
 231        a->magic = swab16(a->magic);
 232        a->vstamp = swab16(a->vstamp);
 233        a->tsize = swab32(a->tsize);
 234        a->dsize = swab32(a->dsize);
 235        a->bsize = swab32(a->bsize);
 236        a->entry = swab32(a->entry);
 237        a->text_start = swab32(a->text_start);
 238        a->data_start = swab32(a->data_start);
 239        a->bss_start = swab32(a->bss_start);
 240        a->gprmask = swab32(a->gprmask);
 241        a->cprmask[0] = swab32(a->cprmask[0]);
 242        a->cprmask[1] = swab32(a->cprmask[1]);
 243        a->cprmask[2] = swab32(a->cprmask[2]);
 244        a->cprmask[3] = swab32(a->cprmask[3]);
 245        a->gp_value = swab32(a->gp_value);
 246}
 247
 248static void convert_ecoff_esecs(struct scnhdr *s, int num)
 249{
 250        int i;
 251
 252        for (i = 0; i < num; i++, s++) {
 253                s->s_paddr = swab32(s->s_paddr);
 254                s->s_vaddr = swab32(s->s_vaddr);
 255                s->s_size = swab32(s->s_size);
 256                s->s_scnptr = swab32(s->s_scnptr);
 257                s->s_relptr = swab32(s->s_relptr);
 258                s->s_lnnoptr = swab32(s->s_lnnoptr);
 259                s->s_nreloc = swab16(s->s_nreloc);
 260                s->s_nlnno = swab16(s->s_nlnno);
 261                s->s_flags = swab32(s->s_flags);
 262        }
 263}
 264
 265int main(int argc, char *argv[])
 266{
 267        Elf32_Ehdr ex;
 268        Elf32_Phdr *ph;
 269        Elf32_Shdr *sh;
 270        char *shstrtab;
 271        int i, pad;
 272        struct sect text, data, bss;
 273        struct filehdr efh;
 274        struct aouthdr eah;
 275        struct scnhdr esecs[6];
 276        int infile, outfile;
 277        unsigned long cur_vma = ULONG_MAX;
 278        int addflag = 0;
 279        int nosecs;
 280
 281        text.len = data.len = bss.len = 0;
 282        text.vaddr = data.vaddr = bss.vaddr = 0;
 283
 284        /* Check args... */
 285        if (argc < 3 || argc > 4) {
 286              usage:
 287                fprintf(stderr,
 288                        "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
 289                exit(1);
 290        }
 291        if (argc == 4) {
 292                if (strcmp(argv[3], "-a"))
 293                        goto usage;
 294                addflag = 1;
 295        }
 296
 297        /* Try the input file... */
 298        if ((infile = open(argv[1], O_RDONLY)) < 0) {
 299                fprintf(stderr, "Can't open %s for read: %s\n",
 300                        argv[1], strerror(errno));
 301                exit(1);
 302        }
 303
 304        /* Read the header, which is at the beginning of the file... */
 305        i = read(infile, &ex, sizeof ex);
 306        if (i != sizeof ex) {
 307                fprintf(stderr, "ex: %s: %s.\n",
 308                        argv[1],
 309                        i ? strerror(errno) : "End of file reached");
 310                exit(1);
 311        }
 312
 313        if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
 314                format_bigendian = 1;
 315
 316        if (ntohs(0xaa55) == 0xaa55) {
 317                if (!format_bigendian)
 318                        must_convert_endian = 1;
 319        } else {
 320                if (format_bigendian)
 321                        must_convert_endian = 1;
 322        }
 323        if (must_convert_endian)
 324                convert_elf_hdr(&ex);
 325
 326        /* Read the program headers... */
 327        ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
 328                                     ex.e_phnum * sizeof(Elf32_Phdr),
 329                                     "ph");
 330        if (must_convert_endian)
 331                convert_elf_phdrs(ph, ex.e_phnum);
 332        /* Read the section headers... */
 333        sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
 334                                     ex.e_shnum * sizeof(Elf32_Shdr),
 335                                     "sh");
 336        if (must_convert_endian)
 337                convert_elf_shdrs(sh, ex.e_shnum);
 338        /* Read in the section string table. */
 339        shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
 340                            sh[ex.e_shstrndx].sh_size, "shstrtab");
 341
 342        /* Figure out if we can cram the program header into an ECOFF
 343           header...  Basically, we can't handle anything but loadable
 344           segments, but we can ignore some kinds of segments.  We can't
 345           handle holes in the address space.  Segments may be out of order,
 346           so we sort them first. */
 347
 348        qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
 349
 350        for (i = 0; i < ex.e_phnum; i++) {
 351                /* Section types we can ignore... */
 352                if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
 353                    ph[i].p_type == PT_PHDR
 354                    || ph[i].p_type == PT_MIPS_REGINFO)
 355                        continue;
 356                /* Section types we can't handle... */
 357                else if (ph[i].p_type != PT_LOAD) {
 358                        fprintf(stderr,
 359                                "Program header %d type %d can't be converted.\n",
 360                                ex.e_phnum, ph[i].p_type);
 361                        exit(1);
 362                }
 363                /* Writable (data) segment? */
 364                if (ph[i].p_flags & PF_W) {
 365                        struct sect ndata, nbss;
 366
 367                        ndata.vaddr = ph[i].p_vaddr;
 368                        ndata.len = ph[i].p_filesz;
 369                        nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
 370                        nbss.len = ph[i].p_memsz - ph[i].p_filesz;
 371
 372                        combine(&data, &ndata, 0);
 373                        combine(&bss, &nbss, 1);
 374                } else {
 375                        struct sect ntxt;
 376
 377                        ntxt.vaddr = ph[i].p_vaddr;
 378                        ntxt.len = ph[i].p_filesz;
 379
 380                        combine(&text, &ntxt, 0);
 381                }
 382                /* Remember the lowest segment start address. */
 383                if (ph[i].p_vaddr < cur_vma)
 384                        cur_vma = ph[i].p_vaddr;
 385        }
 386
 387        /* Sections must be in order to be converted... */
 388        if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
 389            text.vaddr + text.len > data.vaddr
 390            || data.vaddr + data.len > bss.vaddr) {
 391                fprintf(stderr,
 392                        "Sections ordering prevents a.out conversion.\n");
 393                exit(1);
 394        }
 395
 396        /* If there's a data section but no text section, then the loader
 397           combined everything into one section.   That needs to be the
 398           text section, so just make the data section zero length following
 399           text. */
 400        if (data.len && !text.len) {
 401                text = data;
 402                data.vaddr = text.vaddr + text.len;
 403                data.len = 0;
 404        }
 405
 406        /* If there is a gap between text and data, we'll fill it when we copy
 407           the data, so update the length of the text segment as represented in
 408           a.out to reflect that, since a.out doesn't allow gaps in the program
 409           address space. */
 410        if (text.vaddr + text.len < data.vaddr)
 411                text.len = data.vaddr - text.vaddr;
 412
 413        /* We now have enough information to cons up an a.out header... */
 414        eah.magic = OMAGIC;
 415        eah.vstamp = 200;
 416        eah.tsize = text.len;
 417        eah.dsize = data.len;
 418        eah.bsize = bss.len;
 419        eah.entry = ex.e_entry;
 420        eah.text_start = text.vaddr;
 421        eah.data_start = data.vaddr;
 422        eah.bss_start = bss.vaddr;
 423        eah.gprmask = 0xf3fffffe;
 424        memset(&eah.cprmask, '\0', sizeof eah.cprmask);
 425        eah.gp_value = 0;       /* unused. */
 426
 427        if (format_bigendian)
 428                efh.f_magic = MIPSEBMAGIC;
 429        else
 430                efh.f_magic = MIPSELMAGIC;
 431        if (addflag)
 432                nosecs = 6;
 433        else
 434                nosecs = 3;
 435        efh.f_nscns = nosecs;
 436        efh.f_timdat = 0;       /* bogus */
 437        efh.f_symptr = 0;
 438        efh.f_nsyms = 0;
 439        efh.f_opthdr = sizeof eah;
 440        efh.f_flags = 0x100f;   /* Stripped, not sharable. */
 441
 442        memset(esecs, 0, sizeof esecs);
 443        strcpy(esecs[0].s_name, ".text");
 444        strcpy(esecs[1].s_name, ".data");
 445        strcpy(esecs[2].s_name, ".bss");
 446        if (addflag) {
 447                strcpy(esecs[3].s_name, ".rdata");
 448                strcpy(esecs[4].s_name, ".sdata");
 449                strcpy(esecs[5].s_name, ".sbss");
 450        }
 451        esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
 452        esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
 453        esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
 454        if (addflag) {
 455                esecs[3].s_paddr = esecs[3].s_vaddr = 0;
 456                esecs[4].s_paddr = esecs[4].s_vaddr = 0;
 457                esecs[5].s_paddr = esecs[5].s_vaddr = 0;
 458        }
 459        esecs[0].s_size = eah.tsize;
 460        esecs[1].s_size = eah.dsize;
 461        esecs[2].s_size = eah.bsize;
 462        if (addflag) {
 463                esecs[3].s_size = 0;
 464                esecs[4].s_size = 0;
 465                esecs[5].s_size = 0;
 466        }
 467        esecs[0].s_scnptr = N_TXTOFF(efh, eah);
 468        esecs[1].s_scnptr = N_DATOFF(efh, eah);
 469#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
 470#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
 471        esecs[2].s_scnptr = esecs[1].s_scnptr +
 472            ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
 473        if (addflag) {
 474                esecs[3].s_scnptr = 0;
 475                esecs[4].s_scnptr = 0;
 476                esecs[5].s_scnptr = 0;
 477        }
 478        esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
 479        esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
 480        esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
 481        esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
 482        if (addflag) {
 483                esecs[3].s_relptr = esecs[4].s_relptr
 484                    = esecs[5].s_relptr = 0;
 485                esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
 486                    = esecs[5].s_lnnoptr = 0;
 487                esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
 488                    0;
 489                esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
 490        }
 491        esecs[0].s_flags = 0x20;
 492        esecs[1].s_flags = 0x40;
 493        esecs[2].s_flags = 0x82;
 494        if (addflag) {
 495                esecs[3].s_flags = 0x100;
 496                esecs[4].s_flags = 0x200;
 497                esecs[5].s_flags = 0x400;
 498        }
 499
 500        /* Make the output file... */
 501        if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
 502                fprintf(stderr, "Unable to create %s: %s\n", argv[2],
 503                        strerror(errno));
 504                exit(1);
 505        }
 506
 507        if (must_convert_endian)
 508                convert_ecoff_filehdr(&efh);
 509        /* Write the headers... */
 510        i = write(outfile, &efh, sizeof efh);
 511        if (i != sizeof efh) {
 512                perror("efh: write");
 513                exit(1);
 514
 515                for (i = 0; i < nosecs; i++) {
 516                        printf
 517                            ("Section %d: %s phys %lx  size %lx  file offset %lx\n",
 518                             i, esecs[i].s_name, esecs[i].s_paddr,
 519                             esecs[i].s_size, esecs[i].s_scnptr);
 520                }
 521        }
 522        fprintf(stderr, "wrote %d byte file header.\n", i);
 523
 524        if (must_convert_endian)
 525                convert_ecoff_aouthdr(&eah);
 526        i = write(outfile, &eah, sizeof eah);
 527        if (i != sizeof eah) {
 528                perror("eah: write");
 529                exit(1);
 530        }
 531        fprintf(stderr, "wrote %d byte a.out header.\n", i);
 532
 533        if (must_convert_endian)
 534                convert_ecoff_esecs(&esecs[0], nosecs);
 535        i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
 536        if (i != nosecs * sizeof(struct scnhdr)) {
 537                perror("esecs: write");
 538                exit(1);
 539        }
 540        fprintf(stderr, "wrote %d bytes of section headers.\n", i);
 541
 542        pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
 543        if (pad) {
 544                pad = 16 - pad;
 545                i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
 546                if (i < 0) {
 547                        perror("ipad: write");
 548                        exit(1);
 549                }
 550                fprintf(stderr, "wrote %d byte pad.\n", i);
 551        }
 552
 553        /*
 554         * Copy the loadable sections.   Zero-fill any gaps less than 64k;
 555         * complain about any zero-filling, and die if we're asked to zero-fill
 556         * more than 64k.
 557         */
 558        for (i = 0; i < ex.e_phnum; i++) {
 559                /* Unprocessable sections were handled above, so just verify that
 560                   the section can be loaded before copying. */
 561                if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
 562                        if (cur_vma != ph[i].p_vaddr) {
 563                                unsigned long gap =
 564                                    ph[i].p_vaddr - cur_vma;
 565                                char obuf[1024];
 566                                if (gap > 65536) {
 567                                        fprintf(stderr,
 568                                                "Intersegment gap (%ld bytes) too large.\n",
 569                                                gap);
 570                                        exit(1);
 571                                }
 572                                fprintf(stderr,
 573                                        "Warning: %ld byte intersegment gap.\n",
 574                                        gap);
 575                                memset(obuf, 0, sizeof obuf);
 576                                while (gap) {
 577                                        int count =
 578                                            write(outfile, obuf,
 579                                                  (gap >
 580                                                   sizeof obuf ? sizeof
 581                                                   obuf : gap));
 582                                        if (count < 0) {
 583                                                fprintf(stderr,
 584                                                        "Error writing gap: %s\n",
 585                                                        strerror(errno));
 586                                                exit(1);
 587                                        }
 588                                        gap -= count;
 589                                }
 590                        }
 591                        fprintf(stderr, "writing %d bytes...\n",
 592                                ph[i].p_filesz);
 593                        copy(outfile, infile, ph[i].p_offset,
 594                             ph[i].p_filesz);
 595                        cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
 596                }
 597        }
 598
 599        /*
 600         * Write a page of padding for boot PROMS that read entire pages.
 601         * Without this, they may attempt to read past the end of the
 602         * data section, incur an error, and refuse to boot.
 603         */
 604        {
 605                char obuf[4096];
 606                memset(obuf, 0, sizeof obuf);
 607                if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
 608                        fprintf(stderr, "Error writing PROM padding: %s\n",
 609                                strerror(errno));
 610                        exit(1);
 611                }
 612        }
 613
 614        /* Looks like we won... */
 615        exit(0);
 616}
 617