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
113 * The option names for the suppressible warnings. As before, entry
116 static const char *suppressed_names
[ERR_WARN_MAX
+1] = {
117 "error", "macro-params", "macro-selfref", "macro-defaults",
118 "orphan-labels", "number-overflow", "gnu-elf-extensions",
119 "float-overflow", "float-denorm", "float-underflow", "float-toolong"
123 * The explanations for the suppressible warnings. As before, entry
126 static const char *suppressed_what
[ERR_WARN_MAX
+1] = {
127 "treat warnings as errors",
128 "macro calls with wrong parameter count",
129 "cyclic macro references",
130 "macros with more default than optional parameters",
131 "labels alone on lines without trailing `:'",
132 "numeric constants does not fit in 64 bits",
133 "using 8- or 16-bit relocation in ELF32, a GNU extension",
134 "floating point overflow",
135 "floating point denormal",
136 "floating point underflow",
137 "too many digits in floating-point number"
141 * This is a null preprocessor which just copies lines from input
142 * to output. It's used when someone explicitly requests that NASM
143 * not preprocess their source file.
146 static void no_pp_reset(char *, int, efunc
, evalfunc
, ListGen
*, StrList
**);
147 static char *no_pp_getline(void);
148 static void no_pp_cleanup(int);
149 static Preproc no_pp
= {
156 * get/set current offset...
158 #define GET_CURR_OFFS (in_abs_seg?abs_offset:\
159 raa_read(offsets,location.segment))
160 #define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
161 (void)(offsets=raa_write(offsets,location.segment,(x))))
163 static int want_usage
;
164 static int terminate_after_phase
;
165 int user_nolist
= 0; /* fbk 9/2/00 */
167 static void nasm_fputs(const char *line
, FILE * outfile
)
170 fputs(line
, outfile
);
176 /* Convert a struct tm to a POSIX-style time constant */
177 static int64_t posix_mktime(struct tm
*tm
)
180 int64_t y
= tm
->tm_year
;
182 /* See IEEE 1003.1:2004, section 4.14 */
184 t
= (y
-70)*365 + (y
-69)/4 - (y
-1)/100 + (y
+299)/400;
196 static void define_macros_early(void)
199 struct tm lt
, *lt_p
, gm
, *gm_p
;
202 lt_p
= localtime(&official_compile_time
);
206 strftime(temp
, sizeof temp
, "__DATE__=\"%Y-%m-%d\"", <
);
208 strftime(temp
, sizeof temp
, "__DATE_NUM__=%Y%m%d", <
);
210 strftime(temp
, sizeof temp
, "__TIME__=\"%H:%M:%S\"", <
);
212 strftime(temp
, sizeof temp
, "__TIME_NUM__=%H%M%S", <
);
216 gm_p
= gmtime(&official_compile_time
);
220 strftime(temp
, sizeof temp
, "__UTC_DATE__=\"%Y-%m-%d\"", &gm
);
222 strftime(temp
, sizeof temp
, "__UTC_DATE_NUM__=%Y%m%d", &gm
);
224 strftime(temp
, sizeof temp
, "__UTC_TIME__=\"%H:%M:%S\"", &gm
);
226 strftime(temp
, sizeof temp
, "__UTC_TIME_NUM__=%H%M%S", &gm
);
231 posix_time
= posix_mktime(&gm
);
233 posix_time
= posix_mktime(<
);
238 snprintf(temp
, sizeof temp
, "__POSIX_TIME__=%"PRId64
, posix_time
);
243 static void define_macros_late(void)
247 snprintf(temp
, sizeof(temp
), "__OUTPUT_FORMAT__=%s\n",
252 static void emit_dependencies(StrList
*list
)
258 if (depend_file
&& strcmp(depend_file
, "-")) {
259 deps
= fopen(depend_file
, "w");
261 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
262 "unable to write dependency file `%s'", depend_file
);
269 linepos
= fprintf(deps
, "%s:", depend_target
);
270 for (l
= list
; l
; l
= l
->next
) {
271 len
= strlen(l
->str
);
272 if (linepos
+ len
> 62) {
273 fprintf(deps
, " \\\n ");
276 fprintf(deps
, " %s", l
->str
);
279 fprintf(deps
, "\n\n");
281 for (l
= list
; l
; l
= nl
) {
282 if (depend_emit_phony
)
283 fprintf(deps
, "%s:\n\n", l
->str
);
293 int main(int argc
, char **argv
)
295 StrList
*depend_list
= NULL
, **depend_ptr
;
297 time(&official_compile_time
);
300 want_usage
= terminate_after_phase
= false;
301 report_error
= report_error_gnu
;
307 nasm_set_malloc_error(report_error
);
308 offsets
= raa_init();
309 forwrefs
= saa_init((int32_t)sizeof(struct forwrefinfo
));
312 operating_mode
= op_normal
;
316 register_output_formats();
318 /* Define some macros dependent on the runtime, but not
319 on the command line. */
320 define_macros_early();
322 parse_cmdline(argc
, argv
);
324 if (terminate_after_phase
) {
330 /* If debugging info is disabled, suppress any debug calls */
331 if (!using_debug_info
)
332 ofmt
->current_dfmt
= &null_debug_form
;
335 pp_extra_stdmac(ofmt
->stdmac
);
336 parser_global_info(ofmt
, &location
);
337 eval_global_info(ofmt
, lookup_label
, &location
);
339 /* define some macros dependent of command-line */
340 define_macros_late();
342 depend_ptr
= (depend_file
|| (operating_mode
== op_depend
))
343 ? &depend_list
: NULL
;
345 depend_target
= outname
;
347 switch (operating_mode
) {
352 if (depend_missing_ok
)
353 pp_include_path(NULL
); /* "assume generated" */
355 preproc
->reset(inname
, 0, report_error
, evaluate
, &nasmlist
,
357 if (outname
[0] == '\0')
358 ofmt
->filename(inname
, outname
, report_error
);
360 while ((line
= preproc
->getline()))
369 char *file_name
= NULL
;
370 int32_t prior_linnum
= 0;
374 ofile
= fopen(outname
, "w");
376 report_error(ERR_FATAL
| ERR_NOFILE
,
377 "unable to open output file `%s'",
382 location
.known
= false;
385 preproc
->reset(inname
, 2, report_error
, evaluate
, &nasmlist
,
388 while ((line
= preproc
->getline())) {
390 * We generate %line directives if needed for later programs
392 int32_t linnum
= prior_linnum
+= lineinc
;
393 int altline
= src_get(&linnum
, &file_name
);
395 if (altline
== 1 && lineinc
== 1)
396 nasm_fputs("", ofile
);
398 lineinc
= (altline
!= -1 || lineinc
!= 1);
399 fprintf(ofile
? ofile
: stdout
,
400 "%%line %"PRId32
"+%d %s\n", linnum
, lineinc
,
403 prior_linnum
= linnum
;
405 nasm_fputs(line
, ofile
);
408 nasm_free(file_name
);
412 if (ofile
&& terminate_after_phase
)
420 * We must call ofmt->filename _anyway_, even if the user
421 * has specified their own output file, because some
422 * formats (eg OBJ and COFF) use ofmt->filename to find out
423 * the name of the input file and then put that inside the
426 ofmt
->filename(inname
, outname
, report_error
);
428 ofile
= fopen(outname
, "wb");
430 report_error(ERR_FATAL
| ERR_NOFILE
,
431 "unable to open output file `%s'", outname
);
435 * We must call init_labels() before ofmt->init() since
436 * some object formats will want to define labels in their
437 * init routines. (eg OS/2 defines the FLAT group)
441 ofmt
->init(ofile
, report_error
, define_label
, evaluate
);
443 assemble_file(inname
, depend_ptr
);
445 if (!terminate_after_phase
) {
446 ofmt
->cleanup(using_debug_info
);
450 * Despite earlier comments, we need this fclose.
451 * The object output drivers only fclose on cleanup,
452 * and we just skipped that.
465 emit_dependencies(depend_list
);
475 if (terminate_after_phase
)
482 * Get a parameter for a command line option.
483 * First arg must be in the form of e.g. -f...
485 static char *get_param(char *p
, char *q
, bool *advance
)
488 if (p
[2]) { /* the parameter's in the option */
490 while (nasm_isspace(*p
))
498 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
499 "option `-%c' requires an argument", p
[1]);
506 static void copy_filename(char *dst
, const char *src
)
508 size_t len
= strlen(src
);
510 if (len
>= (size_t)FILENAME_MAX
) {
511 report_error(ERR_FATAL
| ERR_NOFILE
, "file name too long");
514 strncpy(dst
, src
, FILENAME_MAX
);
518 * Convert a string to Make-safe form
520 static char *quote_for_make(const char *str
)
525 size_t n
= 1; /* Terminating zero */
531 for (p
= str
; *p
; p
++) {
535 /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
555 /* Convert N backslashes at the end of filename to 2N backslashes */
559 os
= q
= nasm_malloc(n
);
562 for (p
= str
; *p
; p
++) {
605 #define OPT_POSTFIX 1
606 struct textargs textopts
[] = {
607 {"prefix", OPT_PREFIX
},
608 {"postfix", OPT_POSTFIX
},
612 static bool stopoptions
= false;
613 static bool process_arg(char *p
, char *q
)
617 bool advance
= false;
623 if (p
[0] == '-' && !stopoptions
) {
624 if (strchr("oOfpPdDiIlFXuUZwW", p
[1])) {
625 /* These parameters take values */
626 if (!(param
= get_param(p
, q
, &advance
)))
635 case 'o': /* output file */
636 copy_filename(outname
, param
);
639 case 'f': /* output format */
640 ofmt
= ofmt_find(param
);
642 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
643 "unrecognised output format `%s' - "
644 "use -hf for a list", param
);
646 ofmt
->current_dfmt
= ofmt
->debug_formats
[0];
650 case 'O': /* Optimization level */
655 /* Naked -O == -Ox */
656 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
660 case '0': case '1': case '2': case '3': case '4':
661 case '5': case '6': case '7': case '8': case '9':
662 opt
= strtoul(param
, ¶m
, 10);
664 /* -O0 -> optimizing == -1, 0.98 behaviour */
665 /* -O1 -> optimizing == 0, 0.98.09 behaviour */
667 optimizing
= opt
- 1;
675 opt_verbose_info
= true;
680 optimizing
= INT_MAX
>> 1; /* Almost unlimited */
684 report_error(ERR_FATAL
,
685 "unknown optimization option -O%c\n",
694 case 'p': /* pre-include */
696 pp_pre_include(param
);
699 case 'd': /* pre-define */
701 pp_pre_define(param
);
704 case 'u': /* un-define */
706 pp_pre_undefine(param
);
709 case 'i': /* include search path */
711 pp_include_path(param
);
714 case 'l': /* listing file */
715 copy_filename(listname
, param
);
718 case 'Z': /* error messages file */
719 strcpy(errname
, param
);
722 case 'F': /* specify debug format */
723 ofmt
->current_dfmt
= dfmt_find(ofmt
, param
);
724 if (!ofmt
->current_dfmt
) {
725 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
726 "unrecognized debug format `%s' for"
727 " output format `%s'",
728 param
, ofmt
->shortname
);
730 using_debug_info
= true;
733 case 'X': /* specify error reporting format */
734 if (nasm_stricmp("vc", param
) == 0)
735 report_error
= report_error_vc
;
736 else if (nasm_stricmp("gnu", param
) == 0)
737 report_error
= report_error_gnu
;
739 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
740 "unrecognized error reporting format `%s'",
745 using_debug_info
= true;
750 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
752 " [options...] [--] filename\n"
753 " or nasm -v for version info\n\n"
754 " -t assemble in SciTech TASM compatible mode\n"
755 " -g generate debug information in selected format.\n");
757 (" -E (or -e) preprocess only (writes output to stdout by default)\n"
758 " -a don't preprocess (assemble only)\n"
759 " -M generate Makefile dependencies on stdout\n"
760 " -MG d:o, missing files assumed generated\n\n"
761 " -Z<file> redirect error messages to file\n"
762 " -s redirect error messages to stdout\n\n"
763 " -F format select a debugging format\n\n"
764 " -I<path> adds a pathname to the include file path\n");
766 (" -O<digit> optimize branch offsets (-O0 disables, default)\n"
767 " -P<file> pre-includes a file\n"
768 " -D<macro>[=<value>] pre-defines a macro\n"
769 " -U<macro> undefines a macro\n"
770 " -X<format> specifies error reporting format (gnu or vc)\n"
771 " -w+foo enables warning foo (equiv. -Wfoo)\n"
772 " -w-foo disable warning foo (equiv. -Wno-foo)\n"
774 for (i
= 0; i
<= ERR_WARN_MAX
; i
++)
775 printf(" %-23s %s (default %s)\n",
776 suppressed_names
[i
], suppressed_what
[i
],
777 suppressed_global
[i
] ? "off" : "on");
779 ("\nresponse files should contain command line parameters"
780 ", one per line.\n");
782 printf("\nvalid output formats for -f are"
783 " (`*' denotes default):\n");
784 ofmt_list(ofmt
, stdout
);
786 printf("\nFor a list of valid output formats, use -hf.\n");
787 printf("For a list of debug formats, use -f <form> -y.\n");
789 exit(0); /* never need usage message here */
793 printf("\nvalid debug formats for '%s' output format are"
794 " ('*' denotes default):\n", ofmt
->shortname
);
795 dfmt_list(ofmt
, stdout
);
800 tasm_compatible_mode
= true;
805 const char *nasm_version_string
=
806 "NASM version " NASM_VER
" compiled on " __DATE__
811 puts(nasm_version_string
);
812 exit(0); /* never need usage message here */
816 case 'e': /* preprocess only */
818 operating_mode
= op_preprocess
;
821 case 'a': /* assemble only - don't preprocess */
826 if (param
[0] == 'n' && param
[1] == 'o' && param
[2] == '-') {
835 if (param
[0] != '+' && param
[0] != '-') {
836 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
837 "invalid option to `-w'");
840 suppress
= (param
[0] == '-');
844 for (i
= 0; i
<= ERR_WARN_MAX
; i
++)
845 if (!nasm_stricmp(param
, suppressed_names
[i
]))
847 if (i
<= ERR_WARN_MAX
)
848 suppressed_global
[i
] = suppress
;
849 else if (!nasm_stricmp(param
, "all"))
850 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
851 suppressed_global
[i
] = suppress
;
852 else if (!nasm_stricmp(param
, "none"))
853 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
854 suppressed_global
[i
] = !suppress
;
856 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
857 "invalid warning `%s'", param
);
863 operating_mode
= op_depend
;
866 operating_mode
= op_depend
;
867 depend_missing_ok
= true;
870 depend_emit_phony
= true;
881 depend_target
= quote_for_make(q
);
885 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
886 "unknown dependency option `-M%c'", p
[2]);
889 if (advance
&& (!q
|| !q
[0])) {
890 report_error(ERR_NONFATAL
|ERR_NOFILE
|ERR_USAGE
,
891 "option `-M%c' requires a parameter", p
[2]);
900 if (p
[2] == 0) { /* -- => stop processing options */
904 for (s
= 0; textopts
[s
].label
; s
++) {
905 if (!nasm_stricmp(p
+ 2, textopts
[s
].label
)) {
916 report_error(ERR_NONFATAL
| ERR_NOFILE
|
918 "option `--%s' requires an argument",
922 advance
= 1, param
= q
;
925 if (s
== OPT_PREFIX
) {
926 strncpy(lprefix
, param
, PREFIX_MAX
- 1);
927 lprefix
[PREFIX_MAX
- 1] = 0;
930 if (s
== OPT_POSTFIX
) {
931 strncpy(lpostfix
, param
, POSTFIX_MAX
- 1);
932 lpostfix
[POSTFIX_MAX
- 1] = 0;
939 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
940 "unrecognised option `--%s'", p
+ 2);
948 if (!ofmt
->setinfo(GI_SWITCH
, &p
))
949 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
950 "unrecognised option `-%c'", p
[1]);
955 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
956 "more than one input file specified");
958 copy_filename(inname
, p
);
965 #define ARG_BUF_DELTA 128
967 static void process_respfile(FILE * rfile
)
969 char *buffer
, *p
, *q
, *prevarg
;
970 int bufsize
, prevargsize
;
972 bufsize
= prevargsize
= ARG_BUF_DELTA
;
973 buffer
= nasm_malloc(ARG_BUF_DELTA
);
974 prevarg
= nasm_malloc(ARG_BUF_DELTA
);
977 while (1) { /* Loop to handle all lines in file */
979 while (1) { /* Loop to handle long lines */
980 q
= fgets(p
, bufsize
- (p
- buffer
), rfile
);
984 if (p
> buffer
&& p
[-1] == '\n')
986 if (p
- buffer
> bufsize
- 10) {
989 bufsize
+= ARG_BUF_DELTA
;
990 buffer
= nasm_realloc(buffer
, bufsize
);
995 if (!q
&& p
== buffer
) {
997 process_arg(prevarg
, NULL
);
1004 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1005 * them are present at the end of the line.
1007 *(p
= &buffer
[strcspn(buffer
, "\r\n\032")]) = '\0';
1009 while (p
> buffer
&& nasm_isspace(p
[-1]))
1013 while (nasm_isspace(*p
))
1016 if (process_arg(prevarg
, p
))
1019 if ((int) strlen(p
) > prevargsize
- 10) {
1020 prevargsize
+= ARG_BUF_DELTA
;
1021 prevarg
= nasm_realloc(prevarg
, prevargsize
);
1023 strncpy(prevarg
, p
, prevargsize
);
1027 /* Function to process args from a string of args, rather than the
1028 * argv array. Used by the environment variable and response file
1031 static void process_args(char *args
)
1033 char *p
, *q
, *arg
, *prevarg
;
1034 char separator
= ' ';
1037 if (*p
&& *p
!= '-')
1042 while (*p
&& *p
!= separator
)
1044 while (*p
== separator
)
1048 if (process_arg(prevarg
, arg
))
1052 process_arg(arg
, NULL
);
1055 static void process_response_file(const char *file
)
1058 FILE *f
= fopen(file
, "r");
1063 while (fgets(str
, sizeof str
, f
)) {
1069 static void parse_cmdline(int argc
, char **argv
)
1072 char *envreal
, *envcopy
= NULL
, *p
, *arg
;
1074 *inname
= *outname
= *listname
= *errname
= '\0';
1077 * First, process the NASMENV environment variable.
1079 envreal
= getenv("NASMENV");
1082 envcopy
= nasm_strdup(envreal
);
1083 process_args(envcopy
);
1088 * Now process the actual command line.
1093 if (argv
[0][0] == '@') {
1094 /* We have a response file, so process this as a set of
1095 * arguments like the environment variable. This allows us
1096 * to have multiple arguments on a single line, which is
1097 * different to the -@resp file processing below for regular
1100 process_response_file(argv
[0]+1);
1104 if (!stopoptions
&& argv
[0][0] == '-' && argv
[0][1] == '@') {
1105 p
= get_param(argv
[0], argc
> 1 ? argv
[1] : NULL
, &advance
);
1107 rfile
= fopen(p
, "r");
1109 process_respfile(rfile
);
1112 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
1113 "unable to open response file `%s'", p
);
1116 advance
= process_arg(argv
[0], argc
> 1 ? argv
[1] : NULL
);
1117 argv
+= advance
, argc
-= advance
;
1120 /* Look for basic command line typos. This definitely doesn't
1121 catch all errors, but it might help cases of fumbled fingers. */
1123 report_error(ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
1124 "no input file specified");
1125 else if (!strcmp(inname
, errname
) ||
1126 !strcmp(inname
, outname
) ||
1127 !strcmp(inname
, listname
) ||
1128 (depend_file
&& !strcmp(inname
, depend_file
)))
1129 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
1130 "file `%s' is both input and output file",
1134 error_file
= fopen(errname
, "w");
1136 error_file
= stderr
; /* Revert to default! */
1137 report_error(ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
1138 "cannot open file `%s' for error messages",
1144 /* List of directives */
1146 D_NONE
, D_ABSOLUTE
, D_BITS
, D_COMMON
, D_CPU
, D_DEBUG
, D_DEFAULT
,
1147 D_EXTERN
, D_FLOAT
, D_GLOBAL
, D_LIST
, D_SECTION
, D_SEGMENT
, D_WARNING
1149 static const char *directives
[] = {
1150 "", "absolute", "bits", "common", "cpu", "debug", "default",
1151 "extern", "float", "global", "list", "section", "segment", "warning"
1153 static enum directives
getkw(char **directive
, char **value
);
1155 static void assemble_file(char *fname
, StrList
**depend_ptr
)
1157 char *directive
, *value
, *p
, *q
, *special
, *line
, debugid
[80];
1163 struct tokenval tokval
;
1167 if (cmd_sb
== 32 && cmd_cpu
< IF_386
)
1168 report_error(ERR_FATAL
, "command line: "
1169 "32-bit segment size requires a higher cpu");
1171 pass_max
= prev_offset_changed
= (INT_MAX
>> 1) + 2; /* Almost unlimited */
1172 for (passn
= 1; pass0
<= 2; passn
++) {
1176 pass1
= pass0
== 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
1177 pass2
= passn
> 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
1178 /* pass0 0, 0, 0, ..., 1, 2 */
1180 def_label
= passn
> 1 ? redefine_label
: define_label
;
1182 globalbits
= sb
= cmd_sb
; /* set 'bits' to command line default */
1186 nasmlist
.init(listname
, report_error
);
1189 global_offset_changed
= 0; /* set by redefine_label */
1190 location
.segment
= ofmt
->section(NULL
, pass2
, &sb
);
1193 saa_rewind(forwrefs
);
1194 forwref
= saa_rstruct(forwrefs
);
1196 offsets
= raa_init();
1198 preproc
->reset(fname
, pass1
, report_error
, evaluate
, &nasmlist
,
1199 pass1
== 2 ? depend_ptr
: NULL
);
1200 memcpy(suppressed
, suppressed_global
, (ERR_WARN_MAX
+1) * sizeof(bool));
1204 location
.known
= true;
1205 location
.offset
= offs
= GET_CURR_OFFS
;
1207 while ((line
= preproc
->getline())) {
1211 /* here we parse our directives; this is not handled by the 'real'
1214 d
= getkw(&directive
, &value
);
1219 case D_SEGMENT
: /* [SEGMENT n] */
1221 seg
= ofmt
->section(value
, pass2
, &sb
);
1222 if (seg
== NO_SEG
) {
1223 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1224 "segment name `%s' not recognized",
1228 location
.segment
= seg
;
1231 case D_EXTERN
: /* [EXTERN label:special] */
1233 value
++; /* skip initial $ if present */
1236 while (*q
&& *q
!= ':')
1240 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1242 } else if (passn
== 1) {
1247 while (*q
&& *q
!= ':') {
1253 report_error(ERR_NONFATAL
,
1254 "identifier expected after EXTERN");
1262 if (!is_extern(value
)) { /* allow re-EXTERN to be ignored */
1264 pass0
= 1; /* fake pass 1 in labels.c */
1265 declare_as_global(value
, special
,
1267 define_label(value
, seg_alloc(), 0L, NULL
,
1268 false, true, ofmt
, report_error
);
1271 } /* else pass0 == 1 */
1273 case D_BITS
: /* [BITS bits] */
1274 globalbits
= sb
= get_bits(value
);
1276 case D_GLOBAL
: /* [GLOBAL symbol:special] */
1278 value
++; /* skip initial $ if present */
1279 if (pass0
== 2) { /* pass 2 */
1281 while (*q
&& *q
!= ':')
1285 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1287 } else if (pass2
== 1) { /* pass == 1 */
1292 while (*q
&& *q
!= ':') {
1298 report_error(ERR_NONFATAL
,
1299 "identifier expected after GLOBAL");
1307 declare_as_global(value
, special
, report_error
);
1310 case D_COMMON
: /* [COMMON symbol size:special] */
1312 value
++; /* skip initial $ if present */
1318 while (*p
&& !nasm_isspace(*p
)) {
1324 report_error(ERR_NONFATAL
,
1325 "identifier expected after COMMON");
1331 while (*p
&& nasm_isspace(*p
))
1334 while (*q
&& *q
!= ':')
1341 size
= readnum(p
, &rn_error
);
1343 report_error(ERR_NONFATAL
,
1344 "invalid size specified"
1345 " in COMMON declaration");
1347 define_common(value
, seg_alloc(), size
,
1348 special
, ofmt
, report_error
);
1350 report_error(ERR_NONFATAL
,
1351 "no size specified in"
1352 " COMMON declaration");
1353 } else if (pass0
== 2) { /* pass == 2 */
1355 while (*q
&& *q
!= ':') {
1356 if (nasm_isspace(*q
))
1362 ofmt
->symdef(value
, 0L, 0L, 3, q
);
1366 case D_ABSOLUTE
: /* [ABSOLUTE address] */
1368 stdscan_bufptr
= value
;
1369 tokval
.t_type
= TOKEN_INVALID
;
1370 e
= evaluate(stdscan
, NULL
, &tokval
, NULL
, pass2
,
1371 report_error
, NULL
);
1374 report_error(pass0
==
1375 1 ? ERR_NONFATAL
: ERR_PANIC
,
1376 "cannot use non-relocatable expression as "
1377 "ABSOLUTE address");
1379 abs_seg
= reloc_seg(e
);
1380 abs_offset
= reloc_value(e
);
1382 } else if (passn
== 1)
1383 abs_offset
= 0x100; /* don't go near zero in case of / */
1385 report_error(ERR_PANIC
, "invalid ABSOLUTE address "
1388 location
.segment
= NO_SEG
;
1390 case D_DEBUG
: /* [DEBUG] */
1396 while (*p
&& !nasm_isspace(*p
)) {
1403 report_error(passn
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1404 "identifier expected after DEBUG");
1407 while (*p
&& nasm_isspace(*p
))
1410 ofmt
->current_dfmt
->debug_directive(debugid
, p
);
1412 case D_WARNING
: /* [WARNING {+|-|*}warn-name] */
1414 while (*value
&& nasm_isspace(*value
))
1418 case '-': validid
= 0; value
++; break;
1419 case '+': validid
= 1; value
++; break;
1420 case '*': validid
= 2; value
++; break;
1422 * Should this error out?
1423 * I'll keep it so nothing breaks.
1428 for (i
= 1; i
<= ERR_WARN_MAX
; i
++)
1429 if (!nasm_stricmp(value
, suppressed_names
[i
]))
1431 if (i
<= ERR_WARN_MAX
) {
1433 case 0: suppressed
[i
] = true; break;
1434 case 1: suppressed
[i
] = false; break;
1435 case 2: suppressed
[i
] = suppressed_global
[i
];
1440 report_error(ERR_NONFATAL
,
1441 "invalid warning id in WARNING directive");
1444 case D_CPU
: /* [CPU] */
1445 cpu
= get_cpu(value
);
1447 case D_LIST
: /* [LIST {+|-}] */
1448 while (*value
&& nasm_isspace(*value
))
1451 if (*value
== '+') {
1454 if (*value
== '-') {
1461 case D_DEFAULT
: /* [DEFAULT] */
1463 stdscan_bufptr
= value
;
1464 tokval
.t_type
= TOKEN_INVALID
;
1465 if (stdscan(NULL
, &tokval
) == TOKEN_SPECIAL
) {
1466 switch ((int)tokval
.t_integer
) {
1482 if (float_option(value
)) {
1483 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1484 "unknown 'float' directive: %s",
1489 if (!ofmt
->directive(directive
, value
, pass2
))
1490 report_error(pass1
== 1 ? ERR_NONFATAL
: ERR_PANIC
,
1491 "unrecognised directive [%s]",
1495 report_error(ERR_NONFATAL
,
1496 "invalid parameter to [%s] directive",
1499 } else { /* it isn't a directive */
1501 parse_line(pass1
, line
, &output_ins
,
1502 report_error
, evaluate
, def_label
);
1504 if (optimizing
> 0) {
1505 if (forwref
!= NULL
&& globallineno
== forwref
->lineno
) {
1506 output_ins
.forw_ref
= true;
1508 output_ins
.oprs
[forwref
->operand
].opflags
|=
1510 forwref
= saa_rstruct(forwrefs
);
1511 } while (forwref
!= NULL
1512 && forwref
->lineno
== globallineno
);
1514 output_ins
.forw_ref
= false;
1517 if (optimizing
> 0) {
1519 for (i
= 0; i
< output_ins
.operands
; i
++) {
1520 if (output_ins
.oprs
[i
].
1521 opflags
& OPFLAG_FORWARD
) {
1522 struct forwrefinfo
*fwinf
=
1523 (struct forwrefinfo
*)
1524 saa_wstruct(forwrefs
);
1525 fwinf
->lineno
= globallineno
;
1533 if (output_ins
.opcode
== I_EQU
) {
1536 * Special `..' EQUs get processed in pass two,
1537 * except `..@' macro-processor EQUs which are done
1538 * in the normal place.
1540 if (!output_ins
.label
)
1541 report_error(ERR_NONFATAL
,
1542 "EQU not preceded by label");
1544 else if (output_ins
.label
[0] != '.' ||
1545 output_ins
.label
[1] != '.' ||
1546 output_ins
.label
[2] == '@') {
1547 if (output_ins
.operands
== 1 &&
1548 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
1549 output_ins
.oprs
[0].wrt
== NO_SEG
) {
1552 opflags
& OPFLAG_EXTERN
;
1553 def_label(output_ins
.label
,
1554 output_ins
.oprs
[0].segment
,
1555 output_ins
.oprs
[0].offset
, NULL
,
1558 } else if (output_ins
.operands
== 2
1559 && (output_ins
.oprs
[0].
1561 && (output_ins
.oprs
[0].type
& COLON
)
1562 && output_ins
.oprs
[0].segment
==
1564 && output_ins
.oprs
[0].wrt
== NO_SEG
1565 && (output_ins
.oprs
[1].
1567 && output_ins
.oprs
[1].segment
==
1569 && output_ins
.oprs
[1].wrt
==
1571 def_label(output_ins
.label
,
1574 output_ins
.oprs
[1].offset
, NULL
,
1578 report_error(ERR_NONFATAL
,
1579 "bad syntax for EQU");
1583 * Special `..' EQUs get processed here, except
1584 * `..@' macro processor EQUs which are done above.
1586 if (output_ins
.label
[0] == '.' &&
1587 output_ins
.label
[1] == '.' &&
1588 output_ins
.label
[2] != '@') {
1589 if (output_ins
.operands
== 1 &&
1590 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
1591 define_label(output_ins
.label
,
1592 output_ins
.oprs
[0].segment
,
1593 output_ins
.oprs
[0].offset
,
1594 NULL
, false, false, ofmt
,
1596 } else if (output_ins
.operands
== 2
1597 && (output_ins
.oprs
[0].
1599 && (output_ins
.oprs
[0].type
& COLON
)
1600 && output_ins
.oprs
[0].segment
==
1602 && (output_ins
.oprs
[1].
1604 && output_ins
.oprs
[1].segment
==
1606 define_label(output_ins
.label
,
1609 output_ins
.oprs
[1].offset
,
1610 NULL
, false, false, ofmt
,
1613 report_error(ERR_NONFATAL
,
1614 "bad syntax for EQU");
1617 } else { /* instruction isn't an EQU */
1621 int64_t l
= insn_size(location
.segment
, offs
, sb
, cpu
,
1622 &output_ins
, report_error
);
1624 /* if (using_debug_info) && output_ins.opcode != -1) */
1625 if (using_debug_info
)
1626 { /* fbk 03/25/01 */
1627 /* this is done here so we can do debug type info */
1629 TYS_ELEMENTS(output_ins
.operands
);
1630 switch (output_ins
.opcode
) {
1633 TYS_ELEMENTS(output_ins
.oprs
[0].
1638 TYS_ELEMENTS(output_ins
.oprs
[0].
1643 TYS_ELEMENTS(output_ins
.oprs
[0].
1648 TYS_ELEMENTS(output_ins
.oprs
[0].
1653 TYS_ELEMENTS(output_ins
.oprs
[0].
1658 TYS_ELEMENTS(output_ins
.oprs
[0].
1663 TYS_ELEMENTS(output_ins
.oprs
[0].
1667 typeinfo
|= TY_BYTE
;
1670 typeinfo
|= TY_WORD
;
1673 if (output_ins
.eops_float
)
1674 typeinfo
|= TY_FLOAT
;
1676 typeinfo
|= TY_DWORD
;
1679 typeinfo
|= TY_QWORD
;
1682 typeinfo
|= TY_TBYTE
;
1685 typeinfo
|= TY_OWORD
;
1688 typeinfo
|= TY_YWORD
;
1691 typeinfo
= TY_LABEL
;
1695 ofmt
->current_dfmt
->debug_typevalue(typeinfo
);
1700 SET_CURR_OFFS(offs
);
1703 * else l == -1 => invalid instruction, which will be
1704 * flagged as an error on pass 2
1708 offs
+= assemble(location
.segment
, offs
, sb
, cpu
,
1709 &output_ins
, ofmt
, report_error
,
1711 SET_CURR_OFFS(offs
);
1715 cleanup_insn(&output_ins
);
1718 location
.offset
= offs
= GET_CURR_OFFS
;
1719 } /* end while (line = preproc->getline... */
1720 if (pass1
== 2 && global_offset_changed
)
1721 report_error(ERR_NONFATAL
,
1722 "phase error detected at end of assembly.");
1725 preproc
->cleanup(1);
1727 if (pass1
== 1 && terminate_after_phase
) {
1735 if (passn
> 1 && !global_offset_changed
)
1737 else if (global_offset_changed
&& global_offset_changed
< prev_offset_changed
) {
1738 prev_offset_changed
= global_offset_changed
;
1743 if((stall_count
> 997) || (passn
>= pass_max
))
1744 /* We get here if the labels don't converge
1745 * Example: FOO equ FOO + 1
1747 report_error(ERR_NONFATAL
,
1748 "Can't find valid values for all labels "
1749 "after %d passes, giving up.\n"
1750 " Possible cause: recursive equ's.", passn
);
1753 preproc
->cleanup(0);
1755 if (opt_verbose_info
) /* -On and -Ov switches */
1757 "info:: assembly required 1+%d+1 passes\n", passn
-3);
1758 } /* exit from assemble_file (...) */
1760 static enum directives
getkw(char **directive
, char **value
)
1766 /* allow leading spaces or tabs */
1767 while (*buf
== ' ' || *buf
== '\t')
1775 while (*p
&& *p
!= ']')
1783 while (*p
&& *p
!= ';') {
1784 if (!nasm_isspace(*p
))
1790 *directive
= p
= buf
+ 1;
1791 while (*buf
&& *buf
!= ' ' && *buf
!= ']' && *buf
!= '\t')
1798 while (nasm_isspace(*buf
))
1799 buf
++; /* beppu - skip leading whitespace */
1806 return bsii(*directive
, directives
, elements(directives
));
1810 * gnu style error reporting
1811 * This function prints an error message to error_file in the
1812 * style used by GNU. An example would be:
1813 * file.asm:50: error: blah blah blah
1814 * where file.asm is the name of the file, 50 is the line number on
1815 * which the error occurs (or is detected) and "error:" is one of
1816 * the possible optional diagnostics -- it can be "error" or "warning"
1817 * or something else. Finally the line terminates with the actual
1820 * @param severity the severity of the warning or error
1821 * @param fmt the printf style format string
1823 static void report_error_gnu(int severity
, const char *fmt
, ...)
1827 if (is_suppressed_warning(severity
))
1830 if (severity
& ERR_NOFILE
)
1831 fputs("nasm: ", error_file
);
1833 char *currentfile
= NULL
;
1835 src_get(&lineno
, ¤tfile
);
1836 fprintf(error_file
, "%s:%"PRId32
": ", currentfile
, lineno
);
1837 nasm_free(currentfile
);
1840 report_error_common(severity
, fmt
, ap
);
1845 * MS style error reporting
1846 * This function prints an error message to error_file in the
1847 * style used by Visual C and some other Microsoft tools. An example
1849 * file.asm(50) : error: blah blah blah
1850 * where file.asm is the name of the file, 50 is the line number on
1851 * which the error occurs (or is detected) and "error:" is one of
1852 * the possible optional diagnostics -- it can be "error" or "warning"
1853 * or something else. Finally the line terminates with the actual
1856 * @param severity the severity of the warning or error
1857 * @param fmt the printf style format string
1859 static void report_error_vc(int severity
, const char *fmt
, ...)
1863 if (is_suppressed_warning(severity
))
1866 if (severity
& ERR_NOFILE
)
1867 fputs("nasm: ", error_file
);
1869 char *currentfile
= NULL
;
1871 src_get(&lineno
, ¤tfile
);
1872 fprintf(error_file
, "%s(%"PRId32
") : ", currentfile
, lineno
);
1873 nasm_free(currentfile
);
1876 report_error_common(severity
, fmt
, ap
);
1881 * check for supressed warning
1882 * checks for suppressed warning or pass one only warning and we're
1885 * @param severity the severity of the warning or error
1886 * @return true if we should abort error/warning printing
1888 static bool is_suppressed_warning(int severity
)
1891 * See if it's a suppressed warning.
1893 return (severity
& ERR_MASK
) == ERR_WARNING
&&
1894 (((severity
& ERR_WARN_MASK
) != 0 &&
1895 suppressed
[(severity
& ERR_WARN_MASK
) >> ERR_WARN_SHR
]) ||
1896 /* See if it's a pass-one only warning and we're not in pass one. */
1897 ((severity
& ERR_PASS1
) && pass0
!= 1));
1901 * common error reporting
1902 * This is the common back end of the error reporting schemes currently
1903 * implemented. It prints the nature of the warning and then the
1904 * specific error message to error_file and may or may not return. It
1905 * doesn't return if the error severity is a "panic" or "debug" type.
1907 * @param severity the severity of the warning or error
1908 * @param fmt the printf style format string
1910 static void report_error_common(int severity
, const char *fmt
,
1913 switch (severity
& (ERR_MASK
|ERR_NO_SEVERITY
)) {
1915 fputs("warning: ", error_file
);
1918 fputs("error: ", error_file
);
1921 fputs("fatal: ", error_file
);
1924 fputs("panic: ", error_file
);
1927 fputs("debug: ", error_file
);
1933 vfprintf(error_file
, fmt
, args
);
1934 putc('\n', error_file
);
1936 if (severity
& ERR_USAGE
)
1939 switch (severity
& ERR_MASK
) {
1941 /* no further action, by definition */
1944 if (!suppressed
[0]) /* Treat warnings as errors */
1945 terminate_after_phase
= true;
1948 terminate_after_phase
= true;
1957 exit(1); /* instantly die */
1958 break; /* placate silly compilers */
1961 /* abort(); *//* halt, catch fire, and dump core */
1967 static void usage(void)
1969 fputs("type `nasm -h' for help\n", error_file
);
1972 static void register_output_formats(void)
1974 ofmt
= ofmt_register(report_error
);
1977 #define BUF_DELTA 512
1979 static FILE *no_pp_fp
;
1980 static efunc no_pp_err
;
1981 static ListGen
*no_pp_list
;
1982 static int32_t no_pp_lineinc
;
1984 static void no_pp_reset(char *file
, int pass
, efunc error
, evalfunc eval
,
1985 ListGen
* listgen
, StrList
**deplist
)
1987 src_set_fname(nasm_strdup(file
));
1991 no_pp_fp
= fopen(file
, "r");
1993 no_pp_err(ERR_FATAL
| ERR_NOFILE
,
1994 "unable to open input file `%s'", file
);
1995 no_pp_list
= listgen
;
1996 (void)pass
; /* placate compilers */
1997 (void)eval
; /* placate compilers */
2000 StrList
*sl
= nasm_malloc(strlen(file
)+1+sizeof sl
->next
);
2002 strcpy(sl
->str
, file
);
2007 static char *no_pp_getline(void)
2009 char *buffer
, *p
, *q
;
2012 bufsize
= BUF_DELTA
;
2013 buffer
= nasm_malloc(BUF_DELTA
);
2014 src_set_linnum(src_get_linnum() + no_pp_lineinc
);
2016 while (1) { /* Loop to handle %line */
2019 while (1) { /* Loop to handle long lines */
2020 q
= fgets(p
, bufsize
- (p
- buffer
), no_pp_fp
);
2024 if (p
> buffer
&& p
[-1] == '\n')
2026 if (p
- buffer
> bufsize
- 10) {
2028 offset
= p
- buffer
;
2029 bufsize
+= BUF_DELTA
;
2030 buffer
= nasm_realloc(buffer
, bufsize
);
2031 p
= buffer
+ offset
;
2035 if (!q
&& p
== buffer
) {
2041 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
2042 * them are present at the end of the line.
2044 buffer
[strcspn(buffer
, "\r\n\032")] = '\0';
2046 if (!nasm_strnicmp(buffer
, "%line", 5)) {
2049 char *nm
= nasm_malloc(strlen(buffer
));
2050 if (sscanf(buffer
+ 5, "%"PRId32
"+%d %s", &ln
, &li
, nm
) == 3) {
2051 nasm_free(src_set_fname(nm
));
2061 no_pp_list
->line(LIST_READ
, buffer
);
2066 static void no_pp_cleanup(int pass
)
2068 (void)pass
; /* placate GCC */
2072 static uint32_t get_cpu(char *value
)
2074 if (!strcmp(value
, "8086"))
2076 if (!strcmp(value
, "186"))
2078 if (!strcmp(value
, "286"))
2080 if (!strcmp(value
, "386"))
2082 if (!strcmp(value
, "486"))
2084 if (!strcmp(value
, "586") || !nasm_stricmp(value
, "pentium"))
2086 if (!strcmp(value
, "686") ||
2087 !nasm_stricmp(value
, "ppro") ||
2088 !nasm_stricmp(value
, "pentiumpro") || !nasm_stricmp(value
, "p2"))
2090 if (!nasm_stricmp(value
, "p3") || !nasm_stricmp(value
, "katmai"))
2092 if (!nasm_stricmp(value
, "p4") || /* is this right? -- jrc */
2093 !nasm_stricmp(value
, "willamette"))
2094 return IF_WILLAMETTE
;
2095 if (!nasm_stricmp(value
, "prescott"))
2097 if (!nasm_stricmp(value
, "x64") ||
2098 !nasm_stricmp(value
, "x86-64"))
2100 if (!nasm_stricmp(value
, "ia64") ||
2101 !nasm_stricmp(value
, "ia-64") ||
2102 !nasm_stricmp(value
, "itanium") ||
2103 !nasm_stricmp(value
, "itanic") || !nasm_stricmp(value
, "merced"))
2106 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2107 "unknown 'cpu' type");
2109 return IF_PLEVEL
; /* the maximum level */
2112 static int get_bits(char *value
)
2116 if ((i
= atoi(value
)) == 16)
2117 return i
; /* set for a 16-bit segment */
2120 report_error(ERR_NONFATAL
,
2121 "cannot specify 32-bit segment on processor below a 386");
2124 } else if (i
== 64) {
2125 if (cpu
< IF_X86_64
) {
2126 report_error(ERR_NONFATAL
,
2127 "cannot specify 64-bit segment on processor below an x86-64");
2131 report_error(ERR_NONFATAL
,
2132 "%s output format does not support 64-bit code",
2137 report_error(pass0
< 2 ? ERR_NONFATAL
: ERR_FATAL
,
2138 "`%s' is not a valid segment size; must be 16, 32 or 64",