0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <stdio.h>
0037 #include <string.h>
0038 #include <errno.h>
0039 #include <sys/types.h>
0040 #include <fcntl.h>
0041 #include <unistd.h>
0042 #include <elf.h>
0043 #include <limits.h>
0044 #include <netinet/in.h>
0045 #include <stdlib.h>
0046 #include <stdint.h>
0047 #include <inttypes.h>
0048
0049 #include "ecoff.h"
0050
0051
0052
0053
0054 #define PT_MIPS_REGINFO 0x70000000
0055 #define PT_MIPS_ABIFLAGS 0x70000003
0056
0057
0058
0059 struct sect {
0060 uint32_t vaddr;
0061 uint32_t len;
0062 };
0063
0064 int *symTypeTable;
0065 int must_convert_endian;
0066 int format_bigendian;
0067
0068 static void copy(int out, int in, off_t offset, off_t size)
0069 {
0070 char ibuf[4096];
0071 int remaining, cur, count;
0072
0073
0074 if (lseek(in, offset, SEEK_SET) < 0) {
0075 perror("copy: lseek");
0076 exit(1);
0077 }
0078
0079 remaining = size;
0080 while (remaining) {
0081 cur = remaining;
0082 if (cur > sizeof ibuf)
0083 cur = sizeof ibuf;
0084 remaining -= cur;
0085 if ((count = read(in, ibuf, cur)) != cur) {
0086 fprintf(stderr, "copy: read: %s\n",
0087 count ? strerror(errno) :
0088 "premature end of file");
0089 exit(1);
0090 }
0091 if ((count = write(out, ibuf, cur)) != cur) {
0092 perror("copy: write");
0093 exit(1);
0094 }
0095 }
0096 }
0097
0098
0099
0100
0101
0102 static void combine(struct sect *base, struct sect *new, int pad)
0103 {
0104 if (!base->len)
0105 *base = *new;
0106 else if (new->len) {
0107 if (base->vaddr + base->len != new->vaddr) {
0108 if (pad)
0109 base->len = new->vaddr - base->vaddr;
0110 else {
0111 fprintf(stderr,
0112 "Non-contiguous data can't be converted.\n");
0113 exit(1);
0114 }
0115 }
0116 base->len += new->len;
0117 }
0118 }
0119
0120 static int phcmp(const void *v1, const void *v2)
0121 {
0122 const Elf32_Phdr *h1 = v1;
0123 const Elf32_Phdr *h2 = v2;
0124
0125 if (h1->p_vaddr > h2->p_vaddr)
0126 return 1;
0127 else if (h1->p_vaddr < h2->p_vaddr)
0128 return -1;
0129 else
0130 return 0;
0131 }
0132
0133 static char *saveRead(int file, off_t offset, off_t len, char *name)
0134 {
0135 char *tmp;
0136 int count;
0137 off_t off;
0138 if ((off = lseek(file, offset, SEEK_SET)) < 0) {
0139 fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
0140 exit(1);
0141 }
0142 if (!(tmp = (char *) malloc(len))) {
0143 fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
0144 len);
0145 exit(1);
0146 }
0147 count = read(file, tmp, len);
0148 if (count != len) {
0149 fprintf(stderr, "%s: read: %s.\n",
0150 name,
0151 count ? strerror(errno) : "End of file reached");
0152 exit(1);
0153 }
0154 return tmp;
0155 }
0156
0157 #define swab16(x) \
0158 ((uint16_t)( \
0159 (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
0160 (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
0161
0162 #define swab32(x) \
0163 ((unsigned int)( \
0164 (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
0165 (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
0166 (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
0167 (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
0168
0169 static void convert_elf_hdr(Elf32_Ehdr * e)
0170 {
0171 e->e_type = swab16(e->e_type);
0172 e->e_machine = swab16(e->e_machine);
0173 e->e_version = swab32(e->e_version);
0174 e->e_entry = swab32(e->e_entry);
0175 e->e_phoff = swab32(e->e_phoff);
0176 e->e_shoff = swab32(e->e_shoff);
0177 e->e_flags = swab32(e->e_flags);
0178 e->e_ehsize = swab16(e->e_ehsize);
0179 e->e_phentsize = swab16(e->e_phentsize);
0180 e->e_phnum = swab16(e->e_phnum);
0181 e->e_shentsize = swab16(e->e_shentsize);
0182 e->e_shnum = swab16(e->e_shnum);
0183 e->e_shstrndx = swab16(e->e_shstrndx);
0184 }
0185
0186 static void convert_elf_phdrs(Elf32_Phdr * p, int num)
0187 {
0188 int i;
0189
0190 for (i = 0; i < num; i++, p++) {
0191 p->p_type = swab32(p->p_type);
0192 p->p_offset = swab32(p->p_offset);
0193 p->p_vaddr = swab32(p->p_vaddr);
0194 p->p_paddr = swab32(p->p_paddr);
0195 p->p_filesz = swab32(p->p_filesz);
0196 p->p_memsz = swab32(p->p_memsz);
0197 p->p_flags = swab32(p->p_flags);
0198 p->p_align = swab32(p->p_align);
0199 }
0200
0201 }
0202
0203 static void convert_elf_shdrs(Elf32_Shdr * s, int num)
0204 {
0205 int i;
0206
0207 for (i = 0; i < num; i++, s++) {
0208 s->sh_name = swab32(s->sh_name);
0209 s->sh_type = swab32(s->sh_type);
0210 s->sh_flags = swab32(s->sh_flags);
0211 s->sh_addr = swab32(s->sh_addr);
0212 s->sh_offset = swab32(s->sh_offset);
0213 s->sh_size = swab32(s->sh_size);
0214 s->sh_link = swab32(s->sh_link);
0215 s->sh_info = swab32(s->sh_info);
0216 s->sh_addralign = swab32(s->sh_addralign);
0217 s->sh_entsize = swab32(s->sh_entsize);
0218 }
0219 }
0220
0221 static void convert_ecoff_filehdr(struct filehdr *f)
0222 {
0223 f->f_magic = swab16(f->f_magic);
0224 f->f_nscns = swab16(f->f_nscns);
0225 f->f_timdat = swab32(f->f_timdat);
0226 f->f_symptr = swab32(f->f_symptr);
0227 f->f_nsyms = swab32(f->f_nsyms);
0228 f->f_opthdr = swab16(f->f_opthdr);
0229 f->f_flags = swab16(f->f_flags);
0230 }
0231
0232 static void convert_ecoff_aouthdr(struct aouthdr *a)
0233 {
0234 a->magic = swab16(a->magic);
0235 a->vstamp = swab16(a->vstamp);
0236 a->tsize = swab32(a->tsize);
0237 a->dsize = swab32(a->dsize);
0238 a->bsize = swab32(a->bsize);
0239 a->entry = swab32(a->entry);
0240 a->text_start = swab32(a->text_start);
0241 a->data_start = swab32(a->data_start);
0242 a->bss_start = swab32(a->bss_start);
0243 a->gprmask = swab32(a->gprmask);
0244 a->cprmask[0] = swab32(a->cprmask[0]);
0245 a->cprmask[1] = swab32(a->cprmask[1]);
0246 a->cprmask[2] = swab32(a->cprmask[2]);
0247 a->cprmask[3] = swab32(a->cprmask[3]);
0248 a->gp_value = swab32(a->gp_value);
0249 }
0250
0251 static void convert_ecoff_esecs(struct scnhdr *s, int num)
0252 {
0253 int i;
0254
0255 for (i = 0; i < num; i++, s++) {
0256 s->s_paddr = swab32(s->s_paddr);
0257 s->s_vaddr = swab32(s->s_vaddr);
0258 s->s_size = swab32(s->s_size);
0259 s->s_scnptr = swab32(s->s_scnptr);
0260 s->s_relptr = swab32(s->s_relptr);
0261 s->s_lnnoptr = swab32(s->s_lnnoptr);
0262 s->s_nreloc = swab16(s->s_nreloc);
0263 s->s_nlnno = swab16(s->s_nlnno);
0264 s->s_flags = swab32(s->s_flags);
0265 }
0266 }
0267
0268 int main(int argc, char *argv[])
0269 {
0270 Elf32_Ehdr ex;
0271 Elf32_Phdr *ph;
0272 Elf32_Shdr *sh;
0273 int i, pad;
0274 struct sect text, data, bss;
0275 struct filehdr efh;
0276 struct aouthdr eah;
0277 struct scnhdr esecs[6];
0278 int infile, outfile;
0279 uint32_t cur_vma = UINT32_MAX;
0280 int addflag = 0;
0281 int nosecs;
0282
0283 text.len = data.len = bss.len = 0;
0284 text.vaddr = data.vaddr = bss.vaddr = 0;
0285
0286
0287 if (argc < 3 || argc > 4) {
0288 usage:
0289 fprintf(stderr,
0290 "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
0291 exit(1);
0292 }
0293 if (argc == 4) {
0294 if (strcmp(argv[3], "-a"))
0295 goto usage;
0296 addflag = 1;
0297 }
0298
0299
0300 if ((infile = open(argv[1], O_RDONLY)) < 0) {
0301 fprintf(stderr, "Can't open %s for read: %s\n",
0302 argv[1], strerror(errno));
0303 exit(1);
0304 }
0305
0306
0307 i = read(infile, &ex, sizeof ex);
0308 if (i != sizeof ex) {
0309 fprintf(stderr, "ex: %s: %s.\n",
0310 argv[1],
0311 i ? strerror(errno) : "End of file reached");
0312 exit(1);
0313 }
0314
0315 if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
0316 format_bigendian = 1;
0317
0318 if (ntohs(0xaa55) == 0xaa55) {
0319 if (!format_bigendian)
0320 must_convert_endian = 1;
0321 } else {
0322 if (format_bigendian)
0323 must_convert_endian = 1;
0324 }
0325 if (must_convert_endian)
0326 convert_elf_hdr(&ex);
0327
0328
0329 ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
0330 ex.e_phnum * sizeof(Elf32_Phdr),
0331 "ph");
0332 if (must_convert_endian)
0333 convert_elf_phdrs(ph, ex.e_phnum);
0334
0335 sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
0336 ex.e_shnum * sizeof(Elf32_Shdr),
0337 "sh");
0338 if (must_convert_endian)
0339 convert_elf_shdrs(sh, ex.e_shnum);
0340
0341
0342
0343
0344
0345
0346
0347 qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
0348
0349 for (i = 0; i < ex.e_phnum; i++) {
0350
0351 switch (ph[i].p_type) {
0352 case PT_NULL:
0353 case PT_NOTE:
0354 case PT_PHDR:
0355 case PT_MIPS_REGINFO:
0356 case PT_MIPS_ABIFLAGS:
0357 continue;
0358
0359 case PT_LOAD:
0360
0361 if (ph[i].p_flags & PF_W) {
0362 struct sect ndata, nbss;
0363
0364 ndata.vaddr = ph[i].p_vaddr;
0365 ndata.len = ph[i].p_filesz;
0366 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
0367 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
0368
0369 combine(&data, &ndata, 0);
0370 combine(&bss, &nbss, 1);
0371 } else {
0372 struct sect ntxt;
0373
0374 ntxt.vaddr = ph[i].p_vaddr;
0375 ntxt.len = ph[i].p_filesz;
0376
0377 combine(&text, &ntxt, 0);
0378 }
0379
0380 if (ph[i].p_vaddr < cur_vma)
0381 cur_vma = ph[i].p_vaddr;
0382 break;
0383
0384 default:
0385
0386 fprintf(stderr,
0387 "Program header %d type %d can't be converted.\n",
0388 ex.e_phnum, ph[i].p_type);
0389 exit(1);
0390 }
0391 }
0392
0393
0394 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
0395 text.vaddr + text.len > data.vaddr
0396 || data.vaddr + data.len > bss.vaddr) {
0397 fprintf(stderr,
0398 "Sections ordering prevents a.out conversion.\n");
0399 exit(1);
0400 }
0401
0402
0403
0404
0405
0406 if (data.len && !text.len) {
0407 text = data;
0408 data.vaddr = text.vaddr + text.len;
0409 data.len = 0;
0410 }
0411
0412
0413
0414
0415
0416 if (text.vaddr + text.len < data.vaddr)
0417 text.len = data.vaddr - text.vaddr;
0418
0419
0420 eah.magic = OMAGIC;
0421 eah.vstamp = 200;
0422 eah.tsize = text.len;
0423 eah.dsize = data.len;
0424 eah.bsize = bss.len;
0425 eah.entry = ex.e_entry;
0426 eah.text_start = text.vaddr;
0427 eah.data_start = data.vaddr;
0428 eah.bss_start = bss.vaddr;
0429 eah.gprmask = 0xf3fffffe;
0430 memset(&eah.cprmask, '\0', sizeof eah.cprmask);
0431 eah.gp_value = 0;
0432
0433 if (format_bigendian)
0434 efh.f_magic = MIPSEBMAGIC;
0435 else
0436 efh.f_magic = MIPSELMAGIC;
0437 if (addflag)
0438 nosecs = 6;
0439 else
0440 nosecs = 3;
0441 efh.f_nscns = nosecs;
0442 efh.f_timdat = 0;
0443 efh.f_symptr = 0;
0444 efh.f_nsyms = 0;
0445 efh.f_opthdr = sizeof eah;
0446 efh.f_flags = 0x100f;
0447
0448 memset(esecs, 0, sizeof esecs);
0449 strcpy(esecs[0].s_name, ".text");
0450 strcpy(esecs[1].s_name, ".data");
0451 strcpy(esecs[2].s_name, ".bss");
0452 if (addflag) {
0453 strcpy(esecs[3].s_name, ".rdata");
0454 strcpy(esecs[4].s_name, ".sdata");
0455 strcpy(esecs[5].s_name, ".sbss");
0456 }
0457 esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
0458 esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
0459 esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
0460 if (addflag) {
0461 esecs[3].s_paddr = esecs[3].s_vaddr = 0;
0462 esecs[4].s_paddr = esecs[4].s_vaddr = 0;
0463 esecs[5].s_paddr = esecs[5].s_vaddr = 0;
0464 }
0465 esecs[0].s_size = eah.tsize;
0466 esecs[1].s_size = eah.dsize;
0467 esecs[2].s_size = eah.bsize;
0468 if (addflag) {
0469 esecs[3].s_size = 0;
0470 esecs[4].s_size = 0;
0471 esecs[5].s_size = 0;
0472 }
0473 esecs[0].s_scnptr = N_TXTOFF(efh, eah);
0474 esecs[1].s_scnptr = N_DATOFF(efh, eah);
0475 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
0476 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
0477 esecs[2].s_scnptr = esecs[1].s_scnptr +
0478 ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
0479 if (addflag) {
0480 esecs[3].s_scnptr = 0;
0481 esecs[4].s_scnptr = 0;
0482 esecs[5].s_scnptr = 0;
0483 }
0484 esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
0485 esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
0486 esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
0487 esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
0488 if (addflag) {
0489 esecs[3].s_relptr = esecs[4].s_relptr
0490 = esecs[5].s_relptr = 0;
0491 esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
0492 = esecs[5].s_lnnoptr = 0;
0493 esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
0494 0;
0495 esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
0496 }
0497 esecs[0].s_flags = 0x20;
0498 esecs[1].s_flags = 0x40;
0499 esecs[2].s_flags = 0x82;
0500 if (addflag) {
0501 esecs[3].s_flags = 0x100;
0502 esecs[4].s_flags = 0x200;
0503 esecs[5].s_flags = 0x400;
0504 }
0505
0506
0507 if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
0508 fprintf(stderr, "Unable to create %s: %s\n", argv[2],
0509 strerror(errno));
0510 exit(1);
0511 }
0512
0513 if (must_convert_endian)
0514 convert_ecoff_filehdr(&efh);
0515
0516 i = write(outfile, &efh, sizeof efh);
0517 if (i != sizeof efh) {
0518 perror("efh: write");
0519 exit(1);
0520
0521 for (i = 0; i < nosecs; i++) {
0522 printf
0523 ("Section %d: %s phys %"PRIx32" size %"PRIx32"\t file offset %"PRIx32"\n",
0524 i, esecs[i].s_name, esecs[i].s_paddr,
0525 esecs[i].s_size, esecs[i].s_scnptr);
0526 }
0527 }
0528 fprintf(stderr, "wrote %d byte file header.\n", i);
0529
0530 if (must_convert_endian)
0531 convert_ecoff_aouthdr(&eah);
0532 i = write(outfile, &eah, sizeof eah);
0533 if (i != sizeof eah) {
0534 perror("eah: write");
0535 exit(1);
0536 }
0537 fprintf(stderr, "wrote %d byte a.out header.\n", i);
0538
0539 if (must_convert_endian)
0540 convert_ecoff_esecs(&esecs[0], nosecs);
0541 i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
0542 if (i != nosecs * sizeof(struct scnhdr)) {
0543 perror("esecs: write");
0544 exit(1);
0545 }
0546 fprintf(stderr, "wrote %d bytes of section headers.\n", i);
0547
0548 pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
0549 if (pad) {
0550 pad = 16 - pad;
0551 i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
0552 if (i < 0) {
0553 perror("ipad: write");
0554 exit(1);
0555 }
0556 fprintf(stderr, "wrote %d byte pad.\n", i);
0557 }
0558
0559
0560
0561
0562
0563
0564 for (i = 0; i < ex.e_phnum; i++) {
0565
0566
0567 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
0568 if (cur_vma != ph[i].p_vaddr) {
0569 uint32_t gap = ph[i].p_vaddr - cur_vma;
0570 char obuf[1024];
0571 if (gap > 65536) {
0572 fprintf(stderr,
0573 "Intersegment gap (%"PRId32" bytes) too large.\n",
0574 gap);
0575 exit(1);
0576 }
0577 fprintf(stderr,
0578 "Warning: %d byte intersegment gap.\n",
0579 gap);
0580 memset(obuf, 0, sizeof obuf);
0581 while (gap) {
0582 int count =
0583 write(outfile, obuf,
0584 (gap >
0585 sizeof obuf ? sizeof
0586 obuf : gap));
0587 if (count < 0) {
0588 fprintf(stderr,
0589 "Error writing gap: %s\n",
0590 strerror(errno));
0591 exit(1);
0592 }
0593 gap -= count;
0594 }
0595 }
0596 fprintf(stderr, "writing %d bytes...\n",
0597 ph[i].p_filesz);
0598 copy(outfile, infile, ph[i].p_offset,
0599 ph[i].p_filesz);
0600 cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
0601 }
0602 }
0603
0604
0605
0606
0607
0608
0609 {
0610 char obuf[4096];
0611 memset(obuf, 0, sizeof obuf);
0612 if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
0613 fprintf(stderr, "Error writing PROM padding: %s\n",
0614 strerror(errno));
0615 exit(1);
0616 }
0617 }
0618
0619
0620 exit(0);
0621 }