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