Fix multipass inline warning (dis/en)abling
[platform/upstream/nasm.git] / nasm.c
1 /* The Netwide Assembler main program module
2  *
3  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4  * Julian Hall. All rights reserved. The software is
5  * redistributable under the license given in the file "LICENSE"
6  * distributed in the NASM archive.
7  */
8
9 #include "compiler.h"
10
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <time.h>
19
20 #include "nasm.h"
21 #include "nasmlib.h"
22 #include "saa.h"
23 #include "raa.h"
24 #include "float.h"
25 #include "stdscan.h"
26 #include "insns.h"
27 #include "preproc.h"
28 #include "parser.h"
29 #include "eval.h"
30 #include "assemble.h"
31 #include "labels.h"
32 #include "outform.h"
33 #include "listing.h"
34
35 struct forwrefinfo {            /* info held on forward refs. */
36     int lineno;
37     int operand;
38 };
39
40 static int get_bits(char *value);
41 static uint32_t get_cpu(char *cpu_str);
42 static void parse_cmdline(int, char **);
43 static void assemble_file(char *, StrList **);
44 static void register_output_formats(void);
45 static void report_error_gnu(int severity, const char *fmt, ...);
46 static void report_error_vc(int severity, const char *fmt, ...);
47 static void report_error_common(int severity, const char *fmt,
48                                 va_list args);
49 static bool is_suppressed_warning(int severity);
50 static void usage(void);
51 static efunc report_error;
52
53 static int using_debug_info, opt_verbose_info;
54 bool tasm_compatible_mode = false;
55 int pass0, passn;
56 int maxbits = 0;
57 int globalrel = 0;
58
59 time_t official_compile_time;
60
61 static char inname[FILENAME_MAX];
62 static char outname[FILENAME_MAX];
63 static char listname[FILENAME_MAX];
64 static char errname[FILENAME_MAX];
65 static int globallineno;        /* for forward-reference tracking */
66 /* static int pass = 0; */
67 static struct ofmt *ofmt = NULL;
68
69 static FILE *error_file;        /* Where to write error messages */
70
71 static FILE *ofile = NULL;
72 int optimizing = -1;            /* number of optimization passes to take */
73 static int sb, cmd_sb = 16;     /* by default */
74 static uint32_t cmd_cpu = IF_PLEVEL;       /* highest level by default */
75 static uint32_t cpu = IF_PLEVEL;   /* passed to insn_size & assemble.c */
76 bool global_offset_changed;      /* referenced in labels.c */
77
78 static struct location location;
79 int in_abs_seg;                 /* Flag we are in ABSOLUTE seg */
80 int32_t abs_seg;                   /* ABSOLUTE segment basis */
81 int32_t abs_offset;                /* ABSOLUTE offset */
82
83 static struct RAA *offsets;
84
85 static struct SAA *forwrefs;    /* keep track of forward references */
86 static const struct forwrefinfo *forwref;
87
88 static Preproc *preproc;
89 enum op_type {
90     op_normal,                  /* Preprocess and assemble */
91     op_preprocess,              /* Preprocess only */
92     op_depend,                  /* Generate dependencies */
93 };
94 static enum op_type operating_mode;
95 /* Dependency flags */
96 static bool depend_emit_phony = false;
97 static bool depend_missing_ok = false;
98 static const char *depend_target = NULL;
99 static const char *depend_file = NULL;
100
101 /*
102  * Which of the suppressible warnings are suppressed. Entry zero
103  * isn't an actual warning, but it used for -w+error/-Werror.
104  */
105 static bool suppressed[ERR_WARN_MAX+1];
106
107 static bool suppressed_global[ERR_WARN_MAX+1] = {
108     true, false, true, false, false, true, false, true, true, false
109 };
110 /*
111  * The option names for the suppressible warnings. As before, entry
112  * zero does nothing.
113  */
114 static const char *suppressed_names[ERR_WARN_MAX+1] = {
115     "error", "macro-params", "macro-selfref", "orphan-labels",
116     "number-overflow", "gnu-elf-extensions", "float-overflow",
117     "float-denorm", "float-underflow", "float-toolong"
118 };
119
120 /*
121  * The explanations for the suppressible warnings. As before, entry
122  * zero does nothing.
123  */
124 static const char *suppressed_what[ERR_WARN_MAX+1] = {
125     "treat warnings as errors",
126     "macro calls with wrong parameter count",
127     "cyclic macro references",
128     "labels alone on lines without trailing `:'",
129     "numeric constants does not fit in 64 bits",
130     "using 8- or 16-bit relocation in ELF32, a GNU extension",
131     "floating point overflow",
132     "floating point denormal",
133     "floating point underflow",
134     "too many digits in floating-point number"
135 };
136
137 /*
138  * This is a null preprocessor which just copies lines from input
139  * to output. It's used when someone explicitly requests that NASM
140  * not preprocess their source file.
141  */
142
143 static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *, StrList **);
144 static char *no_pp_getline(void);
145 static void no_pp_cleanup(int);
146 static Preproc no_pp = {
147     no_pp_reset,
148     no_pp_getline,
149     no_pp_cleanup
150 };
151
152 /*
153  * get/set current offset...
154  */
155 #define GET_CURR_OFFS (in_abs_seg?abs_offset:\
156                       raa_read(offsets,location.segment))
157 #define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
158                          (void)(offsets=raa_write(offsets,location.segment,(x))))
159
160 static int want_usage;
161 static int terminate_after_phase;
162 int user_nolist = 0;            /* fbk 9/2/00 */
163
164 static void nasm_fputs(const char *line, FILE * outfile)
165 {
166     if (outfile) {
167         fputs(line, outfile);
168         putc('\n', outfile);
169     } else
170         puts(line);
171 }
172
173 /* Convert a struct tm to a POSIX-style time constant */
174 static int64_t posix_mktime(struct tm *tm)
175 {
176     int64_t t;
177     int64_t y = tm->tm_year;
178
179     /* See IEEE 1003.1:2004, section 4.14 */
180
181     t = (y-70)*365 + (y-69)/4 - (y-1)/100 + (y+299)/400;
182     t += tm->tm_yday;
183     t *= 24;
184     t += tm->tm_hour;
185     t *= 60;
186     t += tm->tm_min;
187     t *= 60;
188     t += tm->tm_sec;
189
190     return t;
191 }
192
193 static void define_macros_early(void)
194 {
195     char temp[128];
196     struct tm lt, *lt_p, gm, *gm_p;
197     int64_t posix_time;
198
199     lt_p = localtime(&official_compile_time);
200     if (lt_p) {
201         lt = *lt_p;
202
203         strftime(temp, sizeof temp, "__DATE__=\"%Y-%m-%d\"", &lt);
204         pp_pre_define(temp);
205         strftime(temp, sizeof temp, "__DATE_NUM__=%Y%m%d", &lt);
206         pp_pre_define(temp);
207         strftime(temp, sizeof temp, "__TIME__=\"%H:%M:%S\"", &lt);
208         pp_pre_define(temp);
209         strftime(temp, sizeof temp, "__TIME_NUM__=%H%M%S", &lt);
210         pp_pre_define(temp);
211     }
212
213     gm_p = gmtime(&official_compile_time);
214     if (gm_p) {
215         gm = *gm_p;
216
217         strftime(temp, sizeof temp, "__UTC_DATE__=\"%Y-%m-%d\"", &gm);
218         pp_pre_define(temp);
219         strftime(temp, sizeof temp, "__UTC_DATE_NUM__=%Y%m%d", &gm);
220         pp_pre_define(temp);
221         strftime(temp, sizeof temp, "__UTC_TIME__=\"%H:%M:%S\"", &gm);
222         pp_pre_define(temp);
223         strftime(temp, sizeof temp, "__UTC_TIME_NUM__=%H%M%S", &gm);
224         pp_pre_define(temp);
225     }
226
227     if (gm_p)
228         posix_time = posix_mktime(&gm);
229     else if (lt_p)
230         posix_time = posix_mktime(&lt);
231     else
232         posix_time = 0;
233
234     if (posix_time) {
235         snprintf(temp, sizeof temp, "__POSIX_TIME__=%"PRId64, posix_time);
236         pp_pre_define(temp);
237     }
238 }
239
240 static void define_macros_late(void)
241 {
242     char temp[128];
243
244     snprintf(temp, sizeof(temp), "__OUTPUT_FORMAT__=%s\n",
245              ofmt->shortname);
246     pp_pre_define(temp);
247 }
248
249 static void emit_dependencies(StrList *list)
250 {
251     FILE *deps;
252     int linepos, len;
253     StrList *l, *nl;
254
255     if (depend_file && strcmp(depend_file, "-")) {
256         deps = fopen(depend_file, "w");
257         if (!deps) {
258             report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
259                          "unable to write dependency file `%s'", depend_file);
260             return;
261         }
262     } else {
263         deps = stdout;
264     }
265     
266     linepos = fprintf(deps, "%s:", depend_target);
267     for (l = list; l; l = l->next) {
268         len = strlen(l->str);
269         if (linepos + len > 62) {
270             fprintf(deps, " \\\n ");
271             linepos = 1;
272         }
273         fprintf(deps, " %s", l->str);
274         linepos += len+1;
275     }
276     fprintf(deps, "\n\n");
277     
278     for (l = list; l; l = nl) {
279         if (depend_emit_phony)
280             fprintf(deps, "%s:\n\n", l->str);
281             
282         nl = l->next;
283         nasm_free(l);
284     }
285
286     if (deps != stdout)
287         fclose(deps);
288 }
289
290 int main(int argc, char **argv)
291 {
292     StrList *depend_list = NULL, **depend_ptr;
293
294     time(&official_compile_time);
295
296     pass0 = 1;
297     want_usage = terminate_after_phase = false;
298     report_error = report_error_gnu;
299
300     error_file = stderr;
301
302     tolower_init();
303
304     nasm_set_malloc_error(report_error);
305     offsets = raa_init();
306     forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo));
307
308     preproc = &nasmpp;
309     operating_mode = op_normal;
310
311     seg_init();
312
313     register_output_formats();
314
315     /* Define some macros dependent on the runtime, but not
316        on the command line. */
317     define_macros_early();
318
319     parse_cmdline(argc, argv);
320
321     if (terminate_after_phase) {
322         if (want_usage)
323             usage();
324         return 1;
325     }
326
327     /* If debugging info is disabled, suppress any debug calls */
328     if (!using_debug_info)
329         ofmt->current_dfmt = &null_debug_form;
330
331     if (ofmt->stdmac)
332         pp_extra_stdmac(ofmt->stdmac);
333     parser_global_info(ofmt, &location);
334     eval_global_info(ofmt, lookup_label, &location);
335
336     /* define some macros dependent of command-line */
337     define_macros_late();
338
339     depend_ptr = (depend_file || (operating_mode == op_depend))
340         ? &depend_list : NULL;
341     if (!depend_target)
342         depend_target = outname;
343
344     switch (operating_mode) {
345     case op_depend:
346         {
347             char *line;
348
349             if (depend_missing_ok)
350                 pp_include_path(NULL);  /* "assume generated" */
351
352             preproc->reset(inname, 0, report_error, evaluate, &nasmlist,
353                            depend_ptr);
354             if (outname[0] == '\0')
355                 ofmt->filename(inname, outname, report_error);
356             ofile = NULL;
357             while ((line = preproc->getline()))
358                 nasm_free(line);
359             preproc->cleanup(0);
360         }
361         break;
362
363     case op_preprocess:
364         {
365             char *line;
366             char *file_name = NULL;
367             int32_t prior_linnum = 0;
368             int lineinc = 0;
369
370             if (*outname) {
371                 ofile = fopen(outname, "w");
372                 if (!ofile)
373                     report_error(ERR_FATAL | ERR_NOFILE,
374                                  "unable to open output file `%s'",
375                                  outname);
376             } else
377                 ofile = NULL;
378
379             location.known = false;
380
381             /* pass = 1; */
382             preproc->reset(inname, 2, report_error, evaluate, &nasmlist,
383                            depend_ptr);
384
385             while ((line = preproc->getline())) {
386                 /*
387                  * We generate %line directives if needed for later programs
388                  */
389                 int32_t linnum = prior_linnum += lineinc;
390                 int altline = src_get(&linnum, &file_name);
391                 if (altline) {
392                     if (altline == 1 && lineinc == 1)
393                         nasm_fputs("", ofile);
394                     else {
395                         lineinc = (altline != -1 || lineinc != 1);
396                         fprintf(ofile ? ofile : stdout,
397                                 "%%line %"PRId32"+%d %s\n", linnum, lineinc,
398                                 file_name);
399                     }
400                     prior_linnum = linnum;
401                 }
402                 nasm_fputs(line, ofile);
403                 nasm_free(line);
404             }
405             nasm_free(file_name);
406             preproc->cleanup(0);
407             if (ofile)
408                 fclose(ofile);
409             if (ofile && terminate_after_phase)
410                 remove(outname);
411         }
412         break;
413
414     case op_normal:
415         {
416             /*
417              * We must call ofmt->filename _anyway_, even if the user
418              * has specified their own output file, because some
419              * formats (eg OBJ and COFF) use ofmt->filename to find out
420              * the name of the input file and then put that inside the
421              * file.
422              */
423             ofmt->filename(inname, outname, report_error);
424
425             ofile = fopen(outname, "wb");
426             if (!ofile) {
427                 report_error(ERR_FATAL | ERR_NOFILE,
428                              "unable to open output file `%s'", outname);
429             }
430
431             /*
432              * We must call init_labels() before ofmt->init() since
433              * some object formats will want to define labels in their
434              * init routines. (eg OS/2 defines the FLAT group)
435              */
436             init_labels();
437
438             ofmt->init(ofile, report_error, define_label, evaluate);
439
440             assemble_file(inname, depend_ptr);
441
442             if (!terminate_after_phase) {
443                 ofmt->cleanup(using_debug_info);
444                 cleanup_labels();
445             } else {
446                 /*
447                  * Despite earlier comments, we need this fclose.
448                  * The object output drivers only fclose on cleanup,
449                  * and we just skipped that.
450                  */
451                 fclose (ofile);
452
453                 remove(outname);
454                 if (listname[0])
455                     remove(listname);
456             }
457         }
458         break;
459     }
460
461     if (depend_list)
462         emit_dependencies(depend_list);
463
464     if (want_usage)
465         usage();
466
467     raa_free(offsets);
468     saa_free(forwrefs);
469     eval_cleanup();
470     stdscan_cleanup();
471
472     if (terminate_after_phase)
473         return 1;
474     else
475         return 0;
476 }
477
478 /*
479  * Get a parameter for a command line option.
480  * First arg must be in the form of e.g. -f...
481  */
482 static char *get_param(char *p, char *q, bool *advance)
483 {
484     *advance = false;
485     if (p[2]) {                 /* the parameter's in the option */
486         p += 2;
487         while (nasm_isspace(*p))
488             p++;
489         return p;
490     }
491     if (q && q[0]) {
492         *advance = true;
493         return q;
494     }
495     report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
496                  "option `-%c' requires an argument", p[1]);
497     return NULL;
498 }
499
500 /*
501  * Copy a filename
502  */
503 static void copy_filename(char *dst, const char *src)
504 {
505     size_t len = strlen(src);
506
507     if (len >= (size_t)FILENAME_MAX) {
508         report_error(ERR_FATAL | ERR_NOFILE, "file name too long");
509         return;
510     }
511     strncpy(dst, src, FILENAME_MAX);
512 }
513
514 /*
515  * Convert a string to Make-safe form
516  */
517 static char *quote_for_make(const char *str)
518 {
519     const char *p;
520     char *os, *q;
521
522     size_t n = 1;               /* Terminating zero */
523     size_t nbs = 0;
524
525     if (!str)
526         return NULL;
527
528     for (p = str; *p; p++) {
529         switch (*p) {
530         case ' ':
531         case '\t':
532             /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
533             n += nbs + 2;
534             nbs = 0;
535             break;
536         case '$':
537         case '#':
538             nbs = 0;
539             n += 2;
540             break;
541         case '\\':
542             nbs++;
543             n++;
544             break;
545         default:
546             nbs = 0;
547             n++;
548         break;
549         }
550     }
551
552     /* Convert N backslashes at the end of filename to 2N backslashes */
553     if (nbs)
554         n += nbs;
555
556     os = q = nasm_malloc(n);
557
558     nbs = 0;
559     for (p = str; *p; p++) {
560         switch (*p) {
561         case ' ':
562         case '\t':
563             while (nbs--)
564                 *q++ = '\\';
565             *q++ = '\\';
566             *q++ = *p;
567             break;
568         case '$':
569             *q++ = *p;
570             *q++ = *p;
571             nbs = 0;
572             break;
573         case '#':
574             *q++ = '\\';
575             *q++ = *p;
576             nbs = 0;
577             break;
578         case '\\':
579             *q++ = *p;
580             nbs++;
581             break;
582         default:
583             *q++ = *p;
584             nbs = 0;
585         break;
586         }
587     }
588     while (nbs--)
589         *q++ = '\\';
590
591     *q = '\0';
592
593     return os;
594 }
595
596 struct textargs {
597     const char *label;
598     int value;
599 };
600
601 #define OPT_PREFIX 0
602 #define OPT_POSTFIX 1
603 struct textargs textopts[] = {
604     {"prefix", OPT_PREFIX},
605     {"postfix", OPT_POSTFIX},
606     {NULL, 0}
607 };
608
609 static bool stopoptions = false;
610 static bool process_arg(char *p, char *q)
611 {
612     char *param;
613     int i;
614     bool advance = false;
615     bool suppress;
616
617     if (!p || !p[0])
618         return false;
619
620     if (p[0] == '-' && !stopoptions) {
621         if (strchr("oOfpPdDiIlFXuUZwW", p[1])) {
622             /* These parameters take values */
623             if (!(param = get_param(p, q, &advance)))
624                 return advance;
625         }
626
627         switch (p[1]) {
628         case 's':
629             error_file = stdout;
630             break;
631
632         case 'o':               /* output file */
633             copy_filename(outname, param);
634             break;
635
636         case 'f':               /* output format */
637             ofmt = ofmt_find(param);
638             if (!ofmt) {
639                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
640                              "unrecognised output format `%s' - "
641                              "use -hf for a list", param);
642             } else {
643                 ofmt->current_dfmt = ofmt->debug_formats[0];
644             }
645             break;
646
647         case 'O':               /* Optimization level */
648         {
649             int opt;
650
651             if (!*param) {
652                 /* Naked -O == -Ox */
653                 optimizing = INT_MAX >> 1; /* Almost unlimited */
654             } else {
655                 while (*param) {
656                     switch (*param) {
657                     case '0': case '1': case '2': case '3': case '4':
658                     case '5': case '6': case '7': case '8': case '9':
659                         opt = strtoul(param, &param, 10);
660
661                         /* -O0 -> optimizing == -1, 0.98 behaviour */
662                         /* -O1 -> optimizing == 0, 0.98.09 behaviour */
663                         if (opt < 2)
664                             optimizing = opt - 1;
665                         else
666                             optimizing = opt;
667                         break;
668
669                     case 'v':
670                     case '+':
671                         param++;
672                         opt_verbose_info = true;
673                         break;
674
675                     case 'x':
676                         param++;
677                         optimizing = INT_MAX >> 1; /* Almost unlimited */
678                         break;
679
680                     default:
681                         report_error(ERR_FATAL,
682                                      "unknown optimization option -O%c\n",
683                                      *param);
684                         break;
685                     }
686                 }
687             }
688             break;
689         }
690
691         case 'p':                       /* pre-include */
692         case 'P':
693             pp_pre_include(param);
694             break;
695
696         case 'd':                       /* pre-define */
697         case 'D':
698             pp_pre_define(param);
699             break;
700
701         case 'u':                       /* un-define */
702         case 'U':
703             pp_pre_undefine(param);
704             break;
705
706         case 'i':                       /* include search path */
707         case 'I':
708             pp_include_path(param);
709             break;
710
711         case 'l':                       /* listing file */
712             copy_filename(listname, param);
713             break;
714
715         case 'Z':                       /* error messages file */
716             strcpy(errname, param);
717             break;
718
719         case 'F':                       /* specify debug format */
720             ofmt->current_dfmt = dfmt_find(ofmt, param);
721             if (!ofmt->current_dfmt) {
722                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
723                              "unrecognized debug format `%s' for"
724                              " output format `%s'",
725                              param, ofmt->shortname);
726             }
727             using_debug_info = true;
728             break;
729
730         case 'X':               /* specify error reporting format */
731             if (nasm_stricmp("vc", param) == 0)
732                 report_error = report_error_vc;
733             else if (nasm_stricmp("gnu", param) == 0)
734                 report_error = report_error_gnu;
735             else
736                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
737                              "unrecognized error reporting format `%s'",
738                              param);
739             break;
740
741         case 'g':
742             using_debug_info = true;
743             break;
744
745         case 'h':
746             printf
747                 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
748                  "[-l listfile]\n"
749                  "            [options...] [--] filename\n"
750                  "    or nasm -v   for version info\n\n"
751                  "    -t          assemble in SciTech TASM compatible mode\n"
752                  "    -g          generate debug information in selected format.\n");
753             printf
754                 ("    -E (or -e)  preprocess only (writes output to stdout by default)\n"
755                  "    -a          don't preprocess (assemble only)\n"
756                  "    -M          generate Makefile dependencies on stdout\n"
757                  "    -MG         d:o, missing files assumed generated\n\n"
758                  "    -Z<file>    redirect error messages to file\n"
759                  "    -s          redirect error messages to stdout\n\n"
760                  "    -F format   select a debugging format\n\n"
761                  "    -I<path>    adds a pathname to the include file path\n");
762             printf
763                 ("    -O<digit>   optimize branch offsets (-O0 disables, default)\n"
764                  "    -P<file>    pre-includes a file\n"
765                  "    -D<macro>[=<value>] pre-defines a macro\n"
766                  "    -U<macro>   undefines a macro\n"
767                  "    -X<format>  specifies error reporting format (gnu or vc)\n"
768                  "    -w+foo      enables warning foo (equiv. -Wfoo)\n"
769                  "    -w-foo      disable warning foo (equiv. -Wno-foo)\n"
770                  "Warnings:\n");
771             for (i = 0; i <= ERR_WARN_MAX; i++)
772                 printf("    %-23s %s (default %s)\n",
773                        suppressed_names[i], suppressed_what[i],
774                        suppressed_global[i] ? "off" : "on");
775             printf
776                 ("\nresponse files should contain command line parameters"
777                  ", one per line.\n");
778             if (p[2] == 'f') {
779                 printf("\nvalid output formats for -f are"
780                        " (`*' denotes default):\n");
781                 ofmt_list(ofmt, stdout);
782             } else {
783                 printf("\nFor a list of valid output formats, use -hf.\n");
784                 printf("For a list of debug formats, use -f <form> -y.\n");
785             }
786             exit(0);            /* never need usage message here */
787             break;
788
789         case 'y':
790             printf("\nvalid debug formats for '%s' output format are"
791                    " ('*' denotes default):\n", ofmt->shortname);
792             dfmt_list(ofmt, stdout);
793             exit(0);
794             break;
795
796         case 't':
797             tasm_compatible_mode = true;
798             break;
799
800         case 'v':
801             {
802                 const char *nasm_version_string =
803                     "NASM version " NASM_VER " compiled on " __DATE__
804 #ifdef DEBUG
805                     " with -DDEBUG"
806 #endif
807                     ;
808                 puts(nasm_version_string);
809                 exit(0);        /* never need usage message here */
810             }
811             break;
812
813         case 'e':              /* preprocess only */
814         case 'E':
815             operating_mode = op_preprocess;
816             break;
817
818         case 'a':              /* assemble only - don't preprocess */
819             preproc = &no_pp;
820             break;
821
822         case 'W':
823             if (param[0] == 'n' && param[1] == 'o' && param[2] == '-') {
824                 suppress = true;
825                 param += 3;
826             } else {
827                 suppress = false;
828             }
829             goto set_warning;
830
831         case 'w':
832             if (param[0] != '+' && param[0] != '-') {
833                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
834                              "invalid option to `-w'");
835                 break;
836             }
837             suppress = (param[0] == '-');
838             param++;
839             goto set_warning;
840         set_warning:
841             for (i = 0; i <= ERR_WARN_MAX; i++)
842                 if (!nasm_stricmp(param, suppressed_names[i]))
843                     break;
844             if (i <= ERR_WARN_MAX)
845                 suppressed_global[i] = suppress;
846             else if (!nasm_stricmp(param, "all"))
847                 for (i = 1; i <= ERR_WARN_MAX; i++)
848                     suppressed_global[i] = suppress;
849             else if (!nasm_stricmp(param, "none"))
850                 for (i = 1; i <= ERR_WARN_MAX; i++)
851                     suppressed_global[i] = !suppress;
852             else
853                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
854                              "invalid warning `%s'", param);
855             break;
856
857         case 'M':
858             switch (p[2]) {
859             case 0:
860                 operating_mode = op_depend;
861                 break;
862             case 'G':
863                 operating_mode = op_depend;
864                 depend_missing_ok = true;
865                 break;
866             case 'P':
867                 depend_emit_phony = true;
868                 break;
869             case 'D':
870                 depend_file = q;
871                 advance = true;
872                 break;
873             case 'T':
874                 depend_target = q;
875                 advance = true;
876                 break;
877             case 'Q':
878                 depend_target = quote_for_make(q);
879                 advance = true;
880                 break;
881             default:
882                 report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
883                              "unknown dependency option `-M%c'", p[2]);
884                 break;
885             }
886             if (advance && (!q || !q[0])) {
887                 report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
888                              "option `-M%c' requires a parameter", p[2]);
889                 break;
890             }
891             break;
892
893         case '-':
894             {
895                 int s;
896
897                 if (p[2] == 0) {        /* -- => stop processing options */
898                     stopoptions = 1;
899                     break;
900                 }
901                 for (s = 0; textopts[s].label; s++) {
902                     if (!nasm_stricmp(p + 2, textopts[s].label)) {
903                         break;
904                     }
905                 }
906
907                 switch (s) {
908
909                 case OPT_PREFIX:
910                 case OPT_POSTFIX:
911                     {
912                         if (!q) {
913                             report_error(ERR_NONFATAL | ERR_NOFILE |
914                                          ERR_USAGE,
915                                          "option `--%s' requires an argument",
916                                          p + 2);
917                             break;
918                         } else {
919                             advance = 1, param = q;
920                         }
921
922                         if (s == OPT_PREFIX) {
923                             strncpy(lprefix, param, PREFIX_MAX - 1);
924                             lprefix[PREFIX_MAX - 1] = 0;
925                             break;
926                         }
927                         if (s == OPT_POSTFIX) {
928                             strncpy(lpostfix, param, POSTFIX_MAX - 1);
929                             lpostfix[POSTFIX_MAX - 1] = 0;
930                             break;
931                         }
932                         break;
933                     }
934                 default:
935                     {
936                         report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
937                                      "unrecognised option `--%s'", p + 2);
938                         break;
939                     }
940                 }
941                 break;
942             }
943
944         default:
945             if (!ofmt->setinfo(GI_SWITCH, &p))
946                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
947                              "unrecognised option `-%c'", p[1]);
948             break;
949         }
950     } else {
951         if (*inname) {
952             report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
953                          "more than one input file specified");
954         } else {
955             copy_filename(inname, p);
956         }
957     }
958
959     return advance;
960 }
961
962 #define ARG_BUF_DELTA 128
963
964 static void process_respfile(FILE * rfile)
965 {
966     char *buffer, *p, *q, *prevarg;
967     int bufsize, prevargsize;
968
969     bufsize = prevargsize = ARG_BUF_DELTA;
970     buffer = nasm_malloc(ARG_BUF_DELTA);
971     prevarg = nasm_malloc(ARG_BUF_DELTA);
972     prevarg[0] = '\0';
973
974     while (1) {                 /* Loop to handle all lines in file */
975         p = buffer;
976         while (1) {             /* Loop to handle long lines */
977             q = fgets(p, bufsize - (p - buffer), rfile);
978             if (!q)
979                 break;
980             p += strlen(p);
981             if (p > buffer && p[-1] == '\n')
982                 break;
983             if (p - buffer > bufsize - 10) {
984                 int offset;
985                 offset = p - buffer;
986                 bufsize += ARG_BUF_DELTA;
987                 buffer = nasm_realloc(buffer, bufsize);
988                 p = buffer + offset;
989             }
990         }
991
992         if (!q && p == buffer) {
993             if (prevarg[0])
994                 process_arg(prevarg, NULL);
995             nasm_free(buffer);
996             nasm_free(prevarg);
997             return;
998         }
999
1000         /*
1001          * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1002          * them are present at the end of the line.
1003          */
1004         *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
1005
1006         while (p > buffer && nasm_isspace(p[-1]))
1007             *--p = '\0';
1008
1009         p = buffer;
1010         while (nasm_isspace(*p))
1011             p++;
1012
1013         if (process_arg(prevarg, p))
1014             *p = '\0';
1015
1016         if ((int) strlen(p) > prevargsize - 10) {
1017             prevargsize += ARG_BUF_DELTA;
1018             prevarg = nasm_realloc(prevarg, prevargsize);
1019         }
1020         strncpy(prevarg, p, prevargsize);
1021     }
1022 }
1023
1024 /* Function to process args from a string of args, rather than the
1025  * argv array. Used by the environment variable and response file
1026  * processing.
1027  */
1028 static void process_args(char *args)
1029 {
1030     char *p, *q, *arg, *prevarg;
1031     char separator = ' ';
1032
1033     p = args;
1034     if (*p && *p != '-')
1035         separator = *p++;
1036     arg = NULL;
1037     while (*p) {
1038         q = p;
1039         while (*p && *p != separator)
1040             p++;
1041         while (*p == separator)
1042             *p++ = '\0';
1043         prevarg = arg;
1044         arg = q;
1045         if (process_arg(prevarg, arg))
1046             arg = NULL;
1047     }
1048     if (arg)
1049         process_arg(arg, NULL);
1050 }
1051
1052 static void process_response_file(const char *file)
1053 {
1054     char str[2048];
1055     FILE *f = fopen(file, "r");
1056     if (!f) {
1057         perror(file);
1058         exit(-1);
1059     }
1060     while (fgets(str, sizeof str, f)) {
1061         process_args(str);
1062     }
1063     fclose(f);
1064 }
1065
1066 static void parse_cmdline(int argc, char **argv)
1067 {
1068     FILE *rfile;
1069     char *envreal, *envcopy = NULL, *p, *arg;
1070
1071     *inname = *outname = *listname = *errname = '\0';
1072
1073     /*
1074      * First, process the NASMENV environment variable.
1075      */
1076     envreal = getenv("NASMENV");
1077     arg = NULL;
1078     if (envreal) {
1079         envcopy = nasm_strdup(envreal);
1080         process_args(envcopy);
1081         nasm_free(envcopy);
1082     }
1083
1084     /*
1085      * Now process the actual command line.
1086      */
1087     while (--argc) {
1088         bool advance;
1089         argv++;
1090         if (argv[0][0] == '@') {
1091             /* We have a response file, so process this as a set of
1092              * arguments like the environment variable. This allows us
1093              * to have multiple arguments on a single line, which is
1094              * different to the -@resp file processing below for regular
1095              * NASM.
1096              */
1097             process_response_file(argv[0]+1);
1098             argc--;
1099             argv++;
1100         }
1101         if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
1102             p = get_param(argv[0], argc > 1 ? argv[1] : NULL, &advance);
1103             if (p) {
1104                 rfile = fopen(p, "r");
1105                 if (rfile) {
1106                     process_respfile(rfile);
1107                     fclose(rfile);
1108                 } else
1109                     report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1110                                  "unable to open response file `%s'", p);
1111             }
1112         } else
1113             advance = process_arg(argv[0], argc > 1 ? argv[1] : NULL);
1114         argv += advance, argc -= advance;
1115     }
1116
1117     /* Look for basic command line typos.  This definitely doesn't
1118        catch all errors, but it might help cases of fumbled fingers. */
1119     if (!*inname)
1120         report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1121                      "no input file specified");
1122     else if (!strcmp(inname, errname) ||
1123              !strcmp(inname, outname) ||
1124              !strcmp(inname, listname) ||
1125              (depend_file && !strcmp(inname, depend_file)))
1126         report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
1127                      "file `%s' is both input and output file",
1128                      inname);
1129
1130     if (*errname) {
1131         error_file = fopen(errname, "w");
1132         if (!error_file) {
1133             error_file = stderr;        /* Revert to default! */
1134             report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
1135                          "cannot open file `%s' for error messages",
1136                          errname);
1137         }
1138     }
1139 }
1140
1141 /* List of directives */
1142 enum directives {
1143     D_NONE, D_ABSOLUTE, D_BITS, D_COMMON, D_CPU, D_DEBUG, D_DEFAULT,
1144     D_EXTERN, D_FLOAT, D_GLOBAL, D_LIST, D_SECTION, D_SEGMENT, D_WARNING
1145 };
1146 static const char *directives[] = {
1147     "", "absolute", "bits", "common", "cpu", "debug", "default",
1148     "extern", "float", "global", "list", "section", "segment", "warning"
1149 };
1150 static enum directives getkw(char **directive, char **value);
1151
1152 static void assemble_file(char *fname, StrList **depend_ptr)
1153 {
1154     char *directive, *value, *p, *q, *special, *line, debugid[80];
1155     insn output_ins;
1156     int i, validid;
1157     bool rn_error;
1158     int32_t seg;
1159     int64_t offs;
1160     struct tokenval tokval;
1161     expr *e;
1162     int pass_max;
1163
1164     if (cmd_sb == 32 && cmd_cpu < IF_386)
1165         report_error(ERR_FATAL, "command line: "
1166                      "32-bit segment size requires a higher cpu");
1167
1168     pass_max = (optimizing > 0 ? optimizing : 0) + 2;   /* passes 1, optimizing, then 2 */
1169     pass0 = !(optimizing > 0);  /* start at 1 if not optimizing */
1170     for (passn = 1; pass0 <= 2; passn++) {
1171         int pass1, pass2;
1172         ldfunc def_label;
1173
1174         pass1 = pass0 == 2 ? 2 : 1;     /* 1, 1, 1, ..., 1, 2 */
1175         pass2 = passn > 1  ? 2 : 1;     /* 1, 2, 2, ..., 2, 2 */
1176         /* pass0                           0, 0, 0, ..., 1, 2 */
1177
1178         def_label = passn > 1 ? redefine_label : define_label;
1179
1180         globalbits = sb = cmd_sb;   /* set 'bits' to command line default */
1181         cpu = cmd_cpu;
1182         if (pass0 == 2) {
1183             if (*listname)
1184                 nasmlist.init(listname, report_error);
1185         }
1186         in_abs_seg = false;
1187         global_offset_changed = false;  /* set by redefine_label */
1188         location.segment = ofmt->section(NULL, pass2, &sb);
1189         globalbits = sb;
1190         if (passn > 1) {
1191             saa_rewind(forwrefs);
1192             forwref = saa_rstruct(forwrefs);
1193             raa_free(offsets);
1194             offsets = raa_init();
1195         }
1196         preproc->reset(fname, pass1, report_error, evaluate, &nasmlist,
1197                        pass1 == 2 ? depend_ptr : NULL);
1198         memcpy(suppressed, suppressed_global, (ERR_WARN_MAX+1) * sizeof(bool));
1199
1200         globallineno = 0;
1201         if (passn == 1)
1202             location.known = true;
1203         location.offset = offs = GET_CURR_OFFS;
1204
1205         while ((line = preproc->getline())) {
1206             enum directives d;
1207             globallineno++;
1208
1209             /* here we parse our directives; this is not handled by the 'real'
1210              * parser. */
1211             directive = line;
1212             d = getkw(&directive, &value);
1213             if (d) {
1214                 int err = 0;
1215
1216                 switch (d) {
1217                 case D_SEGMENT:         /* [SEGMENT n] */
1218                 case D_SECTION:
1219                     seg = ofmt->section(value, pass2, &sb);
1220                     if (seg == NO_SEG) {
1221                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
1222                                      "segment name `%s' not recognized",
1223                                      value);
1224                     } else {
1225                         in_abs_seg = false;
1226                         location.segment = seg;
1227                     }
1228                     break;
1229                 case D_EXTERN:          /* [EXTERN label:special] */
1230                     if (*value == '$')
1231                         value++;        /* skip initial $ if present */
1232                     if (pass0 == 2) {
1233                         q = value;
1234                         while (*q && *q != ':')
1235                             q++;
1236                         if (*q == ':') {
1237                             *q++ = '\0';
1238                             ofmt->symdef(value, 0L, 0L, 3, q);
1239                         }
1240                     } else if (passn == 1) {
1241                         q = value;
1242                         validid = true;
1243                         if (!isidstart(*q))
1244                             validid = false;
1245                         while (*q && *q != ':') {
1246                             if (!isidchar(*q))
1247                                 validid = false;
1248                             q++;
1249                         }
1250                         if (!validid) {
1251                             report_error(ERR_NONFATAL,
1252                                          "identifier expected after EXTERN");
1253                             break;
1254                         }
1255                         if (*q == ':') {
1256                             *q++ = '\0';
1257                             special = q;
1258                         } else
1259                             special = NULL;
1260                         if (!is_extern(value)) {        /* allow re-EXTERN to be ignored */
1261                             int temp = pass0;
1262                             pass0 = 1;  /* fake pass 1 in labels.c */
1263                             declare_as_global(value, special,
1264                                               report_error);
1265                             define_label(value, seg_alloc(), 0L, NULL,
1266                                          false, true, ofmt, report_error);
1267                             pass0 = temp;
1268                         }
1269                     }           /* else  pass0 == 1 */
1270                     break;
1271                 case D_BITS:            /* [BITS bits] */
1272                     globalbits = sb = get_bits(value);
1273                     break;
1274                 case D_GLOBAL:          /* [GLOBAL symbol:special] */
1275                     if (*value == '$')
1276                         value++;        /* skip initial $ if present */
1277                     if (pass0 == 2) {   /* pass 2 */
1278                         q = value;
1279                         while (*q && *q != ':')
1280                             q++;
1281                         if (*q == ':') {
1282                             *q++ = '\0';
1283                             ofmt->symdef(value, 0L, 0L, 3, q);
1284                         }
1285                     } else if (pass2 == 1) {    /* pass == 1 */
1286                         q = value;
1287                         validid = true;
1288                         if (!isidstart(*q))
1289                             validid = false;
1290                         while (*q && *q != ':') {
1291                             if (!isidchar(*q))
1292                                 validid = false;
1293                             q++;
1294                         }
1295                         if (!validid) {
1296                             report_error(ERR_NONFATAL,
1297                                          "identifier expected after GLOBAL");
1298                             break;
1299                         }
1300                         if (*q == ':') {
1301                             *q++ = '\0';
1302                             special = q;
1303                         } else
1304                             special = NULL;
1305                         declare_as_global(value, special, report_error);
1306                     }           /* pass == 1 */
1307                     break;
1308                 case D_COMMON:          /* [COMMON symbol size:special] */
1309                     if (*value == '$')
1310                         value++;        /* skip initial $ if present */
1311                     if (pass0 == 1) {
1312                         p = value;
1313                         validid = true;
1314                         if (!isidstart(*p))
1315                             validid = false;
1316                         while (*p && !nasm_isspace(*p)) {
1317                             if (!isidchar(*p))
1318                                 validid = false;
1319                             p++;
1320                         }
1321                         if (!validid) {
1322                             report_error(ERR_NONFATAL,
1323                                          "identifier expected after COMMON");
1324                             break;
1325                         }
1326                         if (*p) {
1327                             int64_t size;
1328
1329                             while (*p && nasm_isspace(*p))
1330                                 *p++ = '\0';
1331                             q = p;
1332                             while (*q && *q != ':')
1333                                 q++;
1334                             if (*q == ':') {
1335                                 *q++ = '\0';
1336                                 special = q;
1337                             } else
1338                                 special = NULL;
1339                             size = readnum(p, &rn_error);
1340                             if (rn_error)
1341                                 report_error(ERR_NONFATAL,
1342                                              "invalid size specified"
1343                                              " in COMMON declaration");
1344                             else
1345                                 define_common(value, seg_alloc(), size,
1346                                               special, ofmt, report_error);
1347                         } else
1348                             report_error(ERR_NONFATAL,
1349                                          "no size specified in"
1350                                          " COMMON declaration");
1351                     } else if (pass0 == 2) {    /* pass == 2 */
1352                         q = value;
1353                         while (*q && *q != ':') {
1354                             if (nasm_isspace(*q))
1355                                 *q = '\0';
1356                             q++;
1357                         }
1358                         if (*q == ':') {
1359                             *q++ = '\0';
1360                             ofmt->symdef(value, 0L, 0L, 3, q);
1361                         }
1362                     }
1363                     break;
1364                 case D_ABSOLUTE:                /* [ABSOLUTE address] */
1365                     stdscan_reset();
1366                     stdscan_bufptr = value;
1367                     tokval.t_type = TOKEN_INVALID;
1368                     e = evaluate(stdscan, NULL, &tokval, NULL, pass2,
1369                                  report_error, NULL);
1370                     if (e) {
1371                         if (!is_reloc(e))
1372                             report_error(pass0 ==
1373                                          1 ? ERR_NONFATAL : ERR_PANIC,
1374                                          "cannot use non-relocatable expression as "
1375                                          "ABSOLUTE address");
1376                         else {
1377                             abs_seg = reloc_seg(e);
1378                             abs_offset = reloc_value(e);
1379                         }
1380                     } else if (passn == 1)
1381                         abs_offset = 0x100;     /* don't go near zero in case of / */
1382                     else
1383                         report_error(ERR_PANIC, "invalid ABSOLUTE address "
1384                                      "in pass two");
1385                     in_abs_seg = true;
1386                     location.segment = NO_SEG;
1387                     break;
1388                 case D_DEBUG:           /* [DEBUG] */
1389                     p = value;
1390                     q = debugid;
1391                     validid = true;
1392                     if (!isidstart(*p))
1393                         validid = false;
1394                     while (*p && !nasm_isspace(*p)) {
1395                         if (!isidchar(*p))
1396                             validid = false;
1397                         *q++ = *p++;
1398                     }
1399                     *q++ = 0;
1400                     if (!validid) {
1401                         report_error(passn == 1 ? ERR_NONFATAL : ERR_PANIC,
1402                                      "identifier expected after DEBUG");
1403                         break;
1404                     }
1405                     while (*p && nasm_isspace(*p))
1406                         p++;
1407                     if (pass0 == 2)
1408                         ofmt->current_dfmt->debug_directive(debugid, p);
1409                     break;
1410                 case D_WARNING:         /* [WARNING {+|-|*}warn-name] */
1411                     if (pass1 == 1) {
1412                         while (*value && nasm_isspace(*value))
1413                             value++;
1414
1415                         switch(*value) {
1416                             case '-': validid = 0; value++; break;
1417                             case '+': validid = 1; value++; break;
1418                             case '*': validid = 2; value++; break;
1419                             default: /*
1420                                        * Should this error out?
1421                                        * I'll keep it so nothing breaks.
1422                                        */
1423                                       validid = 1; break;
1424                         }
1425
1426                         for (i = 1; i <= ERR_WARN_MAX; i++)
1427                             if (!nasm_stricmp(value, suppressed_names[i]))
1428                                 break;
1429                         if (i <= ERR_WARN_MAX) {
1430                             switch(validid) {
1431                                 case 0: suppressed[i] = true; break;
1432                                 case 1: suppressed[i] = false; break;
1433                                 case 2: suppressed[i] = suppressed_global[i];
1434                                         break;
1435                             }
1436                         }
1437                         else
1438                             report_error(ERR_NONFATAL,
1439                                          "invalid warning id in WARNING directive");
1440                     }
1441                     break;
1442                 case D_CPU:             /* [CPU] */
1443                     cpu = get_cpu(value);
1444                     break;
1445                 case D_LIST:            /* [LIST {+|-}] */
1446                     while (*value && nasm_isspace(*value))
1447                         value++;
1448
1449                     if (*value == '+') {
1450                         user_nolist = 0;
1451                     } else {
1452                         if (*value == '-') {
1453                             user_nolist = 1;
1454                         } else {
1455                             err = 1;
1456                         }
1457                     }
1458                     break;
1459                 case D_DEFAULT:         /* [DEFAULT] */
1460                     stdscan_reset();
1461                     stdscan_bufptr = value;
1462                     tokval.t_type = TOKEN_INVALID;
1463                     if (stdscan(NULL, &tokval) == TOKEN_SPECIAL) {
1464                         switch ((int)tokval.t_integer) {
1465                         case S_REL:
1466                             globalrel = 1;
1467                             break;
1468                         case S_ABS:
1469                             globalrel = 0;
1470                             break;
1471                         default:
1472                             err = 1;
1473                             break;
1474                         }
1475                     } else {
1476                         err = 1;
1477                     }
1478                     break;
1479                 case D_FLOAT:
1480                     if (float_option(value)) {
1481                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
1482                                      "unknown 'float' directive: %s",
1483                                      value);
1484                     }
1485                     break;
1486                 default:
1487                     if (!ofmt->directive(directive, value, pass2))
1488                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
1489                                      "unrecognised directive [%s]",
1490                                      directive);
1491                 }
1492                 if (err) {
1493                     report_error(ERR_NONFATAL,
1494                                  "invalid parameter to [%s] directive",
1495                                  directive);
1496                 }
1497             } else {            /* it isn't a directive */
1498
1499                 parse_line(pass1, line, &output_ins,
1500                            report_error, evaluate, def_label);
1501
1502                 if (!(optimizing > 0) && pass0 == 2) {
1503                     if (forwref != NULL && globallineno == forwref->lineno) {
1504                         output_ins.forw_ref = true;
1505                         do {
1506                             output_ins.oprs[forwref->operand].opflags |=
1507                                 OPFLAG_FORWARD;
1508                             forwref = saa_rstruct(forwrefs);
1509                         } while (forwref != NULL
1510                                  && forwref->lineno == globallineno);
1511                     } else
1512                         output_ins.forw_ref = false;
1513                 }
1514
1515                 if (!(optimizing > 0) && output_ins.forw_ref) {
1516                     if (passn == 1) {
1517                         for (i = 0; i < output_ins.operands; i++) {
1518                             if (output_ins.oprs[i].
1519                                 opflags & OPFLAG_FORWARD) {
1520                                 struct forwrefinfo *fwinf =
1521                                     (struct forwrefinfo *)
1522                                     saa_wstruct(forwrefs);
1523                                 fwinf->lineno = globallineno;
1524                                 fwinf->operand = i;
1525                             }
1526                         }
1527                     } else {    /* passn > 1 */
1528                         /*
1529                          * Hack to prevent phase error in the code
1530                          *   rol ax,x
1531                          *   x equ 1
1532                          *
1533                          * If the second operand is a forward reference,
1534                          * the UNITY property of the number 1 in that
1535                          * operand is cancelled. Otherwise the above
1536                          * sequence will cause a phase error.
1537                          *
1538                          * This hack means that the above code will
1539                          * generate 286+ code.
1540                          *
1541                          * The forward reference will mean that the
1542                          * operand will not have the UNITY property on
1543                          * the first pass, so the pass behaviours will
1544                          * be consistent.
1545                          */
1546
1547                         if (output_ins.operands >= 2 &&
1548                             (output_ins.oprs[1].opflags & OPFLAG_FORWARD) &&
1549                             !(IMMEDIATE & ~output_ins.oprs[1].type))
1550                         {
1551                             /* Remove special properties bits */
1552                             output_ins.oprs[1].type &= ~REG_SMASK;
1553                         }
1554
1555                     }
1556
1557                 }
1558
1559                 /*  forw_ref */
1560                 if (output_ins.opcode == I_EQU) {
1561                     if (pass1 == 1) {
1562                         /*
1563                          * Special `..' EQUs get processed in pass two,
1564                          * except `..@' macro-processor EQUs which are done
1565                          * in the normal place.
1566                          */
1567                         if (!output_ins.label)
1568                             report_error(ERR_NONFATAL,
1569                                          "EQU not preceded by label");
1570
1571                         else if (output_ins.label[0] != '.' ||
1572                                  output_ins.label[1] != '.' ||
1573                                  output_ins.label[2] == '@') {
1574                             if (output_ins.operands == 1 &&
1575                                 (output_ins.oprs[0].type & IMMEDIATE) &&
1576                                 output_ins.oprs[0].wrt == NO_SEG) {
1577                                 int isext =
1578                                     output_ins.oprs[0].
1579                                     opflags & OPFLAG_EXTERN;
1580                                 def_label(output_ins.label,
1581                                           output_ins.oprs[0].segment,
1582                                           output_ins.oprs[0].offset, NULL,
1583                                           false, isext, ofmt,
1584                                           report_error);
1585                             } else if (output_ins.operands == 2
1586                                        && (output_ins.oprs[0].
1587                                            type & IMMEDIATE)
1588                                        && (output_ins.oprs[0].type & COLON)
1589                                        && output_ins.oprs[0].segment ==
1590                                        NO_SEG
1591                                        && output_ins.oprs[0].wrt == NO_SEG
1592                                        && (output_ins.oprs[1].
1593                                            type & IMMEDIATE)
1594                                        && output_ins.oprs[1].segment ==
1595                                        NO_SEG
1596                                        && output_ins.oprs[1].wrt ==
1597                                        NO_SEG) {
1598                                 def_label(output_ins.label,
1599                                           output_ins.oprs[0].
1600                                           offset | SEG_ABS,
1601                                           output_ins.oprs[1].offset, NULL,
1602                                           false, false, ofmt,
1603                                           report_error);
1604                             } else
1605                                 report_error(ERR_NONFATAL,
1606                                              "bad syntax for EQU");
1607                         }
1608                     } else {
1609                         /*
1610                          * Special `..' EQUs get processed here, except
1611                          * `..@' macro processor EQUs which are done above.
1612                          */
1613                         if (output_ins.label[0] == '.' &&
1614                             output_ins.label[1] == '.' &&
1615                             output_ins.label[2] != '@') {
1616                             if (output_ins.operands == 1 &&
1617                                 (output_ins.oprs[0].type & IMMEDIATE)) {
1618                                 define_label(output_ins.label,
1619                                              output_ins.oprs[0].segment,
1620                                              output_ins.oprs[0].offset,
1621                                              NULL, false, false, ofmt,
1622                                              report_error);
1623                             } else if (output_ins.operands == 2
1624                                        && (output_ins.oprs[0].
1625                                            type & IMMEDIATE)
1626                                        && (output_ins.oprs[0].type & COLON)
1627                                        && output_ins.oprs[0].segment ==
1628                                        NO_SEG
1629                                        && (output_ins.oprs[1].
1630                                            type & IMMEDIATE)
1631                                        && output_ins.oprs[1].segment ==
1632                                        NO_SEG) {
1633                                 define_label(output_ins.label,
1634                                              output_ins.oprs[0].
1635                                              offset | SEG_ABS,
1636                                              output_ins.oprs[1].offset,
1637                                              NULL, false, false, ofmt,
1638                                              report_error);
1639                             } else
1640                                 report_error(ERR_NONFATAL,
1641                                              "bad syntax for EQU");
1642                         }
1643                     }
1644                 } else {        /* instruction isn't an EQU */
1645
1646                     if (pass1 == 1) {
1647
1648                         int64_t l = insn_size(location.segment, offs, sb, cpu,
1649                                            &output_ins, report_error);
1650
1651                         /* if (using_debug_info)  && output_ins.opcode != -1) */
1652                         if (using_debug_info)
1653                         {       /* fbk 03/25/01 */
1654                             /* this is done here so we can do debug type info */
1655                             int32_t typeinfo =
1656                                 TYS_ELEMENTS(output_ins.operands);
1657                             switch (output_ins.opcode) {
1658                             case I_RESB:
1659                                 typeinfo =
1660                                     TYS_ELEMENTS(output_ins.oprs[0].
1661                                                  offset) | TY_BYTE;
1662                                 break;
1663                             case I_RESW:
1664                                 typeinfo =
1665                                     TYS_ELEMENTS(output_ins.oprs[0].
1666                                                  offset) | TY_WORD;
1667                                 break;
1668                             case I_RESD:
1669                                 typeinfo =
1670                                     TYS_ELEMENTS(output_ins.oprs[0].
1671                                                  offset) | TY_DWORD;
1672                                 break;
1673                             case I_RESQ:
1674                                 typeinfo =
1675                                     TYS_ELEMENTS(output_ins.oprs[0].
1676                                                  offset) | TY_QWORD;
1677                                 break;
1678                             case I_REST:
1679                                 typeinfo =
1680                                     TYS_ELEMENTS(output_ins.oprs[0].
1681                                                  offset) | TY_TBYTE;
1682                                 break;
1683                             case I_RESO:
1684                                 typeinfo =
1685                                     TYS_ELEMENTS(output_ins.oprs[0].
1686                                                  offset) | TY_OWORD;
1687                                 break;
1688                             case I_RESY:
1689                                 typeinfo =
1690                                     TYS_ELEMENTS(output_ins.oprs[0].
1691                                                  offset) | TY_YWORD;
1692                                 break;
1693                             case I_DB:
1694                                 typeinfo |= TY_BYTE;
1695                                 break;
1696                             case I_DW:
1697                                 typeinfo |= TY_WORD;
1698                                 break;
1699                             case I_DD:
1700                                 if (output_ins.eops_float)
1701                                     typeinfo |= TY_FLOAT;
1702                                 else
1703                                     typeinfo |= TY_DWORD;
1704                                 break;
1705                             case I_DQ:
1706                                 typeinfo |= TY_QWORD;
1707                                 break;
1708                             case I_DT:
1709                                 typeinfo |= TY_TBYTE;
1710                                 break;
1711                             case I_DO:
1712                                 typeinfo |= TY_OWORD;
1713                                 break;
1714                             case I_DY:
1715                                 typeinfo |= TY_YWORD;
1716                                 break;
1717                             default:
1718                                 typeinfo = TY_LABEL;
1719
1720                             }
1721
1722                             ofmt->current_dfmt->debug_typevalue(typeinfo);
1723
1724                         }
1725                         if (l != -1) {
1726                             offs += l;
1727                             SET_CURR_OFFS(offs);
1728                         }
1729                         /*
1730                          * else l == -1 => invalid instruction, which will be
1731                          * flagged as an error on pass 2
1732                          */
1733
1734                     } else {
1735                         offs += assemble(location.segment, offs, sb, cpu,
1736                                          &output_ins, ofmt, report_error,
1737                                          &nasmlist);
1738                         SET_CURR_OFFS(offs);
1739
1740                     }
1741                 }               /* not an EQU */
1742                 cleanup_insn(&output_ins);
1743             }
1744             nasm_free(line);
1745             location.offset = offs = GET_CURR_OFFS;
1746         }                       /* end while (line = preproc->getline... */
1747
1748         if (pass1 == 2 && global_offset_changed)
1749             report_error(ERR_NONFATAL,
1750                          "phase error detected at end of assembly.");
1751
1752         if (pass1 == 1)
1753             preproc->cleanup(1);
1754
1755         if (pass1 == 1 && terminate_after_phase) {
1756             fclose(ofile);
1757             remove(outname);
1758             if (want_usage)
1759                 usage();
1760             exit(1);
1761         }
1762         if (passn >= pass_max - 2 ||
1763             (passn > 1 && !global_offset_changed))
1764             pass0++;
1765     }
1766
1767     preproc->cleanup(0);
1768     nasmlist.cleanup();
1769 #if 1
1770     if (optimizing > 0 && opt_verbose_info)     /*  -On and -Ov switches */
1771         fprintf(stdout,
1772                 "info:: assembly required 1+%d+1 passes\n", passn-3);
1773 #endif
1774 }                               /* exit from assemble_file (...) */
1775
1776 static enum directives getkw(char **directive, char **value)
1777 {
1778     char *p, *q, *buf;
1779
1780     buf = *directive;
1781
1782     /*  allow leading spaces or tabs */
1783     while (*buf == ' ' || *buf == '\t')
1784         buf++;
1785
1786     if (*buf != '[')
1787         return 0;
1788
1789     p = buf;
1790
1791     while (*p && *p != ']')
1792         p++;
1793
1794     if (!*p)
1795         return 0;
1796
1797     q = p++;
1798
1799     while (*p && *p != ';') {
1800         if (!nasm_isspace(*p))
1801             return 0;
1802         p++;
1803     }
1804     q[1] = '\0';
1805
1806     *directive = p = buf + 1;
1807     while (*buf && *buf != ' ' && *buf != ']' && *buf != '\t')
1808         buf++;
1809     if (*buf == ']') {
1810         *buf = '\0';
1811         *value = buf;
1812     } else {
1813         *buf++ = '\0';
1814         while (nasm_isspace(*buf))
1815             buf++;              /* beppu - skip leading whitespace */
1816         *value = buf;
1817         while (*buf != ']')
1818             buf++;
1819         *buf++ = '\0';
1820     }
1821
1822     return bsii(*directive, directives, elements(directives));
1823 }
1824
1825 /**
1826  * gnu style error reporting
1827  * This function prints an error message to error_file in the
1828  * style used by GNU. An example would be:
1829  * file.asm:50: error: blah blah blah
1830  * where file.asm is the name of the file, 50 is the line number on
1831  * which the error occurs (or is detected) and "error:" is one of
1832  * the possible optional diagnostics -- it can be "error" or "warning"
1833  * or something else.  Finally the line terminates with the actual
1834  * error message.
1835  *
1836  * @param severity the severity of the warning or error
1837  * @param fmt the printf style format string
1838  */
1839 static void report_error_gnu(int severity, const char *fmt, ...)
1840 {
1841     va_list ap;
1842
1843     if (is_suppressed_warning(severity))
1844         return;
1845
1846     if (severity & ERR_NOFILE)
1847         fputs("nasm: ", error_file);
1848     else {
1849         char *currentfile = NULL;
1850         int32_t lineno = 0;
1851         src_get(&lineno, &currentfile);
1852         fprintf(error_file, "%s:%"PRId32": ", currentfile, lineno);
1853         nasm_free(currentfile);
1854     }
1855     va_start(ap, fmt);
1856     report_error_common(severity, fmt, ap);
1857     va_end(ap);
1858 }
1859
1860 /**
1861  * MS style error reporting
1862  * This function prints an error message to error_file in the
1863  * style used by Visual C and some other Microsoft tools. An example
1864  * would be:
1865  * file.asm(50) : error: blah blah blah
1866  * where file.asm is the name of the file, 50 is the line number on
1867  * which the error occurs (or is detected) and "error:" is one of
1868  * the possible optional diagnostics -- it can be "error" or "warning"
1869  * or something else.  Finally the line terminates with the actual
1870  * error message.
1871  *
1872  * @param severity the severity of the warning or error
1873  * @param fmt the printf style format string
1874  */
1875 static void report_error_vc(int severity, const char *fmt, ...)
1876 {
1877     va_list ap;
1878
1879     if (is_suppressed_warning(severity))
1880         return;
1881
1882     if (severity & ERR_NOFILE)
1883         fputs("nasm: ", error_file);
1884     else {
1885         char *currentfile = NULL;
1886         int32_t lineno = 0;
1887         src_get(&lineno, &currentfile);
1888         fprintf(error_file, "%s(%"PRId32") : ", currentfile, lineno);
1889         nasm_free(currentfile);
1890     }
1891     va_start(ap, fmt);
1892     report_error_common(severity, fmt, ap);
1893     va_end(ap);
1894 }
1895
1896 /**
1897  * check for supressed warning
1898  * checks for suppressed warning or pass one only warning and we're
1899  * not in pass 1
1900  *
1901  * @param severity the severity of the warning or error
1902  * @return true if we should abort error/warning printing
1903  */
1904 static bool is_suppressed_warning(int severity)
1905 {
1906     /*
1907      * See if it's a suppressed warning.
1908      */
1909     return (severity & ERR_MASK) == ERR_WARNING &&
1910         (((severity & ERR_WARN_MASK) != 0 &&
1911           suppressed[(severity & ERR_WARN_MASK) >> ERR_WARN_SHR]) ||
1912          /* See if it's a pass-one only warning and we're not in pass one. */
1913          ((severity & ERR_PASS1) && pass0 != 1));
1914 }
1915
1916 /**
1917  * common error reporting
1918  * This is the common back end of the error reporting schemes currently
1919  * implemented.  It prints the nature of the warning and then the
1920  * specific error message to error_file and may or may not return.  It
1921  * doesn't return if the error severity is a "panic" or "debug" type.
1922  *
1923  * @param severity the severity of the warning or error
1924  * @param fmt the printf style format string
1925  */
1926 static void report_error_common(int severity, const char *fmt,
1927                                 va_list args)
1928 {
1929     switch (severity & (ERR_MASK|ERR_NO_SEVERITY)) {
1930     case ERR_WARNING:
1931         fputs("warning: ", error_file);
1932         break;
1933     case ERR_NONFATAL:
1934         fputs("error: ", error_file);
1935         break;
1936     case ERR_FATAL:
1937         fputs("fatal: ", error_file);
1938         break;
1939     case ERR_PANIC:
1940         fputs("panic: ", error_file);
1941         break;
1942     case ERR_DEBUG:
1943         fputs("debug: ", error_file);
1944         break;
1945     default:
1946         break;
1947     }
1948
1949     vfprintf(error_file, fmt, args);
1950     putc('\n', error_file);
1951
1952     if (severity & ERR_USAGE)
1953         want_usage = true;
1954
1955     switch (severity & ERR_MASK) {
1956     case ERR_DEBUG:
1957         /* no further action, by definition */
1958         break;
1959     case ERR_WARNING:
1960         if (!suppressed[0])     /* Treat warnings as errors */
1961             terminate_after_phase = true;
1962         break;
1963     case ERR_NONFATAL:
1964         terminate_after_phase = true;
1965         break;
1966     case ERR_FATAL:
1967         if (ofile) {
1968             fclose(ofile);
1969             remove(outname);
1970         }
1971         if (want_usage)
1972             usage();
1973         exit(1);                /* instantly die */
1974         break;                  /* placate silly compilers */
1975     case ERR_PANIC:
1976         fflush(NULL);
1977         /*      abort();        *//* halt, catch fire, and dump core */
1978         exit(3);
1979         break;
1980     }
1981 }
1982
1983 static void usage(void)
1984 {
1985     fputs("type `nasm -h' for help\n", error_file);
1986 }
1987
1988 static void register_output_formats(void)
1989 {
1990     ofmt = ofmt_register(report_error);
1991 }
1992
1993 #define BUF_DELTA 512
1994
1995 static FILE *no_pp_fp;
1996 static efunc no_pp_err;
1997 static ListGen *no_pp_list;
1998 static int32_t no_pp_lineinc;
1999
2000 static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
2001                         ListGen * listgen, StrList **deplist)
2002 {
2003     src_set_fname(nasm_strdup(file));
2004     src_set_linnum(0);
2005     no_pp_lineinc = 1;
2006     no_pp_err = error;
2007     no_pp_fp = fopen(file, "r");
2008     if (!no_pp_fp)
2009         no_pp_err(ERR_FATAL | ERR_NOFILE,
2010                   "unable to open input file `%s'", file);
2011     no_pp_list = listgen;
2012     (void)pass;                 /* placate compilers */
2013     (void)eval;                 /* placate compilers */
2014
2015     if (deplist) {
2016         StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
2017         sl->next = NULL;
2018         strcpy(sl->str, file);
2019         *deplist = sl;
2020     }
2021 }
2022
2023 static char *no_pp_getline(void)
2024 {
2025     char *buffer, *p, *q;
2026     int bufsize;
2027
2028     bufsize = BUF_DELTA;
2029     buffer = nasm_malloc(BUF_DELTA);
2030     src_set_linnum(src_get_linnum() + no_pp_lineinc);
2031
2032     while (1) {                 /* Loop to handle %line */
2033
2034         p = buffer;
2035         while (1) {             /* Loop to handle long lines */
2036             q = fgets(p, bufsize - (p - buffer), no_pp_fp);
2037             if (!q)
2038                 break;
2039             p += strlen(p);
2040             if (p > buffer && p[-1] == '\n')
2041                 break;
2042             if (p - buffer > bufsize - 10) {
2043                 int offset;
2044                 offset = p - buffer;
2045                 bufsize += BUF_DELTA;
2046                 buffer = nasm_realloc(buffer, bufsize);
2047                 p = buffer + offset;
2048             }
2049         }
2050
2051         if (!q && p == buffer) {
2052             nasm_free(buffer);
2053             return NULL;
2054         }
2055
2056         /*
2057          * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
2058          * them are present at the end of the line.
2059          */
2060         buffer[strcspn(buffer, "\r\n\032")] = '\0';
2061
2062         if (!nasm_strnicmp(buffer, "%line", 5)) {
2063             int32_t ln;
2064             int li;
2065             char *nm = nasm_malloc(strlen(buffer));
2066             if (sscanf(buffer + 5, "%"PRId32"+%d %s", &ln, &li, nm) == 3) {
2067                 nasm_free(src_set_fname(nm));
2068                 src_set_linnum(ln);
2069                 no_pp_lineinc = li;
2070                 continue;
2071             }
2072             nasm_free(nm);
2073         }
2074         break;
2075     }
2076
2077     no_pp_list->line(LIST_READ, buffer);
2078
2079     return buffer;
2080 }
2081
2082 static void no_pp_cleanup(int pass)
2083 {
2084     (void)pass;                     /* placate GCC */
2085     fclose(no_pp_fp);
2086 }
2087
2088 static uint32_t get_cpu(char *value)
2089 {
2090     if (!strcmp(value, "8086"))
2091         return IF_8086;
2092     if (!strcmp(value, "186"))
2093         return IF_186;
2094     if (!strcmp(value, "286"))
2095         return IF_286;
2096     if (!strcmp(value, "386"))
2097         return IF_386;
2098     if (!strcmp(value, "486"))
2099         return IF_486;
2100     if (!strcmp(value, "586") || !nasm_stricmp(value, "pentium"))
2101         return IF_PENT;
2102     if (!strcmp(value, "686") ||
2103         !nasm_stricmp(value, "ppro") ||
2104         !nasm_stricmp(value, "pentiumpro") || !nasm_stricmp(value, "p2"))
2105         return IF_P6;
2106     if (!nasm_stricmp(value, "p3") || !nasm_stricmp(value, "katmai"))
2107         return IF_KATMAI;
2108     if (!nasm_stricmp(value, "p4") ||   /* is this right? -- jrc */
2109         !nasm_stricmp(value, "willamette"))
2110         return IF_WILLAMETTE;
2111     if (!nasm_stricmp(value, "prescott"))
2112         return IF_PRESCOTT;
2113     if (!nasm_stricmp(value, "x64") ||
2114         !nasm_stricmp(value, "x86-64"))
2115         return IF_X86_64;
2116     if (!nasm_stricmp(value, "ia64") ||
2117         !nasm_stricmp(value, "ia-64") ||
2118         !nasm_stricmp(value, "itanium") ||
2119         !nasm_stricmp(value, "itanic") || !nasm_stricmp(value, "merced"))
2120         return IF_IA64;
2121
2122     report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
2123                  "unknown 'cpu' type");
2124
2125     return IF_PLEVEL;           /* the maximum level */
2126 }
2127
2128 static int get_bits(char *value)
2129 {
2130     int i;
2131
2132     if ((i = atoi(value)) == 16)
2133         return i;               /* set for a 16-bit segment */
2134     else if (i == 32) {
2135         if (cpu < IF_386) {
2136             report_error(ERR_NONFATAL,
2137                          "cannot specify 32-bit segment on processor below a 386");
2138             i = 16;
2139         }
2140     } else if (i == 64) {
2141         if (cpu < IF_X86_64) {
2142             report_error(ERR_NONFATAL,
2143                          "cannot specify 64-bit segment on processor below an x86-64");
2144             i = 16;
2145         }
2146         if (i != maxbits) {
2147             report_error(ERR_NONFATAL,
2148                          "%s output format does not support 64-bit code",
2149                          ofmt->shortname);
2150             i = 16;
2151         }
2152     } else {
2153         report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
2154                      "`%s' is not a valid segment size; must be 16, 32 or 64",
2155                      value);
2156         i = 16;
2157     }
2158     return i;
2159 }
2160
2161 /* end of nasm.c */