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