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