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