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