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