1 /*------------------------------------------------------------------*/
2 /*								    */
3 /*			MC68000 Cross Assembler			    */
4 /*								    */
5 /*		  Copyright 1985 by Brian R. Anderson		    */
6 /*								    */
7 /*                    Main program - May 23, 1992		    */
8 /*								    */
9 /*   This program may be copied for personal, non-commercial use    */
10 /*   only, provided that the above copyright notice is included	    */
11 /*   on all copies of the source code.  Copying for any other use   */
12 /*   without the consent of the author is prohibited.		    */
13 /*								    */
14 /*------------------------------------------------------------------*/
15 /*								    */
16 /*              Originally published (in Modula-2) in		    */
17 /*          Dr. Dobb's Journal, April, May, and June 1986.          */
18 /*								    */
19 /*       AmigaDOS conversion copyright 1991 by Charlie Gibbs.	    */
20 /*								    */
21 /*------------------------------------------------------------------*/
22 
23 
24 #define PRIMARY
25 #include "A68kdef.h"
26 #include "A68kglb.h"
27 
28 char *Version = "2.71.F3w (Jul 27, 2006)";
29 
main(argc,argv)30 int main (argc,argv) int argc; char *argv[];
31 {
32     char ListFN[MAXFN], EquateFN[MAXFN]; /* File names */
33     int  makeequ;			/* Make an equate file. */
34     int  keepobj;			/* Keep object file with errors. */
35     int  endfile;			/* End-of-file flag */
36     long maxheap2;			/* Maximum secondary heap size */
37 /*    int  cmderror, dummy; */
38     int  cmderror; /* using now void in v.2.71.F3d - Kevin Kofler */
39     long codesize, datasize, bsssize;
40     int  *intptr;
41     long templong;
42     char tempchar[MAXLINE];
43     register int i, j;
44     struct SymTab **hashptr, **fsp;
45     struct FwdBr *fp1, *fp2, *fp3;
46     char *vopt[16]; int vopt_num; /* added by Paul Froissart in v.2.71.F3c
47                                      variables for the -v switch */
48     char *p;		/* Temporary - added by Paul Froissart in v.2.71.F3c
49                        variable for the -r switch */
50 
51 /*    dummy = 0; */  /* using now void in v.2.71.F3d - Kevin Kofler */
52     Hash = NULL;	/* Clear all memory pointers - */
53     SymStart = NULL;	/*  we haven't allocated anything yet. */
54     NameStart = NULL;
55     RelStart = NULL;
56     Heap2 = NULL;
57     SymSort = NULL;
58     vopt_num=0; /* number of -v switches -  added by Paul Froissart
59                                             in v.2.71.F3c */
60     optim=-1;	/* All optimizations are allowed (variable for the -r switch)
61                    added by Paul Froissart in v.2.71.F3c*/
62     In.fd = Eq.fd = List.fd = Srec.fd = NOFD;	/* No files are open yet. */
63     In.Buf = Eq.Buf = List.Buf = Srec.Buf = NULL;
64 
65     cmderror = FALSE;		/* Clear command-line error flag. */
66     InclErrs = FALSE;
67     SourceFN[0] = '\0';			/* We don't have source name yet. */
68     HeaderFN[0] = EquateFN[0] = '\0';	/* No header or equate files yet */
69     makeequ = FALSE;
70     ListFN[0] = SrecFN[0] = '\0';	/* Indicate default file names. */
71     InclList[0] = '\0';		/* Clear the include directory list. */
72     IdntName[0] = '\0';		/* Clear program unit name. */
73     DataOffset = 32768L;	/* Default small data offset */
74     LnMax = 60;			/* Default page size */
75     Quiet = 100;		/* Show progress every 100 lines. */
76     strcpy (MacSize, "W");	/* Macro call size (\0) */
77     XrefList = DumpSym = GotEqur = KeepTabs = keepobj = FALSE;
78     Unaligned = FALSE; /* added by Kevin Kofler in v.2.71.F3k */
79     AllRelocs = FALSE; /* added by Kevin Kofler in v.2.71.F3l */
80     SuppList = TRUE;		/* Default to no listing file. */
81     HashStats = FALSE;		/* Default to no hashing statistics. */
82     HashSize = DEFHASH;		/* Hash table size default */
83     maxheap2 = DEFHEAP2;	/* Secondary heap size default */
84     DebugStart = NODEF /*32767*/; DebugEnd = 0;	/* Disable debug displays. */
85 
86     isError = FALSE; /* bugfix by Kevin Kofler for the TIGCC team in v.2.71.F3a */
87 
88     for (i = 0; i < 256; i++)
89 	OpPrec[i] = '\0';	/* Set up the operator precedence table. */
90     i = (unsigned int) '('; OpPrec[i] = 1;
91     i = (unsigned int) ')'; OpPrec[i] = 2;
92     i = (unsigned int) '+'; OpPrec[i] = 3;
93     i = (unsigned int) '-'; OpPrec[i] = 3;
94     i = (unsigned int) '*'; OpPrec[i] = 4;
95     i = (unsigned int) '/'; OpPrec[i] = 4;
96     i = (unsigned int) '&'; OpPrec[i] = 5;
97     i = (unsigned int) '!'; OpPrec[i] = 5;
98     i = (unsigned int) '|'; OpPrec[i] = 5;
99     i = (unsigned int) '<'; OpPrec[i] = 6;
100     i = (unsigned int) '>'; OpPrec[i] = 6;
101 
102     for (i = 1; i < argc; i++) {	/* Analyze the command line. */
103 	if (argv[i][0] != '-') {
104 	    if (SourceFN[0] == '\0')
105 		strcpy (SourceFN, argv[i]);	/* Source file name */
106 	    else if (SrecFN[0] == '\0')
107 		strcpy (SrecFN, argv[i]);	/* Object file name */
108 	    else if (ListFN[0] == '\0')
109 		strcpy (ListFN, argv[i]);	/* Listing file name */
110 	    else {
111 		fprintf (stderr, "Too many file names.\n");
112 		cmderror = TRUE;
113 	    }
114 	} else {
115 	    switch (toupper(argv[i][1])) {
116 	    case 'A':			/* Output all relocs. */
117 		AllRelocs = TRUE;
118 		cmderror |= checkswitch (argv[i], "all relocs");
119 		break;
120 	    case 'D':			/* Dump the symbol table. */
121 		DumpSym = TRUE;
122 		strcpy (DumpSymList, &argv[i][2]);	/* Selections */
123 		break;
124 	    case 'E':			/* Equate file name */
125 		makeequ = TRUE;
126 		if (getfilename (EquateFN, &argv[i][2], "Equate", FALSE))
127 		    cmderror = keepobj = TRUE;
128 		break;
129 	    case 'F':			/* Dump the symbol table. */
130 		FwdProc = TRUE;
131 		cmderror |= checkswitch (argv[i], "forward reference");
132 		break;
133 	    case 'G':			/* XREF all unknown globals */
134 		GlobalXREF = TRUE;
135 		cmderror |= checkswitch (argv[i], "automatic XREF");
136 		break;
137 	    case 'H':			/* Header file name */
138 		if (getfilename (HeaderFN, &argv[i][2], "Header", TRUE))
139 		    cmderror = keepobj = TRUE;
140 		break;
141 	    case 'I':			/* Include directories */
142 		if (argv[i][2]) {
143 		    if (InclList[0])
144 			strcat (InclList, ",");	/* Add to previous list */
145 		    strcat (InclList, &argv[i][2]);
146 		} else {
147 		    fprintf (stderr, "Include directory list is missing.\n");
148 		    cmderror = keepobj = TRUE;
149 		}
150 		break;
151 	    case 'K':			/* Keep object code file. */
152 		keepobj = TRUE;
153 		cmderror |= checkswitch (argv[i], "object file keep");
154 		break;
155 	    case 'X':			/* Cross-reference listing */
156 		XrefList = TRUE;	/* Falls through to case 'L': */
157 	    case 'L':			/* Produce a listing file. */
158 		SuppList = FALSE;
159 		if (getfilename (ListFN, &argv[i][2], "List", FALSE))
160 		    cmderror = keepobj = TRUE;
161 		break;
162 	    case 'M':			/* Offset to small data base */
163 		if (argv[i][2] == '\0') {
164 		    fprintf (stderr, "Small data offset is missing.\n");
165 		    cmderror = keepobj = TRUE;
166 		    break;
167 		}
168 		if (!isdigit (argv[i][2])) {
169 		    fprintf (stderr, "Small data offset is invalid.\n");
170 		    cmderror = TRUE;
171 		    break;
172 		}
173 		DataOffset = CalcValue (&argv[i][2], 0);
174 		break;
175 	    case 'N':			/* Suppress optimization. */
176 		NoOpt = TRUE;
177 		cmderror |= checkswitch (argv[i], "optimization suppress");
178 		break;
179 	    case 'O':			/* Object file name */
180 		if (getfilename (SrecFN, &argv[i][2], "Object", TRUE))
181 		    cmderror = keepobj = TRUE;
182 		break;
183 	    case 'P':			/* Page depth */
184 		if (argv[i][2] == '\0') {
185 		    fprintf (stderr, "Page depth is missing.\n");
186 		    cmderror = keepobj = TRUE;
187 		    break;
188 		}
189 		if (!isdigit (argv[i][2])) {
190 		    fprintf (stderr, "Page depth is invalid.\n");
191 		    cmderror = TRUE;
192 		    break;
193 		}
194 		if ((LnMax = CalcValue (&argv[i][2], 0)) < 10) {
195 		    fprintf (stderr, "Page depth is invalid.\n");
196 		    cmderror = TRUE;
197 		}
198 		break;
199 	    case 'Q':			/* Quiet console display */
200 		if (argv[i][2] == '\0') {
201 		    Quiet = 0;
202 		    break;
203 		}
204 		if (!isdigit (argv[i][2])) {
205 		    fprintf (stderr, "Quiet interval is invalid.\n");
206 		    cmderror = TRUE;
207 		    break;
208 		}
209 		Quiet = CalcValue (&argv[i][2], 0);
210 		break;
211  	    case 'R':			/* Remove optimization - added by Paul Froissart
212                                in v.2.71.F3c */
213  		p=&argv[i][2];
214  		while (*p) switch (tolower(*p++)) {
215  		    case 'a': optim &= ~OPTIM_ADDA; break;
216  		    case 'l': optim &= ~OPTIM_LEA; break;
217  		    case 'm': optim &= ~OPTIM_MOVEM; break;
218  		    default: cmderror |= checkswitch (argv[i],"optimization removal");
219             /* a slightly dirty, but correct way to catch invalid options */
220  		}
221  		break;
222 	    case 'S':			/* Motorola S-format */
223 		SFormat = TRUE;
224 		cmderror |= checkswitch (argv[i], "S-format");
225 		break;
226 	    case 'T':			/* Keep tabs in listing. */
227 		KeepTabs = TRUE;
228 		cmderror |= checkswitch (argv[i], "tab");
229 		break;
230 	    case 'U':			/* Allow unaligned DC/DCB/DS.W/L and code. */
231 		Unaligned = TRUE;
232 		cmderror |= checkswitch (argv[i], "unaligned");
233 		break;
234  	    case 'V':		/* Set value - added by Paul Froissart in v.2.71.F3c
235                            also checks if more than 16 -v switches (Kevin
236                            Kofler) */
237 		if (vopt_num<=15) {
238 		vopt[vopt_num++]=&argv[i][2];
239 		if (!argv[i][2]) { cmderror=TRUE; fprintf(stderr,"Invalid SET value switch (-v).\n"); }
240 		} else {
241 		cmderror=TRUE; fprintf(stderr,"Too many SET value switches (-v).\n");
242 		}
243 		break;
244 	    case 'W':			/* Work storage size(s) */
245 		if (argv[i][2] == '\0') {
246 		    fprintf (stderr, "Work storage size is missing.\n");
247 		    cmderror = keepobj = TRUE;
248 		    break;
249 		}
250 /*		if (argv[i][2] != ',') {*/
251 		if ((argv[i][2] != ',') && (argv[i][2] != ';')) {
252 		/* also allow ; as separator - Kevin Kofler, v.2.71.F3f */
253 		    GetField (argv[i]+2, tempchar);
254 		    if (!isdigit (tempchar[0])) {
255 			fprintf (stderr, "Hash table size is invalid.\n");
256 			cmderror = TRUE;
257 			break;
258 		    }
259 		    HashSize = CalcValue (tempchar, 0);
260 		    if (HashSize >= 16384) {
261 			fprintf (stderr, "Hash table size is too big.\n");
262 			cmderror = TRUE;
263 		    }
264 		}
265 		for (j = 2; argv[i][j]; j++) {
266 /*		    if (argv[i][j] == ',') {*/
267 		    if ((argv[i][j] == ',') || (argv[i][j] == ';')) {
268 		    /* also allow ; as separator - Kevin Kofler, v.2.71.F3f */
269 		    /* Find secondary size. */
270 			if (!isdigit (argv[i][j+1])) {
271 			    fprintf (stderr, "Secondary size is invalid.\n");
272 			    cmderror = TRUE;
273 			    break;
274 			}
275 			maxheap2 = CalcValue (&argv[i][j+1], 0);
276 			if (maxheap2 < MAXLINE)
277 			    maxheap2 = MAXLINE;
278 			maxheap2 &= ~3L;
279 			break;
280 		    }
281 		}
282 		break;
283 	    case 'Y':			/* Display hashing statistics. */
284 		HashStats = TRUE;
285 		cmderror |= checkswitch (argv[i], "hash statistics");
286 		break;
287 	    case 'Z':			/* Debug option */
288 		DebugStart = 0;
289 		DebugEnd = NODEF /*32767*/;
290 /*		if (argv[i][2] != ',') {*/
291 		if ((argv[i][2] != ',') && (argv[i][2] != ';')) {
292 		/* also allow ; as separator - Kevin Kofler, v.2.71.F3f */
293 		/* Debug dump starts here. */
294 		    GetField (argv[i]+2, tempchar);
295 		    if (!isdigit (tempchar[0])) {
296 			fprintf (stderr, "Debug start line is invalid.\n");
297 			cmderror = TRUE;
298 			break;
299 		    }
300 		    DebugStart = CalcValue (tempchar, 0);
301 		}
302 		for (j = 2; argv[i][j]; j++) {
303 /*		    if (argv[i][j] == ',') {*/
304 		    if ((argv[i][j] == ',') || (argv[i][j] == ';')) {
305 		    /* also allow ; as separator - Kevin Kofler, v.2.71.F3f */
306 		    /* Debug dump ends here. */
307 			if (!isdigit (argv[i][j+1])) {
308 			    fprintf (stderr, "Debug end line is invalid.\n");
309 			    cmderror = TRUE;
310 			    break;
311 			}
312 			DebugEnd = CalcValue (&argv[i][j+1], 0);
313 			if (DebugEnd == 0)
314 			    DebugEnd = NODEF /*32767*/;
315 		    }
316 		}
317 		break;
318 	    default:
319 		fprintf (stderr, "Unrecognized switch: %c\n", argv[i][1]);
320 		cmderror = TRUE;
321 		break;
322 	    }
323 	}
324     }
325 
326     if (makeequ)
327 	defaultfile (EquateFN, ".equ");	/* Default equate file name */
328     if (!SuppList)
329 	defaultfile (ListFN, ".lst");	/* Default list file name */
330     else			/* If there's no listing, don't bother */
331 	KeepTabs = TRUE;	/*  expanding tabs - it's faster.      */
332     if (SFormat)
333 	defaultfile (SrecFN, ".s");	/* Default S-format file name */
334     else
335 	defaultfile (SrecFN, ".o");	/* Default object file name */
336 
337 /* Check for duplicate file names. */
338 
339     if (SourceFN[0]) {
340 	cmderror |= checkdupfile (SourceFN, "Source", EquateFN, "equate");
341 	cmderror |= checkdupfile (SourceFN, "Source", ListFN, "listing");
342 	cmderror |= checkdupfile (SourceFN, "Source", SrecFN, "object");
343     } else {
344 	fprintf (stderr, "Source file name is missing.\n");
345 	cmderror = TRUE;
346     }
347     if (EquateFN[0]) {
348 	cmderror |= checkdupfile (EquateFN, "Equate", ListFN, "listing");
349 	cmderror |= checkdupfile (EquateFN, "Equate", SrecFN, "object");
350     }
351     if (ListFN[0]) {
352 	cmderror |= checkdupfile (ListFN, "Listing", SrecFN, "object");
353     }
354 
355 /*	Open files.	*/
356 
357     if (!cmderror) {				/* Source file */
358 	if ((In.Buf = (char *) malloc (BUFFSIZE)) == NULL)
359 	    quit_cleanup ("Out of memory!\n");
360 #ifdef MSDOS
361 	_fmode = O_BINARY;
362 #endif
363 	if ((In.fd = open (SourceFN, 0)) < 0) {
364 	    fprintf (stderr, "Unable to open source file.\n");
365 	    In.fd = NOFD;
366 	    cmderror = TRUE;
367 	}
368 	In.Ptr = In.Lim = In.Buf;
369     }
370 #ifdef MSDOS
371     _fmode = O_TEXT;
372 #endif
373     if (!cmderror && EquateFN[0])		/* Equate file */
374 	cmderror |= xopen (EquateFN, &Eq, "equate");
375 
376     if (!cmderror && !SuppList)			/* Listing file */
377 	cmderror |= xopen (ListFN, &List, "listing");
378 
379 #ifdef MSDOS
380     if (!SFormat)
381 	_fmode = O_BINARY;
382 #endif
383     if (!cmderror)				/* Object code file */
384 	cmderror |= xopen (SrecFN, &Srec, "object code");
385 #ifdef MSDOS
386     _fmode = O_BINARY;
387 #endif
388 
389     if (cmderror) {
390 	fprintf (stderr, "\n");
391 	fprintf (stderr, "68000 Assembler - version %s\n", Version);
392 	fprintf (stderr,
393 		 "Copyright 1985 by Brian R. Anderson\n"
394 		 "AmigaDOS conversion copyright 1991 by Charlie Gibbs.\n"
395 		 "Adapted for use with Fargo by David Ellsworth.\n"
396 #ifdef ST_VERSION
397 		 "Atari ST conversion copyright 1990 by Colin Fox and Darren Schebek\n\n"
398 #endif ST_VERSION
399 #ifdef WIN32
400          "Win32 port copyright 2001-2005 by Kevin Kofler for the TIGCC project\n"
401 #endif
402          "Bugfixes and additions by Julien Muchembled, Paul Froissart and Kevin Kofler\n\n"
403 		 "Usage: a68k <source file>\n"
404 		 "            [-a]                    [-p<page depth>]\n"
405 		 "            [-d[[!]<prefix>]]       [-q[<quiet interval>]]\n"
406 		 "            [-e[<equate file>]]     [-r[a][l][m]]\n"
407 		 "            [-f]                    [-s]\n"
408 		 "            [-g]                    [-t]\n"
409 		 "            [-h<header file>]       [-u]\n"
410 		 "            [-i<include dirlist>]   [-v<name>[,<value>]]\n"
411 		 "            [-k]                    "
412 		 "[-w[<hash size>][,<heap size>]]\n"
413 		 "            [-l[<listing file>]]    [-x]\n"
414 		 "            [-m<small data offset>] [-y]\n"
415 		 "            [-n]                    "
416 		 "[-z[<debug start>][,<debug end>]]\n"
417 		 "            [-o<object file>]\n\n"
418 		 "Heap size default:  -w"
419 		 "%ld,%ld\n", (long) DEFHASH, (long) DEFHEAP2);
420 	SrecFN[0] = '\0';	/* Don't scratch the object file! */
421 	quit_cleanup ("\n");
422     }
423 
424     if (Quiet != 0) {
425 	printf ("68000 Assembler - version %s\n", Version);
426 	printf ("Copyright 1985 by Brian R. Anderson\n"
427 		"AmigaDOS conversion copyright 1991 by Charlie Gibbs.\n"
428 		"Adapted for use with Fargo by David Ellsworth.\n"
429 #ifdef ST_VERSION
430 		"Atari ST conversion copyright 1990 by Colin Fox and Darren Schebek\n\n"
431 #endif ST_VERSION
432 #ifdef WIN32
433 		"Win32 port copyright 2001-2005 by Kevin Kofler for the TIGCC project\n"
434 #endif
435 		"Bugfixes and additions by Julien Muchembled, Paul Froissart and Kevin Kofler\n\n"
436 		"Assembling %s\n\n", SourceFN);
437     }
438 
439 /* Allocate initial symbol table chunks. */
440 
441     templong = sizeof (struct SymTab *) * HashSize;
442     Hash = (struct SymTab **) malloc ((unsigned) templong);
443     if (Hash == NULL)
444 	quit_cleanup ("Out of memory!\n");
445     for (hashptr = Hash, i = 0; i < HashSize; hashptr++, i++)
446 	*hashptr = NULL;	/* Clear the hash table. */
447 
448     SymStart = (struct SymTab *) malloc ((unsigned) CHUNKSIZE);
449     if (SymStart == NULL)
450 	quit_cleanup ("Out of memory!\n");
451     SymCurr = SymStart;			/* Make the first chunk current. */
452     SymCurr->Link = NULL;		/* Clear forward pointer. */
453     SymLim = SymCurr;
454     SymLim++;				/* Start of names */
455 
456     NameStart = (struct NameChunk *) malloc ((unsigned) CHUNKSIZE);
457     if (NameStart == NULL)
458 	quit_cleanup ("Out of memory!\n");
459     NameCurr = NameStart;		/* Make the first chunk current. */
460     NameCurr->Link = NULL;		/* Clear forward pointer. */
461     NameLim = (char *) NameCurr + sizeof (char *);  /* Start of names */
462 
463 /* Allocate the relocation attribute table. */
464 
465     RelStart = (struct RelTab *) malloc ((unsigned) CHUNKSIZE);
466     if (RelStart == NULL)
467 	quit_cleanup ("Out of memory!\n");
468     RelCurr = RelStart;			/* Relocation table */
469     RelCurr->Link = NULL;		/* No additional chunks */
470     RelLast = NULL;			/* There are no entries yet. */
471     RelLim = RelStart;
472     RelLim++;				/* First unused space */
473 
474 /* Allocate the secondary heap (input files and parser stack). */
475 
476     Heap2 = malloc ((unsigned) maxheap2);
477     if (Heap2 == NULL)
478 	quit_cleanup ("Out of memory!\n");
479 
480 /* Allocate the INCLUDE skip table. */
481 
482     SkipLim = (struct SkipEnt *) malloc ((unsigned) INCSKSIZ);
483     if (SkipLim == NULL)
484 	quit_cleanup ("Out of memory!\n");
485     SkipIdx = SkipLim;
486     SetFixLim = (struct SetFixup *) ((char *) SkipLim + INCSKSIZ);
487     IncStart = 0;
488 
489 /* Allocate the forward branch optimization log. */
490 
491     if (NoOpt) {
492 	FwdStart = NULL;
493     } else {
494 	FwdStart = (struct FwdTable *) malloc ((unsigned) FWDSIZE);
495 	if (FwdStart == NULL)
496 	    quit_cleanup ("Out of memory!\n");
497 	FwdCurr = FwdStart;	/* Make the first chunk current. */
498 	FwdCurr->Link = NULL;	/* Clear forward pointer. */
499 	FwdLim2 = (int *) ((char *) FwdCurr + sizeof (struct FwdTable *));
500 	FwdPtr = FwdLim2;	/* Current position in pass 2 */
501     }
502 
503 /*-------------------------------------------------------------------
504 
505     Begin Pass 1.
506 								   */
507     Pass2 = FALSE;
508     startpass ('1', maxheap2);
509     NumSyms = 0;	/* There's nothing in the symbol table yet. */
510     NextHunk = 0L;	/* Start in hunk zero. */
511     LowInF = InF;	/* Initialize secondary heap usage pointers. */
512     High2 = NextFNS;
513     Low2  = (char *) LowInF;
514     FwdLim1     = FwdBranch;	/* Forward branch controls */
515     FwdFixLimit = FwdBranchFix;
516 
517     /* Define ".A68K" as a SET symbol with an absolute value of 1.
518 	This allows programs to identify this assembler.	*/
519     AddSymTab (".A68K", 1L, (long) ABSHUNK, 0, 4);  /* All spellings */
520     AddSymTab (".A68k", 1L, (long) ABSHUNK, 0, 4);
521     AddSymTab (".a68K", 1L, (long) ABSHUNK, 0, 4);
522     AddSymTab (".a68k", 1L, (long) ABSHUNK, 0, 4);
523 
524     /* If -a is given, define "__ld_all_relocs" as an XDEF symbol to a dummy label.
525 	This allows linkers to identify such object files. -- Kevin Kofler, v.2.71.F3l	*/
526     if (AllRelocs) AddSymTab ("__ld_all_relocs", 0L, 0L, 1, 2);
527 
528     /* Add -v variables - added by Paul Froissart in 2.71.F3c: */
529     while (vopt_num) {
530     	char *s=vopt[--vopt_num]; long val; /* decrement vopt_num at the
531     	                               beginning - Kevin Kofler, v.2.71.F3c */
532 /*    	while (*s && *s!=',') s++;*/
533     	while ((*s) && (*s!=',') && (*s!=';') && (*s!='=')) s++;
534     	/* also allow ; and = as separators - Kevin Kofler, v.2.71.F3f */
535     	if (s==vopt[vopt_num]) /* exit(0x39); */
536     	quit_cleanup ("Invalid SET value switch (-v).\n");
537     	/* exit cleanly and with an error message - Kevin Kofler, v.2.71.F3c */
538     	if (!*s) val=1; else { *s++=0; val=CalcValue(s,0); }
539     	AddSymTab(vopt[vopt_num],val,(long)ABSHUNK,0,4);
540     	/* vopt_num--; */ /* see above - Kevin Kofler, v.2.71.F3c */
541     }
542 
543     endfile = FALSE;
544     Dir = None;
545     while (!endfile && (Dir != End)) {
546 	PrevDir = Dir;			/* Save previous directive. */
547 	endfile = LineParts (/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);	/* Get a statement. */
548 pass1cont: /* necessary for optional END - Paul Froissart, v.2.71.F3c */
549 	GetObjectCode (/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);		/* Process the statement. */
550 
551 	if (IncStart != 0) {
552 	    if ((OpCode[0] != '\0') && (Dir < SkipDir)) {
553 		IncStart = 0;			/* We can't      */
554 		if (SkipLim->Set1 != NULL) {	/*  skip this    */
555 		    SetFixLim = SkipLim->Set1;	/*  INCLUDE file */
556 		    SetFixLim++;		/*  in pass 2.   */
557 		}
558 	    }
559 	}
560 	if ((HunkType == HunkNone) && (AddrAdv != 0)) {
561 	    DoSection ("", 0, "", 0, "", 0);	/* Start unnamed CODE section. */
562 	    MakeHunk = TRUE;
563 	}
564 	if ((Label[0] != '\0')			/* If the statement is labeled */
565 	&& (Dir != Set) && (Dir != Equr) && (Dir != Reg)) {
566 	    if (!ReadSymTab (Label)) {		/* Make a new entry. */
567 		AddSymTab (Label, AddrCnt, CurrHunk, LineCount, 0);
568 	    } else if ((Sym->Flags & 1)		/* If dup., ignore... */
569 	    || (Sym->Defn == NODEF)) {		/* else fill in... */
570 		Sym->Val = AddrCnt;		/* Current loc. */
571 		Sym->Hunk = CurrHunk;		/* Hunk number */
572 		Sym->Defn = LineCount;		/* Statement number */
573 		Sym->Flags &= ~1;		/* Clear XREF flag. */
574 		if (Sym->Flags & 0x80) {	/* If it's PUBLIC, */
575 		    Sym->Flags |= 2;		/*  make it XDEF. */
576 		}
577 	    }
578         else isError=TRUE; /* bugfix by Kevin Kofler for the TIGCC team in
579                               v.2.71.F3a
580                               if duplicate, set "error detected" flag */
581 	    if (Dir == Equ) {
582 		Sym->Val = ObjSrc;		/* Equated value */
583 		Sym->Hunk = Src.Hunk;		/* Hunk number */
584 	    }
585 	    if (!NoOpt && (Dir != Equ)) {	/* Forward optimization */
586 		PackFwdBranch (/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);		/* Drop expired entries. */
587 		fp1 = FwdBranch;
588 		while (fp1 < FwdLim1) {		/* Scan forward branches. */
589 		    if (fp1->FwdSym == Sym) {	/* It branched here. */
590 			if (fp1->Loc != (AddrCnt-4)) {	/* Don't make zero displacement! */
591 			    if (fp1->Line < LineCount)
592 				Sym->Val -= 2;	/* Move the label back. */
593 			    AddrCnt -= 2;	/* Shorten the program. */
594 			    for (fsp = FwdBranchFix; fsp < FwdFixLimit; fsp++) {
595 				if (fp1->Loc<(*fsp)->Val) {	/* Adjust labels  */
596 				    (*fsp)->Val -= 2;		/*  within range. */
597 				}
598 			    }
599 			    if ((char *) FwdLim2 >= ((char *) FwdCurr + FWDSIZE)) {
600 				FwdCurr->Link =	/* Get a new chunk. */
601 				    (struct FwdTable *) malloc ((unsigned) FWDSIZE);
602 				if (FwdCurr->Link == NULL)
603 				    quit_cleanup ("Out of memory!\n");
604 				FwdCurr = FwdCurr->Link;
605 				FwdCurr->Link = NULL; /* Make sure it does not link to anything
606 				It is a freshly allocated block AT THE END of the linked list!
607 				bugfix submitted by [Pollux] (Paul Froissart) for 2.71.F3a */
608 				FwdLim2 = (int *)
609 				    ((char *) FwdCurr + sizeof (struct FwdTable *));
610 			    }
611 			    *FwdLim2++ = fp1->Line; /* Flag this branch in pass 2. */
612 			}
613 			fp3 = fp2 = fp1;
614 			fp3++;
615 			while (fp3 < FwdLim1) {	/* Remove processed entry. */
616 			    fp2->Loc    = fp3->Loc - 2;	/* Locations shifted too! */
617 			    fp2->FwdSym = fp3->FwdSym;
618 			    fp2->Line   = fp3->Line;
619 			    fp2++;
620 			    fp3++;
621 			}
622 			FwdLim1--;	/* Decrement table limit pointer. */
623 			fp1--;		/* Offset increment below. */
624 		    }
625 		    fp1++;		/* Check the next entry. */
626 		}
627 		if (FwdLim1 > FwdBranch) {	/* Store labels within    */
628 		    *FwdFixLimit++ = Sym;	/*  range of fwd. branch. */
629 		}
630 	    }
631 	}
632 	AddrCnt	+= AddrAdv * DupFact;	/* Advance the location counter. */
633 
634 	if (endfile) { /* END is now optional */
635 	    strcpy(Line," end"); endfile=0;	/* Enhancement by Paul Froissart */
636 	    SubArgs(/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/); GetParts(/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);	/*     in version v2.71.F3c      */
637 	    goto pass1cont;
638 	}
639 
640     }
641     if ((HunkType == HunkNone) && (NumSyms != 0)) { /* Dummy section   */
642 	DoSection ("", 0, "", 0, "", 0);	    /*  to get XDEF    */
643 	MakeHunk = TRUE;			    /*  symbols if any */
644     }
645     if (HunkType != HunkNone)
646 	if (AddrCnt > OrgHigh)
647 	    Sect->Val = AddrCnt;	/* End of the last section */
648 	else
649 	    Sect->Val = OrgHigh;	/* We've ORGed higher. */
650 
651     if (InclErrs)
652 	quit_cleanup ("Fatal errors - assembly aborted\n");
653 
654     if (Quiet > 0)
655 	fprintf (stderr, "%d\n", LineCount);
656     else if (Quiet < 0)
657 	fprintf (stderr, "%d\n\n", InF->Line);
658 
659 
660 
661 /*----------------------------------------------------------------
662 
663 	Begin Pass 2.
664 								*/
665     Pass2 = TRUE;
666     lseek (In.fd, 0L, 0);		/* "Rewind" the source file. */
667     In.Ptr = In.Lim = In.Buf;
668     startpass ('2', maxheap2);
669 /*    RefLim = (struct Ref *) SymLim; */	/* Cross-reference table */
670     RefLim = (struct Ref *) (SymLim+1);
671 /* don't overwrite the last symbol - Kevin Kofler, v.2.71.F3h */
672 
673 /* Calculate the total size of each section type,
674     reset all section pointers to the beginning, and
675     write all absolute symbols to an equate file if desired. */
676 
677     codesize = datasize = bsssize = 0;
678     if (EquateFN[0]) {
679 	xputs (&Eq, "* Equate file for ");
680 	xputs (&Eq, SourceFN);
681 	xputs (&Eq, "\n* Created by");
682 	xputs (&Eq, " A68k version ");
683 	xputs (&Eq, Version);
684 	xputs (&Eq, "\n");
685     }
686     Sym = SymChunk = SymStart;
687     Sym++;
688     SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
689     while (Sym) {
690 	if (Sym->Flags & 0x10) {
691 	    templong = (Sym->Val + 3) & ~3L;		/* Hunk size */
692 	    j = (Sym->Hunk & 0x3FFF0000L) >> 16;	/* Hunk type */
693 	    if (j == HunkCode)		/* Accumulate sizes by type. */
694 		codesize += templong;
695 	    else if (j == HunkData)
696 		datasize += templong;
697 	    else
698 		bsssize += templong;
699 	    Sym->Val = 0L;		/* Back to start of all sections */
700 	}
701 	if (EquateFN[0]) {
702 	    if (((Sym->Hunk & 0x00007FFFL) == ABSHUNK)
703 	    && ((Sym->Flags == 0) || (Sym->Flags == 2))) {
704 		xputs (&Eq, Sym->Nam);
705 		xputs (&Eq, "\tEQU\t$");
706 		LongPut (&Eq, Sym->Val, 4);
707 		xputs (&Eq, "\n");
708 	    }
709 	}
710 	Sym = NextSym (Sym);	/* Try for another symbol table entry. */
711     }
712     if (EquateFN[0])
713 	xclose (&Eq);
714 
715 /* Write sign-on messages for listing file. */
716 
717     LnCnt = LnMax;
718     PgCnt = 0;
719     if (!SuppList) {
720 	CheckPage (&List, FALSE);		/* Print headings. */
721 	xputs (&List, "68000 Assembler - version ");
722 	xputs (&List, Version);
723 	xputs (&List, "\nCopyright 1985 by Brian R. Anderson.\n");
724 	xputs (&List, "AmigaDOS conversion copyright 1991");
725 	xputs (&List, " by Charlie Gibbs.\n\n");
726 	LnCnt += 4;
727     }
728 
729     StartSrec (&Srec, IdntName);	/* Write object header record. */
730 
731 /*	Process the second pass.	*/
732 
733     endfile = FALSE;
734     Dir = None;
735     while (!endfile && (Dir != End)) {
736 	PrevDir = Dir;			/* Save previous directive. */
737 	endfile = LineParts (/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);	/* Get a statement. */
738 
739 	/* if (!endfile) { */
740 pass2cont: /* necessary for optional END - Paul Froissart, v.2.71.F3c */
741 
742 	    GetObjectCode (/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);	/* Process the statement. */
743 	    if (Label[0] != '\0') {	/* If statement is labeled, */
744 		ReadSymTab (Label);	/*  check for duplicate defn. */
745         if (Sym) /* Check if Sym actually exists -- bugfix by Kevin Kofler for
746                     the TIGCC Team in v.2.71.F3a. */
747         { /* (TIGCC) */
748  		if (Sym->Defn != LineCount) {
749 		    AddRef (LineCount);	/* Got one - flag as reference. */
750 		    if (Dir == Set) {
751 			if ((Sym->Flags & 4) == 0)
752 			    Error (LabLoc, SymDup); /* Can't SET normal label. */
753 		    } else {
754 			Error (LabLoc, SymDup);	/* Ordinary duplicate */
755 		    }
756 		} else if (Dir == Set) {
757 		    AddRef (LineCount);	/* Flag all SETs as references. */
758 		} else {
759 		    if (Sym->Val != AddrCnt)
760 			if ((Dir != Equ) && (Dir != Equr) && (Dir != Reg))
761 			    Error (0, Phase);	/* Assembler error */
762 		}
763         } /* (TIGCC) */
764         else /* (TIGCC) */
765         Error (0, Phase); /* (TIGCC) */
766 	    }
767 	    WriteListLine (&List);
768 /*	    WriteSrecLine (&Srec); */
769 	    WriteSrecLine (); /* removed useless parameter - Kevin Kofler, v.2.71.F3d */
770 	    AddrCnt += AddrAdv * DupFact;	/* Advance the location counter. */
771 
772 /*	} else {
773 	    Error (0, EndErr);		** END statement is missing. **
774 	    WriteListLine (&List); */
775 	if (endfile) { /* END is now optional */
776 	    strcpy(Line," end"); endfile=0;	/* Enhancement by Paul Froissart */
777 	    SubArgs(/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/); GetParts(/*dummy*/ /*(using now void in v.2.71.F3d - Kevin Kofler)*/);	/*     in version v2.71.F3c      */
778 	    goto pass2cont;
779 
780 	}
781     }
782     if ((HunkType == HunkNone) && (NumSyms != 0)) { /* Dummy section   */
783 	DoSection ("", 0, "", 0, "", 0);	    /*  to get XDEF    */
784 	MakeHunk = TRUE;			    /*  symbols if any */
785     }
786 
787 /*----------------------------------------------------------------
788 
789 	Clean up.
790 								*/
791 
792     if (HunkType != HunkNone)
793 	if (AddrCnt > OrgHigh)
794 	    Sect->Val = AddrCnt;	/* End of the last section */
795 	else
796 	    Sect->Val = OrgHigh;	/* We've ORGed higher. */
797 
798     if (Quiet > 0)
799 	fprintf (stderr, "%d", LineCount);	/* Final line number */
800     else if (Quiet < 0)
801 	fprintf (stderr, "%d\n", InF->Line);
802     fflush (stderr);			/* Make sure it gets out. */
803 
804     close (In.fd);		/* We're finished with the source file. */
805     In.fd = NOFD;
806     free (In.Buf);
807     In.Buf = NULL;
808 
809     EndSdata (&Srec, EndAddr);	/* Write remaining data and end record. */
810     xclose (&Srec);		/* We're finished with the object file. */
811     if ((ErrorCount != 0) && (!keepobj))
812 	unlink (SrecFN);	/* Scratch it if there were errors. */
813 
814     RelCurr = RelStart;
815     RelStart = NULL;
816     while (RelCurr != NULL) {
817 	RelLim = RelCurr;
818 	RelCurr = RelCurr->Link;
819 	free (RelLim);		/* Free the relocation table. */
820     }
821 
822     if (Heap2 != NULL) {
823 	free (Heap2);		/* Free the secondary heap. */
824 	Heap2 = NULL;
825     }
826 
827     if (XrefList)
828 	WriteSymTab (&List);	/* List the symbol table. */
829 
830 /* Display final error count. */
831 
832     if (Quiet != 0)
833 	fprintf (stderr, "\nEnd of assembly - ");
834     if (!SuppList)
835 	xputs (&List, "\nEnd of assembly - ");
836     if (ErrorCount == 0) {
837 	if (Quiet != 0)
838 	    fprintf (stderr, "no errors were found.\n");
839 	if (!SuppList)
840 	    xputs (&List, "no errors were found.\n");
841     } else if (ErrorCount == 1) {
842 	if (Quiet != 0)
843 	    fprintf (stderr, "1 error was found.\n");
844 	if (!SuppList)
845 	    xputs (&List, "1 error was found.\n");
846     } else {
847 	if (Quiet != 0)
848 	    fprintf (stderr, "%d errors were found.\n", ErrorCount);
849 	if (!SuppList) {
850 	    sprintf (tempchar, "%d errors were found.\n", ErrorCount);
851 	    xputs (&List, tempchar);
852 	}
853     }
854 
855 /* Display heap usage. */
856 
857     if (Quiet != 0)
858 	fprintf (stderr, "Heap usage:  -w%ld", HashSize);
859     if (!SuppList) {
860 	sprintf (tempchar, "Heap usage:  -w%ld", HashSize);
861 	xputs (&List, tempchar);
862     }
863     templong = (long) (High2 - Heap2);
864     if (Low2 < (char *) LowInF)
865 	templong += (long) (Heap2 + maxheap2 - Low2);
866     else
867 	templong += (long) (Heap2 + maxheap2 - (char *) LowInF);
868     if (Quiet != 0)
869 	fprintf (stderr, ",%ld\n", templong);
870     if (!SuppList) {
871 	sprintf (tempchar, ",%ld\n", templong);
872 	xputs (&List, tempchar);
873     }
874 
875 /* Display the total size of all section types. */
876 
877     if (Quiet != 0) {
878 	fprintf (stderr, "Total hunk sizes:  %lx code, ", codesize);
879 	fprintf (stderr, "%lx data, %lx BSS\n", datasize, bsssize);
880     }
881     if (!SuppList) {
882 	sprintf (tempchar, "Total hunk sizes:  %lx code, ", codesize);
883 	xputs (&List, tempchar);
884 	sprintf (tempchar, "%lx data, %lx BSS\n", datasize, bsssize);
885 	xputs (&List, tempchar);
886     }
887 
888 /* Display hashing statistics if required. */
889 
890     if (HashStats && (NumSyms != 0)) {
891 	printf ("\n");
892 	printf ("HASH CHAIN STATISTICS - %d symbols\n\n", NumSyms);
893 	templong = (NumSyms + 1) * sizeof (int);
894 	HashCount = (int *) malloc ((unsigned) templong);
895 	if (HashCount == NULL)
896 	    quit_cleanup ("Out of memory!\n");
897 
898 	printf ("Length     No. of chains\n");
899 	printf ("------     -------------\n");
900 	intptr = HashCount;
901 	for (i = 0; i <= NumSyms; i++)
902 	    *(intptr++) = 0;	/* Clear hash chain length counters. */
903 
904 	hashptr = Hash;
905 	for (i = 0; i < HashSize; i++) {
906 	    j = 0;
907 	    if ((Sym = *hashptr) != NULL) {
908 		j++;		/* This chain has at least one entry. */
909 		while ((Sym = Sym->Link) != NULL) {
910 		    j++;	/* Count entries in the chain. */
911 		}
912 	    }
913 	    intptr = HashCount + j;
914 	    (*intptr)++;	/* Bump counter by chain length. */
915 	    hashptr++;
916 	}
917 	intptr = HashCount;
918 	for (i = 0; i <= NumSyms; i++) {
919 	    if (*intptr)
920 		printf ("%4d          %4d\n", i, *intptr);
921 	    intptr++;
922 	}
923 	free (HashCount);		/* Free hash statistics table. */
924 	HashCount = NULL;
925     }
926 
927 /* All done! */
928     if (!SuppList) {
929 	xputs (&List, "\f");	/* One last page eject */
930 	xclose (&List);		/* We're finished with the listing file. */
931     }
932     quit_cleanup ("");		/* Normal termination */
933 }
934 
935 
936 
937 /*======================================================================*/
938 /*									*/
939 /*              Subroutines used by the main program			*/
940 /*									*/
941 /*======================================================================*/
942 
943 
944 
getfilename(name,arg,desc,needit)945 int getfilename (name, arg, desc, needit)
946 char *name, *arg, *desc;
947 int needit;
948 /* If "name" is not a duplicate, copies "arg" to it, else flags
949     duplicate using "desc".  If "needit" is TRUE, also flags
950     an error if "arg" is a null string.
951     Returns TRUE if an error is found, FALSE otherwise. */
952 {
953     if (*name) {
954 	fprintf (stderr, "%s file is declared more than once.\n", desc);
955 	return (TRUE);
956     }
957     if (*arg) {
958 	strcpy (name, arg);
959 	return (FALSE);
960     }
961     if (needit) {
962 	fprintf (stderr, "%s file name is missing\n", desc);
963 	return (TRUE);
964     }
965     return (FALSE);
966 }
967 
968 
969 
checkswitch(sw,name)970 int checkswitch (sw, name) char *sw, *name;
971 /* Displays an error message and returns TRUE if the argument
972     pointed to by "s" is more than two characters long.
973     Just returns FALSE otherwise.				*/
974 {
975     if (strlen (sw) > 2) {
976 	fprintf (stderr, "Invalid %s switch (%s).\n", name, sw);
977 	return (TRUE);
978     } else {
979 	return (FALSE);
980     }
981 }
982 
983 
984 
defaultfile(name,ext)985 void defaultfile (name, ext) char *name, *ext;
986 /* If "name" is a null string, search for the last period in "name"
987     (if any) and append "ext".
988     If "name" doesn't contain a period, append a period and "ext". */
989 {
990     char *s;
991 
992     if (*name == '\0') {	/* If name isn't specified... */
993 	strcpy (name,SourceFN);	/* Start with source file name. */
994 	s = name+strlen(name);	/* Scan backwards for period. */
995 	while (--s > name) {
996 	    if (*s == '.') {
997 		*s = '\0';	/* Chop off name extension. */
998 		break;
999 	    }
1000 	}
1001 	strcat (name, ext);	/* Add name extension. */
1002     }
1003 }
1004 
1005 
1006 
checkdupfile(name1,desc1,name2,desc2)1007 int checkdupfile (name1, desc1, name2, desc2)
1008 char *name1, *desc1, *name2, *desc2;
1009 /* If "name1" is the same as "name2", display an error message using
1010     "desc1" and "desc2" and return TRUE.  Otherwise, return FALSE. */
1011 {
1012     if (strcmp (name1, name2) == 0) {
1013 	fprintf (stderr,
1014 	    "%s and %s file names are the same.\n", desc1, desc2);
1015 	return (TRUE);
1016     } else {
1017 	return (FALSE);
1018     }
1019 }
1020 
1021 
1022 
startpass(pchar,maxheap2)1023 void startpass (pchar, maxheap2) char pchar; long maxheap2;
1024 /* Set up to start the next pass. */
1025 {
1026     if (Quiet > 0) {
1027 	fprintf (stderr, "PASS %c line ", pchar);
1028 	fflush (stderr);
1029     } else if (Quiet < 0) {
1030 	fprintf (stderr, "PASS %c\n", pchar);
1031     }
1032     NextFNS = Heap2;
1033     InF = (struct InFCtl *) (Heap2 + maxheap2);
1034     InF--;
1035     InFNum = OuterMac = SkipNest = InF->Pos = InF->MCnt = 0;
1036     InF->Line = 0;
1037     InF->UPtr = 0;
1038     InF->NPtr = NextFNS;
1039     InF->NArg = -1;
1040     InF->MCnt = 0;
1041     strcpy (NextFNS, SourceFN);
1042     ShowFile (FALSE);			/* Show source file name. */
1043     NextFNS += strlen (SourceFN) + 1;
1044     LineCount = LabLine = MacCount = ErrorCount = 0;
1045     AddrCnt = CurrHunk = SectStart = EndAddr = 0L;
1046     HunkType = HunkNone;		/* We're not in a hunk yet. */
1047     HunkFlags = SectLine = HunkSeq = 0;
1048     ListOff = MakeHunk = InnrFMac = FALSE;
1049     SmallData = -1;
1050     TTLstring[0] = '\0';		/* Clear the title string. */
1051 }
1052 
1053 
1054 
quit_cleanup(s)1055 void quit_cleanup (s) char *s;
1056 /* Clean up and exit.  If "s" doesn't point to a null string, print the
1057     string as an error message, remove the partially-formed object
1058     file if it exists, and exit with an error code.			*/
1059 {
1060     if (In.fd != NOFD)			/* Close all files... */
1061 	close (In.fd);
1062     if (In.Buf != NULL)			/*  and free buffers. */
1063 	free (In.Buf);
1064     if (Srec.fd != NOFD)
1065 	xclose (&Srec);
1066     if (List.fd != NOFD)
1067 	xclose (&List);
1068     if (Eq.fd != NOFD)
1069 	xclose (&Eq);
1070 
1071     if (Hash != NULL)
1072 	free (Hash);			/* Free the hash table. */
1073 
1074     SymCurr = SymStart;
1075     while (SymCurr != NULL) {
1076 	SymLim = SymCurr;
1077 	SymCurr = SymCurr->Link;
1078 	free (SymLim);			/* Free the symbol table. */
1079     }
1080 
1081     NameCurr = NameStart;
1082     while (NameCurr != NULL) {
1083 	NameLim = (char *) NameCurr;
1084 	NameCurr = NameCurr->Link;
1085 	free (NameLim);			/* Free the name table. */
1086     }
1087 
1088     RelCurr = RelStart;
1089     while (RelCurr != NULL) {
1090 	RelLim = RelCurr;
1091 	RelCurr = RelCurr->Link;
1092 	free (RelLim);			/* Free the relocation table. */
1093     }
1094 
1095     FwdCurr = FwdStart;
1096     while (FwdCurr != NULL) {
1097 	FwdLim2 = (int *) FwdCurr;
1098 	FwdCurr = FwdCurr->Link;
1099 	free (FwdLim2);			/* Free the forward branch log. */
1100     }
1101 
1102     if (Heap2 != NULL)
1103 	free (Heap2);			/* Free the secondary heap. */
1104 
1105     if (SymSort != NULL)
1106 	free (SymSort);			/* Free symbol table sort area. */
1107 
1108     if (HashCount != NULL)
1109 	free (HashCount);		/* Free hash statistics table. */
1110 
1111     /* Get rid of leftover AddrDiffs list -- Kevin Kofler, v.2.71.F3l */
1112     while (AddrDiffs) {
1113       struct AddrDiff *next=AddrDiffs->Link;
1114       free(AddrDiffs);
1115       AddrDiffs=next;
1116     }
1117 
1118     if (*s) {				/* If we have an error message, */
1119 	if (SrecFN[0])
1120 	    unlink (SrecFN);		/*  scratch the object file,    */
1121 	fprintf (stderr, "%s", s);	/*  display the error message,  */
1122 	exit (20);			/*  and die. */
1123     } else {
1124 	exit (ErrorCount ? 10 : 0);	/* Normal termination */
1125     }
1126 }
1127