Annotation of src/usr.bin/elf2ecoff/elf2ecoff.c, Revision 1.5
1.5 ! henning 1: /* $OpenBSD: elf2ecoff.c,v 1.4 2003/06/10 22:20:46 deraadt Exp $ */
1.3 deraadt 2: /* $NetBSD: elf2ecoff.c,v 1.8 1997/07/20 03:50:54 jonathan Exp $ */
1.2 maja 3:
1.1 pefo 4: /*
1.2 maja 5: * Copyright (c) 1997 Jonathan Stone
6: * All rights reserved.
1.1 pefo 7: * Copyright (c) 1995
8: * Ted Lemon (hereinafter referred to as the author)
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
1.3 deraadt 34: /*
35: * elf2ecoff.c
36: *
37: * This program converts an elf executable to an ECOFF executable. No symbol
38: * table is retained. This is useful primarily in building net-bootable
39: * kernels for machines (e.g., DECstation and Alpha) which only support the
40: * ECOFF object file format.
41: */
1.2 maja 42:
1.1 pefo 43: #include <sys/types.h>
44: #include <fcntl.h>
45: #include <unistd.h>
46: #include <elf_abi.h>
47: #include <machine/elf_abi.h>
48: #include <stdio.h>
49: #include <sys/exec_ecoff.h>
50: #include <sys/errno.h>
51: #include <string.h>
52: #include <limits.h>
53:
1.3 deraadt 54: extern char *__progname;
1.1 pefo 55:
56: struct sect {
1.3 deraadt 57: unsigned long vaddr;
58: unsigned long len;
1.1 pefo 59: };
60:
1.3 deraadt 61: int phcmp();
62: char *saveRead(int file, off_t offset, off_t len, char *name);
63: int copy(int, int, off_t, off_t);
64: int translate_syms(int, int, off_t, off_t, off_t, off_t);
65: int *symTypeTable;
1.1 pefo 66:
1.3 deraadt 67: int
68: main(int argc, char *argv[])
1.1 pefo 69: {
1.3 deraadt 70: Elf32_Ehdr ex;
71: Elf32_Phdr *ph;
72: Elf32_Shdr *sh;
73: struct sym *symtab;
74: char *shstrtab;
75: int strtabix, symtabix;
76: int i, pad;
77: struct sect text, data, bss;
78: struct ecoff_exechdr eh;
79: struct ecoff_scnhdr esecs[3];
80: int infile, outfile;
81: unsigned long cur_vma = ULONG_MAX;
82:
83: text.len = data.len = bss.len = 0;
84: text.vaddr = data.vaddr = bss.vaddr = 0;
85:
86: /* Check args... */
87: if (argc < 3 || argc > 4) {
88: usage:
89: fprintf(stderr,
90: "usage: %s <elf executable> <ecoff executable>\n", __progname);
91: exit(1);
92: }
93: /* Try the input file... */
94: if ((infile = open(argv[1], O_RDONLY)) < 0) {
95: fprintf(stderr, "Can't open %s for read: %s\n",
96: argv[1], strerror(errno));
97: exit(1);
98: }
99: /* Read the header, which is at the beginning of the file... */
100: i = read(infile, &ex, sizeof ex);
101: if (i != sizeof ex) {
102: fprintf(stderr, "ex: %s: %s.\n",
103: argv[1], i ? strerror(errno) : "End of file reached");
104: exit(1);
105: }
106: /* Read the program headers... */
107: ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
108: ex.e_phnum * sizeof(Elf32_Phdr), "ph");
109: /* Read the section headers... */
110: sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
111: ex.e_shnum * sizeof(Elf32_Shdr), "sh");
112: /* Read in the section string table. */
113: shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
114: sh[ex.e_shstrndx].sh_size, "shstrtab");
115:
116: /*
117: * Figure out if we can cram the program header into an ECOFF
118: * header... Basically, we can't handle anything but loadable
119: * segments, but we can ignore some kinds of segments. We can't
120: * handle holes in the address space. Segments may be out of order,
121: * so we sort them first.
122: */
123:
124: qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
125:
126: for (i = 0; i < ex.e_phnum; i++) {
127: /* Section types we can ignore... */
128: if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
129: ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
130: continue;
131: /* Section types we can't handle... */
132: else if (ph[i].p_type != PT_LOAD) {
133: fprintf(stderr,
1.5 ! henning 134: "Program header %d type %d can't be converted.\n",
! 135: i, ph[i].p_type);
1.3 deraadt 136: exit(1);
137: }
138: /* Writable (data) segment? */
139: if (ph[i].p_flags & PF_W) {
140: struct sect ndata, nbss;
141:
142: ndata.vaddr = ph[i].p_vaddr;
143: ndata.len = ph[i].p_filesz;
144: nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
145: nbss.len = ph[i].p_memsz - ph[i].p_filesz;
146:
147: combine(&data, &ndata, 0);
148: combine(&bss, &nbss, 1);
149: } else {
150: struct sect ntxt;
151:
152: ntxt.vaddr = ph[i].p_vaddr;
153: ntxt.len = ph[i].p_filesz;
154: combine(&text, &ntxt);
155: }
156: /* Remember the lowest segment start address. */
157: if (ph[i].p_vaddr < cur_vma)
158: cur_vma = ph[i].p_vaddr;
1.1 pefo 159: }
160:
1.3 deraadt 161: /* Sections must be in order to be converted... */
162: if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
163: text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
164: fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
165: exit(1);
166: }
167: /*
168: * If there's a data section but no text section, then the loader
169: * combined everything into one section. That needs to be the text
170: * section, so just make the data section zero length following text.
171: */
172: if (data.len && !text.len) {
173: text = data;
174: data.vaddr = text.vaddr + text.len;
175: data.len = 0;
176: }
177: /*
178: * If there is a gap between text and data, we'll fill it when we
179: * copy the data, so update the length of the text segment as
180: * represented in a.out to reflect that, since a.out doesn't allow
181: * gaps in the program address space.
182: */
183: if (text.vaddr + text.len < data.vaddr)
184: text.len = data.vaddr - text.vaddr;
185:
186: /* We now have enough information to cons up an a.out header... */
187: eh.a.magic = ECOFF_OMAGIC;
188: eh.a.vstamp = 200;
189: eh.a.tsize = text.len;
190: eh.a.dsize = data.len;
191: eh.a.bsize = bss.len;
192: eh.a.entry = ex.e_entry;
193: eh.a.text_start = text.vaddr;
194: eh.a.data_start = data.vaddr;
195: eh.a.bss_start = bss.vaddr;
196: eh.a.ea_gprmask = 0xf3fffffe;
197: bzero(&eh.a.ea_cprmask, sizeof eh.a.ea_cprmask);
198: eh.a.ea_gp_value = 0; /* unused. */
199:
200: eh.f.f_magic = ECOFF_MAGIC_MIPSEL;
201: eh.f.f_nscns = 3;
202: eh.f.f_timdat = 0; /* bogus */
203: eh.f.f_symptr = 0;
204: eh.f.f_nsyms = 0;
205: eh.f.f_opthdr = sizeof eh.a;
206: eh.f.f_flags = 0x100f; /* Stripped, not sharable. */
207:
208: strlcpy(esecs[0].s_name, ".text", sizeof(esecs[0].s_name));
209: strlcpy(esecs[1].s_name, ".data", sizeof(esecs[0].s_name));
210: strlcpy(esecs[2].s_name, ".bss", sizeof(esecs[0].s_name));
211: esecs[0].s_paddr = esecs[0].s_vaddr = eh.a.text_start;
212: esecs[1].s_paddr = esecs[1].s_vaddr = eh.a.data_start;
213: esecs[2].s_paddr = esecs[2].s_vaddr = eh.a.bss_start;
214: esecs[0].s_size = eh.a.tsize;
215: esecs[1].s_size = eh.a.dsize;
216: esecs[2].s_size = eh.a.bsize;
217: esecs[0].s_scnptr = ECOFF_TXTOFF(&eh);
218: esecs[1].s_scnptr = ECOFF_DATOFF(&eh);
219: esecs[2].s_scnptr = esecs[1].s_scnptr +
220: ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eh));
221: esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
222: esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
223: esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
224: esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
225: esecs[0].s_flags = 0x20;
226: esecs[1].s_flags = 0x40;
227: esecs[2].s_flags = 0x82;
228:
229: /* Make the output file... */
230: if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
231: fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
232: exit(1);
233: }
234: /* Write the headers... */
235: i = write(outfile, &eh.f, sizeof(struct ecoff_filehdr));
236: if (i != sizeof(struct ecoff_filehdr)) {
237: perror("efh: write");
238: exit(1);
239:
240: for (i = 0; i < 6; i++) {
241: printf("Section %d: %s phys %x size %x file offset %x\n",
242: i, esecs[i].s_name, esecs[i].s_paddr,
243: esecs[i].s_size, esecs[i].s_scnptr);
244: }
245: }
246: fprintf(stderr, "wrote %d byte file header.\n", i);
1.1 pefo 247:
1.3 deraadt 248: i = write(outfile, &eh.a, sizeof(struct ecoff_aouthdr));
249: if (i != sizeof(struct ecoff_aouthdr)) {
250: perror("eah: write");
251: exit(1);
1.1 pefo 252: }
1.3 deraadt 253: fprintf(stderr, "wrote %d byte a.out header.\n", i);
1.1 pefo 254:
1.3 deraadt 255: i = write(outfile, &esecs, sizeof esecs);
256: if (i != sizeof esecs) {
257: perror("esecs: write");
258: exit(1);
259: }
260: fprintf(stderr, "wrote %d bytes of section headers.\n", i);
1.1 pefo 261:
1.3 deraadt 262: if (pad = ((sizeof eh + sizeof esecs) & 15)) {
263: pad = 16 - pad;
264: i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
265: if (i < 0) {
266: perror("ipad: write");
267: exit(1);
268: }
269: fprintf(stderr, "wrote %d byte pad.\n", i);
1.1 pefo 270: }
1.3 deraadt 271: /*
272: * Copy the loadable sections. Zero-fill any gaps less than 64k;
273: * complain about any zero-filling, and die if we're asked to
274: * zero-fill more than 64k.
275: */
276: for (i = 0; i < ex.e_phnum; i++) {
277: /*
278: * Unprocessable sections were handled above, so just verify
279: * that the section can be loaded before copying.
280: */
281: if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
282: if (cur_vma != ph[i].p_vaddr) {
283: unsigned long gap = ph[i].p_vaddr - cur_vma;
284: char obuf[1024];
285: if (gap > 65536) {
1.4 deraadt 286: fprintf(stderr,
287: "Intersegment gap (%d bytes) too large.\n",
288: gap);
1.3 deraadt 289: exit(1);
290: }
1.4 deraadt 291: fprintf(stderr,
292: "Warning: %d byte intersegment gap.\n", gap);
1.3 deraadt 293: memset(obuf, 0, sizeof obuf);
294: while (gap) {
295: int count = write(outfile, obuf,
296: (gap > sizeof obuf
297: ? sizeof obuf : gap));
298: if (count < 0) {
299: fprintf(stderr,
300: "Error writing gap: %s\n",
301: strerror(errno));
302: exit(1);
303: }
304: gap -= count;
305: }
306: }
307: fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
308: copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
309: cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
310: }
1.1 pefo 311: }
312:
1.3 deraadt 313: /*
314: * Write a page of padding for boot PROMS that read entire pages.
315: * Without this, they may attempt to read past the end of the
316: * data section, incur an error, and refuse to boot.
317: */
1.1 pefo 318: {
1.3 deraadt 319: char obuf[4096];
320: memset(obuf, 0, sizeof obuf);
321: if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
322: fprintf(stderr, "Error writing PROM padding: %s\n",
323: strerror(errno));
324: exit(1);
1.1 pefo 325: }
1.3 deraadt 326: }
1.1 pefo 327:
1.3 deraadt 328: /* Looks like we won... */
329: exit(0);
1.1 pefo 330: }
331:
1.4 deraadt 332: void
333: copy(int out, int in, off_t offset, off_t size)
1.1 pefo 334: {
1.3 deraadt 335: char ibuf[4096];
336: int remaining, cur, count;
1.1 pefo 337:
1.5 ! henning 338: /* Go to the start of the ELF symbol table... */
1.3 deraadt 339: if (lseek(in, offset, SEEK_SET) < 0) {
340: perror("copy: lseek");
341: exit(1);
1.1 pefo 342: }
1.3 deraadt 343: remaining = size;
344: while (remaining) {
345: cur = remaining;
346: if (cur > sizeof ibuf)
347: cur = sizeof ibuf;
348: remaining -= cur;
349: if ((count = read(in, ibuf, cur)) != cur) {
350: fprintf(stderr, "copy: read: %s\n",
351: count ? strerror(errno) : "premature end of file");
352: exit(1);
353: }
354: if ((count = write(out, ibuf, cur)) != cur) {
355: perror("copy: write");
356: exit(1);
357: }
1.1 pefo 358: }
359: }
360:
1.3 deraadt 361: /*
362: * Combine two segments, which must be contiguous. If pad is true, it's
363: * okay for there to be padding between.
364: */
1.4 deraadt 365: void
366: combine(struct sect *base, struct sect *new, int pad)
1.1 pefo 367: {
1.3 deraadt 368: if (!base->len)
369: *base = *new;
370: else if (new->len) {
371: if (base->vaddr + base->len != new->vaddr) {
372: if (pad)
373: base->len = new->vaddr - base->vaddr;
374: else {
375: fprintf(stderr,
376: "Non-contiguous data can't be converted.\n");
377: exit(1);
378: }
379: }
380: base->len += new->len;
1.1 pefo 381: }
382: }
383:
1.4 deraadt 384: int
385: phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2)
1.1 pefo 386: {
1.3 deraadt 387: if (h1->p_vaddr > h2->p_vaddr)
388: return 1;
389: else if (h1->p_vaddr < h2->p_vaddr)
390: return -1;
391: else
392: return 0;
1.1 pefo 393: }
394:
1.4 deraadt 395: char *
1.3 deraadt 396: saveRead(int file, off_t offset, off_t len, char *name)
1.1 pefo 397: {
1.3 deraadt 398: char *tmp;
399: int count;
400: off_t off;
401:
402: if ((off = lseek(file, offset, SEEK_SET)) < 0) {
403: fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
404: exit(1);
405: }
406: if (!(tmp = (char *) malloc(len))) {
407: fprintf(stderr, "%s: Can't allocate %d bytes.\n", name, len);
408: exit(1);
409: }
410: count = read(file, tmp, len);
411: if (count != len) {
412: fprintf(stderr, "%s: read: %s.\n",
413: name, count ? strerror(errno) : "End of file reached");
414: exit(1);
415: }
416: return tmp;
1.1 pefo 417: }