cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

elf2ecoff.c (16905B)


      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}