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.
35 struct forwrefinfo
{ /* info held on forward refs. */
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
,
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;
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
;
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
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
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
= {
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
)
168 fputs(line
, outfile
);
174 /* Convert a struct tm to a POSIX-style time constant */
175 static int64_t posix_mktime(struct tm
*tm
)
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;
194 static void define_macros_early(void)
197 struct tm lt
, *lt_p
, gm
, *gm_p
;
200 lt_p
= localtime(&official_compile_time
);
204 strftime(temp
, sizeof temp
, "__DATE__=\"%Y-%m-%d\"", <
);
206 strftime(temp
, sizeof temp
, "__DATE_NUM__=%Y%m%d", <
);
208 strftime(temp
, sizeof temp
, "__TIME__=\"%H:%M:%S\"", <
);
210 strftime(temp
, sizeof temp
, "__TIME_NUM__=%H%M%S", <
);
214 gm_p
= gmtime(&official_compile_time
);
218 strftime(temp
, sizeof temp
, "__UTC_DATE__=\"%Y-%m-%d\"", &gm
);
220 strftime(temp
, sizeof temp
, "__UTC_DATE_NUM__=%Y%m%d", &gm
);
222 strftime(temp
, sizeof temp
, "__UTC_TIME__=\"%H:%M:%S\"", &gm
);
224 strftime(temp
, sizeof temp
, "__UTC_TIME_NUM__=%H%M%S", &gm
);
229 posix_time
= posix_mktime(&gm
);
231 posix_time
= posix_mktime(<
);
236 snprintf(temp
, sizeof temp
, "__POSIX_TIME__=%"PRId64
, posix_time
);
241 static void define_macros_late(void)
245 snprintf(temp
, sizeof(temp
), "__OUTPUT_FORMAT__=%s\n",
250 static void emit_dependencies(StrList
*list
)
256 if (depend_file
&& strcmp(depend_file
, "-")) {
257 deps
= fopen(depend_file
, "w");
259 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
260 "unable to write dependency file `%s'", depend_file
);
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 ");
274 fprintf(deps
, " %s", l
->str
);
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
);
291 int main(int argc
, char **argv
)
293 StrList
*depend_list
= NULL
, **depend_ptr
;
295 time(&official_compile_time
);
298 want_usage
= terminate_after_phase
= false;
299 report_error
= report_error_gnu
;
305 nasm_set_malloc_error(report_error
);
306 offsets
= raa_init();
307 forwrefs
= saa_init((int32_t)sizeof(struct forwrefinfo
));
310 operating_mode
= op_normal
;
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
) {
328 /* If debugging info is disabled, suppress any debug calls */
329 if (!using_debug_info
)
330 ofmt
->current_dfmt
= &null_debug_form
;
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
;
343 depend_target
= outname
;
345 switch (operating_mode
) {
350 if (depend_missing_ok
)
351 pp_include_path(NULL
); /* "assume generated" */
353 preproc
->reset(inname
, 0, report_error
, evaluate
, &nasmlist
,
355 if (outname
[0] == '\0')
356 ofmt
->filename(inname
, outname
, report_error
);
358 while ((line
= preproc
->getline()))
367 char *file_name
= NULL
;
368 int32_t prior_linnum
= 0;
372 ofile
= fopen(outname
, "w");
374 report_error(ERR_FATAL
| ERR_NOFILE
,
375 "unable to open output file `%s'",
380 location
.known
= false;
383 preproc
->reset(inname
, 2, report_error
, evaluate
, &nasmlist
,
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
);
393 if (altline
== 1 && lineinc
== 1)
394 nasm_fputs("", ofile
);
396 lineinc
= (altline
!= -1 || lineinc
!= 1);
397 fprintf(ofile
? ofile
: stdout
,
398 "%%line %"PRId32
"+%d %s\n", linnum
, lineinc
,
401 prior_linnum
= linnum
;
403 nasm_fputs(line
, ofile
);
406 nasm_free(file_name
);
410 if (ofile
&& terminate_after_phase
)
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
424 ofmt
->filename(inname
, outname
, report_error
);
426 ofile
= fopen(outname
, "wb");
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)
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
);
448 * Despite earlier comments, we need this fclose.
449 * The object output drivers only fclose on cleanup,
450 * and we just skipped that.
463 emit_dependencies(depend_list
);
473 if (terminate_after_phase
)
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
)
486 if (p
[2]) { /* the parameter's in the option */
488 while (nasm_isspace(*p
))
496 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
497 "option `-%c' requires an argument", p
[1]);
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");
512 strncpy(dst
, src
, FILENAME_MAX
);
516 * Convert a string to Make-safe form
518 static char *quote_for_make(const char *str
)
523 size_t n
= 1; /* Terminating zero */
529 for (p
= str
; *p
; p
++) {
533 /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
553 /* Convert N backslashes at the end of filename to 2N backslashes */
557 os
= q
= nasm_malloc(n
);
560 for (p
= str
; *p
; p
++) {
603 #define OPT_POSTFIX 1
604 struct textargs textopts
[] = {
605 {"prefix", OPT_PREFIX
},
606 {"postfix", OPT_POSTFIX
},
610 static bool stopoptions
= false;
611 static bool process_arg(char *p
, char *q
)
615 bool advance
= 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
)))
633 case 'o': /* output file */
634 copy_filename(outname
, param
);
637 case 'f': /* output format */
638 ofmt
= ofmt_find(param
);
640 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
641 "unrecognised output format `%s' - "
642 "use -hf for a list", param
);
644 ofmt
->current_dfmt
= ofmt
->debug_formats
[0];
648 case 'O': /* Optimization level */
653 /* Naked -O == -Ox */
654 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
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
, ¶m
, 10);
662 /* -O0 -> optimizing == -1, 0.98 behaviour */
663 /* -O1 -> optimizing == 0, 0.98.09 behaviour */
665 optimizing
= opt
- 1;
673 opt_verbose_info
= true;
678 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
682 report_error(ERR_FATAL
,
683 "unknown optimization option -O%c\n",
692 case 'p': /* pre-include */
694 pp_pre_include(param
);
697 case 'd': /* pre-define */
699 pp_pre_define(param
);
702 case 'u': /* un-define */
704 pp_pre_undefine(param
);
707 case 'i': /* include search path */
709 pp_include_path(param
);
712 case 'l': /* listing file */
713 copy_filename(listname
, param
);
716 case 'Z': /* error messages file */
717 strcpy(errname
, param
);
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;
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
;
737 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
738 "unrecognized error reporting format `%s'",
743 using_debug_info
= true;
748 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
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");
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");
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"
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");
777 ("\nresponse files should contain command line parameters"
778 ", one per line.\n");
780 printf("\nvalid output formats for -f are"
781 " (`*' denotes default):\n");
782 ofmt_list(ofmt
, stdout
);
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 */
791 printf("\nvalid debug formats for '%s' output format are"
792 " ('*' denotes default):\n", ofmt
->shortname
);
793 dfmt_list(ofmt
, stdout
);
798 tasm_compatible_mode
= true;
803 const char *nasm_version_string
=
804 "NASM version " NASM_VER
" compiled on " __DATE__
809 puts(nasm_version_string
);
810 exit(0); /* never need usage message here */
814 case 'e': /* preprocess only */
816 operating_mode
= op_preprocess
;
819 case 'a': /* assemble only - don't preprocess */
824 if (param
[0] == 'n' && param
[1] == 'o' && param
[2] == '-') {
833 if (param
[0] != '+' && param
[0] != '-') {
834 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
835 "invalid option to `-w'");
838 suppress
= (param
[0] == '-');
842 for (i
= 0; i
<= ERR_WARN_MAX
; i
++)
843 if (!nasm_stricmp(param
, suppressed_names
[i
]))
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
;
854 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
855 "invalid warning `%s'", param
);
861 operating_mode
= op_depend
;
864 operating_mode
= op_depend
;
865 depend_missing_ok
= true;
868 depend_emit_phony
= true;
879 depend_target
= quote_for_make(q
);
883 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
884 "unknown dependency option `-M%c'", p
[2]);
887 if (advance
&& (!q
|| !q
[0])) {
888 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
889 "option `-M%c' requires a parameter", p
[2]);
898 if (p
[2] == 0) { /* -- => stop processing options */
902 for (s
= 0; textopts
[s
].label
; s
++) {
903 if (!nasm_stricmp(p
+ 2, textopts
[s
].label
)) {
914 report_error(ERR_NONFATAL
| ERR_NOFILE
|
916 "option `--%s' requires an argument",
920 advance
= 1, param
= q
;
923 if (s
== OPT_PREFIX
) {
924 strncpy(lprefix
, param
, PREFIX_MAX
- 1);
925 lprefix
[PREFIX_MAX
- 1] = 0;
928 if (s
== OPT_POSTFIX
) {
929 strncpy(lpostfix
, param
, POSTFIX_MAX
- 1);
930 lpostfix
[POSTFIX_MAX
- 1] = 0;
937 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
938 "unrecognised option `--%s'", p
+ 2);
946 if (!ofmt
->setinfo(GI_SWITCH
, &p
))
947 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
948 "unrecognised option `-%c'", p
[1]);
953 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
954 "more than one input file specified");
956 copy_filename(inname
, p
);
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
);
975 while (1) { /* Loop to handle all lines in file */
977 while (1) { /* Loop to handle long lines */
978 q
= fgets(p
, bufsize
- (p
- buffer
), rfile
);
982 if (p
> buffer
&& p
[-1] == '\n')
984 if (p
- buffer
> bufsize
- 10) {
987 bufsize
+= ARG_BUF_DELTA
;
988 buffer
= nasm_realloc(buffer
, bufsize
);
993 if (!q
&& p
== buffer
) {
995 process_arg(prevarg
, NULL
);
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]))
1011 while (nasm_isspace(*p
))
1014 if (process_arg(prevarg
, p
))
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
1029 static void process_args(char *args
)
1031 char *p
, *q
, *arg
, *prevarg
;
1032 char separator
= ' ';
1035 if (*p
&& *p
!= '-')
1040 while (*p
&& *p
!= separator
)
1042 while (*p
== separator
)
1046 if (process_arg(prevarg
, arg
))
1050 process_arg(arg
, NULL
);
1053 static void process_response_file(const char *file
)
1056 FILE *f
= fopen(file
, "r");
1061 while (fgets(str
, sizeof str
, f
)) {
1067 static void parse_cmdline(int argc
, char **argv
)
1070 char *envreal
, *envcopy
= NULL
, *p
, *arg
;
1072 *inname
= *outname
= *listname
= *errname
= '\0';
1075 * First, process the NASMENV environment variable.
1077 envreal
= getenv("NASMENV");
1080 envcopy
= nasm_strdup(envreal
);
1081 process_args(envcopy
);
1086 * Now process the actual command line.
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
1098 process_response_file(argv
[0]+1);
1102 if (!stopoptions
&& argv
[0][0] == '-' && argv
[0][1] == '@') {
1103 p
= get_param(argv
[0], argc
> 1 ? argv
[1] : NULL
, &advance
);
1105 rfile
= fopen(p
, "r");
1107 process_respfile(rfile
);
1110 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
1111 "unable to open response file `%s'", p
);
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. */
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",
1132 error_file
= fopen(errname
, "w");
1134 error_file
= stderr
; /* Revert to default! */
1135 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
1136 "cannot open file `%s' for error messages",
1142 /* List of 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];
1161 struct tokenval tokval
;
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
= (INT_MAX
>> 1) + 2; /* Almost unlimited */
1170 for (passn
= 1; pass0
<= 2; passn
++) {
1174 pass1
= pass0
== 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
1175 pass2
= passn
> 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
1176 /* pass0 0, 0, 0, ..., 1, 2 */
1178 def_label
= passn
> 1 ? redefine_label
: define_label
;
1180 globalbits
= sb
= cmd_sb
; /* set 'bits' to command line default */
1184 nasmlist
.init(listname
, report_error
);
1187 global_offset_changed
= false; /* set by redefine_label */
1188 location
.segment
= ofmt
->section(NULL
, pass2
, &sb
);
1191 saa_rewind(forwrefs
);
1192 forwref
= saa_rstruct(forwrefs
);
1194 offsets
= raa_init();
1196 preproc
->reset(fname
, pass1
, report_error
, evaluate
, &nasmlist
,
1197 pass1
== 2 ? depend_ptr
: NULL
);
1198 memcpy(suppressed
, suppressed_global
, (ERR_WARN_MAX
+1) * sizeof(bool));
1202 location
.known
= true;
1203 location
.offset
= offs
= GET_CURR_OFFS
;
1205 while ((line
= preproc
->getline())) {
1209 /* here we parse our directives; this is not handled by the 'real'
1212 d
= getkw(&directive
, &value
);
1217 case D_SEGMENT
: /* [SEGMENT n] */
1219 seg
= ofmt
->section(value
, pass2
, &sb
);
1220 if (seg
== NO_SEG
) {
1221 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1222 "segment name `%s' not recognized",
1226 location
.segment
= seg
;
1229 case D_EXTERN
: /* [EXTERN label:special] */
1231 value
++; /* skip initial $ if present */
1234 while (*q
&& *q
!= ':')
1238 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1240 } else if (passn
== 1) {
1245 while (*q
&& *q
!= ':') {
1251 report_error(ERR_NONFATAL
,
1252 "identifier expected after EXTERN");
1260 if (!is_extern(value
)) { /* allow re-EXTERN to be ignored */
1262 pass0
= 1; /* fake pass 1 in labels.c */
1263 declare_as_global(value
, special
,
1265 define_label(value
, seg_alloc(), 0L, NULL
,
1266 false, true, ofmt
, report_error
);
1269 } /* else pass0 == 1 */
1271 case D_BITS
: /* [BITS bits] */
1272 globalbits
= sb
= get_bits(value
);
1274 case D_GLOBAL
: /* [GLOBAL symbol:special] */
1276 value
++; /* skip initial $ if present */
1277 if (pass0
== 2) { /* pass 2 */
1279 while (*q
&& *q
!= ':')
1283 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1285 } else if (pass2
== 1) { /* pass == 1 */
1290 while (*q
&& *q
!= ':') {
1296 report_error(ERR_NONFATAL
,
1297 "identifier expected after GLOBAL");
1305 declare_as_global(value
, special
, report_error
);
1308 case D_COMMON
: /* [COMMON symbol size:special] */
1310 value
++; /* skip initial $ if present */
1316 while (*p
&& !nasm_isspace(*p
)) {
1322 report_error(ERR_NONFATAL
,
1323 "identifier expected after COMMON");
1329 while (*p
&& nasm_isspace(*p
))
1332 while (*q
&& *q
!= ':')
1339 size
= readnum(p
, &rn_error
);
1341 report_error(ERR_NONFATAL
,
1342 "invalid size specified"
1343 " in COMMON declaration");
1345 define_common(value
, seg_alloc(), size
,
1346 special
, ofmt
, report_error
);
1348 report_error(ERR_NONFATAL
,
1349 "no size specified in"
1350 " COMMON declaration");
1351 } else if (pass0
== 2) { /* pass == 2 */
1353 while (*q
&& *q
!= ':') {
1354 if (nasm_isspace(*q
))
1360 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1364 case D_ABSOLUTE
: /* [ABSOLUTE address] */
1366 stdscan_bufptr
= value
;
1367 tokval
.t_type
= TOKEN_INVALID
;
1368 e
= evaluate(stdscan
, NULL
, &tokval
, NULL
, pass2
,
1369 report_error
, NULL
);
1372 report_error(pass0
==
1373 1 ? ERR_NONFATAL
: ERR_PANIC
,
1374 "cannot use non-relocatable expression as "
1375 "ABSOLUTE address");
1377 abs_seg
= reloc_seg(e
);
1378 abs_offset
= reloc_value(e
);
1380 } else if (passn
== 1)
1381 abs_offset
= 0x100; /* don't go near zero in case of / */
1383 report_error(ERR_PANIC
, "invalid ABSOLUTE address "
1386 location
.segment
= NO_SEG
;
1388 case D_DEBUG
: /* [DEBUG] */
1394 while (*p
&& !nasm_isspace(*p
)) {
1401 report_error(passn
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1402 "identifier expected after DEBUG");
1405 while (*p
&& nasm_isspace(*p
))
1408 ofmt
->current_dfmt
->debug_directive(debugid
, p
);
1410 case D_WARNING
: /* [WARNING {+|-|*}warn-name] */
1412 while (*value
&& nasm_isspace(*value
))
1416 case '-': validid
= 0; value
++; break;
1417 case '+': validid
= 1; value
++; break;
1418 case '*': validid
= 2; value
++; break;
1420 * Should this error out?
1421 * I'll keep it so nothing breaks.
1426 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
1427 if (!nasm_stricmp(value
, suppressed_names
[i
]))
1429 if (i
<= ERR_WARN_MAX
) {
1431 case 0: suppressed
[i
] = true; break;
1432 case 1: suppressed
[i
] = false; break;
1433 case 2: suppressed
[i
] = suppressed_global
[i
];
1438 report_error(ERR_NONFATAL
,
1439 "invalid warning id in WARNING directive");
1442 case D_CPU
: /* [CPU] */
1443 cpu
= get_cpu(value
);
1445 case D_LIST
: /* [LIST {+|-}] */
1446 while (*value
&& nasm_isspace(*value
))
1449 if (*value
== '+') {
1452 if (*value
== '-') {
1459 case D_DEFAULT
: /* [DEFAULT] */
1461 stdscan_bufptr
= value
;
1462 tokval
.t_type
= TOKEN_INVALID
;
1463 if (stdscan(NULL
, &tokval
) == TOKEN_SPECIAL
) {
1464 switch ((int)tokval
.t_integer
) {
1480 if (float_option(value
)) {
1481 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1482 "unknown 'float' directive: %s",
1487 if (!ofmt
->directive(directive
, value
, pass2
))
1488 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1489 "unrecognised directive [%s]",
1493 report_error(ERR_NONFATAL
,
1494 "invalid parameter to [%s] directive",
1497 } else { /* it isn't a directive */
1499 parse_line(pass1
, line
, &output_ins
,
1500 report_error
, evaluate
, def_label
);
1502 if (optimizing
> 0) {
1503 if (forwref
!= NULL
&& globallineno
== forwref
->lineno
) {
1504 output_ins
.forw_ref
= true;
1506 output_ins
.oprs
[forwref
->operand
].opflags
|=
1508 forwref
= saa_rstruct(forwrefs
);
1509 } while (forwref
!= NULL
1510 && forwref
->lineno
== globallineno
);
1512 output_ins
.forw_ref
= false;
1515 if (optimizing
> 0) {
1517 for (i
= 0; i
< output_ins
.operands
; i
++) {
1518 if (output_ins
.oprs
[i
].
1519 opflags
& OPFLAG_FORWARD
) {
1520 struct forwrefinfo
*fwinf
=
1521 (struct forwrefinfo
*)
1522 saa_wstruct(forwrefs
);
1523 fwinf
->lineno
= globallineno
;
1527 } else { /* passn > 1 */
1529 * Hack to prevent phase error in the code
1533 * If the second operand is a forward reference,
1534 * the UNITY property of the number 1 in that
1535 * operand is cancelled. Otherwise the above
1536 * sequence will cause a phase error.
1538 * This hack means that the above code will
1539 * generate 286+ code.
1541 * The forward reference will mean that the
1542 * operand will not have the UNITY property on
1543 * the first pass, so the pass behaviours will
1547 if (output_ins
.operands
>= 2 &&
1548 (output_ins
.oprs
[1].opflags
& OPFLAG_FORWARD
) &&
1549 !(IMMEDIATE
& ~output_ins
.oprs
[1].type
))
1551 /* Remove special properties bits */
1552 output_ins
.oprs
[1].type
&= ~REG_SMASK
;
1560 if (output_ins
.opcode
== I_EQU
) {
1563 * Special `..' EQUs get processed in pass two,
1564 * except `..@' macro-processor EQUs which are done
1565 * in the normal place.
1567 if (!output_ins
.label
)
1568 report_error(ERR_NONFATAL
,
1569 "EQU not preceded by label");
1571 else if (output_ins
.label
[0] != '.' ||
1572 output_ins
.label
[1] != '.' ||
1573 output_ins
.label
[2] == '@') {
1574 if (output_ins
.operands
== 1 &&
1575 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
1576 output_ins
.oprs
[0].wrt
== NO_SEG
) {
1579 opflags
& OPFLAG_EXTERN
;
1580 def_label(output_ins
.label
,
1581 output_ins
.oprs
[0].segment
,
1582 output_ins
.oprs
[0].offset
, NULL
,
1585 } else if (output_ins
.operands
== 2
1586 && (output_ins
.oprs
[0].
1588 && (output_ins
.oprs
[0].type
& COLON
)
1589 && output_ins
.oprs
[0].segment
==
1591 && output_ins
.oprs
[0].wrt
== NO_SEG
1592 && (output_ins
.oprs
[1].
1594 && output_ins
.oprs
[1].segment
==
1596 && output_ins
.oprs
[1].wrt
==
1598 def_label(output_ins
.label
,
1601 output_ins
.oprs
[1].offset
, NULL
,
1605 report_error(ERR_NONFATAL
,
1606 "bad syntax for EQU");
1610 * Special `..' EQUs get processed here, except
1611 * `..@' macro processor EQUs which are done above.
1613 if (output_ins
.label
[0] == '.' &&
1614 output_ins
.label
[1] == '.' &&
1615 output_ins
.label
[2] != '@') {
1616 if (output_ins
.operands
== 1 &&
1617 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
1618 define_label(output_ins
.label
,
1619 output_ins
.oprs
[0].segment
,
1620 output_ins
.oprs
[0].offset
,
1621 NULL
, false, false, ofmt
,
1623 } else if (output_ins
.operands
== 2
1624 && (output_ins
.oprs
[0].
1626 && (output_ins
.oprs
[0].type
& COLON
)
1627 && output_ins
.oprs
[0].segment
==
1629 && (output_ins
.oprs
[1].
1631 && output_ins
.oprs
[1].segment
==
1633 define_label(output_ins
.label
,
1636 output_ins
.oprs
[1].offset
,
1637 NULL
, false, false, ofmt
,
1640 report_error(ERR_NONFATAL
,
1641 "bad syntax for EQU");
1644 } else { /* instruction isn't an EQU */
1648 int64_t l
= insn_size(location
.segment
, offs
, sb
, cpu
,
1649 &output_ins
, report_error
);
1651 /* if (using_debug_info) && output_ins.opcode != -1) */
1652 if (using_debug_info
)
1653 { /* fbk 03/25/01 */
1654 /* this is done here so we can do debug type info */
1656 TYS_ELEMENTS(output_ins
.operands
);
1657 switch (output_ins
.opcode
) {
1660 TYS_ELEMENTS(output_ins
.oprs
[0].
1665 TYS_ELEMENTS(output_ins
.oprs
[0].
1670 TYS_ELEMENTS(output_ins
.oprs
[0].
1675 TYS_ELEMENTS(output_ins
.oprs
[0].
1680 TYS_ELEMENTS(output_ins
.oprs
[0].
1685 TYS_ELEMENTS(output_ins
.oprs
[0].
1690 TYS_ELEMENTS(output_ins
.oprs
[0].
1694 typeinfo
|= TY_BYTE
;
1697 typeinfo
|= TY_WORD
;
1700 if (output_ins
.eops_float
)
1701 typeinfo
|= TY_FLOAT
;
1703 typeinfo
|= TY_DWORD
;
1706 typeinfo
|= TY_QWORD
;
1709 typeinfo
|= TY_TBYTE
;
1712 typeinfo
|= TY_OWORD
;
1715 typeinfo
|= TY_YWORD
;
1718 typeinfo
= TY_LABEL
;
1722 ofmt
->current_dfmt
->debug_typevalue(typeinfo
);
1727 SET_CURR_OFFS(offs
);
1730 * else l == -1 => invalid instruction, which will be
1731 * flagged as an error on pass 2
1735 offs
+= assemble(location
.segment
, offs
, sb
, cpu
,
1736 &output_ins
, ofmt
, report_error
,
1738 SET_CURR_OFFS(offs
);
1742 cleanup_insn(&output_ins
);
1745 location
.offset
= offs
= GET_CURR_OFFS
;
1746 } /* end while (line = preproc->getline... */
1748 if (pass1
== 2 && global_offset_changed
)
1749 report_error(ERR_NONFATAL
,
1750 "phase error detected at end of assembly.");
1753 preproc
->cleanup(1);
1755 if (pass1
== 1 && terminate_after_phase
) {
1762 if (passn
>= pass_max
- 2 ||
1763 (passn
> 1 && !global_offset_changed
))
1767 preproc
->cleanup(0);
1770 if (opt_verbose_info
) /* -On and -Ov switches */
1772 "info:: assembly required 1+%d+1 passes\n", passn
-3);
1774 } /* exit from assemble_file (...) */
1776 static enum directives
getkw(char **directive
, char **value
)
1782 /* allow leading spaces or tabs */
1783 while (*buf
== ' ' || *buf
== '\t')
1791 while (*p
&& *p
!= ']')
1799 while (*p
&& *p
!= ';') {
1800 if (!nasm_isspace(*p
))
1806 *directive
= p
= buf
+ 1;
1807 while (*buf
&& *buf
!= ' ' && *buf
!= ']' && *buf
!= '\t')
1814 while (nasm_isspace(*buf
))
1815 buf
++; /* beppu - skip leading whitespace */
1822 return bsii(*directive
, directives
, elements(directives
));
1826 * gnu style error reporting
1827 * This function prints an error message to error_file in the
1828 * style used by GNU. An example would be:
1829 * file.asm:50: error: blah blah blah
1830 * where file.asm is the name of the file, 50 is the line number on
1831 * which the error occurs (or is detected) and "error:" is one of
1832 * the possible optional diagnostics -- it can be "error" or "warning"
1833 * or something else. Finally the line terminates with the actual
1836 * @param severity the severity of the warning or error
1837 * @param fmt the printf style format string
1839 static void report_error_gnu(int severity
, const char *fmt
, ...)
1843 if (is_suppressed_warning(severity
))
1846 if (severity
& ERR_NOFILE
)
1847 fputs("nasm: ", error_file
);
1849 char *currentfile
= NULL
;
1851 src_get(&lineno
, ¤tfile
);
1852 fprintf(error_file
, "%s:%"PRId32
": ", currentfile
, lineno
);
1853 nasm_free(currentfile
);
1856 report_error_common(severity
, fmt
, ap
);
1861 * MS style error reporting
1862 * This function prints an error message to error_file in the
1863 * style used by Visual C and some other Microsoft tools. An example
1865 * file.asm(50) : error: blah blah blah
1866 * where file.asm is the name of the file, 50 is the line number on
1867 * which the error occurs (or is detected) and "error:" is one of
1868 * the possible optional diagnostics -- it can be "error" or "warning"
1869 * or something else. Finally the line terminates with the actual
1872 * @param severity the severity of the warning or error
1873 * @param fmt the printf style format string
1875 static void report_error_vc(int severity
, const char *fmt
, ...)
1879 if (is_suppressed_warning(severity
))
1882 if (severity
& ERR_NOFILE
)
1883 fputs("nasm: ", error_file
);
1885 char *currentfile
= NULL
;
1887 src_get(&lineno
, ¤tfile
);
1888 fprintf(error_file
, "%s(%"PRId32
") : ", currentfile
, lineno
);
1889 nasm_free(currentfile
);
1892 report_error_common(severity
, fmt
, ap
);
1897 * check for supressed warning
1898 * checks for suppressed warning or pass one only warning and we're
1901 * @param severity the severity of the warning or error
1902 * @return true if we should abort error/warning printing
1904 static bool is_suppressed_warning(int severity
)
1907 * See if it's a suppressed warning.
1909 return (severity
& ERR_MASK
) == ERR_WARNING
&&
1910 (((severity
& ERR_WARN_MASK
) != 0 &&
1911 suppressed
[(severity
& ERR_WARN_MASK
) >> ERR_WARN_SHR
]) ||
1912 /* See if it's a pass-one only warning and we're not in pass one. */
1913 ((severity
& ERR_PASS1
) && pass0
!= 1));
1917 * common error reporting
1918 * This is the common back end of the error reporting schemes currently
1919 * implemented. It prints the nature of the warning and then the
1920 * specific error message to error_file and may or may not return. It
1921 * doesn't return if the error severity is a "panic" or "debug" type.
1923 * @param severity the severity of the warning or error
1924 * @param fmt the printf style format string
1926 static void report_error_common(int severity
, const char *fmt
,
1929 switch (severity
& (ERR_MASK
|ERR_NO_SEVERITY
)) {
1931 fputs("warning: ", error_file
);
1934 fputs("error: ", error_file
);
1937 fputs("fatal: ", error_file
);
1940 fputs("panic: ", error_file
);
1943 fputs("debug: ", error_file
);
1949 vfprintf(error_file
, fmt
, args
);
1950 putc('\n', error_file
);
1952 if (severity
& ERR_USAGE
)
1955 switch (severity
& ERR_MASK
) {
1957 /* no further action, by definition */
1960 if (!suppressed
[0]) /* Treat warnings as errors */
1961 terminate_after_phase
= true;
1964 terminate_after_phase
= true;
1973 exit(1); /* instantly die */
1974 break; /* placate silly compilers */
1977 /* abort(); *//* halt, catch fire, and dump core */
1983 static void usage(void)
1985 fputs("type `nasm -h' for help\n", error_file
);
1988 static void register_output_formats(void)
1990 ofmt
= ofmt_register(report_error
);
1993 #define BUF_DELTA 512
1995 static FILE *no_pp_fp
;
1996 static efunc no_pp_err
;
1997 static ListGen
*no_pp_list
;
1998 static int32_t no_pp_lineinc
;
2000 static void no_pp_reset(char *file
, int pass
, efunc error
, evalfunc eval
,
2001 ListGen
* listgen
, StrList
**deplist
)
2003 src_set_fname(nasm_strdup(file
));
2007 no_pp_fp
= fopen(file
, "r");
2009 no_pp_err(ERR_FATAL
| ERR_NOFILE
,
2010 "unable to open input file `%s'", file
);
2011 no_pp_list
= listgen
;
2012 (void)pass
; /* placate compilers */
2013 (void)eval
; /* placate compilers */
2016 StrList
*sl
= nasm_malloc(strlen(file
)+1+sizeof sl
->next
);
2018 strcpy(sl
->str
, file
);
2023 static char *no_pp_getline(void)
2025 char *buffer
, *p
, *q
;
2028 bufsize
= BUF_DELTA
;
2029 buffer
= nasm_malloc(BUF_DELTA
);
2030 src_set_linnum(src_get_linnum() + no_pp_lineinc
);
2032 while (1) { /* Loop to handle %line */
2035 while (1) { /* Loop to handle long lines */
2036 q
= fgets(p
, bufsize
- (p
- buffer
), no_pp_fp
);
2040 if (p
> buffer
&& p
[-1] == '\n')
2042 if (p
- buffer
> bufsize
- 10) {
2044 offset
= p
- buffer
;
2045 bufsize
+= BUF_DELTA
;
2046 buffer
= nasm_realloc(buffer
, bufsize
);
2047 p
= buffer
+ offset
;
2051 if (!q
&& p
== buffer
) {
2057 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
2058 * them are present at the end of the line.
2060 buffer
[strcspn(buffer
, "\r\n\032")] = '\0';
2062 if (!nasm_strnicmp(buffer
, "%line", 5)) {
2065 char *nm
= nasm_malloc(strlen(buffer
));
2066 if (sscanf(buffer
+ 5, "%"PRId32
"+%d %s", &ln
, &li
, nm
) == 3) {
2067 nasm_free(src_set_fname(nm
));
2077 no_pp_list
->line(LIST_READ
, buffer
);
2082 static void no_pp_cleanup(int pass
)
2084 (void)pass
; /* placate GCC */
2088 static uint32_t get_cpu(char *value
)
2090 if (!strcmp(value
, "8086"))
2092 if (!strcmp(value
, "186"))
2094 if (!strcmp(value
, "286"))
2096 if (!strcmp(value
, "386"))
2098 if (!strcmp(value
, "486"))
2100 if (!strcmp(value
, "586") || !nasm_stricmp(value
, "pentium"))
2102 if (!strcmp(value
, "686") ||
2103 !nasm_stricmp(value
, "ppro") ||
2104 !nasm_stricmp(value
, "pentiumpro") || !nasm_stricmp(value
, "p2"))
2106 if (!nasm_stricmp(value
, "p3") || !nasm_stricmp(value
, "katmai"))
2108 if (!nasm_stricmp(value
, "p4") || /* is this right? -- jrc */
2109 !nasm_stricmp(value
, "willamette"))
2110 return IF_WILLAMETTE
;
2111 if (!nasm_stricmp(value
, "prescott"))
2113 if (!nasm_stricmp(value
, "x64") ||
2114 !nasm_stricmp(value
, "x86-64"))
2116 if (!nasm_stricmp(value
, "ia64") ||
2117 !nasm_stricmp(value
, "ia-64") ||
2118 !nasm_stricmp(value
, "itanium") ||
2119 !nasm_stricmp(value
, "itanic") || !nasm_stricmp(value
, "merced"))
2122 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2123 "unknown 'cpu' type");
2125 return IF_PLEVEL
; /* the maximum level */
2128 static int get_bits(char *value
)
2132 if ((i
= atoi(value
)) == 16)
2133 return i
; /* set for a 16-bit segment */
2136 report_error(ERR_NONFATAL
,
2137 "cannot specify 32-bit segment on processor below a 386");
2140 } else if (i
== 64) {
2141 if (cpu
< IF_X86_64
) {
2142 report_error(ERR_NONFATAL
,
2143 "cannot specify 64-bit segment on processor below an x86-64");
2147 report_error(ERR_NONFATAL
,
2148 "%s output format does not support 64-bit code",
2153 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2154 "`%s' is not a valid segment size; must be 16, 32 or 64",