xref: /netbsd-src/usr.bin/elf2ecoff/elf2ecoff.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: elf2ecoff.c,v 1.14 2000/03/13 23:22:51 soren 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.h>
46 #include <sys/exec_elf.h>
47 #include <sys/exec_aout.h>
48 #include <stdio.h>
49 #include <sys/exec_ecoff.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <limits.h>
53 
54 
55 #define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
56 
57 struct sect {
58 	unsigned long vaddr;
59 	unsigned long len;
60 };
61 
62 struct elf_syms {
63 	int     nsymbols;
64 	Elf32_Sym *elf_syms;
65 	off_t   stringsize;
66 	char   *stringtab;
67 };
68 
69 struct ecoff_syms {
70 	int     nsymbols;
71 	struct ecoff_extsym *ecoff_syms;
72 	off_t   stringsize;
73 	char   *stringtab;
74 };
75 
76 int     debug = 0;
77 
78 int     phcmp(Elf32_Phdr * h1, Elf32_Phdr * h2);
79 
80 
81 char   *saveRead(int file, off_t offset, off_t len, char *name);
82 void    safewrite(int outfile, void *buf, off_t len, const char *msg);
83 void    copy(int, int, off_t, off_t);
84 void    combine(struct sect * base, struct sect * new, int paddable);
85 void    translate_syms(struct elf_syms *, struct ecoff_syms *);
86 void
87 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 
93 int
94 make_ecoff_section_hdrs(struct ecoff_exechdr * ep,
95     struct ecoff_scnhdr * esecs);
96 
97 void
98 write_ecoff_symhdr(int outfile, struct ecoff_exechdr * ep,
99     struct ecoff_symhdr * symhdrp,
100     long nesyms, long extsymoff, long extstroff,
101     long strsize);
102 
103 void    pad16(int fd, int size, const char *msg);
104 
105 int    *symTypeTable;
106 
107 
108 
109 
110 void
111 elf_read_syms(struct elf_syms * elfsymsp, int infile,
112     off_t symoff, off_t symsize, off_t stroff, off_t strsize);
113 
114 
115 int
116 main(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 
136 	text.len = data.len = bss.len = 0;
137 	text.vaddr = data.vaddr = bss.vaddr = 0;
138 
139 	rdata.len = sdata.len = sbss.len = 0;
140 	rdata.vaddr = sdata.vaddr = sbss.vaddr = 0;
141 
142 	/* Check args... */
143 	if (argc < 3 || argc > 4) {
144 usage:
145 		fprintf(stderr,
146 		    "usage: elf2ecoff <elf executable> <ECOFF executable> [-s]\n");
147 		exit(1);
148 	}
149 	if (argc == 4) {
150 		if (strcmp(argv[3], "-s"))
151 			goto usage;
152 		symflag = 1;
153 	}
154 	/* Try the input file... */
155 	if ((infile = open(argv[1], O_RDONLY)) < 0) {
156 		fprintf(stderr, "Can't open %s for read: %s\n",
157 		    argv[1], strerror(errno));
158 		exit(1);
159 	}
160 	/* Read the header, which is at the beginning of the file... */
161 	i = read(infile, &ex, sizeof ex);
162 	if (i != sizeof ex) {
163 		fprintf(stderr, "ex: %s: %s.\n",
164 		    argv[1], i ? strerror(errno) : "End of file reached");
165 		exit(1);
166 	}
167 	/* Read the program headers... */
168 	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
169 	    ex.e_phnum * sizeof(Elf32_Phdr), "ph");
170 	/* Read the section headers... */
171 	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
172 	    ex.e_shnum * sizeof(Elf32_Shdr), "sh");
173 	/* Read in the section string table. */
174 	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
175 	    sh[ex.e_shstrndx].sh_size, "shstrtab");
176 	/* Read in the section string table. */
177 	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
178 	    sh[ex.e_shstrndx].sh_size, "shstrtab");
179 
180 
181 	/* Look for the symbol table and string table... Also map section
182 	 * indices to symbol types for a.out */
183 	symtabix = 0;
184 	strtabix = 0;
185 	for (i = 0; i < ex.e_shnum; i++) {
186 		char   *name = shstrtab + sh[i].sh_name;
187 		if (!strcmp(name, ".symtab"))
188 			symtabix = i;
189 		else
190 			if (!strcmp(name, ".strtab"))
191 				strtabix = i;
192 
193 	}
194 
195 	/* Figure out if we can cram the program header into an ECOFF
196 	 * header...  Basically, we can't handle anything but loadable
197 	 * segments, but we can ignore some kinds of segments.  We can't
198 	 * handle holes in the address space.  Segments may be out of order,
199 	 * so we sort them first. */
200 
201 	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr),
202 	    (int (*) (const void *, const void *)) phcmp);
203 
204 	for (i = 0; i < ex.e_phnum; i++) {
205 		/* Section types we can ignore... */
206 		if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
207 		    ph[i].p_type == PT_PHDR ||
208 		    ph[i].p_type == PT_MIPS_REGINFO) {
209 
210 			if (debug) {
211 				fprintf(stderr, "  skipping PH %d type %d flags 0x%x\n",
212 				    i, ph[i].p_type, ph[i].p_flags);
213 			}
214 			continue;
215 		}
216 		/* Section types we can't handle... */
217 		else
218 			if (ph[i].p_type != PT_LOAD) {
219 				fprintf(stderr, "Program header %d type %d can't be converted.\n",
220 				    i, ph[i].p_type);
221 				exit(1);
222 			}
223 		/* Writable (data) segment? */
224 		if (ph[i].p_flags & PF_W) {
225 			struct sect ndata, nbss;
226 
227 			ndata.vaddr = ph[i].p_vaddr;
228 			ndata.len = ph[i].p_filesz;
229 			nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
230 			nbss.len = ph[i].p_memsz - ph[i].p_filesz;
231 
232 			if (debug) {
233 				fprintf(stderr,
234 				    "  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);
235 			}
236 			combine(&data, &ndata, 0);
237 			combine(&bss, &nbss, 1);
238 		} else {
239 			struct sect ntxt;
240 
241 			ntxt.vaddr = ph[i].p_vaddr;
242 			ntxt.len = ph[i].p_filesz;
243 			if (debug) {
244 
245 				fprintf(stderr,
246 				    "  combinining PH %d type %d flags 0x%x with text, len = %ld\n",
247 				    i, ph[i].p_type, ph[i].p_flags, ntxt.len);
248 			}
249 			combine(&text, &ntxt, 0);
250 		}
251 		/* Remember the lowest segment start address. */
252 		if (ph[i].p_vaddr < cur_vma)
253 			cur_vma = ph[i].p_vaddr;
254 	}
255 
256 	/* Sections must be in order to be converted... */
257 	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
258 	    text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
259 		fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
260 		exit(1);
261 	}
262 	/* If there's a data section but no text section, then the loader
263 	 * combined everything into one section.   That needs to be the text
264 	 * section, so just make the data section zero length following text. */
265 	if (data.len && !text.len) {
266 		text = data;
267 		data.vaddr = text.vaddr + text.len;
268 		data.len = 0;
269 	}
270 	/* If there is a gap between text and data, we'll fill it when we copy
271 	 * the data, so update the length of the text segment as represented
272 	 * in a.out to reflect that, since a.out doesn't allow gaps in the
273 	 * program address space. */
274 	if (text.vaddr + text.len < data.vaddr)
275 		text.len = data.vaddr - text.vaddr;
276 
277 	/* We now have enough information to cons up an a.out header... */
278 	ep.a.magic = ECOFF_OMAGIC;
279 	ep.a.vstamp = 2 * 256 + 10;	/* compatible with version 2.10 */
280 	ep.a.tsize = text.len;
281 	ep.a.dsize = data.len;
282 	ep.a.bsize = bss.len;
283 	ep.a.entry = ex.e_entry;
284 	ep.a.text_start = text.vaddr;
285 	ep.a.data_start = data.vaddr;
286 	ep.a.bss_start = bss.vaddr;
287 	ep.a.gprmask = 0xf3fffffe;
288 	memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask);
289 	ep.a.gp_value = 0;	/* unused. */
290 
291 	ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
292 	ep.f.f_nscns = 6;
293 	ep.f.f_timdat = 0;	/* bogus */
294 	ep.f.f_symptr = 0;
295 	ep.f.f_nsyms = sizeof(struct ecoff_symhdr);
296 	ep.f.f_opthdr = sizeof ep.a;
297 	ep.f.f_flags = 0x100f;	/* Stripped, not sharable. */
298 
299 	memset(esecs, 0, sizeof(esecs));
300 
301 	/* Make  ECOFF section headers, with empty stubs for
302 	 * .rdata/.sdata/.sbss. */
303 	make_ecoff_section_hdrs(&ep, esecs);
304 
305 	nsecs = ep.f.f_nscns;
306 
307 	/* Make the output file... */
308 	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
309 		fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
310 		exit(1);
311 	}
312 	/* Truncate file... */
313 	if (ftruncate(outfile, 0)) {
314 		warn("ftruncate %s", argv[2]);
315 	}
316 	/* Write the headers... */
317 	safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write: %s\n");
318 	if (debug)
319 		fprintf(stderr, "wrote %d byte file header.\n", sizeof(ep.f));
320 
321 	safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write: %s\n");
322 	if (debug)
323 		fprintf(stderr, "wrote %d byte a.out header.\n", sizeof(ep.a));
324 
325 	safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs,
326 	    "esecs: write: %s\n");
327 	if (debug)
328 		fprintf(stderr, "wrote %d bytes of section headers.\n",
329 		    sizeof(esecs[0]) * nsecs);
330 
331 
332 	pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
333 	if (pad) {
334 		pad = 16 - pad;
335 		pad16(outfile, pad, "ipad: write: %s\n");
336 		if (debug)
337 			fprintf(stderr, "wrote %d byte pad.\n", pad);
338 	}
339 	/* Copy the loadable sections.   Zero-fill any gaps less than 64k;
340 	 * complain about any zero-filling, and die if we're asked to
341 	 * zero-fill more than 64k. */
342 	for (i = 0; i < ex.e_phnum; i++) {
343 		/* Unprocessable sections were handled above, so just verify
344 		 * that the section can be loaded before copying. */
345 		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
346 			if (cur_vma != ph[i].p_vaddr) {
347 				unsigned long gap = ph[i].p_vaddr - cur_vma;
348 				char    obuf[1024];
349 				if (gap > 65536) {
350 					fprintf(stderr, "Intersegment gap (%ld bytes) too large.\n",
351 					    gap);
352 					exit(1);
353 				}
354 				if (debug)
355 					fprintf(stderr, "Warning: %ld byte intersegment gap.\n", gap);
356 				memset(obuf, 0, sizeof obuf);
357 				while (gap) {
358 					int     count = write(outfile, obuf, (gap > sizeof obuf
359 						? sizeof obuf : gap));
360 					if (count < 0) {
361 						fprintf(stderr, "Error writing gap: %s\n",
362 						    strerror(errno));
363 						exit(1);
364 					}
365 					gap -= count;
366 				}
367 			}
368 			if (debug)
369 				fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
370 			copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
371 			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
372 		}
373 	}
374 
375 
376 	if (debug)
377 		fprintf(stderr, "writing syms at offset 0x%lx\n",
378 		    (u_long) ep.f.f_symptr + sizeof(symhdr));
379 
380 	/* Copy and translate the symbol table... */
381 	elf_symbol_table_to_ecoff(outfile, infile, &ep,
382 	    sh[symtabix].sh_offset, sh[symtabix].sh_size,
383 	    sh[strtabix].sh_offset, sh[strtabix].sh_size);
384 
385 	/*
386          * Write a page of padding for boot PROMS that read entire pages.
387          * Without this, they may attempt to read past the end of the
388          * data section, incur an error, and refuse to boot.
389          */
390 	{
391 		char    obuf[4096];
392 		memset(obuf, 0, sizeof obuf);
393 		if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
394 			fprintf(stderr, "Error writing PROM padding: %s\n",
395 			    strerror(errno));
396 			exit(1);
397 		}
398 	}
399 
400 	/* Looks like we won... */
401 	exit(0);
402 }
403 
404 void
405 copy(out, in, offset, size)
406 	int     out, in;
407 	off_t   offset, size;
408 {
409 	char    ibuf[4096];
410 	int     remaining, cur, count;
411 
412 	/* Go to the start of the ELF symbol table... */
413 	if (lseek(in, offset, SEEK_SET) < 0) {
414 		perror("copy: lseek");
415 		exit(1);
416 	}
417 	remaining = size;
418 	while (remaining) {
419 		cur = remaining;
420 		if (cur > sizeof ibuf)
421 			cur = sizeof ibuf;
422 		remaining -= cur;
423 		if ((count = read(in, ibuf, cur)) != cur) {
424 			fprintf(stderr, "copy: read: %s\n",
425 			    count ? strerror(errno) : "premature end of file");
426 			exit(1);
427 		}
428 		safewrite(out, ibuf, cur, "copy: write: %s\n");
429 	}
430 }
431 /* Combine two segments, which must be contiguous.   If pad is true, it's
432    okay for there to be padding between. */
433 void
434 combine(base, new, pad)
435 	struct sect *base, *new;
436 	int     pad;
437 {
438 	if (!base->len)
439 		*base = *new;
440 	else
441 		if (new->len) {
442 			if (base->vaddr + base->len != new->vaddr) {
443 				if (pad)
444 					base->len = new->vaddr - base->vaddr;
445 				else {
446 					fprintf(stderr,
447 					    "Non-contiguous data can't be converted.\n");
448 					exit(1);
449 				}
450 			}
451 			base->len += new->len;
452 		}
453 }
454 
455 int
456 phcmp(h1, h2)
457 	Elf32_Phdr *h1, *h2;
458 {
459 	if (h1->p_vaddr > h2->p_vaddr)
460 		return 1;
461 	else
462 		if (h1->p_vaddr < h2->p_vaddr)
463 			return -1;
464 		else
465 			return 0;
466 }
467 
468 char
469        *
470 saveRead(int file, off_t offset, off_t len, char *name)
471 {
472 	char   *tmp;
473 	int     count;
474 	off_t   off;
475 	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
476 		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
477 		exit(1);
478 	}
479 	if (!(tmp = (char *) malloc(len))) {
480 		fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, (long) len);
481 		exit(1);
482 	}
483 	count = read(file, tmp, len);
484 	if (count != len) {
485 		fprintf(stderr, "%s: read: %s.\n",
486 		    name, count ? strerror(errno) : "End of file reached");
487 		exit(1);
488 	}
489 	return tmp;
490 }
491 
492 void
493 safewrite(int outfile, void *buf, off_t len, const char *msg)
494 {
495 	int     written;
496 	written = write(outfile, (char *) buf, len);
497 	if (written != len) {
498 		fprintf(stderr, msg, strerror(errno));
499 		exit(1);
500 	}
501 }
502 
503 
504 /*
505  * Output only three ECOFF sections, corresponding to ELF psecs
506  * for text, data, and bss.
507  */
508 int
509 make_ecoff_section_hdrs(ep, esecs)
510 	struct ecoff_exechdr *ep;
511 	struct ecoff_scnhdr *esecs;
512 
513 {
514 	ep->f.f_nscns = 6;	/* XXX */
515 
516 	strcpy(esecs[0].s_name, ".text");
517 	strcpy(esecs[1].s_name, ".data");
518 	strcpy(esecs[2].s_name, ".bss");
519 
520 	esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
521 	esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
522 	esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
523 	esecs[0].s_size = ep->a.tsize;
524 	esecs[1].s_size = ep->a.dsize;
525 	esecs[2].s_size = ep->a.bsize;
526 
527 	esecs[0].s_scnptr = ECOFF_TXTOFF(ep);
528 	esecs[1].s_scnptr = ECOFF_DATOFF(ep);
529 #if 0
530 	esecs[2].s_scnptr = esecs[1].s_scnptr +
531 	    ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(ep));
532 #endif
533 
534 	esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
535 	esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
536 	esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
537 	esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
538 
539 	esecs[1].s_flags = 0x100;	/* ECOFF rdata */
540 	esecs[3].s_flags = 0x200;	/* ECOFF sdata */
541 	esecs[4].s_flags = 0x400;	/* ECOFF sbss */
542 
543 	/*
544 	 * Set the symbol-table offset  to point at the end of any
545 	 * sections we loaded above, so later code can use it to write
546 	 * symbol table info..
547 	 */
548 	ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
549 	return (ep->f.f_nscns);
550 }
551 
552 
553 /*
554  * Write the ECOFF symbol header.
555  * Guess at how big the symbol table will be.
556  * Mark all symbols as EXTERN (for now).
557  */
558 void
559 write_ecoff_symhdr(out, ep, symhdrp, nesyms, extsymoff, extstroff, strsize)
560 	int     out;
561 	struct ecoff_exechdr *ep;
562 	struct ecoff_symhdr *symhdrp;
563 	long    nesyms, extsymoff, extstroff, strsize;
564 {
565 	if (debug)
566 		fprintf(stderr, "writing symhdr for %ld entries at offset 0x%lx\n",
567 		    nesyms, (u_long) ep->f.f_symptr);
568 
569 	ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
570 
571 	memset(symhdrp, 0, sizeof(*symhdrp));
572 	symhdrp->esymMax = nesyms;
573 	symhdrp->magic = 0x7009;/* XXX */
574 	symhdrp->cbExtOffset = extsymoff;
575 	symhdrp->cbSsExtOffset = extstroff;
576 
577 	symhdrp->issExtMax = strsize;
578 	if (debug)
579 		fprintf(stderr,
580 		    "ECOFF symhdr: symhdr %x, strsize %lx, symsize %lx\n",
581 		    sizeof(*symhdrp), strsize,
582 		    (nesyms * sizeof(struct ecoff_extsym)));
583 
584 	safewrite(out, symhdrp, sizeof(*symhdrp),
585 	    "writing symbol header: %s\n");
586 }
587 
588 
589 void
590 elf_read_syms(elfsymsp, in, symoff, symsize, stroff, strsize)
591 	struct elf_syms *elfsymsp;
592 	int     in;
593 	off_t   symoff, symsize;
594 	off_t   stroff, strsize;
595 {
596 	register int nsyms;
597 	nsyms = symsize / sizeof(Elf32_Sym);
598 
599 	/* Suck in the ELF symbol list... */
600 	elfsymsp->elf_syms = (Elf32_Sym *)
601 	    saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
602 	    "ELF symboltable");
603 	elfsymsp->nsymbols = nsyms;
604 
605 	/* Suck in the ELF string table... */
606 	elfsymsp->stringtab = (char *)
607 	    saveRead(in, stroff, strsize, "ELF string table");
608 	elfsymsp->stringsize = strsize;
609 }
610 
611 
612 /*
613  *
614  */
615 void
616 elf_symbol_table_to_ecoff(out, in, ep, symoff, symsize, stroff, strsize)
617 	int     out, in;
618 	struct ecoff_exechdr *ep;
619 	off_t   symoff, symsize;
620 	off_t   stroff, strsize;
621 {
622 
623 	struct elf_syms elfsymtab;
624 	struct ecoff_syms ecoffsymtab;
625 	register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
626 	register u_long nextoff, symtabsize, ecoff_strsize;
627 	int     nsyms;
628 	struct ecoff_symhdr symhdr;
629 	int     padding;
630 
631 	/* Read in the ELF symbols. */
632 	elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
633 
634 	/* Approximate translation to ECOFF. */
635 	translate_syms(&elfsymtab, &ecoffsymtab);
636 	nsyms = ecoffsymtab.nsymbols;
637 
638 	/* Compute output ECOFF symbol- and string-table offsets. */
639 	ecoff_symhdr_off = ep->f.f_symptr;
640 
641 	nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
642 	stringtaboff = nextoff;
643 	ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
644 	    (ECOFF_SEGMENT_ALIGNMENT(ep)));
645 
646 
647 	nextoff = stringtaboff + ecoff_strsize;
648 	symtaboff = nextoff;
649 	symtabsize = nsyms * sizeof(struct ecoff_extsym);
650 	symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
651 
652 	/* Write out the symbol header ... */
653 	write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
654 	    stringtaboff, ecoffsymtab.stringsize);
655 
656 	/* Write out the string table... */
657 	padding = ecoff_strsize - ecoffsymtab.stringsize;
658 	safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
659 	    "string table: write: %s\n");
660 	if (padding)
661 		pad16(out, padding, "string table: padding: %s\n");
662 
663 
664 	/* Write out the symbol table... */
665 	padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
666 	safewrite(out, ecoffsymtab.ecoff_syms,
667 	    nsyms * sizeof(struct ecoff_extsym),
668 	    "symbol table: write: %s\n");
669 	if (padding)
670 		pad16(out, padding, "symbols: padding: %s\n");
671 }
672 
673 
674 
675 /*
676  * In-memory translation of ELF symbosl to ECOFF.
677  */
678 void
679 translate_syms(elfp, ecoffp)
680 	struct elf_syms *elfp;
681 	struct ecoff_syms *ecoffp;
682 {
683 
684 	int     i;
685 	char   *oldstringbase;
686 	char   *newstrings, *nsp;
687 
688 	int     nsyms, idx;
689 
690 	nsyms = elfp->nsymbols;
691 	oldstringbase = elfp->stringtab;
692 
693 	/* Allocate space for corresponding ECOFF symbols. */
694 	memset(ecoffp, 0, sizeof(*ecoffp));
695 
696 	ecoffp->nsymbols = 0;
697 	ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
698 
699 	/* we are going to be no bigger than the ELF symbol table. */
700 	ecoffp->stringsize = elfp->stringsize;
701 	ecoffp->stringtab = malloc(elfp->stringsize);
702 
703 	newstrings = (char *) ecoffp->stringtab;
704 	nsp = (char *) ecoffp->stringtab;
705 	if (!newstrings) {
706 		fprintf(stderr, "No memory for new string table!\n");
707 		exit(1);
708 	}
709 	/* Copy and translate  symbols... */
710 	idx = 0;
711 	for (i = 0; i < nsyms; i++) {
712 		int     binding, type;
713 
714 		binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
715 		type = ELF32_ST_TYPE((elfp->elf_syms[i].st_info));
716 
717 		/* skip strange symbols */
718 		if (binding == 0) {
719 			continue;
720 		}
721 		/* Copy the symbol into the new table */
722 		strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
723 		ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
724 		nsp += strlen(nsp) + 1;
725 
726 		/* translate symbol types to ECOFF XXX */
727 		ecoffp->ecoff_syms[idx].es_type = 1;
728 		ecoffp->ecoff_syms[idx].es_class = 5;
729 
730 		/* Symbol values in executables should be compatible. */
731 		ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
732 		ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
733 
734 		idx++;
735 	}
736 
737 	ecoffp->nsymbols = idx;
738 	ecoffp->stringsize = nsp - newstrings;
739 }
740 /*
741  * pad to a 16-byte boundary
742  */
743 void
744 pad16(int fd, int size, const char *msg)
745 {
746 	safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
747 }
748