ack/util/ass/ass00.c

656 lines
12 KiB
C
Raw Normal View History

2019-03-17 14:41:25 +00:00
#include <string.h>
#include <stddef.h>
1984-07-12 12:48:33 +00:00
#include "ass00.h"
#include "assex.h"
2019-03-17 14:41:25 +00:00
#include "assci.h"
#include "asscm.h"
#include "assrl.h"
1984-07-12 12:48:33 +00:00
/*
1987-03-10 01:26:51 +00:00
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
1984-07-12 12:48:33 +00:00
*
*/
2019-03-17 14:41:25 +00:00
char oflag;
static int memflg;
/* Forward declarations. */
static siz_t* getsizes(char *);
static void getcore(void);
static void argument(char *);
static void flags(char *);
static void skipentry(void);
static void enmd_pro(void);
static void enmd_glo(void);
static void archive(void);
static void finish_up(void);
static void check_def(void);
static void c_print(void);
static void c_dprint(char *, char*);
/* External definitions */
void pass_3(void);
void pass_4(void);
void pass_5(void);
1984-11-08 12:08:31 +00:00
1984-07-12 12:48:33 +00:00
/*
2019-03-17 14:41:25 +00:00
** Main routine of EM1-assembler/loader
*/
1984-07-12 12:48:33 +00:00
2019-03-17 14:41:25 +00:00
int main(int argc, char **argv)
1984-07-12 12:48:33 +00:00
{
/*
* Usage: ass [-[d][p][m][u][U]] [-s(s/m/l/x)] [ [file] [flag] ] ...
1984-07-12 12:48:33 +00:00
* The d flag can be repeated several times, resulting in more
* debugging information.
*/
2019-03-17 14:41:25 +00:00
char workspace[6000];
register char *cp;
register int argno;
1984-07-12 12:48:33 +00:00
progname = argv[0];
2019-03-17 14:41:25 +00:00
for (cp = argv[0]; *cp;)
if (*cp++ == '/')
progname = cp;
for (argno = 1; argno < argc; argno++)
{
if (argv[argno][0] == '-' && LC(argv[argno][1]) == 's')
{
oursize = getsizes(&argv[argno][2]);
break;
1984-07-12 12:48:33 +00:00
}
}
/* A piece of the interpreter's stack frame is used as
2019-03-17 14:41:25 +00:00
free area initially */
freearea((area_t) workspace, (unsigned) sizeof workspace);
1984-07-12 12:48:33 +00:00
getcore();
init_files();
init_vars();
2019-03-17 14:41:25 +00:00
while (--argc)
1984-07-12 12:48:33 +00:00
argument(*++argv);
finish_up();
2019-03-17 14:41:25 +00:00
exit(nerrors != 0);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void getcore(void)
{
register siz_t *p;
siz_t bytes;
2019-03-17 14:41:25 +00:00
register unsigned n;
register char *base;
1984-07-12 12:48:33 +00:00
/*
* xglobs[] should be located in front of mglobs[], see upd_reloc()
*/
2019-03-17 14:41:25 +00:00
p = oursize;
n = 0;
1984-07-12 12:48:33 +00:00
n += (bytes.n_glab = p->n_glab * (sizeof *xglobs));
n += (bytes.n_mlab = p->n_mlab * (sizeof *mglobs));
n += (bytes.n_mproc = p->n_mproc * (sizeof *mprocs));
n += (bytes.n_xproc = p->n_xproc * (sizeof *xprocs));
n += (bytes.n_proc = p->n_proc * (sizeof *proctab));
base = getarea(n);
2019-03-17 14:41:25 +00:00
memset(base, 0, n);
xglobs = gbp_cast base;
base += bytes.n_glab;
mglobs = gbp_cast base;
base += bytes.n_mlab;
mprocs = prp_cast base;
base += bytes.n_mproc;
xprocs = prp_cast base;
base += bytes.n_xproc;
proctab = ptp_cast base;
base += bytes.n_proc;
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static siz_t* getsizes(char *str)
{
1984-07-12 12:48:33 +00:00
/*
1989-11-17 16:53:53 +00:00
* accepts -ss (small), -sm (medium), -sl (large), -sx (extra large)
1984-07-12 12:48:33 +00:00
*/
2019-03-17 14:41:25 +00:00
switch (LC(*str))
{
default:
error("bad size option %s", str);
case 's':
return &sizes[0];
break;
case 'm':
return &sizes[1];
break;
case 'l':
return &sizes[2];
break;
case 'x':
return &sizes[3];
break;
1984-07-12 12:48:33 +00:00
}
}
2019-03-17 14:41:25 +00:00
/*
* This routine decides what to do with each argument.
* It recognises flags and modules.
* Furthermore, it knows a library when it sees it and
* call archive() to split it apart.
*/
static void argument(char *arg)
{
register int w;
1984-07-12 12:48:33 +00:00
2019-03-17 14:41:25 +00:00
if (oflag)
{
1984-07-12 12:48:33 +00:00
eout = arg;
2019-03-17 14:41:25 +00:00
oflag = 0;
1984-07-12 12:48:33 +00:00
return;
}
2019-03-17 14:41:25 +00:00
if (*arg == '-')
{
1984-07-12 12:48:33 +00:00
flags(arg);
return;
}
2019-03-17 14:41:25 +00:00
curfile = arg; /* for error messages etc. */
if ((ifile = fopen(arg, "r")) == NULL)
{
error("can't open %s", arg);
1984-07-12 12:48:33 +00:00
return;
}
inpoff = 2;
2019-03-17 14:41:25 +00:00
if ((w = getu16()) == sp_magic)
1984-07-12 12:48:33 +00:00
read_compact();
2019-03-17 14:41:25 +00:00
else if (w == ARMAG || w == AALMAG)
{
1984-07-12 12:48:33 +00:00
archmode = TRUE;
archive();
archmode = FALSE;
2019-03-17 14:41:25 +00:00
}
else
error("%s: bad format", arg);
1984-07-12 12:48:33 +00:00
if (fclose(ifile) == EOF)
2019-03-17 14:41:25 +00:00
{
}
1984-07-12 12:48:33 +00:00
}
/*
2019-03-17 14:41:25 +00:00
** process flag arguments
*/
static void flags(char *arg)
1984-07-12 12:48:33 +00:00
{
2019-03-17 14:41:25 +00:00
register char *argp;
register int on;
1984-07-12 12:48:33 +00:00
argp = arg;
while (*++argp)
{
2019-03-17 14:41:25 +00:00
switch (LC(*argp))
1984-07-12 12:48:33 +00:00
{
2019-03-17 14:41:25 +00:00
case 'd':
d_flag++;
break;
case 'r':
r_flag++;
break;
case 's':
return; /* s-flag is already scanned */
1984-07-12 12:48:33 +00:00
#ifdef MEMUSE
2019-03-17 14:41:25 +00:00
case 'm':
memflg++;
break;
1984-07-12 12:48:33 +00:00
#endif
2019-03-17 14:41:25 +00:00
case 'p':
++procflag;
break;
1984-07-12 12:48:33 +00:00
#ifdef DUMP
2019-03-17 14:41:25 +00:00
case 'u':
++c_flag;
break;
1984-07-12 12:48:33 +00:00
#endif
2019-03-17 14:41:25 +00:00
case 'o':
++oflag;
break;
case 'w':
++wflag;
break;
1984-07-12 12:48:33 +00:00
#ifdef JOHAN
2019-03-17 14:41:25 +00:00
case 'j':
++jflag;
break;
1984-07-12 12:48:33 +00:00
#endif
2019-03-17 14:41:25 +00:00
case 'U':
++Uflag;
break;
case '-':
case '+':
on = (*argp == '+');
while (*++argp)
switch (LC(*argp))
{
case 't':
if (on)
intflags |= 01;
else
intflags &= ~01;
break;
case 'p':
if (on)
intflags |= 02;
else
intflags &= ~02;
break;
case 'f':
if (on)
intflags |= 04;
else
intflags &= ~04;
break;
case 'c':
if (on)
intflags |= 010;
else
intflags &= ~010;
case 'e':
if (on)
intflags |= 040;
else
intflags &= ~040;
break;
1984-07-12 12:48:33 +00:00
default:
2019-03-17 14:41:25 +00:00
error("bad interpreter option %s", argp);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
--argp;
break;
default:
error("bad flag %s", argp);
break;
1984-07-12 12:48:33 +00:00
}
}
}
2019-03-17 14:41:25 +00:00
void do_proc(void)
{
1984-07-12 12:48:33 +00:00
/* One procedure has been read and will be processed.
*
* NOTE: The numbers of the passes, 1 3 4 and 5, are a remainder
* of ancient times.
*/
2019-03-17 14:41:25 +00:00
dump(1);
if (memflg > 2)
memuse();
pass_3();
dump(3);
pass_4();
dump(4);
pass_5();
if (memflg > 2)
memuse();
endproc();
if (memflg > 1)
memuse();
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void archive(void)
{
register int i;
1984-07-12 12:48:33 +00:00
register char *p;
/*
* Read a library.
* The format of the libary used is that of a UNIX/V7(PDP)-archive.
*
* NOTE: If it was allowed for an archive to contain
* obligatory modules as well as optionals,
* it would not be possible to speed up things a bit
* by stopping when all references are resolved.
* This is the only reason.
*/
2019-03-17 14:41:25 +00:00
for (;;)
{
if (unresolved == 0)
{ /* no use for this library anymore */
1984-07-12 12:48:33 +00:00
return;
}
p = chp_cast &archhdr;
2019-03-17 14:41:25 +00:00
if ((i = fgetc(ifile)) == EOF)
{
1984-07-12 12:48:33 +00:00
return;
}
*p++ = i;
2019-03-17 14:41:25 +00:00
for (i = 1; i < sizeof archhdr.ar_name; i++)
1984-07-12 12:48:33 +00:00
*p++ = get8();
2019-03-17 14:41:25 +00:00
for (i = 0; i < 8; i++)
get8();
archhdr.ar_size = ((long) get16() << 16);
archhdr.ar_size += getu16();
inpoff = 0;
libeof = archhdr.ar_size;
1984-07-12 12:48:33 +00:00
/*
* UNIX archiveheader is read now, now process the contents
* of it. Note that recursive archives are not implemented.
*
* The variable libeof is used by get8() to check
* whether or not we try to pass the library-boundary.
*/
2019-03-17 14:41:25 +00:00
if (getu16() == sp_magic)
{
1984-07-12 12:48:33 +00:00
read_compact();
2019-03-17 14:41:25 +00:00
}
else
1984-07-12 12:48:33 +00:00
error("bad archive entry");
skipentry();
libeof = 0;
2019-03-17 14:41:25 +00:00
} /* up to the next entry */
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void skipentry(void)
{
1984-07-12 12:48:33 +00:00
/*
* for some reason the rest of this library entry needs to be
* skipped. Do that now.
*/
2019-03-17 14:41:25 +00:00
while (inpoff < libeof)
1984-07-12 12:48:33 +00:00
get8();
2019-03-17 14:41:25 +00:00
if (odd(libeof)) /* archive entries are evensized */
if (fgetc(ifile) == EOF) /* except maybe the last one */
1984-07-12 12:48:33 +00:00
;
}
2019-03-17 14:41:25 +00:00
void init_vars(void)
{
1984-07-12 12:48:33 +00:00
/*
* A small collection of variables is initialized.
* This occurs only for those that couldn't be initialized
* at compile-time.
*/
}
2019-03-17 14:41:25 +00:00
void init_files(void)
{
1984-07-12 12:48:33 +00:00
/*
* The temporary files on which text and data are kept
* during assembly are set up here.
*/
2019-03-17 14:41:25 +00:00
1984-07-12 12:48:33 +00:00
/*
* The function tmpfil() returns a file-descriptor
* of a file that is valid for reading and writing.
* It has the nice property of generating truly unique names.
*/
2019-03-17 14:41:25 +00:00
tfile = fopen(tmpfil(), "w+");
dfile = fopen(tmpfil(), "w+");
rtfile = fopen(tmpfil(), "w+");
rdfile = fopen(tmpfil(), "w+");
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
void initproc(void)
{
1984-07-12 12:48:33 +00:00
/*
* Called at the start of assembly of every procedure.
*/
2019-03-17 14:41:25 +00:00
stat_t *prevstate;
prevstate = pst_cast getarea(sizeof pstate);
*prevstate = pstate;
pstate.s_prevstat = prevstate;
pstate.s_curpro = prp_cast 0;
pstate.s_fline = lnp_cast 0;
pstate.s_fdata = l_data;
pstate.s_locl = (locl_t (*)[]) getarea(
LOCLABSIZE * sizeof((*(pstate.s_locl))[0]));
memset(chp_cast pstate.s_locl, 0,
LOCLABSIZE * (unsigned) sizeof((*(pstate.s_locl))[0]));
if (memflg > 2)
memuse();
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
void endproc(void)
{
1984-07-12 12:48:33 +00:00
/* Throw the contents of the line and local label table away */
register line_t *lnp1;
2019-03-17 14:41:25 +00:00
register locl_t *lbhead, *lbp, *lbp_next;
register int kind;
1984-07-12 12:48:33 +00:00
register stat_t *prevstate;
2019-03-17 14:41:25 +00:00
while ((lnp1 = pstate.s_fline) != NULL)
{
pstate.s_fline = lnp1->l_next;
kind = lnp1->type1;
if (kind > VALLOW)
kind = VALLOW;
freearea((area_t) lnp1, (unsigned) linesize[kind]);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
prevstate = pstate.s_prevstat;
if (prevstate != pst_cast 0)
{
for (lbhead = *pstate.s_locl; lbhead < &(*pstate.s_locl)[LOCLABSIZE];
lbhead++)
{
for (lbp = lbhead->l_chain; lbp != lbp_cast 0; lbp = lbp_next)
{
lbp_next = lbp->l_chain;
freearea((area_t) lbp, (unsigned) sizeof *lbp);
1984-07-12 12:48:33 +00:00
}
}
2019-03-17 14:41:25 +00:00
freearea((area_t) (*pstate.s_locl),
LOCLABSIZE * (sizeof((*pstate.s_locl)[0])));
pstate = *prevstate;
freearea((area_t) prevstate, (unsigned) sizeof *prevstate);
1984-07-12 12:48:33 +00:00
}
}
2019-03-17 14:41:25 +00:00
void init_module(void)
{
1984-07-12 12:48:33 +00:00
/*
* Called at the start of every module.
*/
2019-03-17 14:41:25 +00:00
holbase = 0;
1984-07-12 12:48:33 +00:00
line_num = 1;
mod_sizes = 0;
}
2019-03-17 14:41:25 +00:00
void end_module(void)
{
1984-07-12 12:48:33 +00:00
/*
* Finish a module.
* Work to be done is mainly forgetting of local names,
* and remembering of those that will live during assembly.
*/
2019-03-17 14:41:25 +00:00
align(wordsize);
set_mode(DATA_NUL);
1984-07-12 12:48:33 +00:00
dump(100);
enmd_pro();
enmd_glo();
2019-03-17 14:41:25 +00:00
if (memflg)
memuse();
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void enmd_pro(void)
{
register proc_t *p, *limit;
1984-07-12 12:48:33 +00:00
/*
* Check that all local procedures have been defined,
* and forget them immediately thereafter.
*/
limit = &mprocs[oursize->n_mproc];
2019-03-17 14:41:25 +00:00
for (p = mprocs; p < limit; p++)
{
1987-04-09 14:15:25 +00:00
if (p->p_name == 0)
1984-07-12 12:48:33 +00:00
continue;
2019-03-17 14:41:25 +00:00
if ((p->p_status & DEF) == 0)
error("undefined local procedure '%s'", p->p_name);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
memset(chp_cast mprocs, 0, (limit - mprocs) * (unsigned ) sizeof *mprocs);
1984-07-12 12:48:33 +00:00
/* Clobber all flags indicating that external procedures
* were used in this module.
*/
limit = &xprocs[oursize->n_xproc];
2019-03-17 14:41:25 +00:00
for (p = xprocs; p < limit; p++)
{
p->p_status &= ~EXT;
1984-07-12 12:48:33 +00:00
}
}
2019-03-17 14:41:25 +00:00
static void enmd_glo(void)
{
register glob_t *mg, *xg, *limit;
1984-07-12 12:48:33 +00:00
/*
* Tougher then enmd_pro().
* Check all the symbols used in this module that are
* not to be forgotten immediately.
* A difficulty arises here:
* In the tables textreloc[] and datareloc[]
* pointers are used to identify the symbols concerned.
* These pointers point into mglobs[].
* Since at the end of assembly only the value of xglobs[]
* is defined, these pointers have to be changed.
* upd_reloc() takes care of this.
*/
limit = &mglobs[oursize->n_mlab];
2019-03-17 14:41:25 +00:00
for (mg = mglobs; mg < limit; mg++)
{
1987-04-09 14:15:25 +00:00
if (mg->g_name == 0)
1984-07-12 12:48:33 +00:00
continue;
2019-03-17 14:41:25 +00:00
if ((mg->g_status & (EXT | DEF)) == 0)
error("undefined local symbol '%s'", glostring(mg));
if ((mg->g_status & EXT) == 0)
1984-07-12 12:48:33 +00:00
continue;
2019-03-17 14:41:25 +00:00
xg = xglolookup(mg->g_name, ENTERING);
switch (xg->g_status & (EXT | DEF))
{
case 0: /* new symbol */
if ((mg->g_status & DEF) == 0)
1984-07-12 12:48:33 +00:00
++unresolved;
break;
2019-03-17 14:41:25 +00:00
case EXT: /* already used but not defined */
if (mg->g_status & DEF)
{
1984-07-12 12:48:33 +00:00
--unresolved;
}
break;
}
xg->g_status |= mg->g_status;
2019-03-17 14:41:25 +00:00
if (mg->g_status & DEF)
1984-07-12 12:48:33 +00:00
xg->g_val.g_addr = mg->g_val.g_addr;
else
2019-03-17 14:41:25 +00:00
mg->g_val.g_gp = xg; /* used by upd_reloc */
1984-07-12 12:48:33 +00:00
} /* up to the next symbol */
upd_reloc();
2019-03-17 14:41:25 +00:00
memset(chp_cast mglobs, 0, (limit - mglobs) * (unsigned ) sizeof *mglobs);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void finish_up(void)
1984-07-12 12:48:33 +00:00
{
/*
* Almost done. Check for unresolved references,
* make the e.out file and stop.
*/
#ifdef DUMP
c_print();
#endif
check_def();
2019-03-17 14:41:25 +00:00
if (nerrors == 0)
copyout();
1984-07-12 12:48:33 +00:00
}
#ifdef DUMP
2019-03-17 14:41:25 +00:00
static void c_print(void)
{
if (!c_flag)
return;
c_dprint("primary", opcnt1);
c_dprint("secondary", opcnt2);
c_dprint("extra long", opcnt3);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
static void c_dprint(char *str, char* cnt)
{
register int first, curr;
printf("unused %s opcodes\n", str);
for (first = -1, curr = 0; curr <= 256; curr++)
{
if (curr == 256 || cnt[curr])
{
if (first != -1)
{
if (first + 1 == curr)
{
printf("%3d\n", first);
}
else
{
printf("%3d..%3d\n", first, curr - 1);
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
first = -1;
1984-07-12 12:48:33 +00:00
}
2019-03-17 14:41:25 +00:00
}
else
{
if (first == -1)
first = curr;
1984-07-12 12:48:33 +00:00
}
}
}
#endif
2019-03-17 14:41:25 +00:00
static void check_def(void)
{
1984-07-12 12:48:33 +00:00
register proc_t *p;
register glob_t *g;
2019-03-17 14:41:25 +00:00
register int count;
1984-07-12 12:48:33 +00:00
/*
* Check for unresolved references.
* NOTE: The occurring of unresolved references is not fatal,
* although the use of the e.out file after this
* occurring must be strongly discouraged.
* Every use of the symbols concerned is undefined.
*/
2019-03-17 14:41:25 +00:00
if (unresolved)
{
1984-07-12 12:48:33 +00:00
printf("Unresolved references\n Procedures:\n");
count = oursize->n_xproc;
for (p = xprocs; count--; p++)
2019-03-17 14:41:25 +00:00
if (p->p_name && (p->p_status & DEF) == 0)
printf(" %s\n", p->p_name);
1984-07-12 12:48:33 +00:00
printf(" Data:\n");
count = oursize->n_glab;
for (g = xglobs; count--; g++)
2019-03-17 14:41:25 +00:00
if (g->g_name && (g->g_status & DEF) == 0)
printf(" %s\n", glostring(g));
if (!Uflag)
nerrors++;
1984-07-12 12:48:33 +00:00
}
}
2019-03-17 14:41:25 +00:00
void ertrap(void)
{ /* trap routine to drain input in case of compile errors */
1984-07-12 12:48:33 +00:00
2019-03-17 14:41:25 +00:00
if (ifile == stdin)
1984-07-12 12:48:33 +00:00
while (fgetc(ifile) != EOF)
;
2019-03-17 14:41:25 +00:00
exit(EXIT_FAILURE);
1984-07-12 12:48:33 +00:00
}