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