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