Ultrix-3.1/src/ucb/l11/pass2.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
static char Sccsid[] = "@(#)pass2.c 3.0 4/22/86";
# include "link.h"
#include <errno.h>
# define MAXREG 8
WORD getword();
char *sprintf();
/******************** variables with global scope ************************/
extern struct objfile *File_root; /* root of object file link-list */
extern struct symbol *Sym_root; /* root of symbol table */
extern struct g_sect *Gsect_root; /* root of global psect tree */
WORD Maxabs; /* maximum size of absolute files,
** also low limit of relocatable code */
extern WORD R_counter; /* relocation counter, used in
** assigning relocation constants,
** also high limit of relocatable
** code after relocation */
extern long Seekoff; /* offset for seeking in out file */
extern char Do_410; /* out file format boolean */
extern char Do_411; /* out file format boolean */
extern char Do_map; /* boolean for printing load map */
extern char Do_lpr_map; /* boolean for line printing map */
extern char Do_bits; /* boolean for including relocation
** bits in .out file */
extern char Do_kludge; /* boolean to write global symbols in
** out file table with underscore */
extern char Do_silent; /* boolean for not printing zero
** errors message */
extern char Do_table; /* boolean for including symbol table
** in out file */
extern char No_locals; /* boolean for not including local
** symbols in out table */
extern WORD Transadd; /* transfer address */
int T_counter; /* used for assigning numbers to the
** global symbols so that they may be
** referenced in relocation bits */
int Glc; /* global location counter */
struct outword Curr; /* Curr.val is the current relocation
** constant, and Curr.rbits is the
** current relocation bits */
WORD Tex_size; /* for out file */
WORD Dat_size; /* for out file */
WORD Bss_size; /* for out file */
char *Outname; /* name of out file */
FILE *Outp = NULL; /* pointer for out file */
extern char Erstring[80]; /* buffer for error messages */
extern int Nerrors; /* the number of user errors */
FILE *Bitp = NULL; /* temporary file for relocation bits */
char Bitname[20]; /* name of temporary bit file */
FILE *Symp = NULL; /* temporary file for symbol table */
char Symname[20]; /* name of temporary file for symbol table */
char *Mapname; /* name of the map file */
FILE *Mapp; /* pointer for map file */
char No_out; /* boolean for no out file */
char Undefineds = 0; /* boolean, set if there are any
** references to undefined global
** symbols in the out file */
struct outword Vreg[MAXREG]; /* virtual registers */
extern int errno;
/************************** warmup ****************************************/
warmup() /* get ready for pass 2: open out file and write header,
** open temporary file for out file
** symbol table and write global variables to it */
{
WORD h[8];
Outp = fopen(Outname, "w");
if (Outp == NULL)
{
sprintf(Erstring, "%s not accessible\n", Outname);
lerror(Erstring);
}
fseek(Outp, 15L+(long)Tex_size+(long)Dat_size, 0);
putc(0, Outp);
/* write header for out file */
if (Do_410)
h[0] = 0410;
else if (Do_411)
h[0] = 0411;
else
h[0] = 0407;
h[1] = Tex_size;
h[2] = Dat_size;
h[3] = Bss_size;
h[4] = 0;
h[5] = Transadd;
h[6] = 0;
h[7] = Do_bits ? 0 : 1;
fseek(Outp, 0L, 0);
fwrite(h, 8, 2, Outp);
if (Do_table)
{
sprintf(Symname, "/tmp/l11.sym.%d", getpid());
Symp = fopen(Symname, "w");
if (Symp == NULL)
lerror("can't open symbol table file");
else
{
T_counter = 0; /* initialize counter for numbering global
** symbols */
dump_tree(Sym_root);
}
}
if (Do_bits)
{
sprintf(Bitname, "/tmp/l11.bit.%d", getpid());
Bitp = fopen(Bitname, "w");
if (Bitp == NULL)
lerror("can't open relocation bits file");
}
}
/************************* dump_tree **************************************/
dump_tree(sym) /* dump the sub-tree of symbols pointed to by *sym and
** number its contents for future reference to
** undefined symbols */
register struct symbol *sym;
{
if (sym == NULL)
return;
dump_tree(sym->left);
write_sym(sym->name, Do_kludge);
if (sym->type & DEF) /* if the symbol is defined */
Putw(040 | get_type(sym->prsect->type), Symp);
else /* undefined */
Putw(040, Symp);
Putw(sym->value, Symp);
sym->t_numb = T_counter++;
dump_tree(sym->right);
}
/************************** write_sym ***********************************/
write_sym(sname, flag) /* write the given symbol as 8 bytes (null padded)
** in the symbol file , if flag then write the symbol
** with an underscore */
register char *sname;
register int flag;
{
if (flag)
putc('_', Symp);
while (*sname)
{
if (*sname == ' ')
putc(0, Symp);
else
putc(*sname, Symp);
sname++;
}
putc(0, Symp);
if (!flag)
putc(0, Symp);
}
/**************************** pass2 ****************************************/
pass2() /* translate code and write local symbols */
{
struct objfile *obj; /* which object file */
obj = File_root;
while (obj != NULL)
{
transcode(obj);
if (Do_table && !No_locals)
dump_locals(obj);
obj = obj->nextfile;
}
}
/************************ transcode ****************************************/
transcode(obj) /* translate code */
struct objfile *obj; /* object file to translate code from */
{
register int drctv; /* directive from obj file */
register int value; /* temporary variable */
int vrd; /* possible virtual register directive */
static struct outword wbuff;
ch_input(obj->fname, CODE);
while (morebytes()) /* continue reading code section until
** empty */
{
switch (drctv = getbyte())
{
case 000:
abswrite((WORD)0, (WORD)0);
break;
case 002:
relwrite((WORD)0, (WORD)0);
break;
case 004:
abswrite(getword(), (WORD)0);
break;
case 006:
relwrite(getword(), (WORD)0);
break;
case 010:
abswrite(Curr.val, Curr.rbits);
break;
case 014:
abswrite(Curr.val + getword(), Curr.rbits);
break;
case 020:
get_sym(&wbuff);
abswrite(wbuff.val, wbuff.rbits);
break;
case 022:
get_sym(&wbuff);
relwrite(wbuff.val, wbuff.rbits);
break;
case 030:
get_rc(&wbuff, obj, (char *)NULL);
abswrite(wbuff.val, wbuff.rbits);
break;
case 032:
get_rc(&wbuff, obj, (char *)NULL);
relwrite(wbuff.val, wbuff.rbits);
break;
case 034:
get_rc(&wbuff, obj, (char *)NULL);
abswrite(wbuff.val + getword(), wbuff.rbits);
break;
case 036:
get_rc(&wbuff, obj, (char *)NULL);
relwrite(wbuff.val + getword(), wbuff.rbits);
break;
case 040:
do040(obj);
break;
case 044:
wbuff.val = getword();
wbuff.rbits = 0;
vreg_oper(getbyte(), &wbuff);
break;
case 050:
if ((vrd = getbyte()) == 0)
linkseek(Curr.val, Curr.rbits);
else
vreg_oper(vrd, &Curr);
break;
case 054:
value = getword();
if ((vrd = getbyte()) == 0)
linkseek(Curr.val + value, Curr.rbits);
else
{
wbuff.val = Curr.val + value;
wbuff.rbits = Curr.rbits;
vreg_oper(vrd, &wbuff);
}
break;
case 060:
get_sym(&wbuff);
vreg_oper(getbyte(), &wbuff);
break;
case 070:
get_rc(&wbuff, obj, (char *)NULL);
if ((vrd = getbyte()) == 0)
{
linkseek(wbuff.val, wbuff.rbits);
Curr.val = wbuff.val;
Curr.rbits = wbuff.rbits;
}
else
vreg_oper(vrd, &wbuff);
break;
case 074:
get_rc(&wbuff, obj, (char *)NULL);
value = getword();
if ((vrd = getbyte()) == 0)
{
linkseek(wbuff.val + value, wbuff.rbits);
Curr.val = wbuff.val;
Curr.rbits = wbuff.rbits;
}
else
{
wbuff.val += value;
vreg_oper(vrd, &wbuff);
}
break;
case 0200:
bytewrite((char)0);
break;
case 0204:
bytewrite((char)getbyte());
break;
case 0220:
get_sym(&wbuff);
if (Do_bits && wbuff.rbits != 0)
uerror("unrelocatable byte expression");
bytewrite((char)(0377 & wbuff.val));
break;
default:
sprintf(Erstring, "bad code directive %03o", drctv);
lerror(Erstring);
}
}
}
/************************* abswrite *****************************************/
abswrite(value, rbits) /* write value in the out file */
register WORD value;
register WORD rbits; /* relocation bits */
{
Putw(value, Outp);
Glc += 2;
if (Do_bits)
Putw(rbits, Bitp);
}
/************************ relwrite ****************************************/
relwrite(value, rbits) /* write value in out file relative to
** global location counter */
register WORD value;
register WORD rbits;
{
Putw(value - Glc - 2, Outp);
Glc += 2;
if (Do_bits)
Putw((rbits == Curr.rbits) ? 0 : (rbits | 01), Bitp);
/* if the relocation bits for the word being written are
** the same as the current psect's then the word is an
** absolute offset, otherwise add 1 to the relocation
** bits to indicate relativity to the PC */
}
/************************* bytewrite *************************************/
bytewrite(value) /* write the byte in the out file */
char value;
{
putc(0377&value, Outp);
Glc++ ;
}
/************************* get_rc *****************************************/
get_rc(wbuff, obj, psname) /* place in wbuff the relocation constant and
** relocation bits of psname
** or if psname is NULL the psect whose
** name is in the input stream, and whose object
** file is pointed to by 'obj'. */
register struct outword *wbuff;
struct objfile *obj;
register char *psname;
{
char name[7]; /* the name of the psect */
register struct psect *ps;
/* if psname is NULL get name from input stream */
if (psname == NULL)
{
psname = name;
dc_symbol(psname);
}
ps = obj->psect_list;
while (strcmp(ps->name, psname)) /* while the strings are
** not equal */
{
ps = ps->obsame;
if (ps == NULL)
{
sprintf(Erstring, "rc not found for %s", psname);
lerror(Erstring);
}
}
wbuff->val = ps->rc;
wbuff->rbits = get_bits(ps->type);
}
/***************************** get_bits **********************************/
get_bits(attributes) /* get the out file symbol table bits and convert
** to relocation table bits */
register int attributes; /* the M11 attributes of a psect */
{
return (2 * (get_type(attributes) - 1));
}
/***************************** get_type ***********************************/
get_type(attr) /* decode the psect type into out file symbol table
** attribute word format */
register int attr;
{
if (!(attr & REL)) /* absolute */
return (01);
else if (attr & INS) /* text */
return (02);
else if (attr & BSS) /* bss */
return (04);
else /* data */
return (03);
}
/*************************** get_sym ***************************************/
get_sym(wbuff) /* get the value of the symbol in the input stream */
register struct outword *wbuff;
{
char sname[7]; /* the name of the symbol */
register struct symbol *sym;
register int cond; /* used for branching left
** or right */
int index; /* virtual register index */
dc_symbol(sname);
if (*sname != ' ')
{
sym = Sym_root;
while (sym != NULL)
{
if ((cond = strcmp(sname, sym->name)) == 0)
{
if (sym->type & DEF) /* if defined */
{
wbuff->val = sym->value;
wbuff->rbits = get_bits(sym->prsect->type);
return;
}
else if (Do_bits) /* set relocation bits
** for undefined symbol
** and return zero */
{
Undefineds = 1;
wbuff->val = 0;
wbuff->rbits = 020 * sym->t_numb + 010;
return;
}
else
{
sprintf(Erstring, "undefined symbol: %s", sname);
uerror(Erstring);
wbuff->val = 0;
wbuff->rbits = 0;
return;
}
}
else if (cond < 0)
sym = sym->left;
else
sym = sym->right;
}
/* symbol has not been found */
sprintf(Erstring, "%s not found", sname);
lerror(Erstring);
wbuff->val = 0;
wbuff->rbits = 0;
}
else /* virtual register */
{
index = sname[5] - 'a';
wbuff->val = Vreg[index].val;
wbuff->rbits = Vreg[index].rbits;
}
}
/*************************** vreg_oper *************************************/
vreg_oper(drctv, wbuff) /* preform an operation on a virtual register */
register int drctv; /* directive (operation) */
register struct outword *wbuff; /* source value and relocation bits */
{
register int index; /* index of destination register */
static char mess[] = "unrelocatable arithmetic expression";
index = getbyte() - 1;
if (index >= MAXREG)
{
uerror("expression involving global symbols too large");
index %= MAXREG;
}
switch(drctv)
{
case 0200:
Vreg[index].val = wbuff->val;
Vreg[index].rbits = wbuff->rbits;
break;
case 0201:
Vreg[index].val += wbuff->val;
if (Do_bits && Vreg[index].rbits && wbuff->rbits)
uerror(mess);
else
Vreg[index].rbits |= wbuff->rbits;
break;
case 0202:
Vreg[index].val -= wbuff->val;
if (Do_bits && wbuff->rbits)
if (Vreg[index].rbits == wbuff->rbits)
Vreg[index].rbits = 0;
else
uerror(mess);
break;
case 0203:
Vreg[index].val *= wbuff->val;
if (Do_bits)
uerror(mess);
break;
case 0204:
Vreg[index].val /= wbuff->val;
if (Do_bits)
uerror(mess);
break;
case 0205:
Vreg[index].val &= wbuff->val;
if (Do_bits)
uerror(mess);
break;
case 0206:
Vreg[index].val |= wbuff->val;
if (Do_bits)
uerror(mess);
break;
default:
sprintf(Erstring, "bad v.r. directive: %03o", drctv);
lerror(Erstring);
}
}
/************************** do040 ***************************************/
do040(obj) /* do 040 code directive */
register struct objfile *obj;
{
register int drctv;
register int index;
switch (drctv = getbyte())
{
case 001: /* low limit */
index = getbyte() - 1;
Vreg[index].val = Maxabs;
Vreg[index].rbits = 0;
if (Do_bits)
uerror("'.limit' directive not relocatable");
break;
case 002: /* high limit */
index = getbyte() - 1;
Vreg[index].val = R_counter;
Vreg[index].rbits = 0;
break;
case 003: /* ^pl */
case 004: /* ^ph */
p_limit(obj, drctv);
break;
case 0200: /* clear */
index = getbyte() - 1;
Vreg[index].val = Vreg[index].rbits = 0;
break;
case 0201: /* add zero */
index = getbyte();
break;
default:
sprintf(Erstring, "bad 040 directive %03o", drctv);
lerror(Erstring);
}
}
/************************* p_limit **************************************/
p_limit(obj, drctv) /* find the low or high limit of a psect */
struct objfile *obj;
int drctv;
{
register struct psect *ps;
register struct g_sect *gptr;
int cond;
register int index;
char pname[7];
dc_symbol(pname);
index = getbyte() - 1;
ps = obj->psect_list;
while (ps != NULL) /* try to find the psect in local link-list */
{
if ( !strcmp(pname, ps->name))
break;
ps = ps->obsame;
}
if (ps != NULL) /* if it was found in the local list */
{
while (ps->pssame != NULL) /* find bottom of sames, if any.
** see relocate() */
ps = ps->pssame;
}
else /* psect not a local so check global tree */
{
gptr = Gsect_root;
while (gptr != NULL)
{
if ( !(cond = strcmp(pname, gptr->name)))
{
if (gptr->last_sect->pssame == NULL)
/* the psect is solitary */
ps = gptr->last_sect;
else
/* last_psect points to the last psect
** in a plural link-list of sames.
** there is a psect after last_sect
** which contains the conglomeration
** of all the sames.
** see relocate() */
ps = gptr->last_sect->pssame;
break;
}
else if (cond < 0)
gptr = gptr->leftt;
else
gptr = gptr->rightt;
}
if (ps == NULL) /* psect not found */
{
sprintf(Erstring, "%s not found in ^p reference", pname);
uerror(Erstring);
Vreg[index].val = Vreg[index].rbits = 0;
return;
}
}
if (drctv == 003) /* low */
Vreg[index].val = ps->rc;
else /* high */
Vreg[index].val = ps->rc + ps->nbytes;
Vreg[index].rbits = get_bits(ps->type);
}
/*************************** linkseek *************************************/
linkseek(nlc, nrbits)
register WORD nlc; /* new location counter */
register WORD nrbits; /* new relocation bits */
{
long where;
Glc = nlc;
if (nrbits == 04) /* if data section add offset */
where = nlc + Seekoff + 020;
else
where = nlc + 020;
if (fseek(Outp, where, 0) == -1)
{
skerr: fprintf(stderr, "Fseek error\n");
bail_out();
}
if (Do_bits)
if (fseek(Bitp, where - 020L, 0) == -1)
goto skerr;
if (nrbits == 06) /* bss section about to be writen */
uerror("error: initialized data in bss psect");
}
/**************************** dump_locals ********************************/
# define MAXCONSTS 10
dump_locals(obj) /* dump local symbols */
struct objfile *obj;
{
int rconst[MAXCONSTS]; /* relocation constants */
int segment[MAXCONSTS]; /* segment type for out file */
struct psect *last;
struct psect *temp;
char sname[7]; /* symbol name */
char index;
char type;
int value;
int i;
/* fill rconst and segment arrays from the first MAXCONSTS psects */
temp = obj->psect_list;
i = 0;
while (temp != NULL && i < MAXCONSTS)
{
rconst[i] = temp->rc;
segment[i++] = get_type(temp->type);
temp = temp->obsame;
}
last = temp; /* (in case there are more psects than MAXCONSTS) */
/* write 'em */
ch_input(obj->fname, SYMBOLS);
while (morebytes())
{
dc_symbol(sname);
type = getbyte();
index = getbyte();
value = getword();
if (type & 001) /* if internal m11 symbol, forget it */
continue;
write_sym(sname, 0);
if (index >= MAXCONSTS)
{
temp = last;
for (i = MAXCONSTS; i < index; i++)
temp = temp->obsame;
Putw(get_type(temp->type), Symp);
Putw(value + temp->rc, Symp);
}
else
{
Putw(segment[index], Symp);
Putw(value + rconst[index], Symp);
}
}
}
/************************ uerror ******************************************/
uerror(mess) /* print user error message and increment Nerrors */
register char *mess;
{
Nerrors++;
fprintf(stderr, "%s\n", mess);
if (Do_map)
fprintf(Mapp, "%s\n", mess);
}
/************************** loose_ends ************************************/
loose_ends()
{
register c;
register int nbytes; /* number of bytes in out file symbol table */
if (Do_bits)
{
if (ferror(Bitp))
werror(Bitname);
Bitp = freopen(Bitname, "r", Bitp);
if (Bitp == NULL)
lerror("can't reopen relocation bits file");
fseek(Outp, (long) (Tex_size + Dat_size + 020L), 0);
while ((c = getc(Bitp)) != EOF)
putc(0377&c, Outp);
unlink(Bitname);
}
if (Do_table)
{
if (ferror(Symp))
werror(Symname);
Symp = freopen(Symname, "r", Symp);
if (Symp == NULL)
lerror("can't reopen symbol table file");
/* send r/w head to end of rbits or code section in out file */
fseek(Outp, (long) ((Tex_size + Dat_size) * (Do_bits + 1) + 020L), 0);
nbytes = 0;
while ((c = getc(Symp)) != EOF)
{
nbytes++;
putc(0377&c, Outp);
}
/* write size of symbol table */
fseek(Outp, 010L, 0);
Putw(nbytes, Outp);
unlink(Symname);
}
if (Do_map)
{
fprintf(Mapp, "errors detected: %d\n", Nerrors);
if (ferror(Mapp))
werror(Mapname);
fclose(Mapp);
if (Do_lpr_map)
execl("/usr/bin/lpr", "lpr", Mapname, 0);
}
if (ferror(Outp))
werror(Outname);
/* change out file to be executable if no errors */
chmod(Outname, Nerrors ? 0644 : 0755);
if (Nerrors || !Do_silent)
fprintf(stderr, "errors detected: %d\n", Nerrors);
exit(Nerrors ? 1 : 0);
}
/**************************** bail_out ***********************************/
bail_out() /* unlink any opened output file then exit */
{
if (Outp != NULL)
unlink(Outname);
if (Mapp != NULL)
unlink(Mapname);
if (Symp != NULL)
unlink(Symname);
if (Bitp != NULL)
unlink(Bitname);
exit(1);
}
/******************************** werror **********************************/
werror(fname) /* write error handler */
char *fname;
{
switch(errno) {
case ENOSPC: printf("No space left on device");
break;
case ENOENT: printf("No such file or directory");
break;
default:
break;
}
printf("file: %s (errno = %d)\n",fname,errno);
/* perror(fname); */
if (Symp != NULL)
unlink(Symname);
if (Bitp != NULL)
unlink(Bitname);
exit(1);
}
Putw(x, p)
FILE *p;
{
putc(x & 0377, p);
x >>= 8;
putc(x & 0377, p);
}