elf2ecoff.c revision 1.18
1/*	$NetBSD: elf2ecoff.c,v 1.18 2002/03/23 17:44:52 bouyer 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#include <sys/types.h>
41#include <err.h>
42#include <errno.h>
43#include <fcntl.h>
44#include <unistd.h>
45#include <sys/exec_elf.h>
46#include <stdio.h>
47#include <sys/exec_ecoff.h>
48#include <stdlib.h>
49#include <string.h>
50#include <limits.h>
51
52
53#define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
54
55struct sect {
56	unsigned long vaddr;
57	unsigned long len;
58};
59
60struct elf_syms {
61	int     nsymbols;
62	Elf32_Sym *elf_syms;
63	off_t   stringsize;
64	char   *stringtab;
65};
66
67struct ecoff_syms {
68	int     nsymbols;
69	struct ecoff_extsym *ecoff_syms;
70	off_t   stringsize;
71	char   *stringtab;
72};
73
74int     debug = 0;
75
76int     phcmp(Elf32_Phdr * h1, Elf32_Phdr * h2);
77
78
79char   *saveRead(int file, off_t offset, off_t len, char *name);
80void    safewrite(int outfile, void *buf, off_t len, const char *msg);
81void    copy(int, int, off_t, off_t);
82void    combine(struct sect * base, struct sect * new, int paddable);
83void    translate_syms(struct elf_syms *, struct ecoff_syms *);
84void
85elf_symbol_table_to_ecoff(int out, int in,
86    struct ecoff_exechdr * ep,
87    off_t symoff, off_t symsize,
88    off_t stroff, off_t strsize);
89
90
91int
92make_ecoff_section_hdrs(struct ecoff_exechdr * ep,
93    struct ecoff_scnhdr * esecs);
94
95void
96write_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(u_int32_t* , int);
103
104int    *symTypeTable;
105int	needswap;
106
107
108
109
110void
111elf_read_syms(struct elf_syms * elfsymsp, int infile,
112    off_t symoff, off_t symsize, off_t stroff, off_t strsize);
113
114
115int
116main(int argc, char **argv, char **envp)
117{
118	Elf32_Ehdr ex;
119	Elf32_Phdr *ph;
120	Elf32_Shdr *sh;
121	char   *shstrtab;
122	int     strtabix, symtabix;
123	int     i, 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((u_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((u_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 %d 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 %d 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 %d 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 %d 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) {
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((u_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 %d 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 %d 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 %d 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(out, in, offset, size)
486	int     out, in;
487	off_t   offset, size;
488{
489	char    ibuf[4096];
490	int     remaining, cur, count;
491
492	/* Go to the start of the ELF symbol table... */
493	if (lseek(in, offset, SEEK_SET) < 0) {
494		perror("copy: lseek");
495		exit(1);
496	}
497	remaining = size;
498	while (remaining) {
499		cur = remaining;
500		if (cur > sizeof ibuf)
501			cur = sizeof ibuf;
502		remaining -= cur;
503		if ((count = read(in, ibuf, cur)) != cur) {
504			fprintf(stderr, "copy: read: %s\n",
505			    count ? strerror(errno) : "premature end of file");
506			exit(1);
507		}
508		safewrite(out, ibuf, cur, "copy: write: %s\n");
509	}
510}
511/* Combine two segments, which must be contiguous.   If pad is true, it's
512   okay for there to be padding between. */
513void
514combine(base, new, pad)
515	struct sect *base, *new;
516	int     pad;
517{
518	if (!base->len)
519		*base = *new;
520	else
521		if (new->len) {
522			if (base->vaddr + base->len != new->vaddr) {
523				if (pad)
524					base->len = new->vaddr - base->vaddr;
525				else {
526					fprintf(stderr,
527					    "Non-contiguous data can't be converted.\n");
528					exit(1);
529				}
530			}
531			base->len += new->len;
532		}
533}
534
535int
536phcmp(h1, h2)
537	Elf32_Phdr *h1, *h2;
538{
539	if (h1->p_vaddr > h2->p_vaddr)
540		return 1;
541	else
542		if (h1->p_vaddr < h2->p_vaddr)
543			return -1;
544		else
545			return 0;
546}
547
548char
549       *
550saveRead(int file, off_t offset, off_t len, char *name)
551{
552	char   *tmp;
553	int     count;
554	off_t   off;
555	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
556		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
557		exit(1);
558	}
559	if (!(tmp = (char *) malloc(len))) {
560		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, (long) len);
561		exit(1);
562	}
563	count = read(file, tmp, len);
564	if (count != len) {
565		fprintf(stderr, "%s: read: %s.\n",
566		    name, count ? strerror(errno) : "End of file reached");
567		exit(1);
568	}
569	return tmp;
570}
571
572void
573safewrite(int outfile, void *buf, off_t len, const char *msg)
574{
575	int     written;
576	written = write(outfile, (char *) buf, len);
577	if (written != len) {
578		fprintf(stderr, msg, strerror(errno));
579		exit(1);
580	}
581}
582
583
584/*
585 * Output only three ECOFF sections, corresponding to ELF psecs
586 * for text, data, and bss.
587 */
588int
589make_ecoff_section_hdrs(ep, esecs)
590	struct ecoff_exechdr *ep;
591	struct ecoff_scnhdr *esecs;
592
593{
594	ep->f.f_nscns = 6;	/* XXX */
595
596	strcpy(esecs[0].s_name, ".text");
597	strcpy(esecs[1].s_name, ".data");
598	strcpy(esecs[2].s_name, ".bss");
599
600	esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
601	esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
602	esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
603	esecs[0].s_size = ep->a.tsize;
604	esecs[1].s_size = ep->a.dsize;
605	esecs[2].s_size = ep->a.bsize;
606
607	esecs[0].s_scnptr = ECOFF_TXTOFF(ep);
608	esecs[1].s_scnptr = ECOFF_DATOFF(ep);
609#if 0
610	esecs[2].s_scnptr = esecs[1].s_scnptr +
611	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(ep));
612#endif
613
614	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
615	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
616	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
617	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
618
619	esecs[1].s_flags = 0x100;	/* ECOFF rdata */
620	esecs[3].s_flags = 0x200;	/* ECOFF sdata */
621	esecs[4].s_flags = 0x400;	/* ECOFF sbss */
622
623	/*
624	 * Set the symbol-table offset  to point at the end of any
625	 * sections we loaded above, so later code can use it to write
626	 * symbol table info..
627	 */
628	ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
629	return (ep->f.f_nscns);
630}
631
632
633/*
634 * Write the ECOFF symbol header.
635 * Guess at how big the symbol table will be.
636 * Mark all symbols as EXTERN (for now).
637 */
638void
639write_ecoff_symhdr(out, ep, symhdrp, nesyms, extsymoff, extstroff, strsize)
640	int     out;
641	struct ecoff_exechdr *ep;
642	struct ecoff_symhdr *symhdrp;
643	long    nesyms, extsymoff, extstroff, strsize;
644{
645	if (debug)
646		fprintf(stderr, "writing symhdr for %ld entries at offset 0x%lx\n",
647		    nesyms, (u_long) ep->f.f_symptr);
648
649	ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
650
651	memset(symhdrp, 0, sizeof(*symhdrp));
652	symhdrp->esymMax = nesyms;
653	symhdrp->magic = 0x7009;/* XXX */
654	symhdrp->cbExtOffset = extsymoff;
655	symhdrp->cbSsExtOffset = extstroff;
656
657	symhdrp->issExtMax = strsize;
658	if (debug)
659		fprintf(stderr,
660		    "ECOFF symhdr: symhdr %x, strsize %lx, symsize %lx\n",
661		    sizeof(*symhdrp), strsize,
662		    (nesyms * sizeof(struct ecoff_extsym)));
663
664	if (needswap) {
665		bswap32_region((u_int32_t*)&symhdrp->ilineMax,
666		    sizeof(*symhdrp) -  sizeof(symhdrp->magic) -
667		    sizeof(symhdrp->ilineMax));
668		symhdrp->magic = bswap16(symhdrp->magic);
669		symhdrp->ilineMax = bswap16(symhdrp->ilineMax);
670	}
671
672	safewrite(out, symhdrp, sizeof(*symhdrp),
673	    "writing symbol header: %s\n");
674}
675
676
677void
678elf_read_syms(elfsymsp, in, symoff, symsize, stroff, strsize)
679	struct elf_syms *elfsymsp;
680	int     in;
681	off_t   symoff, symsize;
682	off_t   stroff, strsize;
683{
684	register int nsyms;
685	int i;
686	nsyms = symsize / sizeof(Elf32_Sym);
687
688	/* Suck in the ELF symbol list... */
689	elfsymsp->elf_syms = (Elf32_Sym *)
690	    saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
691	    "ELF symboltable");
692	elfsymsp->nsymbols = nsyms;
693	if (needswap) {
694		for (i = 0; i < nsyms; i++) {
695			Elf32_Sym *s = &elfsymsp->elf_syms[i];
696			s->st_name	= bswap32(s->st_name);
697			s->st_value	= bswap32(s->st_value);
698			s->st_size	= bswap32(s->st_size);
699			s->st_shndx	= bswap16(s->st_shndx);
700		}
701	}
702
703	/* Suck in the ELF string table... */
704	elfsymsp->stringtab = (char *)
705	    saveRead(in, stroff, strsize, "ELF string table");
706	elfsymsp->stringsize = strsize;
707}
708
709
710/*
711 *
712 */
713void
714elf_symbol_table_to_ecoff(out, in, ep, symoff, symsize, stroff, strsize)
715	int     out, in;
716	struct ecoff_exechdr *ep;
717	off_t   symoff, symsize;
718	off_t   stroff, strsize;
719{
720
721	struct elf_syms elfsymtab;
722	struct ecoff_syms ecoffsymtab;
723	register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
724	register u_long nextoff, symtabsize, ecoff_strsize;
725	int     nsyms, i;
726	struct ecoff_symhdr symhdr;
727	int     padding;
728
729	/* Read in the ELF symbols. */
730	elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
731
732	/* Approximate translation to ECOFF. */
733	translate_syms(&elfsymtab, &ecoffsymtab);
734	nsyms = ecoffsymtab.nsymbols;
735
736	/* Compute output ECOFF symbol- and string-table offsets. */
737	ecoff_symhdr_off = ep->f.f_symptr;
738
739	nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
740	stringtaboff = nextoff;
741	ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
742	    (ECOFF_SEGMENT_ALIGNMENT(ep)));
743
744
745	nextoff = stringtaboff + ecoff_strsize;
746	symtaboff = nextoff;
747	symtabsize = nsyms * sizeof(struct ecoff_extsym);
748	symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
749
750	/* Write out the symbol header ... */
751	write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
752	    stringtaboff, ecoffsymtab.stringsize);
753
754	/* Write out the string table... */
755	padding = ecoff_strsize - ecoffsymtab.stringsize;
756	safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
757	    "string table: write: %s\n");
758	if (padding)
759		pad16(out, padding, "string table: padding: %s\n");
760
761
762	/* Write out the symbol table... */
763	padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
764
765	for (i = 0; i < nsyms; i++) {
766		struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i];
767		es->es_flags	= bswap16(es->es_flags);
768		es->es_ifd	= bswap16(es->es_ifd);
769		bswap32_region(&es->es_strindex,
770		    sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd));
771	}
772	safewrite(out, ecoffsymtab.ecoff_syms,
773	    nsyms * sizeof(struct ecoff_extsym),
774	    "symbol table: write: %s\n");
775	if (padding)
776		pad16(out, padding, "symbols: padding: %s\n");
777}
778
779
780
781/*
782 * In-memory translation of ELF symbosl to ECOFF.
783 */
784void
785translate_syms(elfp, ecoffp)
786	struct elf_syms *elfp;
787	struct ecoff_syms *ecoffp;
788{
789
790	int     i;
791	char   *oldstringbase;
792	char   *newstrings, *nsp;
793
794	int     nsyms, idx;
795
796	nsyms = elfp->nsymbols;
797	oldstringbase = elfp->stringtab;
798
799	/* Allocate space for corresponding ECOFF symbols. */
800	memset(ecoffp, 0, sizeof(*ecoffp));
801
802	ecoffp->nsymbols = 0;
803	ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
804
805	/* we are going to be no bigger than the ELF symbol table. */
806	ecoffp->stringsize = elfp->stringsize;
807	ecoffp->stringtab = malloc(elfp->stringsize);
808
809	newstrings = (char *) ecoffp->stringtab;
810	nsp = (char *) ecoffp->stringtab;
811	if (!newstrings) {
812		fprintf(stderr, "No memory for new string table!\n");
813		exit(1);
814	}
815	/* Copy and translate  symbols... */
816	idx = 0;
817	for (i = 0; i < nsyms; i++) {
818		int     binding, type;
819
820		binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
821		type = ELF32_ST_TYPE((elfp->elf_syms[i].st_info));
822
823		/* skip strange symbols */
824		if (binding == 0) {
825			continue;
826		}
827		/* Copy the symbol into the new table */
828		strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
829		ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
830		nsp += strlen(nsp) + 1;
831
832		/* translate symbol types to ECOFF XXX */
833		ecoffp->ecoff_syms[idx].es_type = 1;
834		ecoffp->ecoff_syms[idx].es_class = 5;
835
836		/* Symbol values in executables should be compatible. */
837		ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
838		ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
839
840		idx++;
841	}
842
843	ecoffp->nsymbols = idx;
844	ecoffp->stringsize = nsp - newstrings;
845}
846/*
847 * pad to a 16-byte boundary
848 */
849void
850pad16(int fd, int size, const char *msg)
851{
852	safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
853}
854
855/* swap a 32bit region */
856void
857bswap32_region(u_int32_t* p, int len)
858{
859	int i;
860
861	for (i = 0; i < len / sizeof(u_int32_t); i++, p++)
862		*p = bswap32(*p);
863}
864