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