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