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