xref: /netbsd-src/usr.bin/elf2aout/elf2aout.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: elf2aout.c,v 1.15 2011/07/10 05:07:48 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 1995
5  *	Ted Lemon (hereinafter referred to as the author)
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /* elf2aout.c
32 
33    This program converts an elf executable to a NetBSD a.out executable.
34    The minimal symbol table is copied, but the debugging symbols and
35    other informational sections are not. */
36 
37 #if HAVE_NBTOOL_CONFIG_H
38 #include "nbtool_config.h"
39 #endif
40 
41 #ifndef TARGET_BYTE_ORDER
42 #define TARGET_BYTE_ORDER	BYTE_ORDER
43 #endif
44 
45 #include <sys/types.h>
46 #include <sys/exec_aout.h>
47 #include <sys/exec_elf.h>
48 
49 #include <a.out.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <limits.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 
60 struct sect {
61 	/* should be unsigned long, but assume no a.out binaries on LP64 */
62 	uint32_t vaddr;
63 	uint32_t len;
64 };
65 
66 void	combine(struct sect *, struct sect *, int);
67 int	phcmp(const void *, const void *);
68 char   *saveRead(int file, off_t offset, off_t len, const char *name);
69 void	copy(int, int, off_t, off_t);
70 void	translate_syms(int, int, off_t, off_t, off_t, off_t);
71 
72 #if TARGET_BYTE_ORDER != BYTE_ORDER
73 void	bswap32_region(int32_t* , int);
74 #endif
75 
76 int    *symTypeTable;
77 
78 int
79 main(int argc, char **argv)
80 {
81 	Elf32_Ehdr ex;
82 	Elf32_Phdr *ph;
83 	Elf32_Shdr *sh;
84 	char   *shstrtab;
85 	int     strtabix, symtabix;
86 	int     i;
87 	struct sect text, data, bss;
88 	struct exec aex;
89 	int     infile, outfile;
90 	uint32_t cur_vma = UINT32_MAX;
91 	uint32_t mid;
92 	int     symflag = 0;
93 
94 	strtabix = symtabix = 0;
95 	text.len = data.len = bss.len = 0;
96 	text.vaddr = data.vaddr = bss.vaddr = 0;
97 
98 	/* Check args... */
99 	if (argc < 3 || argc > 4) {
100 usage:
101 		fprintf(stderr,
102 		    "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
103 		exit(1);
104 	}
105 	if (argc == 4) {
106 		if (strcmp(argv[3], "-s"))
107 			goto usage;
108 		symflag = 1;
109 	}
110 	/* Try the input file... */
111 	if ((infile = open(argv[1], O_RDONLY)) < 0) {
112 		fprintf(stderr, "Can't open %s for read: %s\n",
113 		    argv[1], strerror(errno));
114 		exit(1);
115 	}
116 	/* Read the header, which is at the beginning of the file... */
117 	i = read(infile, &ex, sizeof ex);
118 	if (i != sizeof ex) {
119 		fprintf(stderr, "ex: %s: %s.\n",
120 		    argv[1], i ? strerror(errno) : "End of file reached");
121 		exit(1);
122 	}
123 #if TARGET_BYTE_ORDER != BYTE_ORDER
124 	ex.e_type	= bswap16(ex.e_type);
125 	ex.e_machine	= bswap16(ex.e_machine);
126 	ex.e_version	= bswap32(ex.e_version);
127 	ex.e_entry 	= bswap32(ex.e_entry);
128 	ex.e_phoff	= bswap32(ex.e_phoff);
129 	ex.e_shoff	= bswap32(ex.e_shoff);
130 	ex.e_flags	= bswap32(ex.e_flags);
131 	ex.e_ehsize	= bswap16(ex.e_ehsize);
132 	ex.e_phentsize	= bswap16(ex.e_phentsize);
133 	ex.e_phnum	= bswap16(ex.e_phnum);
134 	ex.e_shentsize	= bswap16(ex.e_shentsize);
135 	ex.e_shnum	= bswap16(ex.e_shnum);
136 	ex.e_shstrndx	= bswap16(ex.e_shstrndx);
137 #endif
138 	/* Read the program headers... */
139 	ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
140 	    ex.e_phnum * sizeof(Elf32_Phdr), "ph");
141 #if TARGET_BYTE_ORDER != BYTE_ORDER
142 	bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
143 #endif
144 	/* Read the section headers... */
145 	sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
146 	    ex.e_shnum * sizeof(Elf32_Shdr), "sh");
147 #if TARGET_BYTE_ORDER != BYTE_ORDER
148 	bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
149 #endif
150 	/* Read in the section string table. */
151 	shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
152 	    sh[ex.e_shstrndx].sh_size, "shstrtab");
153 
154 	/* Find space for a table matching ELF section indices to a.out symbol
155 	 * types. */
156 	symTypeTable = malloc(ex.e_shnum * sizeof(int));
157 	if (symTypeTable == NULL) {
158 		fprintf(stderr, "symTypeTable: can't allocate.\n");
159 		exit(1);
160 	}
161 	memset(symTypeTable, 0, ex.e_shnum * sizeof(int));
162 
163 	/* Look for the symbol table and string table... Also map section
164 	 * indices to symbol types for a.out */
165 	for (i = 0; i < ex.e_shnum; i++) {
166 		char   *name = shstrtab + sh[i].sh_name;
167 		if (!strcmp(name, ".symtab"))
168 			symtabix = i;
169 		else
170 			if (!strcmp(name, ".strtab"))
171 				strtabix = i;
172 			else
173 				if (!strcmp(name, ".text") || !strcmp(name, ".rodata"))
174 					symTypeTable[i] = N_TEXT;
175 				else
176 					if (!strcmp(name, ".data") || !strcmp(name, ".sdata") ||
177 					    !strcmp(name, ".lit4") || !strcmp(name, ".lit8"))
178 						symTypeTable[i] = N_DATA;
179 					else
180 						if (!strcmp(name, ".bss") || !strcmp(name, ".sbss"))
181 							symTypeTable[i] = N_BSS;
182 	}
183 
184 	/* Figure out if we can cram the program header into an a.out
185 	 * header... Basically, we can't handle anything but loadable
186 	 * segments, but we can ignore some kinds of segments.   We can't
187 	 * handle holes in the address space, and we handle start addresses
188 	 * other than 0x1000 by hoping that the loader will know where to load
189 	 * - a.out doesn't have an explicit load address.   Segments may be
190 	 * out of order, so we sort them first. */
191 	qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
192 	for (i = 0; i < ex.e_phnum; i++) {
193 		/* Section types we can ignore... */
194 		if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
195 		    ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
196 			continue;
197 		/* Section types we can't handle... */
198 		else
199 			if (ph[i].p_type != PT_LOAD)
200 				errx(1, "Program header %d type %d can't be converted.", i, ph[i].p_type);
201 		/* Writable (data) segment? */
202 		if (ph[i].p_flags & PF_W) {
203 			struct sect ndata, nbss;
204 
205 			ndata.vaddr = ph[i].p_vaddr;
206 			ndata.len = ph[i].p_filesz;
207 			nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
208 			nbss.len = ph[i].p_memsz - ph[i].p_filesz;
209 
210 			combine(&data, &ndata, 0);
211 			combine(&bss, &nbss, 1);
212 		} else {
213 			struct sect ntxt;
214 
215 			ntxt.vaddr = ph[i].p_vaddr;
216 			ntxt.len = ph[i].p_filesz;
217 
218 			combine(&text, &ntxt, 0);
219 		}
220 		/* Remember the lowest segment start address. */
221 		if (ph[i].p_vaddr < cur_vma)
222 			cur_vma = ph[i].p_vaddr;
223 	}
224 
225 	/* Sections must be in order to be converted... */
226 	if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
227 	    text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
228 		fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
229 		exit(1);
230 	}
231 	/* If there's a data section but no text section, then the loader
232 	 * combined everything into one section.   That needs to be the text
233 	 * section, so just make the data section zero length following text. */
234 	if (data.len && text.len == 0) {
235 		text = data;
236 		data.vaddr = text.vaddr + text.len;
237 		data.len = 0;
238 	}
239 	/* If there is a gap between text and data, we'll fill it when we copy
240 	 * the data, so update the length of the text segment as represented
241 	 * in a.out to reflect that, since a.out doesn't allow gaps in the
242 	 * program address space. */
243 	if (text.vaddr + text.len < data.vaddr)
244 		text.len = data.vaddr - text.vaddr;
245 
246 	/* We now have enough information to cons up an a.out header... */
247 	switch (ex.e_machine) {
248 	case EM_SPARC:
249 		mid = MID_SPARC;
250 		break;
251 	case EM_386:
252 		mid = MID_PC386;
253 		break;
254 	case EM_68K:
255 		mid = MID_M68K;
256 		break;
257 	case EM_MIPS:
258 		if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
259 			mid = MID_PMAX;
260 		else
261 			mid = MID_MIPS;
262 		break;
263 	case EM_PPC:
264 		mid = MID_POWERPC;
265 		break;
266 	case EM_ARM:
267 		mid = MID_ARM6;
268 		break;
269 	case EM_VAX:
270 		mid = MID_VAX;
271 		break;
272 	case EM_NONE:
273 	default:
274 		mid = MID_ZERO;
275 	}
276 	aex.a_midmag = htonl((symflag << 26) | (mid << 16) | OMAGIC);
277 
278 	aex.a_text = text.len;
279 	aex.a_data = data.len;
280 	aex.a_bss = bss.len;
281 	aex.a_entry = ex.e_entry;
282 	aex.a_syms = (sizeof(struct nlist) *
283 	    (symtabix != -1
284 		? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0));
285 	aex.a_trsize = 0;
286 	aex.a_drsize = 0;
287 #if TARGET_BYTE_ORDER != BYTE_ORDER
288 	aex.a_text = bswap32(aex.a_text);
289 	aex.a_data = bswap32(aex.a_data);
290 	aex.a_bss = bswap32(aex.a_bss);
291 	aex.a_entry = bswap32(aex.a_entry);
292 	aex.a_syms = bswap32(aex.a_syms);
293 	aex.a_trsize = bswap32(aex.a_trsize);
294 	aex.a_drsize = bswap32(aex.a_drsize);
295 #endif
296 
297 	/* Make the output file... */
298 	if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
299 		fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
300 		exit(1);
301 	}
302 	/* Truncate file... */
303 	if (ftruncate(outfile, 0)) {
304 		warn("ftruncate %s", argv[2]);
305 	}
306 	/* Write the header... */
307 	i = write(outfile, &aex, sizeof aex);
308 	if (i != sizeof aex) {
309 		perror("aex: write");
310 		exit(1);
311 	}
312 	/* Copy the loadable sections.   Zero-fill any gaps less than 64k;
313 	 * complain about any zero-filling, and die if we're asked to
314 	 * zero-fill more than 64k. */
315 	for (i = 0; i < ex.e_phnum; i++) {
316 		/* Unprocessable sections were handled above, so just verify
317 		 * that the section can be loaded before copying. */
318 		if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
319 			if (cur_vma != ph[i].p_vaddr) {
320 				uint32_t gap = ph[i].p_vaddr - cur_vma;
321 				char    obuf[1024];
322 				if (gap > 65536)
323 					errx(1,
324 			"Intersegment gap (%ld bytes) too large.", (long) gap);
325 #ifdef DEBUG
326 				warnx("Warning: %ld byte intersegment gap.",
327 				    (long)gap);
328 #endif
329 				memset(obuf, 0, sizeof obuf);
330 				while (gap) {
331 					int     count = write(outfile, obuf, (gap > sizeof obuf
332 						? sizeof obuf : gap));
333 					if (count < 0) {
334 						fprintf(stderr, "Error writing gap: %s\n",
335 						    strerror(errno));
336 						exit(1);
337 					}
338 					gap -= count;
339 				}
340 			}
341 			copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
342 			cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
343 		}
344 	}
345 
346 	/* Copy and translate the symbol table... */
347 	translate_syms(outfile, infile,
348 	    sh[symtabix].sh_offset, sh[symtabix].sh_size,
349 	    sh[strtabix].sh_offset, sh[strtabix].sh_size);
350 
351 	/* Looks like we won... */
352 	exit(0);
353 }
354 /* translate_syms (out, in, offset, size)
355 
356    Read the ELF symbol table from in at offset; translate it into a.out
357    nlist format and write it to out. */
358 
359 void
360 translate_syms(int out, int in, off_t symoff, off_t symsize,
361     off_t stroff, off_t strsize)
362 {
363 #define SYMS_PER_PASS	64
364 	Elf32_Sym inbuf[64];
365 	struct nlist outbuf[64];
366 	int     i, remaining, cur;
367 	char   *oldstrings;
368 	char   *newstrings, *nsp;
369 	int     newstringsize, stringsizebuf;
370 
371 	/* Zero the unused fields in the output buffer.. */
372 	memset(outbuf, 0, sizeof outbuf);
373 
374 	/* Find number of symbols to process... */
375 	remaining = symsize / sizeof(Elf32_Sym);
376 
377 	/* Suck in the old string table... */
378 	oldstrings = saveRead(in, stroff, strsize, "string table");
379 
380 	/* Allocate space for the new one.   XXX We make the wild assumption
381 	 * that no two symbol table entries will point at the same place in
382 	 * the string table - if that assumption is bad, this could easily
383 	 * blow up. */
384 	newstringsize = strsize + remaining;
385 	newstrings = malloc(newstringsize);
386 	if (newstrings == NULL) {
387 		fprintf(stderr, "No memory for new string table!\n");
388 		exit(1);
389 	}
390 	/* Initialize the table pointer... */
391 	nsp = newstrings;
392 
393 	/* Go the start of the ELF symbol table... */
394 	if (lseek(in, symoff, SEEK_SET) < 0) {
395 		perror("translate_syms: lseek");
396 		exit(1);
397 	}
398 	/* Translate and copy symbols... */
399 	while (remaining) {
400 		cur = remaining;
401 		if (cur > SYMS_PER_PASS)
402 			cur = SYMS_PER_PASS;
403 		remaining -= cur;
404 		if ((i = read(in, inbuf, cur * sizeof(Elf32_Sym)))
405 		    != cur * (ssize_t)sizeof(Elf32_Sym)) {
406 			if (i < 0)
407 				perror("translate_syms");
408 			else
409 				fprintf(stderr, "translate_syms: premature end of file.\n");
410 			exit(1);
411 		}
412 		/* Do the translation... */
413 		for (i = 0; i < cur; i++) {
414 			int     binding, type;
415 
416 #if TARGET_BYTE_ORDER != BYTE_ORDER
417 			inbuf[i].st_name  = bswap32(inbuf[i].st_name);
418 			inbuf[i].st_value = bswap32(inbuf[i].st_value);
419 			inbuf[i].st_size  = bswap32(inbuf[i].st_size);
420 			inbuf[i].st_shndx = bswap16(inbuf[i].st_shndx);
421 #endif
422 			/* Copy the symbol into the new table, but prepend an
423 			 * underscore. */
424 			*nsp = '_';
425 			strcpy(nsp + 1, oldstrings + inbuf[i].st_name);
426 			outbuf[i].n_un.n_strx = nsp - newstrings + 4;
427 			nsp += strlen(nsp) + 1;
428 
429 			type = ELF32_ST_TYPE(inbuf[i].st_info);
430 			binding = ELF32_ST_BIND(inbuf[i].st_info);
431 
432 			/* Convert ELF symbol type/section/etc info into a.out
433 			 * type info. */
434 			if (type == STT_FILE)
435 				outbuf[i].n_type = N_FN;
436 			else
437 				if (inbuf[i].st_shndx == SHN_UNDEF)
438 					outbuf[i].n_type = N_UNDF;
439 				else
440 					if (inbuf[i].st_shndx == SHN_ABS)
441 						outbuf[i].n_type = N_ABS;
442 					else
443 						if (inbuf[i].st_shndx == SHN_COMMON ||
444 						    inbuf[i].st_shndx == SHN_MIPS_ACOMMON)
445 							outbuf[i].n_type = N_COMM;
446 						else
447 							outbuf[i].n_type = symTypeTable[inbuf[i].st_shndx];
448 			if (binding == STB_GLOBAL)
449 				outbuf[i].n_type |= N_EXT;
450 			/* Symbol values in executables should be compatible. */
451 			outbuf[i].n_value = inbuf[i].st_value;
452 #if TARGET_BYTE_ORDER != BYTE_ORDER
453 			outbuf[i].n_un.n_strx = bswap32(outbuf[i].n_un.n_strx);
454 			outbuf[i].n_desc      = bswap16(outbuf[i].n_desc);
455 			outbuf[i].n_value     = bswap32(outbuf[i].n_value);
456 #endif
457 		}
458 		/* Write out the symbols... */
459 		if ((i = write(out, outbuf, cur * sizeof(struct nlist)))
460 		    != cur * (ssize_t)sizeof(struct nlist)) {
461 			fprintf(stderr, "translate_syms: write: %s\n", strerror(errno));
462 			exit(1);
463 		}
464 	}
465 	/* Write out the string table length... */
466 	stringsizebuf = newstringsize;
467 #if TARGET_BYTE_ORDER != BYTE_ORDER
468 	stringsizebuf = bswap32(stringsizebuf);
469 #endif
470 	if (write(out, &stringsizebuf, sizeof stringsizebuf)
471 	    != sizeof stringsizebuf) {
472 		fprintf(stderr,
473 		    "translate_syms: newstringsize: %s\n", strerror(errno));
474 		exit(1);
475 	}
476 	/* Write out the string table... */
477 	if (write(out, newstrings, newstringsize) != newstringsize) {
478 		fprintf(stderr, "translate_syms: newstrings: %s\n", strerror(errno));
479 		exit(1);
480 	}
481 }
482 
483 void
484 copy(int out, int in, off_t offset, off_t size)
485 {
486 	char    ibuf[4096];
487 	int     remaining, cur, count;
488 
489 	/* Go to the start of the ELF symbol table... */
490 	if (lseek(in, offset, SEEK_SET) < 0) {
491 		perror("copy: lseek");
492 		exit(1);
493 	}
494 	remaining = size;
495 	while (remaining) {
496 		cur = remaining;
497 		if (cur > (int)sizeof ibuf)
498 			cur = sizeof ibuf;
499 		remaining -= cur;
500 		if ((count = read(in, ibuf, cur)) != cur) {
501 			fprintf(stderr, "copy: read: %s\n",
502 			    count ? strerror(errno) : "premature end of file");
503 			exit(1);
504 		}
505 		if ((count = write(out, ibuf, cur)) != cur) {
506 			perror("copy: write");
507 			exit(1);
508 		}
509 	}
510 }
511 /* Combine two segments, which must be contiguous.   If pad is true, it's
512    okay for there to be padding between. */
513 void
514 combine(struct sect *base, struct sect *new, int pad)
515 {
516 
517 	if (base->len == 0)
518 		*base = *new;
519 	else
520 		if (new->len) {
521 			if (base->vaddr + base->len != new->vaddr) {
522 				if (pad)
523 					base->len = new->vaddr - base->vaddr;
524 				else {
525 					fprintf(stderr,
526 					    "Non-contiguous data can't be converted.\n");
527 					exit(1);
528 				}
529 			}
530 			base->len += new->len;
531 		}
532 }
533 
534 int
535 phcmp(const void *vh1, const void *vh2)
536 {
537 	const Elf32_Phdr *h1, *h2;
538 
539 	h1 = (const Elf32_Phdr *)vh1;
540 	h2 = (const Elf32_Phdr *)vh2;
541 
542 	if (h1->p_vaddr > h2->p_vaddr)
543 		return 1;
544 	else
545 		if (h1->p_vaddr < h2->p_vaddr)
546 			return -1;
547 		else
548 			return 0;
549 }
550 
551 char *
552 saveRead(int file, off_t offset, off_t len, const char *name)
553 {
554 	char   *tmp;
555 	int     count;
556 	off_t   off;
557 	if ((off = lseek(file, offset, SEEK_SET)) < 0) {
558 		fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
559 		exit(1);
560 	}
561 	if ((tmp = malloc(len)) == NULL)
562 		errx(1, "%s: Can't allocate %ld bytes.", name, (long)len);
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 
572 #if TARGET_BYTE_ORDER != BYTE_ORDER
573 /* swap a 32bit region */
574 void
575 bswap32_region(int32_t* p, int len)
576 {
577 	size_t i;
578 
579 	for (i = 0; i < len / sizeof(int32_t); i++, p++)
580 		*p = bswap32(*p);
581 }
582 #endif
583