ack/util/ass/assci.c
2019-03-17 22:46:32 +08:00

1080 lines
19 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
*/
#include "ass00.h"
#include "assex.h"
#include "assci.h"
#include "asscm.h"
#include "assrl.h"
#include <em_mes.h>
#include <em_pseu.h>
#include <em_ptyp.h>
/*
* read compact code and fill in tables
*/
static int tabval;
static cons_t argval;
static int oksizes; /* MES EMX,.,. seen */
static enum m_type
{
CON, ROM, HOLBSS
} memtype;
static int valtype; /* Transfer of type information between
valsize, inpseudo and putval
*/
/* Forward declarations
* Yes, there is a better way to reorder to avoid these forward
* declarations, but its complex to do, so we use the lazy way
*/
static int getarg(int);
static cons_t getint(void);
static glob_t *getlab(int);
static char *getdig(char *, unsigned int);
static void make_string(unsigned int);
static void getstring(void);
static void inident(void);
static char *inproname(void);
static int needed(void);
static cons_t valsize(void);
static void setline(void);
static void inpseudo(int);
static void compact_line(void);
static cons_t maxval(int);
static void setsizes(void);
static void exchange(int, int);
static void doinsert(line_t *, int, int);
static void putval(void);
static void chkstart(void);
static void typealign(enum m_type);
static void sizealign(cons_t);
static void extconst(cons_t);
static void extbss(cons_t);
static void extloc(register locl_t *);
static void extglob(glob_t *, cons_t);
static void extpro(proc_t *);
static void extstring(void);
static void extxcon(int);
static long myatol(register char *);
static void extvcon(int);
static int table3(int i)
{
switch (i)
{
case sp_ilb1:
tabval = get8();
break;
case sp_dlb1:
make_string(get8());
i = sp_dnam;
break;
case sp_dlb2:
tabval = get16();
if (tabval < 0)
{
error("illegal data label .%d", tabval);
tabval = 0;
}
make_string(tabval);
i = sp_dnam;
break;
case sp_cst2:
argval = get16();
break;
case sp_ilb2:
tabval = get16();
if (tabval < 0)
{
error("illegal instruction label %d", tabval);
tabval = 0;
}
i = sp_ilb1;
break;
case sp_cst4:
i = sp_cst2;
argval = get32();
break;
case sp_dnam:
case sp_pnam:
inident();
break;
case sp_scon:
getstring();
break;
case sp_doff:
getarg(sym_ptyp);
getarg(cst_ptyp);
break;
case sp_icon:
case sp_ucon:
case sp_fcon:
getarg(cst_ptyp);
consiz = argval;
if (consiz < wordsize ? wordsize % consiz != 0 : consiz % wordsize != 0)
{
fatal("illegal object size");
}
getstring();
break;
}
return (i);
}
int get16(void)
{
register int l_byte, h_byte;
l_byte = get8();
h_byte = get8();
if (h_byte >= 128)
h_byte -= 256;
return l_byte | (h_byte * 256);
}
int getu16(void)
{
register int l_byte, h_byte;
l_byte = get8();
h_byte = get8();
return l_byte | (h_byte * 256);
}
cons_t get32(void)
{
register cons_t l;
register int h_byte;
l = get8();
l |= (unsigned) get8() * 256;
l |= get8() * 256L * 256L;
h_byte = get8();
if (h_byte >= 128)
h_byte -= 256;
return l | (h_byte * 256L * 256 * 256L);
}
static int table1(void)
{
register int i;
i = xget8();
if (i < sp_fmnem + sp_nmnem && i >= sp_fmnem)
{
tabval = i - sp_fmnem;
return (sp_fmnem);
}
if (i < sp_fpseu + sp_npseu && i >= sp_fpseu)
{
tabval = i;
return (sp_fpseu);
}
if (i < sp_filb0 + sp_nilb0 && i >= sp_filb0)
{
tabval = i - sp_filb0;
return (sp_ilb1);
}
return (table3(i));
}
static int table2(void)
{
register int i;
i = get8();
if (i < sp_fcst0 + sp_ncst0 && i >= sp_fcst0)
{
argval = i - sp_zcst0;
return (sp_cst2);
}
return (table3(i));
}
/* Read argument of instruction */
static int getarg(int typset)
{
register int t, argtyp;
argtyp = t = table2();
t -= sp_fspec;
t = 1 << t;
if ((typset & t) == 0)
error("bad argument type %d", argtyp);
return (argtyp);
}
static cons_t getint(void)
{
getarg(cst_ptyp);
return (argval);
}
static glob_t *getlab(int status)
{
getarg(sym_ptyp);
return (glo2lookup(string, status));
}
static char *getdig(char *str, unsigned int number)
{
register int remain;
remain = number % 10;
number /= 10;
if (number)
str = getdig(str, number);
*str++ = '0' + remain;
return str;
}
static void make_string(unsigned int n)
{
string[0] = '.';
*getdig(&string[1], n) = 0;
}
static void getstring(void)
{
register char *p;
register int n;
getarg(cst_ptyp);
if (argval < 0 || argval >= MAXSTRING - 1)
fatal("string/identifier too long");
strlngth = n = argval;
p = string;
while (--n >= 0)
*p++ = get8();
*p = 0;
}
static void inident(void)
{
getstring();
}
static char *inproname(void)
{
getarg(ptyp(sp_pnam));
return (string);
}
static int needed(void)
{
register glob_t *g;
register proc_t *p;
for (;;)
{
switch (table2())
{
case sp_dnam:
if ( (g = xglolookup(string, SEARCHING)) != NULL)
{
if ((g->g_status & DEF) != 0)
continue;
}
else
continue;
break;
case sp_pnam:
p = searchproc(string, xprocs, oursize->n_xproc);
if (p->p_name)
{
if ((p->p_status & DEF) != 0)
continue;
}
else
continue;
break;
default:
error("Unexpected byte after ms_ext");
case sp_cend:
return FALSE;
}
while (table2() != sp_cend)
;
return TRUE;
}
}
static cons_t valsize(void)
{
switch (valtype = table2())
{ /* valtype is used by putval and inpseudo */
case sp_cst2:
return wordsize;
case sp_ilb1:
case sp_dnam:
case sp_doff:
case sp_pnam:
return ptrsize;
case sp_scon:
return strlngth;
case sp_fcon:
case sp_icon:
case sp_ucon:
return consiz;
case sp_cend:
return 0;
default:
fatal("value expected");
return 0;
/* NOTREACHED */
}
}
void newline(int type)
{
register line_t *n_lnp;
if (type > VALLOW)
type = VALLOW;
n_lnp = lnp_cast getarea((unsigned) linesize[type]);
n_lnp->l_next = pstate.s_fline;
pstate.s_fline = n_lnp;
n_lnp->type1 = type;
n_lnp->opoff = NO_OFF;
}
static void setline(void)
{
/* Get line numbers correct */
if (pstate.s_fline &&
ctrunc(pstate.s_fline->instr_num) == sp_fpseu)
{
/* Already one present */
pstate.s_fline->ad.ad_ln.ln_extra++;
}
else
{
newline(LINES);
pstate.s_fline->instr_num = sp_fpseu;
pstate.s_fline->ad.ad_ln.ln_extra = 0;
pstate.s_fline->ad.ad_ln.ln_first = line_num;
}
}
static void inpseudo(int instr_no)
{
cons_t cst;
register proc_t *prptr;
cons_t objsize;
cons_t par1, par2;
register char *pars;
/*
* get operands of pseudo (if needed) and process it.
*/
switch (ctrunc(instr_no))
{
case ps_bss:
chkstart();
typealign(HOLBSS);
cst = getint(); /* number of bytes */
extbss(cst);
break;
case ps_hol:
chkstart();
typealign(HOLBSS);
holsize = getint();
holbase = databytes;
extbss(holsize);
break;
case ps_rom:
case ps_con:
chkstart();
typealign( ctrunc(instr_no) == ps_rom ? ROM : CON);
while ((objsize = valsize()) != 0)
{
if (valtype != sp_scon)
sizealign(objsize);
putval();
databytes += objsize;
}
break;
case ps_end:
prptr = pstate.s_curpro;
if (prptr == prp_cast 0)
fatal("unexpected END");
proctab[prptr->p_num].pr_off = textbytes;
if (procflag)
{
printf("%6lu\t%6lo\t%5d\t%-12s\t%s", textbytes, textbytes,
prptr->p_num, prptr->p_name, curfile);
if (archmode)
printf("(%.14s)", archhdr.ar_name);
printf("\n");
}
par2 = proctab[prptr->p_num].pr_loc;
if (getarg(cst_ptyp | ptyp(sp_cend)) == sp_cend)
{
if (par2 == -1)
{
fatal("size of local area unspecified");
}
}
else
{
if (par2 != -1 && argval != par2)
{
fatal("inconsistent local area size");
}
proctab[prptr->p_num].pr_loc = argval;
}
setline();
do_proc();
break;
case ps_mes:
switch ( int_cast getint())
{
case ms_err:
error("module with error");
ertrap();
/* NOTREACHED */
case ms_emx:
if (oksizes)
{
if (wordsize != getint())
{
fatal("Inconsistent word size");
}
if (ptrsize != getint())
{
fatal("Inconsistent pointer size");
}
}
else
{
oksizes++;
wordsize = getint();
ptrsize = getint();
if (wordsize != 2 && wordsize != 4)
{
fatal("Illegal word size");
}
if (ptrsize != 2 && ptrsize != 4)
{
fatal("Illegal pointer size");
}
setsizes();
}
++mod_sizes;
break;
case ms_src:
break;
case ms_flt:
intflags |= 020;
break; /*floats used*/
case ms_ext:
if (!needed())
{
eof_seen++;
}
if (line_num > 2)
{
werror("mes ms_ext must be first or second pseudo");
}
return;
}
while (table2() != sp_cend)
;
break;
case ps_exc:
par1 = getint();
par2 = getint();
if (par1 == 0 || par2 == 0)
break;
exchange((int) par2, (int) par1);
break;
case ps_exa:
getlab(EXTERNING);
break;
case ps_ina:
getlab(INTERNING);
break;
case ps_pro:
chkstart();
initproc();
pars = inproname();
if (getarg(cst_ptyp | ptyp(sp_cend)) == sp_cend)
{
par2 = -1;
}
else
{
par2 = argval;
}
prptr = prolookup(pars, PRO_DEF);
proctab[prptr->p_num].pr_loc = par2;
pstate.s_curpro = prptr;
break;
case ps_inp:
prptr = prolookup(inproname(), PRO_INT);
break;
case ps_exp:
prptr = prolookup(inproname(), PRO_EXT);
break;
default:
fatal("unknown pseudo");
}
if (!mod_sizes)
fatal("Missing size specification");
if (databytes > maxadr)
error("Maximum data area size exceeded");
}
/*
* read one "line" of compact code.
*/
static void compact_line(void)
{
register int instr_no;
curglosym = 0;
switch (table1())
{
default:
fatal("unknown byte at start of \"line\""); /* NOTREACHED */
case EOF:
eof_seen++;
while (pstate.s_prevstat != pst_cast 0)
{
error("missing end");
do_proc();
}
return;
case sp_fmnem:
if (pstate.s_curpro == prp_cast 0)
{
error("instruction outside procedure");
}
instr_no = tabval;
if ((em_flag[instr_no] & EM_PAR) == PAR_NO)
{
newline(MISSING);
pstate.s_fline->instr_num = instr_no;
return;
}
/*
* This instruction should have an opcode, so read it after
* this switch.
*/
break;
case sp_dnam:
chkstart();
align(wordsize);
curglosym = glo2lookup(string, DEFINING);
curglosym->g_val.g_addr = databytes;
lastglosym = curglosym;
setline();
line_num++;
if (table1() != sp_fpseu)
fatal("no pseudo after data label");
case sp_fpseu:
inpseudo(tabval);
setline();
return;
case sp_ilb1:
newline(LOCSYM);
pstate.s_fline->ad.ad_lp = loclookup(tabval, DEFINING);
pstate.s_fline->instr_num = sp_ilb1;
return;
}
/*
* Now process argument
*/
switch (table2())
{
default:
fatal("unknown byte at start of argument"); /*NOTREACHED*/
case sp_cst2:
if ((em_flag[instr_no] & EM_PAR) == PAR_B)
{
/* value indicates a label */
newline(LOCSYM);
pstate.s_fline->ad.ad_lp = loclookup((int) argval, OCCURRING);
}
else
{
if (argval >= VAL1(VALLOW) && argval <= VAL1(VALHIGH))
{
newline(VALLOW);
pstate.s_fline->type1 = argval + VALMID;
}
else
{
newline(CONST);
pstate.s_fline->ad.ad_i = argval;
pstate.s_fline->type1 = CONST;
}
}
break;
case sp_ilb1:
newline(LOCSYM);
pstate.s_fline->ad.ad_lp = loclookup(tabval, OCCURRING);
break;
case sp_dnam:
newline(GLOSYM);
pstate.s_fline->ad.ad_gp = glo2lookup(string, OCCURRING);
break;
case sp_pnam:
newline(PROCNAME);
pstate.s_fline->ad.ad_pp = prolookup(string, PRO_OCC);
break;
case sp_cend:
if ((em_flag[instr_no] & EM_PAR) != PAR_W)
{
fatal("missing operand");
}
newline(MISSING);
break;
case sp_doff:
newline(GLOOFF);
pstate.s_fline->ad.ad_df.df_i = argval;
pstate.s_fline->ad.ad_df.df_gp = glo2lookup(string, OCCURRING);
break;
}
pstate.s_fline->instr_num = instr_no;
return;
}
void read_compact(void)
{
init_module();
pass = 1;
eof_seen = 0;
do
{
compact_line();
line_num++;
} while (!eof_seen);
endproc(); /* Throw away unwanted garbage */
if (mod_sizes)
end_module();
/* mod_sizes is only false for rejected library modules */
}
static cons_t maxval(int bits)
{
/* find the maximum positive value,
* fitting in 'bits' bits AND
* fitting in a 'cons_t' .
*/
cons_t val;
val = 1;
while (bits--)
{
val <<= 1;
if (val < 0)
return ~val;
}
return val - 1;
}
static void setsizes(void)
{
maxadr = maxval(8 * ptrsize);
maxint = maxval(8 * wordsize - 1);
maxunsig = maxval(8 * wordsize);
maxdint = maxval(2 * 8 * wordsize - 1);
maxdunsig = maxval(2 * 8 * wordsize);
}
static void exchange(int p1, int p2)
{
int size, line;
register line_t *t_lnp, *a_lnp, *b_lnp;
/* Since the lines are linked backwards it is easy
* to count the number of lines backwards.
* Each instr counts for 1, each pseudo for ln_extra + 1.
* The line numbers in error messages etc. are INCORRECT
* If exc's are used.
*/
line = line_num;
size = 0;
newline(LINES);
a_lnp = pstate.s_fline;
a_lnp->instr_num = sp_fpseu;
a_lnp->ad.ad_ln.ln_first = line;
a_lnp->ad.ad_ln.ln_extra = -1;
for (; a_lnp; a_lnp = a_lnp->l_next)
{
line--;
switch (ctrunc(a_lnp->instr_num))
{
case sp_fpseu:
line = a_lnp->ad.ad_ln.ln_first;
size += a_lnp->ad.ad_ln.ln_extra;
break;
case sp_ilb1:
a_lnp->ad.ad_lp->l_min -= p2;
break;
}
size++;
if (size >= p1)
break;
}
if ((size -= p1) > 0)
{
if ( ctrunc(a_lnp->instr_num) != sp_fpseu)
{
fatal("EXC inconsistency");
}
doinsert(a_lnp, line, size - 1);
a_lnp->ad.ad_ln.ln_extra -= size;
size = 0;
}
else
{
if (a_lnp)
doinsert(a_lnp, line, -1);
}
b_lnp = a_lnp;
while (b_lnp)
{
b_lnp = b_lnp->l_next;
line--;
switch (ctrunc(b_lnp->instr_num))
{
case sp_fpseu:
size += b_lnp->ad.ad_ln.ln_extra;
line = b_lnp->ad.ad_ln.ln_first;
break;
case sp_ilb1:
b_lnp->ad.ad_lp->l_min += p1;
break;
}
size++;
if (size >= p2)
break;
}
if (!b_lnp)
{ /* if a_lnp==0, so is b_lnp */
fatal("Cannot perform exchange");
}
if ((size -= p2) > 0)
{
if ( ctrunc(b_lnp->instr_num) != sp_fpseu)
{
fatal("EXC inconsistency");
}
doinsert(b_lnp, line, size - 1);
b_lnp->ad.ad_ln.ln_extra -= size;
}
else
{
doinsert(b_lnp, line, -1);
}
t_lnp = b_lnp->l_next;
b_lnp->l_next = pstate.s_fline;
pstate.s_fline = a_lnp->l_next;
a_lnp->l_next = t_lnp;
}
static void doinsert(line_t *lnp, int first, int extra)
{
/* Beware : s_fline will be clobbered and restored */
register line_t *t_lnp;
t_lnp = pstate.s_fline;
pstate.s_fline = lnp->l_next;
newline(LINES);
pstate.s_fline->instr_num = sp_fpseu;
pstate.s_fline->ad.ad_ln.ln_first = first;
pstate.s_fline->ad.ad_ln.ln_extra = extra;
lnp->l_next = pstate.s_fline;
pstate.s_fline = t_lnp; /* restore */
}
static void putval(void)
{
switch (valtype)
{
case sp_cst2:
extconst(argval);
return;
case sp_ilb1:
extloc(loclookup(tabval, OCCURRING));
return;
case sp_dnam:
extglob(glo2lookup(string, OCCURRING), (cons_t) 0);
return;
case sp_doff:
extglob(glo2lookup(string, OCCURRING), argval);
return;
case sp_pnam:
extpro(prolookup(string, PRO_OCC));
return;
case sp_scon:
extstring();
return;
case sp_fcon:
extxcon(DATA_FCON);
return;
case sp_icon:
extvcon(DATA_ICON);
return;
case sp_ucon:
extvcon(DATA_UCON);
return;
default:
fatal("putval notreached");
/* NOTREACHED */
}
}
static void chkstart(void)
{
static int absout = 0;
if (absout)
return;
if (!oksizes)
fatal("missing size specification");
set_mode(DATA_CONST);
extconst((cons_t) 0);
databytes = wordsize;
set_mode(DATA_REP);
if (wordsize < ABSSIZE)
{
register int factor = ABSSIZE / wordsize - 1;
extadr((cons_t) factor);
databytes += factor * wordsize;
}
absout++;
memtype = HOLBSS;
}
static void typealign(enum m_type new)
{
if (memtype == new)
return;
align(wordsize);
memtype = new;
}
static void sizealign(cons_t size)
{
align(size > wordsize ? wordsize : (int) size);
}
void align(int size)
{
while (databytes % size)
{
set_mode(DATA_BYTES);
ext8(0);
databytes++;
}
}
static void extconst(cons_t n)
{
set_mode(DATA_CONST);
extword(n);
}
static void extbss(cons_t n)
{
cons_t objsize, amount;
cons_t sv_argval;
int sv_tabval;
if (n <= 0)
{
if (n < 0)
werror("negative bss/hol size");
if (table2() == sp_cend || table2() == sp_cend)
{
werror("Unexpected end-of-line");
}
return;
}
set_mode(DATA_NUL); /* flush descriptor */
objsize = valsize();
if (objsize == 0)
{
werror("Unexpected end-of-line");
return;
}
if (n % objsize != 0)
error("BSS/HOL incompatible sizes");
sv_tabval = tabval;
sv_argval = argval;
getarg(sp_cst2);
if (argval < 0 || argval > 1)
error("illegal last argument");
databytes += n;
if (argval == 1)
{
tabval = sv_tabval;
argval = sv_argval;
putval();
amount = n / objsize;
if (amount > 1)
{
set_mode(DATA_REP);
extadr(amount - 1);
}
}
else
{
n = (n + wordsize - 1) / wordsize;
while (n > MAXBYTE)
{
set_mode(DATA_BSS);
ext8(MAXBYTE);
n -= MAXBYTE;
}
set_mode(DATA_BSS);
ext8((int) n);
}
}
static void extloc(register locl_t *lbp)
{
/*
* assemble a pointer constant from a local label.
* For example con *1
*/
set_mode(DATA_IPTR);
data_reloc( chp_cast lbp, dataoff, RELLOC);
extadr((cons_t) 0);
}
static void extglob(glob_t *agbp, cons_t off)
{
register glob_t *gbp;
/*
* generate a word of data that is defined by a global symbol.
* Various relocation has to be prepared here in some cases
*/
gbp = agbp;
set_mode(DATA_DPTR);
if (gbp->g_status & DEF)
{
extadr(gbp->g_val.g_addr + off);
}
else
{
data_reloc( chp_cast gbp, dataoff, RELGLO);
extadr(off);
}
}
static void extpro(proc_t *aprp)
{
/*
* generate a address that is defined by a procedure descriptor.
*/
consiz = ptrsize;
set_mode(DATA_UCON);
extarb((int) ptrsize, (long) (aprp->p_num));
}
static void extstring(void )
{
register char *s;
register int n;
/*
* generate data for a string.
*/
for (n = strlngth, s = string; n--;)
{
set_mode(DATA_BYTES);
ext8(*s++);
}
return;
}
static void extxcon(int header)
{
register char *s;
register int n;
/*
* generate data for a floating constant initialized by a string.
*/
set_mode(header);
s = string;
for (n = strlngth; n--;)
{
if (*s == 0)
error("Zero byte in initializer");
ext8(*s++);
}
ext8(0);
return;
}
/* Added atol() that ignores overflow. --Ceriel */
static long myatol(register char *s)
{
register long total = 0;
register unsigned digit;
int minus = 0;
while (*s == ' ' || *s == '\t')
s++;
if (*s == '+')
s++;
else if (*s == '-')
{
s++;
minus = 1;
}
while ((digit = *s++ - '0') < 10)
{
total *= 10;
total += digit;
}
return (minus ? -total : total);
}
static void extvcon(int header)
{
/*
* generate data for a constant initialized by a string.
*/
set_mode(header);
if (consiz > 4)
{
error("Size of initializer exceeds loader capability");
}
extarb((int) consiz, myatol(string));
return;
}