1/* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2018 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * The Netwide Assembler main program module
36 */
37
38#include "compiler.h"
39
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <string.h>
44#include <ctype.h>
45#include <limits.h>
46
47#include "nasm.h"
48#include "nasmlib.h"
49#include "error.h"
50#include "saa.h"
51#include "raa.h"
52#include "float.h"
53#include "stdscan.h"
54#include "insns.h"
55#include "preproc.h"
56#include "parser.h"
57#include "eval.h"
58#include "assemble.h"
59#include "labels.h"
60#include "outform.h"
61#include "listing.h"
62#include "iflag.h"
63#include "ver.h"
64
65/*
66 * This is the maximum number of optimization passes to do. If we ever
67 * find a case where the optimizer doesn't naturally converge, we might
68 * have to drop this value so the assembler doesn't appear to just hang.
69 */
70#define MAX_OPTIMIZE (INT_MAX >> 1)
71
72struct forwrefinfo { /* info held on forward refs. */
73 int lineno;
74 int operand;
75};
76
77static void parse_cmdline(int, char **, int);
78static void assemble_file(const char *, StrList **);
79static bool skip_this_pass(int severity);
80static void nasm_verror_asm(int severity, const char *fmt, va_list args);
81static void usage(void);
82static void help(char xopt);
83
84struct error_format {
85 const char *beforeline; /* Before line number, if present */
86 const char *afterline; /* After line number, if present */
87 const char *beforemsg; /* Before actual message */
88};
89
90static const struct error_format errfmt_gnu = { ":", "", ": " };
91static const struct error_format errfmt_msvc = { "(", ")", " : " };
92static const struct error_format *errfmt = &errfmt_gnu;
93
94static bool using_debug_info, opt_verbose_info;
95static const char *debug_format;
96
97#ifndef ABORT_ON_PANIC
98# define ABORT_ON_PANIC 0
99#endif
100static bool abort_on_panic = ABORT_ON_PANIC;
101static bool keep_all;
102
103bool tasm_compatible_mode = false;
104int pass0;
105int64_t passn;
106static int pass1, pass2; /* XXX: Get rid of these, they are redundant */
107int globalrel = 0;
108int globalbnd = 0;
109
110struct compile_time official_compile_time;
111
112const char *inname;
113const char *outname;
114static const char *listname;
115static const char *errname;
116
117static int64_t globallineno; /* for forward-reference tracking */
118
119/* static int pass = 0; */
120const struct ofmt *ofmt = &OF_DEFAULT;
121const struct ofmt_alias *ofmt_alias = NULL;
122const struct dfmt *dfmt;
123
124FILE *error_file; /* Where to write error messages */
125
126FILE *ofile = NULL;
127struct optimization optimizing =
128 { MAX_OPTIMIZE, OPTIM_ALL_ENABLED }; /* number of optimization passes to take */
129static int cmd_sb = 16; /* by default */
130
131iflag_t cpu;
132static iflag_t cmd_cpu;
133
134struct location location;
135bool in_absolute; /* Flag we are in ABSOLUTE seg */
136struct location absolute; /* Segment/offset inside ABSOLUTE */
137
138static struct RAA *offsets;
139
140static struct SAA *forwrefs; /* keep track of forward references */
141static const struct forwrefinfo *forwref;
142
143static const struct preproc_ops *preproc;
144static StrList *include_path;
145bool pp_noline; /* Ignore %line directives */
146
147#define OP_NORMAL (1U << 0)
148#define OP_PREPROCESS (1U << 1)
149#define OP_DEPEND (1U << 2)
150
151static unsigned int operating_mode;
152
153/* Dependency flags */
154static bool depend_emit_phony = false;
155static bool depend_missing_ok = false;
156static const char *depend_target = NULL;
157static const char *depend_file = NULL;
158StrList *depend_list;
159
160static bool want_usage;
161static bool terminate_after_phase;
162bool user_nolist = false;
163
164static char *quote_for_pmake(const char *str);
165static char *quote_for_wmake(const char *str);
166static char *(*quote_for_make)(const char *) = quote_for_pmake;
167
168/*
169 * Execution limits that can be set via a command-line option or %pragma
170 */
171
172#define LIMIT_MAX_VAL (INT64_MAX >> 1) /* Effectively unlimited */
173
174int64_t nasm_limit[LIMIT_MAX+1] =
175{ LIMIT_MAX_VAL, 1000, 1000000, 1000000, 1000000, 2000000000 };
176
177struct limit_info {
178 const char *name;
179 const char *help;
180};
181static const struct limit_info limit_info[LIMIT_MAX+1] = {
182 { "passes", "total number of passes" },
183 { "stalled-passes", "number of passes without forward progress" },
184 { "macro-levels", "levels of macro expansion"},
185 { "rep", "%rep count" },
186 { "eval", "expression evaluation descent"},
187 { "lines", "total source lines processed"}
188};
189
190enum directive_result
191nasm_set_limit(const char *limit, const char *valstr)
192{
193 int i;
194 int64_t val;
195 bool rn_error;
196 int errlevel;
197
198 for (i = 0; i <= LIMIT_MAX; i++) {
199 if (!nasm_stricmp(limit, limit_info[i].name))
200 break;
201 }
202 if (i > LIMIT_MAX) {
203 if (passn == 0)
204 errlevel = ERR_WARNING|ERR_NOFILE|ERR_USAGE;
205 else
206 errlevel = ERR_WARNING|ERR_PASS1|WARN_UNKNOWN_PRAGMA;
207 nasm_error(errlevel, "unknown limit: `%s'", limit);
208 return DIRR_ERROR;
209 }
210
211 if (!nasm_stricmp(valstr, "unlimited")) {
212 val = LIMIT_MAX_VAL;
213 } else {
214 val = readnum(valstr, &rn_error);
215 if (rn_error || val < 0) {
216 if (passn == 0)
217 errlevel = ERR_WARNING|ERR_NOFILE|ERR_USAGE;
218 else
219 errlevel = ERR_WARNING|ERR_PASS1|WARN_BAD_PRAGMA;
220 nasm_error(errlevel, "invalid limit value: `%s'", limit);
221 return DIRR_ERROR;
222 }
223 if (val > LIMIT_MAX_VAL)
224 val = LIMIT_MAX_VAL;
225 }
226
227 nasm_limit[i] = val;
228 return DIRR_OK;
229}
230
231int64_t switch_segment(int32_t segment)
232{
233 location.segment = segment;
234 if (segment == NO_SEG) {
235 location.offset = absolute.offset;
236 in_absolute = true;
237 } else {
238 location.offset = raa_read(offsets, segment);
239 in_absolute = false;
240 }
241 return location.offset;
242}
243
244static void set_curr_offs(int64_t l_off)
245{
246 if (in_absolute)
247 absolute.offset = l_off;
248 else
249 offsets = raa_write(offsets, location.segment, l_off);
250}
251
252static void increment_offset(int64_t delta)
253{
254 if (unlikely(delta == 0))
255 return;
256
257 location.offset += delta;
258 set_curr_offs(location.offset);
259}
260
261static void nasm_fputs(const char *line, FILE * outfile)
262{
263 if (outfile) {
264 fputs(line, outfile);
265 putc('\n', outfile);
266 } else
267 puts(line);
268}
269
270/*
271 * Define system-defined macros that are not part of
272 * macros/standard.mac.
273 */
274static void define_macros(void)
275{
276 const struct compile_time * const oct = &official_compile_time;
277 char temp[128];
278
279 if (oct->have_local) {
280 strftime(temp, sizeof temp, "__DATE__=\"%Y-%m-%d\"", &oct->local);
281 preproc->pre_define(temp);
282 strftime(temp, sizeof temp, "__DATE_NUM__=%Y%m%d", &oct->local);
283 preproc->pre_define(temp);
284 strftime(temp, sizeof temp, "__TIME__=\"%H:%M:%S\"", &oct->local);
285 preproc->pre_define(temp);
286 strftime(temp, sizeof temp, "__TIME_NUM__=%H%M%S", &oct->local);
287 preproc->pre_define(temp);
288 }
289
290 if (oct->have_gm) {
291 strftime(temp, sizeof temp, "__UTC_DATE__=\"%Y-%m-%d\"", &oct->gm);
292 preproc->pre_define(temp);
293 strftime(temp, sizeof temp, "__UTC_DATE_NUM__=%Y%m%d", &oct->gm);
294 preproc->pre_define(temp);
295 strftime(temp, sizeof temp, "__UTC_TIME__=\"%H:%M:%S\"", &oct->gm);
296 preproc->pre_define(temp);
297 strftime(temp, sizeof temp, "__UTC_TIME_NUM__=%H%M%S", &oct->gm);
298 preproc->pre_define(temp);
299 }
300
301 if (oct->have_posix) {
302 snprintf(temp, sizeof temp, "__POSIX_TIME__=%"PRId64, oct->posix);
303 preproc->pre_define(temp);
304 }
305
306 /*
307 * In case if output format is defined by alias
308 * we have to put shortname of the alias itself here
309 * otherwise ABI backward compatibility gets broken.
310 */
311 snprintf(temp, sizeof(temp), "__OUTPUT_FORMAT__=%s",
312 ofmt_alias ? ofmt_alias->shortname : ofmt->shortname);
313 preproc->pre_define(temp);
314
315 /*
316 * Output-format specific macros.
317 */
318 if (ofmt->stdmac)
319 preproc->extra_stdmac(ofmt->stdmac);
320
321 /*
322 * Debug format, if any
323 */
324 if (dfmt != &null_debug_form) {
325 snprintf(temp, sizeof(temp), "__DEBUG_FORMAT__=%s", dfmt->shortname);
326 preproc->pre_define(temp);
327 }
328}
329
330/*
331 * Initialize the preprocessor, set up the include path, and define
332 * the system-included macros. This is called between passes 1 and 2
333 * of parsing the command options; ofmt and dfmt are defined at this
334 * point.
335 *
336 * Command-line specified preprocessor directives (-p, -d, -u,
337 * --pragma, --before) are processed after this function.
338 */
339static void preproc_init(void)
340{
341 StrList *ip, *iptmp;
342
343 preproc->init();
344 define_macros();
345 list_for_each_safe(ip, iptmp, include_path) {
346 preproc->include_path(ip->str);
347 nasm_free(ip);
348 }
349}
350
351static void emit_dependencies(StrList *list)
352{
353 FILE *deps;
354 int linepos, len;
355 StrList *l, *nl;
356 bool wmake = (quote_for_make == quote_for_wmake);
357 const char *wrapstr, *nulltarget;
358
359 wrapstr = wmake ? " &\n " : " \\\n ";
360 nulltarget = wmake ? "\t%null\n" : "";
361
362 if (depend_file && strcmp(depend_file, "-")) {
363 deps = nasm_open_write(depend_file, NF_TEXT);
364 if (!deps) {
365 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
366 "unable to write dependency file `%s'", depend_file);
367 return;
368 }
369 } else {
370 deps = stdout;
371 }
372
373 linepos = fprintf(deps, "%s :", depend_target);
374 list_for_each(l, list) {
375 char *file = quote_for_make(l->str);
376 len = strlen(file);
377 if (linepos + len > 62 && linepos > 1) {
378 fputs(wrapstr, deps);
379 linepos = 1;
380 }
381 fprintf(deps, " %s", file);
382 linepos += len+1;
383 nasm_free(file);
384 }
385 fprintf(deps, "\n\n");
386
387 list_for_each_safe(l, nl, list) {
388 if (depend_emit_phony) {
389 char *file = quote_for_make(l->str);
390 fprintf(deps, "%s :\n%s\n", file, nulltarget);
391 nasm_free(file);
392 }
393 nasm_free(l);
394 }
395
396 if (deps != stdout)
397 fclose(deps);
398}
399
400/* Convert a struct tm to a POSIX-style time constant */
401static int64_t make_posix_time(const struct tm *tm)
402{
403 int64_t t;
404 int64_t y = tm->tm_year;
405
406 /* See IEEE 1003.1:2004, section 4.14 */
407
408 t = (y-70)*365 + (y-69)/4 - (y-1)/100 + (y+299)/400;
409 t += tm->tm_yday;
410 t *= 24;
411 t += tm->tm_hour;
412 t *= 60;
413 t += tm->tm_min;
414 t *= 60;
415 t += tm->tm_sec;
416
417 return t;
418}
419
420static void timestamp(void)
421{
422 struct compile_time * const oct = &official_compile_time;
423 const struct tm *tp, *best_gm;
424
425 time(&oct->t);
426
427 best_gm = NULL;
428
429 tp = localtime(&oct->t);
430 if (tp) {
431 oct->local = *tp;
432 best_gm = &oct->local;
433 oct->have_local = true;
434 }
435
436 tp = gmtime(&oct->t);
437 if (tp) {
438 oct->gm = *tp;
439 best_gm = &oct->gm;
440 oct->have_gm = true;
441 if (!oct->have_local)
442 oct->local = oct->gm;
443 } else {
444 oct->gm = oct->local;
445 }
446
447 if (best_gm) {
448 oct->posix = make_posix_time(best_gm);
449 oct->have_posix = true;
450 }
451}
452
453int main(int argc, char **argv)
454{
455 StrList **depend_ptr;
456
457 timestamp();
458
459 error_file = stderr;
460
461 iflag_set_default_cpu(&cpu);
462 iflag_set_default_cpu(&cmd_cpu);
463
464 pass0 = 0;
465 want_usage = terminate_after_phase = false;
466 nasm_set_verror(nasm_verror_asm);
467
468 tolower_init();
469 src_init();
470
471 /*
472 * We must call init_labels() before the command line parsing,
473 * because we may be setting prefixes/suffixes from the command
474 * line.
475 */
476 init_labels();
477
478 offsets = raa_init();
479 forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo));
480
481 preproc = &nasmpp;
482 operating_mode = OP_NORMAL;
483
484 parse_cmdline(argc, argv, 1);
485 if (terminate_after_phase) {
486 if (want_usage)
487 usage();
488 return 1;
489 }
490
491 /* At this point we have ofmt and the name of the desired debug format */
492 if (!using_debug_info) {
493 /* No debug info, redirect to the null backend (empty stubs) */
494 dfmt = &null_debug_form;
495 } else if (!debug_format) {
496 /* Default debug format for this backend */
497 dfmt = ofmt->default_dfmt;
498 } else {
499 dfmt = dfmt_find(ofmt, debug_format);
500 if (!dfmt) {
501 nasm_fatal(ERR_USAGE,
502 "unrecognized debug format `%s' for"
503 " output format `%s'",
504 debug_format, ofmt->shortname);
505 }
506 }
507
508 preproc_init();
509
510 parse_cmdline(argc, argv, 2);
511 if (terminate_after_phase) {
512 if (want_usage)
513 usage();
514 return 1;
515 }
516
517 /* Save away the default state of warnings */
518 memcpy(warning_state_init, warning_state, sizeof warning_state);
519
520 /* Dependency filename if we are also doing other things */
521 if (!depend_file && (operating_mode & ~OP_DEPEND)) {
522 if (outname)
523 depend_file = nasm_strcat(outname, ".d");
524 else
525 depend_file = filename_set_extension(inname, ".d");
526 }
527
528 /*
529 * If no output file name provided and this
530 * is preprocess mode, we're perfectly
531 * fine to output into stdout.
532 */
533 if (!outname && !(operating_mode & OP_PREPROCESS)) {
534 outname = filename_set_extension(inname, ofmt->extension);
535 if (!strcmp(outname, inname)) {
536 outname = "nasm.out";
537 nasm_error(ERR_WARNING,
538 "default output file same as input, using `%s' for output\n",
539 outname);
540 }
541 }
542
543 depend_ptr = (operating_mode & OP_DEPEND) ? &depend_list : NULL;
544
545 if (!depend_target)
546 depend_target = quote_for_make(outname);
547
548 if (!(operating_mode & (OP_PREPROCESS|OP_NORMAL))) {
549 char *line;
550
551 if (depend_missing_ok)
552 preproc->include_path(NULL); /* "assume generated" */
553
554 preproc->reset(inname, 0, depend_ptr);
555 ofile = NULL;
556 while ((line = preproc->getline()))
557 nasm_free(line);
558 preproc->cleanup(0);
559 } else if (operating_mode & OP_PREPROCESS) {
560 char *line;
561 const char *file_name = NULL;
562 int32_t prior_linnum = 0;
563 int lineinc = 0;
564
565 if (outname) {
566 ofile = nasm_open_write(outname, NF_TEXT);
567 if (!ofile)
568 nasm_fatal(0, "unable to open output file `%s'", outname);
569 } else
570 ofile = NULL;
571
572 location.known = false;
573
574 /* pass = 1; */
575 preproc->reset(inname, 3, depend_ptr);
576
577 /* Revert all warnings to the default state */
578 memcpy(warning_state, warning_state_init, sizeof warning_state);
579
580 while ((line = preproc->getline())) {
581 /*
582 * We generate %line directives if needed for later programs
583 */
584 int32_t linnum = prior_linnum += lineinc;
585 int altline = src_get(&linnum, &file_name);
586 if (altline) {
587 if (altline == 1 && lineinc == 1)
588 nasm_fputs("", ofile);
589 else {
590 lineinc = (altline != -1 || lineinc != 1);
591 fprintf(ofile ? ofile : stdout,
592 "%%line %"PRId32"+%d %s\n", linnum, lineinc,
593 file_name);
594 }
595 prior_linnum = linnum;
596 }
597 nasm_fputs(line, ofile);
598 nasm_free(line);
599 }
600 preproc->cleanup(0);
601 if (ofile)
602 fclose(ofile);
603 if (ofile && terminate_after_phase && !keep_all)
604 remove(outname);
605 ofile = NULL;
606 }
607
608 if (operating_mode & OP_NORMAL) {
609 ofile = nasm_open_write(outname, (ofmt->flags & OFMT_TEXT) ? NF_TEXT : NF_BINARY);
610 if (!ofile)
611 nasm_fatal(ERR_NOFILE,
612 "unable to open output file `%s'", outname);
613
614 ofmt->init();
615 dfmt->init();
616
617 assemble_file(inname, depend_ptr);
618
619 if (!terminate_after_phase) {
620 ofmt->cleanup();
621 cleanup_labels();
622 fflush(ofile);
623 if (ferror(ofile)) {
624 nasm_error(ERR_NONFATAL|ERR_NOFILE,
625 "write error on output file `%s'", outname);
626 terminate_after_phase = true;
627 }
628 }
629
630 if (ofile) {
631 fclose(ofile);
632 if (terminate_after_phase && !keep_all)
633 remove(outname);
634 ofile = NULL;
635 }
636 }
637
638 if (depend_list && !terminate_after_phase)
639 emit_dependencies(depend_list);
640
641 if (want_usage)
642 usage();
643
644 raa_free(offsets);
645 saa_free(forwrefs);
646 eval_cleanup();
647 stdscan_cleanup();
648 src_free();
649
650 return terminate_after_phase;
651}
652
653/*
654 * Get a parameter for a command line option.
655 * First arg must be in the form of e.g. -f...
656 */
657static char *get_param(char *p, char *q, bool *advance)
658{
659 *advance = false;
660 if (p[2]) /* the parameter's in the option */
661 return nasm_skip_spaces(p + 2);
662 if (q && q[0]) {
663 *advance = true;
664 return q;
665 }
666 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
667 "option `-%c' requires an argument", p[1]);
668 return NULL;
669}
670
671/*
672 * Copy a filename
673 */
674static void copy_filename(const char **dst, const char *src, const char *what)
675{
676 if (*dst)
677 nasm_fatal(0, "more than one %s file specified: %s\n", what, src);
678
679 *dst = nasm_strdup(src);
680}
681
682/*
683 * Convert a string to a POSIX make-safe form
684 */
685static char *quote_for_pmake(const char *str)
686{
687 const char *p;
688 char *os, *q;
689
690 size_t n = 1; /* Terminating zero */
691 size_t nbs = 0;
692
693 if (!str)
694 return NULL;
695
696 for (p = str; *p; p++) {
697 switch (*p) {
698 case ' ':
699 case '\t':
700 /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
701 n += nbs + 2;
702 nbs = 0;
703 break;
704 case '$':
705 case '#':
706 nbs = 0;
707 n += 2;
708 break;
709 case '\\':
710 nbs++;
711 n++;
712 break;
713 default:
714 nbs = 0;
715 n++;
716 break;
717 }
718 }
719
720 /* Convert N backslashes at the end of filename to 2N backslashes */
721 if (nbs)
722 n += nbs;
723
724 os = q = nasm_malloc(n);
725
726 nbs = 0;
727 for (p = str; *p; p++) {
728 switch (*p) {
729 case ' ':
730 case '\t':
731 while (nbs--)
732 *q++ = '\\';
733 *q++ = '\\';
734 *q++ = *p;
735 break;
736 case '$':
737 *q++ = *p;
738 *q++ = *p;
739 nbs = 0;
740 break;
741 case '#':
742 *q++ = '\\';
743 *q++ = *p;
744 nbs = 0;
745 break;
746 case '\\':
747 *q++ = *p;
748 nbs++;
749 break;
750 default:
751 *q++ = *p;
752 nbs = 0;
753 break;
754 }
755 }
756 while (nbs--)
757 *q++ = '\\';
758
759 *q = '\0';
760
761 return os;
762}
763
764/*
765 * Convert a string to a Watcom make-safe form
766 */
767static char *quote_for_wmake(const char *str)
768{
769 const char *p;
770 char *os, *q;
771 bool quote = false;
772
773 size_t n = 1; /* Terminating zero */
774
775 if (!str)
776 return NULL;
777
778 for (p = str; *p; p++) {
779 switch (*p) {
780 case ' ':
781 case '\t':
782 case '&':
783 quote = true;
784 n++;
785 break;
786 case '\"':
787 quote = true;
788 n += 2;
789 break;
790 case '$':
791 case '#':
792 n += 2;
793 break;
794 default:
795 n++;
796 break;
797 }
798 }
799
800 if (quote)
801 n += 2;
802
803 os = q = nasm_malloc(n);
804
805 if (quote)
806 *q++ = '\"';
807
808 for (p = str; *p; p++) {
809 switch (*p) {
810 case '$':
811 case '#':
812 *q++ = '$';
813 *q++ = *p;
814 break;
815 case '\"':
816 *q++ = *p;
817 *q++ = *p;
818 break;
819 default:
820 *q++ = *p;
821 break;
822 }
823 }
824
825 if (quote)
826 *q++ = '\"';
827
828 *q = '\0';
829
830 return os;
831}
832
833enum text_options {
834 OPT_BOGUS,
835 OPT_VERSION,
836 OPT_HELP,
837 OPT_ABORT_ON_PANIC,
838 OPT_MANGLE,
839 OPT_INCLUDE,
840 OPT_PRAGMA,
841 OPT_BEFORE,
842 OPT_LIMIT,
843 OPT_KEEP_ALL,
844 OPT_NO_LINE
845};
846struct textargs {
847 const char *label;
848 enum text_options opt;
849 bool need_arg;
850 int pvt;
851};
852static const struct textargs textopts[] = {
853 {"v", OPT_VERSION, false, 0},
854 {"version", OPT_VERSION, false, 0},
855 {"help", OPT_HELP, false, 0},
856 {"abort-on-panic", OPT_ABORT_ON_PANIC, false, 0},
857 {"prefix", OPT_MANGLE, true, LM_GPREFIX},
858 {"postfix", OPT_MANGLE, true, LM_GSUFFIX},
859 {"gprefix", OPT_MANGLE, true, LM_GPREFIX},
860 {"gpostfix", OPT_MANGLE, true, LM_GSUFFIX},
861 {"lprefix", OPT_MANGLE, true, LM_LPREFIX},
862 {"lpostfix", OPT_MANGLE, true, LM_LSUFFIX},
863 {"include", OPT_INCLUDE, true, 0},
864 {"pragma", OPT_PRAGMA, true, 0},
865 {"before", OPT_BEFORE, true, 0},
866 {"limit-", OPT_LIMIT, true, 0},
867 {"keep-all", OPT_KEEP_ALL, false, 0},
868 {"no-line", OPT_NO_LINE, false, 0},
869 {NULL, OPT_BOGUS, false, 0}
870};
871
872static void show_version(void)
873{
874 printf("NASM version %s compiled on %s%s\n",
875 nasm_version, nasm_date, nasm_compile_options);
876 exit(0);
877}
878
879static bool stopoptions = false;
880static bool process_arg(char *p, char *q, int pass)
881{
882 char *param;
883 bool advance = false;
884
885 if (!p || !p[0])
886 return false;
887
888 if (p[0] == '-' && !stopoptions) {
889 if (strchr("oOfpPdDiIlFXuUZwW", p[1])) {
890 /* These parameters take values */
891 if (!(param = get_param(p, q, &advance)))
892 return advance;
893 }
894
895 switch (p[1]) {
896 case 's':
897 if (pass == 1)
898 error_file = stdout;
899 break;
900
901 case 'o': /* output file */
902 if (pass == 2)
903 copy_filename(&outname, param, "output");
904 break;
905
906 case 'f': /* output format */
907 if (pass == 1) {
908 ofmt = ofmt_find(param, &ofmt_alias);
909 if (!ofmt) {
910 nasm_fatal(ERR_USAGE, "unrecognised output format `%s' - use -hf for a list", param);
911 }
912 }
913 break;
914
915 case 'O': /* Optimization level */
916 if (pass == 1) {
917 int opt;
918
919 if (!*param) {
920 /* Naked -O == -Ox */
921 optimizing.level = MAX_OPTIMIZE;
922 } else {
923 while (*param) {
924 switch (*param) {
925 case '0': case '1': case '2': case '3': case '4':
926 case '5': case '6': case '7': case '8': case '9':
927 opt = strtoul(param, &param, 10);
928
929 /* -O0 -> optimizing.level == -1, 0.98 behaviour */
930 /* -O1 -> optimizing.level == 0, 0.98.09 behaviour */
931 if (opt < 2)
932 optimizing.level = opt - 1;
933 else
934 optimizing.level = opt;
935 break;
936
937 case 'v':
938 case '+':
939 param++;
940 opt_verbose_info = true;
941 break;
942
943 case 'x':
944 param++;
945 optimizing.level = MAX_OPTIMIZE;
946 break;
947
948 default:
949 nasm_fatal(0,
950 "unknown optimization option -O%c\n",
951 *param);
952 break;
953 }
954 }
955 if (optimizing.level > MAX_OPTIMIZE)
956 optimizing.level = MAX_OPTIMIZE;
957 }
958 }
959 break;
960
961 case 'p': /* pre-include */
962 case 'P':
963 if (pass == 2)
964 preproc->pre_include(param);
965 break;
966
967 case 'd': /* pre-define */
968 case 'D':
969 if (pass == 2)
970 preproc->pre_define(param);
971 break;
972
973 case 'u': /* un-define */
974 case 'U':
975 if (pass == 2)
976 preproc->pre_undefine(param);
977 break;
978
979 case 'i': /* include search path */
980 case 'I':
981 if (pass == 1)
982 nasm_add_string_to_strlist(&include_path, param);
983 break;
984
985 case 'l': /* listing file */
986 if (pass == 2)
987 copy_filename(&listname, param, "listing");
988 break;
989
990 case 'Z': /* error messages file */
991 if (pass == 1)
992 copy_filename(&errname, param, "error");
993 break;
994
995 case 'F': /* specify debug format */
996 if (pass == 1) {
997 using_debug_info = true;
998 debug_format = param;
999 }
1000 break;
1001
1002 case 'X': /* specify error reporting format */
1003 if (pass == 1) {
1004 if (!nasm_stricmp("vc", param) || !nasm_stricmp("msvc", param) || !nasm_stricmp("ms", param))
1005 errfmt = &errfmt_msvc;
1006 else if (!nasm_stricmp("gnu", param) || !nasm_stricmp("gcc", param))
1007 errfmt = &errfmt_gnu;
1008 else
1009 nasm_fatal(ERR_USAGE, "unrecognized error reporting format `%s'", param);
1010 }
1011 break;
1012
1013 case 'g':
1014 if (pass == 1) {
1015 using_debug_info = true;
1016 if (p[2])
1017 debug_format = nasm_skip_spaces(p + 2);
1018 }
1019 break;
1020
1021 case 'h':
1022 help(p[2]);
1023 exit(0); /* never need usage message here */
1024 break;
1025
1026 case 'y':
1027 printf("\nvalid debug formats for '%s' output format are"
1028 " ('*' denotes default):\n", ofmt->shortname);
1029 dfmt_list(ofmt, stdout);
1030 exit(0);
1031 break;
1032
1033 case 't':
1034 if (pass == 2)
1035 tasm_compatible_mode = true;
1036 break;
1037
1038 case 'v':
1039 show_version();
1040 break;
1041
1042 case 'e': /* preprocess only */
1043 case 'E':
1044 if (pass == 1)
1045 operating_mode = OP_PREPROCESS;
1046 break;
1047
1048 case 'a': /* assemble only - don't preprocess */
1049 if (pass == 1)
1050 preproc = &preproc_nop;
1051 break;
1052
1053 case 'w':
1054 case 'W':
1055 if (pass == 2) {
1056 if (!set_warning_status(param)) {
1057 nasm_error(ERR_WARNING|ERR_NOFILE|WARN_UNK_WARNING,
1058 "unknown warning option: %s", param);
1059 }
1060 }
1061 break;
1062
1063 case 'M':
1064 if (pass == 1) {
1065 switch (p[2]) {
1066 case 'W':
1067 quote_for_make = quote_for_wmake;
1068 break;
1069 case 'D':
1070 case 'F':
1071 case 'T':
1072 case 'Q':
1073 advance = true;
1074 break;
1075 default:
1076 break;
1077 }
1078 } else {
1079 switch (p[2]) {
1080 case 0:
1081 operating_mode = OP_DEPEND;
1082 break;
1083 case 'G':
1084 operating_mode = OP_DEPEND;
1085 depend_missing_ok = true;
1086 break;
1087 case 'P':
1088 depend_emit_phony = true;
1089 break;
1090 case 'D':
1091 operating_mode |= OP_DEPEND;
1092 if (q && (q[0] != '-' || q[1] == '\0')) {
1093 depend_file = q;
1094 advance = true;
1095 }
1096 break;
1097 case 'F':
1098 depend_file = q;
1099 advance = true;
1100 break;
1101 case 'T':
1102 depend_target = q;
1103 advance = true;
1104 break;
1105 case 'Q':
1106 depend_target = quote_for_make(q);
1107 advance = true;
1108 break;
1109 case 'W':
1110 /* handled in pass 1 */
1111 break;
1112 default:
1113 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
1114 "unknown dependency option `-M%c'", p[2]);
1115 break;
1116 }
1117 }
1118 if (advance && (!q || !q[0])) {
1119 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
1120 "option `-M%c' requires a parameter", p[2]);
1121 break;
1122 }
1123 break;
1124
1125 case '-':
1126 {
1127 const struct textargs *tx;
1128 size_t olen, plen;
1129 char *eqsave;
1130
1131 p += 2;
1132
1133 if (!*p) { /* -- => stop processing options */
1134 stopoptions = true;
1135 break;
1136 }
1137
1138 olen = 0; /* Placate gcc at lower optimization levels */
1139 plen = strlen(p);
1140 for (tx = textopts; tx->label; tx++) {
1141 olen = strlen(tx->label);
1142
1143 if (olen > plen)
1144 continue;
1145
1146 if (nasm_memicmp(p, tx->label, olen))
1147 continue;
1148
1149 if (tx->label[olen-1] == '-')
1150 break; /* Incomplete option */
1151
1152 if (!p[olen] || p[olen] == '=')
1153 break; /* Complete option */
1154 }
1155
1156 if (!tx->label) {
1157 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1158 "unrecognized option `--%s'", p);
1159 }
1160
1161 eqsave = param = strchr(p+olen, '=');
1162 if (param)
1163 *param++ = '\0';
1164
1165 if (tx->need_arg) {
1166 if (!param) {
1167 param = q;
1168 advance = true;
1169 }
1170
1171 /* Note: a null string is a valid parameter */
1172 if (!param) {
1173 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1174 "option `--%s' requires an argument",
1175 p);
1176 break;
1177 }
1178 } else {
1179 if (param) {
1180 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1181 "option `--%s' does not take an argument",
1182 p);
1183
1184 }
1185 }
1186
1187 switch (tx->opt) {
1188 case OPT_VERSION:
1189 show_version();
1190 break;
1191 case OPT_ABORT_ON_PANIC:
1192 abort_on_panic = true;
1193 break;
1194 case OPT_MANGLE:
1195 if (pass == 2)
1196 set_label_mangle(tx->pvt, param);
1197 break;
1198 case OPT_INCLUDE:
1199 if (pass == 2)
1200 preproc->pre_include(q);
1201 break;
1202 case OPT_PRAGMA:
1203 if (pass == 2)
1204 preproc->pre_command("pragma", param);
1205 break;
1206 case OPT_BEFORE:
1207 if (pass == 2)
1208 preproc->pre_command(NULL, param);
1209 break;
1210 case OPT_LIMIT:
1211 if (pass == 1)
1212 nasm_set_limit(p+olen, param);
1213 break;
1214 case OPT_KEEP_ALL:
1215 keep_all = true;
1216 break;
1217 case OPT_NO_LINE:
1218 pp_noline = true;
1219 break;
1220 case OPT_HELP:
1221 help(0);
1222 exit(0);
1223 default:
1224 panic();
1225 }
1226
1227 if (eqsave)
1228 *eqsave = '='; /* Restore = argument separator */
1229
1230 break;
1231 }
1232
1233 default:
1234 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1235 "unrecognised option `-%c'", p[1]);
1236 break;
1237 }
1238 } else if (pass == 2) {
1239 /* In theory we could allow multiple input files... */
1240 copy_filename(&inname, p, "input");
1241 }
1242
1243 return advance;
1244}
1245
1246#define ARG_BUF_DELTA 128
1247
1248static void process_respfile(FILE * rfile, int pass)
1249{
1250 char *buffer, *p, *q, *prevarg;
1251 int bufsize, prevargsize;
1252
1253 bufsize = prevargsize = ARG_BUF_DELTA;
1254 buffer = nasm_malloc(ARG_BUF_DELTA);
1255 prevarg = nasm_malloc(ARG_BUF_DELTA);
1256 prevarg[0] = '\0';
1257
1258 while (1) { /* Loop to handle all lines in file */
1259 p = buffer;
1260 while (1) { /* Loop to handle long lines */
1261 q = fgets(p, bufsize - (p - buffer), rfile);
1262 if (!q)
1263 break;
1264 p += strlen(p);
1265 if (p > buffer && p[-1] == '\n')
1266 break;
1267 if (p - buffer > bufsize - 10) {
1268 int offset;
1269 offset = p - buffer;
1270 bufsize += ARG_BUF_DELTA;
1271 buffer = nasm_realloc(buffer, bufsize);
1272 p = buffer + offset;
1273 }
1274 }
1275
1276 if (!q && p == buffer) {
1277 if (prevarg[0])
1278 process_arg(prevarg, NULL, pass);
1279 nasm_free(buffer);
1280 nasm_free(prevarg);
1281 return;
1282 }
1283
1284 /*
1285 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1286 * them are present at the end of the line.
1287 */
1288 *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
1289
1290 while (p > buffer && nasm_isspace(p[-1]))
1291 *--p = '\0';
1292
1293 p = nasm_skip_spaces(buffer);
1294
1295 if (process_arg(prevarg, p, pass))
1296 *p = '\0';
1297
1298 if ((int) strlen(p) > prevargsize - 10) {
1299 prevargsize += ARG_BUF_DELTA;
1300 prevarg = nasm_realloc(prevarg, prevargsize);
1301 }
1302 strncpy(prevarg, p, prevargsize);
1303 }
1304}
1305
1306/* Function to process args from a string of args, rather than the
1307 * argv array. Used by the environment variable and response file
1308 * processing.
1309 */
1310static void process_args(char *args, int pass)
1311{
1312 char *p, *q, *arg, *prevarg;
1313 char separator = ' ';
1314
1315 p = args;
1316 if (*p && *p != '-')
1317 separator = *p++;
1318 arg = NULL;
1319 while (*p) {
1320 q = p;
1321 while (*p && *p != separator)
1322 p++;
1323 while (*p == separator)
1324 *p++ = '\0';
1325 prevarg = arg;
1326 arg = q;
1327 if (process_arg(prevarg, arg, pass))
1328 arg = NULL;
1329 }
1330 if (arg)
1331 process_arg(arg, NULL, pass);
1332}
1333
1334static void process_response_file(const char *file, int pass)
1335{
1336 char str[2048];
1337 FILE *f = nasm_open_read(file, NF_TEXT);
1338 if (!f) {
1339 perror(file);
1340 exit(-1);
1341 }
1342 while (fgets(str, sizeof str, f)) {
1343 process_args(str, pass);
1344 }
1345 fclose(f);
1346}
1347
1348static void parse_cmdline(int argc, char **argv, int pass)
1349{
1350 FILE *rfile;
1351 char *envreal, *envcopy = NULL, *p;
1352 int i;
1353
1354 /*
1355 * Initialize all the warnings to their default state, including
1356 * warning index 0 used for "always on".
1357 */
1358 for (i = 0; i < WARN_ALL; i++)
1359 warning_state_init[i] = warning_state[i] = warnings[i].state;
1360
1361 /*
1362 * First, process the NASMENV environment variable.
1363 */
1364 envreal = getenv("NASMENV");
1365 if (envreal) {
1366 envcopy = nasm_strdup(envreal);
1367 process_args(envcopy, pass);
1368 nasm_free(envcopy);
1369 }
1370
1371 /*
1372 * Now process the actual command line.
1373 */
1374 while (--argc) {
1375 bool advance;
1376 argv++;
1377 if (argv[0][0] == '@') {
1378 /*
1379 * We have a response file, so process this as a set of
1380 * arguments like the environment variable. This allows us
1381 * to have multiple arguments on a single line, which is
1382 * different to the -@resp file processing below for regular
1383 * NASM.
1384 */
1385 process_response_file(argv[0]+1, pass);
1386 argc--;
1387 argv++;
1388 }
1389 if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
1390 p = get_param(argv[0], argc > 1 ? argv[1] : NULL, &advance);
1391 if (p) {
1392 rfile = nasm_open_read(p, NF_TEXT);
1393 if (rfile) {
1394 process_respfile(rfile, pass);
1395 fclose(rfile);
1396 } else
1397 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
1398 "unable to open response file `%s'", p);
1399 }
1400 } else
1401 advance = process_arg(argv[0], argc > 1 ? argv[1] : NULL, pass);
1402 argv += advance, argc -= advance;
1403 }
1404
1405 /*
1406 * Look for basic command line typos. This definitely doesn't
1407 * catch all errors, but it might help cases of fumbled fingers.
1408 */
1409 if (pass != 2)
1410 return;
1411
1412 if (!inname)
1413 nasm_fatal(ERR_USAGE, "no input file specified");
1414 else if ((errname && !strcmp(inname, errname)) ||
1415 (outname && !strcmp(inname, outname)) ||
1416 (listname && !strcmp(inname, listname)) ||
1417 (depend_file && !strcmp(inname, depend_file)))
1418 nasm_fatal(ERR_USAGE, "will not overwrite input file");
1419
1420 if (errname) {
1421 error_file = nasm_open_write(errname, NF_TEXT);
1422 if (!error_file) {
1423 error_file = stderr; /* Revert to default! */
1424 nasm_fatal(ERR_USAGE, "cannot open file `%s' for error messages", errname);
1425 }
1426 }
1427}
1428
1429static void assemble_file(const char *fname, StrList **depend_ptr)
1430{
1431 char *line;
1432 insn output_ins;
1433 int i;
1434 uint64_t prev_offset_changed;
1435 int64_t stall_count = 0; /* Make sure we make forward progress... */
1436
1437 switch (cmd_sb) {
1438 case 16:
1439 break;
1440 case 32:
1441 if (!iflag_cpu_level_ok(&cmd_cpu, IF_386))
1442 nasm_fatal(0, "command line: 32-bit segment size requires a higher cpu");
1443 break;
1444 case 64:
1445 if (!iflag_cpu_level_ok(&cmd_cpu, IF_X86_64))
1446 nasm_fatal(0, "command line: 64-bit segment size requires a higher cpu");
1447 break;
1448 default:
1449 panic();
1450 break;
1451 }
1452
1453 prev_offset_changed = nasm_limit[LIMIT_PASSES];
1454 for (passn = 1; pass0 <= 2; passn++) {
1455 pass1 = pass0 == 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
1456 pass2 = passn > 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
1457 /* pass0 0, 0, 0, ..., 1, 2 */
1458
1459 globalbits = cmd_sb; /* set 'bits' to command line default */
1460 cpu = cmd_cpu;
1461 if (pass0 == 2) {
1462 lfmt->init(listname);
1463 } else if (passn == 1 && listname && !keep_all) {
1464 /* Remove the list file in case we die before the output pass */
1465 remove(listname);
1466 }
1467 in_absolute = false;
1468 global_offset_changed = 0; /* set by redefine_label */
1469 if (passn > 1) {
1470 saa_rewind(forwrefs);
1471 forwref = saa_rstruct(forwrefs);
1472 raa_free(offsets);
1473 offsets = raa_init();
1474 }
1475 location.segment = NO_SEG;
1476 location.offset = 0;
1477 if (passn == 1)
1478 location.known = true;
1479 ofmt->reset();
1480 switch_segment(ofmt->section(NULL, pass2, &globalbits));
1481 preproc->reset(fname, pass1, pass1 == 2 ? depend_ptr : NULL);
1482
1483 /* Revert all warnings to the default state */
1484 memcpy(warning_state, warning_state_init, sizeof warning_state);
1485
1486 globallineno = 0;
1487
1488 while ((line = preproc->getline())) {
1489 if (++globallineno > nasm_limit[LIMIT_LINES])
1490 nasm_fatal(0,
1491 "overall line count exceeds the maximum %"PRId64"\n",
1492 nasm_limit[LIMIT_LINES]);
1493
1494 /*
1495 * Here we parse our directives; this is not handled by the
1496 * main parser.
1497 */
1498 if (process_directives(line))
1499 goto end_of_line; /* Just do final cleanup */
1500
1501 /* Not a directive, or even something that starts with [ */
1502 parse_line(pass1, line, &output_ins);
1503
1504 if (optimizing.level > 0) {
1505 if (forwref != NULL && globallineno == forwref->lineno) {
1506 output_ins.forw_ref = true;
1507 do {
1508 output_ins.oprs[forwref->operand].opflags |= OPFLAG_FORWARD;
1509 forwref = saa_rstruct(forwrefs);
1510 } while (forwref != NULL
1511 && forwref->lineno == globallineno);
1512 } else
1513 output_ins.forw_ref = false;
1514
1515 if (output_ins.forw_ref) {
1516 if (passn == 1) {
1517 for (i = 0; i < output_ins.operands; i++) {
1518 if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) {
1519 struct forwrefinfo *fwinf = (struct forwrefinfo *)saa_wstruct(forwrefs);
1520 fwinf->lineno = globallineno;
1521 fwinf->operand = i;
1522 }
1523 }
1524 }
1525 }
1526 }
1527
1528 /* forw_ref */
1529 if (output_ins.opcode == I_EQU) {
1530 if (!output_ins.label) {
1531 nasm_error(ERR_NONFATAL, "EQU not preceded by label");
1532 } else if (output_ins.operands == 1 &&
1533 (output_ins.oprs[0].type & IMMEDIATE) &&
1534 output_ins.oprs[0].wrt == NO_SEG) {
1535 define_label(output_ins.label,
1536 output_ins.oprs[0].segment,
1537 output_ins.oprs[0].offset, false);
1538 } else if (output_ins.operands == 2
1539 && (output_ins.oprs[0].type & IMMEDIATE)
1540 && (output_ins.oprs[0].type & COLON)
1541 && output_ins.oprs[0].segment == NO_SEG
1542 && output_ins.oprs[0].wrt == NO_SEG
1543 && (output_ins.oprs[1].type & IMMEDIATE)
1544 && output_ins.oprs[1].segment == NO_SEG
1545 && output_ins.oprs[1].wrt == NO_SEG) {
1546 define_label(output_ins.label,
1547 output_ins.oprs[0].offset | SEG_ABS,
1548 output_ins.oprs[1].offset, false);
1549 } else {
1550 nasm_error(ERR_NONFATAL, "bad syntax for EQU");
1551 }
1552 } else { /* instruction isn't an EQU */
1553 int32_t n;
1554
1555 nasm_assert(output_ins.times >= 0);
1556
1557 for (n = 1; n <= output_ins.times; n++) {
1558 if (pass1 == 1) {
1559 int64_t l = insn_size(location.segment,
1560 location.offset,
1561 globalbits, &output_ins);
1562
1563 /* if (using_debug_info) && output_ins.opcode != -1) */
1564 if (using_debug_info)
1565 { /* fbk 03/25/01 */
1566 /* this is done here so we can do debug type info */
1567 int32_t typeinfo =
1568 TYS_ELEMENTS(output_ins.operands);
1569 switch (output_ins.opcode) {
1570 case I_RESB:
1571 typeinfo =
1572 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
1573 break;
1574 case I_RESW:
1575 typeinfo =
1576 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
1577 break;
1578 case I_RESD:
1579 typeinfo =
1580 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
1581 break;
1582 case I_RESQ:
1583 typeinfo =
1584 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
1585 break;
1586 case I_REST:
1587 typeinfo =
1588 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
1589 break;
1590 case I_RESO:
1591 typeinfo =
1592 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_OWORD;
1593 break;
1594 case I_RESY:
1595 typeinfo =
1596 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_YWORD;
1597 break;
1598 case I_RESZ:
1599 typeinfo =
1600 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_ZWORD;
1601 break;
1602 case I_DB:
1603 typeinfo |= TY_BYTE;
1604 break;
1605 case I_DW:
1606 typeinfo |= TY_WORD;
1607 break;
1608 case I_DD:
1609 if (output_ins.eops_float)
1610 typeinfo |= TY_FLOAT;
1611 else
1612 typeinfo |= TY_DWORD;
1613 break;
1614 case I_DQ:
1615 typeinfo |= TY_QWORD;
1616 break;
1617 case I_DT:
1618 typeinfo |= TY_TBYTE;
1619 break;
1620 case I_DO:
1621 typeinfo |= TY_OWORD;
1622 break;
1623 case I_DY:
1624 typeinfo |= TY_YWORD;
1625 break;
1626 case I_DZ:
1627 typeinfo |= TY_ZWORD;
1628 break;
1629 default:
1630 typeinfo = TY_LABEL;
1631 break;
1632 }
1633
1634 dfmt->debug_typevalue(typeinfo);
1635 }
1636
1637 /*
1638 * For INCBIN, let the code in assemble
1639 * handle TIMES, so we don't have to read the
1640 * input file over and over.
1641 */
1642 if (l != -1) {
1643 increment_offset(l);
1644 }
1645 /*
1646 * else l == -1 => invalid instruction, which will be
1647 * flagged as an error on pass 2
1648 */
1649 } else {
1650 if (n == 2)
1651 lfmt->uplevel(LIST_TIMES);
1652 increment_offset(assemble(location.segment,
1653 location.offset,
1654 globalbits, &output_ins));
1655 }
1656 } /* not an EQU */
1657 }
1658 if (output_ins.times > 1)
1659 lfmt->downlevel(LIST_TIMES);
1660
1661 cleanup_insn(&output_ins);
1662
1663 end_of_line:
1664 nasm_free(line);
1665 } /* end while (line = preproc->getline... */
1666
1667 if (global_offset_changed && !terminate_after_phase) {
1668 switch (pass0) {
1669 case 1:
1670 nasm_error(ERR_WARNING|WARN_PHASE,
1671 "phase error during stabilization pass, hoping for the best");
1672 break;
1673
1674 case 2:
1675 nasm_error(ERR_NONFATAL,
1676 "phase error during code generation pass");
1677 break;
1678
1679 default:
1680 /* This is normal, we'll keep going... */
1681 break;
1682 }
1683 }
1684
1685 if (pass1 == 1)
1686 preproc->cleanup(1);
1687
1688 /*
1689 * Always run at least two optimization passes (pass0 == 0);
1690 * things like subsections will fail miserably without that.
1691 * Once we commit to a stabilization pass (pass0 == 1), we can't
1692 * go back, and if something goes bad, we can only hope
1693 * that we don't end up with a phase error at the end.
1694 */
1695 if ((passn > 1 && !global_offset_changed) || pass0 > 0) {
1696 pass0++;
1697 } else if (global_offset_changed &&
1698 global_offset_changed < prev_offset_changed) {
1699 prev_offset_changed = global_offset_changed;
1700 stall_count = 0;
1701 } else {
1702 stall_count++;
1703 }
1704
1705 if (terminate_after_phase)
1706 break;
1707
1708 if ((stall_count > nasm_limit[LIMIT_STALLED]) ||
1709 (passn >= nasm_limit[LIMIT_PASSES])) {
1710 /* We get here if the labels don't converge
1711 * Example: FOO equ FOO + 1
1712 */
1713 nasm_error(ERR_NONFATAL,
1714 "Can't find valid values for all labels "
1715 "after %"PRId64" passes, giving up.", passn);
1716 nasm_error(ERR_NONFATAL,
1717 "Possible causes: recursive EQUs, macro abuse.");
1718 break;
1719 }
1720 }
1721
1722 preproc->cleanup(0);
1723 lfmt->cleanup();
1724 if (!terminate_after_phase && opt_verbose_info) {
1725 /* -On and -Ov switches */
1726 fprintf(stdout, "info: assembly required 1+%"PRId64"+1 passes\n",
1727 passn-3);
1728 }
1729}
1730
1731/**
1732 * get warning index; 0 if this is non-suppressible.
1733 */
1734static size_t warn_index(int severity)
1735{
1736 size_t index;
1737
1738 if ((severity & ERR_MASK) >= ERR_FATAL)
1739 return 0; /* Fatal errors are never suppressible */
1740
1741 /* If this is a warning and no index is provided, it is WARN_OTHER */
1742 if ((severity & (ERR_MASK|WARN_MASK)) == ERR_WARNING)
1743 severity |= WARN_OTHER;
1744
1745 index = WARN_IDX(severity);
1746 nasm_assert(index < WARN_ALL);
1747
1748 return index;
1749}
1750
1751static bool skip_this_pass(int severity)
1752{
1753 /*
1754 * See if it's a pass-specific error or warning which should be skipped.
1755 * We can never skip fatal errors as by definition they cannot be
1756 * resumed from.
1757 */
1758 if ((severity & ERR_MASK) >= ERR_FATAL)
1759 return false;
1760
1761 /*
1762 * passn is 1 on the very first pass only.
1763 * pass0 is 2 on the code-generation (final) pass only.
1764 * These are the passes we care about in this case.
1765 */
1766 return (((severity & ERR_PASS1) && passn != 1) ||
1767 ((severity & ERR_PASS2) && pass0 != 2));
1768}
1769
1770/**
1771 * check for suppressed message (usually warnings or notes)
1772 *
1773 * @param severity the severity of the warning or error
1774 * @return true if we should abort error/warning printing
1775 */
1776static bool is_suppressed(int severity)
1777{
1778 if ((severity & ERR_MASK) >= ERR_FATAL)
1779 return false; /* Fatal errors can never be suppressed */
1780
1781 return !(warning_state[warn_index(severity)] & WARN_ST_ENABLED);
1782}
1783
1784/**
1785 * Return the true error type (the ERR_MASK part) of the given
1786 * severity, accounting for warnings that may need to be promoted to
1787 * error.
1788 *
1789 * @param severity the severity of the warning or error
1790 * @return true if we should error out
1791 */
1792static int true_error_type(int severity)
1793{
1794 const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR;
1795 int type;
1796
1797 type = severity & ERR_MASK;
1798
1799 /* Promote warning to error? */
1800 if (type == ERR_WARNING) {
1801 uint8_t state = warning_state[warn_index(severity)];
1802 if ((state & warn_is_err) == warn_is_err)
1803 type = ERR_NONFATAL;
1804 }
1805
1806 return type;
1807}
1808
1809/**
1810 * common error reporting
1811 * This is the common back end of the error reporting schemes currently
1812 * implemented. It prints the nature of the warning and then the
1813 * specific error message to error_file and may or may not return. It
1814 * doesn't return if the error severity is a "panic" or "debug" type.
1815 *
1816 * @param severity the severity of the warning or error
1817 * @param fmt the printf style format string
1818 */
1819static void nasm_verror_asm(int severity, const char *fmt, va_list args)
1820{
1821 char msg[1024];
1822 char warnsuf[64];
1823 char linestr[64];
1824 const char *pfx;
1825 int spec_type = severity & ERR_MASK; /* type originally specified */
1826 int true_type = true_error_type(severity);
1827 const char *currentfile = NULL;
1828 int32_t lineno = 0;
1829 static const char * const pfx_table[ERR_MASK+1] = {
1830 "debug: ", "note: ", "warning: ", "error: ",
1831 "", "", "fatal: ", "panic: "
1832 };
1833
1834 if (is_suppressed(severity))
1835 return;
1836
1837 if (!(severity & ERR_NOFILE)) {
1838 src_get(&lineno, &currentfile);
1839 if (!currentfile) {
1840 currentfile = currentfile ? currentfile :
1841 inname && inname[0] ? inname :
1842 outname && outname[0] ? outname :
1843 NULL;
1844 lineno = 0;
1845 }
1846 }
1847
1848 /*
1849 * For a debug/warning/note event, if ERR_HERE is set don't
1850 * output anything if there is no current filename available
1851 */
1852 if (!currentfile && (severity & ERR_HERE) && true_type <= ERR_WARNING)
1853 return;
1854
1855 if (severity & ERR_NO_SEVERITY)
1856 pfx = "";
1857 else
1858 pfx = pfx_table[true_type];
1859
1860 vsnprintf(msg, sizeof msg, fmt, args);
1861 *warnsuf = 0;
1862 if (spec_type == ERR_WARNING) {
1863 snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]",
1864 (true_type >= ERR_NONFATAL) ? "error=" : "",
1865 warnings[warn_index(severity)].name);
1866 }
1867
1868 *linestr = 0;
1869 if (lineno) {
1870 snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
1871 errfmt->beforeline, lineno, errfmt->afterline);
1872 }
1873
1874 if (!skip_this_pass(severity)) {
1875 fprintf(error_file, "%s%s%s%s%s%s%s\n",
1876 currentfile ? currentfile : "nasm",
1877 linestr, errfmt->beforemsg, pfx, msg,
1878 (severity & ERR_HERE) ? " here" : "", warnsuf);
1879 }
1880
1881 /* Are we recursing from error_list_macros? */
1882 if (severity & ERR_PP_LISTMACRO)
1883 return;
1884
1885 /*
1886 * Don't suppress this with skip_this_pass(), or we don't get
1887 * pass1 or preprocessor warnings in the list file
1888 */
1889 if (severity & ERR_HERE) {
1890 if (lineno)
1891 lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
1892 pfx, msg, currentfile, lineno, warnsuf);
1893 else if (currentfile)
1894 lfmt->error(severity, "%s%s in file %s%s",
1895 pfx, msg, currentfile, warnsuf);
1896 else
1897 lfmt->error(severity, "%s%s in unknown location%s",
1898 pfx, msg, warnsuf);
1899 } else {
1900 lfmt->error(severity, "%s%s%s", pfx, msg, warnsuf);
1901 }
1902
1903 if (skip_this_pass(severity))
1904 return;
1905
1906 if (severity & ERR_USAGE)
1907 want_usage = true;
1908
1909 preproc->error_list_macros(severity);
1910
1911 switch (true_type) {
1912 case ERR_NOTE:
1913 case ERR_DEBUG:
1914 case ERR_WARNING:
1915 /* no further action, by definition */
1916 break;
1917 case ERR_NONFATAL:
1918 terminate_after_phase = true;
1919 break;
1920 case ERR_FATAL:
1921 if (ofile) {
1922 fclose(ofile);
1923 if (!keep_all)
1924 remove(outname);
1925 ofile = NULL;
1926 }
1927 if (want_usage)
1928 usage();
1929 exit(1); /* instantly die */
1930 break; /* placate silly compilers */
1931 case ERR_PANIC:
1932 fflush(NULL);
1933
1934 if (abort_on_panic)
1935 abort(); /* halt, catch fire, dump core/stop debugger */
1936
1937 if (ofile) {
1938 fclose(ofile);
1939 if (!keep_all)
1940 remove(outname);
1941 ofile = NULL;
1942 }
1943 exit(3);
1944 break;
1945 default:
1946 break; /* ??? */
1947 }
1948}
1949
1950static void usage(void)
1951{
1952 fputs("type `nasm -h' for help\n", error_file);
1953}
1954
1955static void help(const char xopt)
1956{
1957 int i;
1958
1959 printf
1960 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
1961 "[-l listfile]\n"
1962 " [options...] [--] filename\n"
1963 " or nasm -v (or --v) for version info\n\n"
1964 "\n"
1965 "Response files should contain command line parameters,\n"
1966 "one per line.\n"
1967 "\n"
1968 " -t assemble in SciTech TASM compatible mode\n");
1969 printf
1970 (" -E (or -e) preprocess only (writes output to stdout by default)\n"
1971 " -a don't preprocess (assemble only)\n"
1972 " -M generate Makefile dependencies on stdout\n"
1973 " -MG d:o, missing files assumed generated\n"
1974 " -MF file set Makefile dependency file\n"
1975 " -MD file assemble and generate dependencies\n"
1976 " -MT file dependency target name\n"
1977 " -MQ file dependency target name (quoted)\n"
1978 " -MP emit phony target\n\n"
1979 " -Zfile redirect error messages to file\n"
1980 " -s redirect error messages to stdout\n\n"
1981 " -g generate debugging information\n\n"
1982 " -F format select a debugging format\n\n"
1983 " -gformat same as -g -F format\n\n"
1984 " -o outfile write output to an outfile\n\n"
1985 " -f format select an output format\n\n"
1986 " -l listfile write listing to a listfile\n\n"
1987 " -Ipath add a pathname to the include file path\n");
1988 printf
1989 (" -Oflags... optimize opcodes, immediates and branch offsets\n"
1990 " -O0 no optimization\n"
1991 " -O1 minimal optimization\n"
1992 " -Ox multipass optimization (default)\n"
1993 " -Ov display the number of passes executed at the end\n"
1994 " -Pfile pre-include a file (also --include)\n"
1995 " -Dmacro[=str] pre-define a macro\n"
1996 " -Umacro undefine a macro\n"
1997 " -Xformat specifiy error reporting format (gnu or vc)\n"
1998 " -w+foo enable warning foo (equiv. -Wfoo)\n"
1999 " -w-foo disable warning foo (equiv. -Wno-foo)\n"
2000 " -w[+-]error[=foo]\n"
2001 " promote [specific] warnings to errors\n"
2002 " -h show invocation summary and exit (also --help)\n\n"
2003 " --pragma str pre-executes a specific %%pragma\n"
2004 " --before str add line (usually a preprocessor statement) before the input\n"
2005 " --prefix str prepend the given string to all the given string\n"
2006 " to all extern, common and global symbols (also --gprefix)\n"
2007 " --postfix str append the given string to all the given string\n"
2008 " to all extern, common and global symbols (also --gpostfix)\n"
2009 " --lprefix str prepend the given string to all other symbols\n"
2010 " --lpostfix str append the given string to all other symbols\n"
2011 " --keep-all output files will not be removed even if an error happens\n"
2012 " --no-line ignore %%line directives in input\n"
2013 " --limit-X val set execution limit X\n");
2014
2015 for (i = 0; i <= LIMIT_MAX; i++) {
2016 printf(" %-15s %s (default ",
2017 limit_info[i].name, limit_info[i].help);
2018 if (nasm_limit[i] < LIMIT_MAX_VAL) {
2019 printf("%"PRId64")\n", nasm_limit[i]);
2020 } else {
2021 printf("unlimited)\n");
2022 }
2023 }
2024
2025 printf("\nWarnings for the -W/-w options: (default in brackets)\n");
2026
2027 for (i = 1; i <= WARN_ALL; i++)
2028 printf(" %-23s %s%s\n",
2029 warnings[i].name, warnings[i].help,
2030 i == WARN_ALL ? "\n" :
2031 (warnings[i].state & WARN_ST_ERROR) ? " [error]" :
2032 (warnings[i].state & WARN_ST_ENABLED) ? " [on]" : " [off]");
2033
2034 if (xopt == 'f') {
2035 printf("valid output formats for -f are"
2036 " (`*' denotes default):\n");
2037 ofmt_list(ofmt, stdout);
2038 } else {
2039 printf("For a list of valid output formats, use -hf.\n");
2040 printf("For a list of debug formats, use -f <format> -y.\n");
2041 }
2042}
2043