ref: 12e226ac6798412271020d42645f69138715c519
dir: /utils/5cv/5cv.c/
#include <lib9.h> #include <bio.h> #include <mach.h> char *Cmd; int Hdrtype; int Strip; long Txtaddr = -1; int Ofd; int Ifd; Fhdr Ihdr; int Debug; static void get_file(char *); static void put_file(char *); static void Usage(char *); static long strxtol(char *); char *fail = "error"; void main(int argc, char *argv[]) { char *ifile, *ofile; Cmd = argv[0]; Hdrtype = 2; ARGBEGIN { /* * Options without args */ case 's': Strip = 1; break; /* * Options with args */ case 'T': Txtaddr = strxtol(ARGF()); break; case 'H': Hdrtype = strxtol(ARGF()); break; case 'D': Debug |= strxtol(ARGF()); break; default: Usage("Invalid option"); } ARGEND if (argc != 2) Usage("Wrong number of arguments"); ifile = argv[0]; ofile = argv[1]; get_file(ifile); put_file(ofile); exits(0); } char usagemsg[] = "Usage: %s options infile outfile\n\t options (for outfile): -H[123456] -s -T<text> \n"; static void Usage(char *msg) { fprint(2, "***Error: %s\n", msg); fprint(2, usagemsg, Cmd); exits("usage"); } static long strxtol(char *s) { char *es; int base = 0; long r; if (*s == '0') if (*++s == 'x'){ base = 16; s++; } else base = 8; r = strtol(s, &es, base); if (*es) Usage("bad number"); return(r); } static void get_file(char *ifile) { int h; int d; Ifd = open(ifile, OREAD); if (Ifd < 0) { fprint(2, "5cv: open %s: %r\n", ifile); exits("open"); } h = crackhdr(Ifd, &Ihdr); if (!h || Debug){ fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, Ihdr.type, Ihdr.name); fprint(2, "txt %llux, ent %llux, txtsz %lux, dataddr %llux\n", Ihdr.txtaddr, Ihdr.entry, Ihdr.txtsz, Ihdr.dataddr); } if (!h) Usage("File type not recognized"); machbytype(Ihdr.type); if (Debug) fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize); if (Txtaddr != -1){ d = Txtaddr - Ihdr.txtaddr; Ihdr.txtaddr += d; Ihdr.dataddr = Ihdr.txtaddr + Ihdr.txtsz; } } char Wbuf[128]; char *wp = Wbuf; void lput(long l) { wp[0] = l>>24; wp[1] = l>>16; wp[2] = l>>8; wp[3] = l; wp += 4; } void lputl(long l) { wp[3] = l>>24; wp[2] = l>>16; wp[1] = l>>8; wp[0] = l; wp += 4; } static void copyseg(long sz) { char buf[1024]; while (sz > 0){ long n; long r; n = sz; if (n > sizeof buf) n = sizeof buf; sz -= n; if ((r = read(Ifd, buf, n)) != n){ fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(Ifd, 0, 1)); perror("Premature eof"); exits(fail); } if ((r = write(Ofd, buf, n)) != n){ fprint(2, "%ld = write(...%ld)\n", r, n); perror("Write error!"); exits(fail); } } } static void zero(long sz) { char buf[1024]; memset(buf, 0, sizeof buf); while (sz > 0){ long n; long r; n = sz; if (n > sizeof buf) n = sizeof buf; sz -= n; if ((r = write(Ofd, buf, n)) != n){ fprint(2, "%ld = write(...%ld)\n", r, n); perror("Write error!"); exits(fail); } } } static long rnd(long v, long r) { long c; if(r <= 0) return v; v += r - 1; c = v % r; if(c < 0) c += r; v -= c; return v; } static void put_file(char *ofile) { int ii; long doff; long dsize; long hlen; long pad; Ofd = create(ofile, OWRITE, 0666); if (Ofd < 0) { fprint(2, "5cv: create %s: %r\n", ofile); exits("create"); } pad = 0; switch(Hdrtype) { case 1: /* aif for risc os */ Strip = 1; hlen = 128; lputl(0xe1a00000); /* NOP - decompress code */ lputl(0xe1a00000); /* NOP - relocation code */ lputl(0xeb000000 + 12); /* BL - zero init code */ lputl(0xeb000000 + (Ihdr.entry - Ihdr.txtaddr + hlen - 12 - 8) / 4); /* BL - entry code */ lputl(0xef000011); /* SWI - exit code */ doff = Ihdr.txtsz+hlen; lputl(doff); /* text size */ dsize = Ihdr.datsz; lputl(dsize); /* data size */ lputl(0); /* sym size */ lputl(Ihdr.bsssz); /* bss size */ lputl(0); /* sym type */ lputl(Ihdr.txtaddr-hlen); /* text addr */ lputl(0); /* workspace - ignored */ lputl(32); /* addr mode / data addr flag */ lputl(0); /* data addr */ for(ii=0; ii<2; ii++) lputl(0); /* reserved */ for(ii=0; ii<15; ii++) lputl(0xe1a00000); /* NOP - zero init code */ lputl(0xe1a0f00e); /* B (R14) - zero init return */ break; case 2: /* plan 9 */ hlen = 32; doff = hlen + Ihdr.txtsz; dsize = Ihdr.datsz; lput(0x647); /* magic */ lput(Ihdr.txtsz); /* sizes */ lput(Ihdr.datsz); lput(Ihdr.bsssz); if (Strip) /* nsyms */ lput(0); else lput(Ihdr.symsz); lput(Ihdr.entry); /* va of entry */ lput(0L); lput(Ihdr.lnpcsz); break; case 3: /* boot for NetBSD */ hlen = 32; doff = rnd(hlen+Ihdr.txtsz, 4096); dsize = rnd(Ihdr.datsz, 4096); lput((143<<16)|0413); /* magic */ lputl(doff); lputl(dsize); lputl(Ihdr.bsssz); if (Strip) /* nsyms */ lputl(0); else lputl(Ihdr.symsz); lputl(Ihdr.entry); /* va of entry */ lputl(0L); lputl(0L); break; case 4: /* no header, stripped, padded to 2K, for serial bootstrap */ hlen = 0; Strip = 1; doff = hlen + Ihdr.txtsz; dsize = Ihdr.datsz; pad = 2048; break; case 5: /* no header, stripped, for all sorts */ hlen = 0; Strip = 1; doff = hlen + Ihdr.txtsz; dsize = Ihdr.datsz; break; case 6: /* fake EPOC IMG format header */ hlen = 256; *wp++ = 'E'; *wp++ = 'P'; Strip = 1; doff = hlen + Ihdr.txtsz; dsize = Ihdr.datsz; break; default: Usage("Bad -Htype"); return; } write(Ofd, Wbuf, hlen); seek(Ifd, Ihdr.txtoff, 0); copyseg(Ihdr.txtsz); seek(Ifd, Ihdr.datoff, 0); seek(Ofd, doff, 0); copyseg(Ihdr.datsz); if (!Strip) { /* Write symbols */ seek(Ofd, doff + dsize, 0); if (Ihdr.symsz){ seek(Ifd, Ihdr.symoff, 0); copyseg(Ihdr.symsz); } if (Hdrtype == 2) copyseg(Ihdr.lnpcsz); } if (pad) { if (doff + Ihdr.datsz > pad) { perror("Too big!"); exits(fail); } else if (doff + Ihdr.datsz < pad) zero(pad - (doff + Ihdr.datsz)); } }