ass00.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. #include "ass00.h"
  2. #include "assex.h"
  3. /*
  4. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
  5. * See the copyright notice in the ACK home directory, in the file "Copyright".
  6. *
  7. */
  8. #ifndef NORCSID
  9. static char rcs_id[] = "$Id$" ;
  10. #endif
  11. /*
  12. ** Main routine of EM1-assembler/loader
  13. */
  14. main(argc, argv)
  15. int argc;
  16. char **argv;
  17. {
  18. /*
  19. * Usage: ass [-[d][p][m][u][U]] [-s(s/m/l/x)] [ [file] [flag] ] ...
  20. * The d flag can be repeated several times, resulting in more
  21. * debugging information.
  22. */
  23. char workspace[6000] ;
  24. register char *cp ;
  25. register int argno ;
  26. progname = argv[0];
  27. for ( cp=argv[0] ; *cp ; ) if ( *cp++ == '/' ) progname= cp;
  28. for ( argno=1 ; argno<argc ; argno++ ) {
  29. if ( argv[argno][0] == '-' && LC(argv[argno][1]) == 's') {
  30. getsizes(&argv[argno][2]);
  31. break ;
  32. }
  33. }
  34. /* A piece of the interpreter's stack frame is used as
  35. free area initially */
  36. freearea( (area_t) workspace, (unsigned) sizeof workspace ) ;
  37. getcore();
  38. init_files();
  39. init_vars();
  40. while ( --argc )
  41. argument(*++argv);
  42. finish_up();
  43. exit(nerrors!=0);
  44. }
  45. getcore() {
  46. register siz_t *p;
  47. siz_t bytes;
  48. register unsigned n ;
  49. register char *base ;
  50. /*
  51. * xglobs[] should be located in front of mglobs[], see upd_reloc()
  52. */
  53. p = oursize; n = 0;
  54. n += (bytes.n_glab = p->n_glab * (sizeof *xglobs));
  55. n += (bytes.n_mlab = p->n_mlab * (sizeof *mglobs));
  56. n += (bytes.n_mproc = p->n_mproc * (sizeof *mprocs));
  57. n += (bytes.n_xproc = p->n_xproc * (sizeof *xprocs));
  58. n += (bytes.n_proc = p->n_proc * (sizeof *proctab));
  59. base = getarea(n);
  60. zero(base,n);
  61. xglobs = gbp_cast base; base += bytes.n_glab;
  62. mglobs = gbp_cast base; base += bytes.n_mlab;
  63. mprocs = prp_cast base; base += bytes.n_mproc;
  64. xprocs = prp_cast base; base += bytes.n_xproc;
  65. proctab = ptp_cast base; base += bytes.n_proc;
  66. }
  67. getsizes(str) char *str; {
  68. /*
  69. * accepts -ss (small), -sm (medium), -sl (large), -sx (extra large)
  70. */
  71. switch(LC(*str)) {
  72. default:error("bad size option %s",str);
  73. case 's': oursize = &sizes[0]; break;
  74. case 'm': oursize = &sizes[1]; break;
  75. case 'l': oursize = &sizes[2]; break;
  76. case 'x': oursize = &sizes[3]; break;
  77. }
  78. }
  79. char oflag;
  80. argument(arg) char *arg; {
  81. register w;
  82. /*
  83. * This routine decides what to do with each argument.
  84. * It recognises flags and modules.
  85. * Furthermore, it knows a library when it sees it and
  86. * call archive() to split it apart.
  87. */
  88. if (oflag) {
  89. eout = arg;
  90. oflag=0;
  91. return;
  92. }
  93. if(*arg == '-') {
  94. flags(arg);
  95. return;
  96. }
  97. curfile = arg; /* for error messages etc. */
  98. if ((ifile = fopen(arg,"r")) == 0) {
  99. error("can't open %s",arg);
  100. return;
  101. }
  102. inpoff = 2;
  103. if ((w = getu16()) == sp_magic )
  104. read_compact();
  105. else if (w == ARMAG || w == AALMAG) {
  106. archmode = TRUE;
  107. archive();
  108. archmode = FALSE;
  109. } else
  110. error("%s: bad format",arg);
  111. if (fclose(ifile) == EOF)
  112. ;
  113. }
  114. /*
  115. ** process flag arguments
  116. */
  117. static int memflg ;
  118. flags(arg)
  119. char *arg;
  120. {
  121. register char *argp;
  122. register on;
  123. argp = arg;
  124. while (*++argp)
  125. {
  126. switch(LC(*argp))
  127. {
  128. case 'd': d_flag++;break;
  129. case 'r': r_flag++;break;
  130. case 's': return ; /* s-flag is already scanned */
  131. #ifdef MEMUSE
  132. case 'm': memflg++ ; break ;
  133. #endif
  134. case 'p': ++procflag;break;
  135. #ifdef DUMP
  136. case 'u': ++c_flag;break;
  137. #endif
  138. case 'o': ++oflag; break;
  139. case 'w': ++wflag; break;
  140. #ifdef JOHAN
  141. case 'j': ++jflag; break;
  142. #endif
  143. case 'U': ++Uflag; break;
  144. case '-':
  145. case '+':
  146. on = (*argp == '+');
  147. while (*++argp) switch(LC(*argp)) {
  148. case 't': if (on) intflags |= 01;
  149. else intflags &= ~01;
  150. break;
  151. case 'p': if (on) intflags |= 02;
  152. else intflags &= ~02;
  153. break;
  154. case 'f': if (on) intflags |= 04;
  155. else intflags &= ~04;
  156. break;
  157. case 'c': if (on) intflags |= 010;
  158. else intflags &= ~010;
  159. case 'e': if (on) intflags |= 040;
  160. else intflags &= ~040;
  161. break;
  162. default:
  163. error("bad interpreter option %s",argp);
  164. }
  165. --argp;
  166. break;
  167. default:
  168. error("bad flag %s",argp);
  169. break;
  170. }
  171. }
  172. }
  173. do_proc() {
  174. /* One procedure has been read and will be processed.
  175. *
  176. * NOTE: The numbers of the passes, 1 3 4 and 5, are a remainder
  177. * of ancient times.
  178. */
  179. dump(1); if ( memflg>2 )memuse();
  180. pass_3(); dump(3);
  181. pass_4(); dump(4);
  182. pass_5(); if ( memflg>2 ) memuse() ;
  183. endproc(); if ( memflg>1 ) memuse() ;
  184. }
  185. archive() {
  186. register i;
  187. register char *p;
  188. /*
  189. * Read a library.
  190. * The format of the libary used is that of a UNIX/V7(PDP)-archive.
  191. *
  192. * NOTE: If it was allowed for an archive to contain
  193. * obligatory modules as well as optionals,
  194. * it would not be possible to speed up things a bit
  195. * by stopping when all references are resolved.
  196. * This is the only reason.
  197. */
  198. for(;;) {
  199. if (unresolved == 0) { /* no use for this library anymore */
  200. return;
  201. }
  202. p = chp_cast &archhdr;
  203. if ((i = fgetc(ifile))==EOF ) {
  204. return;
  205. }
  206. *p++ = i;
  207. for (i=1;i< sizeof archhdr.ar_name; i++)
  208. *p++ = get8();
  209. for (i=0;i<8;i++) get8();
  210. archhdr.ar_size= ((long)get16()<<16) ;
  211. archhdr.ar_size+= getu16();
  212. inpoff = 0; libeof = archhdr.ar_size;
  213. /*
  214. * UNIX archiveheader is read now, now process the contents
  215. * of it. Note that recursive archives are not implemented.
  216. *
  217. * The variable libeof is used by get8() to check
  218. * whether or not we try to pass the library-boundary.
  219. */
  220. if ( getu16() == sp_magic ) {
  221. read_compact();
  222. } else
  223. error("bad archive entry");
  224. skipentry();
  225. libeof = 0;
  226. } /* up to the next entry */
  227. }
  228. skipentry() {
  229. /*
  230. * for some reason the rest of this library entry needs to be
  231. * skipped. Do that now.
  232. */
  233. while(inpoff<libeof)
  234. get8();
  235. if(odd(libeof)) /* archive entries are evensized */
  236. if (fgetc(ifile) == EOF) /* except maybe the last one */
  237. ;
  238. }
  239. init_vars() {
  240. /*
  241. * A small collection of variables is initialized.
  242. * This occurs only for those that couldn't be initialized
  243. * at compile-time.
  244. */
  245. }
  246. init_files() {
  247. /*
  248. * The temporary files on which text and data are kept
  249. * during assembly are set up here.
  250. */
  251. #ifdef CPM
  252. unlink("????????.$$$");
  253. tfile=fopen("TFILE.$$$", "w");
  254. dfile=fopen("DFILE.$$$", "w");
  255. rtfile=fopen("RTFILE.$$$", "w");
  256. rdfile=fopen("RDFILE.$$$", "w");
  257. #else
  258. /*
  259. * The function tmpfil() returns a file-descriptor
  260. * of a file that is valid for reading and writing.
  261. * It has the nice property of generating truly unique names.
  262. */
  263. tfile=fdopen(tmpfil(),"w") ;
  264. dfile=fdopen(tmpfil(),"w") ;
  265. rtfile=fdopen(tmpfil(),"w") ;
  266. rdfile=fdopen(tmpfil(),"w") ;
  267. #endif
  268. }
  269. initproc() {
  270. /*
  271. * Called at the start of assembly of every procedure.
  272. */
  273. stat_t *prevstate ;
  274. prevstate= pst_cast getarea(sizeof pstate) ;
  275. *prevstate= pstate ;
  276. pstate.s_prevstat= prevstate ;
  277. pstate.s_curpro= prp_cast 0 ;
  278. pstate.s_fline= lnp_cast 0 ;
  279. pstate.s_fdata= l_data ;
  280. pstate.s_locl = (locl_t (*)[])
  281. getarea(LOCLABSIZE * sizeof ((*(pstate.s_locl))[0]));
  282. zero(chp_cast pstate.s_locl,
  283. LOCLABSIZE * (unsigned) sizeof ((*(pstate.s_locl))[0]));
  284. if ( memflg>2 ) memuse() ;
  285. }
  286. endproc() {
  287. /* Throw the contents of the line and local label table away */
  288. register line_t *lnp1;
  289. register locl_t *lbhead,*lbp,*lbp_next;
  290. register kind ;
  291. register stat_t *prevstate;
  292. while ( lnp1= pstate.s_fline ) {
  293. pstate.s_fline= lnp1->l_next ;
  294. kind= lnp1->type1 ;
  295. if ( kind>VALLOW ) kind=VALLOW ;
  296. freearea((area_t)lnp1,(unsigned)linesize[kind]) ;
  297. }
  298. prevstate= pstate.s_prevstat ;
  299. if ( prevstate!= pst_cast 0 ) {
  300. for ( lbhead= *pstate.s_locl;
  301. lbhead<&(*pstate.s_locl)[LOCLABSIZE] ; lbhead++ ) {
  302. for ( lbp=lbhead->l_chain; lbp!= lbp_cast 0; lbp= lbp_next ) {
  303. lbp_next= lbp->l_chain;
  304. freearea((area_t)lbp,(unsigned)sizeof *lbp) ;
  305. }
  306. }
  307. freearea((area_t)(*pstate.s_locl),
  308. LOCLABSIZE * (sizeof((*pstate.s_locl)[0])));
  309. pstate= *prevstate ;
  310. freearea((area_t)prevstate,(unsigned)sizeof *prevstate) ;
  311. }
  312. }
  313. init_module() {
  314. /*
  315. * Called at the start of every module.
  316. */
  317. holbase = 0;
  318. line_num = 1;
  319. mod_sizes = 0;
  320. }
  321. end_module() {
  322. /*
  323. * Finish a module.
  324. * Work to be done is mainly forgetting of local names,
  325. * and remembering of those that will live during assembly.
  326. */
  327. align(wordsize) ;
  328. setmode(DATA_NUL);
  329. dump(100);
  330. enmd_pro();
  331. enmd_glo();
  332. if ( memflg ) memuse() ;
  333. }
  334. enmd_pro() {
  335. register proc_t *p,*limit;
  336. /*
  337. * Check that all local procedures have been defined,
  338. * and forget them immediately thereafter.
  339. */
  340. limit = &mprocs[oursize->n_mproc];
  341. for (p=mprocs; p<limit; p++) {
  342. if (p->p_name == 0)
  343. continue;
  344. if ((p->p_status&DEF)==0)
  345. error("undefined local procedure '%s'",p->p_name);
  346. }
  347. zero(chp_cast mprocs,(limit-mprocs)* (unsigned)sizeof *mprocs);
  348. /* Clobber all flags indicating that external procedures
  349. * were used in this module.
  350. */
  351. limit = &xprocs[oursize->n_xproc];
  352. for (p=xprocs; p<limit; p++) {
  353. p->p_status &= ~EXT ;
  354. }
  355. }
  356. enmd_glo() {
  357. register glob_t *mg,*xg,*limit;
  358. /*
  359. * Tougher then enmd_pro().
  360. * Check all the symbols used in this module that are
  361. * not to be forgotten immediately.
  362. * A difficulty arises here:
  363. * In the tables textreloc[] and datareloc[]
  364. * pointers are used to identify the symbols concerned.
  365. * These pointers point into mglobs[].
  366. * Since at the end of assembly only the value of xglobs[]
  367. * is defined, these pointers have to be changed.
  368. * upd_reloc() takes care of this.
  369. */
  370. limit = &mglobs[oursize->n_mlab];
  371. for ( mg = mglobs; mg < limit; mg++) {
  372. if (mg->g_name == 0)
  373. continue;
  374. if ((mg->g_status&(EXT|DEF))==0)
  375. error("undefined local symbol '%s'",glostring(mg));
  376. if ((mg->g_status&EXT)==0)
  377. continue;
  378. xg = xglolookup(mg->g_name,ENTERING);
  379. switch(xg->g_status&(EXT|DEF)) {
  380. case 0: /* new symbol */
  381. if((mg->g_status&DEF)==0)
  382. ++unresolved;
  383. break;
  384. case EXT: /* already used but not defined */
  385. if(mg->g_status&DEF) {
  386. --unresolved;
  387. }
  388. break;
  389. }
  390. xg->g_status |= mg->g_status;
  391. if (mg->g_status&DEF)
  392. xg->g_val.g_addr = mg->g_val.g_addr;
  393. else
  394. mg->g_val.g_gp = xg; /* used by upd_reloc */
  395. } /* up to the next symbol */
  396. upd_reloc();
  397. zero(chp_cast mglobs,(limit-mglobs)*(unsigned) sizeof *mglobs);
  398. }
  399. finish_up()
  400. {
  401. /*
  402. * Almost done. Check for unresolved references,
  403. * make the e.out file and stop.
  404. */
  405. #ifdef DUMP
  406. c_print();
  407. #endif
  408. check_def();
  409. if ( nerrors==0 ) copyout();
  410. }
  411. #ifdef DUMP
  412. c_print() {
  413. if ( ! c_flag ) return ;
  414. c_dprint("primary",opcnt1) ;
  415. c_dprint("secondary",opcnt2) ;
  416. c_dprint("extra long",opcnt3) ;
  417. }
  418. c_dprint(str,cnt) char *str,*cnt ; {
  419. register int first,curr ;
  420. printf("unused %s opcodes\n",str) ;
  421. for ( first= -1 , curr=0 ; curr<=256 ; curr++ ) {
  422. if ( curr==256 || cnt[curr] ) {
  423. if ( first!= -1 ) {
  424. if ( first+1 == curr ) {
  425. printf("%3d\n",first ) ;
  426. } else {
  427. printf("%3d..%3d\n",first,curr-1) ;
  428. }
  429. first= -1 ;
  430. }
  431. } else {
  432. if ( first== -1 ) first=curr ;
  433. }
  434. }
  435. }
  436. #endif
  437. check_def() {
  438. register proc_t *p;
  439. register glob_t *g;
  440. register count;
  441. /*
  442. * Check for unresolved references.
  443. * NOTE: The occurring of unresolved references is not fatal,
  444. * although the use of the e.out file after this
  445. * occurring must be strongly discouraged.
  446. * Every use of the symbols concerned is undefined.
  447. */
  448. if (unresolved) {
  449. printf("Unresolved references\n Procedures:\n");
  450. count = oursize->n_xproc;
  451. for (p = xprocs; count--; p++)
  452. if (p->p_name && (p->p_status&DEF)==0)
  453. printf(" %s\n",p->p_name);
  454. printf(" Data:\n");
  455. count = oursize->n_glab;
  456. for (g = xglobs; count--; g++)
  457. if (g->g_name && (g->g_status&DEF)==0)
  458. printf(" %s\n",glostring(g));
  459. if (! Uflag) nerrors++;
  460. }
  461. }
  462. ertrap() { /* trap routine to drain input in case of compile errors */
  463. if (fileno(ifile)== 0)
  464. while (fgetc(ifile) != EOF)
  465. ;
  466. exit(1);
  467. }