xref: /openbmc/linux/arch/mips/boot/elf2ecoff.c (revision 0c3bf184)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 1995
31da177e4SLinus Torvalds  *	Ted Lemon (hereinafter referred to as the author)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Redistribution and use in source and binary forms, with or without
61da177e4SLinus Torvalds  * modification, are permitted provided that the following conditions
71da177e4SLinus Torvalds  * are met:
81da177e4SLinus Torvalds  * 1. Redistributions of source code must retain the above copyright
91da177e4SLinus Torvalds  *    notice, this list of conditions and the following disclaimer.
101da177e4SLinus Torvalds  * 2. Redistributions in binary form must reproduce the above copyright
111da177e4SLinus Torvalds  *    notice, this list of conditions and the following disclaimer in the
121da177e4SLinus Torvalds  *    documentation and/or other materials provided with the distribution.
131da177e4SLinus Torvalds  * 3. The name of the author may not be used to endorse or promote products
141da177e4SLinus Torvalds  *    derived from this software without specific prior written permission.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
171da177e4SLinus Torvalds  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181da177e4SLinus Torvalds  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191da177e4SLinus Torvalds  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
201da177e4SLinus Torvalds  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211da177e4SLinus Torvalds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221da177e4SLinus Torvalds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231da177e4SLinus Torvalds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241da177e4SLinus Torvalds  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251da177e4SLinus Torvalds  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261da177e4SLinus Torvalds  * SUCH DAMAGE.
271da177e4SLinus Torvalds  */
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds /* elf2ecoff.c
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds    This program converts an elf executable to an ECOFF executable.
321da177e4SLinus Torvalds    No symbol table is retained.	  This is useful primarily in building
331da177e4SLinus Torvalds    net-bootable kernels for machines (e.g., DECstation and Alpha) which
341da177e4SLinus Torvalds    only support the ECOFF object file format. */
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <stdio.h>
371da177e4SLinus Torvalds #include <string.h>
381da177e4SLinus Torvalds #include <errno.h>
391da177e4SLinus Torvalds #include <sys/types.h>
401da177e4SLinus Torvalds #include <fcntl.h>
411da177e4SLinus Torvalds #include <unistd.h>
421da177e4SLinus Torvalds #include <elf.h>
431da177e4SLinus Torvalds #include <limits.h>
441da177e4SLinus Torvalds #include <netinet/in.h>
451da177e4SLinus Torvalds #include <stdlib.h>
460c3bf184SThomas Bogendoerfer #include <stdint.h>
470c3bf184SThomas Bogendoerfer #include <inttypes.h>
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds #include "ecoff.h"
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /*
521da177e4SLinus Torvalds  * Some extra ELF definitions
531da177e4SLinus Torvalds  */
541da177e4SLinus Torvalds #define PT_MIPS_REGINFO 	0x70000000	/* Register usage information */
5526f7c4bdSRalf Baechle #define PT_MIPS_ABIFLAGS	0x70000003	/* Records ABI related flags  */
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds /* -------------------------------------------------------------------- */
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds struct sect {
600c3bf184SThomas Bogendoerfer 	uint32_t vaddr;
610c3bf184SThomas Bogendoerfer 	uint32_t len;
621da177e4SLinus Torvalds };
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds int *symTypeTable;
65982f6ffeSRalf Baechle int must_convert_endian;
66982f6ffeSRalf Baechle int format_bigendian;
671da177e4SLinus Torvalds 
copy(int out,int in,off_t offset,off_t size)681da177e4SLinus Torvalds static void copy(int out, int in, off_t offset, off_t size)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	char ibuf[4096];
711da177e4SLinus Torvalds 	int remaining, cur, count;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	/* Go to the start of the ELF symbol table... */
741da177e4SLinus Torvalds 	if (lseek(in, offset, SEEK_SET) < 0) {
751da177e4SLinus Torvalds 		perror("copy: lseek");
761da177e4SLinus Torvalds 		exit(1);
771da177e4SLinus Torvalds 	}
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	remaining = size;
801da177e4SLinus Torvalds 	while (remaining) {
811da177e4SLinus Torvalds 		cur = remaining;
821da177e4SLinus Torvalds 		if (cur > sizeof ibuf)
831da177e4SLinus Torvalds 			cur = sizeof ibuf;
841da177e4SLinus Torvalds 		remaining -= cur;
851da177e4SLinus Torvalds 		if ((count = read(in, ibuf, cur)) != cur) {
861da177e4SLinus Torvalds 			fprintf(stderr, "copy: read: %s\n",
871da177e4SLinus Torvalds 				count ? strerror(errno) :
881da177e4SLinus Torvalds 				"premature end of file");
891da177e4SLinus Torvalds 			exit(1);
901da177e4SLinus Torvalds 		}
911da177e4SLinus Torvalds 		if ((count = write(out, ibuf, cur)) != cur) {
921da177e4SLinus Torvalds 			perror("copy: write");
931da177e4SLinus Torvalds 			exit(1);
941da177e4SLinus Torvalds 		}
951da177e4SLinus Torvalds 	}
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds  * Combine two segments, which must be contiguous.   If pad is true, it's
1001da177e4SLinus Torvalds  * okay for there to be padding between.
1011da177e4SLinus Torvalds  */
combine(struct sect * base,struct sect * new,int pad)1021da177e4SLinus Torvalds static void combine(struct sect *base, struct sect *new, int pad)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds 	if (!base->len)
1051da177e4SLinus Torvalds 		*base = *new;
1061da177e4SLinus Torvalds 	else if (new->len) {
1071da177e4SLinus Torvalds 		if (base->vaddr + base->len != new->vaddr) {
1081da177e4SLinus Torvalds 			if (pad)
1091da177e4SLinus Torvalds 				base->len = new->vaddr - base->vaddr;
1101da177e4SLinus Torvalds 			else {
1111da177e4SLinus Torvalds 				fprintf(stderr,
1121da177e4SLinus Torvalds 					"Non-contiguous data can't be converted.\n");
1131da177e4SLinus Torvalds 				exit(1);
1141da177e4SLinus Torvalds 			}
1151da177e4SLinus Torvalds 		}
1161da177e4SLinus Torvalds 		base->len += new->len;
1171da177e4SLinus Torvalds 	}
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
phcmp(const void * v1,const void * v2)1201da177e4SLinus Torvalds static int phcmp(const void *v1, const void *v2)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	const Elf32_Phdr *h1 = v1;
1231da177e4SLinus Torvalds 	const Elf32_Phdr *h2 = v2;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	if (h1->p_vaddr > h2->p_vaddr)
1261da177e4SLinus Torvalds 		return 1;
1271da177e4SLinus Torvalds 	else if (h1->p_vaddr < h2->p_vaddr)
1281da177e4SLinus Torvalds 		return -1;
1291da177e4SLinus Torvalds 	else
1301da177e4SLinus Torvalds 		return 0;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
saveRead(int file,off_t offset,off_t len,char * name)1331da177e4SLinus Torvalds static char *saveRead(int file, off_t offset, off_t len, char *name)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	char *tmp;
1361da177e4SLinus Torvalds 	int count;
1371da177e4SLinus Torvalds 	off_t off;
1381da177e4SLinus Torvalds 	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
1391da177e4SLinus Torvalds 		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
1401da177e4SLinus Torvalds 		exit(1);
1411da177e4SLinus Torvalds 	}
1421da177e4SLinus Torvalds 	if (!(tmp = (char *) malloc(len))) {
1431da177e4SLinus Torvalds 		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
1441da177e4SLinus Torvalds 			len);
1451da177e4SLinus Torvalds 		exit(1);
1461da177e4SLinus Torvalds 	}
1471da177e4SLinus Torvalds 	count = read(file, tmp, len);
1481da177e4SLinus Torvalds 	if (count != len) {
1491da177e4SLinus Torvalds 		fprintf(stderr, "%s: read: %s.\n",
1501da177e4SLinus Torvalds 			name,
1511da177e4SLinus Torvalds 			count ? strerror(errno) : "End of file reached");
1521da177e4SLinus Torvalds 		exit(1);
1531da177e4SLinus Torvalds 	}
1541da177e4SLinus Torvalds 	return tmp;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds #define swab16(x) \
1580c3bf184SThomas Bogendoerfer 	((uint16_t)( \
1590c3bf184SThomas Bogendoerfer 		(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
1600c3bf184SThomas Bogendoerfer 		(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds #define swab32(x) \
1631da177e4SLinus Torvalds 	((unsigned int)( \
1640c3bf184SThomas Bogendoerfer 		(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
1650c3bf184SThomas Bogendoerfer 		(((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) | \
1660c3bf184SThomas Bogendoerfer 		(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) | \
1670c3bf184SThomas Bogendoerfer 		(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
1681da177e4SLinus Torvalds 
convert_elf_hdr(Elf32_Ehdr * e)1691da177e4SLinus Torvalds static void convert_elf_hdr(Elf32_Ehdr * e)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	e->e_type = swab16(e->e_type);
1721da177e4SLinus Torvalds 	e->e_machine = swab16(e->e_machine);
1731da177e4SLinus Torvalds 	e->e_version = swab32(e->e_version);
1741da177e4SLinus Torvalds 	e->e_entry = swab32(e->e_entry);
1751da177e4SLinus Torvalds 	e->e_phoff = swab32(e->e_phoff);
1761da177e4SLinus Torvalds 	e->e_shoff = swab32(e->e_shoff);
1771da177e4SLinus Torvalds 	e->e_flags = swab32(e->e_flags);
1781da177e4SLinus Torvalds 	e->e_ehsize = swab16(e->e_ehsize);
1791da177e4SLinus Torvalds 	e->e_phentsize = swab16(e->e_phentsize);
1801da177e4SLinus Torvalds 	e->e_phnum = swab16(e->e_phnum);
1811da177e4SLinus Torvalds 	e->e_shentsize = swab16(e->e_shentsize);
1821da177e4SLinus Torvalds 	e->e_shnum = swab16(e->e_shnum);
1831da177e4SLinus Torvalds 	e->e_shstrndx = swab16(e->e_shstrndx);
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds 
convert_elf_phdrs(Elf32_Phdr * p,int num)1861da177e4SLinus Torvalds static void convert_elf_phdrs(Elf32_Phdr * p, int num)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds 	int i;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	for (i = 0; i < num; i++, p++) {
1911da177e4SLinus Torvalds 		p->p_type = swab32(p->p_type);
1921da177e4SLinus Torvalds 		p->p_offset = swab32(p->p_offset);
1931da177e4SLinus Torvalds 		p->p_vaddr = swab32(p->p_vaddr);
1941da177e4SLinus Torvalds 		p->p_paddr = swab32(p->p_paddr);
1951da177e4SLinus Torvalds 		p->p_filesz = swab32(p->p_filesz);
1961da177e4SLinus Torvalds 		p->p_memsz = swab32(p->p_memsz);
1971da177e4SLinus Torvalds 		p->p_flags = swab32(p->p_flags);
1981da177e4SLinus Torvalds 		p->p_align = swab32(p->p_align);
1991da177e4SLinus Torvalds 	}
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
convert_elf_shdrs(Elf32_Shdr * s,int num)2031da177e4SLinus Torvalds static void convert_elf_shdrs(Elf32_Shdr * s, int num)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	int i;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	for (i = 0; i < num; i++, s++) {
2081da177e4SLinus Torvalds 		s->sh_name = swab32(s->sh_name);
2091da177e4SLinus Torvalds 		s->sh_type = swab32(s->sh_type);
2101da177e4SLinus Torvalds 		s->sh_flags = swab32(s->sh_flags);
2111da177e4SLinus Torvalds 		s->sh_addr = swab32(s->sh_addr);
2121da177e4SLinus Torvalds 		s->sh_offset = swab32(s->sh_offset);
2131da177e4SLinus Torvalds 		s->sh_size = swab32(s->sh_size);
2141da177e4SLinus Torvalds 		s->sh_link = swab32(s->sh_link);
2151da177e4SLinus Torvalds 		s->sh_info = swab32(s->sh_info);
2161da177e4SLinus Torvalds 		s->sh_addralign = swab32(s->sh_addralign);
2171da177e4SLinus Torvalds 		s->sh_entsize = swab32(s->sh_entsize);
2181da177e4SLinus Torvalds 	}
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
convert_ecoff_filehdr(struct filehdr * f)2211da177e4SLinus Torvalds static void convert_ecoff_filehdr(struct filehdr *f)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	f->f_magic = swab16(f->f_magic);
2241da177e4SLinus Torvalds 	f->f_nscns = swab16(f->f_nscns);
2251da177e4SLinus Torvalds 	f->f_timdat = swab32(f->f_timdat);
2261da177e4SLinus Torvalds 	f->f_symptr = swab32(f->f_symptr);
2271da177e4SLinus Torvalds 	f->f_nsyms = swab32(f->f_nsyms);
2281da177e4SLinus Torvalds 	f->f_opthdr = swab16(f->f_opthdr);
2291da177e4SLinus Torvalds 	f->f_flags = swab16(f->f_flags);
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds 
convert_ecoff_aouthdr(struct aouthdr * a)2321da177e4SLinus Torvalds static void convert_ecoff_aouthdr(struct aouthdr *a)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	a->magic = swab16(a->magic);
2351da177e4SLinus Torvalds 	a->vstamp = swab16(a->vstamp);
2361da177e4SLinus Torvalds 	a->tsize = swab32(a->tsize);
2371da177e4SLinus Torvalds 	a->dsize = swab32(a->dsize);
2381da177e4SLinus Torvalds 	a->bsize = swab32(a->bsize);
2391da177e4SLinus Torvalds 	a->entry = swab32(a->entry);
2401da177e4SLinus Torvalds 	a->text_start = swab32(a->text_start);
2411da177e4SLinus Torvalds 	a->data_start = swab32(a->data_start);
2421da177e4SLinus Torvalds 	a->bss_start = swab32(a->bss_start);
2431da177e4SLinus Torvalds 	a->gprmask = swab32(a->gprmask);
2441da177e4SLinus Torvalds 	a->cprmask[0] = swab32(a->cprmask[0]);
2451da177e4SLinus Torvalds 	a->cprmask[1] = swab32(a->cprmask[1]);
2461da177e4SLinus Torvalds 	a->cprmask[2] = swab32(a->cprmask[2]);
2471da177e4SLinus Torvalds 	a->cprmask[3] = swab32(a->cprmask[3]);
2481da177e4SLinus Torvalds 	a->gp_value = swab32(a->gp_value);
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds 
convert_ecoff_esecs(struct scnhdr * s,int num)2511da177e4SLinus Torvalds static void convert_ecoff_esecs(struct scnhdr *s, int num)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds 	int i;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	for (i = 0; i < num; i++, s++) {
2561da177e4SLinus Torvalds 		s->s_paddr = swab32(s->s_paddr);
2571da177e4SLinus Torvalds 		s->s_vaddr = swab32(s->s_vaddr);
2581da177e4SLinus Torvalds 		s->s_size = swab32(s->s_size);
2591da177e4SLinus Torvalds 		s->s_scnptr = swab32(s->s_scnptr);
2601da177e4SLinus Torvalds 		s->s_relptr = swab32(s->s_relptr);
2611da177e4SLinus Torvalds 		s->s_lnnoptr = swab32(s->s_lnnoptr);
2621da177e4SLinus Torvalds 		s->s_nreloc = swab16(s->s_nreloc);
2631da177e4SLinus Torvalds 		s->s_nlnno = swab16(s->s_nlnno);
2641da177e4SLinus Torvalds 		s->s_flags = swab32(s->s_flags);
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds 
main(int argc,char * argv[])2681da177e4SLinus Torvalds int main(int argc, char *argv[])
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds 	Elf32_Ehdr ex;
2711da177e4SLinus Torvalds 	Elf32_Phdr *ph;
2721da177e4SLinus Torvalds 	Elf32_Shdr *sh;
2731da177e4SLinus Torvalds 	int i, pad;
2741da177e4SLinus Torvalds 	struct sect text, data, bss;
2751da177e4SLinus Torvalds 	struct filehdr efh;
2761da177e4SLinus Torvalds 	struct aouthdr eah;
2771da177e4SLinus Torvalds 	struct scnhdr esecs[6];
2781da177e4SLinus Torvalds 	int infile, outfile;
2790c3bf184SThomas Bogendoerfer 	uint32_t cur_vma = UINT32_MAX;
2801da177e4SLinus Torvalds 	int addflag = 0;
2811da177e4SLinus Torvalds 	int nosecs;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	text.len = data.len = bss.len = 0;
2841da177e4SLinus Torvalds 	text.vaddr = data.vaddr = bss.vaddr = 0;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	/* Check args... */
2871da177e4SLinus Torvalds 	if (argc < 3 || argc > 4) {
2881da177e4SLinus Torvalds 	      usage:
2891da177e4SLinus Torvalds 		fprintf(stderr,
2901da177e4SLinus Torvalds 			"usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
2911da177e4SLinus Torvalds 		exit(1);
2921da177e4SLinus Torvalds 	}
2931da177e4SLinus Torvalds 	if (argc == 4) {
2941da177e4SLinus Torvalds 		if (strcmp(argv[3], "-a"))
2951da177e4SLinus Torvalds 			goto usage;
2961da177e4SLinus Torvalds 		addflag = 1;
2971da177e4SLinus Torvalds 	}
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	/* Try the input file... */
3001da177e4SLinus Torvalds 	if ((infile = open(argv[1], O_RDONLY)) < 0) {
3011da177e4SLinus Torvalds 		fprintf(stderr, "Can't open %s for read: %s\n",
3021da177e4SLinus Torvalds 			argv[1], strerror(errno));
3031da177e4SLinus Torvalds 		exit(1);
3041da177e4SLinus Torvalds 	}
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	/* Read the header, which is at the beginning of the file... */
3071da177e4SLinus Torvalds 	i = read(infile, &ex, sizeof ex);
3081da177e4SLinus Torvalds 	if (i != sizeof ex) {
3091da177e4SLinus Torvalds 		fprintf(stderr, "ex: %s: %s.\n",
3101da177e4SLinus Torvalds 			argv[1],
3111da177e4SLinus Torvalds 			i ? strerror(errno) : "End of file reached");
3121da177e4SLinus Torvalds 		exit(1);
3131da177e4SLinus Torvalds 	}
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
3161da177e4SLinus Torvalds 		format_bigendian = 1;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	if (ntohs(0xaa55) == 0xaa55) {
3191da177e4SLinus Torvalds 		if (!format_bigendian)
3201da177e4SLinus Torvalds 			must_convert_endian = 1;
3211da177e4SLinus Torvalds 	} else {
3221da177e4SLinus Torvalds 		if (format_bigendian)
3231da177e4SLinus Torvalds 			must_convert_endian = 1;
3241da177e4SLinus Torvalds 	}
3251da177e4SLinus Torvalds 	if (must_convert_endian)
3261da177e4SLinus Torvalds 		convert_elf_hdr(&ex);
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	/* Read the program headers... */
3291da177e4SLinus Torvalds 	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
3301da177e4SLinus Torvalds 				     ex.e_phnum * sizeof(Elf32_Phdr),
3311da177e4SLinus Torvalds 				     "ph");
3321da177e4SLinus Torvalds 	if (must_convert_endian)
3331da177e4SLinus Torvalds 		convert_elf_phdrs(ph, ex.e_phnum);
3341da177e4SLinus Torvalds 	/* Read the section headers... */
3351da177e4SLinus Torvalds 	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
3361da177e4SLinus Torvalds 				     ex.e_shnum * sizeof(Elf32_Shdr),
3371da177e4SLinus Torvalds 				     "sh");
3381da177e4SLinus Torvalds 	if (must_convert_endian)
3391da177e4SLinus Torvalds 		convert_elf_shdrs(sh, ex.e_shnum);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	/* Figure out if we can cram the program header into an ECOFF
3421da177e4SLinus Torvalds 	   header...  Basically, we can't handle anything but loadable
3431da177e4SLinus Torvalds 	   segments, but we can ignore some kinds of segments.	We can't
3441da177e4SLinus Torvalds 	   handle holes in the address space.  Segments may be out of order,
3451da177e4SLinus Torvalds 	   so we sort them first. */
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	for (i = 0; i < ex.e_phnum; i++) {
3501da177e4SLinus Torvalds 		/* Section types we can ignore... */
35106a40ed1SRalf Baechle 		switch (ph[i].p_type) {
35206a40ed1SRalf Baechle 		case PT_NULL:
35306a40ed1SRalf Baechle 		case PT_NOTE:
35406a40ed1SRalf Baechle 		case PT_PHDR:
35506a40ed1SRalf Baechle 		case PT_MIPS_REGINFO:
35626f7c4bdSRalf Baechle 		case PT_MIPS_ABIFLAGS:
3571da177e4SLinus Torvalds 			continue;
35806a40ed1SRalf Baechle 
35906a40ed1SRalf Baechle 		case PT_LOAD:
3601da177e4SLinus Torvalds 			/* Writable (data) segment? */
3611da177e4SLinus Torvalds 			if (ph[i].p_flags & PF_W) {
3621da177e4SLinus Torvalds 				struct sect ndata, nbss;
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 				ndata.vaddr = ph[i].p_vaddr;
3651da177e4SLinus Torvalds 				ndata.len = ph[i].p_filesz;
3661da177e4SLinus Torvalds 				nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
3671da177e4SLinus Torvalds 				nbss.len = ph[i].p_memsz - ph[i].p_filesz;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 				combine(&data, &ndata, 0);
3701da177e4SLinus Torvalds 				combine(&bss, &nbss, 1);
3711da177e4SLinus Torvalds 			} else {
3721da177e4SLinus Torvalds 				struct sect ntxt;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 				ntxt.vaddr = ph[i].p_vaddr;
3751da177e4SLinus Torvalds 				ntxt.len = ph[i].p_filesz;
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 				combine(&text, &ntxt, 0);
3781da177e4SLinus Torvalds 			}
3791da177e4SLinus Torvalds 			/* Remember the lowest segment start address. */
3801da177e4SLinus Torvalds 			if (ph[i].p_vaddr < cur_vma)
3811da177e4SLinus Torvalds 				cur_vma = ph[i].p_vaddr;
38206a40ed1SRalf Baechle 			break;
38306a40ed1SRalf Baechle 
38406a40ed1SRalf Baechle 		default:
38506a40ed1SRalf Baechle 			/* Section types we can't handle... */
38606a40ed1SRalf Baechle 			fprintf(stderr,
38706a40ed1SRalf Baechle 				"Program header %d type %d can't be converted.\n",
38806a40ed1SRalf Baechle 				ex.e_phnum, ph[i].p_type);
38906a40ed1SRalf Baechle 			exit(1);
39006a40ed1SRalf Baechle 		}
3911da177e4SLinus Torvalds 	}
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	/* Sections must be in order to be converted... */
3941da177e4SLinus Torvalds 	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
3951da177e4SLinus Torvalds 	    text.vaddr + text.len > data.vaddr
3961da177e4SLinus Torvalds 	    || data.vaddr + data.len > bss.vaddr) {
3971da177e4SLinus Torvalds 		fprintf(stderr,
3981da177e4SLinus Torvalds 			"Sections ordering prevents a.out conversion.\n");
3991da177e4SLinus Torvalds 		exit(1);
4001da177e4SLinus Torvalds 	}
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	/* If there's a data section but no text section, then the loader
4031da177e4SLinus Torvalds 	   combined everything into one section.   That needs to be the
4041da177e4SLinus Torvalds 	   text section, so just make the data section zero length following
4051da177e4SLinus Torvalds 	   text. */
4061da177e4SLinus Torvalds 	if (data.len && !text.len) {
4071da177e4SLinus Torvalds 		text = data;
4081da177e4SLinus Torvalds 		data.vaddr = text.vaddr + text.len;
4091da177e4SLinus Torvalds 		data.len = 0;
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	/* If there is a gap between text and data, we'll fill it when we copy
4131da177e4SLinus Torvalds 	   the data, so update the length of the text segment as represented in
4141da177e4SLinus Torvalds 	   a.out to reflect that, since a.out doesn't allow gaps in the program
4151da177e4SLinus Torvalds 	   address space. */
4161da177e4SLinus Torvalds 	if (text.vaddr + text.len < data.vaddr)
4171da177e4SLinus Torvalds 		text.len = data.vaddr - text.vaddr;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	/* We now have enough information to cons up an a.out header... */
4201da177e4SLinus Torvalds 	eah.magic = OMAGIC;
4211da177e4SLinus Torvalds 	eah.vstamp = 200;
4221da177e4SLinus Torvalds 	eah.tsize = text.len;
4231da177e4SLinus Torvalds 	eah.dsize = data.len;
4241da177e4SLinus Torvalds 	eah.bsize = bss.len;
4251da177e4SLinus Torvalds 	eah.entry = ex.e_entry;
4261da177e4SLinus Torvalds 	eah.text_start = text.vaddr;
4271da177e4SLinus Torvalds 	eah.data_start = data.vaddr;
4281da177e4SLinus Torvalds 	eah.bss_start = bss.vaddr;
4291da177e4SLinus Torvalds 	eah.gprmask = 0xf3fffffe;
4301da177e4SLinus Torvalds 	memset(&eah.cprmask, '\0', sizeof eah.cprmask);
4311da177e4SLinus Torvalds 	eah.gp_value = 0;	/* unused. */
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds 	if (format_bigendian)
4341da177e4SLinus Torvalds 		efh.f_magic = MIPSEBMAGIC;
4351da177e4SLinus Torvalds 	else
4361da177e4SLinus Torvalds 		efh.f_magic = MIPSELMAGIC;
4371da177e4SLinus Torvalds 	if (addflag)
4381da177e4SLinus Torvalds 		nosecs = 6;
4391da177e4SLinus Torvalds 	else
4401da177e4SLinus Torvalds 		nosecs = 3;
4411da177e4SLinus Torvalds 	efh.f_nscns = nosecs;
4421da177e4SLinus Torvalds 	efh.f_timdat = 0;	/* bogus */
4431da177e4SLinus Torvalds 	efh.f_symptr = 0;
4441da177e4SLinus Torvalds 	efh.f_nsyms = 0;
4451da177e4SLinus Torvalds 	efh.f_opthdr = sizeof eah;
4461da177e4SLinus Torvalds 	efh.f_flags = 0x100f;	/* Stripped, not sharable. */
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	memset(esecs, 0, sizeof esecs);
4491da177e4SLinus Torvalds 	strcpy(esecs[0].s_name, ".text");
4501da177e4SLinus Torvalds 	strcpy(esecs[1].s_name, ".data");
4511da177e4SLinus Torvalds 	strcpy(esecs[2].s_name, ".bss");
4521da177e4SLinus Torvalds 	if (addflag) {
4531da177e4SLinus Torvalds 		strcpy(esecs[3].s_name, ".rdata");
4541da177e4SLinus Torvalds 		strcpy(esecs[4].s_name, ".sdata");
4551da177e4SLinus Torvalds 		strcpy(esecs[5].s_name, ".sbss");
4561da177e4SLinus Torvalds 	}
4571da177e4SLinus Torvalds 	esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
4581da177e4SLinus Torvalds 	esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
4591da177e4SLinus Torvalds 	esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
4601da177e4SLinus Torvalds 	if (addflag) {
4611da177e4SLinus Torvalds 		esecs[3].s_paddr = esecs[3].s_vaddr = 0;
4621da177e4SLinus Torvalds 		esecs[4].s_paddr = esecs[4].s_vaddr = 0;
4631da177e4SLinus Torvalds 		esecs[5].s_paddr = esecs[5].s_vaddr = 0;
4641da177e4SLinus Torvalds 	}
4651da177e4SLinus Torvalds 	esecs[0].s_size = eah.tsize;
4661da177e4SLinus Torvalds 	esecs[1].s_size = eah.dsize;
4671da177e4SLinus Torvalds 	esecs[2].s_size = eah.bsize;
4681da177e4SLinus Torvalds 	if (addflag) {
4691da177e4SLinus Torvalds 		esecs[3].s_size = 0;
4701da177e4SLinus Torvalds 		esecs[4].s_size = 0;
4711da177e4SLinus Torvalds 		esecs[5].s_size = 0;
4721da177e4SLinus Torvalds 	}
4731da177e4SLinus Torvalds 	esecs[0].s_scnptr = N_TXTOFF(efh, eah);
4741da177e4SLinus Torvalds 	esecs[1].s_scnptr = N_DATOFF(efh, eah);
4751da177e4SLinus Torvalds #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
4761da177e4SLinus Torvalds #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
4771da177e4SLinus Torvalds 	esecs[2].s_scnptr = esecs[1].s_scnptr +
4781da177e4SLinus Torvalds 	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
4791da177e4SLinus Torvalds 	if (addflag) {
4801da177e4SLinus Torvalds 		esecs[3].s_scnptr = 0;
4811da177e4SLinus Torvalds 		esecs[4].s_scnptr = 0;
4821da177e4SLinus Torvalds 		esecs[5].s_scnptr = 0;
4831da177e4SLinus Torvalds 	}
4841da177e4SLinus Torvalds 	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
4851da177e4SLinus Torvalds 	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
4861da177e4SLinus Torvalds 	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
4871da177e4SLinus Torvalds 	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
4881da177e4SLinus Torvalds 	if (addflag) {
4891da177e4SLinus Torvalds 		esecs[3].s_relptr = esecs[4].s_relptr
4901da177e4SLinus Torvalds 		    = esecs[5].s_relptr = 0;
4911da177e4SLinus Torvalds 		esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
4921da177e4SLinus Torvalds 		    = esecs[5].s_lnnoptr = 0;
4931da177e4SLinus Torvalds 		esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
4941da177e4SLinus Torvalds 		    0;
4951da177e4SLinus Torvalds 		esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 	esecs[0].s_flags = 0x20;
4981da177e4SLinus Torvalds 	esecs[1].s_flags = 0x40;
4991da177e4SLinus Torvalds 	esecs[2].s_flags = 0x82;
5001da177e4SLinus Torvalds 	if (addflag) {
5011da177e4SLinus Torvalds 		esecs[3].s_flags = 0x100;
5021da177e4SLinus Torvalds 		esecs[4].s_flags = 0x200;
5031da177e4SLinus Torvalds 		esecs[5].s_flags = 0x400;
5041da177e4SLinus Torvalds 	}
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	/* Make the output file... */
5071da177e4SLinus Torvalds 	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
5081da177e4SLinus Torvalds 		fprintf(stderr, "Unable to create %s: %s\n", argv[2],
5091da177e4SLinus Torvalds 			strerror(errno));
5101da177e4SLinus Torvalds 		exit(1);
5111da177e4SLinus Torvalds 	}
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	if (must_convert_endian)
5141da177e4SLinus Torvalds 		convert_ecoff_filehdr(&efh);
5151da177e4SLinus Torvalds 	/* Write the headers... */
5161da177e4SLinus Torvalds 	i = write(outfile, &efh, sizeof efh);
5171da177e4SLinus Torvalds 	if (i != sizeof efh) {
5181da177e4SLinus Torvalds 		perror("efh: write");
5191da177e4SLinus Torvalds 		exit(1);
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 		for (i = 0; i < nosecs; i++) {
5221da177e4SLinus Torvalds 			printf
5230c3bf184SThomas Bogendoerfer 			    ("Section %d: %s phys %"PRIx32"  size %"PRIx32"\t file offset %"PRIx32"\n",
5241da177e4SLinus Torvalds 			     i, esecs[i].s_name, esecs[i].s_paddr,
5251da177e4SLinus Torvalds 			     esecs[i].s_size, esecs[i].s_scnptr);
5261da177e4SLinus Torvalds 		}
5271da177e4SLinus Torvalds 	}
5281da177e4SLinus Torvalds 	fprintf(stderr, "wrote %d byte file header.\n", i);
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	if (must_convert_endian)
5311da177e4SLinus Torvalds 		convert_ecoff_aouthdr(&eah);
5321da177e4SLinus Torvalds 	i = write(outfile, &eah, sizeof eah);
5331da177e4SLinus Torvalds 	if (i != sizeof eah) {
5341da177e4SLinus Torvalds 		perror("eah: write");
5351da177e4SLinus Torvalds 		exit(1);
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds 	fprintf(stderr, "wrote %d byte a.out header.\n", i);
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds 	if (must_convert_endian)
5401da177e4SLinus Torvalds 		convert_ecoff_esecs(&esecs[0], nosecs);
5411da177e4SLinus Torvalds 	i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
5421da177e4SLinus Torvalds 	if (i != nosecs * sizeof(struct scnhdr)) {
5431da177e4SLinus Torvalds 		perror("esecs: write");
5441da177e4SLinus Torvalds 		exit(1);
5451da177e4SLinus Torvalds 	}
5461da177e4SLinus Torvalds 	fprintf(stderr, "wrote %d bytes of section headers.\n", i);
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
5491da177e4SLinus Torvalds 	if (pad) {
5501da177e4SLinus Torvalds 		pad = 16 - pad;
5511da177e4SLinus Torvalds 		i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
5521da177e4SLinus Torvalds 		if (i < 0) {
5531da177e4SLinus Torvalds 			perror("ipad: write");
5541da177e4SLinus Torvalds 			exit(1);
5551da177e4SLinus Torvalds 		}
5561da177e4SLinus Torvalds 		fprintf(stderr, "wrote %d byte pad.\n", i);
5571da177e4SLinus Torvalds 	}
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	/*
5601da177e4SLinus Torvalds 	 * Copy the loadable sections.	 Zero-fill any gaps less than 64k;
5611da177e4SLinus Torvalds 	 * complain about any zero-filling, and die if we're asked to zero-fill
5621da177e4SLinus Torvalds 	 * more than 64k.
5631da177e4SLinus Torvalds 	 */
5641da177e4SLinus Torvalds 	for (i = 0; i < ex.e_phnum; i++) {
5651da177e4SLinus Torvalds 		/* Unprocessable sections were handled above, so just verify that
5661da177e4SLinus Torvalds 		   the section can be loaded before copying. */
5671da177e4SLinus Torvalds 		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
5681da177e4SLinus Torvalds 			if (cur_vma != ph[i].p_vaddr) {
5690c3bf184SThomas Bogendoerfer 				uint32_t gap = ph[i].p_vaddr - cur_vma;
5701da177e4SLinus Torvalds 				char obuf[1024];
5711da177e4SLinus Torvalds 				if (gap > 65536) {
5721da177e4SLinus Torvalds 					fprintf(stderr,
5730c3bf184SThomas Bogendoerfer 						"Intersegment gap (%"PRId32" bytes) too large.\n",
5741da177e4SLinus Torvalds 						gap);
5751da177e4SLinus Torvalds 					exit(1);
5761da177e4SLinus Torvalds 				}
5771da177e4SLinus Torvalds 				fprintf(stderr,
5780c3bf184SThomas Bogendoerfer 					"Warning: %d byte intersegment gap.\n",
5791da177e4SLinus Torvalds 					gap);
5801da177e4SLinus Torvalds 				memset(obuf, 0, sizeof obuf);
5811da177e4SLinus Torvalds 				while (gap) {
5821da177e4SLinus Torvalds 					int count =
5831da177e4SLinus Torvalds 					    write(outfile, obuf,
5841da177e4SLinus Torvalds 						  (gap >
5851da177e4SLinus Torvalds 						   sizeof obuf ? sizeof
5861da177e4SLinus Torvalds 						   obuf : gap));
5871da177e4SLinus Torvalds 					if (count < 0) {
5881da177e4SLinus Torvalds 						fprintf(stderr,
5891da177e4SLinus Torvalds 							"Error writing gap: %s\n",
5901da177e4SLinus Torvalds 							strerror(errno));
5911da177e4SLinus Torvalds 						exit(1);
5921da177e4SLinus Torvalds 					}
5931da177e4SLinus Torvalds 					gap -= count;
5941da177e4SLinus Torvalds 				}
5951da177e4SLinus Torvalds 			}
5961da177e4SLinus Torvalds 			fprintf(stderr, "writing %d bytes...\n",
5971da177e4SLinus Torvalds 				ph[i].p_filesz);
5981da177e4SLinus Torvalds 			copy(outfile, infile, ph[i].p_offset,
5991da177e4SLinus Torvalds 			     ph[i].p_filesz);
6001da177e4SLinus Torvalds 			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
6011da177e4SLinus Torvalds 		}
6021da177e4SLinus Torvalds 	}
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	/*
6051da177e4SLinus Torvalds 	 * Write a page of padding for boot PROMS that read entire pages.
6061da177e4SLinus Torvalds 	 * Without this, they may attempt to read past the end of the
6071da177e4SLinus Torvalds 	 * data section, incur an error, and refuse to boot.
6081da177e4SLinus Torvalds 	 */
6091da177e4SLinus Torvalds 	{
6101da177e4SLinus Torvalds 		char obuf[4096];
6111da177e4SLinus Torvalds 		memset(obuf, 0, sizeof obuf);
6121da177e4SLinus Torvalds 		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
6131da177e4SLinus Torvalds 			fprintf(stderr, "Error writing PROM padding: %s\n",
6141da177e4SLinus Torvalds 				strerror(errno));
6151da177e4SLinus Torvalds 			exit(1);
6161da177e4SLinus Torvalds 		}
6171da177e4SLinus Torvalds 	}
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	/* Looks like we won... */
6201da177e4SLinus Torvalds 	exit(0);
6211da177e4SLinus Torvalds }
622