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