xref: /linux/arch/mips/boot/elf2ecoff.c (revision 4949009eb8d40a441dcddcd96e101e77d31cf1b2)
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 
57 struct sect {
58 	unsigned long vaddr;
59 	unsigned long len;
60 };
61 
62 int *symTypeTable;
63 int must_convert_endian;
64 int format_bigendian;
65 
66 static 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  */
100 static 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 
118 static 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 
131 static 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 
167 static 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 
184 static 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 
201 static 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 
219 static 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 
230 static 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 
249 static 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 
266 int main(int argc, char *argv[])
267 {
268 	Elf32_Ehdr ex;
269 	Elf32_Phdr *ph;
270 	Elf32_Shdr *sh;
271 	char *shstrtab;
272 	int i, pad;
273 	struct sect text, data, bss;
274 	struct filehdr efh;
275 	struct aouthdr eah;
276 	struct scnhdr esecs[6];
277 	int infile, outfile;
278 	unsigned long cur_vma = ULONG_MAX;
279 	int addflag = 0;
280 	int nosecs;
281 
282 	text.len = data.len = bss.len = 0;
283 	text.vaddr = data.vaddr = bss.vaddr = 0;
284 
285 	/* Check args... */
286 	if (argc < 3 || argc > 4) {
287 	      usage:
288 		fprintf(stderr,
289 			"usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
290 		exit(1);
291 	}
292 	if (argc == 4) {
293 		if (strcmp(argv[3], "-a"))
294 			goto usage;
295 		addflag = 1;
296 	}
297 
298 	/* Try the input file... */
299 	if ((infile = open(argv[1], O_RDONLY)) < 0) {
300 		fprintf(stderr, "Can't open %s for read: %s\n",
301 			argv[1], strerror(errno));
302 		exit(1);
303 	}
304 
305 	/* Read the header, which is at the beginning of the file... */
306 	i = read(infile, &ex, sizeof ex);
307 	if (i != sizeof ex) {
308 		fprintf(stderr, "ex: %s: %s.\n",
309 			argv[1],
310 			i ? strerror(errno) : "End of file reached");
311 		exit(1);
312 	}
313 
314 	if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
315 		format_bigendian = 1;
316 
317 	if (ntohs(0xaa55) == 0xaa55) {
318 		if (!format_bigendian)
319 			must_convert_endian = 1;
320 	} else {
321 		if (format_bigendian)
322 			must_convert_endian = 1;
323 	}
324 	if (must_convert_endian)
325 		convert_elf_hdr(&ex);
326 
327 	/* Read the program headers... */
328 	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
329 				     ex.e_phnum * sizeof(Elf32_Phdr),
330 				     "ph");
331 	if (must_convert_endian)
332 		convert_elf_phdrs(ph, ex.e_phnum);
333 	/* Read the section headers... */
334 	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
335 				     ex.e_shnum * sizeof(Elf32_Shdr),
336 				     "sh");
337 	if (must_convert_endian)
338 		convert_elf_shdrs(sh, ex.e_shnum);
339 	/* Read in the section string table. */
340 	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
341 			    sh[ex.e_shstrndx].sh_size, "shstrtab");
342 
343 	/* Figure out if we can cram the program header into an ECOFF
344 	   header...  Basically, we can't handle anything but loadable
345 	   segments, but we can ignore some kinds of segments.	We can't
346 	   handle holes in the address space.  Segments may be out of order,
347 	   so we sort them first. */
348 
349 	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
350 
351 	for (i = 0; i < ex.e_phnum; i++) {
352 		/* Section types we can ignore... */
353 		switch (ph[i].p_type) {
354 		case PT_NULL:
355 		case PT_NOTE:
356 		case PT_PHDR:
357 		case PT_MIPS_REGINFO:
358 		case PT_MIPS_ABIFLAGS:
359 			continue;
360 
361 		case PT_LOAD:
362 			/* Writable (data) segment? */
363 			if (ph[i].p_flags & PF_W) {
364 				struct sect ndata, nbss;
365 
366 				ndata.vaddr = ph[i].p_vaddr;
367 				ndata.len = ph[i].p_filesz;
368 				nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
369 				nbss.len = ph[i].p_memsz - ph[i].p_filesz;
370 
371 				combine(&data, &ndata, 0);
372 				combine(&bss, &nbss, 1);
373 			} else {
374 				struct sect ntxt;
375 
376 				ntxt.vaddr = ph[i].p_vaddr;
377 				ntxt.len = ph[i].p_filesz;
378 
379 				combine(&text, &ntxt, 0);
380 			}
381 			/* Remember the lowest segment start address. */
382 			if (ph[i].p_vaddr < cur_vma)
383 				cur_vma = ph[i].p_vaddr;
384 			break;
385 
386 		default:
387 			/* Section types we can't handle... */
388 			fprintf(stderr,
389 				"Program header %d type %d can't be converted.\n",
390 				ex.e_phnum, ph[i].p_type);
391 			exit(1);
392 		}
393 	}
394 
395 	/* Sections must be in order to be converted... */
396 	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
397 	    text.vaddr + text.len > data.vaddr
398 	    || data.vaddr + data.len > bss.vaddr) {
399 		fprintf(stderr,
400 			"Sections ordering prevents a.out conversion.\n");
401 		exit(1);
402 	}
403 
404 	/* If there's a data section but no text section, then the loader
405 	   combined everything into one section.   That needs to be the
406 	   text section, so just make the data section zero length following
407 	   text. */
408 	if (data.len && !text.len) {
409 		text = data;
410 		data.vaddr = text.vaddr + text.len;
411 		data.len = 0;
412 	}
413 
414 	/* If there is a gap between text and data, we'll fill it when we copy
415 	   the data, so update the length of the text segment as represented in
416 	   a.out to reflect that, since a.out doesn't allow gaps in the program
417 	   address space. */
418 	if (text.vaddr + text.len < data.vaddr)
419 		text.len = data.vaddr - text.vaddr;
420 
421 	/* We now have enough information to cons up an a.out header... */
422 	eah.magic = OMAGIC;
423 	eah.vstamp = 200;
424 	eah.tsize = text.len;
425 	eah.dsize = data.len;
426 	eah.bsize = bss.len;
427 	eah.entry = ex.e_entry;
428 	eah.text_start = text.vaddr;
429 	eah.data_start = data.vaddr;
430 	eah.bss_start = bss.vaddr;
431 	eah.gprmask = 0xf3fffffe;
432 	memset(&eah.cprmask, '\0', sizeof eah.cprmask);
433 	eah.gp_value = 0;	/* unused. */
434 
435 	if (format_bigendian)
436 		efh.f_magic = MIPSEBMAGIC;
437 	else
438 		efh.f_magic = MIPSELMAGIC;
439 	if (addflag)
440 		nosecs = 6;
441 	else
442 		nosecs = 3;
443 	efh.f_nscns = nosecs;
444 	efh.f_timdat = 0;	/* bogus */
445 	efh.f_symptr = 0;
446 	efh.f_nsyms = 0;
447 	efh.f_opthdr = sizeof eah;
448 	efh.f_flags = 0x100f;	/* Stripped, not sharable. */
449 
450 	memset(esecs, 0, sizeof esecs);
451 	strcpy(esecs[0].s_name, ".text");
452 	strcpy(esecs[1].s_name, ".data");
453 	strcpy(esecs[2].s_name, ".bss");
454 	if (addflag) {
455 		strcpy(esecs[3].s_name, ".rdata");
456 		strcpy(esecs[4].s_name, ".sdata");
457 		strcpy(esecs[5].s_name, ".sbss");
458 	}
459 	esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
460 	esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
461 	esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
462 	if (addflag) {
463 		esecs[3].s_paddr = esecs[3].s_vaddr = 0;
464 		esecs[4].s_paddr = esecs[4].s_vaddr = 0;
465 		esecs[5].s_paddr = esecs[5].s_vaddr = 0;
466 	}
467 	esecs[0].s_size = eah.tsize;
468 	esecs[1].s_size = eah.dsize;
469 	esecs[2].s_size = eah.bsize;
470 	if (addflag) {
471 		esecs[3].s_size = 0;
472 		esecs[4].s_size = 0;
473 		esecs[5].s_size = 0;
474 	}
475 	esecs[0].s_scnptr = N_TXTOFF(efh, eah);
476 	esecs[1].s_scnptr = N_DATOFF(efh, eah);
477 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
478 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
479 	esecs[2].s_scnptr = esecs[1].s_scnptr +
480 	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
481 	if (addflag) {
482 		esecs[3].s_scnptr = 0;
483 		esecs[4].s_scnptr = 0;
484 		esecs[5].s_scnptr = 0;
485 	}
486 	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
487 	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
488 	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
489 	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
490 	if (addflag) {
491 		esecs[3].s_relptr = esecs[4].s_relptr
492 		    = esecs[5].s_relptr = 0;
493 		esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
494 		    = esecs[5].s_lnnoptr = 0;
495 		esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
496 		    0;
497 		esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
498 	}
499 	esecs[0].s_flags = 0x20;
500 	esecs[1].s_flags = 0x40;
501 	esecs[2].s_flags = 0x82;
502 	if (addflag) {
503 		esecs[3].s_flags = 0x100;
504 		esecs[4].s_flags = 0x200;
505 		esecs[5].s_flags = 0x400;
506 	}
507 
508 	/* Make the output file... */
509 	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
510 		fprintf(stderr, "Unable to create %s: %s\n", argv[2],
511 			strerror(errno));
512 		exit(1);
513 	}
514 
515 	if (must_convert_endian)
516 		convert_ecoff_filehdr(&efh);
517 	/* Write the headers... */
518 	i = write(outfile, &efh, sizeof efh);
519 	if (i != sizeof efh) {
520 		perror("efh: write");
521 		exit(1);
522 
523 		for (i = 0; i < nosecs; i++) {
524 			printf
525 			    ("Section %d: %s phys %lx  size %lx	 file offset %lx\n",
526 			     i, esecs[i].s_name, esecs[i].s_paddr,
527 			     esecs[i].s_size, esecs[i].s_scnptr);
528 		}
529 	}
530 	fprintf(stderr, "wrote %d byte file header.\n", i);
531 
532 	if (must_convert_endian)
533 		convert_ecoff_aouthdr(&eah);
534 	i = write(outfile, &eah, sizeof eah);
535 	if (i != sizeof eah) {
536 		perror("eah: write");
537 		exit(1);
538 	}
539 	fprintf(stderr, "wrote %d byte a.out header.\n", i);
540 
541 	if (must_convert_endian)
542 		convert_ecoff_esecs(&esecs[0], nosecs);
543 	i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
544 	if (i != nosecs * sizeof(struct scnhdr)) {
545 		perror("esecs: write");
546 		exit(1);
547 	}
548 	fprintf(stderr, "wrote %d bytes of section headers.\n", i);
549 
550 	pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
551 	if (pad) {
552 		pad = 16 - pad;
553 		i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
554 		if (i < 0) {
555 			perror("ipad: write");
556 			exit(1);
557 		}
558 		fprintf(stderr, "wrote %d byte pad.\n", i);
559 	}
560 
561 	/*
562 	 * Copy the loadable sections.	 Zero-fill any gaps less than 64k;
563 	 * complain about any zero-filling, and die if we're asked to zero-fill
564 	 * more than 64k.
565 	 */
566 	for (i = 0; i < ex.e_phnum; i++) {
567 		/* Unprocessable sections were handled above, so just verify that
568 		   the section can be loaded before copying. */
569 		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
570 			if (cur_vma != ph[i].p_vaddr) {
571 				unsigned long gap =
572 				    ph[i].p_vaddr - cur_vma;
573 				char obuf[1024];
574 				if (gap > 65536) {
575 					fprintf(stderr,
576 						"Intersegment gap (%ld bytes) too large.\n",
577 						gap);
578 					exit(1);
579 				}
580 				fprintf(stderr,
581 					"Warning: %ld byte intersegment gap.\n",
582 					gap);
583 				memset(obuf, 0, sizeof obuf);
584 				while (gap) {
585 					int count =
586 					    write(outfile, obuf,
587 						  (gap >
588 						   sizeof obuf ? sizeof
589 						   obuf : gap));
590 					if (count < 0) {
591 						fprintf(stderr,
592 							"Error writing gap: %s\n",
593 							strerror(errno));
594 						exit(1);
595 					}
596 					gap -= count;
597 				}
598 			}
599 			fprintf(stderr, "writing %d bytes...\n",
600 				ph[i].p_filesz);
601 			copy(outfile, infile, ph[i].p_offset,
602 			     ph[i].p_filesz);
603 			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
604 		}
605 	}
606 
607 	/*
608 	 * Write a page of padding for boot PROMS that read entire pages.
609 	 * Without this, they may attempt to read past the end of the
610 	 * data section, incur an error, and refuse to boot.
611 	 */
612 	{
613 		char obuf[4096];
614 		memset(obuf, 0, sizeof obuf);
615 		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
616 			fprintf(stderr, "Error writing PROM padding: %s\n",
617 				strerror(errno));
618 			exit(1);
619 		}
620 	}
621 
622 	/* Looks like we won... */
623 	exit(0);
624 }
625