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 
56 struct sect {
57 	unsigned long vaddr;
58 	unsigned long len;
59 };
60 
61 int *symTypeTable;
62 int must_convert_endian;
63 int format_bigendian;
64 
copy(int out,int in,off_t offset,off_t size)65 static 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  */
combine(struct sect * base,struct sect * new,int pad)99 static 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 
phcmp(const void * v1,const void * v2)117 static 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 
saveRead(int file,off_t offset,off_t len,char * name)130 static 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 
convert_elf_hdr(Elf32_Ehdr * e)166 static 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 
convert_elf_phdrs(Elf32_Phdr * p,int num)183 static 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 
convert_elf_shdrs(Elf32_Shdr * s,int num)200 static 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 
convert_ecoff_filehdr(struct filehdr * f)218 static 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 
convert_ecoff_aouthdr(struct aouthdr * a)229 static 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 
convert_ecoff_esecs(struct scnhdr * s,int num)248 static 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 
main(int argc,char * argv[])265 int 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