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 int64_t global_offset_changed
; /* referenced in labels.c */
77 int64_t prev_offset_changed
;
80 static struct location location
;
81 int in_abs_seg
; /* Flag we are in ABSOLUTE seg */
82 int32_t abs_seg
; /* ABSOLUTE segment basis */
83 int32_t abs_offset
; /* ABSOLUTE offset */
85 static struct RAA
*offsets
;
87 static struct SAA
*forwrefs
; /* keep track of forward references */
88 static const struct forwrefinfo
*forwref
;
90 static Preproc
*preproc
;
92 op_normal
, /* Preprocess and assemble */
93 op_preprocess
, /* Preprocess only */
94 op_depend
, /* Generate dependencies */
96 static enum op_type operating_mode
;
97 /* Dependency flags */
98 static bool depend_emit_phony
= false;
99 static bool depend_missing_ok
= false;
100 static const char *depend_target
= NULL
;
101 static const char *depend_file
= NULL
;
104 * Which of the suppressible warnings are suppressed. Entry zero
105 * isn't an actual warning, but it used for -w+error/-Werror.
107 static bool suppressed
[ERR_WARN_MAX
+1];
109 static bool suppressed_global
[ERR_WARN_MAX
+1] = {
110 true, false, true, false, false, false, true, false, true, true, false,
114 * The option names for the suppressible warnings. As before, entry
117 static const char *suppressed_names
[ERR_WARN_MAX
+1] = {
118 "error", "macro-params", "macro-selfref", "macro-defaults",
119 "orphan-labels", "number-overflow", "gnu-elf-extensions",
120 "float-overflow", "float-denorm", "float-underflow", "float-toolong",
125 * The explanations for the suppressible warnings. As before, entry
128 static const char *suppressed_what
[ERR_WARN_MAX
+1] = {
129 "treat warnings as errors",
130 "macro calls with wrong parameter count",
131 "cyclic macro references",
132 "macros with more default than optional parameters",
133 "labels alone on lines without trailing `:'",
134 "numeric constants does not fit in 64 bits",
135 "using 8- or 16-bit relocation in ELF32, a GNU extension",
136 "floating point overflow",
137 "floating point denormal",
138 "floating point underflow",
139 "too many digits in floating-point number",
140 "%warning directives"
144 * This is a null preprocessor which just copies lines from input
145 * to output. It's used when someone explicitly requests that NASM
146 * not preprocess their source file.
149 static void no_pp_reset(char *, int, efunc
, evalfunc
, ListGen
*, StrList
**);
150 static char *no_pp_getline(void);
151 static void no_pp_cleanup(int);
152 static Preproc no_pp
= {
159 * get/set current offset...
161 #define GET_CURR_OFFS (in_abs_seg?abs_offset:\
162 raa_read(offsets,location.segment))
163 #define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
164 (void)(offsets=raa_write(offsets,location.segment,(x))))
166 static int want_usage
;
167 static int terminate_after_phase
;
168 int user_nolist
= 0; /* fbk 9/2/00 */
170 static void nasm_fputs(const char *line
, FILE * outfile
)
173 fputs(line
, outfile
);
179 /* Convert a struct tm to a POSIX-style time constant */
180 static int64_t posix_mktime(struct tm
*tm
)
183 int64_t y
= tm
->tm_year
;
185 /* See IEEE 1003.1:2004, section 4.14 */
187 t
= (y
-70)*365 + (y
-69)/4 - (y
-1)/100 + (y
+299)/400;
199 static void define_macros_early(void)
202 struct tm lt
, *lt_p
, gm
, *gm_p
;
205 lt_p
= localtime(&official_compile_time
);
209 strftime(temp
, sizeof temp
, "__DATE__=\"%Y-%m-%d\"", <
);
211 strftime(temp
, sizeof temp
, "__DATE_NUM__=%Y%m%d", <
);
213 strftime(temp
, sizeof temp
, "__TIME__=\"%H:%M:%S\"", <
);
215 strftime(temp
, sizeof temp
, "__TIME_NUM__=%H%M%S", <
);
219 gm_p
= gmtime(&official_compile_time
);
223 strftime(temp
, sizeof temp
, "__UTC_DATE__=\"%Y-%m-%d\"", &gm
);
225 strftime(temp
, sizeof temp
, "__UTC_DATE_NUM__=%Y%m%d", &gm
);
227 strftime(temp
, sizeof temp
, "__UTC_TIME__=\"%H:%M:%S\"", &gm
);
229 strftime(temp
, sizeof temp
, "__UTC_TIME_NUM__=%H%M%S", &gm
);
234 posix_time
= posix_mktime(&gm
);
236 posix_time
= posix_mktime(<
);
241 snprintf(temp
, sizeof temp
, "__POSIX_TIME__=%"PRId64
, posix_time
);
246 static void define_macros_late(void)
250 snprintf(temp
, sizeof(temp
), "__OUTPUT_FORMAT__=%s\n",
255 static void emit_dependencies(StrList
*list
)
261 if (depend_file
&& strcmp(depend_file
, "-")) {
262 deps
= fopen(depend_file
, "w");
264 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
265 "unable to write dependency file `%s'", depend_file
);
272 linepos
= fprintf(deps
, "%s:", depend_target
);
273 for (l
= list
; l
; l
= l
->next
) {
274 len
= strlen(l
->str
);
275 if (linepos
+ len
> 62) {
276 fprintf(deps
, " \\\n ");
279 fprintf(deps
, " %s", l
->str
);
282 fprintf(deps
, "\n\n");
284 for (l
= list
; l
; l
= nl
) {
285 if (depend_emit_phony
)
286 fprintf(deps
, "%s:\n\n", l
->str
);
296 int main(int argc
, char **argv
)
298 StrList
*depend_list
= NULL
, **depend_ptr
;
300 time(&official_compile_time
);
303 want_usage
= terminate_after_phase
= false;
304 report_error
= report_error_gnu
;
310 nasm_set_malloc_error(report_error
);
311 offsets
= raa_init();
312 forwrefs
= saa_init((int32_t)sizeof(struct forwrefinfo
));
315 operating_mode
= op_normal
;
319 register_output_formats();
321 /* Define some macros dependent on the runtime, but not
322 on the command line. */
323 define_macros_early();
325 parse_cmdline(argc
, argv
);
327 if (terminate_after_phase
) {
333 /* If debugging info is disabled, suppress any debug calls */
334 if (!using_debug_info
)
335 ofmt
->current_dfmt
= &null_debug_form
;
338 pp_extra_stdmac(ofmt
->stdmac
);
339 parser_global_info(ofmt
, &location
);
340 eval_global_info(ofmt
, lookup_label
, &location
);
342 /* define some macros dependent of command-line */
343 define_macros_late();
345 depend_ptr
= (depend_file
|| (operating_mode
== op_depend
))
346 ? &depend_list
: NULL
;
348 depend_target
= outname
;
350 switch (operating_mode
) {
355 if (depend_missing_ok
)
356 pp_include_path(NULL
); /* "assume generated" */
358 preproc
->reset(inname
, 0, report_error
, evaluate
, &nasmlist
,
360 if (outname
[0] == '\0')
361 ofmt
->filename(inname
, outname
, report_error
);
363 while ((line
= preproc
->getline()))
372 char *file_name
= NULL
;
373 int32_t prior_linnum
= 0;
377 ofile
= fopen(outname
, "w");
379 report_error(ERR_FATAL
| ERR_NOFILE
,
380 "unable to open output file `%s'",
385 location
.known
= false;
388 preproc
->reset(inname
, 3, report_error
, evaluate
, &nasmlist
,
391 while ((line
= preproc
->getline())) {
393 * We generate %line directives if needed for later programs
395 int32_t linnum
= prior_linnum
+= lineinc
;
396 int altline
= src_get(&linnum
, &file_name
);
398 if (altline
== 1 && lineinc
== 1)
399 nasm_fputs("", ofile
);
401 lineinc
= (altline
!= -1 || lineinc
!= 1);
402 fprintf(ofile
? ofile
: stdout
,
403 "%%line %"PRId32
"+%d %s\n", linnum
, lineinc
,
406 prior_linnum
= linnum
;
408 nasm_fputs(line
, ofile
);
411 nasm_free(file_name
);
415 if (ofile
&& terminate_after_phase
)
423 * We must call ofmt->filename _anyway_, even if the user
424 * has specified their own output file, because some
425 * formats (eg OBJ and COFF) use ofmt->filename to find out
426 * the name of the input file and then put that inside the
429 ofmt
->filename(inname
, outname
, report_error
);
431 ofile
= fopen(outname
, "wb");
433 report_error(ERR_FATAL
| ERR_NOFILE
,
434 "unable to open output file `%s'", outname
);
438 * We must call init_labels() before ofmt->init() since
439 * some object formats will want to define labels in their
440 * init routines. (eg OS/2 defines the FLAT group)
444 ofmt
->init(ofile
, report_error
, define_label
, evaluate
);
446 assemble_file(inname
, depend_ptr
);
448 if (!terminate_after_phase
) {
449 ofmt
->cleanup(using_debug_info
);
453 * Despite earlier comments, we need this fclose.
454 * The object output drivers only fclose on cleanup,
455 * and we just skipped that.
468 emit_dependencies(depend_list
);
478 if (terminate_after_phase
)
485 * Get a parameter for a command line option.
486 * First arg must be in the form of e.g. -f...
488 static char *get_param(char *p
, char *q
, bool *advance
)
491 if (p
[2]) { /* the parameter's in the option */
493 while (nasm_isspace(*p
))
501 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
502 "option `-%c' requires an argument", p
[1]);
509 static void copy_filename(char *dst
, const char *src
)
511 size_t len
= strlen(src
);
513 if (len
>= (size_t)FILENAME_MAX
) {
514 report_error(ERR_FATAL
| ERR_NOFILE
, "file name too long");
517 strncpy(dst
, src
, FILENAME_MAX
);
521 * Convert a string to Make-safe form
523 static char *quote_for_make(const char *str
)
528 size_t n
= 1; /* Terminating zero */
534 for (p
= str
; *p
; p
++) {
538 /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
558 /* Convert N backslashes at the end of filename to 2N backslashes */
562 os
= q
= nasm_malloc(n
);
565 for (p
= str
; *p
; p
++) {
608 #define OPT_POSTFIX 1
609 struct textargs textopts
[] = {
610 {"prefix", OPT_PREFIX
},
611 {"postfix", OPT_POSTFIX
},
615 static bool stopoptions
= false;
616 static bool process_arg(char *p
, char *q
)
620 bool advance
= false;
626 if (p
[0] == '-' && !stopoptions
) {
627 if (strchr("oOfpPdDiIlFXuUZwW", p
[1])) {
628 /* These parameters take values */
629 if (!(param
= get_param(p
, q
, &advance
)))
638 case 'o': /* output file */
639 copy_filename(outname
, param
);
642 case 'f': /* output format */
643 ofmt
= ofmt_find(param
);
645 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
646 "unrecognised output format `%s' - "
647 "use -hf for a list", param
);
649 ofmt
->current_dfmt
= ofmt
->debug_formats
[0];
653 case 'O': /* Optimization level */
658 /* Naked -O == -Ox */
659 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
663 case '0': case '1': case '2': case '3': case '4':
664 case '5': case '6': case '7': case '8': case '9':
665 opt
= strtoul(param
, ¶m
, 10);
667 /* -O0 -> optimizing == -1, 0.98 behaviour */
668 /* -O1 -> optimizing == 0, 0.98.09 behaviour */
670 optimizing
= opt
- 1;
678 opt_verbose_info
= true;
683 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
687 report_error(ERR_FATAL
,
688 "unknown optimization option -O%c\n",
697 case 'p': /* pre-include */
699 pp_pre_include(param
);
702 case 'd': /* pre-define */
704 pp_pre_define(param
);
707 case 'u': /* un-define */
709 pp_pre_undefine(param
);
712 case 'i': /* include search path */
714 pp_include_path(param
);
717 case 'l': /* listing file */
718 copy_filename(listname
, param
);
721 case 'Z': /* error messages file */
722 strcpy(errname
, param
);
725 case 'F': /* specify debug format */
726 ofmt
->current_dfmt
= dfmt_find(ofmt
, param
);
727 if (!ofmt
->current_dfmt
) {
728 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
729 "unrecognized debug format `%s' for"
730 " output format `%s'",
731 param
, ofmt
->shortname
);
733 using_debug_info
= true;
736 case 'X': /* specify error reporting format */
737 if (nasm_stricmp("vc", param
) == 0)
738 report_error
= report_error_vc
;
739 else if (nasm_stricmp("gnu", param
) == 0)
740 report_error
= report_error_gnu
;
742 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
743 "unrecognized error reporting format `%s'",
748 using_debug_info
= true;
753 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
755 " [options...] [--] filename\n"
756 " or nasm -v for version info\n\n"
757 " -t assemble in SciTech TASM compatible mode\n"
758 " -g generate debug information in selected format.\n");
760 (" -E (or -e) preprocess only (writes output to stdout by default)\n"
761 " -a don't preprocess (assemble only)\n"
762 " -M generate Makefile dependencies on stdout\n"
763 " -MG d:o, missing files assumed generated\n\n"
764 " -Z<file> redirect error messages to file\n"
765 " -s redirect error messages to stdout\n\n"
766 " -F format select a debugging format\n\n"
767 " -I<path> adds a pathname to the include file path\n");
769 (" -O<digit> optimize branch offsets (-O0 disables, default)\n"
770 " -P<file> pre-includes a file\n"
771 " -D<macro>[=<value>] pre-defines a macro\n"
772 " -U<macro> undefines a macro\n"
773 " -X<format> specifies error reporting format (gnu or vc)\n"
774 " -w+foo enables warning foo (equiv. -Wfoo)\n"
775 " -w-foo disable warning foo (equiv. -Wno-foo)\n"
777 for (i
= 0; i
<= ERR_WARN_MAX
; i
++)
778 printf(" %-23s %s (default %s)\n",
779 suppressed_names
[i
], suppressed_what
[i
],
780 suppressed_global
[i
] ? "off" : "on");
782 ("\nresponse files should contain command line parameters"
783 ", one per line.\n");
785 printf("\nvalid output formats for -f are"
786 " (`*' denotes default):\n");
787 ofmt_list(ofmt
, stdout
);
789 printf("\nFor a list of valid output formats, use -hf.\n");
790 printf("For a list of debug formats, use -f <form> -y.\n");
792 exit(0); /* never need usage message here */
796 printf("\nvalid debug formats for '%s' output format are"
797 " ('*' denotes default):\n", ofmt
->shortname
);
798 dfmt_list(ofmt
, stdout
);
803 tasm_compatible_mode
= true;
808 const char *nasm_version_string
=
809 "NASM version " NASM_VER
" compiled on " __DATE__
814 puts(nasm_version_string
);
815 exit(0); /* never need usage message here */
819 case 'e': /* preprocess only */
821 operating_mode
= op_preprocess
;
824 case 'a': /* assemble only - don't preprocess */
829 if (param
[0] == 'n' && param
[1] == 'o' && param
[2] == '-') {
838 if (param
[0] != '+' && param
[0] != '-') {
839 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
840 "invalid option to `-w'");
843 suppress
= (param
[0] == '-');
847 for (i
= 0; i
<= ERR_WARN_MAX
; i
++)
848 if (!nasm_stricmp(param
, suppressed_names
[i
]))
850 if (i
<= ERR_WARN_MAX
)
851 suppressed_global
[i
] = suppress
;
852 else if (!nasm_stricmp(param
, "all"))
853 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
854 suppressed_global
[i
] = suppress
;
855 else if (!nasm_stricmp(param
, "none"))
856 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
857 suppressed_global
[i
] = !suppress
;
859 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
860 "invalid warning `%s'", param
);
866 operating_mode
= op_depend
;
869 operating_mode
= op_depend
;
870 depend_missing_ok
= true;
873 depend_emit_phony
= true;
884 depend_target
= quote_for_make(q
);
888 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
889 "unknown dependency option `-M%c'", p
[2]);
892 if (advance
&& (!q
|| !q
[0])) {
893 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
894 "option `-M%c' requires a parameter", p
[2]);
903 if (p
[2] == 0) { /* -- => stop processing options */
907 for (s
= 0; textopts
[s
].label
; s
++) {
908 if (!nasm_stricmp(p
+ 2, textopts
[s
].label
)) {
919 report_error(ERR_NONFATAL
| ERR_NOFILE
|
921 "option `--%s' requires an argument",
925 advance
= 1, param
= q
;
928 if (s
== OPT_PREFIX
) {
929 strncpy(lprefix
, param
, PREFIX_MAX
- 1);
930 lprefix
[PREFIX_MAX
- 1] = 0;
933 if (s
== OPT_POSTFIX
) {
934 strncpy(lpostfix
, param
, POSTFIX_MAX
- 1);
935 lpostfix
[POSTFIX_MAX
- 1] = 0;
942 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
943 "unrecognised option `--%s'", p
+ 2);
951 if (!ofmt
->setinfo(GI_SWITCH
, &p
))
952 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
953 "unrecognised option `-%c'", p
[1]);
958 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
959 "more than one input file specified");
961 copy_filename(inname
, p
);
968 #define ARG_BUF_DELTA 128
970 static void process_respfile(FILE * rfile
)
972 char *buffer
, *p
, *q
, *prevarg
;
973 int bufsize
, prevargsize
;
975 bufsize
= prevargsize
= ARG_BUF_DELTA
;
976 buffer
= nasm_malloc(ARG_BUF_DELTA
);
977 prevarg
= nasm_malloc(ARG_BUF_DELTA
);
980 while (1) { /* Loop to handle all lines in file */
982 while (1) { /* Loop to handle long lines */
983 q
= fgets(p
, bufsize
- (p
- buffer
), rfile
);
987 if (p
> buffer
&& p
[-1] == '\n')
989 if (p
- buffer
> bufsize
- 10) {
992 bufsize
+= ARG_BUF_DELTA
;
993 buffer
= nasm_realloc(buffer
, bufsize
);
998 if (!q
&& p
== buffer
) {
1000 process_arg(prevarg
, NULL
);
1007 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1008 * them are present at the end of the line.
1010 *(p
= &buffer
[strcspn(buffer
, "\r\n\032")]) = '\0';
1012 while (p
> buffer
&& nasm_isspace(p
[-1]))
1016 while (nasm_isspace(*p
))
1019 if (process_arg(prevarg
, p
))
1022 if ((int) strlen(p
) > prevargsize
- 10) {
1023 prevargsize
+= ARG_BUF_DELTA
;
1024 prevarg
= nasm_realloc(prevarg
, prevargsize
);
1026 strncpy(prevarg
, p
, prevargsize
);
1030 /* Function to process args from a string of args, rather than the
1031 * argv array. Used by the environment variable and response file
1034 static void process_args(char *args
)
1036 char *p
, *q
, *arg
, *prevarg
;
1037 char separator
= ' ';
1040 if (*p
&& *p
!= '-')
1045 while (*p
&& *p
!= separator
)
1047 while (*p
== separator
)
1051 if (process_arg(prevarg
, arg
))
1055 process_arg(arg
, NULL
);
1058 static void process_response_file(const char *file
)
1061 FILE *f
= fopen(file
, "r");
1066 while (fgets(str
, sizeof str
, f
)) {
1072 static void parse_cmdline(int argc
, char **argv
)
1075 char *envreal
, *envcopy
= NULL
, *p
, *arg
;
1077 *inname
= *outname
= *listname
= *errname
= '\0';
1080 * First, process the NASMENV environment variable.
1082 envreal
= getenv("NASMENV");
1085 envcopy
= nasm_strdup(envreal
);
1086 process_args(envcopy
);
1091 * Now process the actual command line.
1096 if (argv
[0][0] == '@') {
1097 /* We have a response file, so process this as a set of
1098 * arguments like the environment variable. This allows us
1099 * to have multiple arguments on a single line, which is
1100 * different to the -@resp file processing below for regular
1103 process_response_file(argv
[0]+1);
1107 if (!stopoptions
&& argv
[0][0] == '-' && argv
[0][1] == '@') {
1108 p
= get_param(argv
[0], argc
> 1 ? argv
[1] : NULL
, &advance
);
1110 rfile
= fopen(p
, "r");
1112 process_respfile(rfile
);
1115 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
1116 "unable to open response file `%s'", p
);
1119 advance
= process_arg(argv
[0], argc
> 1 ? argv
[1] : NULL
);
1120 argv
+= advance
, argc
-= advance
;
1123 /* Look for basic command line typos. This definitely doesn't
1124 catch all errors, but it might help cases of fumbled fingers. */
1126 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
1127 "no input file specified");
1128 else if (!strcmp(inname
, errname
) ||
1129 !strcmp(inname
, outname
) ||
1130 !strcmp(inname
, listname
) ||
1131 (depend_file
&& !strcmp(inname
, depend_file
)))
1132 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
1133 "file `%s' is both input and output file",
1137 error_file
= fopen(errname
, "w");
1139 error_file
= stderr
; /* Revert to default! */
1140 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
1141 "cannot open file `%s' for error messages",
1147 /* List of directives */
1149 D_NONE
, D_ABSOLUTE
, D_BITS
, D_COMMON
, D_CPU
, D_DEBUG
, D_DEFAULT
,
1150 D_EXTERN
, D_FLOAT
, D_GLOBAL
, D_LIST
, D_SECTION
, D_SEGMENT
, D_WARNING
1152 static const char *directives
[] = {
1153 "", "absolute", "bits", "common", "cpu", "debug", "default",
1154 "extern", "float", "global", "list", "section", "segment", "warning"
1156 static enum directives
getkw(char **directive
, char **value
);
1158 static void assemble_file(char *fname
, StrList
**depend_ptr
)
1160 char *directive
, *value
, *p
, *q
, *special
, *line
, debugid
[80];
1166 struct tokenval tokval
;
1170 if (cmd_sb
== 32 && cmd_cpu
< IF_386
)
1171 report_error(ERR_FATAL
, "command line: "
1172 "32-bit segment size requires a higher cpu");
1174 pass_max
= prev_offset_changed
= (INT_MAX
>> 1) + 2; /* Almost unlimited */
1175 for (passn
= 1; pass0
<= 2; passn
++) {
1179 pass1
= pass0
== 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
1180 pass2
= passn
> 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
1181 /* pass0 0, 0, 0, ..., 1, 2 */
1183 def_label
= passn
> 1 ? redefine_label
: define_label
;
1185 globalbits
= sb
= cmd_sb
; /* set 'bits' to command line default */
1189 nasmlist
.init(listname
, report_error
);
1192 global_offset_changed
= 0; /* set by redefine_label */
1193 location
.segment
= ofmt
->section(NULL
, pass2
, &sb
);
1196 saa_rewind(forwrefs
);
1197 forwref
= saa_rstruct(forwrefs
);
1199 offsets
= raa_init();
1201 preproc
->reset(fname
, pass1
, report_error
, evaluate
, &nasmlist
,
1202 pass1
== 2 ? depend_ptr
: NULL
);
1203 memcpy(suppressed
, suppressed_global
, (ERR_WARN_MAX
+1) * sizeof(bool));
1207 location
.known
= true;
1208 location
.offset
= offs
= GET_CURR_OFFS
;
1210 while ((line
= preproc
->getline())) {
1214 /* here we parse our directives; this is not handled by the 'real'
1217 d
= getkw(&directive
, &value
);
1222 case D_SEGMENT
: /* [SEGMENT n] */
1224 seg
= ofmt
->section(value
, pass2
, &sb
);
1225 if (seg
== NO_SEG
) {
1226 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1227 "segment name `%s' not recognized",
1231 location
.segment
= seg
;
1234 case D_EXTERN
: /* [EXTERN label:special] */
1236 value
++; /* skip initial $ if present */
1239 while (*q
&& *q
!= ':')
1243 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1245 } else if (passn
== 1) {
1250 while (*q
&& *q
!= ':') {
1256 report_error(ERR_NONFATAL
,
1257 "identifier expected after EXTERN");
1265 if (!is_extern(value
)) { /* allow re-EXTERN to be ignored */
1267 pass0
= 1; /* fake pass 1 in labels.c */
1268 declare_as_global(value
, special
,
1270 define_label(value
, seg_alloc(), 0L, NULL
,
1271 false, true, ofmt
, report_error
);
1274 } /* else pass0 == 1 */
1276 case D_BITS
: /* [BITS bits] */
1277 globalbits
= sb
= get_bits(value
);
1279 case D_GLOBAL
: /* [GLOBAL symbol:special] */
1281 value
++; /* skip initial $ if present */
1282 if (pass0
== 2) { /* pass 2 */
1284 while (*q
&& *q
!= ':')
1288 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1290 } else if (pass2
== 1) { /* pass == 1 */
1295 while (*q
&& *q
!= ':') {
1301 report_error(ERR_NONFATAL
,
1302 "identifier expected after GLOBAL");
1310 declare_as_global(value
, special
, report_error
);
1313 case D_COMMON
: /* [COMMON symbol size:special] */
1315 value
++; /* skip initial $ if present */
1321 while (*p
&& !nasm_isspace(*p
)) {
1327 report_error(ERR_NONFATAL
,
1328 "identifier expected after COMMON");
1334 while (*p
&& nasm_isspace(*p
))
1337 while (*q
&& *q
!= ':')
1344 size
= readnum(p
, &rn_error
);
1346 report_error(ERR_NONFATAL
,
1347 "invalid size specified"
1348 " in COMMON declaration");
1350 define_common(value
, seg_alloc(), size
,
1351 special
, ofmt
, report_error
);
1353 report_error(ERR_NONFATAL
,
1354 "no size specified in"
1355 " COMMON declaration");
1356 } else if (pass0
== 2) { /* pass == 2 */
1358 while (*q
&& *q
!= ':') {
1359 if (nasm_isspace(*q
))
1365 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1369 case D_ABSOLUTE
: /* [ABSOLUTE address] */
1371 stdscan_bufptr
= value
;
1372 tokval
.t_type
= TOKEN_INVALID
;
1373 e
= evaluate(stdscan
, NULL
, &tokval
, NULL
, pass2
,
1374 report_error
, NULL
);
1377 report_error(pass0
==
1378 1 ? ERR_NONFATAL
: ERR_PANIC
,
1379 "cannot use non-relocatable expression as "
1380 "ABSOLUTE address");
1382 abs_seg
= reloc_seg(e
);
1383 abs_offset
= reloc_value(e
);
1385 } else if (passn
== 1)
1386 abs_offset
= 0x100; /* don't go near zero in case of / */
1388 report_error(ERR_PANIC
, "invalid ABSOLUTE address "
1391 location
.segment
= NO_SEG
;
1393 case D_DEBUG
: /* [DEBUG] */
1399 while (*p
&& !nasm_isspace(*p
)) {
1406 report_error(passn
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1407 "identifier expected after DEBUG");
1410 while (*p
&& nasm_isspace(*p
))
1413 ofmt
->current_dfmt
->debug_directive(debugid
, p
);
1415 case D_WARNING
: /* [WARNING {+|-|*}warn-name] */
1417 while (*value
&& nasm_isspace(*value
))
1421 case '-': validid
= 0; value
++; break;
1422 case '+': validid
= 1; value
++; break;
1423 case '*': validid
= 2; value
++; break;
1425 * Should this error out?
1426 * I'll keep it so nothing breaks.
1431 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
1432 if (!nasm_stricmp(value
, suppressed_names
[i
]))
1434 if (i
<= ERR_WARN_MAX
) {
1436 case 0: suppressed
[i
] = true; break;
1437 case 1: suppressed
[i
] = false; break;
1438 case 2: suppressed
[i
] = suppressed_global
[i
];
1443 report_error(ERR_NONFATAL
,
1444 "invalid warning id in WARNING directive");
1447 case D_CPU
: /* [CPU] */
1448 cpu
= get_cpu(value
);
1450 case D_LIST
: /* [LIST {+|-}] */
1451 while (*value
&& nasm_isspace(*value
))
1454 if (*value
== '+') {
1457 if (*value
== '-') {
1464 case D_DEFAULT
: /* [DEFAULT] */
1466 stdscan_bufptr
= value
;
1467 tokval
.t_type
= TOKEN_INVALID
;
1468 if (stdscan(NULL
, &tokval
) == TOKEN_SPECIAL
) {
1469 switch ((int)tokval
.t_integer
) {
1485 if (float_option(value
)) {
1486 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1487 "unknown 'float' directive: %s",
1492 if (!ofmt
->directive(directive
, value
, pass2
))
1493 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1494 "unrecognised directive [%s]",
1498 report_error(ERR_NONFATAL
,
1499 "invalid parameter to [%s] directive",
1502 } else { /* it isn't a directive */
1504 parse_line(pass1
, line
, &output_ins
,
1505 report_error
, evaluate
, def_label
);
1507 if (optimizing
> 0) {
1508 if (forwref
!= NULL
&& globallineno
== forwref
->lineno
) {
1509 output_ins
.forw_ref
= true;
1511 output_ins
.oprs
[forwref
->operand
].opflags
|=
1513 forwref
= saa_rstruct(forwrefs
);
1514 } while (forwref
!= NULL
1515 && forwref
->lineno
== globallineno
);
1517 output_ins
.forw_ref
= false;
1520 if (optimizing
> 0) {
1522 for (i
= 0; i
< output_ins
.operands
; i
++) {
1523 if (output_ins
.oprs
[i
].
1524 opflags
& OPFLAG_FORWARD
) {
1525 struct forwrefinfo
*fwinf
=
1526 (struct forwrefinfo
*)
1527 saa_wstruct(forwrefs
);
1528 fwinf
->lineno
= globallineno
;
1536 if (output_ins
.opcode
== I_EQU
) {
1539 * Special `..' EQUs get processed in pass two,
1540 * except `..@' macro-processor EQUs which are done
1541 * in the normal place.
1543 if (!output_ins
.label
)
1544 report_error(ERR_NONFATAL
,
1545 "EQU not preceded by label");
1547 else if (output_ins
.label
[0] != '.' ||
1548 output_ins
.label
[1] != '.' ||
1549 output_ins
.label
[2] == '@') {
1550 if (output_ins
.operands
== 1 &&
1551 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
1552 output_ins
.oprs
[0].wrt
== NO_SEG
) {
1555 opflags
& OPFLAG_EXTERN
;
1556 def_label(output_ins
.label
,
1557 output_ins
.oprs
[0].segment
,
1558 output_ins
.oprs
[0].offset
, NULL
,
1561 } else if (output_ins
.operands
== 2
1562 && (output_ins
.oprs
[0].
1564 && (output_ins
.oprs
[0].type
& COLON
)
1565 && output_ins
.oprs
[0].segment
==
1567 && output_ins
.oprs
[0].wrt
== NO_SEG
1568 && (output_ins
.oprs
[1].
1570 && output_ins
.oprs
[1].segment
==
1572 && output_ins
.oprs
[1].wrt
==
1574 def_label(output_ins
.label
,
1577 output_ins
.oprs
[1].offset
, NULL
,
1581 report_error(ERR_NONFATAL
,
1582 "bad syntax for EQU");
1586 * Special `..' EQUs get processed here, except
1587 * `..@' macro processor EQUs which are done above.
1589 if (output_ins
.label
[0] == '.' &&
1590 output_ins
.label
[1] == '.' &&
1591 output_ins
.label
[2] != '@') {
1592 if (output_ins
.operands
== 1 &&
1593 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
1594 define_label(output_ins
.label
,
1595 output_ins
.oprs
[0].segment
,
1596 output_ins
.oprs
[0].offset
,
1597 NULL
, false, false, ofmt
,
1599 } else if (output_ins
.operands
== 2
1600 && (output_ins
.oprs
[0].
1602 && (output_ins
.oprs
[0].type
& COLON
)
1603 && output_ins
.oprs
[0].segment
==
1605 && (output_ins
.oprs
[1].
1607 && output_ins
.oprs
[1].segment
==
1609 define_label(output_ins
.label
,
1612 output_ins
.oprs
[1].offset
,
1613 NULL
, false, false, ofmt
,
1616 report_error(ERR_NONFATAL
,
1617 "bad syntax for EQU");
1620 } else { /* instruction isn't an EQU */
1624 int64_t l
= insn_size(location
.segment
, offs
, sb
, cpu
,
1625 &output_ins
, report_error
);
1627 /* if (using_debug_info) && output_ins.opcode != -1) */
1628 if (using_debug_info
)
1629 { /* fbk 03/25/01 */
1630 /* this is done here so we can do debug type info */
1632 TYS_ELEMENTS(output_ins
.operands
);
1633 switch (output_ins
.opcode
) {
1636 TYS_ELEMENTS(output_ins
.oprs
[0].
1641 TYS_ELEMENTS(output_ins
.oprs
[0].
1646 TYS_ELEMENTS(output_ins
.oprs
[0].
1651 TYS_ELEMENTS(output_ins
.oprs
[0].
1656 TYS_ELEMENTS(output_ins
.oprs
[0].
1661 TYS_ELEMENTS(output_ins
.oprs
[0].
1666 TYS_ELEMENTS(output_ins
.oprs
[0].
1670 typeinfo
|= TY_BYTE
;
1673 typeinfo
|= TY_WORD
;
1676 if (output_ins
.eops_float
)
1677 typeinfo
|= TY_FLOAT
;
1679 typeinfo
|= TY_DWORD
;
1682 typeinfo
|= TY_QWORD
;
1685 typeinfo
|= TY_TBYTE
;
1688 typeinfo
|= TY_OWORD
;
1691 typeinfo
|= TY_YWORD
;
1694 typeinfo
= TY_LABEL
;
1698 ofmt
->current_dfmt
->debug_typevalue(typeinfo
);
1703 SET_CURR_OFFS(offs
);
1706 * else l == -1 => invalid instruction, which will be
1707 * flagged as an error on pass 2
1711 offs
+= assemble(location
.segment
, offs
, sb
, cpu
,
1712 &output_ins
, ofmt
, report_error
,
1714 SET_CURR_OFFS(offs
);
1718 cleanup_insn(&output_ins
);
1721 location
.offset
= offs
= GET_CURR_OFFS
;
1722 } /* end while (line = preproc->getline... */
1723 if (pass1
== 2 && global_offset_changed
)
1724 report_error(ERR_NONFATAL
,
1725 "phase error detected at end of assembly.");
1728 preproc
->cleanup(1);
1730 if (pass1
== 1 && terminate_after_phase
) {
1738 if (passn
> 1 && !global_offset_changed
)
1740 else if (global_offset_changed
&& global_offset_changed
< prev_offset_changed
) {
1741 prev_offset_changed
= global_offset_changed
;
1746 if((stall_count
> 997) || (passn
>= pass_max
))
1747 /* We get here if the labels don't converge
1748 * Example: FOO equ FOO + 1
1750 report_error(ERR_NONFATAL
,
1751 "Can't find valid values for all labels "
1752 "after %d passes, giving up.\n"
1753 " Possible cause: recursive equ's.", passn
);
1756 preproc
->cleanup(0);
1758 if (opt_verbose_info
) /* -On and -Ov switches */
1760 "info:: assembly required 1+%d+1 passes\n", passn
-3);
1761 } /* exit from assemble_file (...) */
1763 static enum directives
getkw(char **directive
, char **value
)
1769 /* allow leading spaces or tabs */
1770 while (*buf
== ' ' || *buf
== '\t')
1778 while (*p
&& *p
!= ']')
1786 while (*p
&& *p
!= ';') {
1787 if (!nasm_isspace(*p
))
1793 *directive
= p
= buf
+ 1;
1794 while (*buf
&& *buf
!= ' ' && *buf
!= ']' && *buf
!= '\t')
1801 while (nasm_isspace(*buf
))
1802 buf
++; /* beppu - skip leading whitespace */
1809 return bsii(*directive
, directives
, elements(directives
));
1813 * gnu style error reporting
1814 * This function prints an error message to error_file in the
1815 * style used by GNU. An example would be:
1816 * file.asm:50: error: blah blah blah
1817 * where file.asm is the name of the file, 50 is the line number on
1818 * which the error occurs (or is detected) and "error:" is one of
1819 * the possible optional diagnostics -- it can be "error" or "warning"
1820 * or something else. Finally the line terminates with the actual
1823 * @param severity the severity of the warning or error
1824 * @param fmt the printf style format string
1826 static void report_error_gnu(int severity
, const char *fmt
, ...)
1830 if (is_suppressed_warning(severity
))
1833 if (severity
& ERR_NOFILE
)
1834 fputs("nasm: ", error_file
);
1836 char *currentfile
= NULL
;
1838 src_get(&lineno
, ¤tfile
);
1839 fprintf(error_file
, "%s:%"PRId32
": ", currentfile
, lineno
);
1840 nasm_free(currentfile
);
1843 report_error_common(severity
, fmt
, ap
);
1848 * MS style error reporting
1849 * This function prints an error message to error_file in the
1850 * style used by Visual C and some other Microsoft tools. An example
1852 * file.asm(50) : error: blah blah blah
1853 * where file.asm is the name of the file, 50 is the line number on
1854 * which the error occurs (or is detected) and "error:" is one of
1855 * the possible optional diagnostics -- it can be "error" or "warning"
1856 * or something else. Finally the line terminates with the actual
1859 * @param severity the severity of the warning or error
1860 * @param fmt the printf style format string
1862 static void report_error_vc(int severity
, const char *fmt
, ...)
1866 if (is_suppressed_warning(severity
))
1869 if (severity
& ERR_NOFILE
)
1870 fputs("nasm: ", error_file
);
1872 char *currentfile
= NULL
;
1874 src_get(&lineno
, ¤tfile
);
1875 fprintf(error_file
, "%s(%"PRId32
") : ", currentfile
, lineno
);
1876 nasm_free(currentfile
);
1879 report_error_common(severity
, fmt
, ap
);
1884 * check for supressed warning
1885 * checks for suppressed warning or pass one only warning and we're
1888 * @param severity the severity of the warning or error
1889 * @return true if we should abort error/warning printing
1891 static bool is_suppressed_warning(int severity
)
1894 * See if it's a suppressed warning.
1896 return (severity
& ERR_MASK
) == ERR_WARNING
&&
1897 (((severity
& ERR_WARN_MASK
) != 0 &&
1898 suppressed
[(severity
& ERR_WARN_MASK
) >> ERR_WARN_SHR
]) ||
1899 /* See if it's a pass-one only warning and we're not in pass one. */
1900 ((severity
& ERR_PASS1
) && pass0
!= 1));
1904 * common error reporting
1905 * This is the common back end of the error reporting schemes currently
1906 * implemented. It prints the nature of the warning and then the
1907 * specific error message to error_file and may or may not return. It
1908 * doesn't return if the error severity is a "panic" or "debug" type.
1910 * @param severity the severity of the warning or error
1911 * @param fmt the printf style format string
1913 static void report_error_common(int severity
, const char *fmt
,
1916 switch (severity
& (ERR_MASK
|ERR_NO_SEVERITY
)) {
1918 fputs("warning: ", error_file
);
1921 fputs("error: ", error_file
);
1924 fputs("fatal: ", error_file
);
1927 fputs("panic: ", error_file
);
1930 fputs("debug: ", error_file
);
1936 vfprintf(error_file
, fmt
, args
);
1937 putc('\n', error_file
);
1939 if (severity
& ERR_USAGE
)
1942 switch (severity
& ERR_MASK
) {
1944 /* no further action, by definition */
1947 if (!suppressed
[0]) /* Treat warnings as errors */
1948 terminate_after_phase
= true;
1951 terminate_after_phase
= true;
1960 exit(1); /* instantly die */
1961 break; /* placate silly compilers */
1964 /* abort(); *//* halt, catch fire, and dump core */
1970 static void usage(void)
1972 fputs("type `nasm -h' for help\n", error_file
);
1975 static void register_output_formats(void)
1977 ofmt
= ofmt_register(report_error
);
1980 #define BUF_DELTA 512
1982 static FILE *no_pp_fp
;
1983 static efunc no_pp_err
;
1984 static ListGen
*no_pp_list
;
1985 static int32_t no_pp_lineinc
;
1987 static void no_pp_reset(char *file
, int pass
, efunc error
, evalfunc eval
,
1988 ListGen
* listgen
, StrList
**deplist
)
1990 src_set_fname(nasm_strdup(file
));
1994 no_pp_fp
= fopen(file
, "r");
1996 no_pp_err(ERR_FATAL
| ERR_NOFILE
,
1997 "unable to open input file `%s'", file
);
1998 no_pp_list
= listgen
;
1999 (void)pass
; /* placate compilers */
2000 (void)eval
; /* placate compilers */
2003 StrList
*sl
= nasm_malloc(strlen(file
)+1+sizeof sl
->next
);
2005 strcpy(sl
->str
, file
);
2010 static char *no_pp_getline(void)
2012 char *buffer
, *p
, *q
;
2015 bufsize
= BUF_DELTA
;
2016 buffer
= nasm_malloc(BUF_DELTA
);
2017 src_set_linnum(src_get_linnum() + no_pp_lineinc
);
2019 while (1) { /* Loop to handle %line */
2022 while (1) { /* Loop to handle long lines */
2023 q
= fgets(p
, bufsize
- (p
- buffer
), no_pp_fp
);
2027 if (p
> buffer
&& p
[-1] == '\n')
2029 if (p
- buffer
> bufsize
- 10) {
2031 offset
= p
- buffer
;
2032 bufsize
+= BUF_DELTA
;
2033 buffer
= nasm_realloc(buffer
, bufsize
);
2034 p
= buffer
+ offset
;
2038 if (!q
&& p
== buffer
) {
2044 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
2045 * them are present at the end of the line.
2047 buffer
[strcspn(buffer
, "\r\n\032")] = '\0';
2049 if (!nasm_strnicmp(buffer
, "%line", 5)) {
2052 char *nm
= nasm_malloc(strlen(buffer
));
2053 if (sscanf(buffer
+ 5, "%"PRId32
"+%d %s", &ln
, &li
, nm
) == 3) {
2054 nasm_free(src_set_fname(nm
));
2064 no_pp_list
->line(LIST_READ
, buffer
);
2069 static void no_pp_cleanup(int pass
)
2071 (void)pass
; /* placate GCC */
2075 static uint32_t get_cpu(char *value
)
2077 if (!strcmp(value
, "8086"))
2079 if (!strcmp(value
, "186"))
2081 if (!strcmp(value
, "286"))
2083 if (!strcmp(value
, "386"))
2085 if (!strcmp(value
, "486"))
2087 if (!strcmp(value
, "586") || !nasm_stricmp(value
, "pentium"))
2089 if (!strcmp(value
, "686") ||
2090 !nasm_stricmp(value
, "ppro") ||
2091 !nasm_stricmp(value
, "pentiumpro") || !nasm_stricmp(value
, "p2"))
2093 if (!nasm_stricmp(value
, "p3") || !nasm_stricmp(value
, "katmai"))
2095 if (!nasm_stricmp(value
, "p4") || /* is this right? -- jrc */
2096 !nasm_stricmp(value
, "willamette"))
2097 return IF_WILLAMETTE
;
2098 if (!nasm_stricmp(value
, "prescott"))
2100 if (!nasm_stricmp(value
, "x64") ||
2101 !nasm_stricmp(value
, "x86-64"))
2103 if (!nasm_stricmp(value
, "ia64") ||
2104 !nasm_stricmp(value
, "ia-64") ||
2105 !nasm_stricmp(value
, "itanium") ||
2106 !nasm_stricmp(value
, "itanic") || !nasm_stricmp(value
, "merced"))
2109 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2110 "unknown 'cpu' type");
2112 return IF_PLEVEL
; /* the maximum level */
2115 static int get_bits(char *value
)
2119 if ((i
= atoi(value
)) == 16)
2120 return i
; /* set for a 16-bit segment */
2123 report_error(ERR_NONFATAL
,
2124 "cannot specify 32-bit segment on processor below a 386");
2127 } else if (i
== 64) {
2128 if (cpu
< IF_X86_64
) {
2129 report_error(ERR_NONFATAL
,
2130 "cannot specify 64-bit segment on processor below an x86-64");
2134 report_error(ERR_NONFATAL
,
2135 "%s output format does not support 64-bit code",
2140 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2141 "`%s' is not a valid segment size; must be 16, 32 or 64",