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