elf2ecoff.c revision 1.27
1/*	$NetBSD: elf2ecoff.c,v 1.27 2011/06/28 13:13:15 tsutsui Exp $	*/
2
3/*
4 * Copyright (c) 1997 Jonathan Stone
5 *    All rights reserved.
6 * Copyright (c) 1995
7 *	Ted Lemon (hereinafter referred to as the author)
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/* elf2ecoff.c
34
35   This program converts an elf executable to an ECOFF executable.
36   No symbol table is retained.   This is useful primarily in building
37   net-bootable kernels for machines (e.g., DECstation and Alpha) which
38   only support the ECOFF object file format. */
39
40#if HAVE_NBTOOL_CONFIG_H
41#include "nbtool_config.h"
42#endif
43
44#include <sys/types.h>
45#include <err.h>
46#include <errno.h>
47#include <fcntl.h>
48#include <unistd.h>
49#include <sys/exec_elf.h>
50#include <stdio.h>
51#include <sys/exec_ecoff.h>
52#include <stdlib.h>
53#include <string.h>
54#include <limits.h>
55
56#define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
57
58struct sect {
59	unsigned long vaddr;
60	unsigned long len;
61};
62
63struct elf_syms {
64	int     nsymbols;
65	Elf32_Sym *elf_syms;
66	off_t   stringsize;
67	char   *stringtab;
68};
69
70struct ecoff_syms {
71	int     nsymbols;
72	struct ecoff_extsym *ecoff_syms;
73	off_t   stringsize;
74	char   *stringtab;
75};
76
77int     debug = 0;
78
79int     phcmp(Elf32_Phdr * h1, Elf32_Phdr * h2);
80
81
82char   *saveRead(int file, off_t offset, off_t len, const char *name);
83void    safewrite(int outfile, const void *buf, off_t len, const char *msg);
84void    copy(int, int, off_t, off_t);
85void    combine(struct sect * base, struct sect * new, int paddable);
86void    translate_syms(struct elf_syms *, struct ecoff_syms *);
87void	elf_symbol_table_to_ecoff(int out, int in,
88	    struct ecoff_exechdr * ep,
89	    off_t symoff, off_t symsize,
90	    off_t stroff, off_t strsize);
91
92
93int	make_ecoff_section_hdrs(struct ecoff_exechdr * ep,
94	    struct ecoff_scnhdr * esecs);
95
96void	write_ecoff_symhdr(int outfile, struct ecoff_exechdr * ep,
97	    struct ecoff_symhdr * symhdrp,
98	    long nesyms, long extsymoff, long extstroff,
99	    long strsize);
100
101void    pad16(int fd, int size, const char *msg);
102void	bswap32_region(int32_t* , int);
103
104int    *symTypeTable;
105int	needswap;
106
107
108
109
110void	elf_read_syms(struct elf_syms * elfsymsp, int infile,
111	    off_t symoff, off_t symsize, off_t stroff, off_t strsize);
112
113
114int
115main(int argc, char **argv, char **envp)
116{
117	Elf32_Ehdr ex;
118	Elf32_Phdr *ph;
119	Elf32_Shdr *sh;
120	char   *shstrtab;
121	int     strtabix, symtabix;
122	size_t	i;
123	int     pad;
124	struct sect text, data, bss;	/* a.out-compatible sections */
125	struct sect rdata, sdata, sbss;	/* ECOFF-only sections */
126
127	struct ecoff_exechdr ep;
128	struct ecoff_scnhdr esecs[6];
129	struct ecoff_symhdr symhdr;
130
131	int     infile, outfile;
132	unsigned long cur_vma = ULONG_MAX;
133	int     symflag = 0;
134	int     nsecs = 0;
135	int	mipsel;
136
137
138	text.len = data.len = bss.len = 0;
139	text.vaddr = data.vaddr = bss.vaddr = 0;
140
141	rdata.len = sdata.len = sbss.len = 0;
142	rdata.vaddr = sdata.vaddr = sbss.vaddr = 0;
143
144	/* Check args... */
145	if (argc < 3 || argc > 4) {
146usage:
147		fprintf(stderr,
148		    "usage: elf2ecoff <elf executable> <ECOFF executable> [-s]\n");
149		exit(1);
150	}
151	if (argc == 4) {
152		if (strcmp(argv[3], "-s"))
153			goto usage;
154		symflag = 1;
155	}
156	/* Try the input file... */
157	if ((infile = open(argv[1], O_RDONLY)) < 0) {
158		fprintf(stderr, "Can't open %s for read: %s\n",
159		    argv[1], strerror(errno));
160		exit(1);
161	}
162	/* Read the header, which is at the beginning of the file... */
163	i = read(infile, &ex, sizeof ex);
164	if (i != sizeof ex) {
165		fprintf(stderr, "ex: %s: %s.\n",
166		    argv[1], i ? strerror(errno) : "End of file reached");
167		exit(1);
168	}
169	if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
170		mipsel = 1;
171	else if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
172		mipsel = 0;
173	else {
174		fprintf(stderr, "invalid ELF byte order %d\n",
175		    ex.e_ident[EI_DATA]);
176		exit(1);
177	}
178#if BYTE_ORDER == BIG_ENDIAN
179	if (mipsel)
180		needswap = 1;
181	else
182		needswap = 0;
183#elif BYTE_ORDER == LITTLE_ENDIAN
184	if (mipsel)
185		needswap = 0;
186	else
187		needswap = 1;
188#else
189#error "unknown endian"
190#endif
191
192	if (needswap) {
193		ex.e_type	= bswap16(ex.e_type);
194		ex.e_machine	= bswap16(ex.e_machine);
195		ex.e_version	= bswap32(ex.e_version);
196		ex.e_entry 	= bswap32(ex.e_entry);
197		ex.e_phoff	= bswap32(ex.e_phoff);
198		ex.e_shoff	= bswap32(ex.e_shoff);
199		ex.e_flags	= bswap32(ex.e_flags);
200		ex.e_ehsize	= bswap16(ex.e_ehsize);
201		ex.e_phentsize	= bswap16(ex.e_phentsize);
202		ex.e_phnum	= bswap16(ex.e_phnum);
203		ex.e_shentsize	= bswap16(ex.e_shentsize);
204		ex.e_shnum	= bswap16(ex.e_shnum);
205		ex.e_shstrndx	= bswap16(ex.e_shstrndx);
206	}
207
208	/* Read the program headers... */
209	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
210	    ex.e_phnum * sizeof(Elf32_Phdr), "ph");
211	if (needswap)
212		bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
213	/* Read the section headers... */
214	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
215	    ex.e_shnum * sizeof(Elf32_Shdr), "sh");
216	if (needswap)
217		bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
218
219	/* Read in the section string table. */
220	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
221	    sh[ex.e_shstrndx].sh_size, "shstrtab");
222
223
224	/* Look for the symbol table and string table... Also map section
225	 * indices to symbol types for a.out */
226	symtabix = 0;
227	strtabix = 0;
228	for (i = 0; i < ex.e_shnum; i++) {
229		char   *name = shstrtab + sh[i].sh_name;
230		if (!strcmp(name, ".symtab"))
231			symtabix = i;
232		else
233			if (!strcmp(name, ".strtab"))
234				strtabix = i;
235
236	}
237
238	/* Figure out if we can cram the program header into an ECOFF
239	 * header...  Basically, we can't handle anything but loadable
240	 * segments, but we can ignore some kinds of segments.  We can't
241	 * handle holes in the address space.  Segments may be out of order,
242	 * so we sort them first. */
243
244	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr),
245	    (int (*) (const void *, const void *)) phcmp);
246
247	for (i = 0; i < ex.e_phnum; i++) {
248		/* Section types we can ignore... */
249		if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
250		    ph[i].p_type == PT_PHDR ||
251		    ph[i].p_type == PT_MIPS_REGINFO) {
252
253			if (debug) {
254				fprintf(stderr, "  skipping PH %zu type %d flags 0x%x\n",
255				    i, ph[i].p_type, ph[i].p_flags);
256			}
257			continue;
258		}
259		/* Section types we can't handle... */
260		else
261			if (ph[i].p_type != PT_LOAD) {
262				fprintf(stderr, "Program header %zu type %d can't be converted.\n",
263				    i, ph[i].p_type);
264				exit(1);
265			}
266		/* Writable (data) segment? */
267		if (ph[i].p_flags & PF_W) {
268			struct sect ndata, nbss;
269
270			ndata.vaddr = ph[i].p_vaddr;
271			ndata.len = ph[i].p_filesz;
272			nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
273			nbss.len = ph[i].p_memsz - ph[i].p_filesz;
274
275			if (debug) {
276				fprintf(stderr,
277				    "  combinining PH %zu type %d flags 0x%x with data, ndata = %ld, nbss =%ld\n", i, ph[i].p_type, ph[i].p_flags, ndata.len, nbss.len);
278			}
279			combine(&data, &ndata, 0);
280			combine(&bss, &nbss, 1);
281		} else {
282			struct sect ntxt;
283
284			ntxt.vaddr = ph[i].p_vaddr;
285			ntxt.len = ph[i].p_filesz;
286			if (debug) {
287
288				fprintf(stderr,
289				    "  combinining PH %zu type %d flags 0x%x with text, len = %ld\n",
290				    i, ph[i].p_type, ph[i].p_flags, ntxt.len);
291			}
292			combine(&text, &ntxt, 0);
293		}
294		/* Remember the lowest segment start address. */
295		if (ph[i].p_vaddr < cur_vma)
296			cur_vma = ph[i].p_vaddr;
297	}
298
299	/* Sections must be in order to be converted... */
300	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
301	    text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
302		fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
303		exit(1);
304	}
305	/* If there's a data section but no text section, then the loader
306	 * combined everything into one section.   That needs to be the text
307	 * section, so just make the data section zero length following text. */
308	if (data.len && text.len == 0) {
309		text = data;
310		data.vaddr = text.vaddr + text.len;
311		data.len = 0;
312	}
313	/* If there is a gap between text and data, we'll fill it when we copy
314	 * the data, so update the length of the text segment as represented
315	 * in a.out to reflect that, since a.out doesn't allow gaps in the
316	 * program address space. */
317	if (text.vaddr + text.len < data.vaddr)
318		text.len = data.vaddr - text.vaddr;
319
320	/* We now have enough information to cons up an a.out header... */
321	ep.a.magic = ECOFF_OMAGIC;
322	ep.a.vstamp = 2 * 256 + 10;	/* compatible with version 2.10 */
323	ep.a.tsize = text.len;
324	ep.a.dsize = data.len;
325	ep.a.bsize = bss.len;
326	ep.a.entry = ex.e_entry;
327	ep.a.text_start = text.vaddr;
328	ep.a.data_start = data.vaddr;
329	ep.a.bss_start = bss.vaddr;
330	ep.a.gprmask = 0xf3fffffe;
331	memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask);
332	ep.a.gp_value = 0;	/* unused. */
333
334	if (mipsel)
335		ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
336	else
337		ep.f.f_magic = ECOFF_MAGIC_MIPSEB;
338
339	ep.f.f_nscns = 6;
340	ep.f.f_timdat = 0;	/* bogus */
341	ep.f.f_symptr = 0;
342	ep.f.f_nsyms = sizeof(struct ecoff_symhdr);
343	ep.f.f_opthdr = sizeof ep.a;
344	ep.f.f_flags = 0x100f;	/* Stripped, not sharable. */
345
346	memset(esecs, 0, sizeof(esecs));
347
348	/* Make  ECOFF section headers, with empty stubs for
349	 * .rdata/.sdata/.sbss. */
350	make_ecoff_section_hdrs(&ep, esecs);
351
352	nsecs = ep.f.f_nscns;
353
354	if (needswap) {
355		ep.f.f_magic	= bswap16(ep.f.f_magic);
356		ep.f.f_nscns	= bswap16(ep.f.f_nscns);
357		ep.f.f_timdat	= bswap32(ep.f.f_timdat);
358		ep.f.f_symptr	= bswap32(ep.f.f_symptr);
359		ep.f.f_nsyms	= bswap32(ep.f.f_nsyms);
360		ep.f.f_opthdr	= bswap16(ep.f.f_opthdr);
361		ep.f.f_flags	= bswap16(ep.f.f_flags);
362		ep.a.magic	= bswap16(ep.a.magic);
363		ep.a.vstamp	= bswap16(ep.a.vstamp);
364		ep.a.tsize	= bswap32(ep.a.tsize);
365		ep.a.dsize	= bswap32(ep.a.dsize);
366		ep.a.bsize	= bswap32(ep.a.bsize);
367		ep.a.entry	= bswap32(ep.a.entry);
368		ep.a.text_start	= bswap32(ep.a.text_start);
369		ep.a.data_start	= bswap32(ep.a.data_start);
370		ep.a.bss_start	= bswap32(ep.a.bss_start);
371		ep.a.gprmask	= bswap32(ep.a.gprmask);
372		bswap32_region((int32_t*)ep.a.cprmask, sizeof(ep.a.cprmask));
373		ep.a.gp_value	= bswap32(ep.a.gp_value);
374		for (i = 0; i < sizeof(esecs) / sizeof(esecs[0]); i++) {
375			esecs[i].s_paddr	= bswap32(esecs[i].s_paddr);
376			esecs[i].s_vaddr	= bswap32(esecs[i].s_vaddr);
377			esecs[i].s_size 	= bswap32(esecs[i].s_size);
378			esecs[i].s_scnptr	= bswap32(esecs[i].s_scnptr);
379			esecs[i].s_relptr	= bswap32(esecs[i].s_relptr);
380			esecs[i].s_lnnoptr	= bswap32(esecs[i].s_lnnoptr);
381			esecs[i].s_nreloc	= bswap16(esecs[i].s_nreloc);
382			esecs[i].s_nlnno	= bswap16(esecs[i].s_nlnno);
383			esecs[i].s_flags	= bswap32(esecs[i].s_flags);
384		}
385	}
386
387	/* Make the output file... */
388	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
389		fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
390		exit(1);
391	}
392	/* Truncate file... */
393	if (ftruncate(outfile, 0)) {
394		warn("ftruncate %s", argv[2]);
395	}
396	/* Write the headers... */
397	safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write: %s\n");
398	if (debug)
399		fprintf(stderr, "wrote %zu byte file header.\n", sizeof(ep.f));
400
401	safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write: %s\n");
402	if (debug)
403		fprintf(stderr, "wrote %zu byte a.out header.\n", sizeof(ep.a));
404
405	safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs,
406	    "esecs: write: %s\n");
407	if (debug)
408		fprintf(stderr, "wrote %zu bytes of section headers.\n",
409		    sizeof(esecs[0]) * nsecs);
410
411
412	pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
413	if (pad) {
414		pad = 16 - pad;
415		pad16(outfile, pad, "ipad: write: %s\n");
416		if (debug)
417			fprintf(stderr, "wrote %d byte pad.\n", pad);
418	}
419	/* Copy the loadable sections.   Zero-fill any gaps less than 64k;
420	 * complain about any zero-filling, and die if we're asked to
421	 * zero-fill more than 64k. */
422	for (i = 0; i < ex.e_phnum; i++) {
423		/* Unprocessable sections were handled above, so just verify
424		 * that the section can be loaded before copying. */
425		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
426			if (cur_vma != ph[i].p_vaddr) {
427				unsigned long gap = ph[i].p_vaddr - cur_vma;
428				char    obuf[1024];
429				if (gap > 65536) {
430					fprintf(stderr, "Intersegment gap (%ld bytes) too large.\n",
431					    gap);
432					exit(1);
433				}
434				if (debug)
435					fprintf(stderr, "Warning: %ld byte intersegment gap.\n", gap);
436				memset(obuf, 0, sizeof obuf);
437				while (gap) {
438					int     count = write(outfile, obuf, (gap > sizeof obuf
439						? sizeof obuf : gap));
440					if (count < 0) {
441						fprintf(stderr, "Error writing gap: %s\n",
442						    strerror(errno));
443						exit(1);
444					}
445					gap -= count;
446				}
447			}
448			if (debug)
449				fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
450			copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
451			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
452		}
453	}
454
455
456	if (debug)
457		fprintf(stderr, "writing syms at offset 0x%lx\n",
458		    (u_long) ep.f.f_symptr + sizeof(symhdr));
459
460	/* Copy and translate the symbol table... */
461	elf_symbol_table_to_ecoff(outfile, infile, &ep,
462	    sh[symtabix].sh_offset, sh[symtabix].sh_size,
463	    sh[strtabix].sh_offset, sh[strtabix].sh_size);
464
465	/*
466         * Write a page of padding for boot PROMS that read entire pages.
467         * Without this, they may attempt to read past the end of the
468         * data section, incur an error, and refuse to boot.
469         */
470	{
471		char    obuf[4096];
472		memset(obuf, 0, sizeof obuf);
473		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
474			fprintf(stderr, "Error writing PROM padding: %s\n",
475			    strerror(errno));
476			exit(1);
477		}
478	}
479
480	/* Looks like we won... */
481	exit(0);
482}
483
484void
485copy(int out, int in, off_t offset, off_t size)
486{
487	char    ibuf[4096];
488	size_t  remaining, cur, count;
489
490	/* Go to the start of the ELF symbol table... */
491	if (lseek(in, offset, SEEK_SET) < 0) {
492		perror("copy: lseek");
493		exit(1);
494	}
495	remaining = size;
496	while (remaining) {
497		cur = remaining;
498		if (cur > sizeof ibuf)
499			cur = sizeof ibuf;
500		remaining -= cur;
501		if ((count = read(in, ibuf, cur)) != cur) {
502			fprintf(stderr, "copy: read: %s\n",
503			    count ? strerror(errno) : "premature end of file");
504			exit(1);
505		}
506		safewrite(out, ibuf, cur, "copy: write: %s\n");
507	}
508}
509/* Combine two segments, which must be contiguous.   If pad is true, it's
510   okay for there to be padding between. */
511void
512combine(struct sect *base, struct sect *new, int pad)
513{
514
515	if (base->len == 0)
516		*base = *new;
517	else
518		if (new->len) {
519			if (base->vaddr + base->len != new->vaddr) {
520				if (pad)
521					base->len = new->vaddr - base->vaddr;
522				else {
523					fprintf(stderr,
524					    "Non-contiguous data can't be converted.\n");
525					exit(1);
526				}
527			}
528			base->len += new->len;
529		}
530}
531
532int
533phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2)
534{
535
536	if (h1->p_vaddr > h2->p_vaddr)
537		return 1;
538	else
539		if (h1->p_vaddr < h2->p_vaddr)
540			return -1;
541		else
542			return 0;
543}
544
545char *
546saveRead(int file, off_t offset, off_t len, const char *name)
547{
548	char   *tmp;
549	int     count;
550	off_t   off;
551
552	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
553		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
554		exit(1);
555	}
556	if ((tmp = malloc(len)) == NULL) {
557		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, (long) len);
558		exit(1);
559	}
560	count = read(file, tmp, len);
561	if (count != len) {
562		fprintf(stderr, "%s: read: %s.\n",
563		    name, count ? strerror(errno) : "End of file reached");
564		exit(1);
565	}
566	return tmp;
567}
568
569void
570safewrite(int outfile, const void *buf, off_t len, const char *msg)
571{
572	int     written;
573
574	written = write(outfile, buf, len);
575	if (written != len) {
576		fprintf(stderr, msg, strerror(errno));
577		exit(1);
578	}
579}
580
581
582/*
583 * Output only three ECOFF sections, corresponding to ELF psecs
584 * for text, data, and bss.
585 */
586int
587make_ecoff_section_hdrs(struct ecoff_exechdr *ep, struct ecoff_scnhdr *esecs)
588{
589
590	ep->f.f_nscns = 6;	/* XXX */
591
592	strcpy(esecs[0].s_name, ".text");
593	strcpy(esecs[1].s_name, ".data");
594	strcpy(esecs[2].s_name, ".bss");
595
596	esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
597	esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
598	esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
599	esecs[0].s_size = ep->a.tsize;
600	esecs[1].s_size = ep->a.dsize;
601	esecs[2].s_size = ep->a.bsize;
602
603	esecs[0].s_scnptr = ECOFF_TXTOFF(ep);
604	esecs[1].s_scnptr = ECOFF_DATOFF(ep);
605#if 0
606	esecs[2].s_scnptr = esecs[1].s_scnptr +
607	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(ep));
608#endif
609
610	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
611	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
612	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
613	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
614
615	esecs[1].s_flags = 0x100;	/* ECOFF rdata */
616	esecs[3].s_flags = 0x200;	/* ECOFF sdata */
617	esecs[4].s_flags = 0x400;	/* ECOFF sbss */
618
619	/*
620	 * Set the symbol-table offset  to point at the end of any
621	 * sections we loaded above, so later code can use it to write
622	 * symbol table info..
623	 */
624	ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
625	return (ep->f.f_nscns);
626}
627
628
629/*
630 * Write the ECOFF symbol header.
631 * Guess at how big the symbol table will be.
632 * Mark all symbols as EXTERN (for now).
633 */
634void
635write_ecoff_symhdr(int out, struct ecoff_exechdr *ep,
636    struct ecoff_symhdr *symhdrp, long nesyms,
637    long extsymoff, long extstroff, long strsize)
638{
639
640	if (debug)
641		fprintf(stderr, "writing symhdr for %ld entries at offset 0x%lx\n",
642		    nesyms, (u_long) ep->f.f_symptr);
643
644	ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
645
646	memset(symhdrp, 0, sizeof(*symhdrp));
647	symhdrp->esymMax = nesyms;
648	symhdrp->magic = 0x7009;/* XXX */
649	symhdrp->cbExtOffset = extsymoff;
650	symhdrp->cbSsExtOffset = extstroff;
651
652	symhdrp->issExtMax = strsize;
653	if (debug)
654		fprintf(stderr,
655		    "ECOFF symhdr: symhdr %zx, strsize %lx, symsize %lx\n",
656		    sizeof(*symhdrp), strsize,
657		    (nesyms * sizeof(struct ecoff_extsym)));
658
659	if (needswap) {
660		bswap32_region(&symhdrp->ilineMax,
661		    sizeof(*symhdrp) -  sizeof(symhdrp->magic) -
662		    sizeof(symhdrp->ilineMax));
663		symhdrp->magic = bswap16(symhdrp->magic);
664		symhdrp->ilineMax = bswap16(symhdrp->ilineMax);
665	}
666
667	safewrite(out, symhdrp, sizeof(*symhdrp),
668	    "writing symbol header: %s\n");
669}
670
671
672void
673elf_read_syms(struct elf_syms *elfsymsp, int in, off_t symoff, off_t symsize,
674    off_t stroff, off_t strsize)
675{
676	register int nsyms;
677	int i;
678	nsyms = symsize / sizeof(Elf32_Sym);
679
680	/* Suck in the ELF symbol list... */
681	elfsymsp->elf_syms = (Elf32_Sym *)
682	    saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
683	    "ELF symboltable");
684	elfsymsp->nsymbols = nsyms;
685	if (needswap) {
686		for (i = 0; i < nsyms; i++) {
687			Elf32_Sym *s = &elfsymsp->elf_syms[i];
688			s->st_name	= bswap32(s->st_name);
689			s->st_value	= bswap32(s->st_value);
690			s->st_size	= bswap32(s->st_size);
691			s->st_shndx	= bswap16(s->st_shndx);
692		}
693	}
694
695	/* Suck in the ELF string table... */
696	elfsymsp->stringtab = (char *)
697	    saveRead(in, stroff, strsize, "ELF string table");
698	elfsymsp->stringsize = strsize;
699}
700
701
702/*
703 *
704 */
705void
706elf_symbol_table_to_ecoff(int out, int in, struct ecoff_exechdr *ep,
707    off_t symoff, off_t symsize, off_t stroff, off_t strsize)
708{
709
710	struct elf_syms elfsymtab;
711	struct ecoff_syms ecoffsymtab;
712	register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
713	register u_long nextoff, symtabsize, ecoff_strsize;
714	int     nsyms, i;
715	struct ecoff_symhdr symhdr;
716	int     padding;
717
718	/* Read in the ELF symbols. */
719	elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
720
721	/* Approximate translation to ECOFF. */
722	translate_syms(&elfsymtab, &ecoffsymtab);
723	nsyms = ecoffsymtab.nsymbols;
724
725	/* Compute output ECOFF symbol- and string-table offsets. */
726	ecoff_symhdr_off = ep->f.f_symptr;
727
728	nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
729	stringtaboff = nextoff;
730	ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
731	    (ECOFF_SEGMENT_ALIGNMENT(ep)));
732
733
734	nextoff = stringtaboff + ecoff_strsize;
735	symtaboff = nextoff;
736	symtabsize = nsyms * sizeof(struct ecoff_extsym);
737	symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
738
739	/* Write out the symbol header ... */
740	write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
741	    stringtaboff, ecoffsymtab.stringsize);
742
743	/* Write out the string table... */
744	padding = ecoff_strsize - ecoffsymtab.stringsize;
745	safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
746	    "string table: write: %s\n");
747	if (padding)
748		pad16(out, padding, "string table: padding: %s\n");
749
750
751	/* Write out the symbol table... */
752	padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
753
754	for (i = 0; i < nsyms; i++) {
755		struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i];
756		es->es_flags	= bswap16(es->es_flags);
757		es->es_ifd	= bswap16(es->es_ifd);
758		bswap32_region(&es->es_strindex,
759		    sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd));
760	}
761	safewrite(out, ecoffsymtab.ecoff_syms,
762	    nsyms * sizeof(struct ecoff_extsym),
763	    "symbol table: write: %s\n");
764	if (padding)
765		pad16(out, padding, "symbols: padding: %s\n");
766}
767
768
769
770/*
771 * In-memory translation of ELF symbosl to ECOFF.
772 */
773void
774translate_syms(struct elf_syms *elfp, struct ecoff_syms *ecoffp)
775{
776
777	int     i;
778	char   *oldstringbase;
779	char   *newstrings, *nsp;
780
781	int     nsyms, idx;
782
783	nsyms = elfp->nsymbols;
784	oldstringbase = elfp->stringtab;
785
786	/* Allocate space for corresponding ECOFF symbols. */
787	memset(ecoffp, 0, sizeof(*ecoffp));
788
789	ecoffp->nsymbols = 0;
790	ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
791
792	/* we are going to be no bigger than the ELF symbol table. */
793	ecoffp->stringsize = elfp->stringsize;
794	ecoffp->stringtab = malloc(elfp->stringsize);
795
796	newstrings = (char *) ecoffp->stringtab;
797	nsp = (char *) ecoffp->stringtab;
798	if (newstrings == NULL) {
799		fprintf(stderr, "No memory for new string table!\n");
800		exit(1);
801	}
802	/* Copy and translate  symbols... */
803	idx = 0;
804	for (i = 0; i < nsyms; i++) {
805		int     binding, type;
806
807		binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
808		type = ELF32_ST_TYPE((elfp->elf_syms[i].st_info));
809
810		/* skip strange symbols */
811		if (binding == 0) {
812			continue;
813		}
814		/* Copy the symbol into the new table */
815		strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
816		ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
817		nsp += strlen(nsp) + 1;
818
819		/* translate symbol types to ECOFF XXX */
820		ecoffp->ecoff_syms[idx].es_type = 1;
821		ecoffp->ecoff_syms[idx].es_class = 5;
822
823		/* Symbol values in executables should be compatible. */
824		ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
825		ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
826
827		idx++;
828	}
829
830	ecoffp->nsymbols = idx;
831	ecoffp->stringsize = nsp - newstrings;
832}
833/*
834 * pad to a 16-byte boundary
835 */
836void
837pad16(int fd, int size, const char *msg)
838{
839
840	safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
841}
842
843/* swap a 32bit region */
844void
845bswap32_region(int32_t* p, int len)
846{
847	size_t i;
848
849	for (i = 0; i < len / sizeof(int32_t); i++, p++)
850		*p = bswap32(*p);
851}
852