xref: /netbsd-src/usr.bin/elf2ecoff/elf2ecoff.c (revision a5175f1e986253dff5bbe596a6ad8c22a091e4b6)
1*a5175f1eSandvar /*	$NetBSD: elf2ecoff.c,v 1.35 2024/02/08 20:11:56 andvar Exp $	*/
2559daf50Sjonathan 
355e1f3d7Sjonathan /*
4623d454fSjonathan  * Copyright (c) 1997 Jonathan Stone
5623d454fSjonathan  *    All rights reserved.
655e1f3d7Sjonathan  * Copyright (c) 1995
755e1f3d7Sjonathan  *	Ted Lemon (hereinafter referred to as the author)
855e1f3d7Sjonathan  *
955e1f3d7Sjonathan  * Redistribution and use in source and binary forms, with or without
1055e1f3d7Sjonathan  * modification, are permitted provided that the following conditions
1155e1f3d7Sjonathan  * are met:
1255e1f3d7Sjonathan  * 1. Redistributions of source code must retain the above copyright
1355e1f3d7Sjonathan  *    notice, this list of conditions and the following disclaimer.
1455e1f3d7Sjonathan  * 2. Redistributions in binary form must reproduce the above copyright
1555e1f3d7Sjonathan  *    notice, this list of conditions and the following disclaimer in the
1655e1f3d7Sjonathan  *    documentation and/or other materials provided with the distribution.
1755e1f3d7Sjonathan  * 3. The name of the author may not be used to endorse or promote products
1855e1f3d7Sjonathan  *    derived from this software without specific prior written permission.
1955e1f3d7Sjonathan  *
2055e1f3d7Sjonathan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
2155e1f3d7Sjonathan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2255e1f3d7Sjonathan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2355e1f3d7Sjonathan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
2455e1f3d7Sjonathan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2555e1f3d7Sjonathan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2655e1f3d7Sjonathan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2755e1f3d7Sjonathan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2855e1f3d7Sjonathan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2955e1f3d7Sjonathan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3055e1f3d7Sjonathan  * SUCH DAMAGE.
3155e1f3d7Sjonathan  */
3255e1f3d7Sjonathan 
3355e1f3d7Sjonathan /* elf2ecoff.c
3455e1f3d7Sjonathan 
3555e1f3d7Sjonathan    This program converts an elf executable to an ECOFF executable.
3655e1f3d7Sjonathan    No symbol table is retained.   This is useful primarily in building
3755e1f3d7Sjonathan    net-bootable kernels for machines (e.g., DECstation and Alpha) which
3855e1f3d7Sjonathan    only support the ECOFF object file format. */
3955e1f3d7Sjonathan 
40171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
41171d6532Slukem #include "nbtool_config.h"
4265910421Stv #endif
4365910421Stv 
4455e1f3d7Sjonathan #include <sys/types.h>
45552d6a2aSsimonb #include <err.h>
463ed4fcf6Skleink #include <errno.h>
4755e1f3d7Sjonathan #include <fcntl.h>
4855e1f3d7Sjonathan #include <unistd.h>
4958e8bd3bSjonathan #include <sys/exec_elf.h>
5055e1f3d7Sjonathan #include <stdio.h>
5155e1f3d7Sjonathan #include <sys/exec_ecoff.h>
5225afea2dSjonathan #include <stdlib.h>
5355e1f3d7Sjonathan #include <string.h>
5455e1f3d7Sjonathan #include <limits.h>
5555e1f3d7Sjonathan 
5625afea2dSjonathan #define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
5725afea2dSjonathan 
5855e1f3d7Sjonathan struct sect {
59c9ed2107Schristos 	uint32_t vaddr;
60c9ed2107Schristos 	uint32_t len;
6155e1f3d7Sjonathan };
6255e1f3d7Sjonathan 
63623d454fSjonathan struct elf_syms {
64623d454fSjonathan 	int     nsymbols;
65623d454fSjonathan 	Elf32_Sym *elf_syms;
66623d454fSjonathan 	off_t   stringsize;
67623d454fSjonathan 	char   *stringtab;
68623d454fSjonathan };
69623d454fSjonathan 
70623d454fSjonathan struct ecoff_syms {
71623d454fSjonathan 	int     nsymbols;
72623d454fSjonathan 	struct ecoff_extsym *ecoff_syms;
73623d454fSjonathan 	off_t   stringsize;
74623d454fSjonathan 	char   *stringtab;
75623d454fSjonathan };
76623d454fSjonathan 
7776987894Schristos static int     debug = 0;
7876987894Schristos static int     needswap;
7925afea2dSjonathan 
8076987894Schristos static int     phcmp(Elf32_Phdr *, Elf32_Phdr *);
8176987894Schristos static char   *saveRead(int, off_t, off_t, const char *);
8276987894Schristos static void    safewrite(int, const void *, off_t, const char *);
8376987894Schristos static void    copy(int, int, off_t, off_t);
8476987894Schristos static void    combine(struct sect *, struct sect *, int);
8576987894Schristos static void    translate_syms(struct elf_syms *, struct ecoff_syms *);
86c9ed2107Schristos static void    elf_symbol_table_to_ecoff(int, int, struct ecoff32_exechdr *,
8776987894Schristos     off_t, off_t, off_t, off_t);
88c9ed2107Schristos static int     make_ecoff_section_hdrs(struct ecoff32_exechdr *,
89c9ed2107Schristos     struct ecoff32_scnhdr *);
90c9ed2107Schristos static void    write_ecoff_symhdr(int, struct ecoff32_exechdr *,
91c9ed2107Schristos     struct ecoff32_symhdr *, int32_t, int32_t, int32_t, int32_t);
9276987894Schristos static void    pad16(int, int, const char *);
9376987894Schristos static void    bswap32_region(int32_t* , int);
9476987894Schristos static void    elf_read_syms(struct elf_syms *, int, off_t, off_t, off_t,
9576987894Schristos     off_t);
96623d454fSjonathan 
97623d454fSjonathan 
9825afea2dSjonathan int
main(int argc,char ** argv)9976987894Schristos main(int argc, char **argv)
10055e1f3d7Sjonathan {
10158e8bd3bSjonathan 	Elf32_Ehdr ex;
10258e8bd3bSjonathan 	Elf32_Phdr *ph;
10358e8bd3bSjonathan 	Elf32_Shdr *sh;
10455e1f3d7Sjonathan 	char   *shstrtab;
10555e1f3d7Sjonathan 	int     strtabix, symtabix;
106c37f283fStsutsui 	size_t	i;
107c37f283fStsutsui 	int     pad;
10825afea2dSjonathan 	struct sect text, data, bss;	/* a.out-compatible sections */
10925afea2dSjonathan 
110c9ed2107Schristos 	struct ecoff32_exechdr ep;
111c9ed2107Schristos 	struct ecoff32_scnhdr esecs[6];
112c9ed2107Schristos 	struct ecoff32_symhdr symhdr;
11325afea2dSjonathan 
11455e1f3d7Sjonathan 	int     infile, outfile;
115c9ed2107Schristos 	uint32_t cur_vma = UINT32_MAX;
11625afea2dSjonathan 	int     nsecs = 0;
11733176a12Sbouyer 	int	mipsel;
11833176a12Sbouyer 
11955e1f3d7Sjonathan 
12055e1f3d7Sjonathan 	text.len = data.len = bss.len = 0;
12155e1f3d7Sjonathan 	text.vaddr = data.vaddr = bss.vaddr = 0;
12255e1f3d7Sjonathan 
12355e1f3d7Sjonathan 	/* Check args... */
124043bfc92Slukem 	if (argc < 3 || argc > 4) {
12555e1f3d7Sjonathan usage:
12655e1f3d7Sjonathan 		fprintf(stderr,
12776987894Schristos 		    "Usage: %s <elf executable> <ECOFF executable> [-s]\n",
12876987894Schristos 		    getprogname());
12955e1f3d7Sjonathan 		exit(1);
13055e1f3d7Sjonathan 	}
131043bfc92Slukem 	if (argc == 4) {
13255e1f3d7Sjonathan 		if (strcmp(argv[3], "-s"))
13355e1f3d7Sjonathan 			goto usage;
13455e1f3d7Sjonathan 	}
13555e1f3d7Sjonathan 	/* Try the input file... */
13676987894Schristos 	if ((infile = open(argv[1], O_RDONLY)) < 0)
13776987894Schristos 		err(1, "Can't open %s for read", argv[1]);
13855e1f3d7Sjonathan 	/* Read the header, which is at the beginning of the file... */
13955e1f3d7Sjonathan 	i = read(infile, &ex, sizeof ex);
14076987894Schristos 	if (i != sizeof ex)
14176987894Schristos 		err(1, "Short header read from %s", argv[1]);
14233176a12Sbouyer 	if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
14333176a12Sbouyer 		mipsel = 1;
14433176a12Sbouyer 	else if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
14533176a12Sbouyer 		mipsel = 0;
14676987894Schristos 	else
14776987894Schristos 		errx(1, "invalid ELF byte order %d", ex.e_ident[EI_DATA]);
14833176a12Sbouyer #if BYTE_ORDER == BIG_ENDIAN
14933176a12Sbouyer 	if (mipsel)
15033176a12Sbouyer 		needswap = 1;
15133176a12Sbouyer 	else
15233176a12Sbouyer 		needswap = 0;
15333176a12Sbouyer #elif BYTE_ORDER == LITTLE_ENDIAN
15433176a12Sbouyer 	if (mipsel)
15533176a12Sbouyer 		needswap = 0;
15633176a12Sbouyer 	else
15733176a12Sbouyer 		needswap = 1;
15833176a12Sbouyer #else
15933176a12Sbouyer #error "unknown endian"
16033176a12Sbouyer #endif
16133176a12Sbouyer 
16233176a12Sbouyer 	if (needswap) {
16333176a12Sbouyer 		ex.e_type	= bswap16(ex.e_type);
16433176a12Sbouyer 		ex.e_machine	= bswap16(ex.e_machine);
16533176a12Sbouyer 		ex.e_version	= bswap32(ex.e_version);
16633176a12Sbouyer 		ex.e_entry 	= bswap32(ex.e_entry);
16733176a12Sbouyer 		ex.e_phoff	= bswap32(ex.e_phoff);
16833176a12Sbouyer 		ex.e_shoff	= bswap32(ex.e_shoff);
16933176a12Sbouyer 		ex.e_flags	= bswap32(ex.e_flags);
17033176a12Sbouyer 		ex.e_ehsize	= bswap16(ex.e_ehsize);
17133176a12Sbouyer 		ex.e_phentsize	= bswap16(ex.e_phentsize);
17233176a12Sbouyer 		ex.e_phnum	= bswap16(ex.e_phnum);
17333176a12Sbouyer 		ex.e_shentsize	= bswap16(ex.e_shentsize);
17433176a12Sbouyer 		ex.e_shnum	= bswap16(ex.e_shnum);
17533176a12Sbouyer 		ex.e_shstrndx	= bswap16(ex.e_shstrndx);
17633176a12Sbouyer 	}
17733176a12Sbouyer 
17855e1f3d7Sjonathan 	/* Read the program headers... */
17958e8bd3bSjonathan 	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
18058e8bd3bSjonathan 	    ex.e_phnum * sizeof(Elf32_Phdr), "ph");
18133176a12Sbouyer 	if (needswap)
182f11583faSsimonb 		bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
18355e1f3d7Sjonathan 	/* Read the section headers... */
18458e8bd3bSjonathan 	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
18558e8bd3bSjonathan 	    ex.e_shnum * sizeof(Elf32_Shdr), "sh");
18633176a12Sbouyer 	if (needswap)
187f11583faSsimonb 		bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
18833176a12Sbouyer 
18925afea2dSjonathan 	/* Read in the section string table. */
19025afea2dSjonathan 	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
19125afea2dSjonathan 	    sh[ex.e_shstrndx].sh_size, "shstrtab");
19225afea2dSjonathan 
19325afea2dSjonathan 
194043bfc92Slukem 	/* Look for the symbol table and string table... Also map section
195043bfc92Slukem 	 * indices to symbol types for a.out */
19625afea2dSjonathan 	symtabix = 0;
19725afea2dSjonathan 	strtabix = 0;
198043bfc92Slukem 	for (i = 0; i < ex.e_shnum; i++) {
19925afea2dSjonathan 		char   *name = shstrtab + sh[i].sh_name;
20025afea2dSjonathan 		if (!strcmp(name, ".symtab"))
20125afea2dSjonathan 			symtabix = i;
202043bfc92Slukem 		else
203043bfc92Slukem 			if (!strcmp(name, ".strtab"))
20425afea2dSjonathan 				strtabix = i;
20525afea2dSjonathan 
20625afea2dSjonathan 	}
20755e1f3d7Sjonathan 
20876987894Schristos 	/*
20976987894Schristos 	 * Figure out if we can cram the program header into an ECOFF
210043bfc92Slukem 	 * header...  Basically, we can't handle anything but loadable
211043bfc92Slukem 	 * segments, but we can ignore some kinds of segments.  We can't
212043bfc92Slukem 	 * handle holes in the address space.  Segments may be out of order,
21376987894Schristos 	 * so we sort them first.
21476987894Schristos 	 */
21555e1f3d7Sjonathan 
21625afea2dSjonathan 	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr),
21725afea2dSjonathan 	    (int (*) (const void *, const void *)) phcmp);
21855e1f3d7Sjonathan 
219043bfc92Slukem 	for (i = 0; i < ex.e_phnum; i++) {
2201d13ed3dSchristos 		switch (ph[i].p_type) {
2211d13ed3dSchristos 		case PT_NOTE:
2221d13ed3dSchristos 		case PT_NULL:
2231d13ed3dSchristos 		case PT_PHDR:
2241d13ed3dSchristos 		case PT_MIPS_ABIFLAGS:
2251d13ed3dSchristos 		case PT_MIPS_REGINFO:
22655e1f3d7Sjonathan 			/* Section types we can ignore... */
22725afea2dSjonathan 			if (debug) {
2281d13ed3dSchristos 				fprintf(stderr, "  skipping PH %zu type %#x "
2291d13ed3dSchristos 				    "flags %#x\n",
23025afea2dSjonathan 				    i, ph[i].p_type, ph[i].p_flags);
23125afea2dSjonathan 			}
23255e1f3d7Sjonathan 			continue;
2331d13ed3dSchristos 		default:
23455e1f3d7Sjonathan 			/* Section types we can't handle... */
23576987894Schristos 			if (ph[i].p_type != PT_LOAD)
2361d13ed3dSchristos 				errx(1, "Program header %zu type %#x can't be "
23776987894Schristos 				    "converted", i, ph[i].p_type);
2381d13ed3dSchristos 		}
23955e1f3d7Sjonathan 		/* Writable (data) segment? */
240043bfc92Slukem 		if (ph[i].p_flags & PF_W) {
24155e1f3d7Sjonathan 			struct sect ndata, nbss;
24255e1f3d7Sjonathan 
24358e8bd3bSjonathan 			ndata.vaddr = ph[i].p_vaddr;
24458e8bd3bSjonathan 			ndata.len = ph[i].p_filesz;
24558e8bd3bSjonathan 			nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
24658e8bd3bSjonathan 			nbss.len = ph[i].p_memsz - ph[i].p_filesz;
24755e1f3d7Sjonathan 
24825afea2dSjonathan 			if (debug) {
249c9b3c34dSandvar 				fprintf(stderr, "  combining PH %zu type %d "
250425b4f39Schristos 				    "flags %#x with data, ndata = %d, "
251c9ed2107Schristos 				    "nbss =%d\n", i, ph[i].p_type,
25276987894Schristos 				    ph[i].p_flags, ndata.len, nbss.len);
25325afea2dSjonathan 			}
25455e1f3d7Sjonathan 			combine(&data, &ndata, 0);
25555e1f3d7Sjonathan 			combine(&bss, &nbss, 1);
256043bfc92Slukem 		} else {
25755e1f3d7Sjonathan 			struct sect ntxt;
25855e1f3d7Sjonathan 
25958e8bd3bSjonathan 			ntxt.vaddr = ph[i].p_vaddr;
26058e8bd3bSjonathan 			ntxt.len = ph[i].p_filesz;
26125afea2dSjonathan 			if (debug) {
262c9b3c34dSandvar 				fprintf(stderr, "  combining PH %zu type %d "
263425b4f39Schristos 				    "flags %#x with text, len = %d\n",
26425afea2dSjonathan 				    i, ph[i].p_type, ph[i].p_flags, ntxt.len);
26525afea2dSjonathan 			}
26625afea2dSjonathan 			combine(&text, &ntxt, 0);
26755e1f3d7Sjonathan 		}
26855e1f3d7Sjonathan 		/* Remember the lowest segment start address. */
26958e8bd3bSjonathan 		if (ph[i].p_vaddr < cur_vma)
27058e8bd3bSjonathan 			cur_vma = ph[i].p_vaddr;
27155e1f3d7Sjonathan 	}
27255e1f3d7Sjonathan 
27355e1f3d7Sjonathan 	/* Sections must be in order to be converted... */
27455e1f3d7Sjonathan 	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
27576987894Schristos 	    text.vaddr + text.len > data.vaddr ||
27676987894Schristos 	    data.vaddr + data.len > bss.vaddr)
27776987894Schristos 		errx(1, "Sections ordering prevents a.out conversion");
27855e1f3d7Sjonathan 	/* If there's a data section but no text section, then the loader
279043bfc92Slukem 	 * combined everything into one section.   That needs to be the text
280043bfc92Slukem 	 * section, so just make the data section zero length following text. */
28163fc11e9Stsutsui 	if (data.len && text.len == 0) {
28255e1f3d7Sjonathan 		text = data;
28355e1f3d7Sjonathan 		data.vaddr = text.vaddr + text.len;
28455e1f3d7Sjonathan 		data.len = 0;
28555e1f3d7Sjonathan 	}
28655e1f3d7Sjonathan 	/* If there is a gap between text and data, we'll fill it when we copy
287043bfc92Slukem 	 * the data, so update the length of the text segment as represented
288043bfc92Slukem 	 * in a.out to reflect that, since a.out doesn't allow gaps in the
289043bfc92Slukem 	 * program address space. */
29055e1f3d7Sjonathan 	if (text.vaddr + text.len < data.vaddr)
29155e1f3d7Sjonathan 		text.len = data.vaddr - text.vaddr;
29255e1f3d7Sjonathan 
29355e1f3d7Sjonathan 	/* We now have enough information to cons up an a.out header... */
294559daf50Sjonathan 	ep.a.magic = ECOFF_OMAGIC;
29525afea2dSjonathan 	ep.a.vstamp = 2 * 256 + 10;	/* compatible with version 2.10 */
296559daf50Sjonathan 	ep.a.tsize = text.len;
297559daf50Sjonathan 	ep.a.dsize = data.len;
298559daf50Sjonathan 	ep.a.bsize = bss.len;
29958e8bd3bSjonathan 	ep.a.entry = ex.e_entry;
300559daf50Sjonathan 	ep.a.text_start = text.vaddr;
301559daf50Sjonathan 	ep.a.data_start = data.vaddr;
302559daf50Sjonathan 	ep.a.bss_start = bss.vaddr;
303559daf50Sjonathan 	ep.a.gprmask = 0xf3fffffe;
304bfd52621Sperry 	memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask);
305559daf50Sjonathan 	ep.a.gp_value = 0;	/* unused. */
30655e1f3d7Sjonathan 
30733176a12Sbouyer 	if (mipsel)
308559daf50Sjonathan 		ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
30933176a12Sbouyer 	else
3109f3b0a4dSbouyer 		ep.f.f_magic = ECOFF_MAGIC_MIPSEB;
3119f3b0a4dSbouyer 
31225afea2dSjonathan 	ep.f.f_nscns = 6;
313559daf50Sjonathan 	ep.f.f_timdat = 0;	/* bogus */
314559daf50Sjonathan 	ep.f.f_symptr = 0;
315c9ed2107Schristos 	ep.f.f_nsyms = sizeof(struct ecoff32_symhdr);
316559daf50Sjonathan 	ep.f.f_opthdr = sizeof ep.a;
317*a5175f1eSandvar 	ep.f.f_flags = 0x100f;	/* Stripped, not shareable. */
31855e1f3d7Sjonathan 
319bfd52621Sperry 	memset(esecs, 0, sizeof(esecs));
320559daf50Sjonathan 
321043bfc92Slukem 	/* Make  ECOFF section headers, with empty stubs for
322043bfc92Slukem 	 * .rdata/.sdata/.sbss. */
32325afea2dSjonathan 	make_ecoff_section_hdrs(&ep, esecs);
32425afea2dSjonathan 
32525afea2dSjonathan 	nsecs = ep.f.f_nscns;
32655e1f3d7Sjonathan 
32733176a12Sbouyer 	if (needswap) {
32833176a12Sbouyer 		ep.f.f_magic	= bswap16(ep.f.f_magic);
32933176a12Sbouyer 		ep.f.f_nscns	= bswap16(ep.f.f_nscns);
33033176a12Sbouyer 		ep.f.f_timdat	= bswap32(ep.f.f_timdat);
33133176a12Sbouyer 		ep.f.f_symptr	= bswap32(ep.f.f_symptr);
33233176a12Sbouyer 		ep.f.f_nsyms	= bswap32(ep.f.f_nsyms);
33333176a12Sbouyer 		ep.f.f_opthdr	= bswap16(ep.f.f_opthdr);
33433176a12Sbouyer 		ep.f.f_flags	= bswap16(ep.f.f_flags);
33533176a12Sbouyer 		ep.a.magic	= bswap16(ep.a.magic);
33633176a12Sbouyer 		ep.a.vstamp	= bswap16(ep.a.vstamp);
33733176a12Sbouyer 		ep.a.tsize	= bswap32(ep.a.tsize);
33833176a12Sbouyer 		ep.a.dsize	= bswap32(ep.a.dsize);
33933176a12Sbouyer 		ep.a.bsize	= bswap32(ep.a.bsize);
34033176a12Sbouyer 		ep.a.entry	= bswap32(ep.a.entry);
34133176a12Sbouyer 		ep.a.text_start	= bswap32(ep.a.text_start);
34233176a12Sbouyer 		ep.a.data_start	= bswap32(ep.a.data_start);
34333176a12Sbouyer 		ep.a.bss_start	= bswap32(ep.a.bss_start);
34433176a12Sbouyer 		ep.a.gprmask	= bswap32(ep.a.gprmask);
345f11583faSsimonb 		bswap32_region((int32_t*)ep.a.cprmask, sizeof(ep.a.cprmask));
34633176a12Sbouyer 		ep.a.gp_value	= bswap32(ep.a.gp_value);
34733176a12Sbouyer 		for (i = 0; i < sizeof(esecs) / sizeof(esecs[0]); i++) {
34833176a12Sbouyer 			esecs[i].s_paddr	= bswap32(esecs[i].s_paddr);
34933176a12Sbouyer 			esecs[i].s_vaddr	= bswap32(esecs[i].s_vaddr);
35033176a12Sbouyer 			esecs[i].s_size 	= bswap32(esecs[i].s_size);
35133176a12Sbouyer 			esecs[i].s_scnptr	= bswap32(esecs[i].s_scnptr);
35233176a12Sbouyer 			esecs[i].s_relptr	= bswap32(esecs[i].s_relptr);
35333176a12Sbouyer 			esecs[i].s_lnnoptr	= bswap32(esecs[i].s_lnnoptr);
35433176a12Sbouyer 			esecs[i].s_nreloc	= bswap16(esecs[i].s_nreloc);
35533176a12Sbouyer 			esecs[i].s_nlnno	= bswap16(esecs[i].s_nlnno);
35633176a12Sbouyer 			esecs[i].s_flags	= bswap32(esecs[i].s_flags);
35733176a12Sbouyer 		}
35833176a12Sbouyer 	}
35933176a12Sbouyer 
36055e1f3d7Sjonathan 	/* Make the output file... */
36176987894Schristos 	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0)
36276987894Schristos 		err(1, "Unable to create %s", argv[2]);
36376987894Schristos 
364552d6a2aSsimonb 	/* Truncate file... */
365552d6a2aSsimonb 	if (ftruncate(outfile, 0)) {
366552d6a2aSsimonb 		warn("ftruncate %s", argv[2]);
367552d6a2aSsimonb 	}
36855e1f3d7Sjonathan 	/* Write the headers... */
36976987894Schristos 	safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write");
370552d6a2aSsimonb 	if (debug)
37182d396eaSmatt 		fprintf(stderr, "wrote %zu byte file header.\n", sizeof(ep.f));
37255e1f3d7Sjonathan 
37376987894Schristos 	safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write");
374552d6a2aSsimonb 	if (debug)
37582d396eaSmatt 		fprintf(stderr, "wrote %zu byte a.out header.\n", sizeof(ep.a));
37655e1f3d7Sjonathan 
37776987894Schristos 	safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs, "esecs: write");
378552d6a2aSsimonb 	if (debug)
37982d396eaSmatt 		fprintf(stderr, "wrote %zu bytes of section headers.\n",
380623d454fSjonathan 		    sizeof(esecs[0]) * nsecs);
38155e1f3d7Sjonathan 
38225afea2dSjonathan 
38325afea2dSjonathan 	pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
384623d454fSjonathan 	if (pad) {
38555e1f3d7Sjonathan 		pad = 16 - pad;
38676987894Schristos 		pad16(outfile, pad, "ipad: write");
387552d6a2aSsimonb 		if (debug)
388623d454fSjonathan 			fprintf(stderr, "wrote %d byte pad.\n", pad);
38955e1f3d7Sjonathan 	}
39055e1f3d7Sjonathan 	/* Copy the loadable sections.   Zero-fill any gaps less than 64k;
391043bfc92Slukem 	 * complain about any zero-filling, and die if we're asked to
392043bfc92Slukem 	 * zero-fill more than 64k. */
393043bfc92Slukem 	for (i = 0; i < ex.e_phnum; i++) {
394043bfc92Slukem 		/* Unprocessable sections were handled above, so just verify
395043bfc92Slukem 		 * that the section can be loaded before copying. */
3961899563cSdrochner 		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
397043bfc92Slukem 			if (cur_vma != ph[i].p_vaddr) {
398c9ed2107Schristos 				uint32_t gap = ph[i].p_vaddr - cur_vma;
39955e1f3d7Sjonathan 				char    obuf[1024];
40076987894Schristos 				if (gap > 65536)
401c9ed2107Schristos 					errx(1, "Intersegment gap (%d bytes) "
40276987894Schristos 					    "too large", gap);
403552d6a2aSsimonb 				if (debug)
404c9ed2107Schristos 					fprintf(stderr, "Warning: %d byte "
40576987894Schristos 					    "intersegment gap.\n", gap);
40655e1f3d7Sjonathan 				memset(obuf, 0, sizeof obuf);
407043bfc92Slukem 				while (gap) {
40876987894Schristos 					int count = write(outfile, obuf,
40976987894Schristos 					    (gap > sizeof obuf
41055e1f3d7Sjonathan 					    ? sizeof obuf : gap));
41176987894Schristos 					if (count < 0)
41276987894Schristos 						err(1, "Error writing gap");
41355e1f3d7Sjonathan 					gap -= count;
41455e1f3d7Sjonathan 				}
41555e1f3d7Sjonathan 			}
416552d6a2aSsimonb 			if (debug)
41776987894Schristos 				fprintf(stderr, "writing %d bytes...\n",
41876987894Schristos 				    ph[i].p_filesz);
41958e8bd3bSjonathan 			copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
42058e8bd3bSjonathan 			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
42155e1f3d7Sjonathan 		}
42255e1f3d7Sjonathan 	}
42355e1f3d7Sjonathan 
42425afea2dSjonathan 
425623d454fSjonathan 	if (debug)
426425b4f39Schristos 		fprintf(stderr, "writing syms at offset %#x\n",
427425b4f39Schristos 		    (uint32_t)(ep.f.f_symptr + sizeof(symhdr)));
428623d454fSjonathan 
429623d454fSjonathan 	/* Copy and translate the symbol table... */
430623d454fSjonathan 	elf_symbol_table_to_ecoff(outfile, infile, &ep,
431623d454fSjonathan 	    sh[symtabix].sh_offset, sh[symtabix].sh_size,
432623d454fSjonathan 	    sh[strtabix].sh_offset, sh[strtabix].sh_size);
433623d454fSjonathan 
43425afea2dSjonathan 	/*
43525afea2dSjonathan          * Write a page of padding for boot PROMS that read entire pages.
43625afea2dSjonathan          * Without this, they may attempt to read past the end of the
43725afea2dSjonathan          * data section, incur an error, and refuse to boot.
43825afea2dSjonathan          */
43925afea2dSjonathan 	{
44025afea2dSjonathan 		char    obuf[4096];
44125afea2dSjonathan 		memset(obuf, 0, sizeof obuf);
44276987894Schristos 		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf))
44376987894Schristos 			err(1, "Error writing PROM padding");
44425afea2dSjonathan 	}
44525afea2dSjonathan 
44655e1f3d7Sjonathan 	/* Looks like we won... */
44776987894Schristos 	return 0;
44855e1f3d7Sjonathan }
44955e1f3d7Sjonathan 
45076987894Schristos static void
copy(int out,int in,off_t offset,off_t size)45163fc11e9Stsutsui copy(int out, int in, off_t offset, off_t size)
45255e1f3d7Sjonathan {
45355e1f3d7Sjonathan 	char    ibuf[4096];
454c37f283fStsutsui 	size_t  remaining, cur, count;
45555e1f3d7Sjonathan 
45689c5a767Ssoren 	/* Go to the start of the ELF symbol table... */
45776987894Schristos 	if (lseek(in, offset, SEEK_SET) < 0)
45876987894Schristos 		err(1, "copy: lseek");
45955e1f3d7Sjonathan 	remaining = size;
460043bfc92Slukem 	while (remaining) {
46155e1f3d7Sjonathan 		cur = remaining;
46255e1f3d7Sjonathan 		if (cur > sizeof ibuf)
46355e1f3d7Sjonathan 			cur = sizeof ibuf;
46455e1f3d7Sjonathan 		remaining -= cur;
46576987894Schristos 		if ((count = read(in, ibuf, cur)) != cur)
46676987894Schristos 			err(1, "copy: short read");
46776987894Schristos 		safewrite(out, ibuf, cur, "copy: write");
46855e1f3d7Sjonathan 	}
46955e1f3d7Sjonathan }
47076987894Schristos 
47155e1f3d7Sjonathan /* Combine two segments, which must be contiguous.   If pad is true, it's
47255e1f3d7Sjonathan    okay for there to be padding between. */
47376987894Schristos static void
combine(struct sect * base,struct sect * new,int pad)47463fc11e9Stsutsui combine(struct sect *base, struct sect *new, int pad)
47555e1f3d7Sjonathan {
47663fc11e9Stsutsui 
47763fc11e9Stsutsui 	if (base->len == 0)
47855e1f3d7Sjonathan 		*base = *new;
479043bfc92Slukem 	else
480043bfc92Slukem 		if (new->len) {
481043bfc92Slukem 			if (base->vaddr + base->len != new->vaddr) {
48255e1f3d7Sjonathan 				if (pad)
48355e1f3d7Sjonathan 					base->len = new->vaddr - base->vaddr;
48476987894Schristos 				else
48576987894Schristos 					errx(1, "Non-contiguous data can't be "
48676987894Schristos 					    "converted");
48755e1f3d7Sjonathan 			}
48855e1f3d7Sjonathan 			base->len += new->len;
48955e1f3d7Sjonathan 		}
49055e1f3d7Sjonathan }
49155e1f3d7Sjonathan 
49276987894Schristos static int
phcmp(Elf32_Phdr * h1,Elf32_Phdr * h2)49363fc11e9Stsutsui phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2)
49455e1f3d7Sjonathan {
49563fc11e9Stsutsui 
49658e8bd3bSjonathan 	if (h1->p_vaddr > h2->p_vaddr)
49755e1f3d7Sjonathan 		return 1;
498043bfc92Slukem 	else
499043bfc92Slukem 		if (h1->p_vaddr < h2->p_vaddr)
50055e1f3d7Sjonathan 			return -1;
50155e1f3d7Sjonathan 		else
50255e1f3d7Sjonathan 			return 0;
50355e1f3d7Sjonathan }
50455e1f3d7Sjonathan 
50576987894Schristos static char *
saveRead(int file,off_t offset,off_t len,const char * name)506c37f283fStsutsui saveRead(int file, off_t offset, off_t len, const char *name)
50755e1f3d7Sjonathan {
50855e1f3d7Sjonathan 	char   *tmp;
50955e1f3d7Sjonathan 	int     count;
51055e1f3d7Sjonathan 	off_t   off;
51163fc11e9Stsutsui 
51276987894Schristos 	if ((off = lseek(file, offset, SEEK_SET)) < 0)
51376987894Schristos 		err(1, "%s: fseek", name);
51476987894Schristos 	if ((tmp = malloc(len)) == NULL)
515bb0b3debSchristos 		err(1, "%s: Can't allocate %jd bytes", name, (intmax_t)len);
51655e1f3d7Sjonathan 	count = read(file, tmp, len);
51776987894Schristos 	if (count != len)
51876987894Schristos 		err(1, "%s: short read", name);
51955e1f3d7Sjonathan 	return tmp;
52055e1f3d7Sjonathan }
52125afea2dSjonathan 
52276987894Schristos static void
safewrite(int outfile,const void * buf,off_t len,const char * msg)523c37f283fStsutsui safewrite(int outfile, const void *buf, off_t len, const char *msg)
524623d454fSjonathan {
52576987894Schristos 	ssize_t     written;
52663fc11e9Stsutsui 
527c37f283fStsutsui 	written = write(outfile, buf, len);
52876987894Schristos 	if (written != len)
52976987894Schristos 		err(1, "%s", msg);
530623d454fSjonathan }
531623d454fSjonathan 
53225afea2dSjonathan 
53325afea2dSjonathan /*
534623d454fSjonathan  * Output only three ECOFF sections, corresponding to ELF psecs
535623d454fSjonathan  * for text, data, and bss.
53625afea2dSjonathan  */
53776987894Schristos static int
make_ecoff_section_hdrs(struct ecoff32_exechdr * ep,struct ecoff32_scnhdr * esecs)538c9ed2107Schristos make_ecoff_section_hdrs(struct ecoff32_exechdr *ep, struct ecoff32_scnhdr *esecs)
53925afea2dSjonathan {
54063fc11e9Stsutsui 
54125afea2dSjonathan 	ep->f.f_nscns = 6;	/* XXX */
54225afea2dSjonathan 
54325afea2dSjonathan 	strcpy(esecs[0].s_name, ".text");
54425afea2dSjonathan 	strcpy(esecs[1].s_name, ".data");
54525afea2dSjonathan 	strcpy(esecs[2].s_name, ".bss");
54625afea2dSjonathan 
54725afea2dSjonathan 	esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
54825afea2dSjonathan 	esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
54925afea2dSjonathan 	esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
55025afea2dSjonathan 	esecs[0].s_size = ep->a.tsize;
55125afea2dSjonathan 	esecs[1].s_size = ep->a.dsize;
55225afea2dSjonathan 	esecs[2].s_size = ep->a.bsize;
55325afea2dSjonathan 
554c9ed2107Schristos 	esecs[0].s_scnptr = ECOFF32_TXTOFF(ep);
555c9ed2107Schristos 	esecs[1].s_scnptr = ECOFF32_DATOFF(ep);
55625afea2dSjonathan #if 0
55725afea2dSjonathan 	esecs[2].s_scnptr = esecs[1].s_scnptr +
558c9ed2107Schristos 	    ECOFF_ROUND(esecs[1].s_size, ECOFF32_SEGMENT_ALIGNMENT(ep));
55925afea2dSjonathan #endif
56025afea2dSjonathan 
561623d454fSjonathan 	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
562623d454fSjonathan 	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
56325afea2dSjonathan 	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
56425afea2dSjonathan 	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
56525afea2dSjonathan 
56625afea2dSjonathan 	esecs[1].s_flags = 0x100;	/* ECOFF rdata */
56725afea2dSjonathan 	esecs[3].s_flags = 0x200;	/* ECOFF sdata */
56825afea2dSjonathan 	esecs[4].s_flags = 0x400;	/* ECOFF sbss */
56925afea2dSjonathan 
57025afea2dSjonathan 	/*
571623d454fSjonathan 	 * Set the symbol-table offset  to point at the end of any
572623d454fSjonathan 	 * sections we loaded above, so later code can use it to write
573623d454fSjonathan 	 * symbol table info..
57425afea2dSjonathan 	 */
57525afea2dSjonathan 	ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
57625afea2dSjonathan 	return (ep->f.f_nscns);
57725afea2dSjonathan }
578623d454fSjonathan 
579623d454fSjonathan 
580623d454fSjonathan /*
581623d454fSjonathan  * Write the ECOFF symbol header.
582623d454fSjonathan  * Guess at how big the symbol table will be.
583623d454fSjonathan  * Mark all symbols as EXTERN (for now).
584623d454fSjonathan  */
58576987894Schristos static void
write_ecoff_symhdr(int out,struct ecoff32_exechdr * ep,struct ecoff32_symhdr * symhdrp,int32_t nesyms,int32_t extsymoff,int32_t extstroff,int32_t strsize)586c9ed2107Schristos write_ecoff_symhdr(int out, struct ecoff32_exechdr *ep,
587c9ed2107Schristos     struct ecoff32_symhdr *symhdrp, int32_t nesyms,
588c9ed2107Schristos     int32_t extsymoff, int32_t extstroff, int32_t strsize)
589623d454fSjonathan {
59063fc11e9Stsutsui 
591623d454fSjonathan 	if (debug)
59276987894Schristos 		fprintf(stderr,
593425b4f39Schristos 		    "writing symhdr for %d entries at offset %#x\n",
594c9ed2107Schristos 		    nesyms, ep->f.f_symptr);
595623d454fSjonathan 
596c9ed2107Schristos 	ep->f.f_nsyms = sizeof(struct ecoff32_symhdr);
597623d454fSjonathan 
598bfd52621Sperry 	memset(symhdrp, 0, sizeof(*symhdrp));
599623d454fSjonathan 	symhdrp->esymMax = nesyms;
600623d454fSjonathan 	symhdrp->magic = 0x7009;/* XXX */
601623d454fSjonathan 	symhdrp->cbExtOffset = extsymoff;
602623d454fSjonathan 	symhdrp->cbSsExtOffset = extstroff;
603623d454fSjonathan 
604623d454fSjonathan 	symhdrp->issExtMax = strsize;
605623d454fSjonathan 	if (debug)
606623d454fSjonathan 		fprintf(stderr,
607c9ed2107Schristos 		    "ECOFF symhdr: symhdr %zx, strsize %x, symsize %zx\n",
608623d454fSjonathan 		    sizeof(*symhdrp), strsize,
609c9ed2107Schristos 		    (nesyms * sizeof(struct ecoff32_extsym)));
610623d454fSjonathan 
61133176a12Sbouyer 	if (needswap) {
612f11583faSsimonb 		bswap32_region(&symhdrp->ilineMax,
61333176a12Sbouyer 		    sizeof(*symhdrp) -  sizeof(symhdrp->magic) -
61433176a12Sbouyer 		    sizeof(symhdrp->ilineMax));
61533176a12Sbouyer 		symhdrp->magic = bswap16(symhdrp->magic);
61633176a12Sbouyer 		symhdrp->ilineMax = bswap16(symhdrp->ilineMax);
61733176a12Sbouyer 	}
61833176a12Sbouyer 
619623d454fSjonathan 	safewrite(out, symhdrp, sizeof(*symhdrp),
62076987894Schristos 	    "writing symbol header");
621623d454fSjonathan }
622623d454fSjonathan 
623623d454fSjonathan 
62476987894Schristos static void
elf_read_syms(struct elf_syms * elfsymsp,int in,off_t symoff,off_t symsize,off_t stroff,off_t strsize)62563fc11e9Stsutsui elf_read_syms(struct elf_syms *elfsymsp, int in, off_t symoff, off_t symsize,
62663fc11e9Stsutsui     off_t stroff, off_t strsize)
627623d454fSjonathan {
628c9ed2107Schristos 	int nsyms;
62933176a12Sbouyer 	int i;
630623d454fSjonathan 	nsyms = symsize / sizeof(Elf32_Sym);
631623d454fSjonathan 
632623d454fSjonathan 	/* Suck in the ELF symbol list... */
633623d454fSjonathan 	elfsymsp->elf_syms = (Elf32_Sym *)
634623d454fSjonathan 	    saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
635623d454fSjonathan 	    "ELF symboltable");
636623d454fSjonathan 	elfsymsp->nsymbols = nsyms;
63733176a12Sbouyer 	if (needswap) {
63833176a12Sbouyer 		for (i = 0; i < nsyms; i++) {
63933176a12Sbouyer 			Elf32_Sym *s = &elfsymsp->elf_syms[i];
64033176a12Sbouyer 			s->st_name	= bswap32(s->st_name);
64133176a12Sbouyer 			s->st_value	= bswap32(s->st_value);
64233176a12Sbouyer 			s->st_size	= bswap32(s->st_size);
64333176a12Sbouyer 			s->st_shndx	= bswap16(s->st_shndx);
64433176a12Sbouyer 		}
64533176a12Sbouyer 	}
646623d454fSjonathan 
647623d454fSjonathan 	/* Suck in the ELF string table... */
648623d454fSjonathan 	elfsymsp->stringtab = (char *)
649623d454fSjonathan 	    saveRead(in, stroff, strsize, "ELF string table");
650623d454fSjonathan 	elfsymsp->stringsize = strsize;
651623d454fSjonathan }
652623d454fSjonathan 
653623d454fSjonathan 
65476987894Schristos static void
elf_symbol_table_to_ecoff(int out,int in,struct ecoff32_exechdr * ep,off_t symoff,off_t symsize,off_t stroff,off_t strsize)655c9ed2107Schristos elf_symbol_table_to_ecoff(int out, int in, struct ecoff32_exechdr *ep,
65663fc11e9Stsutsui     off_t symoff, off_t symsize, off_t stroff, off_t strsize)
657623d454fSjonathan {
658623d454fSjonathan 
659623d454fSjonathan 	struct elf_syms elfsymtab;
660623d454fSjonathan 	struct ecoff_syms ecoffsymtab;
661c9ed2107Schristos 	uint32_t ecoff_symhdr_off, symtaboff, stringtaboff;
662c9ed2107Schristos 	uint32_t nextoff, symtabsize, ecoff_strsize;
66333176a12Sbouyer 	int     nsyms, i;
664c9ed2107Schristos 	struct ecoff32_symhdr symhdr;
665623d454fSjonathan 	int     padding;
666623d454fSjonathan 
667623d454fSjonathan 	/* Read in the ELF symbols. */
668623d454fSjonathan 	elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
669623d454fSjonathan 
670623d454fSjonathan 	/* Approximate translation to ECOFF. */
671623d454fSjonathan 	translate_syms(&elfsymtab, &ecoffsymtab);
672623d454fSjonathan 	nsyms = ecoffsymtab.nsymbols;
673623d454fSjonathan 
674623d454fSjonathan 	/* Compute output ECOFF symbol- and string-table offsets. */
675623d454fSjonathan 	ecoff_symhdr_off = ep->f.f_symptr;
676623d454fSjonathan 
677623d454fSjonathan 	nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
678623d454fSjonathan 	stringtaboff = nextoff;
679623d454fSjonathan 	ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
680c9ed2107Schristos 	    (ECOFF32_SEGMENT_ALIGNMENT(ep)));
681623d454fSjonathan 
682623d454fSjonathan 
683623d454fSjonathan 	nextoff = stringtaboff + ecoff_strsize;
684623d454fSjonathan 	symtaboff = nextoff;
685623d454fSjonathan 	symtabsize = nsyms * sizeof(struct ecoff_extsym);
686c9ed2107Schristos 	symtabsize = ECOFF_ROUND(symtabsize, ECOFF32_SEGMENT_ALIGNMENT(ep));
687623d454fSjonathan 
688623d454fSjonathan 	/* Write out the symbol header ... */
689623d454fSjonathan 	write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
690623d454fSjonathan 	    stringtaboff, ecoffsymtab.stringsize);
691623d454fSjonathan 
692623d454fSjonathan 	/* Write out the string table... */
693623d454fSjonathan 	padding = ecoff_strsize - ecoffsymtab.stringsize;
694623d454fSjonathan 	safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
69576987894Schristos 	    "string table: write");
696623d454fSjonathan 	if (padding)
69776987894Schristos 		pad16(out, padding, "string table: padding");
698623d454fSjonathan 
699623d454fSjonathan 
700623d454fSjonathan 	/* Write out the symbol table... */
701623d454fSjonathan 	padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
70233176a12Sbouyer 
70333176a12Sbouyer 	for (i = 0; i < nsyms; i++) {
70433176a12Sbouyer 		struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i];
70533176a12Sbouyer 		es->es_flags	= bswap16(es->es_flags);
70633176a12Sbouyer 		es->es_ifd	= bswap16(es->es_ifd);
70733176a12Sbouyer 		bswap32_region(&es->es_strindex,
70833176a12Sbouyer 		    sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd));
70933176a12Sbouyer 	}
710623d454fSjonathan 	safewrite(out, ecoffsymtab.ecoff_syms,
711623d454fSjonathan 	    nsyms * sizeof(struct ecoff_extsym),
71276987894Schristos 	    "symbol table: write");
713623d454fSjonathan 	if (padding)
71476987894Schristos 		pad16(out, padding, "symbols: padding");
715623d454fSjonathan }
716623d454fSjonathan 
717623d454fSjonathan 
718623d454fSjonathan 
719623d454fSjonathan /*
720c9b3c34dSandvar  * In-memory translation of ELF symbols to ECOFF.
721623d454fSjonathan  */
72276987894Schristos static void
translate_syms(struct elf_syms * elfp,struct ecoff_syms * ecoffp)72363fc11e9Stsutsui translate_syms(struct elf_syms *elfp, struct ecoff_syms *ecoffp)
724623d454fSjonathan {
725623d454fSjonathan 
726623d454fSjonathan 	int     i;
727623d454fSjonathan 	char   *oldstringbase;
728623d454fSjonathan 	char   *newstrings, *nsp;
729623d454fSjonathan 
730623d454fSjonathan 	int     nsyms, idx;
731623d454fSjonathan 
732623d454fSjonathan 	nsyms = elfp->nsymbols;
733623d454fSjonathan 	oldstringbase = elfp->stringtab;
734623d454fSjonathan 
735623d454fSjonathan 	/* Allocate space for corresponding ECOFF symbols. */
736bfd52621Sperry 	memset(ecoffp, 0, sizeof(*ecoffp));
737623d454fSjonathan 
738623d454fSjonathan 	ecoffp->nsymbols = 0;
739623d454fSjonathan 	ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
740623d454fSjonathan 
741623d454fSjonathan 	/* we are going to be no bigger than the ELF symbol table. */
742623d454fSjonathan 	ecoffp->stringsize = elfp->stringsize;
743623d454fSjonathan 	ecoffp->stringtab = malloc(elfp->stringsize);
744623d454fSjonathan 
745623d454fSjonathan 	newstrings = (char *) ecoffp->stringtab;
746623d454fSjonathan 	nsp = (char *) ecoffp->stringtab;
74776987894Schristos 	if (newstrings == NULL)
74876987894Schristos 		errx(1, "No memory for new string table");
749623d454fSjonathan 	/* Copy and translate  symbols... */
750623d454fSjonathan 	idx = 0;
751623d454fSjonathan 	for (i = 0; i < nsyms; i++) {
752fe3f8679Schristos 		int     binding;
753623d454fSjonathan 
7541899563cSdrochner 		binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
755623d454fSjonathan 
756623d454fSjonathan 		/* skip strange symbols */
757623d454fSjonathan 		if (binding == 0) {
758623d454fSjonathan 			continue;
759623d454fSjonathan 		}
760623d454fSjonathan 		/* Copy the symbol into the new table */
761623d454fSjonathan 		strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
762623d454fSjonathan 		ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
763623d454fSjonathan 		nsp += strlen(nsp) + 1;
764623d454fSjonathan 
765623d454fSjonathan 		/* translate symbol types to ECOFF XXX */
766623d454fSjonathan 		ecoffp->ecoff_syms[idx].es_type = 1;
767623d454fSjonathan 		ecoffp->ecoff_syms[idx].es_class = 5;
768623d454fSjonathan 
769623d454fSjonathan 		/* Symbol values in executables should be compatible. */
770623d454fSjonathan 		ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
771623d454fSjonathan 		ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
772623d454fSjonathan 
773623d454fSjonathan 		idx++;
774623d454fSjonathan 	}
775623d454fSjonathan 
776623d454fSjonathan 	ecoffp->nsymbols = idx;
777623d454fSjonathan 	ecoffp->stringsize = nsp - newstrings;
778623d454fSjonathan }
779623d454fSjonathan /*
780623d454fSjonathan  * pad to a 16-byte boundary
781623d454fSjonathan  */
78276987894Schristos static void
pad16(int fd,int size,const char * msg)783623d454fSjonathan pad16(int fd, int size, const char *msg)
784623d454fSjonathan {
78563fc11e9Stsutsui 
786623d454fSjonathan 	safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
787623d454fSjonathan }
78833176a12Sbouyer 
78933176a12Sbouyer /* swap a 32bit region */
79076987894Schristos static void
bswap32_region(int32_t * p,int len)791f11583faSsimonb bswap32_region(int32_t* p, int len)
79233176a12Sbouyer {
793c37f283fStsutsui 	size_t i;
79433176a12Sbouyer 
795f11583faSsimonb 	for (i = 0; i < len / sizeof(int32_t); i++, p++)
79633176a12Sbouyer 		*p = bswap32(*p);
79733176a12Sbouyer }
798