Interdata_v6/usr/source/wgong/cvo.c
#
/*
* Interdata -> Unix object code converter
*/
/* Relocation bits */
#define RABS 00
#define RTEXT 02
#define RDATA 04
#define REXT 010
#define RHI 01
/* Symbol types */
#define SABS 01
#define STEXT 02
#define SDATA 03
#define SEXT 040
/* a.out header */
struct {
int mword;
int tsize;
int dsize;
int bsize;
int ssize;
int entrypt;
int unused;
int rflag;
} hdr;
/* External reference chain */
struct chain {
struct chain *next; /* link to next entry */
int defloc; /* location of reference */
int refseg; /* segment referred to */
/* (ext ref: -(symbol no) */
int refloc; /* location referred to */
/* (ext ref: offset) */
};
/* Segment information */
struct segment {
int loc; /* location counter */
int maxloc; /* highest location so far */
int offset[2]; /* file offsets - code, reloc */
int nchar; /* no. chars in buffers */
struct chain *first; /* chain of ext refs */
char obuf[2][512]; /* buffers - code, reloc bits */
} pure, impure;
/* buffer for symbol table */
int symbuf[128];
int nsym; /* no. words in buf */
int symoff; /* file offset of sym tab */
int symno; /* next available sym number */
/* table of common blocks */
#define NCOM 32
struct combuf {
int com_name[2]; /* name of common block */
int com_sym; /* symbol number */
int com_len; /* length of block */
int com_off; /* offset of beginning of block */
} combuf[NCOM];
struct combuf *lastcom combuf;
int bdata; /* block data flag */
struct segment *curseg { &impure };
struct chain *top { &end };
struct chain *avail { &end };
/* tricky structure for accessing bytes of a word */
struct { char byte[]; };
int ofile;
main(argc, argv)
char *argv[];
{
if (argc != 3)
error("Usage: cvo infile outfile");
close(0);
if (open(argv[1], 0) != 0)
error("Can't find input file");
if ((ofile = creat(argv[2], 0666)) < 0)
error("Can't create output file");
pass1();
/* If block data program, make another pass through input */
if (bdata) {
seek(0, 0, 0);
close(ofile);
if ((ofile = creat(argv[2], 0666)) < 0)
error("can't create output file");
blkdata();
}
putbuf(&pure);
putbuf(&impure);
putsymbuf();
hdr.ssize = symno * 16;
hdr.mword = 0407;
seek(ofile, 0, 0);
write(ofile, &hdr, sizeof hdr);
if (bdata == 0)
pass2();
}
pass1()
{
register c, n;
register struct combuf *cp;
int name[2], word;
readobj();
for(;;) switch (c = cget()) {
case 1: /* End of program */
return;
case 2: /* Reset sequence number */
break;
case 3: /* Block data initialization */
cp = getcom();
cp->com_off = 1; /* flag for second pass */
bdata++;
skip(3);
break;
case 5: /* Pure address */
curseg = &pure;
goto addr;
case 6: /* Impure address */
curseg = &impure;
addr:
if ((n = get(3) - curseg->loc) != 0)
org(n);
break;
case 11: /* Common reference */
cp = getcom();
curseg->loc =- 4;
dchain(-cp->com_sym, get(3));
curseg->loc =+ 4;
break;
case 13: /* Entry */
name[0] = get(4);
name[1] = get(4);
symbol(name);
symno++;
switch (cget()) {
case 4:
putsym(SEXT+SABS, get(3));
break;
case 5:
putsym(SEXT+STEXT, get(3));
break;
case 6:
putsym(SEXT+SDATA, get(3) + hdr.tsize);
break;
default:
error("Unknown entry symbol type");
}
break;
case 14: /* Common definition */
cp = putcom();
symno++;
cp->com_len = n = get(3);
putsym(SEXT, n);
break;
case 15: /* Label */
skip(8);
break;
case 16: /* 3 bytes abs, 3 bytes pure */
put(get(2), RABS);
case 9: /* 4 bytes pure */
word = n = get(4);
dchain(&pure, n&03777777);
if (c==9)
word.byte[0] = '\0';
put(word>>16, RTEXT+RHI);
put(n&0177777, RTEXT);
break;
case 17: /* 3 bytes abs, 3 bytes impure */
put(get(2), RABS);
case 10: /* 4 bytes impure */
word = n = get(4);
dchain(&impure, n&03777777);
n = word.byte[0];
word =+ hdr.tsize;
word.byte[0] = c == 10 ? '\0' : n;
put((n=word)>>16, RDATA+RHI);
put(n&0177777, RDATA);
break;
case 18: /* Entry address */
case 19: /* Chain definition address */
skip(4);
break;
case 21: /* 2 bytes abs, 2 bytes pure */
put(get(2), RABS);
case 7: /* 2 bytes pure */
put(get(2), RTEXT);
break;
case 22: /* 2 bytes abs, 2 bytes impure */
put(get(2), RABS);
case 8: /* 2 bytes impure */
put(get(2) + hdr.tsize, RDATA);
break;
case 12: /* EXTRN */
name[0] = get(4);
name[1] = get(4);
symbol(name);
putsym(SEXT, 0);
switch (cget()) {
case 5:
mkchain(&pure, get(3));
break;
case 6:
mkchain(&impure, get(3));
break;
default:
error("Unknown extrn address type");
}
symno++;
break;
case 24: /* Length of impure & pure segments */
n = get(3);
reset(n, get(3));
break;
case 25: /* Perform fullword chain */
case 27: /* No-op */
break;
/*
* New code (undocumented!) produced by CAL-R05
* - code 31 apparently means 'one byte absolute'
* It will be handled correctly only if followed immediately
* by an 'org' or another 1-byte code
*/
case 31: /* 1 byte absolute? */
put1byte(get(1));
break;
default: /* Absolute data */
if ((c =- 31) <= 0 || c > 60)
error("Unknown control item");
if (bdata)
skip(c*2);
else while (c--)
put(get(2), RABS);
}
}
/*
* Define a common block and write its name to the symbol table
* (returns pointer to common table entry)
*/
putcom()
{
int name[2];
register struct combuf *cp;
if ((cp = lastcom) >= &combuf[NCOM])
error("Too many common blocks");
cp->com_name[0] = get(4);
cp->com_name[1] = get(4);
cp->com_sym = symno;
symbol(cp->com_name);
lastcom = ++cp;
return(cp - 1);
}
/*
* Look up a common block name & return a pointer to its common table entry
*/
getcom()
{
int name[2];
register struct combuf *cp;
name[0] = get(4);
name[1] = get(4);
for (cp = combuf; cp < lastcom; cp++)
if (cp->com_name[0] == name[0] && cp->com_name[1] == name[1])
return(cp);
error("Undefined common block reference");
}
/*
* Link an entry into chain of possible external references
* (sorted by location).
*/
dchain(seg, loc)
struct segment *seg;
{
register struct chain *ch, *lastch, *av;
if ((seg > 0) && loc >= seg->maxloc) /* ignore forward refs */
return;
if ((av = avail) >= top)
brk(top =+ 64);
lastch = &curseg->first;
for (ch = curseg->first; ch; ch = ch->next) {
if (ch->defloc > curseg->loc)
break;
lastch = ch;
}
av->next = ch;
lastch->next = av;
av->defloc = curseg->loc;
av->refseg = seg;
av->refloc = loc;
avail = ++av;
}
/*
* Make chain of external references
*/
mkchain(seg, loc)
struct segment *seg;
{
register struct chain *ch;
for (ch = seg->first; ch;) {
if (ch->defloc > loc)
break;
if (ch->defloc == loc && (ch->refseg > 0)) {
seg = ch->refseg;
loc = ch->refloc;
ch->refseg = -symno;
ch->refloc = 0;
ch = seg->first;
continue;
}
ch = ch->next;
}
seg->loc = loc;
curseg = seg;
dchain(-symno, 0);
}
pass2()
{
register n;
n = sizeof hdr;
fixup(&pure, n, 0);
fixup(&impure, n =+ hdr.tsize, 0);
fixup(&pure, n =+ hdr.dsize, 1);
fixup(&impure, n =+ hdr.tsize, 1);
}
fixup(seg, off, flag)
struct segment *seg;
{
register struct chain *ch;
static zero, s;
for (ch = seg->first; ch; ch = ch->next)
if (ch->refseg <= 0) {
if (flag) {
seek(ofile, off + ch->defloc, 0);
s = (-ch->refseg)<<20 | REXT+RHI<<16
| (-ch->refseg)<<4 | REXT;
write(ofile, &s, sizeof s);
} else {
seek(ofile, off + ch->defloc + 1, 0);
write(ofile, &ch->refloc.byte[1], 3);
}
}
}
/*
* Read next record from object file
*/
char inbuff[126];
char *inp;
readobj()
{
if (read(0, inbuff, 126) != 126)
error("Input file i/o error");
inp = &inbuff[4];
}
/*
* Get next command code from object file
*/
cget()
{
register n;
if ((n = get(1)) == 0) {
readobj();
n = get(1);
}
return(n);
}
/*
* Get next n bytes (1 - 4) from object file
*/
get(n)
{
register i, w;
w = *inp++;
for (i=1; i<n; i++) {
w =<< 8; w =| *inp++;
}
return(w);
}
/*
* Skip next n bytes in object file
*/
skip(n)
{
inp =+ n;
}
/*
* Print error message and exit
*/
error(s)
char *s;
{
char *p;
for (p=s; *p; p++)
;
write(1, s, p-s);
write(1, "\n", 1);
exit(1);
}
/*
* Initialize offsets & buffers
*/
reset(dsize, tsize)
{
register n;
hdr.dsize = dsize;
hdr.tsize = tsize;
pure.offset[0] = n = sizeof hdr;
impure.offset[0] = n =+ tsize;
pure.offset[1] = n =+ dsize;
impure.offset[1] = n =+ tsize;
impure.maxloc = impure.loc = pure.nchar = impure.nchar = 0;
curseg = &impure;
symoff = n =+ dsize;
nsym = 0;
}
/*
* Put a halfword of code & corresponding relocation bits to output
*/
put(code, rel)
{
register struct segment *seg;
register i;
seg = curseg;
if (seg->nchar >= 512)
putbuf(seg);
i = seg->nchar;
seg->obuf[0][i] = code>>8;
seg->obuf[0][i+1] = code&0377;
seg->obuf[1][i] = rel>>8;
seg->obuf[1][i+1] = rel&0377;
seg->nchar = i+2;
seg->loc =+ 2;
if (seg->loc > seg->maxloc)
seg->maxloc = seg->loc;
}
/*
* Put out 1 absolute byte
* (This had better be followed by an org)
*/
put1byte(code)
{
register struct segment *seg;
register i;
seg = curseg;
if (seg->nchar >= 512)
putbuf(seg);
i = seg->nchar;
seg->obuf[0][i] = code;
seg->obuf[1][i] = 0;
seg->nchar = ++i;
seg->loc++;
if (seg->loc > seg->maxloc)
seg->maxloc = seg->loc;
}
/*
* Adjust location in current segment by offset of (off)
*/
org(off)
{
register struct segment *seg;
register n;
seg = curseg;
if ((n = off) > 0 && seg->loc >= seg->maxloc && n < 512) {
while (n--)
put1byte(0);
return;
}
putbuf(seg);
seg->offset[0] =+ n;
seg->offset[1] =+ n;
seg->loc =+ n;
if (seg->loc > seg->maxloc)
seg->maxloc = seg->loc;
}
/*
* Flush output buffers
*/
putbuf(seg)
{
register n, i;
if ((n = seg->nchar) <= 0)
return;
for (i=0; i<=1; i++) {
seek(ofile, seg->offset[i], 0);
write(ofile, seg->obuf[i], n);
seg->offset[i] =+ n;
}
seg->nchar = 0;
}
/*
* Copy a symbol name to the output file
*/
symbol(name)
char *name;
{
int sym[2];
register c, i;
register char *p, *q;
p = sym; q = name;
for (i=8; i>0; i--) {
if ((c = *q++) == ' ')
c = '\0';
*p++ = c;
}
putsym(sym[0], sym[1]);
}
/*
* Write two words to the symbol table
*/
putsym(s1, s2)
{
if (nsym >= 128)
putsymbuf();
symbuf[nsym++] = s1;
symbuf[nsym++] = s2;
}
/*
* Flush the symbol table buffer
*/
putsymbuf()
{
if (nsym <= 0)
return;
seek(ofile, symoff, 0);
write(ofile, symbuf, nsym*4);
symoff =+ nsym*4;
nsym = 0;
}
/*
* Second pass for block data program --
* turn initialized common blocks to data
*/
blkdata()
{
register struct combuf *cp;
register n, c;
/* find total length of commons */
n = 0;
for (cp = combuf; cp < lastcom; cp++)
if (cp->com_off) {
cp->com_off = n;
n =+ cp->com_len;
cp->com_len = 0;
}
/* reset buffers & re-process input */
reset(n, 0);
readobj();
for (;;) switch (c = cget()) {
case 1: /* End of program */
return;
case 2: /* Reset sequence number */
break;
case 3: /* block data initialization */
cp = getcom();
org(cp->com_off + get(3) - curseg->loc);
break;
case 14: /* Common definition */
cp = getcom();
skip(3);
symbol(cp->com_name);
if (cp->com_len)
putsym(SEXT, cp->com_len);
else
putsym(SEXT+SDATA, cp->com_off);
break;
case 24: /* Length of impure & pure segments */
skip(6);
break;
default:
if ((c =- 31) <= 0 || c > 60)
error("Illegal control item in block data program");
while (c--)
put(get(2), RABS);
}
}