1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <stdio.h>
37#include <string.h>
38#include <errno.h>
39#include <sys/types.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <elf.h>
43#include <limits.h>
44#include <netinet/in.h>
45#include <stdlib.h>
46
47#include "ecoff.h"
48
49
50
51
52#define PT_MIPS_REGINFO 0x70000000
53#define PT_MIPS_ABIFLAGS 0x70000003
54
55
56
57struct sect {
58 unsigned long vaddr;
59 unsigned long len;
60};
61
62int *symTypeTable;
63int must_convert_endian;
64int format_bigendian;
65
66static void copy(int out, int in, off_t offset, off_t size)
67{
68 char ibuf[4096];
69 int remaining, cur, count;
70
71
72 if (lseek(in, offset, SEEK_SET) < 0) {
73 perror("copy: lseek");
74 exit(1);
75 }
76
77 remaining = size;
78 while (remaining) {
79 cur = remaining;
80 if (cur > sizeof ibuf)
81 cur = sizeof ibuf;
82 remaining -= cur;
83 if ((count = read(in, ibuf, cur)) != cur) {
84 fprintf(stderr, "copy: read: %s\n",
85 count ? strerror(errno) :
86 "premature end of file");
87 exit(1);
88 }
89 if ((count = write(out, ibuf, cur)) != cur) {
90 perror("copy: write");
91 exit(1);
92 }
93 }
94}
95
96
97
98
99
100static void combine(struct sect *base, struct sect *new, int pad)
101{
102 if (!base->len)
103 *base = *new;
104 else if (new->len) {
105 if (base->vaddr + base->len != new->vaddr) {
106 if (pad)
107 base->len = new->vaddr - base->vaddr;
108 else {
109 fprintf(stderr,
110 "Non-contiguous data can't be converted.\n");
111 exit(1);
112 }
113 }
114 base->len += new->len;
115 }
116}
117
118static int phcmp(const void *v1, const void *v2)
119{
120 const Elf32_Phdr *h1 = v1;
121 const Elf32_Phdr *h2 = v2;
122
123 if (h1->p_vaddr > h2->p_vaddr)
124 return 1;
125 else if (h1->p_vaddr < h2->p_vaddr)
126 return -1;
127 else
128 return 0;
129}
130
131static char *saveRead(int file, off_t offset, off_t len, char *name)
132{
133 char *tmp;
134 int count;
135 off_t off;
136 if ((off = lseek(file, offset, SEEK_SET)) < 0) {
137 fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
138 exit(1);
139 }
140 if (!(tmp = (char *) malloc(len))) {
141 fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
142 len);
143 exit(1);
144 }
145 count = read(file, tmp, len);
146 if (count != len) {
147 fprintf(stderr, "%s: read: %s.\n",
148 name,
149 count ? strerror(errno) : "End of file reached");
150 exit(1);
151 }
152 return tmp;
153}
154
155#define swab16(x) \
156 ((unsigned short)( \
157 (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
158 (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
159
160#define swab32(x) \
161 ((unsigned int)( \
162 (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
163 (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \
164 (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \
165 (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
166
167static void convert_elf_hdr(Elf32_Ehdr * e)
168{
169 e->e_type = swab16(e->e_type);
170 e->e_machine = swab16(e->e_machine);
171 e->e_version = swab32(e->e_version);
172 e->e_entry = swab32(e->e_entry);
173 e->e_phoff = swab32(e->e_phoff);
174 e->e_shoff = swab32(e->e_shoff);
175 e->e_flags = swab32(e->e_flags);
176 e->e_ehsize = swab16(e->e_ehsize);
177 e->e_phentsize = swab16(e->e_phentsize);
178 e->e_phnum = swab16(e->e_phnum);
179 e->e_shentsize = swab16(e->e_shentsize);
180 e->e_shnum = swab16(e->e_shnum);
181 e->e_shstrndx = swab16(e->e_shstrndx);
182}
183
184static void convert_elf_phdrs(Elf32_Phdr * p, int num)
185{
186 int i;
187
188 for (i = 0; i < num; i++, p++) {
189 p->p_type = swab32(p->p_type);
190 p->p_offset = swab32(p->p_offset);
191 p->p_vaddr = swab32(p->p_vaddr);
192 p->p_paddr = swab32(p->p_paddr);
193 p->p_filesz = swab32(p->p_filesz);
194 p->p_memsz = swab32(p->p_memsz);
195 p->p_flags = swab32(p->p_flags);
196 p->p_align = swab32(p->p_align);
197 }
198
199}
200
201static void convert_elf_shdrs(Elf32_Shdr * s, int num)
202{
203 int i;
204
205 for (i = 0; i < num; i++, s++) {
206 s->sh_name = swab32(s->sh_name);
207 s->sh_type = swab32(s->sh_type);
208 s->sh_flags = swab32(s->sh_flags);
209 s->sh_addr = swab32(s->sh_addr);
210 s->sh_offset = swab32(s->sh_offset);
211 s->sh_size = swab32(s->sh_size);
212 s->sh_link = swab32(s->sh_link);
213 s->sh_info = swab32(s->sh_info);
214 s->sh_addralign = swab32(s->sh_addralign);
215 s->sh_entsize = swab32(s->sh_entsize);
216 }
217}
218
219static void convert_ecoff_filehdr(struct filehdr *f)
220{
221 f->f_magic = swab16(f->f_magic);
222 f->f_nscns = swab16(f->f_nscns);
223 f->f_timdat = swab32(f->f_timdat);
224 f->f_symptr = swab32(f->f_symptr);
225 f->f_nsyms = swab32(f->f_nsyms);
226 f->f_opthdr = swab16(f->f_opthdr);
227 f->f_flags = swab16(f->f_flags);
228}
229
230static void convert_ecoff_aouthdr(struct aouthdr *a)
231{
232 a->magic = swab16(a->magic);
233 a->vstamp = swab16(a->vstamp);
234 a->tsize = swab32(a->tsize);
235 a->dsize = swab32(a->dsize);
236 a->bsize = swab32(a->bsize);
237 a->entry = swab32(a->entry);
238 a->text_start = swab32(a->text_start);
239 a->data_start = swab32(a->data_start);
240 a->bss_start = swab32(a->bss_start);
241 a->gprmask = swab32(a->gprmask);
242 a->cprmask[0] = swab32(a->cprmask[0]);
243 a->cprmask[1] = swab32(a->cprmask[1]);
244 a->cprmask[2] = swab32(a->cprmask[2]);
245 a->cprmask[3] = swab32(a->cprmask[3]);
246 a->gp_value = swab32(a->gp_value);
247}
248
249static void convert_ecoff_esecs(struct scnhdr *s, int num)
250{
251 int i;
252
253 for (i = 0; i < num; i++, s++) {
254 s->s_paddr = swab32(s->s_paddr);
255 s->s_vaddr = swab32(s->s_vaddr);
256 s->s_size = swab32(s->s_size);
257 s->s_scnptr = swab32(s->s_scnptr);
258 s->s_relptr = swab32(s->s_relptr);
259 s->s_lnnoptr = swab32(s->s_lnnoptr);
260 s->s_nreloc = swab16(s->s_nreloc);
261 s->s_nlnno = swab16(s->s_nlnno);
262 s->s_flags = swab32(s->s_flags);
263 }
264}
265
266int main(int argc, char *argv[])
267{
268 Elf32_Ehdr ex;
269 Elf32_Phdr *ph;
270 Elf32_Shdr *sh;
271 int i, pad;
272 struct sect text, data, bss;
273 struct filehdr efh;
274 struct aouthdr eah;
275 struct scnhdr esecs[6];
276 int infile, outfile;
277 unsigned long cur_vma = ULONG_MAX;
278 int addflag = 0;
279 int nosecs;
280
281 text.len = data.len = bss.len = 0;
282 text.vaddr = data.vaddr = bss.vaddr = 0;
283
284
285 if (argc < 3 || argc > 4) {
286 usage:
287 fprintf(stderr,
288 "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
289 exit(1);
290 }
291 if (argc == 4) {
292 if (strcmp(argv[3], "-a"))
293 goto usage;
294 addflag = 1;
295 }
296
297
298 if ((infile = open(argv[1], O_RDONLY)) < 0) {
299 fprintf(stderr, "Can't open %s for read: %s\n",
300 argv[1], strerror(errno));
301 exit(1);
302 }
303
304
305 i = read(infile, &ex, sizeof ex);
306 if (i != sizeof ex) {
307 fprintf(stderr, "ex: %s: %s.\n",
308 argv[1],
309 i ? strerror(errno) : "End of file reached");
310 exit(1);
311 }
312
313 if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
314 format_bigendian = 1;
315
316 if (ntohs(0xaa55) == 0xaa55) {
317 if (!format_bigendian)
318 must_convert_endian = 1;
319 } else {
320 if (format_bigendian)
321 must_convert_endian = 1;
322 }
323 if (must_convert_endian)
324 convert_elf_hdr(&ex);
325
326
327 ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
328 ex.e_phnum * sizeof(Elf32_Phdr),
329 "ph");
330 if (must_convert_endian)
331 convert_elf_phdrs(ph, ex.e_phnum);
332
333 sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
334 ex.e_shnum * sizeof(Elf32_Shdr),
335 "sh");
336 if (must_convert_endian)
337 convert_elf_shdrs(sh, ex.e_shnum);
338
339
340
341
342
343
344
345 qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
346
347 for (i = 0; i < ex.e_phnum; i++) {
348
349 switch (ph[i].p_type) {
350 case PT_NULL:
351 case PT_NOTE:
352 case PT_PHDR:
353 case PT_MIPS_REGINFO:
354 case PT_MIPS_ABIFLAGS:
355 continue;
356
357 case PT_LOAD:
358
359 if (ph[i].p_flags & PF_W) {
360 struct sect ndata, nbss;
361
362 ndata.vaddr = ph[i].p_vaddr;
363 ndata.len = ph[i].p_filesz;
364 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
365 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
366
367 combine(&data, &ndata, 0);
368 combine(&bss, &nbss, 1);
369 } else {
370 struct sect ntxt;
371
372 ntxt.vaddr = ph[i].p_vaddr;
373 ntxt.len = ph[i].p_filesz;
374
375 combine(&text, &ntxt, 0);
376 }
377
378 if (ph[i].p_vaddr < cur_vma)
379 cur_vma = ph[i].p_vaddr;
380 break;
381
382 default:
383
384 fprintf(stderr,
385 "Program header %d type %d can't be converted.\n",
386 ex.e_phnum, ph[i].p_type);
387 exit(1);
388 }
389 }
390
391
392 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
393 text.vaddr + text.len > data.vaddr
394 || data.vaddr + data.len > bss.vaddr) {
395 fprintf(stderr,
396 "Sections ordering prevents a.out conversion.\n");
397 exit(1);
398 }
399
400
401
402
403
404 if (data.len && !text.len) {
405 text = data;
406 data.vaddr = text.vaddr + text.len;
407 data.len = 0;
408 }
409
410
411
412
413
414 if (text.vaddr + text.len < data.vaddr)
415 text.len = data.vaddr - text.vaddr;
416
417
418 eah.magic = OMAGIC;
419 eah.vstamp = 200;
420 eah.tsize = text.len;
421 eah.dsize = data.len;
422 eah.bsize = bss.len;
423 eah.entry = ex.e_entry;
424 eah.text_start = text.vaddr;
425 eah.data_start = data.vaddr;
426 eah.bss_start = bss.vaddr;
427 eah.gprmask = 0xf3fffffe;
428 memset(&eah.cprmask, '\0', sizeof eah.cprmask);
429 eah.gp_value = 0;
430
431 if (format_bigendian)
432 efh.f_magic = MIPSEBMAGIC;
433 else
434 efh.f_magic = MIPSELMAGIC;
435 if (addflag)
436 nosecs = 6;
437 else
438 nosecs = 3;
439 efh.f_nscns = nosecs;
440 efh.f_timdat = 0;
441 efh.f_symptr = 0;
442 efh.f_nsyms = 0;
443 efh.f_opthdr = sizeof eah;
444 efh.f_flags = 0x100f;
445
446 memset(esecs, 0, sizeof esecs);
447 strcpy(esecs[0].s_name, ".text");
448 strcpy(esecs[1].s_name, ".data");
449 strcpy(esecs[2].s_name, ".bss");
450 if (addflag) {
451 strcpy(esecs[3].s_name, ".rdata");
452 strcpy(esecs[4].s_name, ".sdata");
453 strcpy(esecs[5].s_name, ".sbss");
454 }
455 esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
456 esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
457 esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
458 if (addflag) {
459 esecs[3].s_paddr = esecs[3].s_vaddr = 0;
460 esecs[4].s_paddr = esecs[4].s_vaddr = 0;
461 esecs[5].s_paddr = esecs[5].s_vaddr = 0;
462 }
463 esecs[0].s_size = eah.tsize;
464 esecs[1].s_size = eah.dsize;
465 esecs[2].s_size = eah.bsize;
466 if (addflag) {
467 esecs[3].s_size = 0;
468 esecs[4].s_size = 0;
469 esecs[5].s_size = 0;
470 }
471 esecs[0].s_scnptr = N_TXTOFF(efh, eah);
472 esecs[1].s_scnptr = N_DATOFF(efh, eah);
473#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
474#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
475 esecs[2].s_scnptr = esecs[1].s_scnptr +
476 ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
477 if (addflag) {
478 esecs[3].s_scnptr = 0;
479 esecs[4].s_scnptr = 0;
480 esecs[5].s_scnptr = 0;
481 }
482 esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
483 esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
484 esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
485 esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
486 if (addflag) {
487 esecs[3].s_relptr = esecs[4].s_relptr
488 = esecs[5].s_relptr = 0;
489 esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
490 = esecs[5].s_lnnoptr = 0;
491 esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
492 0;
493 esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
494 }
495 esecs[0].s_flags = 0x20;
496 esecs[1].s_flags = 0x40;
497 esecs[2].s_flags = 0x82;
498 if (addflag) {
499 esecs[3].s_flags = 0x100;
500 esecs[4].s_flags = 0x200;
501 esecs[5].s_flags = 0x400;
502 }
503
504
505 if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
506 fprintf(stderr, "Unable to create %s: %s\n", argv[2],
507 strerror(errno));
508 exit(1);
509 }
510
511 if (must_convert_endian)
512 convert_ecoff_filehdr(&efh);
513
514 i = write(outfile, &efh, sizeof efh);
515 if (i != sizeof efh) {
516 perror("efh: write");
517 exit(1);
518
519 for (i = 0; i < nosecs; i++) {
520 printf
521 ("Section %d: %s phys %lx size %lx file offset %lx\n",
522 i, esecs[i].s_name, esecs[i].s_paddr,
523 esecs[i].s_size, esecs[i].s_scnptr);
524 }
525 }
526 fprintf(stderr, "wrote %d byte file header.\n", i);
527
528 if (must_convert_endian)
529 convert_ecoff_aouthdr(&eah);
530 i = write(outfile, &eah, sizeof eah);
531 if (i != sizeof eah) {
532 perror("eah: write");
533 exit(1);
534 }
535 fprintf(stderr, "wrote %d byte a.out header.\n", i);
536
537 if (must_convert_endian)
538 convert_ecoff_esecs(&esecs[0], nosecs);
539 i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
540 if (i != nosecs * sizeof(struct scnhdr)) {
541 perror("esecs: write");
542 exit(1);
543 }
544 fprintf(stderr, "wrote %d bytes of section headers.\n", i);
545
546 pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
547 if (pad) {
548 pad = 16 - pad;
549 i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
550 if (i < 0) {
551 perror("ipad: write");
552 exit(1);
553 }
554 fprintf(stderr, "wrote %d byte pad.\n", i);
555 }
556
557
558
559
560
561
562 for (i = 0; i < ex.e_phnum; i++) {
563
564
565 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
566 if (cur_vma != ph[i].p_vaddr) {
567 unsigned long gap =
568 ph[i].p_vaddr - cur_vma;
569 char obuf[1024];
570 if (gap > 65536) {
571 fprintf(stderr,
572 "Intersegment gap (%ld bytes) too large.\n",
573 gap);
574 exit(1);
575 }
576 fprintf(stderr,
577 "Warning: %ld byte intersegment gap.\n",
578 gap);
579 memset(obuf, 0, sizeof obuf);
580 while (gap) {
581 int count =
582 write(outfile, obuf,
583 (gap >
584 sizeof obuf ? sizeof
585 obuf : gap));
586 if (count < 0) {
587 fprintf(stderr,
588 "Error writing gap: %s\n",
589 strerror(errno));
590 exit(1);
591 }
592 gap -= count;
593 }
594 }
595 fprintf(stderr, "writing %d bytes...\n",
596 ph[i].p_filesz);
597 copy(outfile, infile, ph[i].p_offset,
598 ph[i].p_filesz);
599 cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
600 }
601 }
602
603
604
605
606
607
608 {
609 char obuf[4096];
610 memset(obuf, 0, sizeof obuf);
611 if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
612 fprintf(stderr, "Error writing PROM padding: %s\n",
613 strerror(errno));
614 exit(1);
615 }
616 }
617
618
619 exit(0);
620}
621