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