#define VERSION "relslr ver. 1.0" /* This program reads Microsoft LINK compatible .REL files, and converts to SLR .REL format. Reference: SLRNK User's Guide, Appendix A & B. The program was written for Software Toolworks C/80. adapted from READREL by: G. A. Edgar 08/20/83 107 W. Dodridge St. Columbus, OH 43202 CIS 70715,1324 by Michael Bate 195 Lake View Av. Cambridge, MA 02138 */ #define NULL 0 #define EOF -1 /* Table sizes */ #define XNAMES 255 /* # external names */ #define ADDRESSES 2000 /* # addresses */ #define XTADDRESSES 1000 /* # external addresses */ #include "printf.h" extern char Cmode; /* static variables, available to all functions: */ int if_edit; /* ON if -E option selected */ int pass2; /* ON if second pass */ int xidno; /* Keep track of External #s in output file */ int idisk, odisk; /* File ids */ int cn; /* place in input byte */ int irecd1, ibyte1; /* Where to restart for pass 2 */ int absnow; /* # absolute bytes waiting for output */ char bytearray[128]; /* Array of absolute bytes to be output */ char extname[8]; /* Temporary storage for an external name */ char modname[8]; /* Module name */ int ccc; /* Working storage for byte-extraction */ char slrhead; /* SLR-format header byte */ int hdwritten; /* ON if header (F9) has been written */ int nowtype, nowplace; /* Location counter */ /* type tells type of address: 0 if absolute (shouldn't happen) 1 if Code (or program)-relative 2 if data-relative Note that this program does not handle COMMON */ /* Table of addresses, created on first pass */ struct tbldef { char atype; /* Where the address is located */ int aaddr; char ttype; /* Where the address points to */ int taddr; } *atable, *eatable, *iatable, *lookatable(); int sorted; /* Sorted indicator */ /* Table of external names */ struct xnamdef { char xname[8]; /* The actual name */ char xid; } *xnames, *exname; /* table of addresses to be filled in with External refs */ struct xtbldef { char atype; int aaddr; struct xnamdef *xtref; } *xtable, *extble; int ixsorted; /* sorted indicator */ int pgsize, dtsize; /* Sizes of program & data areas */ char *showname(); main(argc, argv) int argc; char *argv[]; { char name[12], nameout[12]; int i, n; unsigned a, b; char atype; int addr, avalue, staddr; unsigned bit(); /* if no arguments, print out version number and usage. */ if_edit = 0; if ((argc != 2) && (argc != 3)) usage(); i = 1; if (argc == 3) if (strcmp(argv[1], "-E")) usage(); else { if_edit = 1; i = 2; } Cmode = 0; strcpy(name, argv[i]); strcpy(nameout, name); strcat(name,".REL"); strcat(nameout, ".SLR"); printf(" %s -- file %s to SLR format %s\n",VERSION,name, nameout); if ((idisk = fopen(name,"rb")) == NULL) cant(name); if ((odisk= fopen(nameout, "wb")) == NULL) cant(nameout); /* Allocate the working arrays */ if ((xtable = alloc(XTADDRESSES * sizeof(struct xtbldef))) == -1) stoflow(); if ((atable = alloc(ADDRESSES * sizeof(struct tbldef))) == -1) stoflow(); if ((xnames = alloc(XNAMES * sizeof(struct xnamdef))) == -1) stoflow(); restart: exname = xnames; xidno = 0; sorted = 0; eatable = atable; hdwritten = 0; ixsorted = 0; extble = xtable; dtsize = pgsize = 0; pass2 = 0; irecd1 = ftellr(idisk); ibyte1 = ftell(idisk) % 256; nxtpass: absnow = 0; cn = 0; nowtype = 1; nowplace = 0; while( 1 ) { switch(bit(1)) { case 0: if (pass2 && if_tbladdr()) { bit(8); if (bit(1)) { for (i=0; i<16; i++) putc(0xff, odisk); fclose(odisk); error("Address-search logic error"); } bit(8); nowplace += 2; break; } bytearray[absnow++] = bit(8); if (absnow == 128) writebyte(); nowplace++; break; case 1: if (absnow) writebyte(); a = bit(2); switch(a) { case 1: /* Program relative */ slrhead = 0x81; write16: a = bit(8); b = bit(8); if (pass2) { if (! if_tbladdr()) { putc(slrhead, odisk); putc(a, odisk); putc(b, odisk); } } else { if (eatable >= (ADDRESSES + atable)) error("Address table overflow"); eatable -> atype = nowtype; eatable -> aaddr = nowplace; eatable -> ttype = slrhead & 0x0f; (eatable++) -> taddr = (b << 8) + a; sorted = 0; } nowplace += 2; break; case 2: slrhead = 0x82; goto write16; case 3: slrhead = 0x83; goto write16; case 0: switch(bit(4)) { case 0: remark("\nEntry point "); bfield(extname); /* Entry name */ showname(extname); break; case 1: error("COMMON block"); case 2: remark("\nProgram name "); bfield(modname); showname(modname); if (pass2) remark(" -- pass 2"); else remark(" -- pass 1"); break; case 3: bfield(extname); /* Library search */ if (pass2) { writebyte(); putc(0xfd, odisk); writename("Library", extname); } break; case 4: error("Special link item"); case 5: error("Define COMMON size "); case 6: afield(&atype, &avalue); /* Chain external */ bfield(extname); if (exname > (XNAMES+ xnames)) error("Too many external names"); exname -> xid = 0; strcpy(exname -> xname, extname); if (pass2) break; if (! sorted) sortaa(); while (atype || avalue) { addxtable(atype, avalue); if (iatable = lookatable(atype, avalue)) { atype = iatable -> ttype; avalue = iatable ->taddr; } else atype = avalue = 0; } exname++; break; case 7: afield(&atype, &avalue); /* Define Entry Point */ bfield(extname); if (! pass2) { if (! hdwritten) writehead(); putc(0xfa,odisk); writename("Entry point", extname); writea(atype, avalue); } break; case 8: error("External - offset "); case 9: error("External + offset "); case 10: afield(&addr, &dtsize); break; case 11: afield(&atype, &addr); nowtype = atype; nowplace = addr; if (pass2) { writebyte(); putc(0xA0+atype, odisk); wrtad(addr); } break; case 12: error("Chain address "); break; case 13: afield(&atype, &pgsize); break; case 14: remark("\nEnd program "); sortx(); afield(&atype, &staddr); if (pass2) { writebyte(); putc(0xFE, odisk); writea(atype, staddr); goto restart; } if (seek (idisk, irecd1, 3)) error("Bad seek to record"); if (seek (idisk, ibyte1, 1)) error("Bad seek to byte"); pass2 = 1; goto nxtpass; bytebd(); break; case 15: putst("\nEnd file"); putc(0xff, odisk); fclose(odisk); bytebd(); exit(0); break; } } } } exit(0); } afield(type, addr) /* process A field */ char *type; int *addr; { unsigned a; *type = bit(2); a = bit(8); *addr = a + (bit(8) << 8); } bfield(name) /* process B field */ char *name; { int n; for(n = bit(3); n>0; n--) *name++ = bit(8); *name++ = 0xff; *name = 0; } unsigned bit(i) /* get the next i bits from the input file */ int i; { unsigned b; int j; for(b = 0 , j = i ; j > 0 ; j--) { if(cn == 0) { cn = 8; if((ccc = getc(idisk))==EOF) { putst("\n Unexpected EOF\n"); exit(1); } ccc = ccc & 0xff; } cn--; ccc <<= 1; b = (b<<1) + (ccc>>8); ccc = ccc & 0xff; } return b; } bytebd() /* move to byte boundary */ { cn = 0; } usage() { remark(VERSION); remark("\nUsage: relslr [-e] filehead \n"); remark("\n converts simple .REL to .SLR"); remark("\n\n do NOT specify extension on the command line"); remark("\n\nYou will probably want to rename the output file"); exit(0); } writebyte() { static int i; if (absnow && pass2) { putc(absnow - 1, odisk); for (i = 0; i name)) { putc(8,0); putc(' ', 0); putc(8,0); p--; } } } p = name; while (1) { putc(*p, odisk); if (*p++ == 0xff) break; } } wrtad(addr) int addr; { putc(addr & 0xff, odisk); putc(addr >> 8, odisk); } writea(i, addr) char i; int addr; { putc(i, odisk); wrtad(addr); } writehead() { hdwritten = 1; putc(0xf9, odisk); writename("Module", modname); wrtad(pgsize); wrtad(dtsize); } /* Sort the table of relocatable addresses */ sortaa() { static int k; struct tbldef *itbl, *jtbl; eatable--; sorted = 1; for (itbl = atable; itbl<(eatable-1); itbl++) for (jtbl = itbl+1; jtbl atype > jtbl -> atype) || ((itbl -> atype == itbl -> atype) && ( itbl -> aaddr > jtbl -> aaddr))) { k = itbl -> aaddr; itbl -> aaddr = jtbl -> aaddr; jtbl -> aaddr = k; k = itbl -> atype; itbl -> atype = jtbl -> atype; jtbl -> atype = k; k = itbl -> ttype; itbl -> ttype = jtbl -> ttype; jtbl -> ttype = k; k = itbl -> taddr; itbl -> taddr = jtbl -> taddr; jtbl -> taddr = k; } } /* Add a value to xtable */ addxtable (type, value) char type; /* Address type to be added */ int value; /* Address value to be added */ { if (extble >= (xtable + XTADDRESSES)) error("External addresses table overflow"); extble -> atype = type; extble -> aaddr = value; (extble++) -> xtref = exname; return; } /* Look up an address in atable (of all addresses in the .REL file) */ struct tbldef *lookatable(type, value) char type; int value; { struct tbldef *itbl; for (itbl=atable; itbl itbl -> atype) break; if (type == itbl -> atype) if (value == itbl -> aaddr) return itbl; } return 0; } /* Sort xtable (of addresses to be filled in on pass 2 */ sortx() { static int k; struct xtbldef *itbl, *jtbl; ixsorted = 1; for (itbl = xtable; itbl<(extble-1); itbl++) for (jtbl = itbl+1; jtbl atype > jtbl -> atype) || ((itbl -> atype == jtbl -> atype) && ( itbl -> aaddr > jtbl -> aaddr))) { k = itbl -> aaddr; itbl -> aaddr = jtbl -> aaddr; jtbl -> aaddr = k; k = itbl -> atype; itbl -> atype = jtbl -> atype; jtbl -> atype = k; k = itbl -> xtref; itbl -> xtref = jtbl -> xtref; jtbl -> xtref = k; } } /* Determine if this address is in the table of externals, process if so */ if_tbladdr() { struct xnamdef *jname; struct xtbldef *itbl; char *q; for (itbl = xtable; itbl < extble; itbl++) if ((nowtype == itbl -> atype) && (nowplace == itbl -> aaddr)) { writebyte(); jname = itbl -> xtref; if (jname -> xid == 0) { putc(0xFC, odisk); writename("External", jname -> xname); jname -> xid = ++xidno; } putc(0x8f, odisk); putc(jname -> xid, odisk); return 1; } return 0; } /* Storage overflow */ stoflow() { error("Not enough storage"); } /* Show an external name on console, return pointer to 'FF' */ char *showname(p) char *p; { while (*p != 0xff) putc(*p++, 0); if (*(p+1)) error("-- Badly formed external name -- logic error"); return p; } /* See if a character exists within string */ isthere(c, p) char c, *p; { while (*p) if (c == *p++) return 1; return 0; }