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