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