xref: /netbsd-src/usr.bin/elf2ecoff/elf2ecoff.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
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 
58 struct sect {
59 	unsigned long vaddr;
60 	unsigned long len;
61 };
62 
63 struct elf_syms {
64 	int     nsymbols;
65 	Elf32_Sym *elf_syms;
66 	off_t   stringsize;
67 	char   *stringtab;
68 };
69 
70 struct ecoff_syms {
71 	int     nsymbols;
72 	struct ecoff_extsym *ecoff_syms;
73 	off_t   stringsize;
74 	char   *stringtab;
75 };
76 
77 int     debug = 0;
78 
79 int     phcmp(Elf32_Phdr * h1, Elf32_Phdr * h2);
80 
81 
82 char   *saveRead(int file, off_t offset, off_t len, const char *name);
83 void    safewrite(int outfile, const void *buf, off_t len, const char *msg);
84 void    copy(int, int, off_t, off_t);
85 void    combine(struct sect * base, struct sect * new, int paddable);
86 void    translate_syms(struct elf_syms *, struct ecoff_syms *);
87 void	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	make_ecoff_section_hdrs(struct ecoff_exechdr * ep,
94 	    struct ecoff_scnhdr * esecs);
95 
96 void	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 
101 void    pad16(int fd, int size, const char *msg);
102 void	bswap32_region(int32_t* , int);
103 
104 int    *symTypeTable;
105 int	needswap;
106 
107 
108 
109 
110 void	elf_read_syms(struct elf_syms * elfsymsp, int infile,
111 	    off_t symoff, off_t symsize, off_t stroff, off_t strsize);
112 
113 
114 int
115 main(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) {
146 usage:
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 
484 void
485 copy(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. */
511 void
512 combine(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 
532 int
533 phcmp(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 
545 char *
546 saveRead(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 
569 void
570 safewrite(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  */
586 int
587 make_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  */
634 void
635 write_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 
672 void
673 elf_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  */
705 void
706 elf_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  */
773 void
774 translate_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  */
836 void
837 pad16(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 */
844 void
845 bswap32_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