5 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
6 * See the copyright notice in the ACK home directory, in the file "Copyright".
11 static char rcs_id[] = "$Id: ass00.c,v 2.15 1994/06/24 10:15:01 ceriel Exp $" ;
15 ** Main routine of EM1-assembler/loader
23 * Usage: ass [-[d][p][m][u][U]] [-s(s/m/l/x)] [ [file] [flag] ] ...
24 * The d flag can be repeated several times, resulting in more
25 * debugging information.
27 char workspace[6000] ;
32 for ( cp=argv[0] ; *cp ; ) if ( *cp++ == '/' ) progname= cp;
33 for ( argno=1 ; argno<argc ; argno++ ) {
34 if ( argv[argno][0] == '-' && LC(argv[argno][1]) == 's') {
35 getsizes(&argv[argno][2]);
39 /* A piece of the interpreter's stack frame is used as
40 free area initially */
41 freearea( (area_t) workspace, (unsigned) sizeof workspace ) ;
58 * xglobs[] should be located in front of mglobs[], see upd_reloc()
62 n += (bytes.n_glab = p->n_glab * (sizeof *xglobs));
63 n += (bytes.n_mlab = p->n_mlab * (sizeof *mglobs));
64 n += (bytes.n_mproc = p->n_mproc * (sizeof *mprocs));
65 n += (bytes.n_xproc = p->n_xproc * (sizeof *xprocs));
66 n += (bytes.n_proc = p->n_proc * (sizeof *proctab));
69 xglobs = gbp_cast base; base += bytes.n_glab;
70 mglobs = gbp_cast base; base += bytes.n_mlab;
71 mprocs = prp_cast base; base += bytes.n_mproc;
72 xprocs = prp_cast base; base += bytes.n_xproc;
73 proctab = ptp_cast base; base += bytes.n_proc;
76 getsizes(str) char *str; {
79 * accepts -ss (small), -sm (medium), -sl (large), -sx (extra large)
83 default:error("bad size option %s",str);
84 case 's': oursize = &sizes[0]; break;
85 case 'm': oursize = &sizes[1]; break;
86 case 'l': oursize = &sizes[2]; break;
87 case 'x': oursize = &sizes[3]; break;
93 argument(arg) char *arg; {
97 * This routine decides what to do with each argument.
98 * It recognises flags and modules.
99 * Furthermore, it knows a library when it sees it and
100 * call archive() to split it apart.
112 curfile = arg; /* for error messages etc. */
113 if ((ifile = fopen(arg,"r")) == 0) {
114 error("can't open %s",arg);
118 if ((w = getu16()) == sp_magic )
120 else if (w == ARMAG || w == AALMAG) {
125 error("%s: bad format",arg);
126 if (fclose(ifile) == EOF)
131 ** process flag arguments
147 case 'd': d_flag++;break;
148 case 'r': r_flag++;break;
149 case 's': return ; /* s-flag is already scanned */
151 case 'm': memflg++ ; break ;
153 case 'p': ++procflag;break;
155 case 'u': ++c_flag;break;
157 case 'o': ++oflag; break;
158 case 'w': ++wflag; break;
160 case 'j': ++jflag; break;
162 case 'U': ++Uflag; break;
166 while (*++argp) switch(LC(*argp)) {
167 case 't': if (on) intflags |= 01;
168 else intflags &= ~01;
170 case 'p': if (on) intflags |= 02;
171 else intflags &= ~02;
173 case 'f': if (on) intflags |= 04;
174 else intflags &= ~04;
176 case 'c': if (on) intflags |= 010;
177 else intflags &= ~010;
178 case 'e': if (on) intflags |= 040;
179 else intflags &= ~040;
182 error("bad interpreter option %s",argp);
187 error("bad flag %s",argp);
194 /* One procedure has been read and will be processed.
196 * NOTE: The numbers of the passes, 1 3 4 and 5, are a remainder
200 dump(1); if ( memflg>2 )memuse();
203 pass_5(); if ( memflg>2 ) memuse() ;
204 endproc(); if ( memflg>1 ) memuse() ;
213 * The format of the libary used is that of a UNIX/V7(PDP)-archive.
215 * NOTE: If it was allowed for an archive to contain
216 * obligatory modules as well as optionals,
217 * it would not be possible to speed up things a bit
218 * by stopping when all references are resolved.
219 * This is the only reason.
223 if (unresolved == 0) { /* no use for this library anymore */
226 p = chp_cast &archhdr;
227 if ((i = fgetc(ifile))==EOF ) {
231 for (i=1;i< sizeof archhdr.ar_name; i++)
233 for (i=0;i<8;i++) get8();
234 archhdr.ar_size= ((long)get16()<<16) ;
235 archhdr.ar_size+= getu16();
236 inpoff = 0; libeof = archhdr.ar_size;
238 * UNIX archiveheader is read now, now process the contents
239 * of it. Note that recursive archives are not implemented.
241 * The variable libeof is used by get8() to check
242 * whether or not we try to pass the library-boundary.
244 if ( getu16() == sp_magic ) {
247 error("bad archive entry");
250 } /* up to the next entry */
256 * for some reason the rest of this library entry needs to be
257 * skipped. Do that now.
261 if(odd(libeof)) /* archive entries are evensized */
262 if (fgetc(ifile) == EOF) /* except maybe the last one */
269 * A small collection of variables is initialized.
270 * This occurs only for those that couldn't be initialized
279 * The temporary files on which text and data are kept
280 * during assembly are set up here.
283 unlink("????????.$$$");
284 tfile=fopen("TFILE.$$$", "w");
285 dfile=fopen("DFILE.$$$", "w");
286 rtfile=fopen("RTFILE.$$$", "w");
287 rdfile=fopen("RDFILE.$$$", "w");
290 * The function tmpfil() returns a file-descriptor
291 * of a file that is valid for reading and writing.
292 * It has the nice property of generating truly unique names.
295 tfile=fdopen(tmpfil(),"w") ;
296 dfile=fdopen(tmpfil(),"w") ;
297 rtfile=fdopen(tmpfil(),"w") ;
298 rdfile=fdopen(tmpfil(),"w") ;
305 * Called at the start of assembly of every procedure.
310 prevstate= pst_cast getarea(sizeof pstate) ;
312 pstate.s_prevstat= prevstate ;
313 pstate.s_curpro= prp_cast 0 ;
314 pstate.s_fline= lnp_cast 0 ;
315 pstate.s_fdata= l_data ;
316 pstate.s_locl = (locl_t (*)[])
317 getarea(LOCLABSIZE * sizeof ((*(pstate.s_locl))[0]));
318 zero(chp_cast pstate.s_locl,
319 LOCLABSIZE * (unsigned) sizeof ((*(pstate.s_locl))[0]));
320 if ( memflg>2 ) memuse() ;
324 /* Throw the contents of the line and local label table away */
325 register line_t *lnp1;
326 register locl_t *lbhead,*lbp,*lbp_next;
328 register stat_t *prevstate;
330 while ( lnp1= pstate.s_fline ) {
331 pstate.s_fline= lnp1->l_next ;
333 if ( kind>VALLOW ) kind=VALLOW ;
334 freearea((area_t)lnp1,(unsigned)linesize[kind]) ;
336 prevstate= pstate.s_prevstat ;
337 if ( prevstate!= pst_cast 0 ) {
338 for ( lbhead= *pstate.s_locl;
339 lbhead<&(*pstate.s_locl)[LOCLABSIZE] ; lbhead++ ) {
340 for ( lbp=lbhead->l_chain; lbp!= lbp_cast 0; lbp= lbp_next ) {
341 lbp_next= lbp->l_chain;
342 freearea((area_t)lbp,(unsigned)sizeof *lbp) ;
345 freearea((area_t)(*pstate.s_locl),
346 LOCLABSIZE * (sizeof((*pstate.s_locl)[0])));
348 freearea((area_t)prevstate,(unsigned)sizeof *prevstate) ;
355 * Called at the start of every module.
367 * Work to be done is mainly forgetting of local names,
368 * and remembering of those that will live during assembly.
376 if ( memflg ) memuse() ;
380 register proc_t *p,*limit;
383 * Check that all local procedures have been defined,
384 * and forget them immediately thereafter.
387 limit = &mprocs[oursize->n_mproc];
388 for (p=mprocs; p<limit; p++) {
391 if ((p->p_status&DEF)==0)
392 error("undefined local procedure '%s'",p->p_name);
394 zero(chp_cast mprocs,(limit-mprocs)* (unsigned)sizeof *mprocs);
396 /* Clobber all flags indicating that external procedures
397 * were used in this module.
400 limit = &xprocs[oursize->n_xproc];
401 for (p=xprocs; p<limit; p++) {
402 p->p_status &= ~EXT ;
407 register glob_t *mg,*xg,*limit;
410 * Tougher then enmd_pro().
411 * Check all the symbols used in this module that are
412 * not to be forgotten immediately.
413 * A difficulty arises here:
414 * In the tables textreloc[] and datareloc[]
415 * pointers are used to identify the symbols concerned.
416 * These pointers point into mglobs[].
417 * Since at the end of assembly only the value of xglobs[]
418 * is defined, these pointers have to be changed.
419 * upd_reloc() takes care of this.
422 limit = &mglobs[oursize->n_mlab];
423 for ( mg = mglobs; mg < limit; mg++) {
426 if ((mg->g_status&(EXT|DEF))==0)
427 error("undefined local symbol '%s'",glostring(mg));
428 if ((mg->g_status&EXT)==0)
430 xg = xglolookup(mg->g_name,ENTERING);
431 switch(xg->g_status&(EXT|DEF)) {
432 case 0: /* new symbol */
433 if((mg->g_status&DEF)==0)
436 case EXT: /* already used but not defined */
437 if(mg->g_status&DEF) {
442 xg->g_status |= mg->g_status;
443 if (mg->g_status&DEF)
444 xg->g_val.g_addr = mg->g_val.g_addr;
446 mg->g_val.g_gp = xg; /* used by upd_reloc */
447 } /* up to the next symbol */
449 zero(chp_cast mglobs,(limit-mglobs)*(unsigned) sizeof *mglobs);
455 * Almost done. Check for unresolved references,
456 * make the e.out file and stop.
463 if ( nerrors==0 ) copyout();
468 if ( ! c_flag ) return ;
469 c_dprint("primary",opcnt1) ;
470 c_dprint("secondary",opcnt2) ;
471 c_dprint("extra long",opcnt3) ;
474 c_dprint(str,cnt) char *str,*cnt ; {
475 register int first,curr ;
476 printf("unused %s opcodes\n",str) ;
477 for ( first= -1 , curr=0 ; curr<=256 ; curr++ ) {
478 if ( curr==256 || cnt[curr] ) {
480 if ( first+1 == curr ) {
481 printf("%3d\n",first ) ;
483 printf("%3d..%3d\n",first,curr-1) ;
488 if ( first== -1 ) first=curr ;
500 * Check for unresolved references.
501 * NOTE: The occurring of unresolved references is not fatal,
502 * although the use of the e.out file after this
503 * occurring must be strongly discouraged.
504 * Every use of the symbols concerned is undefined.
508 printf("Unresolved references\n Procedures:\n");
509 count = oursize->n_xproc;
510 for (p = xprocs; count--; p++)
511 if (p->p_name && (p->p_status&DEF)==0)
512 printf(" %s\n",p->p_name);
514 count = oursize->n_glab;
515 for (g = xglobs; count--; g++)
516 if (g->g_name && (g->g_status&DEF)==0)
517 printf(" %s\n",glostring(g));
518 if (! Uflag) nerrors++;
522 ertrap() { /* trap routine to drain input in case of compile errors */
524 if (fileno(ifile)== 0)
525 while (fgetc(ifile) != EOF)