diff options
Diffstat (limited to 'utils/5cv')
| -rw-r--r-- | utils/5cv/5cv.c | 353 | ||||
| -rw-r--r-- | utils/5cv/mkfile | 18 |
2 files changed, 371 insertions, 0 deletions
diff --git a/utils/5cv/5cv.c b/utils/5cv/5cv.c new file mode 100644 index 00000000..1edbf6c6 --- /dev/null +++ b/utils/5cv/5cv.c @@ -0,0 +1,353 @@ +#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 %lux, ent %lux, txtsz %lux, dataddr %lux\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)); + } +} diff --git a/utils/5cv/mkfile b/utils/5cv/mkfile new file mode 100644 index 00000000..3b544bc6 --- /dev/null +++ b/utils/5cv/mkfile @@ -0,0 +1,18 @@ +<../../mkconfig + +TARG=5cv + +OFILES= 5cv.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE |
