162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 1995
362306a36Sopenharmony_ci *	Ted Lemon (hereinafter referred to as the author)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
762306a36Sopenharmony_ci * are met:
862306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
962306a36Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
1062306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
1162306a36Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
1262306a36Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
1362306a36Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
1462306a36Sopenharmony_ci *    derived from this software without specific prior written permission.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
1762306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1862306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1962306a36Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
2062306a36Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2162306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2262306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2362306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2462306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2562306a36Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2662306a36Sopenharmony_ci * SUCH DAMAGE.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* elf2ecoff.c
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci   This program converts an elf executable to an ECOFF executable.
3262306a36Sopenharmony_ci   No symbol table is retained.	  This is useful primarily in building
3362306a36Sopenharmony_ci   net-bootable kernels for machines (e.g., DECstation and Alpha) which
3462306a36Sopenharmony_ci   only support the ECOFF object file format. */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <stdio.h>
3762306a36Sopenharmony_ci#include <string.h>
3862306a36Sopenharmony_ci#include <errno.h>
3962306a36Sopenharmony_ci#include <sys/types.h>
4062306a36Sopenharmony_ci#include <fcntl.h>
4162306a36Sopenharmony_ci#include <unistd.h>
4262306a36Sopenharmony_ci#include <elf.h>
4362306a36Sopenharmony_ci#include <limits.h>
4462306a36Sopenharmony_ci#include <netinet/in.h>
4562306a36Sopenharmony_ci#include <stdlib.h>
4662306a36Sopenharmony_ci#include <stdint.h>
4762306a36Sopenharmony_ci#include <inttypes.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include "ecoff.h"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Some extra ELF definitions
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ci#define PT_MIPS_REGINFO 	0x70000000	/* Register usage information */
5562306a36Sopenharmony_ci#define PT_MIPS_ABIFLAGS	0x70000003	/* Records ABI related flags  */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct sect {
6062306a36Sopenharmony_ci	uint32_t vaddr;
6162306a36Sopenharmony_ci	uint32_t len;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciint *symTypeTable;
6562306a36Sopenharmony_ciint must_convert_endian;
6662306a36Sopenharmony_ciint format_bigendian;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void copy(int out, int in, off_t offset, off_t size)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	char ibuf[4096];
7162306a36Sopenharmony_ci	int remaining, cur, count;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* Go to the start of the ELF symbol table... */
7462306a36Sopenharmony_ci	if (lseek(in, offset, SEEK_SET) < 0) {
7562306a36Sopenharmony_ci		perror("copy: lseek");
7662306a36Sopenharmony_ci		exit(1);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	remaining = size;
8062306a36Sopenharmony_ci	while (remaining) {
8162306a36Sopenharmony_ci		cur = remaining;
8262306a36Sopenharmony_ci		if (cur > sizeof ibuf)
8362306a36Sopenharmony_ci			cur = sizeof ibuf;
8462306a36Sopenharmony_ci		remaining -= cur;
8562306a36Sopenharmony_ci		if ((count = read(in, ibuf, cur)) != cur) {
8662306a36Sopenharmony_ci			fprintf(stderr, "copy: read: %s\n",
8762306a36Sopenharmony_ci				count ? strerror(errno) :
8862306a36Sopenharmony_ci				"premature end of file");
8962306a36Sopenharmony_ci			exit(1);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci		if ((count = write(out, ibuf, cur)) != cur) {
9262306a36Sopenharmony_ci			perror("copy: write");
9362306a36Sopenharmony_ci			exit(1);
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*
9962306a36Sopenharmony_ci * Combine two segments, which must be contiguous.   If pad is true, it's
10062306a36Sopenharmony_ci * okay for there to be padding between.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_cistatic void combine(struct sect *base, struct sect *new, int pad)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	if (!base->len)
10562306a36Sopenharmony_ci		*base = *new;
10662306a36Sopenharmony_ci	else if (new->len) {
10762306a36Sopenharmony_ci		if (base->vaddr + base->len != new->vaddr) {
10862306a36Sopenharmony_ci			if (pad)
10962306a36Sopenharmony_ci				base->len = new->vaddr - base->vaddr;
11062306a36Sopenharmony_ci			else {
11162306a36Sopenharmony_ci				fprintf(stderr,
11262306a36Sopenharmony_ci					"Non-contiguous data can't be converted.\n");
11362306a36Sopenharmony_ci				exit(1);
11462306a36Sopenharmony_ci			}
11562306a36Sopenharmony_ci		}
11662306a36Sopenharmony_ci		base->len += new->len;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int phcmp(const void *v1, const void *v2)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	const Elf32_Phdr *h1 = v1;
12362306a36Sopenharmony_ci	const Elf32_Phdr *h2 = v2;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (h1->p_vaddr > h2->p_vaddr)
12662306a36Sopenharmony_ci		return 1;
12762306a36Sopenharmony_ci	else if (h1->p_vaddr < h2->p_vaddr)
12862306a36Sopenharmony_ci		return -1;
12962306a36Sopenharmony_ci	else
13062306a36Sopenharmony_ci		return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic char *saveRead(int file, off_t offset, off_t len, char *name)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	char *tmp;
13662306a36Sopenharmony_ci	int count;
13762306a36Sopenharmony_ci	off_t off;
13862306a36Sopenharmony_ci	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
13962306a36Sopenharmony_ci		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
14062306a36Sopenharmony_ci		exit(1);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	if (!(tmp = (char *) malloc(len))) {
14362306a36Sopenharmony_ci		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
14462306a36Sopenharmony_ci			len);
14562306a36Sopenharmony_ci		exit(1);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	count = read(file, tmp, len);
14862306a36Sopenharmony_ci	if (count != len) {
14962306a36Sopenharmony_ci		fprintf(stderr, "%s: read: %s.\n",
15062306a36Sopenharmony_ci			name,
15162306a36Sopenharmony_ci			count ? strerror(errno) : "End of file reached");
15262306a36Sopenharmony_ci		exit(1);
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci	return tmp;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define swab16(x) \
15862306a36Sopenharmony_ci	((uint16_t)( \
15962306a36Sopenharmony_ci		(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
16062306a36Sopenharmony_ci		(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define swab32(x) \
16362306a36Sopenharmony_ci	((unsigned int)( \
16462306a36Sopenharmony_ci		(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
16562306a36Sopenharmony_ci		(((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) | \
16662306a36Sopenharmony_ci		(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) | \
16762306a36Sopenharmony_ci		(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void convert_elf_hdr(Elf32_Ehdr * e)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	e->e_type = swab16(e->e_type);
17262306a36Sopenharmony_ci	e->e_machine = swab16(e->e_machine);
17362306a36Sopenharmony_ci	e->e_version = swab32(e->e_version);
17462306a36Sopenharmony_ci	e->e_entry = swab32(e->e_entry);
17562306a36Sopenharmony_ci	e->e_phoff = swab32(e->e_phoff);
17662306a36Sopenharmony_ci	e->e_shoff = swab32(e->e_shoff);
17762306a36Sopenharmony_ci	e->e_flags = swab32(e->e_flags);
17862306a36Sopenharmony_ci	e->e_ehsize = swab16(e->e_ehsize);
17962306a36Sopenharmony_ci	e->e_phentsize = swab16(e->e_phentsize);
18062306a36Sopenharmony_ci	e->e_phnum = swab16(e->e_phnum);
18162306a36Sopenharmony_ci	e->e_shentsize = swab16(e->e_shentsize);
18262306a36Sopenharmony_ci	e->e_shnum = swab16(e->e_shnum);
18362306a36Sopenharmony_ci	e->e_shstrndx = swab16(e->e_shstrndx);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void convert_elf_phdrs(Elf32_Phdr * p, int num)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	int i;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	for (i = 0; i < num; i++, p++) {
19162306a36Sopenharmony_ci		p->p_type = swab32(p->p_type);
19262306a36Sopenharmony_ci		p->p_offset = swab32(p->p_offset);
19362306a36Sopenharmony_ci		p->p_vaddr = swab32(p->p_vaddr);
19462306a36Sopenharmony_ci		p->p_paddr = swab32(p->p_paddr);
19562306a36Sopenharmony_ci		p->p_filesz = swab32(p->p_filesz);
19662306a36Sopenharmony_ci		p->p_memsz = swab32(p->p_memsz);
19762306a36Sopenharmony_ci		p->p_flags = swab32(p->p_flags);
19862306a36Sopenharmony_ci		p->p_align = swab32(p->p_align);
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void convert_elf_shdrs(Elf32_Shdr * s, int num)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int i;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	for (i = 0; i < num; i++, s++) {
20862306a36Sopenharmony_ci		s->sh_name = swab32(s->sh_name);
20962306a36Sopenharmony_ci		s->sh_type = swab32(s->sh_type);
21062306a36Sopenharmony_ci		s->sh_flags = swab32(s->sh_flags);
21162306a36Sopenharmony_ci		s->sh_addr = swab32(s->sh_addr);
21262306a36Sopenharmony_ci		s->sh_offset = swab32(s->sh_offset);
21362306a36Sopenharmony_ci		s->sh_size = swab32(s->sh_size);
21462306a36Sopenharmony_ci		s->sh_link = swab32(s->sh_link);
21562306a36Sopenharmony_ci		s->sh_info = swab32(s->sh_info);
21662306a36Sopenharmony_ci		s->sh_addralign = swab32(s->sh_addralign);
21762306a36Sopenharmony_ci		s->sh_entsize = swab32(s->sh_entsize);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic void convert_ecoff_filehdr(struct filehdr *f)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	f->f_magic = swab16(f->f_magic);
22462306a36Sopenharmony_ci	f->f_nscns = swab16(f->f_nscns);
22562306a36Sopenharmony_ci	f->f_timdat = swab32(f->f_timdat);
22662306a36Sopenharmony_ci	f->f_symptr = swab32(f->f_symptr);
22762306a36Sopenharmony_ci	f->f_nsyms = swab32(f->f_nsyms);
22862306a36Sopenharmony_ci	f->f_opthdr = swab16(f->f_opthdr);
22962306a36Sopenharmony_ci	f->f_flags = swab16(f->f_flags);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void convert_ecoff_aouthdr(struct aouthdr *a)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	a->magic = swab16(a->magic);
23562306a36Sopenharmony_ci	a->vstamp = swab16(a->vstamp);
23662306a36Sopenharmony_ci	a->tsize = swab32(a->tsize);
23762306a36Sopenharmony_ci	a->dsize = swab32(a->dsize);
23862306a36Sopenharmony_ci	a->bsize = swab32(a->bsize);
23962306a36Sopenharmony_ci	a->entry = swab32(a->entry);
24062306a36Sopenharmony_ci	a->text_start = swab32(a->text_start);
24162306a36Sopenharmony_ci	a->data_start = swab32(a->data_start);
24262306a36Sopenharmony_ci	a->bss_start = swab32(a->bss_start);
24362306a36Sopenharmony_ci	a->gprmask = swab32(a->gprmask);
24462306a36Sopenharmony_ci	a->cprmask[0] = swab32(a->cprmask[0]);
24562306a36Sopenharmony_ci	a->cprmask[1] = swab32(a->cprmask[1]);
24662306a36Sopenharmony_ci	a->cprmask[2] = swab32(a->cprmask[2]);
24762306a36Sopenharmony_ci	a->cprmask[3] = swab32(a->cprmask[3]);
24862306a36Sopenharmony_ci	a->gp_value = swab32(a->gp_value);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void convert_ecoff_esecs(struct scnhdr *s, int num)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	int i;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	for (i = 0; i < num; i++, s++) {
25662306a36Sopenharmony_ci		s->s_paddr = swab32(s->s_paddr);
25762306a36Sopenharmony_ci		s->s_vaddr = swab32(s->s_vaddr);
25862306a36Sopenharmony_ci		s->s_size = swab32(s->s_size);
25962306a36Sopenharmony_ci		s->s_scnptr = swab32(s->s_scnptr);
26062306a36Sopenharmony_ci		s->s_relptr = swab32(s->s_relptr);
26162306a36Sopenharmony_ci		s->s_lnnoptr = swab32(s->s_lnnoptr);
26262306a36Sopenharmony_ci		s->s_nreloc = swab16(s->s_nreloc);
26362306a36Sopenharmony_ci		s->s_nlnno = swab16(s->s_nlnno);
26462306a36Sopenharmony_ci		s->s_flags = swab32(s->s_flags);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ciint main(int argc, char *argv[])
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	Elf32_Ehdr ex;
27162306a36Sopenharmony_ci	Elf32_Phdr *ph;
27262306a36Sopenharmony_ci	Elf32_Shdr *sh;
27362306a36Sopenharmony_ci	int i, pad;
27462306a36Sopenharmony_ci	struct sect text, data, bss;
27562306a36Sopenharmony_ci	struct filehdr efh;
27662306a36Sopenharmony_ci	struct aouthdr eah;
27762306a36Sopenharmony_ci	struct scnhdr esecs[6];
27862306a36Sopenharmony_ci	int infile, outfile;
27962306a36Sopenharmony_ci	uint32_t cur_vma = UINT32_MAX;
28062306a36Sopenharmony_ci	int addflag = 0;
28162306a36Sopenharmony_ci	int nosecs;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	text.len = data.len = bss.len = 0;
28462306a36Sopenharmony_ci	text.vaddr = data.vaddr = bss.vaddr = 0;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Check args... */
28762306a36Sopenharmony_ci	if (argc < 3 || argc > 4) {
28862306a36Sopenharmony_ci	      usage:
28962306a36Sopenharmony_ci		fprintf(stderr,
29062306a36Sopenharmony_ci			"usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
29162306a36Sopenharmony_ci		exit(1);
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci	if (argc == 4) {
29462306a36Sopenharmony_ci		if (strcmp(argv[3], "-a"))
29562306a36Sopenharmony_ci			goto usage;
29662306a36Sopenharmony_ci		addflag = 1;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* Try the input file... */
30062306a36Sopenharmony_ci	if ((infile = open(argv[1], O_RDONLY)) < 0) {
30162306a36Sopenharmony_ci		fprintf(stderr, "Can't open %s for read: %s\n",
30262306a36Sopenharmony_ci			argv[1], strerror(errno));
30362306a36Sopenharmony_ci		exit(1);
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Read the header, which is at the beginning of the file... */
30762306a36Sopenharmony_ci	i = read(infile, &ex, sizeof ex);
30862306a36Sopenharmony_ci	if (i != sizeof ex) {
30962306a36Sopenharmony_ci		fprintf(stderr, "ex: %s: %s.\n",
31062306a36Sopenharmony_ci			argv[1],
31162306a36Sopenharmony_ci			i ? strerror(errno) : "End of file reached");
31262306a36Sopenharmony_ci		exit(1);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
31662306a36Sopenharmony_ci		format_bigendian = 1;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (ntohs(0xaa55) == 0xaa55) {
31962306a36Sopenharmony_ci		if (!format_bigendian)
32062306a36Sopenharmony_ci			must_convert_endian = 1;
32162306a36Sopenharmony_ci	} else {
32262306a36Sopenharmony_ci		if (format_bigendian)
32362306a36Sopenharmony_ci			must_convert_endian = 1;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci	if (must_convert_endian)
32662306a36Sopenharmony_ci		convert_elf_hdr(&ex);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Read the program headers... */
32962306a36Sopenharmony_ci	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
33062306a36Sopenharmony_ci				     ex.e_phnum * sizeof(Elf32_Phdr),
33162306a36Sopenharmony_ci				     "ph");
33262306a36Sopenharmony_ci	if (must_convert_endian)
33362306a36Sopenharmony_ci		convert_elf_phdrs(ph, ex.e_phnum);
33462306a36Sopenharmony_ci	/* Read the section headers... */
33562306a36Sopenharmony_ci	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
33662306a36Sopenharmony_ci				     ex.e_shnum * sizeof(Elf32_Shdr),
33762306a36Sopenharmony_ci				     "sh");
33862306a36Sopenharmony_ci	if (must_convert_endian)
33962306a36Sopenharmony_ci		convert_elf_shdrs(sh, ex.e_shnum);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Figure out if we can cram the program header into an ECOFF
34262306a36Sopenharmony_ci	   header...  Basically, we can't handle anything but loadable
34362306a36Sopenharmony_ci	   segments, but we can ignore some kinds of segments.	We can't
34462306a36Sopenharmony_ci	   handle holes in the address space.  Segments may be out of order,
34562306a36Sopenharmony_ci	   so we sort them first. */
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	for (i = 0; i < ex.e_phnum; i++) {
35062306a36Sopenharmony_ci		/* Section types we can ignore... */
35162306a36Sopenharmony_ci		switch (ph[i].p_type) {
35262306a36Sopenharmony_ci		case PT_NULL:
35362306a36Sopenharmony_ci		case PT_NOTE:
35462306a36Sopenharmony_ci		case PT_PHDR:
35562306a36Sopenharmony_ci		case PT_MIPS_REGINFO:
35662306a36Sopenharmony_ci		case PT_MIPS_ABIFLAGS:
35762306a36Sopenharmony_ci			continue;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		case PT_LOAD:
36062306a36Sopenharmony_ci			/* Writable (data) segment? */
36162306a36Sopenharmony_ci			if (ph[i].p_flags & PF_W) {
36262306a36Sopenharmony_ci				struct sect ndata, nbss;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci				ndata.vaddr = ph[i].p_vaddr;
36562306a36Sopenharmony_ci				ndata.len = ph[i].p_filesz;
36662306a36Sopenharmony_ci				nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
36762306a36Sopenharmony_ci				nbss.len = ph[i].p_memsz - ph[i].p_filesz;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci				combine(&data, &ndata, 0);
37062306a36Sopenharmony_ci				combine(&bss, &nbss, 1);
37162306a36Sopenharmony_ci			} else {
37262306a36Sopenharmony_ci				struct sect ntxt;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci				ntxt.vaddr = ph[i].p_vaddr;
37562306a36Sopenharmony_ci				ntxt.len = ph[i].p_filesz;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci				combine(&text, &ntxt, 0);
37862306a36Sopenharmony_ci			}
37962306a36Sopenharmony_ci			/* Remember the lowest segment start address. */
38062306a36Sopenharmony_ci			if (ph[i].p_vaddr < cur_vma)
38162306a36Sopenharmony_ci				cur_vma = ph[i].p_vaddr;
38262306a36Sopenharmony_ci			break;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		default:
38562306a36Sopenharmony_ci			/* Section types we can't handle... */
38662306a36Sopenharmony_ci			fprintf(stderr,
38762306a36Sopenharmony_ci				"Program header %d type %d can't be converted.\n",
38862306a36Sopenharmony_ci				ex.e_phnum, ph[i].p_type);
38962306a36Sopenharmony_ci			exit(1);
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Sections must be in order to be converted... */
39462306a36Sopenharmony_ci	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
39562306a36Sopenharmony_ci	    text.vaddr + text.len > data.vaddr
39662306a36Sopenharmony_ci	    || data.vaddr + data.len > bss.vaddr) {
39762306a36Sopenharmony_ci		fprintf(stderr,
39862306a36Sopenharmony_ci			"Sections ordering prevents a.out conversion.\n");
39962306a36Sopenharmony_ci		exit(1);
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* If there's a data section but no text section, then the loader
40362306a36Sopenharmony_ci	   combined everything into one section.   That needs to be the
40462306a36Sopenharmony_ci	   text section, so just make the data section zero length following
40562306a36Sopenharmony_ci	   text. */
40662306a36Sopenharmony_ci	if (data.len && !text.len) {
40762306a36Sopenharmony_ci		text = data;
40862306a36Sopenharmony_ci		data.vaddr = text.vaddr + text.len;
40962306a36Sopenharmony_ci		data.len = 0;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* If there is a gap between text and data, we'll fill it when we copy
41362306a36Sopenharmony_ci	   the data, so update the length of the text segment as represented in
41462306a36Sopenharmony_ci	   a.out to reflect that, since a.out doesn't allow gaps in the program
41562306a36Sopenharmony_ci	   address space. */
41662306a36Sopenharmony_ci	if (text.vaddr + text.len < data.vaddr)
41762306a36Sopenharmony_ci		text.len = data.vaddr - text.vaddr;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* We now have enough information to cons up an a.out header... */
42062306a36Sopenharmony_ci	eah.magic = OMAGIC;
42162306a36Sopenharmony_ci	eah.vstamp = 200;
42262306a36Sopenharmony_ci	eah.tsize = text.len;
42362306a36Sopenharmony_ci	eah.dsize = data.len;
42462306a36Sopenharmony_ci	eah.bsize = bss.len;
42562306a36Sopenharmony_ci	eah.entry = ex.e_entry;
42662306a36Sopenharmony_ci	eah.text_start = text.vaddr;
42762306a36Sopenharmony_ci	eah.data_start = data.vaddr;
42862306a36Sopenharmony_ci	eah.bss_start = bss.vaddr;
42962306a36Sopenharmony_ci	eah.gprmask = 0xf3fffffe;
43062306a36Sopenharmony_ci	memset(&eah.cprmask, '\0', sizeof eah.cprmask);
43162306a36Sopenharmony_ci	eah.gp_value = 0;	/* unused. */
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (format_bigendian)
43462306a36Sopenharmony_ci		efh.f_magic = MIPSEBMAGIC;
43562306a36Sopenharmony_ci	else
43662306a36Sopenharmony_ci		efh.f_magic = MIPSELMAGIC;
43762306a36Sopenharmony_ci	if (addflag)
43862306a36Sopenharmony_ci		nosecs = 6;
43962306a36Sopenharmony_ci	else
44062306a36Sopenharmony_ci		nosecs = 3;
44162306a36Sopenharmony_ci	efh.f_nscns = nosecs;
44262306a36Sopenharmony_ci	efh.f_timdat = 0;	/* bogus */
44362306a36Sopenharmony_ci	efh.f_symptr = 0;
44462306a36Sopenharmony_ci	efh.f_nsyms = 0;
44562306a36Sopenharmony_ci	efh.f_opthdr = sizeof eah;
44662306a36Sopenharmony_ci	efh.f_flags = 0x100f;	/* Stripped, not sharable. */
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	memset(esecs, 0, sizeof esecs);
44962306a36Sopenharmony_ci	strcpy(esecs[0].s_name, ".text");
45062306a36Sopenharmony_ci	strcpy(esecs[1].s_name, ".data");
45162306a36Sopenharmony_ci	strcpy(esecs[2].s_name, ".bss");
45262306a36Sopenharmony_ci	if (addflag) {
45362306a36Sopenharmony_ci		strcpy(esecs[3].s_name, ".rdata");
45462306a36Sopenharmony_ci		strcpy(esecs[4].s_name, ".sdata");
45562306a36Sopenharmony_ci		strcpy(esecs[5].s_name, ".sbss");
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci	esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
45862306a36Sopenharmony_ci	esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
45962306a36Sopenharmony_ci	esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
46062306a36Sopenharmony_ci	if (addflag) {
46162306a36Sopenharmony_ci		esecs[3].s_paddr = esecs[3].s_vaddr = 0;
46262306a36Sopenharmony_ci		esecs[4].s_paddr = esecs[4].s_vaddr = 0;
46362306a36Sopenharmony_ci		esecs[5].s_paddr = esecs[5].s_vaddr = 0;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci	esecs[0].s_size = eah.tsize;
46662306a36Sopenharmony_ci	esecs[1].s_size = eah.dsize;
46762306a36Sopenharmony_ci	esecs[2].s_size = eah.bsize;
46862306a36Sopenharmony_ci	if (addflag) {
46962306a36Sopenharmony_ci		esecs[3].s_size = 0;
47062306a36Sopenharmony_ci		esecs[4].s_size = 0;
47162306a36Sopenharmony_ci		esecs[5].s_size = 0;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	esecs[0].s_scnptr = N_TXTOFF(efh, eah);
47462306a36Sopenharmony_ci	esecs[1].s_scnptr = N_DATOFF(efh, eah);
47562306a36Sopenharmony_ci#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
47662306a36Sopenharmony_ci#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
47762306a36Sopenharmony_ci	esecs[2].s_scnptr = esecs[1].s_scnptr +
47862306a36Sopenharmony_ci	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
47962306a36Sopenharmony_ci	if (addflag) {
48062306a36Sopenharmony_ci		esecs[3].s_scnptr = 0;
48162306a36Sopenharmony_ci		esecs[4].s_scnptr = 0;
48262306a36Sopenharmony_ci		esecs[5].s_scnptr = 0;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
48562306a36Sopenharmony_ci	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
48662306a36Sopenharmony_ci	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
48762306a36Sopenharmony_ci	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
48862306a36Sopenharmony_ci	if (addflag) {
48962306a36Sopenharmony_ci		esecs[3].s_relptr = esecs[4].s_relptr
49062306a36Sopenharmony_ci		    = esecs[5].s_relptr = 0;
49162306a36Sopenharmony_ci		esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
49262306a36Sopenharmony_ci		    = esecs[5].s_lnnoptr = 0;
49362306a36Sopenharmony_ci		esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
49462306a36Sopenharmony_ci		    0;
49562306a36Sopenharmony_ci		esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci	esecs[0].s_flags = 0x20;
49862306a36Sopenharmony_ci	esecs[1].s_flags = 0x40;
49962306a36Sopenharmony_ci	esecs[2].s_flags = 0x82;
50062306a36Sopenharmony_ci	if (addflag) {
50162306a36Sopenharmony_ci		esecs[3].s_flags = 0x100;
50262306a36Sopenharmony_ci		esecs[4].s_flags = 0x200;
50362306a36Sopenharmony_ci		esecs[5].s_flags = 0x400;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Make the output file... */
50762306a36Sopenharmony_ci	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
50862306a36Sopenharmony_ci		fprintf(stderr, "Unable to create %s: %s\n", argv[2],
50962306a36Sopenharmony_ci			strerror(errno));
51062306a36Sopenharmony_ci		exit(1);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (must_convert_endian)
51462306a36Sopenharmony_ci		convert_ecoff_filehdr(&efh);
51562306a36Sopenharmony_ci	/* Write the headers... */
51662306a36Sopenharmony_ci	i = write(outfile, &efh, sizeof efh);
51762306a36Sopenharmony_ci	if (i != sizeof efh) {
51862306a36Sopenharmony_ci		perror("efh: write");
51962306a36Sopenharmony_ci		exit(1);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		for (i = 0; i < nosecs; i++) {
52262306a36Sopenharmony_ci			printf
52362306a36Sopenharmony_ci			    ("Section %d: %s phys %"PRIx32"  size %"PRIx32"\t file offset %"PRIx32"\n",
52462306a36Sopenharmony_ci			     i, esecs[i].s_name, esecs[i].s_paddr,
52562306a36Sopenharmony_ci			     esecs[i].s_size, esecs[i].s_scnptr);
52662306a36Sopenharmony_ci		}
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci	fprintf(stderr, "wrote %d byte file header.\n", i);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (must_convert_endian)
53162306a36Sopenharmony_ci		convert_ecoff_aouthdr(&eah);
53262306a36Sopenharmony_ci	i = write(outfile, &eah, sizeof eah);
53362306a36Sopenharmony_ci	if (i != sizeof eah) {
53462306a36Sopenharmony_ci		perror("eah: write");
53562306a36Sopenharmony_ci		exit(1);
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci	fprintf(stderr, "wrote %d byte a.out header.\n", i);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (must_convert_endian)
54062306a36Sopenharmony_ci		convert_ecoff_esecs(&esecs[0], nosecs);
54162306a36Sopenharmony_ci	i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
54262306a36Sopenharmony_ci	if (i != nosecs * sizeof(struct scnhdr)) {
54362306a36Sopenharmony_ci		perror("esecs: write");
54462306a36Sopenharmony_ci		exit(1);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	fprintf(stderr, "wrote %d bytes of section headers.\n", i);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
54962306a36Sopenharmony_ci	if (pad) {
55062306a36Sopenharmony_ci		pad = 16 - pad;
55162306a36Sopenharmony_ci		i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
55262306a36Sopenharmony_ci		if (i < 0) {
55362306a36Sopenharmony_ci			perror("ipad: write");
55462306a36Sopenharmony_ci			exit(1);
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci		fprintf(stderr, "wrote %d byte pad.\n", i);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/*
56062306a36Sopenharmony_ci	 * Copy the loadable sections.	 Zero-fill any gaps less than 64k;
56162306a36Sopenharmony_ci	 * complain about any zero-filling, and die if we're asked to zero-fill
56262306a36Sopenharmony_ci	 * more than 64k.
56362306a36Sopenharmony_ci	 */
56462306a36Sopenharmony_ci	for (i = 0; i < ex.e_phnum; i++) {
56562306a36Sopenharmony_ci		/* Unprocessable sections were handled above, so just verify that
56662306a36Sopenharmony_ci		   the section can be loaded before copying. */
56762306a36Sopenharmony_ci		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
56862306a36Sopenharmony_ci			if (cur_vma != ph[i].p_vaddr) {
56962306a36Sopenharmony_ci				uint32_t gap = ph[i].p_vaddr - cur_vma;
57062306a36Sopenharmony_ci				char obuf[1024];
57162306a36Sopenharmony_ci				if (gap > 65536) {
57262306a36Sopenharmony_ci					fprintf(stderr,
57362306a36Sopenharmony_ci						"Intersegment gap (%"PRId32" bytes) too large.\n",
57462306a36Sopenharmony_ci						gap);
57562306a36Sopenharmony_ci					exit(1);
57662306a36Sopenharmony_ci				}
57762306a36Sopenharmony_ci				fprintf(stderr,
57862306a36Sopenharmony_ci					"Warning: %d byte intersegment gap.\n",
57962306a36Sopenharmony_ci					gap);
58062306a36Sopenharmony_ci				memset(obuf, 0, sizeof obuf);
58162306a36Sopenharmony_ci				while (gap) {
58262306a36Sopenharmony_ci					int count =
58362306a36Sopenharmony_ci					    write(outfile, obuf,
58462306a36Sopenharmony_ci						  (gap >
58562306a36Sopenharmony_ci						   sizeof obuf ? sizeof
58662306a36Sopenharmony_ci						   obuf : gap));
58762306a36Sopenharmony_ci					if (count < 0) {
58862306a36Sopenharmony_ci						fprintf(stderr,
58962306a36Sopenharmony_ci							"Error writing gap: %s\n",
59062306a36Sopenharmony_ci							strerror(errno));
59162306a36Sopenharmony_ci						exit(1);
59262306a36Sopenharmony_ci					}
59362306a36Sopenharmony_ci					gap -= count;
59462306a36Sopenharmony_ci				}
59562306a36Sopenharmony_ci			}
59662306a36Sopenharmony_ci			fprintf(stderr, "writing %d bytes...\n",
59762306a36Sopenharmony_ci				ph[i].p_filesz);
59862306a36Sopenharmony_ci			copy(outfile, infile, ph[i].p_offset,
59962306a36Sopenharmony_ci			     ph[i].p_filesz);
60062306a36Sopenharmony_ci			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	/*
60562306a36Sopenharmony_ci	 * Write a page of padding for boot PROMS that read entire pages.
60662306a36Sopenharmony_ci	 * Without this, they may attempt to read past the end of the
60762306a36Sopenharmony_ci	 * data section, incur an error, and refuse to boot.
60862306a36Sopenharmony_ci	 */
60962306a36Sopenharmony_ci	{
61062306a36Sopenharmony_ci		char obuf[4096];
61162306a36Sopenharmony_ci		memset(obuf, 0, sizeof obuf);
61262306a36Sopenharmony_ci		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
61362306a36Sopenharmony_ci			fprintf(stderr, "Error writing PROM padding: %s\n",
61462306a36Sopenharmony_ci				strerror(errno));
61562306a36Sopenharmony_ci			exit(1);
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* Looks like we won... */
62062306a36Sopenharmony_ci	exit(0);
62162306a36Sopenharmony_ci}
622