1 /*
2     the DASM macro assembler (aka small systems cross assembler)
3 
4     Copyright (c) 1988-2002 by Matthew Dillon.
5     Copyright (c) 1995 by Olaf "Rhialto" Seibert.
6     Copyright (c) 2003-2008 by Andrew Davie.
7     Copyright (c) 2008 by Peter H. Froehlich.
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License along
20     with this program; if not, write to the Free Software Foundation, Inc.,
21     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23 
24 /*
25  *  MAIN.C
26  *  DASM   sourcefile
27  *  NOTE: must handle mnemonic extensions and expression decode/compare.
28  */
29 
30 #include <strings.h>
31 #include <unistd.h>
32 
33 #include "version.h"
34 #include "asm.h"
35 
36 static const char dasm_id[] = DASM_ID;
37 
38 #define ISEGNAME    "INITIAL CODE SEGMENT"
39 
40 /*
41    replace old atoi() calls; I wanted to protect this using
42    #ifdef strtol but the C preprocessor doesn't recognize
43    function names, at least not GCC's; we should be safe
44    since MS compilers document strtol as well... [phf]
45 */
46 #define atoi(x) ((int)strtol(x, (char **)NULL, 10))
47 
48 static const char *cleanup(char *buf, bool bDisable);
49 
50 MNEMONIC *parse(char *buf);
51 void panic(const char *str);
52 MNEMONIC *findmne(char *str);
53 void clearsegs(void);
54 void clearrefs(void);
55 
56 static unsigned int hash1(const char *str);
57 static void outlistfile(const char *);
58 
59 // buffers to supress errors and messages until last pass
60 char *passbuffer [2] = { NULL, NULL};
61 #define ERRORBUF 0
62 #define MSGBUF 1
63 void passbuffer_clear(int);
64 void passbuffer_update(int,char *);
65 void passbuffer_output(int);
66 void passbuffer_cleanup(void);
67 
68 int mlflag = 0; // multi-line comments
69 
70 static char erroradd1[500]; // temp error holders
71 static char erroradd2[500];
72 static char erroradd3[500];
73 
74 /* Table encapsulates errors, descriptions, and fatality flags. */
75 
76 ERROR_DEFINITION sErrorDef[] = {
77 
78     /* Error #, STOPEND, Description */
79 
80     { ERROR_NONE,                                   true,   "OK"   },
81     { ERROR_COMMAND_LINE,                           true,   "Check command-line format."   },
82     { ERROR_FILE_ERROR,                             true,   "Unable to open file."   },
83     { ERROR_NOT_RESOLVABLE,                         true,   "Source is not resolvable."   },
84     { ERROR_TOO_MANY_PASSES,                        true,   "Too many passes (%s)."   },
85     { ERROR_NON_ABORT,                              true,   "See previous output"   },
86     { ERROR_SYNTAX_ERROR,                           true,   "Syntax Error '%s'."   },
87     { ERROR_EXPRESSION_TABLE_OVERFLOW,              true,   "Expression table overflow."   },
88     { ERROR_UNBALANCED_BRACES,                      true,   "Unbalanced Braces []."   },
89     { ERROR_DIVISION_BY_0,                          true,   "Division by zero."  },
90     { ERROR_UNKNOWN_MNEMONIC,                       true,   "Unknown Mnemonic '%s'."   },
91     { ERROR_ILLEGAL_ADDRESSING_MODE,                false,  "Illegal Addressing mode '%s'."   },
92     { ERROR_ILLEGAL_FORCED_ADDRESSING_MODE,         true,   "Illegal forced Addressing mode on '%s'."   },
93     { ERROR_NOT_ENOUGH_ARGUMENTS_PASSED_TO_MACRO,   true,   "Not enough args passed to Macro."   },
94     { ERROR_PREMATURE_EOF,                          false,  "Premature EOF."   },
95     { ERROR_ILLEGAL_CHARACTER,                      true,   "Illegal character '%s'."   },
96     { ERROR_BRANCH_OUT_OF_RANGE,                    false,   "Branch out of range (%s bytes)."   },
97     { ERROR_ERR_PSEUDO_OP_ENCOUNTERED,              true,   "ERR pseudo-op encountered."  },
98     { ERROR_ORIGIN_REVERSE_INDEXED,                 false,  "Origin Reverse-indexed."   },
99     { ERROR_EQU_VALUE_MISMATCH,                     false,  "EQU: Value mismatch."   },
100     { ERROR_ADDRESS_MUST_BE_LT_100,                 true,   "Value in '%s' must be <$100."  },
101     { ERROR_ADDRESS_MUST_BE_LT_10000,               true,   "Value in '%s' must be <$10000."  },
102     { ERROR_ILLEGAL_BIT_SPECIFICATION,              true,   "Illegal bit specification."   },
103     { ERROR_NOT_ENOUGH_ARGS,                        true,   "Not enough arguments."   },
104     { ERROR_LABEL_MISMATCH,                         false,   "Label mismatch...\n --> %s"  },
105     { ERROR_MACRO_REPEATED,                         true,   "Macro \"%s\" definition is repeated."  },
106     { ERROR_VALUE_UNDEFINED,                        true,   "Value Undefined."   },
107     { ERROR_PROCESSOR_NOT_SUPPORTED,                true,   "Processor '%s' not supported."  },
108     { ERROR_REPEAT_NEGATIVE,                        false,  "REPEAT parameter < 0 (ignored)."   },
109     { ERROR_BADERROR,                               true,   "Bad error value (internal error)." },
110     { ERROR_ONLY_ONE_PROCESSOR_SUPPORTED,           true,   "Only one processor type may be selected." },
111     { ERROR_BAD_FORMAT,                             true,   "Bad output format specified." },
112 	{ ERROR_VALUE_MUST_BE_1_OR_4,					true,	"Value in '%s' must be 1 or 4." },
113 	{ ERROR_VALUE_MUST_BE_LT_10,					true,	"Value in '%s' must be <$10." },
114 	{ ERROR_VALUE_MUST_BE_LT_8,						true,	"Value in '%s' must be <$8." },
115 	{ ERROR_VALUE_MUST_BE_LT_F,						true,	"Value in '%s' must be <$f." },
116 	{ ERROR_VALUE_MUST_BE_LT_10000,					true,	"Value in '%s' must be <$10000." },
117 	{ ERROR_ILLEGAL_OPERAND_COMBINATION,			true,	"Illegal combination of operands '%s'" },
118 	{ ERROR_RECURSION_TOO_DEEP,                     true, "Recursion too deep in %s" },
119 	{ ERROR_AVOID_SEGFAULT,				true, "Internal error in %s" },
120 	{ ERROR_MISSING_ENDM,				true, "Unbalanced macro %s" },
121 	{ ERROR_MISSING_COMMENT_END,			true, "Multi-line comment not closed." },
122 	{ ERROR_SPURIOUS_COMMENT_CLOSE,			true, "Multi-line comment closed without open." },
123     {-1, true, "Doh! Internal end-of-table marker, report the bug!"}
124 };
125 
126 #define MAX_ERROR (( sizeof( sErrorDef ) / sizeof( ERROR_DEFINITION )))
127 
128 bool *bStopAtEnd;
129 bool bRemoveOutBin  = false;
130 
131 int nMaxPasses = 10;
132 
133 char     *Extstr;
134 /*unsigned char     Listing = 1;*/
135 
136 int     pass;
137 
138 unsigned char     F_ListAllPasses = 0;
139 
CountUnresolvedSymbols(void)140 static int CountUnresolvedSymbols(void)
141 {
142     SYMBOL *sym;
143     int nUnresolved = 0;
144     int i;
145 
146     /* Pre-count unresolved symbols */
147     for (i = 0; i < SHASHSIZE; ++i)
148         for (sym = SHash[i]; sym; sym = sym->next)
149             if ( sym->flags & SYM_UNKNOWN )
150                 nUnresolved++;
151 
152     return nUnresolved;
153 }
154 
155 
ShowUnresolvedSymbols(void)156 static int ShowUnresolvedSymbols(void)
157 {
158     SYMBOL *sym;
159     int i;
160 
161     int nUnresolved = CountUnresolvedSymbols();
162     if ( nUnresolved )
163     {
164         printf( "--- Unresolved Symbol List\n" );
165 
166         /* Display unresolved symbols */
167         for (i = 0; i < SHASHSIZE; ++i)
168             for (sym = SHash[i]; sym; sym = sym->next)
169                 if ( sym->flags & SYM_UNKNOWN )
170                     printf( "%-24s %s\n", sym->name, sftos( sym->value, sym->flags ) );
171 
172         printf( "--- %d Unresolved Symbol%c\n\n", nUnresolved, ( nUnresolved == 1 ) ? ' ' : 's' );
173     }
174 
175     return nUnresolved;
176 }
177 
178 
CompareAlpha(const void * arg1,const void * arg2)179 static int CompareAlpha( const void *arg1, const void *arg2 )
180 {
181     /* Simple alphabetic ordering comparison function for quicksort */
182 
183     const SYMBOL *sym1 = *(SYMBOL * const *) arg1;
184     const SYMBOL *sym2 = *(SYMBOL * const *) arg2;
185 
186     /*
187        The cast above is wild, thank goodness the Linux man page
188        for qsort(3) has an example explaining it... :-) [phf]
189 
190        TODO: Note that we compare labels case-insensitive here which
191        is not quite right; I believe we should be case-sensitive as
192        in other contexts where symbols (labels) are compared. But
193        the old CompareAlpha() was case-insensitive as well, so I
194        didn't want to change that right now... [phf]
195     */
196 
197     return strcasecmp(sym1->name, sym2->name);
198 }
199 
CompareAddress(const void * arg1,const void * arg2)200 static int CompareAddress( const void *arg1, const void *arg2 )
201 {
202     /* Simple numeric ordering comparison function for quicksort */
203 
204     const SYMBOL *sym1 = *(SYMBOL * const *) arg1;
205     const SYMBOL *sym2 = *(SYMBOL * const *) arg2;
206 
207     return sym1->value - sym2->value;
208 }
209 
210 /* bTableSort true -> by address, false -> by name [phf] */
ShowSymbols(FILE * file,bool bTableSort)211 static void ShowSymbols( FILE *file, bool bTableSort )
212 {
213     /* Display sorted (!) symbol table - if it runs out of memory, table will be displayed unsorted */
214 
215     SYMBOL **symArray;
216     SYMBOL *sym;
217     int i;
218     int nSymbols = 0;
219 
220     fprintf( file, "--- Symbol List");
221 
222     /* Sort the symbol list either via name, or by value */
223 
224     /* First count the number of symbols */
225     for (i = 0; i < SHASHSIZE; ++i)
226         for (sym = SHash[i]; sym; sym = sym->next)
227             nSymbols++;
228 
229     /* Malloc an array of pointers to data */
230 
231     symArray = (SYMBOL **)ckmalloc( sizeof( SYMBOL * ) * nSymbols );
232     if ( !symArray )
233     {
234         fprintf( file, " (unsorted - not enough memory to sort!)\n" );
235 
236         /* Display complete symbol table */
237         for (i = 0; i < SHASHSIZE; ++i)
238             for (sym = SHash[i]; sym; sym = sym->next)
239                 fprintf( file, "%-24s %s\n", sym->name, sftos( sym->value, sym->flags ) );
240     }
241     else
242     {
243          /* Copy the element pointers into the symbol array */
244 
245          int nPtr = 0;
246 
247          for (i = 0; i < SHASHSIZE; ++i)
248              for (sym = SHash[i]; sym; sym = sym->next)
249                  symArray[ nPtr++ ] = sym;
250 
251          if ( bTableSort )
252          {
253              fprintf( file, " (sorted by address)\n" );
254              qsort( symArray, nPtr, sizeof( SYMBOL * ), CompareAddress );           /* Sort via address */
255          }
256          else
257          {
258              fprintf( file, " (sorted by symbol)\n" );
259              qsort( symArray, nPtr, sizeof( SYMBOL * ), CompareAlpha );              /* Sort via name */
260          }
261 
262 
263          /* now display sorted list */
264 
265          for ( i = 0; i < nPtr; i++ )
266          {
267              fprintf( file, "%-24s %-12s", symArray[ i ]->name,
268                  sftos( symArray[ i ]->value, symArray[ i ]->flags ) );
269              if ( symArray[ i ]->flags & SYM_STRING )
270                  fprintf( file, " \"%s\"", symArray[ i ]->string );                  /* If a string, display actual string */
271              fprintf( file, "\n" );
272          }
273 
274          free( symArray );
275     }
276 
277     fputs( "--- End of Symbol List.\n", file );
278 
279 }
280 
281 
282 
ShowSegments(void)283 static void ShowSegments(void)
284 {
285     SEGMENT *seg;
286     const char *bss;
287     const char *sFormat = "%-24s %-3s %-8s %-8s %-8s %-8s\n\0";
288 
289 
290 
291     printf("\n----------------------------------------------------------------------\n");
292     printf( sFormat, "SEGMENT NAME", "", "INIT PC", "INIT RPC", "FINAL PC", "FINAL RPC" );
293 
294     for (seg = Seglist; seg; seg = seg->next)
295     {
296         bss = (seg->flags & SF_BSS) ? "[u]" : "   ";
297 
298         printf( sFormat, seg->name, bss,
299             sftos(seg->initorg, seg->initflags), sftos(seg->initrorg, seg->initrflags),
300             sftos(seg->org, seg->flags), sftos(seg->rorg, seg->rflags) );
301     }
302     puts("----------------------------------------------------------------------");
303 
304     printf( "%d references to unknown symbols.\n", Redo_eval );
305     printf( "%d events requiring another assembler pass.\n", Redo );
306 
307     if ( Redo_why )
308     {
309         if ( Redo_why & REASON_MNEMONIC_NOT_RESOLVED )
310             printf( " - Expression in mnemonic not resolved.\n" );
311 
312         if ( Redo_why & REASON_OBSCURE )
313             printf( " - Obscure reason - to be documented :)\n" );
314 
315         if ( Redo_why & REASON_DC_NOT_RESOVED )
316             printf( " - Expression in a DC not resolved.\n" );
317 
318         if ( Redo_why & REASON_DV_NOT_RESOLVED_PROBABLY )
319             printf( " - Expression in a DV not resolved (probably in DV's EQM symbol).\n" );
320 
321         if ( Redo_why & REASON_DV_NOT_RESOLVED_COULD )
322             printf( " - Expression in a DV not resolved (could be in DV's EQM symbol).\n" );
323 
324         if ( Redo_why & REASON_DS_NOT_RESOLVED )
325             printf( " - Expression in a DS not resolved.\n" );
326 
327         if ( Redo_why & REASON_ALIGN_NOT_RESOLVED )
328             printf( " - Expression in an ALIGN not resolved.\n" );
329 
330         if ( Redo_why & REASON_ALIGN_RELOCATABLE_ORIGIN_NOT_KNOWN )
331             printf( " - ALIGN: Relocatable origin not known (if in RORG at the time).\n" );
332 
333         if ( Redo_why & REASON_ALIGN_NORMAL_ORIGIN_NOT_KNOWN )
334             printf( " - ALIGN: Normal origin not known	(if in ORG at the time).\n" );
335 
336         if ( Redo_why & REASON_EQU_NOT_RESOLVED )
337             printf( " - EQU: Expression not resolved.\n" );
338 
339         if ( Redo_why & REASON_EQU_VALUE_MISMATCH )
340             printf( " - EQU: Value mismatch from previous pass (phase error).\n" );
341 
342         if ( Redo_why & REASON_IF_NOT_RESOLVED )
343             printf( " - IF: Expression not resolved.\n" );
344 
345         if ( Redo_why & REASON_REPEAT_NOT_RESOLVED )
346             printf( " - REPEAT: Expression not resolved.\n" );
347 
348         if ( Redo_why & REASON_FORWARD_REFERENCE )
349             printf( " - Label defined after it has been referenced (forward reference).\n" );
350 
351         if ( Redo_why & REASON_PHASE_ERROR )
352             printf( " - Label value is different from that of the previous pass (phase error).\n" );
353 
354         if ( Redo_why & REASON_BRANCH_OUT_OF_RANGE )
355             printf( " - Branch was out of range.\n" );
356     }
357 
358     printf( "\n" );
359 
360 }
361 
362 
363 
DumpSymbolTable(bool bTableSort)364 static void DumpSymbolTable( bool bTableSort )
365 {
366     if (F_symfile)
367     {
368         FILE *fi = fopen(F_symfile, "w");
369         if (fi)
370         {
371             ShowSymbols( fi, bTableSort );
372             fclose(fi);
373         }
374         else
375         {
376             printf("Warning: Unable to open Symbol Dump file '%s'\n", F_symfile);
377         }
378     }
379 
380 }
381 
382 
MainShadow(int ac,char ** av,bool * pbTableSort)383 static int MainShadow(int ac, char **av, bool *pbTableSort )
384 {
385 
386 
387 
388     int nError = ERROR_NONE;
389     bool bDoAllPasses = false;
390 
391     char buf[MAXLINE];
392     int i;
393     int argVal;
394     MNEMONIC *mne;
395 
396     int oldredo = -1;
397     unsigned long oldwhy = 0;
398     int oldeval = 0;
399 
400     addhashtable(Ops);
401     pass = 1;
402 
403     if (ac < 2)
404     {
405 
406 fail:
407     puts(dasm_id);
408     puts("Copyright (c) 1988-2020 by the DASM team.");
409     puts("License GPLv2+: GNU GPL version 2 or later (see file LICENSE).");
410     puts("DASM is free software: you are free to change and redistribute it.");
411     puts("There is ABSOLUTELY NO WARRANTY, to the extent permitted by law.");
412     puts("");
413     puts("Usage: dasm sourcefile [options]");
414     puts("");
415     puts("-f#      output format 1-3 (default 1)");
416     puts("-oname   output file name (else a.out)");
417     puts("-lname   list file name (else none generated)");
418     puts("-Lname   list file, containing all passes");
419     puts("-sname   symbol dump file name (else none generated)");
420     puts("-v#      verboseness 0-4 (default 0)");
421     puts("-d       debug mode (for developers)");
422     puts("-Dsymbol              define symbol, set to 0");
423     puts("-Dsymbol=expression   define symbol, set to expression");
424     puts("-Msymbol=expression   define symbol using EQM (same as -D)");
425     puts("-Idir    search directory for INCLUDE and INCBIN");
426     puts("-p#      maximum number of passes");
427     puts("-P#      maximum number of passes, with fewer checks");
428     puts("-T#      symbol table sorting (default 0 = alphabetical, 1 = address/value)");
429     puts("-E#      error format (default 0 = MS, 1 = Dillon, 2 = GNU)");
430     puts("-S       strict syntax checking");
431     puts("-R       remove binary output-file in case of errors");
432     puts("-m#      safety barrier to abort on recursions, max. allowed file-size in kB");
433     puts("");
434     puts("Report bugs on https://github.com/dasm-assembler/dasm please!");
435 
436     return ERROR_COMMAND_LINE;
437     }
438 
439     for (i = 2; i < ac; ++i)
440     {
441         if ( ( av[i][0] == '-' ) || ( av[i][0] == '/' ) )
442         {
443             char *str = av[i]+2;
444             switch(av[i][1])
445             {
446             /* TODO: need to improve option parsing and errors for it */
447             case 'E':
448                 F_errorformat = atoi(str);
449                 if (F_errorformat < ERRORFORMAT_DEFAULT
450                    || F_errorformat >= ERRORFORMAT_MAX )
451                 {
452                     panic("Invalid error format for -E, must be 0, 1, 2");
453                 }
454                 break;
455 
456             case 'T':
457                 F_sortmode = atoi(str);
458                 if (F_sortmode < SORTMODE_DEFAULT
459                    || F_sortmode >= SORTMODE_MAX )
460                 {
461                     panic("Invalid sorting mode for -T option, must be 0 or 1");
462                 }
463                 /* TODO: refactor into regular configuration [phf] */
464                 *pbTableSort = (F_sortmode != SORTMODE_DEFAULT);
465                 break;
466 
467             case 'd':
468                 Xdebug = atoi(str) != 0;
469                 printf( "Debug trace %s\n", Xdebug ? "ON" : "OFF" );
470                 break;
471 
472             case 'M':
473             case 'D':
474                 while (*str && *str != '=')
475                     ++str;
476                 if (*str == '=')
477                 {
478                     *str = 0;
479                     ++str;
480                 }
481                 else
482                 {
483                     str = "0";
484                 }
485                 Av[0] = av[i]+2;
486 
487                 if (av[i][1] == 'M')
488                     v_eqm(str, NULL);
489                 else
490                     v_set(str, NULL);
491                 break;
492 
493             case 'f':   /*  F_format    */
494                 F_format = atoi(str);
495                 if (F_format < FORMAT_DEFAULT || F_format >= FORMAT_MAX )
496                     panic("Illegal format specification");
497                 break;
498 
499             case 'o':   /*  F_outfile   */
500                 F_outfile = str;
501 nofile:
502                 if (*str == 0)
503                     panic("-o Switch requires file name.");
504                 break;
505 
506             case 'L':
507                 F_ListAllPasses = 1;
508                 /* fall through to 'l' */
509 
510             case 'l':   /*  F_listfile  */
511                 F_listfile = str;
512                 goto nofile;
513 
514             case 'P':   /*  F_Passes   */
515                 bDoAllPasses = true;
516 
517                 /* fall through to 'p' */
518             case 'p':   /*  F_passes   */
519                 nMaxPasses = atoi(str);
520                 break;
521 
522             case 's':   /*  F_symfile   */
523                 F_symfile = str;
524                 goto nofile;
525             case 'v':   /*  F_verbose   */
526                 F_verbose = atoi(str);
527                 break;
528 
529             case 'I':
530                 v_incdir(str, NULL);
531                 break;
532 
533             case 'S':
534                 bStrictMode = true;
535                 break;
536 
537             case 'R':
538             	bRemoveOutBin = true;
539                 break;
540 
541             case 'm':   /*  F_passes   */
542             	argVal = atol(str);
543             	if (argVal <= 64) {
544             		panic("-m Switch invalid argument, should be > 64");
545             	} else {
546             		maxFileSize = argVal;
547             	}
548                 break;
549 
550             default:
551                 goto fail;
552             }
553             continue;
554         }
555         goto fail;
556     }
557 
558     bStopAtEnd = malloc((nMaxPasses+1) * sizeof(bool));
559     memset(bStopAtEnd, 0, nMaxPasses+1);	// we dont count from zero ! (for fewer code changes)
560 
561     /*    INITIAL SEGMENT */
562 
563     {
564         SEGMENT *seg = (SEGMENT *)permalloc(sizeof(SEGMENT));
565         seg->name = strcpy(permalloc(sizeof(ISEGNAME)), ISEGNAME);
566         seg->flags= seg->rflags = seg->initflags = seg->initrflags = SF_UNKNOWN;
567         Csegment = Seglist = seg;
568     }
569     /*    TOP LEVEL IF    */
570     {
571         IFSTACK *ifs = (IFSTACK *)zmalloc(sizeof(IFSTACK));
572         ifs->file = NULL;
573         ifs->flags = IFF_BASE;
574         ifs->acctrue = 1;
575         ifs->xtrue  = 1;
576         Ifstack = ifs;
577     }
578 
579     // ready error and message buffer...
580     passbuffer_clear(ERRORBUF);
581     passbuffer_clear(MSGBUF);
582 
583 
584 nextpass:
585 
586 
587     if ( F_verbose )
588     {
589         puts("");
590         printf("START OF PASS: %d\n", pass);
591     }
592 
593     Localindex = Lastlocalindex = 0;
594 
595     Localdollarindex = Lastlocaldollarindex = 0;
596 
597     /*_fmode = 0x8000;*/
598     FI_temp = fopen(F_outfile, "wb");
599     /*_fmode = 0;*/
600     Fisclear = 1;
601     CheckSum = 0;
602     if (FI_temp == NULL) {
603         printf("Warning: Unable to [re]open '%s'\n", F_outfile);
604         return ERROR_FILE_ERROR;
605     }
606     if (F_listfile) {
607 
608         FI_listfile = fopen(F_listfile,
609             F_ListAllPasses && (pass > 1)? "ab" : "wb");
610 
611         if (FI_listfile == NULL) {
612             printf("Warning: Unable to [re]open '%s'\n", F_listfile);
613             return ERROR_FILE_ERROR;
614         }
615     }
616     pushinclude(av[1]);
617 
618     while ( pIncfile )
619     {
620         for (;;) {
621             const char *comment;
622             if ( pIncfile->flags & INF_MACRO) {
623                 if ( pIncfile->strlist == NULL) {
624                     Av[0] = "";
625                     v_mexit(NULL, NULL);
626                     continue;
627                 }
628                 strcpy(buf, pIncfile->strlist->buf);
629                 pIncfile->strlist = pIncfile->strlist->next;
630             }
631             else
632             {
633                 if (fgets(buf, MAXLINE, pIncfile->fi) == NULL)
634                     break;
635             }
636 
637             if (Xdebug)
638                 printf("%08lx %s\n", (unsigned long) pIncfile, buf);
639 
640             comment = cleanup(buf, false);
641             ++pIncfile->lineno;
642             mne = parse(buf);
643 
644             if (Av[1][0])
645             {
646                 if (mne)
647                 {
648                     if ((mne->flags & MF_IF) || (Ifstack->xtrue && Ifstack->acctrue))
649                         (*mne->vect)(Av[2], mne);
650                 }
651                 else
652                 {
653                     if (Ifstack->xtrue && Ifstack->acctrue)
654                         asmerr( ERROR_UNKNOWN_MNEMONIC, false, Av[1] );
655                 }
656 
657             }
658             else
659             {
660                 if (Ifstack->xtrue && Ifstack->acctrue)
661                     programlabel();
662             }
663 
664             if (F_listfile && ListMode)
665                 outlistfile(comment);
666         }
667 
668         while (Reploop && Reploop->file == pIncfile)
669             rmnode((void **)&Reploop, sizeof(REPLOOP));
670 
671         while (Ifstack->file == pIncfile)
672             rmnode((void **)&Ifstack, sizeof(IFSTACK));
673 
674         fclose( pIncfile->fi );
675         free( pIncfile->name );
676         --Inclevel;
677         rmnode((void **)&pIncfile, sizeof(INCFILE));
678 
679         if ( pIncfile )
680         {
681         	if (F_verbose > 3)
682         		printf("back to: %s\n", pIncfile->name);
683 
684             if (F_listfile)
685                 fprintf(FI_listfile, "------- FILE %s\n", pIncfile->name);
686         }
687     }
688 
689 
690 
691     if ( F_verbose >= 1 )
692         ShowSegments();
693 
694     if ( F_verbose >= 3 )
695     {
696         if ( !Redo || ( F_verbose == 4 ) )
697             ShowSymbols( stdout, *pbTableSort );
698 
699         ShowUnresolvedSymbols();
700     }
701 
702     closegenerate();
703     fclose(FI_temp);
704     if (FI_listfile)
705         fclose(FI_listfile);
706 
707     if (mlflag) // check if a multi-line comment is missing a terminator
708         return ERROR_MISSING_COMMENT_END;
709 
710     if (Redo)
711     {
712         if ( !bDoAllPasses )
713             if (Redo == oldredo && Redo_why == oldwhy && Redo_eval == oldeval)
714             {
715                 ShowUnresolvedSymbols();
716                 return ERROR_NOT_RESOLVABLE;
717             }
718 
719         oldredo = Redo;
720         oldwhy = Redo_why;
721         oldeval = Redo_eval;
722         Redo = 0;
723         Redo_why = 0;
724         Redo_eval = 0;
725 
726         Redo_if <<= 1;
727         ++pass;
728 
729 
730         if ( pass > nMaxPasses )
731         {
732             char sBuffer[64];
733             sprintf( sBuffer, "%d", pass );
734             return asmerr( ERROR_TOO_MANY_PASSES, false, sBuffer );
735 
736         }
737         else
738         {
739             passbuffer_clear(ERRORBUF);
740             passbuffer_clear(MSGBUF);
741 
742             clearrefs();
743             clearsegs();
744             goto nextpass;
745         }
746     }
747     // Do not print any errors if assembly is successful!!!!! -FXQ
748     // only print messages from last pass and if there's no errors
749     if (!bStopAtEnd[pass])
750     {
751         passbuffer_output(MSGBUF);
752     }
753     else
754     {
755         // Only print errors if assembly is unsuccessful!!!!!
756         // by FXQ
757 	passbuffer_output(ERRORBUF);
758         printf("Unrecoverable error(s) in pass, aborting assembly!\n");
759 	nError = ERROR_NON_ABORT;
760     }
761 
762     if (nMacroClosings != nMacroDeclarations) {
763         /* determine the file pointer to use */
764         FILE *error_file = (F_listfile != NULL) ? FI_listfile : stdout;
765 
766     	fprintf(error_file, "premature end of file, macros opened:%d  closed:%d", nMacroDeclarations, nMacroClosings);
767         fprintf(error_file, "Aborting assembly\n");
768 
769         exit(ERROR_MISSING_ENDM);
770     }
771     printf( "Complete. (%d)\n", nError);
772     return nError;
773 }
774 
addmsg(char * message)775 void addmsg(char *message) // add to message buffer (FXQ)
776 {
777   passbuffer_update(MSGBUF,message);
778 }
779 
780 
tabit(char * buf1,char * buf2)781 static int tabit(char *buf1, char *buf2)
782 {
783     char *bp, *ptr;
784     int j, k;
785 
786     bp = buf2;
787     ptr= buf1;
788     for (j = 0; *ptr && *ptr != '\n'; ++ptr, ++bp, j = (j+1)&7) {
789         *bp = *ptr;
790         if (*ptr == '\t') {
791             /* optimize out spaces before the tab */
792             while (j > 0 && bp[-1] == ' ') {
793                 bp--;
794                 j--;
795             }
796             j = 0;
797             *bp = '\t';         /* recopy the tab */
798         }
799         if (j == 7 && *bp == ' ' && bp[-1] == ' ') {
800             k = j;
801             while (k-- >= 0 && *bp == ' ')
802                 --bp;
803             *++bp = '\t';
804         }
805     }
806     while (bp != buf2 && (bp[-1] == ' ' || bp[-1] == '\t'))
807         --bp;
808     *bp++ = '\n';
809     *bp = '\0';
810     return (int)(bp - buf2);
811 }
812 
outlistfile(const char * comment)813 static void outlistfile(const char *comment)
814 {
815     char xtrue;
816     char c;
817     static char buf1[MAXLINE+32];
818     static char buf2[MAXLINE+32];
819     const char *ptr;
820     const char *dot;
821     int i, j;
822 
823 
824     if ( pIncfile->flags & INF_NOLIST )
825         return;
826 
827     xtrue = (Ifstack->xtrue && Ifstack->acctrue) ? ' ' : '-';
828     c = (Pflags & SF_BSS) ? 'U' : ' ';
829     ptr = Extstr;
830     dot = "";
831     if (ptr)
832         dot = ".";
833     else
834         ptr = "";
835 
836     sprintf(buf1, "%7ld %c%s", pIncfile->lineno, c, sftos(Plab, Pflags & 7));
837     j = strlen(buf1);
838     for (i = 0; i < Glen && i < 4; ++i, j += 3)
839         sprintf(buf1+j, "%02x ", Gen[i]);
840     if (i < Glen && i == 4)
841         xtrue = '*';
842     for (; i < 4; ++i) {
843         buf1[j] = buf1[j+1] = buf1[j+2] = ' ';
844         j += 3;
845     }
846     sprintf(buf1+j-1, "%c%-10s %s%s%s\t%s\n",
847         xtrue, Av[0], Av[1], dot, ptr, Av[2]);
848     if (comment[0]) { /*  tab and comment */
849         j = strlen(buf1) - 1;
850         sprintf(buf1+j, "\t;%s", comment);
851     }
852     fwrite(buf2, tabit(buf1,buf2), 1, FI_listfile);
853     Glen = 0;
854     Extstr = NULL;
855 }
856 
sftos(long val,int flags)857 char *sftos(long val, int flags)
858 {
859     static char buf[ MAX_SYM_LEN + 14 ];
860     static char c;
861     char *ptr = (c) ? buf : buf + sizeof(buf) / 2;
862 
863     memset( buf, 0, sizeof( buf ) );
864 
865     c = 1 - c;
866 
867     sprintf(ptr, "%04lx ", val);
868 
869     if (flags & SYM_UNKNOWN)
870         strcat( ptr, "???? ");
871     else
872         strcat( ptr, "     " );
873 
874     if (flags & SYM_STRING)
875         strcat( ptr, "str ");
876     else
877         strcat( ptr, "    " );
878 
879     if (flags & SYM_MACRO)
880         strcat( ptr, "eqm ");
881     else
882         strcat( ptr, "    " );
883 
884 
885     if (flags & (SYM_MASREF|SYM_SET))
886     {
887         strcat( ptr, "(" );
888     }
889     else
890         strcat( ptr, " " );
891 
892     if (flags & (SYM_MASREF))
893         strcat( ptr, "R" );
894     else
895         strcat( ptr, " " );
896 
897 
898     if (flags & (SYM_SET))
899         strcat( ptr, "S" );
900     else
901         strcat( ptr, " " );
902 
903     if (flags & (SYM_MASREF|SYM_SET))
904     {
905         strcat( ptr, ")" );
906     }
907     else
908         strcat( ptr, " " );
909 
910 
911     return ptr;
912 }
913 
clearsegs(void)914 void clearsegs(void)
915 {
916     SEGMENT *seg;
917 
918     for (seg = Seglist; seg; seg = seg->next) {
919         seg->flags = (seg->flags & SF_BSS) | SF_UNKNOWN;
920         seg->rflags= seg->initflags = seg->initrflags = SF_UNKNOWN;
921     }
922 }
923 
924 
clearrefs(void)925 void clearrefs(void)
926 {
927     SYMBOL *sym;
928     short i;
929 
930     for (i = 0; i < SHASHSIZE; ++i)
931         for (sym = SHash[i]; sym; sym = sym->next)
932             sym->flags &= ~SYM_REF;
933 }
934 
935 
936 
937 
cleanup(char * buf,bool bDisable)938 static const char *cleanup(char *buf, bool bDisable)
939 {
940     char *str;
941     STRLIST *strlist;
942     int arg, add;
943     const char *comment = "";
944 
945     char *mlstart, *mlend, *semistart;
946     mlstart=strstr(buf,"/*");
947     mlend=strstr(buf,"*/");
948     semistart=strstr(buf,";");
949 
950     if (mlflag) // a previous multi-line comment is in progress...
951     {
952         if ( mlend )
953         {
954             mlflag=0; // turn off multiline comments
955 	    char tempbuf[MAXLINE];
956             char *tmpc;
957             *mlend = 0;
958             tmpc = mlend+1;
959             while(*tmpc!=0) // we need to purge any newlines before we reorder the parts of the line
960             {
961                 if((*tmpc == '\r')||(*tmpc == '\n'))
962                     *tmpc=0;
963                 tmpc++;
964             }
965 	    snprintf(tempbuf,MAXLINE,"%s;*/%s",mlend+2,buf); // put the comment at the end of the line
966             strncpy(buf,tempbuf,MAXLINE);
967             return(cleanup(buf,bDisable)); // repeat for any single-line comments that may follow
968         }
969         else
970         {
971             memmove(buf+1,buf,strlen(buf)+1); // make room for the last comment
972             buf[0]=';';
973         }
974     }
975     else // we're not presently in the middle of a multi-line comment...
976     {
977         // check for spurious comment close
978         if (mlend && ( (!semistart) || (mlend < semistart) ) && ( (!mlstart) ||  (mlend < mlstart) ) )
979             asmerr( ERROR_SPURIOUS_COMMENT_CLOSE, false, NULL );
980         if (mlstart && ((!semistart) || (mlstart < semistart)))
981         {
982             if (mlend && (mlstart < mlend) && ((!semistart)||(mlend < semistart))) // single line /* */
983             {
984 	        char tempbuf[MAXLINE];
985                 char *tmpc;
986                 *mlstart = 0;
987                 *(mlend+1)=0;
988                 tmpc = mlend+2;
989                 while(*tmpc!=0) // we need to purge any newlines before we reorder the parts of the line
990                 {
991                     if((*tmpc == '\r')||(*tmpc == '\n'))
992                         *tmpc=0;
993                     tmpc++;
994                 }
995 	        snprintf(tempbuf,MAXLINE,"%s%s;/%s",buf,mlend+2,mlstart+1); // move the first comment to the end of the line
996                 strcpy(buf,tempbuf);
997                 return(cleanup(buf,bDisable)); // repeat for any single-line comments that may follow
998             }
999             mlflag=1; // turn on multiline comments
1000             memmove(mlstart+1,mlstart,strlen(mlstart)+1); // make room for a comment
1001             *mlstart=';';
1002         }
1003     }
1004 
1005     for (str = buf; *str; ++str)
1006     {
1007         switch(*str)
1008         {
1009         case ';':
1010             comment = (char *)str + 1;
1011             /*    FALL THROUGH    */
1012         case '\r':
1013         case '\n':
1014             goto br2;
1015         case TAB:
1016             *str = ' ';
1017             break;
1018         case '\'':
1019             ++str;
1020             if (*str == TAB)
1021                 *str = ' ';
1022             if (*str == '\n' || *str == 0)
1023             {
1024                 str[0] = ' ';
1025                 str[1] = 0;
1026             }
1027             if (str[0] == ' ')
1028                 str[0] = '\x80';
1029             break;
1030         case '\"':
1031             ++str;
1032             while (*str && *str != '\"')
1033             {
1034                 if (*str == ' ')
1035                     *str = '\x80';
1036                 ++str;
1037             }
1038             if (*str != '\"')
1039             {
1040                 asmerr( ERROR_SYNTAX_ERROR, false, buf );
1041                 --str;
1042             }
1043             break;
1044         case '{':
1045             if ( bDisable )
1046                 break;
1047 
1048             if (Xdebug)
1049                 printf("macro tail: '%s'\n", str);
1050 
1051             arg = atoi(str+1);
1052             for (add = 0; *str && *str != '}'; ++str)
1053                 --add;
1054             if (*str != '}')
1055             {
1056                 puts("end brace required");
1057                 --str;
1058                 break;
1059             }
1060             --add;
1061             ++str;
1062 
1063 
1064             if (Xdebug)
1065                 printf("add/str: %d '%s'\n", add, str);
1066 
1067             for (strlist = pIncfile->args; arg && strlist;)
1068             {
1069                 --arg;
1070                 strlist = strlist->next;
1071             }
1072 
1073             if (strlist)
1074             {
1075                 add += strlen(strlist->buf);
1076 
1077                 if (Xdebug)
1078                     printf("strlist: '%s' %zu\n", strlist->buf, strlen(strlist->buf));
1079 
1080                 if (str + add + strlen(str) + 1 > buf + MAXLINE)
1081                 {
1082                     if (Xdebug)
1083                         printf("str %8ld buf %8ld (add/strlen(str)): %d %ld\n",
1084                         (unsigned long)str, (unsigned long)buf, add, (long)strlen(str));
1085                     panic("failure1");
1086                 }
1087 
1088                 memmove(str + add, str, strlen(str)+1);
1089                 str += add;
1090                 if (str - strlen(strlist->buf) < buf)
1091                     panic("failure2");
1092                 memmove(str - strlen(strlist->buf), strlist->buf, strlen(strlist->buf));
1093                 str -= strlen(strlist->buf);
1094                 if (str < buf || str >= buf + MAXLINE)
1095                     panic("failure 3");
1096                 --str;      /*  for loop increments string    */
1097             }
1098             else
1099             {
1100                 asmerr( ERROR_NOT_ENOUGH_ARGUMENTS_PASSED_TO_MACRO, false, NULL );
1101                 goto br2;
1102             }
1103             break;
1104         }
1105     }
1106 
1107 br2:
1108     while(str != buf && *(str-1) == ' ')
1109         --str;
1110     *str = 0;
1111 
1112     return comment;
1113 }
1114 
panic(const char * str)1115 void panic(const char *str)
1116 {
1117     puts(str);
1118     exit(1);
1119 }
1120 
1121 /*
1122 *  .dir    direct              x
1123 *  .ext    extended              x
1124 *  .r          relative              x
1125 *  .x          index, no offset          x
1126 *  .x8     index, byte offset          x
1127 *  .x16    index, word offset          x
1128 *  .bit    bit set/clr
1129 *  .bbr    bit and branch
1130 *  .imp    implied (inherent)          x
1131 *  .b                      x
1132 *  .w                      x
1133 *  .l                      x
1134 *  .u                      x
1135 *  .s       swapped short, force other endian with DC
1136 */
1137 
1138 
findext(char * str)1139 void findext(char *str)
1140 {
1141     Mnext = -1;
1142     Extstr = NULL;
1143 
1144     if (str[0] == '.') {    /* Allow .OP for OP */
1145         return;
1146     }
1147 
1148     while (*str && *str != '.')
1149         ++str;
1150     if (*str) {
1151         *str = 0;
1152         ++str;
1153         Extstr = str;
1154         switch(str[0]|0x20) {
1155 	     case 's':
1156                 Mnext = AM_OTHER_ENDIAN;
1157                 return;
1158 
1159         case '0':
1160         case 'i':
1161             Mnext = AM_IMP;
1162             switch(str[1]|0x20) {
1163             case 'x':
1164                 Mnext = AM_0X;
1165                 break;
1166             case 'y':
1167                 Mnext = AM_0Y;
1168                 break;
1169             case 'n':
1170                 Mnext = AM_INDWORD;
1171                 break;
1172             }
1173             return;
1174             case 'd':
1175             case 'b':
1176             case 'z':
1177                 switch(str[1]|0x20) {
1178                 case 'x':
1179                     Mnext = AM_BYTEADRX;
1180                     break;
1181                 case 'y':
1182                     Mnext = AM_BYTEADRY;
1183                     break;
1184                 case 'i':
1185                     Mnext = AM_BITMOD;
1186                     break;
1187                 case 'b':
1188                     Mnext = AM_BITBRAMOD;
1189                     break;
1190                 default:
1191                     Mnext = AM_BYTEADR;
1192                     break;
1193                 }
1194                 return;
1195                 case 'e':
1196                 case 'w':
1197                 case 'a':
1198                     switch(str[1]|0x20) {
1199                     case 'x':
1200                         Mnext = AM_WORDADRX;
1201                         break;
1202                     case 'y':
1203                         Mnext = AM_WORDADRY;
1204                         break;
1205                     default:
1206                         Mnext = AM_WORDADR;
1207                         break;
1208                     }
1209                     return;
1210                     case 'l':
1211                         Mnext = AM_LONG;
1212                         return;
1213                     case 'r':
1214                         Mnext = AM_REL;
1215                         return;
1216                     case 'u':
1217                         Mnext = AM_BSS;
1218                         return;
1219         }
1220     }
1221 }
1222 
1223 /*
1224 *  bytes arg will eventually be used to implement a linked list of free
1225 *  nodes.
1226 *  Assumes *base is really a pointer to a structure with .next as the first
1227 *  member.
1228 */
1229 
rmnode(void ** base,int bytes)1230 void rmnode(void **base, int bytes)
1231 {
1232     void *node;
1233 
1234     if ((node = *base) != NULL) {
1235         *base = *(void **)node;
1236         free(node);
1237     }
1238 }
1239 
1240 /*
1241 *  Parse into three arguments: Av[0], Av[1], Av[2]
1242 */
parse(char * buf)1243 MNEMONIC *parse(char *buf)
1244 {
1245     int i, j;
1246     MNEMONIC *mne = NULL;
1247     int labelundefined = 0;
1248 
1249     i = 0;
1250     j = 1;
1251 
1252     /*
1253         If the first non-space is a ^, skip all further spaces too.
1254         This means what follows is a label.
1255         If the first non-space is a #, what follows is a directive/opcode.
1256     */
1257     while (buf[i] == ' ')
1258         ++i;
1259     if (buf[i] == '^') {
1260         ++i;
1261         while (buf[i] == ' ')
1262             ++i;
1263     } else if (buf[i] == '#') {
1264         buf[i] = ' ';   /* label separator */
1265     } else
1266         i = 0;
1267 
1268     Av[0] = Avbuf + j;
1269     while (buf[i] && buf[i] != ' ' && buf[i] != '=') {
1270 
1271         if (buf[i] == ':') {
1272             i++;
1273             break;
1274         }
1275 
1276         if (buf[i] == ',')  // we have label arguments
1277         {
1278             if(buf[i+1]=='"') // is it a string constant?
1279             {
1280                 i=i+2; // advance to string contents
1281                 while (buf[i] && buf[i] != '"' && buf[i] != ' ' && buf[i] != ',' && buf[i] != ':')
1282                 {
1283                     Avbuf[j++] = buf[i++];
1284                 }
1285                 if (buf[i] && buf[i]=='"')
1286                 {
1287                     i++;
1288                     continue;
1289                 }
1290                 else
1291                 {
1292                     labelundefined++;
1293                     asmerr( ERROR_SYNTAX_ERROR, false, buf );
1294                     continue;
1295                 }
1296             }
1297             else // or else it's a symbol to be evaluated, and added to the label
1298             {
1299                 int t;
1300                 char tempbuf[257];
1301                 char tempval[257];
1302                 SYMBOL *symarg;
1303                 strncpy(tempbuf,buf+i+1,256);
1304                 tempbuf[256]=0;
1305                 for(t=0;t<strlen(tempbuf);t++)
1306                 {
1307                     if(tempbuf[t] == ',')
1308                         tempbuf[t]=0;
1309                 }
1310                 symarg = eval(tempbuf,0);
1311                 if(symarg)
1312                 {
1313                     if (symarg->flags & SYM_UNKNOWN) // one of the arguments isn't defined yet
1314 			labelundefined++; // ensure the label we're creating doesn't get used
1315                     else
1316                     {
1317                         snprintf(tempval,256,"%d",(unsigned)symarg->value);
1318                         strcpy(Avbuf+j,tempval);
1319 			j=j+strlen(tempval);
1320                     }
1321                 }
1322                 i++;
1323                 while (buf[i] && buf[i] != ' ' && buf[i] != '=' && buf[i] != ','&& buf[i] != ':')
1324                     i++;
1325             }
1326             continue;
1327         }
1328 
1329         if ((unsigned char)buf[i] == 0x80)
1330             buf[i] = ' ';
1331         Avbuf[j++] = buf[i++];
1332     }
1333     Avbuf[j++] = 0;
1334 
1335     // if the label has arguments that aren't defined, we need to scuttle it
1336     // to avoid a partial label being used.
1337     if(labelundefined)
1338     {
1339       j=1;
1340       Avbuf[j++] = 0;
1341     }
1342 
1343     /* Parse the second word of the line */
1344     while (buf[i] == ' ')
1345         ++i;
1346     Av[1] = Avbuf + j;
1347     if (buf[i] == '=') {
1348         /* '=' directly seperates Av[0] and Av[2] */
1349         Avbuf[j++] = buf[i++];
1350     } else while (buf[i] && buf[i] != ' ') {
1351         if ((unsigned char)buf[i] == 0x80)
1352             buf[i] = ' ';
1353         Avbuf[j++] = buf[i++];
1354     }
1355     Avbuf[j++] = 0;
1356     /* and analyse it as an opcode */
1357     findext(Av[1]);
1358     mne = findmne(Av[1]);
1359 
1360     /* Parse the rest of the line */
1361     while (buf[i] == ' ')
1362         ++i;
1363     Av[2] = Avbuf + j;
1364     while (buf[i]) {
1365         if (buf[i] == ' ') {
1366             while(buf[i+1] == ' ')
1367                 ++i;
1368         }
1369         if ((unsigned char)buf[i] == 0x80)
1370             buf[i] = ' ';
1371         Avbuf[j++] = buf[i++];
1372     }
1373     Avbuf[j] = 0;
1374 
1375     if (mne != NULL) {
1376     	if (mne->flags & MF_BEGM) {
1377     		nMacroDeclarations++;
1378     	}
1379     	if (mne->flags & MF_ENDM) {
1380         	nMacroClosings++;
1381     	}
1382     }
1383     return mne;
1384 }
1385 
1386 
1387 
findmne(char * str)1388 MNEMONIC *findmne(char *str)
1389 {
1390 	int h,k;
1391     int i;
1392     char c;
1393     MNEMONIC *mne;
1394     char buf[64];
1395 
1396 
1397     if (str[0] == '.') {    /* Allow .OP for OP */
1398         str++;
1399     }
1400 
1401     for (i = 0; (c = str[i]); ++i) {
1402         if (c >= 'A' && c <= 'Z')
1403             c += 'a' - 'A';
1404         buf[i] = c;
1405     }
1406     buf[i] = 0;
1407     h = hash1(buf);
1408     mne = MHash[h];
1409     k = 0;
1410     while (mne != NULL) {
1411         if (strcmp(buf, mne->name) == 0)
1412             break;
1413 
1414         k++;
1415         mne = mne->next;
1416         if (mne != NULL) {
1417         	if ((mne == mne->next) && (k > 5)) { // any number bigger than 1 would do
1418         		// should not happen at all, I'm not paranoid, I've had this problem really
1419         		fprintf(stderr,"[%s] [%s] %08lx %08lx\n", buf, mne->name, (long)mne, (long)mne->next);
1420         		fprintf(stderr,"BUG: %s:%d: chained list looped to itself and no match, would lock up endlessly\n", __FILE__, __LINE__);
1421         		return NULL; // we need to return NULL here or the program will get stuck in an endless loop
1422         					 // the BUG vanished with increased hashtable
1423         	}
1424         }
1425     }
1426     return mne;
1427 }
1428 
v_macro(char * str,MNEMONIC * dummy)1429 void v_macro(char *str, MNEMONIC *dummy)
1430 {
1431     STRLIST *base;
1432     int defined = 0;
1433     STRLIST **slp, *sl;
1434     MACRO *mac;    /* slp, mac: might be used uninitialised */
1435     MNEMONIC   *mne;
1436     unsigned int i;
1437     char buf[MAXLINE];
1438     int skipit = !(Ifstack->xtrue && Ifstack->acctrue);
1439 
1440     strlower(str);
1441     mne = findmne(str);
1442 
1443     if (skipit) {
1444         defined = 1;
1445     } else {
1446         defined = (mne != NULL);
1447         if (F_listfile && ListMode)
1448             outlistfile("");
1449     }
1450     if (!defined) {
1451         base = NULL;
1452         slp = &base;
1453         mac = (MACRO *)permalloc(sizeof(MACRO));
1454         i = hash1(str);
1455         mac->next = (MACRO *)MHash[i];
1456         mac->vect = v_execmac;
1457         mac->name = strcpy(permalloc(strlen(str)+1), str);
1458         mac->flags = MF_MACRO;
1459         mac->defpass = pass;
1460         if (mac == mac->next) {
1461         	// should not happen
1462         	fprintf(stderr,"BUG: %s:%d: permalloc() returned the same value twice, expect severe problems\n", __FILE__, __LINE__);
1463         }
1464         MHash[i] = (MNEMONIC *)mac;
1465     }
1466     else {
1467         mac = (MACRO *)mne;
1468         if( (bStrictMode) && (mac != NULL) && (mac->defpass == pass) )
1469             asmerr( ERROR_MACRO_REPEATED, true, str );
1470     }
1471     while (fgets(buf, MAXLINE, pIncfile->fi)) {
1472         const char *comment;
1473 
1474         if (Xdebug)
1475             printf("%08lx %s\n", (unsigned long) pIncfile, buf);
1476 
1477         ++pIncfile->lineno;
1478 
1479 
1480         comment = cleanup(buf, true);
1481 
1482         mne = parse(buf);
1483         if (Av[1][0]) {
1484             if (mne != NULL) {	// for some reason I got a segfault while accessing mne->flags, should not happen but gdb said it was here
1485             	if (mne->flags & MF_ENDM) {
1486                 if (!defined)
1487                     mac->strlist = base;
1488                 return;
1489             	}
1490             }
1491         }
1492         if (!skipit && F_listfile && ListMode)
1493             outlistfile(comment);
1494         if (!defined) {
1495             sl = (STRLIST *)permalloc(STRLISTSIZE+1+strlen(buf));
1496             strcpy(sl->buf, buf);
1497             *slp = sl;
1498             slp = &sl->next;
1499         }
1500     }
1501     asmerr( ERROR_PREMATURE_EOF, true, NULL );
1502 }
1503 
1504 
addhashtable(MNEMONIC * mne)1505 void addhashtable(MNEMONIC *mne)
1506 {
1507     int i, j;
1508     unsigned int opcode[NUMOC];
1509 
1510     for (; mne->vect; ++mne) {
1511         memcpy(opcode, mne->opcode, sizeof(mne->opcode));
1512         for (i = j = 0; i < NUMOC; ++i) {
1513             mne->opcode[i] = 0;     /* not really needed */
1514             if (mne->okmask & (1L << i))
1515                 mne->opcode[i] = opcode[j++];
1516         }
1517         i = hash1(mne->name);
1518         mne->next = MHash[i];
1519         MHash[i] = mne;
1520     }
1521 }
1522 
1523 
hash1(const char * str)1524 static unsigned int hash1(const char *str)
1525 {
1526     uint8_t a = 0;
1527     uint8_t b = 0;
1528     while (*str) {	// this is Fletcher's checksum, better distribution, faster
1529     	a += *str++;
1530     	b += a;
1531     }
1532     return ((((a << 8) & 0xFF00) | (b & 0xFF))  ) & MHASHAND;
1533 }
1534 
pushinclude(char * str)1535 void pushinclude(char *str)
1536 {
1537     INCFILE *inf;
1538     FILE *fi;
1539 
1540     if ((fi = pfopen(str, "rb")) != NULL) {
1541         if (F_verbose > 1 && F_verbose != 5 )
1542             printf("%.*s Including file \"%s\"\n", Inclevel*4, "", str);
1543         ++Inclevel;
1544 
1545         if (F_listfile)
1546             fprintf(FI_listfile, "------- FILE %s LEVEL %d PASS %d\n", str, Inclevel, pass);
1547 
1548         inf = (INCFILE *)zmalloc(sizeof(INCFILE));
1549         inf->next    = pIncfile;
1550         inf->name    = strcpy(ckmalloc(strlen(str)+1), str);
1551         inf->fi = fi;
1552         inf->lineno = 0;
1553         pIncfile = inf;
1554         return;
1555     }
1556     printf("Warning: Unable to open '%s'\n", str);
1557     return;
1558 }
1559 
1560 
1561 
1562 
asmerr(int err,bool bAbort,const char * sText)1563 int asmerr(int err, bool bAbort, const char *sText )
1564 {
1565     const char *str;
1566     INCFILE *pincfile;
1567     /* file pointer we print error messages to */
1568     FILE *error_file = NULL;
1569 
1570     if ( err >= MAX_ERROR || err < 0 )
1571     {
1572         return asmerr( ERROR_BADERROR, true, "Bad error ERROR!" );
1573     }
1574     else
1575     {
1576 
1577         if (sErrorDef[err].bFatal)
1578             bStopAtEnd[pass] = true;
1579 
1580 	pincfile = pIncfile;
1581 	while(1) {
1582 		if (pincfile == NULL) {
1583 			fprintf(stderr, "%s:%d: error: pincfile is NULL, err:%d, [%s]: %s\n", __FILE__, __LINE__
1584 						, err, sText, sErrorDef[err].sDescription);
1585 			bAbort = true;
1586 			break;
1587 		}
1588 		if (pincfile->flags & INF_MACRO) {
1589 			pincfile = pincfile->next;
1590 			continue;
1591 		} else {
1592 			break;
1593 		}
1594 	}
1595         str = sErrorDef[err].sDescription;
1596 
1597         /*
1598             New error format selection for 2.20.11 since some
1599             people *don't* use MS products. For historical
1600             reasons we currently send errors to stdout when
1601             they should really go to stderr, but we'll switch
1602             eventually I hope... [phf]
1603         */
1604 
1605         /* determine the file pointer to use */
1606         error_file = (F_listfile != NULL) ? FI_listfile : stdout;
1607 
1608         /* print first part of message, different formats offered */
1609 	if (pincfile != NULL)
1610         switch (F_errorformat)
1611         {
1612             case ERRORFORMAT_WOE:
1613                 /*
1614                     Error format for MS VisualStudio and relatives:
1615                     "file (line): error: string"
1616                 */
1617                 if(error_file!=stdout)
1618                     fprintf(error_file, "%s (%lu): error: ",
1619                         pincfile->name, pincfile->lineno);
1620                 sprintf(erroradd1, "%s (%lu): error: ",
1621                     pincfile->name, pincfile->lineno); // -FXQ
1622                 break;
1623             case ERRORFORMAT_DILLON:
1624                 /*
1625                     Matthew Dillon's original format, except that
1626                     we don't distinguish writing to the terminal
1627                     from writing to the list file for now. Matt's
1628                     2.16 uses these:
1629 
1630                       "*line %4ld %-10s %s\n" (list file)
1631                       "line %4ld %-10s %s\n" (terminal)
1632                 */
1633                 if(error_file!=stdout)
1634                     fprintf(error_file, "line %7ld %-10s ",
1635                         pincfile->lineno, pincfile->name);
1636                 sprintf(erroradd1, "line %7ld %-10s ",
1637                     pincfile->lineno, pincfile->name); // -FXQ
1638                 break;
1639             case ERRORFORMAT_GNU:
1640                 /*
1641                     GNU format error messages, from their coding
1642                     standards.
1643                 */
1644                 if(error_file!=stdout)
1645                     fprintf(error_file, "%s:%lu: error: ",
1646                         pincfile->name, pincfile->lineno);
1647                 sprintf(erroradd1, "%s:%lu: error: ",
1648                     pincfile->name, pincfile->lineno); // -FXQ
1649                 break;
1650             default:
1651                 /* TODO: really panic here? [phf] */
1652                 panic("Invalid error format, internal error!");
1653                 break;
1654         }
1655 
1656         if(error_file!=stdout)
1657         {
1658             /* print second part of message, always the same for now */
1659             fprintf(error_file, str, sText ? sText : "");
1660             fprintf(error_file, "\n");
1661         }
1662         sprintf(erroradd2, str, sText ? sText : "");
1663         sprintf(erroradd3, "\n");
1664 
1665 	passbuffer_update(ERRORBUF,erroradd1);
1666 	passbuffer_update(ERRORBUF,erroradd2);
1667 	passbuffer_update(ERRORBUF,erroradd3);
1668 
1669         if ( bAbort )
1670         {
1671             passbuffer_output(MSGBUF); // dump messages from this pass
1672             fprintf(error_file, "Aborting assembly\n");
1673             passbuffer_output(ERRORBUF); // time to dump the errors from this pass!
1674             exit(err);
1675         }
1676     }
1677 
1678     return err;
1679 }
1680 
zmalloc(int bytes)1681 char *zmalloc(int bytes)
1682 {
1683     char *ptr = ckmalloc(bytes);
1684     if ( ptr )
1685         memset(ptr, 0, bytes);
1686     return ptr;
1687 }
1688 
ckmalloc(int bytes)1689 char *ckmalloc(int bytes)
1690 {
1691     char *ptr = malloc(bytes);
1692     if (ptr)
1693     {
1694         return ptr;
1695     }
1696     panic("unable to malloc");
1697     return NULL;
1698 }
1699 
permalloc(int bytes)1700 char *permalloc(int bytes)
1701 {
1702     static char *buf;
1703     static int left;
1704     char *ptr;
1705 
1706     /* Assume sizeof(union align) is a power of 2 */
1707 
1708     union align
1709     {
1710         long l;
1711         void *p;
1712         void (*fp)(void);
1713     };
1714 
1715     bytes = (bytes + sizeof(union align)-1) & ~(sizeof(union align)-1);
1716     if (bytes > left)
1717     {
1718         if ((buf = malloc(ALLOCSIZE)) == NULL)
1719             panic("unable to malloc");
1720         memset(buf, 0, ALLOCSIZE);
1721         left = ALLOCSIZE;
1722         if (bytes > left)
1723             panic("software error");
1724     }
1725     ptr = buf;
1726     buf += bytes;
1727     left -= bytes;
1728     return ptr;
1729 }
1730 
strlower(char * str)1731 char *strlower(char *str)
1732 {
1733     char c;
1734     char *ptr;
1735 
1736     for (ptr = str; (c = *ptr); ++ptr)
1737     {
1738         if (c >= 'A' && c <= 'Z')
1739             *ptr = c | 0x20;
1740     }
1741     return str;
1742 }
1743 
main(int ac,char ** av)1744 int main(int ac, char **av)
1745 {
1746     bool bTableSort = false;
1747     int nError = MainShadow( ac, av, &bTableSort );
1748 
1749     if ( nError && (nError != ERROR_NON_ABORT) )
1750     {
1751 	// dump messages when aborting due to errors
1752         passbuffer_output(MSGBUF);
1753 
1754         // Only print errors if assembly is unsuccessful
1755         passbuffer_output(ERRORBUF);
1756 
1757         printf( "Fatal assembly error: %s\n", sErrorDef[nError].sDescription );
1758     }
1759 
1760     DumpSymbolTable( bTableSort );
1761 
1762     passbuffer_cleanup();
1763 
1764     if (nError != 0) {
1765     	if (bRemoveOutBin) {
1766     		unlink(F_outfile);
1767     	}
1768     }
1769     return nError;
1770 }
1771 
passbuffer_clear(int mbindex)1772 void passbuffer_clear(int mbindex)
1773 {
1774     // ensure the buffer is initialized before we attempt to clear it,
1775     // just in case no messages have been stored prior to this clear.
1776     if(passbuffer[mbindex] == NULL)
1777         passbuffer_update(mbindex,"");
1778     // clear the requested guffer
1779     passbuffer[mbindex][0] = 0;
1780 }
1781 
passbuffer_update(int mbindex,char * message)1782 void passbuffer_update(int mbindex,char *message)
1783 {
1784     int newsizerequired;
1785 
1786     // allocate 16k buffers to start...
1787     static int passbuffersize[2] = {16384,16384};
1788 
1789 
1790     // check if the buffer we're working with needs initialization
1791     if(passbuffer[mbindex] == NULL)
1792     {
1793         passbuffer[mbindex] = malloc(passbuffersize[mbindex]);
1794         if(passbuffer[mbindex] == NULL)
1795             panic("couldn't allocate memory for message buffer.");
1796         passbuffer[mbindex][0] = 0; // empty string
1797     }
1798 
1799     // check if we need to grow the buffer...
1800     newsizerequired=strlen(passbuffer[mbindex])+strlen(message);
1801     if( newsizerequired > passbuffersize[mbindex])
1802     {
1803         // double the current buffer size, if sufficient, so we don't continually reallocate memory...
1804         newsizerequired = ( newsizerequired < (passbuffersize[mbindex]*2) ) ? passbuffersize[mbindex]*2 : newsizerequired;
1805 
1806         //fprintf(stderr,"DEBUG: growing buffer %d to %d bytes\n", mbindex, newsizerequired);
1807 
1808         passbuffer[mbindex] = realloc(passbuffer[mbindex], newsizerequired);
1809         if(passbuffer[mbindex] == NULL)
1810             panic("couldn't grow memory for message buffer.");
1811         passbuffersize[mbindex]=newsizerequired;
1812     }
1813 
1814     // update the buffer with the message...
1815     strcat(passbuffer[mbindex],message);
1816 }
1817 
passbuffer_output(int mbindex)1818 void passbuffer_output(int mbindex)
1819 {
1820     // ensure the buffer is initialized before we attempt to clear it,
1821     // just in case no messages have been stored yet.
1822     if(passbuffer[mbindex] == NULL)
1823         passbuffer_update(mbindex,"");
1824     printf("%s\n",passbuffer[mbindex]); // ...do we really still need to put this through stdout, instead stderr?
1825 }
1826 
passbuffer_cleanup()1827 void passbuffer_cleanup()
1828 {
1829     int t;
1830     for(t=0;t<2;t++)
1831         if(passbuffer[t]!=NULL)
1832             free(passbuffer[t]);
1833 }
1834