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