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