Pristine Ack-5.5
[Ack-5.5.git] / util / ass / ass00.c
1 #include        "ass00.h"
2 #include        "assex.h"
3
4 /*
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".
7  *
8  */
9
10 #ifndef NORCSID
11 static char rcs_id[] = "$Id: ass00.c,v 2.15 1994/06/24 10:15:01 ceriel Exp $" ;
12 #endif
13
14 /*
15 ** Main routine of EM1-assembler/loader
16 */
17
18 main(argc, argv)
19         int     argc;
20         char    **argv;
21 {
22         /*
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.
26          */
27         char workspace[6000] ;
28         register char *cp ;
29         register int argno ;
30
31         progname = argv[0];
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]);
36                         break ;
37                 }
38         }
39         /* A piece of the interpreter's stack frame is used as
40            free area initially */
41         freearea( (area_t) workspace, (unsigned) sizeof workspace ) ;
42         getcore();
43         init_files();
44         init_vars();
45         while ( --argc )
46                 argument(*++argv);
47         finish_up();
48         exit(nerrors!=0);
49 }
50
51 getcore() {
52         register siz_t *p;
53         siz_t bytes;
54         register unsigned n ;
55         register char *base ;
56
57         /*
58          * xglobs[] should be located in front of mglobs[], see upd_reloc()
59          */
60
61         p = oursize; n = 0;
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));
67         base = getarea(n);
68         zero(base,n);
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;
74 }
75
76 getsizes(str) char *str; {
77
78         /*
79          * accepts -ss (small), -sm (medium), -sl (large), -sx (extra large)
80          */
81
82         switch(LC(*str)) {
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;
88         }
89 }
90
91 char oflag;
92
93 argument(arg) char *arg; {
94         register w;
95
96         /*
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.
101          */
102
103         if (oflag) {
104                 eout = arg;
105                 oflag=0;
106                 return;
107         }
108         if(*arg == '-') {
109                 flags(arg);
110                 return;
111         }
112         curfile = arg;  /* for error messages etc. */
113         if ((ifile = fopen(arg,"r")) == 0) {
114                 error("can't open %s",arg);
115                 return;
116         }
117         inpoff = 2;
118         if ((w = getu16()) == sp_magic )
119                 read_compact();
120         else if (w == ARMAG || w == AALMAG) {
121                 archmode = TRUE;
122                 archive();
123                 archmode = FALSE;
124         } else
125                 error("%s: bad format",arg);
126         if (fclose(ifile) == EOF)
127                 ;
128 }
129
130 /*
131 ** process flag arguments
132 */
133
134 static int memflg ;
135
136 flags(arg)
137         char    *arg;
138 {
139         register char   *argp;
140         register on;
141
142         argp = arg;
143         while (*++argp)
144         {
145                 switch(LC(*argp))
146                 {
147                         case 'd':       d_flag++;break;
148                         case 'r':       r_flag++;break;
149                         case 's':       return ; /* s-flag is already scanned */
150 #ifdef MEMUSE
151                         case 'm':       memflg++ ; break ;
152 #endif
153                         case 'p':       ++procflag;break;
154 #ifdef DUMP
155                         case 'u':       ++c_flag;break;
156 #endif
157                         case 'o':       ++oflag; break;
158                         case 'w':       ++wflag; break;
159 #ifdef JOHAN
160                         case 'j':       ++jflag; break;
161 #endif
162                         case 'U':       ++Uflag; break;
163                         case '-':
164                         case '+':
165                                 on = (*argp == '+');
166                                 while (*++argp) switch(LC(*argp)) {
167                                 case 't': if (on) intflags |= 01;
168                                           else intflags &= ~01;
169                                           break;
170                                 case 'p': if (on) intflags |= 02;
171                                           else intflags &= ~02;
172                                           break;
173                                 case 'f': if (on) intflags |= 04;
174                                           else intflags &= ~04;
175                                           break;
176                                 case 'c': if (on) intflags |= 010;
177                                           else intflags &= ~010;
178                                 case 'e': if (on) intflags |= 040;
179                                           else intflags &= ~040;
180                                           break;
181                                 default:
182                                   error("bad interpreter option %s",argp);
183                                 }
184                                 --argp;
185                                 break;
186                         default:
187                                 error("bad flag %s",argp);
188                                         break;
189                 }
190         }
191 }
192
193 do_proc() {
194         /* One procedure has been read and will be processed.
195          *
196          * NOTE: The numbers of the passes, 1 3 4 and 5, are a remainder
197          *       of ancient times.
198          */
199
200         dump(1); if ( memflg>2 )memuse();
201         pass_3();  dump(3);
202         pass_4();  dump(4);
203         pass_5();  if ( memflg>2 ) memuse() ;
204         endproc();  if ( memflg>1 ) memuse() ;
205 }
206
207 archive() {
208         register i;
209         register char *p;
210
211         /*
212          * Read a library.
213          * The format of the libary used is that of a UNIX/V7(PDP)-archive.
214          *
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.
220          */
221
222         for(;;) {
223                 if (unresolved == 0) {  /* no use for this library anymore */
224                         return;
225                 }
226                 p = chp_cast &archhdr;
227                 if ((i = fgetc(ifile))==EOF ) {
228                         return;
229                 }
230                 *p++ = i;
231                 for (i=1;i< sizeof archhdr.ar_name; i++)
232                         *p++ = get8();
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;
237                 /*
238                  * UNIX archiveheader is read now, now process the contents
239                  * of it. Note that recursive archives are not implemented.
240                  *
241                  * The variable libeof is used by get8() to check
242                  * whether or not we try to pass the library-boundary.
243                  */
244                 if ( getu16() == sp_magic ) {
245                         read_compact();
246                 } else
247                         error("bad archive entry");
248                 skipentry();
249                 libeof = 0;
250         }       /* up to the next entry */
251 }
252
253 skipentry() {
254
255         /*
256          * for some reason the rest of this library entry needs to be
257          * skipped. Do that now.
258          */
259         while(inpoff<libeof)
260                 get8();
261         if(odd(libeof))                 /* archive entries are evensized */
262                 if (fgetc(ifile) == EOF)   /* except maybe the last one */
263                         ;
264 }
265
266 init_vars() {
267
268         /*
269          * A small collection of variables is initialized.
270          * This occurs only for those that couldn't be initialized
271          * at compile-time.
272          */
273
274 }
275
276 init_files() {
277
278         /*
279          * The temporary files on which text and data are kept
280          * during assembly are set up here.
281          */
282 #ifdef CPM
283         unlink("????????.$$$");
284         tfile=fopen("TFILE.$$$", "w");
285         dfile=fopen("DFILE.$$$", "w");
286         rtfile=fopen("RTFILE.$$$", "w");
287         rdfile=fopen("RDFILE.$$$", "w");
288 #else
289         /*
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.
293          */
294
295         tfile=fdopen(tmpfil(),"w") ;
296         dfile=fdopen(tmpfil(),"w") ;
297         rtfile=fdopen(tmpfil(),"w") ;
298         rdfile=fdopen(tmpfil(),"w") ;
299 #endif
300 }
301
302 initproc() {
303
304         /*
305          * Called at the start of assembly of every procedure.
306          */
307
308         stat_t *prevstate ;
309
310         prevstate= pst_cast getarea(sizeof pstate) ;
311         *prevstate= 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() ;
321 }
322
323 endproc() {
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;
327         register kind ;
328         register stat_t *prevstate;
329
330         while ( lnp1= pstate.s_fline ) {
331                 pstate.s_fline= lnp1->l_next ;
332                 kind= lnp1->type1 ;
333                 if ( kind>VALLOW ) kind=VALLOW ;
334                 freearea((area_t)lnp1,(unsigned)linesize[kind]) ;
335         }
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) ;
343                         }
344                 }
345                 freearea((area_t)(*pstate.s_locl),
346                         LOCLABSIZE * (sizeof((*pstate.s_locl)[0])));
347                 pstate= *prevstate ;
348                 freearea((area_t)prevstate,(unsigned)sizeof *prevstate) ;
349         }
350 }
351
352 init_module() {
353
354         /*
355          * Called at the start of every module.
356          */
357
358         holbase  = 0;
359         line_num = 1;
360         mod_sizes = 0;
361 }
362
363 end_module() {
364
365         /*
366          * Finish a module.
367          * Work to be done is mainly forgetting of local names,
368          * and remembering of those that will live during assembly.
369          */
370
371         align(wordsize) ;
372         setmode(DATA_NUL);
373         dump(100);
374         enmd_pro();
375         enmd_glo();
376         if ( memflg ) memuse() ;
377 }
378
379 enmd_pro() {
380         register proc_t *p,*limit;
381
382         /*
383          * Check that all local procedures have been defined,
384          * and forget them immediately thereafter.
385          */
386
387         limit = &mprocs[oursize->n_mproc];
388         for (p=mprocs; p<limit; p++) {
389                 if (p->p_name == 0)
390                         continue;
391                 if ((p->p_status&DEF)==0)
392                         error("undefined local procedure '%s'",p->p_name);
393         }
394         zero(chp_cast mprocs,(limit-mprocs)* (unsigned)sizeof *mprocs);
395
396         /* Clobber all flags indicating that external procedures
397          * were used in this module.
398          */
399
400         limit = &xprocs[oursize->n_xproc];
401         for (p=xprocs; p<limit; p++) {
402                 p->p_status &= ~EXT ;
403         }
404 }
405
406 enmd_glo() {
407         register glob_t *mg,*xg,*limit;
408
409         /*
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.
420          */
421
422         limit = &mglobs[oursize->n_mlab];
423         for ( mg = mglobs; mg < limit; mg++) {
424                 if (mg->g_name == 0)
425                         continue;
426                 if ((mg->g_status&(EXT|DEF))==0)
427                         error("undefined local symbol '%s'",glostring(mg));
428                 if ((mg->g_status&EXT)==0)
429                         continue;
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)
434                                 ++unresolved;
435                         break;
436                 case EXT:       /* already used but not defined */
437                         if(mg->g_status&DEF) {
438                                 --unresolved;
439                         }
440                         break;
441                 }
442                 xg->g_status |= mg->g_status;
443                 if (mg->g_status&DEF)
444                         xg->g_val.g_addr = mg->g_val.g_addr;
445                 else
446                         mg->g_val.g_gp = xg;        /* used by upd_reloc */
447         } /* up to the next symbol */
448         upd_reloc();
449         zero(chp_cast mglobs,(limit-mglobs)*(unsigned) sizeof *mglobs);
450 }
451
452 finish_up()
453 {
454         /*
455          * Almost done. Check for unresolved references,
456          * make the e.out file and stop.
457          */
458
459 #ifdef DUMP
460         c_print();
461 #endif
462         check_def();
463         if ( nerrors==0 ) copyout();
464 }
465
466 #ifdef DUMP
467 c_print() {
468         if ( ! c_flag ) return ;
469         c_dprint("primary",opcnt1) ;
470         c_dprint("secondary",opcnt2) ;
471         c_dprint("extra long",opcnt3) ;
472 }
473
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]  ) {
479                         if ( first!= -1 ) {
480                                 if ( first+1 == curr ) {
481                                         printf("%3d\n",first ) ;
482                                 } else {
483                                         printf("%3d..%3d\n",first,curr-1) ;
484                                 }
485                                 first= -1 ;
486                         }
487                 } else {
488                         if ( first== -1 ) first=curr ;
489                 }
490         }
491 }
492 #endif
493
494 check_def() {
495         register proc_t *p;
496         register glob_t *g;
497         register count;
498
499         /*
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.
505          */
506
507         if (unresolved) {
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);
513                 printf("  Data:\n");
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++;
519         }
520 }
521
522 ertrap() { /* trap routine to drain input in case of compile errors */
523
524         if (fileno(ifile)== 0)
525                 while (fgetc(ifile) != EOF)
526                         ;
527         exit(1);
528 }