NASM 0.98.24p1
[nasm/avx512.git] / nasm.c
blob9f3eebcd631458b42dcb121354bebf3d4865668e
1 /*
2 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
3 * Julian Hall. All rights reserved. The software is
4 * redistributable under the licence given in the file "Licence"
5 * distributed in the NASM archive.
6 */
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
14 #include "nasm.h"
15 #include "nasmlib.h"
16 #include "insns.h"
17 #include "preproc.h"
18 #include "parser.h"
19 #include "eval.h"
20 #include "assemble.h"
21 #include "labels.h"
22 #include "outform.h"
23 #include "listing.h"
24 #define CACHE_ALIGN
26 struct forwrefinfo { /* info held on forward refs. */
27 int lineno;
28 int operand;
31 static int get_bits (char *value);
32 static unsigned long get_cpu (char *cpu_str);
33 static void report_error (int, char *, ...);
34 static void parse_cmdline (int, char **);
35 static void assemble_file (char *);
36 static int getkw (char *buf, char **value);
37 static void register_output_formats(void);
38 static void usage(void);
39 #ifdef CACHE_ALIGN
40 static int get_alignv (char *value);
41 void nop(void);
42 static int isdirective(char * line);
43 typedef struct lline {
44 struct lline * next;
45 char * line;
46 } lline;
47 #endif
49 static int using_debug_info;
50 int tasm_compatible_mode = FALSE;
51 int pass0;
53 static char inname[FILENAME_MAX];
54 static char outname[FILENAME_MAX];
55 static char listname[FILENAME_MAX];
56 static int globallineno; /* for forward-reference tracking */
57 /* static int pass = 0; */
58 static struct ofmt *ofmt = NULL;
60 static FILE *error_file; /* Where to write error messages */
62 static FILE *ofile = NULL;
63 int optimizing = -1; /* number of optimization passes to take */
64 static int sb, cmd_sb = 16; /* by default */
65 static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */
66 static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */
67 #ifdef CACHE_ALIGN
68 static int alignv = 0;
69 static int alignseg;
70 #endif
71 int global_offset_changed; /* referenced in labels.c */
73 static loc_t location;
74 int in_abs_seg; /* Flag we are in ABSOLUTE seg */
75 static long abs_seg;
77 static struct RAA *offsets;
78 static long abs_offset;
80 static struct SAA *forwrefs; /* keep track of forward references */
81 static struct forwrefinfo *forwref;
83 static Preproc *preproc;
84 enum op_type {
85 op_normal, /* Preprocess and assemble */
86 op_preprocess, /* Preprocess only */
87 op_depend /* Generate dependencies */
89 static enum op_type operating_mode;
92 * Which of the suppressible warnings are suppressed. Entry zero
93 * doesn't do anything. Initial defaults are given here.
95 static char suppressed[1+ERR_WARN_MAX] = {
96 0, TRUE, TRUE, TRUE, FALSE
100 * The option names for the suppressible warnings. As before, entry
101 * zero does nothing.
103 static char *suppressed_names[1+ERR_WARN_MAX] = {
104 NULL, "macro-params", "macro-selfref", "orphan-labels", "number-overflow",
108 * The explanations for the suppressible warnings. As before, entry
109 * zero does nothing.
111 static char *suppressed_what[1+ERR_WARN_MAX] = {
112 NULL,
113 "macro calls with wrong no. of params",
114 "cyclic macro self-references",
115 "labels alone on lines without trailing `:'",
116 "numeric constants greater than 0xFFFFFFFF"
120 * This is a null preprocessor which just copies lines from input
121 * to output. It's used when someone explicitly requests that NASM
122 * not preprocess their source file.
125 static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
126 static char *no_pp_getline (void);
127 static void no_pp_cleanup (int);
128 static Preproc no_pp = {
129 no_pp_reset,
130 no_pp_getline,
131 no_pp_cleanup
135 * get/set current offset...
137 #define GET_CURR_OFFS (in_abs_seg?abs_offset:\
138 raa_read(offsets,location.segment))
139 #define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
140 (void)(offsets=raa_write(offsets,location.segment,(x))))
142 static int want_usage;
143 static int terminate_after_phase;
144 int user_nolist = 0; /* fbk 9/2/00 */
146 static void nasm_fputs(char *line, FILE *ofile)
148 if (ofile) {
149 fputs(line, ofile);
150 fputc('\n', ofile);
151 } else
152 puts(line);
155 int main(int argc, char **argv)
157 pass0 = 1;
158 want_usage = terminate_after_phase = FALSE;
160 nasm_set_malloc_error (report_error);
161 offsets = raa_init();
162 forwrefs = saa_init ((long)sizeof(struct forwrefinfo));
164 preproc = &nasmpp;
165 operating_mode = op_normal;
167 error_file = stderr;
169 seg_init();
171 register_output_formats();
173 parse_cmdline(argc, argv);
175 if (terminate_after_phase)
177 if (want_usage)
178 usage();
179 return 1;
182 if (ofmt->stdmac)
183 pp_extra_stdmac (ofmt->stdmac);
184 parser_global_info (ofmt, &location);
185 eval_global_info (ofmt, lookup_label, &location);
187 /* define some macros dependent of command-line */
189 char temp [64];
190 sprintf (temp, "__OUTPUT_FORMAT__=%s\n", ofmt->shortname);
191 pp_pre_define (temp);
194 switch ( operating_mode ) {
195 case op_depend:
197 char *line;
198 preproc->reset (inname, 0, report_error, evaluate, &nasmlist);
199 if (outname[0] == '\0')
200 ofmt->filename (inname, outname, report_error);
201 ofile = NULL;
202 fprintf(stdout, "%s: %s", outname, inname);
203 while ( (line = preproc->getline()) )
204 nasm_free (line);
205 preproc->cleanup(0);
206 putc('\n', stdout);
208 break;
210 case op_preprocess:
212 char *line;
213 char *file_name = NULL;
214 long prior_linnum=0;
215 int lineinc=0;
217 if (*outname) {
218 ofile = fopen(outname, "w");
219 if (!ofile)
220 report_error (ERR_FATAL | ERR_NOFILE,
221 "unable to open output file `%s'", outname);
222 } else
223 ofile = NULL;
225 location.known = FALSE;
227 /* pass = 1; */
228 preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
229 while ( (line = preproc->getline()) ) {
231 * We generate %line directives if needed for later programs
233 long linnum = prior_linnum += lineinc;
234 int altline = src_get(&linnum, &file_name);
235 if (altline) {
236 if (altline==1 && lineinc==1)
237 nasm_fputs("", ofile);
238 else {
239 lineinc = (altline != -1 || lineinc!=1);
240 fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n",
241 linnum, lineinc, file_name);
243 prior_linnum = linnum;
245 nasm_fputs(line, ofile);
246 nasm_free (line);
248 nasm_free(file_name);
249 preproc->cleanup(0);
250 if (ofile)
251 fclose(ofile);
252 if (ofile && terminate_after_phase)
253 remove(outname);
255 break;
257 case op_normal:
260 * We must call ofmt->filename _anyway_, even if the user
261 * has specified their own output file, because some
262 * formats (eg OBJ and COFF) use ofmt->filename to find out
263 * the name of the input file and then put that inside the
264 * file.
266 ofmt->filename (inname, outname, report_error);
268 ofile = fopen(outname, "wb");
269 if (!ofile) {
270 report_error (ERR_FATAL | ERR_NOFILE,
271 "unable to open output file `%s'", outname);
275 * We must call init_labels() before ofmt->init() since
276 * some object formats will want to define labels in their
277 * init routines. (eg OS/2 defines the FLAT group)
279 init_labels ();
281 ofmt->init (ofile, report_error, define_label, evaluate);
283 assemble_file (inname);
285 if (!terminate_after_phase) {
286 ofmt->cleanup (using_debug_info);
287 cleanup_labels ();
288 } else {
290 * We had an fclose on the output file here, but we
291 * actually do that in all the object file drivers as well,
292 * so we're leaving out the one here.
293 * fclose (ofile);
295 remove(outname);
296 if (listname[0])
297 remove(listname);
300 break;
303 if (want_usage)
304 usage();
306 raa_free (offsets);
307 saa_free (forwrefs);
308 eval_cleanup ();
309 nasmlib_cleanup ();
311 if (terminate_after_phase)
312 return 1;
313 else
314 return 0;
319 * Get a parameter for a command line option.
320 * First arg must be in the form of e.g. -f...
322 static char *get_param (char *p, char *q, int *advance)
324 *advance = 0;
325 if (p[2]) /* the parameter's in the option */
327 p += 2;
328 while (isspace(*p))
329 p++;
330 return p;
332 if (q && q[0])
334 *advance = 1;
335 return q;
337 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
338 "option `-%c' requires an argument",
339 p[1]);
340 return NULL;
343 struct textargs
345 char *label;
346 int value;
349 #define OPT_PREFIX 0
350 #define OPT_POSTFIX 1
351 struct textargs textopts[] =
353 {"prefix",OPT_PREFIX},
354 {"postfix",OPT_POSTFIX},
355 {NULL,0}
359 int stopoptions = 0;
360 static int process_arg (char *p, char *q)
362 char *param;
363 int i, advance = 0;
365 if (!p || !p[0])
366 return 0;
368 if (p[0]=='-' && ! stopoptions)
370 switch (p[1]) {
371 case 's':
372 error_file = stdout;
373 break;
374 case 'o': /* these parameters take values */
375 case 'O':
376 case 'f':
377 case 'p':
378 case 'P':
379 case 'd':
380 case 'D':
381 case 'i':
382 case 'I':
383 case 'l':
384 case 'E':
385 case 'F':
386 #ifdef 0/*CACHE_ALIGN*/
387 case 'A':
388 #endif
389 if ( !(param = get_param (p, q, &advance)) )
390 break;
391 if (p[1]=='o') { /* output file */
392 strcpy (outname, param);
393 } else if (p[1]=='f') { /* output format */
394 ofmt = ofmt_find(param);
395 if (!ofmt) {
396 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
397 "unrecognised output format `%s' - "
398 "use -hf for a list",
399 param);
401 else
402 ofmt->current_dfmt = ofmt->debug_formats[0];
404 #ifdef 0 /*CACHE_ALIGN*/
405 else if (p[1]=='A') {
406 int opt;
407 if (!isdigit(*param)) report_error(ERR_FATAL,
408 "command line alignment level must be 0..6");
409 opt = atoi(param);
410 if (opt<=0) alignv = 0;
411 else if (opt>=6) alignv = 64;
412 else alignv = (1 << opt);
414 #endif
415 else if (p[1]=='O') { /* Optimization level */
416 int opt;
417 if (!isdigit(*param)) report_error(ERR_FATAL,
418 "command line optimization level must be 0..3 or <nn>");
419 opt = atoi(param);
420 if (opt<=0) optimizing = -1; /* 0.98 behaviour */
421 else if (opt==1) optimizing = 0; /* Two passes, 0.98.09 behavior */
422 else if (opt<=3) optimizing = opt*5; /* Multiple passes */
423 else optimizing = opt; /* Multiple passes */
424 } else if (p[1]=='P' || p[1]=='p') { /* pre-include */
425 pp_pre_include (param);
426 } else if (p[1]=='D' || p[1]=='d') { /* pre-define */
427 pp_pre_define (param);
428 } else if (p[1]=='U' || p[1]=='u') { /* un-define */
429 pp_pre_undefine (param);
430 } else if (p[1]=='I' || p[1]=='i') { /* include search path */
431 pp_include_path (param);
432 } else if (p[1]=='l') { /* listing file */
433 strcpy (listname, param);
434 } else if (p[1]=='E') { /* error messages file */
435 error_file = fopen(param, "w");
436 if ( !error_file ) {
437 error_file = stderr; /* Revert to default! */
438 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
439 "cannot open file `%s' for error messages",
440 param);
442 } else if (p[1] == 'F') { /* specify debug format */
443 ofmt->current_dfmt = dfmt_find(ofmt, param);
444 if (!ofmt->current_dfmt) {
445 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
446 "unrecognized debug format `%s' for"
447 " output format `%s'",
448 param, ofmt->shortname);
451 break;
452 case 'g':
453 using_debug_info = TRUE;
454 break;
455 case 'h':
456 printf("usage: nasm [-@ response file] [-o outfile] [-f format] "
457 "[-l listfile]\n"
458 " [options...] [--] filename\n"
459 " or nasm -r for version info (obsolete)\n"
460 " or nasm -v for version info (preferred)\n\n"
461 " -t Assemble in SciTech TASM compatible mode\n"
462 " -g Generate debug information in selected format.\n");
463 printf(" -e preprocess only (writes output to stdout by default)\n"
464 " -a don't preprocess (assemble only)\n"
465 " -M generate Makefile dependencies on stdout\n\n"
466 " -E<file> redirect error messages to file\n"
467 " -s redirect error messages to stdout\n\n"
468 " -F format select a debugging format\n\n"
469 " -I<path> adds a pathname to the include file path\n");
470 printf(" -O<digit> optimize branch offsets (-O0 disables, default)\n"
471 " -P<file> pre-includes a file\n"
472 " -D<macro>[=<value>] pre-defines a macro\n"
473 " -U<macro> undefines a macro\n"
474 " -w+foo enables warnings about foo; -w-foo disables them\n"
475 "where foo can be:\n");
476 for (i=1; i<=ERR_WARN_MAX; i++)
477 printf(" %-16s%s (default %s)\n",
478 suppressed_names[i], suppressed_what[i],
479 suppressed[i] ? "off" : "on");
480 printf ("\nresponse files should contain command line parameters"
481 ", one per line.\n");
482 if (p[2] == 'f') {
483 printf("\nvalid output formats for -f are"
484 " (`*' denotes default):\n");
485 ofmt_list(ofmt, stdout);
487 else {
488 printf ("\nFor a list of valid output formats, use -hf.\n");
489 printf ("For a list of debug formats, use -f <form> -y.\n");
491 exit (0); /* never need usage message here */
492 break;
493 case 'y':
494 printf("\nvalid debug formats for '%s' output format are"
495 " ('*' denotes default):\n",
496 ofmt->shortname);
497 dfmt_list(ofmt, stdout);
498 exit(0);
499 break;
500 case 't':
501 tasm_compatible_mode = TRUE;
502 break;
503 case 'r':
504 case 'v':
505 printf("NASM version %s compiled "
506 #ifdef DEBUG
507 "with -DDEBUG "
508 #endif
509 "on " __DATE__ "\n", NASM_VER);
510 exit (0); /* never need usage message here */
511 break;
512 case 'e': /* preprocess only */
513 operating_mode = op_preprocess;
514 break;
515 case 'a': /* assemble only - don't preprocess */
516 preproc = &no_pp;
517 break;
518 case 'w':
519 if (p[2] != '+' && p[2] != '-') {
520 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
521 "invalid option to `-w'");
522 } else {
523 for (i=1; i<=ERR_WARN_MAX; i++)
524 if (!nasm_stricmp(p+3, suppressed_names[i]))
525 break;
526 if (i <= ERR_WARN_MAX)
527 suppressed[i] = (p[2] == '-');
528 else
529 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
530 "invalid option to `-w'");
532 break;
533 case 'M':
534 operating_mode = op_depend;
535 break;
537 case '-':
539 int s;
541 if (p[2]==0) { /* -- => stop processing options */
542 stopoptions = 1;
543 break;
545 for(s=0; textopts[s].label; s++)
547 if(!nasm_stricmp(p+2, textopts[s].label))
549 break;
553 switch(s)
556 case OPT_PREFIX:
557 case OPT_POSTFIX:
559 if (!q)
561 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
562 "option `--%s' requires an argument",
563 p+2);
564 break;
566 else
568 advance = 1, param = q;
571 if(s == OPT_PREFIX)
573 strncpy(lprefix,param,PREFIX_MAX-1);
574 lprefix[PREFIX_MAX-1]=0;
575 break;
577 if(s == OPT_POSTFIX)
579 strncpy(lpostfix,param,POSTFIX_MAX-1);
580 lpostfix[POSTFIX_MAX-1]=0;
581 break;
583 break;
585 default:
587 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
588 "unrecognised option `--%s'",
589 p+2);
590 break;
593 break;
596 default:
597 if (!ofmt->setinfo(GI_SWITCH,&p))
598 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
599 "unrecognised option `-%c'",
600 p[1]);
601 break;
604 else
606 if (*inname) {
607 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
608 "more than one input file specified");
609 } else
610 strcpy(inname, p);
613 return advance;
616 #define ARG_BUF_DELTA 128
618 static void process_respfile (FILE *rfile)
620 char *buffer, *p, *q, *prevarg;
621 int bufsize, prevargsize;
623 bufsize = prevargsize = ARG_BUF_DELTA;
624 buffer = nasm_malloc(ARG_BUF_DELTA);
625 prevarg = nasm_malloc(ARG_BUF_DELTA);
626 prevarg[0] = '\0';
628 while (1) { /* Loop to handle all lines in file */
630 p = buffer;
631 while (1) { /* Loop to handle long lines */
632 q = fgets(p, bufsize-(p-buffer), rfile);
633 if (!q)
634 break;
635 p += strlen(p);
636 if (p > buffer && p[-1] == '\n')
637 break;
638 if (p-buffer > bufsize-10) {
639 int offset;
640 offset = p - buffer;
641 bufsize += ARG_BUF_DELTA;
642 buffer = nasm_realloc(buffer, bufsize);
643 p = buffer + offset;
647 if (!q && p == buffer) {
648 if (prevarg[0])
649 process_arg (prevarg, NULL);
650 nasm_free (buffer);
651 nasm_free (prevarg);
652 return;
656 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
657 * them are present at the end of the line.
659 *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
661 while (p > buffer && isspace(p[-1]))
662 *--p = '\0';
664 p = buffer;
665 while (isspace(*p))
666 p++;
668 if (process_arg (prevarg, p))
669 *p = '\0';
671 if (strlen(p) > prevargsize-10) {
672 prevargsize += ARG_BUF_DELTA;
673 prevarg = nasm_realloc(prevarg, prevargsize);
675 strcpy (prevarg, p);
679 /* Function to process args from a string of args, rather than the
680 * argv array. Used by the environment variable and response file
681 * processing.
683 static void process_args (char *args) {
684 char *p, *q, *arg, *prevarg;
685 char separator = ' ';
687 p = args;
688 if (*p && *p != '-')
689 separator = *p++;
690 arg = NULL;
691 while (*p) {
692 q = p;
693 while (*p && *p != separator) p++;
694 while (*p == separator) *p++ = '\0';
695 prevarg = arg;
696 arg = q;
697 if (process_arg (prevarg, arg))
698 arg = NULL;
700 if (arg)
701 process_arg (arg, NULL);
704 static void parse_cmdline(int argc, char **argv)
706 FILE *rfile;
707 char *envreal, *envcopy=NULL, *p, *arg;
709 *inname = *outname = *listname = '\0';
712 * First, process the NASM environment variable.
714 envreal = getenv("NASM");
715 arg = NULL;
716 if (envreal) {
717 envcopy = nasm_strdup(envreal);
718 process_args(envcopy);
719 nasm_free (envcopy);
723 * Now process the actual command line.
725 while (--argc)
727 int i;
728 argv++;
729 if (argv[0][0] == '@') {
730 /* We have a response file, so process this as a set of
731 * arguments like the environment variable. This allows us
732 * to have multiple arguments on a single line, which is
733 * different to the -@resp file processing below for regular
734 * NASM.
736 char *str = malloc(2048);
737 FILE *f = fopen(&argv[0][1],"r");
738 if (!str) {
739 printf("out of memory");
740 exit(-1);
742 if (f) {
743 while (fgets(str,2048,f)) {
744 process_args(str);
746 fclose(f);
748 free(str);
749 argc--;
750 argv++;
752 if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
753 if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i))) {
754 if ((rfile = fopen(p, "r"))) {
755 process_respfile (rfile);
756 fclose(rfile);
757 } else
758 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
759 "unable to open response file `%s'", p);
761 } else
762 i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
763 argv += i, argc -= i;
766 if (!*inname)
767 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
768 "no input file specified");
772 static void assemble_file (char *fname)
774 char * value, * p, * q, * special, * line, debugid[80];
775 insn output_ins;
777 #ifdef CACHE_ALIGN
778 lline * prevlline, * curlline, * lastlline;
779 char * nextline;
780 insn pad_ins[15] ;
781 char * pad_line[] = {
782 " db 0x90 " ,
783 " db 0x8D,0x36 " ,
784 " db 0x8D,0x76,0x00 " ,
785 " db 0x8D,0x74,0x26,0x00 " ,
786 " db 0x8D,0x74,0x26,0x00,0x90 " ,
787 " db 0x8D,0xB6,0x00,0x00,0x00,0x00 " ,
788 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00 " ,
789 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x90 " ,
790 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x8D,0x36 " ,
791 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x8D,0x76,0x00 " ,
792 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x8D,0x74,0x26,0x00 " ,
793 " db 0x8D,0xB6,0x00,0x00,0x00,0x00,0x8D,0xB6,0x00,0x00,0x00,0x00 " ,
794 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x8D,0xB6,0x00,0x00,0x00,0x00 " ,
795 " db 0x8D,0xB4,0x26,0x00,0x00,0x00,0x00,0x8D,0xB4,0x26,0x00,0x00,0x00,0x00 ",
796 " db 0xEB,0x00 " } ;
797 #endif
799 int i, rn_error, validid;
800 long seg, offs;
801 struct tokenval tokval;
802 expr * e;
803 int pass, pass_max;
804 int pass_cnt = 0; /* count actual passes */
806 #ifdef CACHE_ALIGN
807 for (i=0 ; i<15 ; i++) {
808 parse_line ( 1 , pad_line[i], &pad_ins[i],
809 report_error, evaluate, define_label);
811 #endif
813 if (cmd_sb == 32 && cmd_cpu < IF_386)
814 report_error(ERR_FATAL, "command line: "
815 "32-bit segment size requires a higher cpu");
817 pass_max = (optimizing>0 ? optimizing : 0) + 2; /* passes 1, optimizing,
818 then 2 */
819 pass0 = !(optimizing>0); /* start at 1 if not optimizing */
820 for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) {
821 int pass1, pass2;
822 ldfunc def_label;
824 pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */
825 pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */
826 /* pass0 seq is 0, 0, 0,..., 1, 2 */
828 def_label = pass > 1 ? redefine_label : define_label;
831 sb = cmd_sb; /* set 'bits' to command line default */
832 cpu = cmd_cpu;
833 if (pass0 == 2) {
834 if (*listname)
835 nasmlist.init(listname, report_error);
837 in_abs_seg = FALSE;
838 global_offset_changed = FALSE; /* set by redefine_label */
839 location.segment = ofmt->section(NULL, pass2, &sb);
840 if (pass > 1) {
841 saa_rewind (forwrefs);
842 forwref = saa_rstruct (forwrefs);
843 raa_free (offsets);
844 offsets = raa_init();
846 preproc->reset(fname, pass1, report_error, evaluate, &nasmlist);
847 globallineno = 0;
848 if (pass == 1) location.known = TRUE;
849 location.offset = offs = GET_CURR_OFFS;
850 #ifdef CACHE_ALIGN
851 alignv=0;
852 curlline=nasm_malloc(sizeof(lline));
853 curlline->next=NULL;
854 curlline->line = preproc->getline();
855 prevlline=lastlline=curlline;
856 while (curlline->line!=NULL)
858 line=curlline->line;
859 #else
860 while ( (line = preproc->getline()) )
862 #endif
863 globallineno++;
865 /* here we parse our directives; this is not handled by the 'real'
866 * parser. */
867 if ( (i = getkw (line, &value)) )
869 switch (i) {
870 case 1: /* [SEGMENT n] */
871 seg = ofmt->section (value, pass2, &sb);
872 if (seg == NO_SEG) {
873 report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC,
874 "segment name `%s' not recognised",
875 value);
876 } else {
877 in_abs_seg = FALSE;
878 location.segment = seg;
880 break;
881 case 2: /* [EXTERN label:special] */
882 if (*value == '$') value++; /* skip initial $ if present */
883 if (pass0 == 2) {
884 q = value;
885 while (*q && *q != ':')
886 q++;
887 if (*q == ':') {
888 *q++ = '\0';
889 ofmt->symdef(value, 0L, 0L, 3, q);
891 } else if (pass == 1) { /* pass == 1 */
892 q = value;
893 validid = TRUE;
894 if (!isidstart(*q))
895 validid = FALSE;
896 while (*q && *q != ':') {
897 if (!isidchar(*q))
898 validid = FALSE;
899 q++;
901 if (!validid) {
902 report_error (ERR_NONFATAL,
903 "identifier expected after EXTERN");
904 break;
906 if (*q == ':') {
907 *q++ = '\0';
908 special = q;
909 } else
910 special = NULL;
911 if (!is_extern(value)) { /* allow re-EXTERN to be
912 ignored */
913 int temp = pass0;
914 pass0 = 1; /* fake pass 1 in labels.c */
915 declare_as_global (value, special, report_error);
916 define_label (value, seg_alloc(), 0L, NULL, FALSE,
917 TRUE,
918 ofmt, report_error);
919 pass0 = temp;
921 } /* else pass0 == 1 */
922 break;
923 case 3: /* [BITS bits] */
924 sb = get_bits(value);
925 break;
926 case 4: /* [GLOBAL symbol:special] */
927 if (*value == '$') value++; /* skip initial $ if present */
928 if (pass0 == 2) { /* pass 2 */
929 q = value;
930 while (*q && *q != ':')
931 q++;
932 if (*q == ':') {
933 *q++ = '\0';
934 ofmt->symdef(value, 0L, 0L, 3, q);
936 } else if (pass2 == 1) { /* pass == 1 */
937 q = value;
938 validid = TRUE;
939 if (!isidstart(*q))
940 validid = FALSE;
941 while (*q && *q != ':') {
942 if (!isidchar(*q))
943 validid = FALSE;
944 q++;
946 if (!validid) {
947 report_error (ERR_NONFATAL,
948 "identifier expected after GLOBAL");
949 break;
951 if (*q == ':') {
952 *q++ = '\0';
953 special = q;
954 } else
955 special = NULL;
956 declare_as_global (value, special, report_error);
957 } /* pass == 1 */
958 break;
959 case 5: /* [COMMON symbol size:special] */
960 if (*value == '$') value++; /* skip initial $ if present */
961 if (pass0 == 1) {
962 p = value;
963 validid = TRUE;
964 if (!isidstart(*p))
965 validid = FALSE;
966 while (*p && !isspace(*p)) {
967 if (!isidchar(*p))
968 validid = FALSE;
969 p++;
971 if (!validid) {
972 report_error (ERR_NONFATAL,
973 "identifier expected after COMMON");
974 break;
976 if (*p) {
977 long size;
979 while (*p && isspace(*p))
980 *p++ = '\0';
981 q = p;
982 while (*q && *q != ':')
983 q++;
984 if (*q == ':') {
985 *q++ = '\0';
986 special = q;
987 } else
988 special = NULL;
989 size = readnum (p, &rn_error);
990 if (rn_error)
991 report_error (ERR_NONFATAL, "invalid size specified"
992 " in COMMON declaration");
993 else
994 define_common (value, seg_alloc(), size,
995 special, ofmt, report_error);
996 } else
997 report_error (ERR_NONFATAL, "no size specified in"
998 " COMMON declaration");
999 } else if (pass0 == 2) { /* pass == 2 */
1000 q = value;
1001 while (*q && *q != ':') {
1002 if (isspace(*q))
1003 *q = '\0';
1004 q++;
1006 if (*q == ':') {
1007 *q++ = '\0';
1008 ofmt->symdef(value, 0L, 0L, 3, q);
1011 break;
1012 case 6: /* [ABSOLUTE address] */
1013 stdscan_reset();
1014 stdscan_bufptr = value;
1015 tokval.t_type = TOKEN_INVALID;
1016 e = evaluate(stdscan, NULL, &tokval, NULL, pass2,
1017 report_error,
1018 NULL);
1019 if (e) {
1020 if (!is_reloc(e))
1021 report_error (pass0==1 ? ERR_NONFATAL : ERR_PANIC,
1022 "cannot use non-relocatable expression as "
1023 "ABSOLUTE address");
1024 else {
1025 abs_seg = reloc_seg(e);
1026 abs_offset = reloc_value(e);
1028 } else
1029 if (pass==1) abs_offset = 0x100;/* don't go near zero in
1030 case of / */
1031 else report_error (ERR_PANIC, "invalid ABSOLUTE address "
1032 "in pass two");
1033 in_abs_seg = TRUE;
1034 location.segment = abs_seg;
1035 break;
1036 case 7: /* DEBUG */
1037 p = value;
1038 q = debugid;
1039 validid = TRUE;
1040 if (!isidstart(*p))
1041 validid = FALSE;
1042 while (*p && !isspace(*p)) {
1043 if (!isidchar(*p))
1044 validid = FALSE;
1045 *q++ = *p++;
1047 *q++ = 0;
1048 if (!validid) {
1049 report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC,
1050 "identifier expected after DEBUG");
1051 break;
1053 while (*p && isspace(*p)) p++;
1054 if (pass==pass_max) ofmt->current_dfmt->debug_directive
1055 (debugid, p);
1056 break;
1057 case 8: /* [WARNING {+|-}warn-name] */
1058 if (pass1 == 1) {
1059 while (*value && isspace(*value))
1060 value++;
1062 if (*value == '+' || *value == '-') {
1063 validid = (*value == '-') ? TRUE : FALSE;
1064 value++;
1065 } else
1066 validid = FALSE;
1068 for (i=1; i<=ERR_WARN_MAX; i++)
1069 if (!nasm_stricmp(value, suppressed_names[i]))
1070 break;
1071 if (i <= ERR_WARN_MAX)
1072 suppressed[i] = validid;
1073 else
1074 report_error (ERR_NONFATAL, "invalid warning id in WARNING directive");
1076 break;
1077 case 9: /* cpu */
1078 cpu = get_cpu (value);
1079 break;
1080 case 10: /* fbk 9/2/00 */ /* [LIST {+|-}] */
1081 while (*value && isspace(*value))
1082 value++;
1084 if (*value == '+') {
1085 user_nolist = 0;
1087 else {
1088 if (*value == '-') {
1089 user_nolist = 1;
1091 else {
1092 report_error (ERR_NONFATAL, "invalid parameter to \"list\" directive");
1095 break;
1096 #ifdef CACHE_ALIGN
1097 case 11:
1098 do {
1099 int alignv;
1100 int pad_len;
1101 insn * pad_temp;
1102 extop * pad_eop;
1103 alignv = get_alignv(value);
1104 if (alignv) {
1105 if (pass1 == 1) {
1106 offs = offs + ((alignv - 1) & (-offs));
1107 SET_CURR_OFFS (offs);
1109 else {
1110 pad_len = ((alignv -1 ) & (-offs));
1111 if (pad_len >= 15) {
1112 pad_temp = &pad_ins[14];
1113 pad_eop = pad_temp->eops ;
1114 pad_eop = pad_eop->next ;
1115 pad_eop->offset = pad_len - 2 ;
1116 offs += assemble (location.segment, offs, sb, cpu,
1117 &pad_ins[14], ofmt, report_error,
1118 &nasmlist);
1119 SET_CURR_OFFS (offs);
1120 pad_len-=2 ;
1121 while (pad_len)
1123 offs += assemble (location.segment, offs, sb, cpu,
1124 &pad_ins[0], ofmt, report_error,
1125 &nasmlist);
1126 SET_CURR_OFFS (offs);
1127 pad_len--;
1130 else if (pad_len > 0)
1132 offs += assemble (location.segment, offs, sb, cpu,
1133 &pad_ins[pad_len - 1], ofmt, report_error,
1134 &nasmlist);
1135 SET_CURR_OFFS (offs);
1139 } while (0) ;
1140 break;
1141 case 12:
1142 alignv = get_alignv(value);
1143 alignseg = seg;
1144 break;
1145 #endif
1146 default:
1147 if (!ofmt->directive (line+1, value, pass2))
1148 report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC,
1149 "unrecognised directive [%s]",
1150 line+1);
1153 else /* it isn't a directive */
1155 parse_line (pass1, line, &output_ins,
1156 report_error, evaluate,
1157 def_label);
1159 if (!(optimizing>0) && pass == 2) {
1160 if (forwref != NULL && globallineno == forwref->lineno) {
1161 output_ins.forw_ref = TRUE;
1162 do {
1163 output_ins.oprs[forwref->operand].opflags |=
1164 OPFLAG_FORWARD;
1165 forwref = saa_rstruct (forwrefs);
1166 } while (forwref != NULL && forwref->lineno ==
1167 globallineno);
1168 } else
1169 output_ins.forw_ref = FALSE;
1173 if (!(optimizing>0) && output_ins.forw_ref)
1175 if (pass == 1) {
1176 for(i = 0; i < output_ins.operands; i++)
1178 if (output_ins.oprs[i].opflags & OPFLAG_FORWARD)
1180 struct forwrefinfo *fwinf =
1181 (struct forwrefinfo
1182 *)saa_wstruct(forwrefs);
1183 fwinf->lineno = globallineno;
1184 fwinf->operand = i;
1187 } else { /* pass == 2 */
1189 * Hack to prevent phase error in the code
1190 * rol ax,x
1191 * x equ 1
1193 * If the second operand is a forward reference,
1194 * the UNITY property of the number 1 in that
1195 * operand is cancelled. Otherwise the above
1196 * sequence will cause a phase error.
1198 * This hack means that the above code will
1199 * generate 286+ code.
1201 * The forward reference will mean that the
1202 * operand will not have the UNITY property on
1203 * the first pass, so the pass behaviours will
1204 * be consistent.
1207 if (output_ins.operands >= 2 &&
1208 (output_ins.oprs[1].opflags & OPFLAG_FORWARD))
1210 output_ins.oprs[1].type &= ~(ONENESS|BYTENESS);
1213 } /* pass == 2 */
1215 } /* forw_ref */
1218 if (output_ins.opcode == I_EQU) {
1219 if (pass1 == 1)
1222 * Special `..' EQUs get processed in pass two,
1223 * except `..@' macro-processor EQUs which are done
1224 * in the normal place.
1226 if (!output_ins.label)
1227 report_error (ERR_NONFATAL,
1228 "EQU not preceded by label");
1230 else if (output_ins.label[0] != '.' ||
1231 output_ins.label[1] != '.' ||
1232 output_ins.label[2] == '@')
1234 if (output_ins.operands == 1 &&
1235 (output_ins.oprs[0].type & IMMEDIATE) &&
1236 output_ins.oprs[0].wrt == NO_SEG)
1238 int isext = output_ins.oprs[0].opflags &
1239 OPFLAG_EXTERN;
1240 def_label (output_ins.label,
1241 output_ins.oprs[0].segment,
1242 output_ins.oprs[0].offset,
1243 NULL, FALSE, isext, ofmt,
1244 report_error);
1246 else if (output_ins.operands == 2 &&
1247 (output_ins.oprs[0].type & IMMEDIATE) &&
1248 (output_ins.oprs[0].type & COLON) &&
1249 output_ins.oprs[0].segment == NO_SEG &&
1250 output_ins.oprs[0].wrt == NO_SEG &&
1251 (output_ins.oprs[1].type & IMMEDIATE) &&
1252 output_ins.oprs[1].segment == NO_SEG &&
1253 output_ins.oprs[1].wrt == NO_SEG)
1255 def_label (output_ins.label,
1256 output_ins.oprs[0].offset |
1257 SEG_ABS,
1258 output_ins.oprs[1].offset,
1259 NULL, FALSE, FALSE, ofmt,
1260 report_error);
1262 else
1263 report_error(ERR_NONFATAL, "bad syntax for EQU");
1265 } else { /* pass == 2 */
1267 * Special `..' EQUs get processed here, except
1268 * `..@' macro processor EQUs which are done above.
1270 if (output_ins.label[0] == '.' &&
1271 output_ins.label[1] == '.' &&
1272 output_ins.label[2] != '@')
1274 if (output_ins.operands == 1 &&
1275 (output_ins.oprs[0].type & IMMEDIATE)) {
1276 define_label (output_ins.label,
1277 output_ins.oprs[0].segment,
1278 output_ins.oprs[0].offset,
1279 NULL, FALSE, FALSE, ofmt,
1280 report_error);
1282 else if (output_ins.operands == 2 &&
1283 (output_ins.oprs[0].type & IMMEDIATE) &&
1284 (output_ins.oprs[0].type & COLON) &&
1285 output_ins.oprs[0].segment == NO_SEG &&
1286 (output_ins.oprs[1].type & IMMEDIATE) &&
1287 output_ins.oprs[1].segment == NO_SEG)
1289 define_label (output_ins.label,
1290 output_ins.oprs[0].offset |
1291 SEG_ABS,
1292 output_ins.oprs[1].offset,
1293 NULL, FALSE, FALSE, ofmt,
1294 report_error);
1296 else
1297 report_error(ERR_NONFATAL, "bad syntax for EQU");
1299 } /* pass == 2 */
1300 } else { /* instruction isn't an EQU */
1302 if (pass1 == 1) {
1304 long l = insn_size (location.segment, offs, sb, cpu,
1305 &output_ins, report_error);
1307 /* if (using_debug_info) && output_ins.opcode != -1)*/
1308 if (using_debug_info) /* fbk 03/25/01 */
1311 /* this is done here so we can do debug type info */
1312 long typeinfo = TYS_ELEMENTS(output_ins.operands);
1313 switch (output_ins.opcode) {
1314 case I_RESB:
1315 typeinfo =
1316 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
1317 break;
1318 case I_RESW:
1319 typeinfo =
1320 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
1321 break;
1322 case I_RESD:
1323 typeinfo =
1324 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
1325 break;
1326 case I_RESQ:
1327 typeinfo =
1328 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
1329 break;
1330 case I_REST:
1331 typeinfo =
1332 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
1333 break;
1334 case I_DB:
1335 typeinfo |= TY_BYTE;
1336 break;
1337 case I_DW:
1338 typeinfo |= TY_WORD;
1339 break;
1340 case I_DD:
1341 if (output_ins.eops_float)
1342 typeinfo |= TY_FLOAT;
1343 else
1344 typeinfo |= TY_DWORD;
1345 break;
1346 case I_DQ:
1347 typeinfo |= TY_QWORD;
1348 break;
1349 case I_DT:
1350 typeinfo |= TY_TBYTE;
1351 break;
1352 default:
1353 typeinfo = TY_LABEL;
1357 ofmt->current_dfmt->debug_typevalue(typeinfo);
1360 if (l != -1) {
1361 offs += l;
1362 SET_CURR_OFFS (offs);
1363 #ifdef CACHE_ALIGN
1364 if (alignv && (seg == alignseg))
1366 lline * nextlline;
1367 insn next_ins;
1368 long l;
1369 nextlline=curlline;
1370 while(1)
1372 if (nextlline==lastlline)
1374 lastlline=lastlline->next=nasm_malloc(sizeof(lline));
1375 lastlline->next=NULL;
1376 lastlline->line=preproc->getline();
1378 nextlline=nextlline->next;
1379 nextline=nextlline->line;
1380 if(!nextline) break;
1381 if ((isdirective(nextline)==1))
1383 alignv=0;
1384 break;
1386 if ((isdirective(nextline)==0))
1388 if (in_abs_seg) break;
1389 parse_line (pass1, nextline, &next_ins,report_error, evaluate,nop);
1390 l = insn_size (location.segment, offs, sb, cpu,&next_ins, report_error);
1391 if ( l > 0 )
1393 if (((((offs & (alignv - 1)) + l) > alignv) && (l <= alignv) ))
1395 offs = offs + ((alignv - 1) & (-offs));
1396 SET_CURR_OFFS (offs);
1398 break;
1404 #endif
1407 * else l == -1 => invalid instruction, which will be
1408 * flagged as an error on pass 2
1411 } else { /* pass == 2 */
1412 offs += assemble (location.segment, offs, sb, cpu,
1413 &output_ins, ofmt, report_error,
1414 &nasmlist);
1415 SET_CURR_OFFS (offs);
1416 #ifdef CACHE_ALIGN
1417 if (alignv && (seg==alignseg))
1419 insn next_ins;
1420 int pad_len ;
1421 insn * pad_temp;
1422 extop * pad_eop;
1423 long l;
1424 lline * nextlline;
1425 nextlline=curlline;
1426 while(1)
1428 if (nextlline==lastlline)
1430 lastlline=lastlline->next=nasm_malloc(sizeof(lline));
1431 lastlline->next=NULL;
1432 lastlline->line=preproc->getline();
1434 nextlline=nextlline->next;
1435 nextline=nextlline->line;
1436 if (!nextline) break;
1437 if ((isdirective(nextline)==1))
1439 alignv=0;
1440 break;
1442 if ((isdirective(nextline)==0))
1444 if (in_abs_seg) break;
1445 parse_line (pass1, nextline, &next_ins,report_error, evaluate,nop);
1446 l = insn_size (location.segment, offs, sb, cpu,&next_ins, report_error);
1447 if ( l > 0 )
1449 if (((((offs & (alignv - 1)) + l) > alignv) && (l <= alignv) ))
1451 pad_len = ((alignv - 1) & (-offs));
1452 if (pad_len >= 15)
1454 pad_temp = &pad_ins[14];
1455 pad_eop = pad_temp->eops ;
1456 pad_eop = pad_eop->next ;
1457 pad_eop->offset = pad_len - 2 ;
1458 offs += assemble (location.segment, offs, sb, cpu,
1459 &pad_ins[14], ofmt, report_error,
1460 &nasmlist);
1461 SET_CURR_OFFS (offs);
1462 pad_len-=2 ;
1463 while (pad_len)
1465 offs += assemble (location.segment, offs, sb, cpu,
1466 &pad_ins[0], ofmt, report_error,
1467 &nasmlist);
1468 SET_CURR_OFFS (offs);
1469 pad_len--;
1472 else if (pad_len > 0)
1474 offs += assemble (location.segment, offs, sb, cpu,
1475 &pad_ins[pad_len - 1], ofmt, report_error,
1476 &nasmlist);
1477 SET_CURR_OFFS (offs);
1480 break;
1486 #endif
1490 } /* not an EQU */
1491 cleanup_insn (&output_ins);
1493 nasm_free (line);
1494 location.offset = offs = GET_CURR_OFFS;
1495 #ifdef CACHE_ALIGN
1496 prevlline=curlline;
1497 if (curlline==lastlline)
1499 lastlline=curlline=nasm_malloc(sizeof(lline));
1500 curlline->next=NULL;
1501 curlline->line=preproc->getline();
1503 else curlline=curlline->next;
1504 nasm_free(prevlline);
1505 #endif
1506 } /* end while (line = preproc->getline... */
1508 if (pass1==2 && global_offset_changed)
1509 report_error(ERR_NONFATAL, "phase error detected at end of assembly.");
1511 if (pass1 == 1) preproc->cleanup(1);
1513 if (pass1==1 && terminate_after_phase) {
1514 fclose(ofile);
1515 remove(outname);
1516 if (want_usage)
1517 usage();
1518 exit (1);
1520 pass_cnt++;
1521 if (pass>1 && !global_offset_changed) {
1522 pass0++;
1523 if (pass0==2) pass = pass_max - 1;
1524 } else if (!(optimizing>0)) pass0++;
1526 } /* for (pass=1; pass<=2; pass++) */
1528 preproc->cleanup(0);
1529 nasmlist.cleanup();
1530 #if 1
1531 if (optimizing>0 && using_debug_info) /* -On and -g switches */
1532 fprintf(stdout,
1533 "info:: assembly required 1+%d+1 passes\n", pass_cnt-2);
1534 #endif
1535 } /* exit from assemble_file (...) */
1538 static int getkw (char *buf, char **value)
1540 char *p, *q;
1542 /* allow leading spaces or tabs */
1543 while (*buf==' ' || *buf=='\t')
1544 buf++;
1546 if (*buf!='[')
1547 return 0;
1549 p = buf;
1551 while (*p && *p != ']') p++;
1553 if (!*p)
1554 return 0;
1556 q = p++;
1558 while (*p && *p != ';') {
1559 if (!isspace(*p))
1560 return 0;
1561 p++;
1563 q[1] = '\0';
1565 p = buf+1;
1566 while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
1567 buf++;
1568 if (*buf==']') {
1569 *buf = '\0';
1570 *value = buf;
1571 } else {
1572 *buf++ = '\0';
1573 while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
1574 *value = buf;
1575 while (*buf!=']') buf++;
1576 *buf++ = '\0';
1578 #if 0
1579 for (q=p; *q; q++)
1580 *q = tolower(*q);
1581 #endif
1582 if (!nasm_stricmp(p, "segment") || !nasm_stricmp(p, "section"))
1583 return 1;
1584 if (!nasm_stricmp(p, "extern"))
1585 return 2;
1586 if (!nasm_stricmp(p, "bits"))
1587 return 3;
1588 if (!nasm_stricmp(p, "global"))
1589 return 4;
1590 if (!nasm_stricmp(p, "common"))
1591 return 5;
1592 if (!nasm_stricmp(p, "absolute"))
1593 return 6;
1594 if (!nasm_stricmp(p, "debug"))
1595 return 7;
1596 if (!nasm_stricmp(p, "warning"))
1597 return 8;
1598 if (!nasm_stricmp(p, "cpu"))
1599 return 9;
1600 if (!nasm_stricmp(p, "list")) /* fbk 9/2/00 */
1601 return 10;
1602 #ifdef CACHE_ALIGN
1603 if (!nasm_stricmp(p, "palign"))
1604 return 11;
1605 if (!nasm_stricmp(p, "p2align"))
1606 return 12;
1607 #endif
1608 return -1;
1611 static void report_error (int severity, char *fmt, ...)
1613 va_list ap;
1616 * See if it's a suppressed warning.
1618 if ((severity & ERR_MASK) == ERR_WARNING &&
1619 (severity & ERR_WARN_MASK) != 0 &&
1620 suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
1621 return; /* and bail out if so */
1624 * See if it's a pass-one only warning and we're not in pass one.
1626 if ((severity & ERR_PASS1) && pass0 == 2)
1627 return;
1629 if (severity & ERR_NOFILE)
1630 fputs ("nasm: ", error_file);
1631 else {
1632 char * currentfile = NULL;
1633 long lineno = 0;
1634 src_get (&lineno, &currentfile);
1635 fprintf (error_file, "%s:%ld: ", currentfile, lineno);
1636 nasm_free (currentfile);
1639 switch (severity & ERR_MASK) {
1640 case ERR_WARNING:
1641 fputs ("warning: ", error_file); break;
1642 case ERR_NONFATAL:
1643 fputs ("error: ", error_file); break;
1644 case ERR_FATAL:
1645 fputs ("fatal: ", error_file); break;
1646 case ERR_PANIC:
1647 fputs ("panic: ", error_file); break;
1648 case ERR_DEBUG:
1649 fputs("debug: ", error_file); break;
1652 va_start (ap, fmt);
1653 vfprintf (error_file, fmt, ap);
1654 fputc ('\n', error_file);
1656 if (severity & ERR_USAGE)
1657 want_usage = TRUE;
1659 switch (severity & ERR_MASK) {
1660 case ERR_WARNING: case ERR_DEBUG:
1661 /* no further action, by definition */
1662 break;
1663 case ERR_NONFATAL:
1664 /* terminate_after_phase = TRUE; *//**//* hack enables listing(!) on
1665 errors */
1666 terminate_after_phase = TRUE;
1667 break;
1668 case ERR_FATAL:
1669 if (ofile) {
1670 fclose(ofile);
1671 remove(outname);
1673 if (want_usage)
1674 usage();
1675 exit(1); /* instantly die */
1676 break; /* placate silly compilers */
1677 case ERR_PANIC:
1678 fflush(NULL);
1679 /* abort(); */ /* halt, catch fire, and dump core */
1680 exit(3);
1681 break;
1685 static void usage(void)
1687 fputs("type `nasm -h' for help\n", error_file);
1690 static void register_output_formats(void)
1692 ofmt = ofmt_register (report_error);
1695 #define BUF_DELTA 512
1697 static FILE *no_pp_fp;
1698 static efunc no_pp_err;
1699 static ListGen *no_pp_list;
1700 static long no_pp_lineinc;
1702 static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
1703 ListGen *listgen)
1705 src_set_fname(nasm_strdup(file));
1706 src_set_linnum(0);
1707 no_pp_lineinc = 1;
1708 no_pp_err = error;
1709 no_pp_fp = fopen(file, "r");
1710 if (!no_pp_fp)
1711 no_pp_err (ERR_FATAL | ERR_NOFILE,
1712 "unable to open input file `%s'", file);
1713 no_pp_list = listgen;
1714 (void) pass; /* placate compilers */
1715 (void) eval; /* placate compilers */
1718 static char *no_pp_getline (void)
1720 char *buffer, *p, *q;
1721 int bufsize;
1723 bufsize = BUF_DELTA;
1724 buffer = nasm_malloc(BUF_DELTA);
1725 src_set_linnum(src_get_linnum() + no_pp_lineinc);
1727 while (1) { /* Loop to handle %line */
1729 p = buffer;
1730 while (1) { /* Loop to handle long lines */
1731 q = fgets(p, bufsize-(p-buffer), no_pp_fp);
1732 if (!q)
1733 break;
1734 p += strlen(p);
1735 if (p > buffer && p[-1] == '\n')
1736 break;
1737 if (p-buffer > bufsize-10) {
1738 int offset;
1739 offset = p - buffer;
1740 bufsize += BUF_DELTA;
1741 buffer = nasm_realloc(buffer, bufsize);
1742 p = buffer + offset;
1746 if (!q && p == buffer) {
1747 nasm_free (buffer);
1748 return NULL;
1752 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1753 * them are present at the end of the line.
1755 buffer[strcspn(buffer, "\r\n\032")] = '\0';
1757 if (!strncmp(buffer, "%line", 5)) {
1758 long ln;
1759 int li;
1760 char *nm = nasm_malloc(strlen(buffer));
1761 if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) {
1762 nasm_free( src_set_fname(nm) );
1763 src_set_linnum(ln);
1764 no_pp_lineinc = li;
1765 continue;
1767 nasm_free(nm);
1769 break;
1772 no_pp_list->line (LIST_READ, buffer);
1774 return buffer;
1777 static void no_pp_cleanup (int pass)
1779 fclose(no_pp_fp);
1782 static unsigned long get_cpu (char *value)
1785 if (!strcmp(value, "8086")) return IF_8086;
1786 if (!strcmp(value, "186")) return IF_186;
1787 if (!strcmp(value, "286")) return IF_286;
1788 if (!strcmp(value, "386")) return IF_386;
1789 if (!strcmp(value, "486")) return IF_486;
1790 if (!strcmp(value, "586") ||
1791 !nasm_stricmp(value, "pentium") ) return IF_PENT;
1792 if (!strcmp(value, "686") ||
1793 !nasm_stricmp(value, "ppro") ||
1794 !nasm_stricmp(value, "p2") ) return IF_P6;
1795 if (!nasm_stricmp(value, "p3") ||
1796 !nasm_stricmp(value, "katmai") ) return IF_KATMAI;
1797 if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */
1798 !nasm_stricmp(value, "willamette") ) return IF_WILLAMETTE;
1800 report_error (pass0<2 ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type");
1802 return IF_PLEVEL; /* the maximum level */
1806 static int get_bits (char *value)
1808 int i;
1810 if ((i = atoi(value)) == 16) return i; /* set for a 16-bit segment */
1811 else if (i == 32) {
1812 if (cpu < IF_386) {
1813 report_error(ERR_NONFATAL,
1814 "cannot specify 32-bit segment on processor below a 386");
1815 i = 16;
1817 } else {
1818 report_error(pass0<2 ? ERR_NONFATAL : ERR_FATAL,
1819 "`%s' is not a valid segment size; must be 16 or 32",
1820 value);
1821 i = 16;
1823 return i;
1825 #ifdef CACHE_ALIGN
1826 static int get_alignv (char *value)
1828 int i,j;
1830 i = atoi(value);
1831 if (i<=0) j = 0;
1832 else if (i>=6) j = 64;
1833 else j = (1 << i);
1834 return j;
1837 void nop(void)
1841 static int isdirective(char * line)
1843 int ret;
1844 char * templine;
1845 char * tempvalue;
1846 templine=nasm_malloc(strlen(line)+1);
1847 strcpy(templine,line);
1848 ret=getkw(templine,&tempvalue);
1849 nasm_free(templine);
1850 return ret;
1854 #endif
1858 /* end of nasm.c */