NASM 0.98
[nasm/avx512.git] / nasm.c
blob3c5327a41652b72a466995ec8ffb184a0649b1ea
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 licence given in the file "Licence"
6 * distributed in the NASM archive.
7 */
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
15 #include "nasm.h"
16 #include "nasmlib.h"
17 #include "preproc.h"
18 #include "parser.h"
19 #include "eval.h"
20 #include "assemble.h"
21 #include "labels.h"
22 #include "outform.h"
23 #include "listing.h"
25 struct forwrefinfo { /* info held on forward refs. */
26 int lineno;
27 int operand;
30 static void report_error (int, char *, ...);
31 static void parse_cmdline (int, char **);
32 static void assemble_file (char *);
33 static int getkw (char *buf, char **value);
34 static void register_output_formats(void);
35 static void usage(void);
37 static int using_debug_info;
39 static char inname[FILENAME_MAX];
40 static char outname[FILENAME_MAX];
41 static char listname[FILENAME_MAX];
42 static int globallineno; /* for forward-reference tracking */
43 static int pass;
44 static struct ofmt *ofmt = NULL;
46 static FILE *error_file; /* Where to write error messages */
48 static FILE *ofile = NULL;
49 static int sb = 16; /* by default */
51 static loc_t location;
52 int in_abs_seg; /* Flag we are in ABSOLUTE seg */
53 static long abs_seg;
55 static struct RAA *offsets;
56 static long abs_offset;
58 static struct SAA *forwrefs; /* keep track of forward references */
59 static struct forwrefinfo *forwref;
61 static Preproc *preproc;
62 enum op_type {
63 op_normal, /* Preprocess and assemble */
64 op_preprocess, /* Preprocess only */
65 op_depend /* Generate dependencies */
67 static enum op_type operating_mode;
69 /* used by error function to report location */
72 * Which of the suppressible warnings are suppressed. Entry zero
73 * doesn't do anything. Initial defaults are given here.
75 static char suppressed[1+ERR_WARN_MAX] = {
76 0, TRUE, TRUE, FALSE
80 * The option names for the suppressible warnings. As before, entry
81 * zero does nothing.
83 static char *suppressed_names[1+ERR_WARN_MAX] = {
84 NULL, "macro-params", "orphan-labels", "number-overflow"
88 * The explanations for the suppressible warnings. As before, entry
89 * zero does nothing.
91 static char *suppressed_what[1+ERR_WARN_MAX] = {
92 NULL, "macro calls with wrong no. of params",
93 "labels alone on lines without trailing `:'",
94 "numeric constants greater than 0xFFFFFFFF"
98 * This is a null preprocessor which just copies lines from input
99 * to output. It's used when someone explicitly requests that NASM
100 * not preprocess their source file.
103 static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
104 static char *no_pp_getline (void);
105 static void no_pp_cleanup (void);
106 static Preproc no_pp = {
107 no_pp_reset,
108 no_pp_getline,
109 no_pp_cleanup
113 * get/set current offset...
115 #define get_curr_ofs (in_abs_seg?abs_offset:\
116 raa_read(offsets,location.segment))
117 #define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\
118 (void)(offsets=raa_write(offsets,location.segment,(x))))
120 static int want_usage;
121 static int terminate_after_phase;
123 static void nasm_fputs(char *line, FILE *ofile)
125 if (ofile) {
126 fputs(line, ofile);
127 fputc('\n', ofile);
128 } else
129 puts(line);
132 int main(int argc, char **argv)
134 want_usage = terminate_after_phase = FALSE;
136 nasm_set_malloc_error (report_error);
137 offsets = raa_init();
138 forwrefs = saa_init ((long)sizeof(struct forwrefinfo));
140 preproc = &nasmpp;
141 operating_mode = op_normal;
143 error_file = stderr;
145 seg_init();
147 register_output_formats();
149 parse_cmdline(argc, argv);
151 if (terminate_after_phase)
153 if (want_usage)
154 usage();
155 return 1;
158 if (ofmt->stdmac)
159 pp_extra_stdmac (ofmt->stdmac);
160 parser_global_info (ofmt, &location);
161 eval_global_info (ofmt, lookup_label, &location);
163 switch ( operating_mode ) {
164 case op_depend:
166 char *line;
167 preproc->reset (inname, 0, report_error, evaluate, &nasmlist);
168 if (outname[0] == '\0')
169 ofmt->filename (inname, outname, report_error);
170 ofile = NULL;
171 printf("%s: %s", outname, inname);
172 while ( (line = preproc->getline()) )
173 nasm_free (line);
174 preproc->cleanup();
175 putc('\n', stdout);
177 break;
179 case op_preprocess:
181 char *line;
182 char *file_name = NULL;
183 long prior_linnum=0;
184 int lineinc=0;
186 if (*outname) {
187 ofile = fopen(outname, "w");
188 if (!ofile)
189 report_error (ERR_FATAL | ERR_NOFILE,
190 "unable to open output file `%s'", outname);
191 } else
192 ofile = NULL;
194 location.known = FALSE;
196 preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
197 while ( (line = preproc->getline()) ) {
199 * We generate %line directives if needed for later programs
201 long linnum = prior_linnum += lineinc;
202 int altline = src_get(&linnum, &file_name);
203 if (altline) {
204 if (altline==1 && lineinc==1)
205 nasm_fputs("", ofile);
206 else {
207 lineinc = (altline != -1 || lineinc!=1);
208 fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n",
209 linnum, lineinc, file_name);
211 prior_linnum = linnum;
213 nasm_fputs(line, ofile);
214 nasm_free (line);
216 nasm_free(file_name);
217 preproc->cleanup();
218 if (ofile)
219 fclose(ofile);
220 if (ofile && terminate_after_phase)
221 remove(outname);
223 break;
225 case op_normal:
228 * We must call ofmt->filename _anyway_, even if the user
229 * has specified their own output file, because some
230 * formats (eg OBJ and COFF) use ofmt->filename to find out
231 * the name of the input file and then put that inside the
232 * file.
234 ofmt->filename (inname, outname, report_error);
236 ofile = fopen(outname, "wb");
237 if (!ofile) {
238 report_error (ERR_FATAL | ERR_NOFILE,
239 "unable to open output file `%s'", outname);
243 * We must call init_labels() before ofmt->init() since
244 * some object formats will want to define labels in their
245 * init routines. (eg OS/2 defines the FLAT group)
247 init_labels ();
249 ofmt->init (ofile, report_error, define_label, evaluate);
251 assemble_file (inname);
253 if (!terminate_after_phase) {
254 ofmt->cleanup (using_debug_info);
255 cleanup_labels ();
257 else {
260 * We had an fclose on the output file here, but we
261 * actually do that in all the object file drivers as well,
262 * so we're leaving out the one here.
263 * fclose (ofile);
266 remove(outname);
267 if (listname[0])
268 remove(listname);
271 break;
274 if (want_usage)
275 usage();
277 raa_free (offsets);
278 saa_free (forwrefs);
279 eval_cleanup ();
280 nasmlib_cleanup ();
282 if (terminate_after_phase)
283 return 1;
284 else
285 return 0;
290 * Get a parameter for a command line option.
291 * First arg must be in the form of e.g. -f...
293 static char *get_param (char *p, char *q, int *advance)
295 *advance = 0;
296 if (p[2]) /* the parameter's in the option */
298 p += 2;
299 while (isspace(*p))
300 p++;
301 return p;
303 if (q && q[0])
305 *advance = 1;
306 return q;
308 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
309 "option `-%c' requires an argument",
310 p[1]);
311 return NULL;
314 int stopoptions = 0;
315 static int process_arg (char *p, char *q)
317 char *param;
318 int i, advance = 0;
320 if (!p || !p[0])
321 return 0;
323 if (p[0]=='-' && ! stopoptions)
325 switch (p[1]) {
326 case '-': /* -- => stop processing options */
327 stopoptions = 1;
328 break;
329 case 's':
330 error_file = stdout;
331 break;
332 case 'o': /* these parameters take values */
333 case 'f':
334 case 'p':
335 case 'd':
336 case 'D':
337 case 'i':
338 case 'l':
339 case 'E':
340 case 'F':
341 if ( !(param = get_param (p, q, &advance)) )
342 break;
343 if (p[1]=='o') { /* output file */
344 strcpy (outname, param);
345 } else if (p[1]=='f') { /* output format */
346 ofmt = ofmt_find(param);
347 if (!ofmt) {
348 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
349 "unrecognised output format `%s' - "
350 "use -hf for a list",
351 param);
353 else
354 ofmt->current_dfmt = ofmt->debug_formats[0];
355 } else if (p[1]=='P' || p[1]=='p') { /* pre-include */
356 pp_pre_include (param);
357 } else if (p[1]=='D' || p[1]=='d') { /* pre-define */
358 pp_pre_define (param);
359 } else if (p[1]=='U' || p[1]=='u') { /* un-define */
360 pp_pre_undefine (param);
361 } else if (p[1]=='I' || p[1]=='i') { /* include search path */
362 pp_include_path (param);
363 } else if (p[1]=='l') { /* listing file */
364 strcpy (listname, param);
365 } else if (p[1]=='E') { /* error messages file */
366 error_file = fopen(param, "wt");
367 if ( !error_file ) {
368 error_file = stderr; /* Revert to default! */
369 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
370 "cannot open file `%s' for error messages",
371 param);
373 } else if (p[1] == 'F') { /* specify debug format */
374 ofmt->current_dfmt = dfmt_find(ofmt, param);
375 if (!ofmt->current_dfmt) {
376 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
377 "unrecognized debug format `%s' for"
378 " output format `%s'",
379 param, ofmt->shortname);
382 break;
383 case 'g':
384 using_debug_info = TRUE;
385 break;
386 case 'h':
387 printf("usage: nasm [-@ response file] [-o outfile] [-f format] "
388 "[-l listfile]\n"
389 " [options...] [--] filename\n"
390 " or nasm -r for version info\n\n"
391 " -e preprocess only (writes output to stdout by default)\n"
392 " -a don't preprocess (assemble only)\n"
393 " -M generate Makefile dependencies on stdout\n\n"
394 " -E<file> redirect error messages to file\n"
395 " -s redirect error messages to stdout\n\n"
396 " -g enable debug info\n"
397 " -F format select a debugging format\n\n"
398 " -I<path> adds a pathname to the include file path\n"
399 " -P<file> pre-includes a file\n"
400 " -D<macro>[=<value>] pre-defines a macro\n"
401 " -U<macro> undefines a macro\n"
402 " -w+foo enables warnings about foo; -w-foo disables them\n"
403 "where foo can be:\n");
404 for (i=1; i<=ERR_WARN_MAX; i++)
405 printf(" %-16s%s (default %s)\n",
406 suppressed_names[i], suppressed_what[i],
407 suppressed[i] ? "off" : "on");
408 printf ("\nresponse files should contain command line parameters"
409 ", one per line.\n");
410 if (p[2] == 'f') {
411 printf("\nvalid output formats for -f are"
412 " (`*' denotes default):\n");
413 ofmt_list(ofmt, stdout);
415 else {
416 printf ("\nFor a list of valid output formats, use -hf.\n");
417 printf ("For a list of debug formats, use -f <form> -y.\n");
419 exit (0); /* never need usage message here */
420 break;
421 case 'y':
422 printf("\nvalid debug formats for '%s' output format are"
423 " ('*' denotes default):\n",
424 ofmt->shortname);
425 dfmt_list(ofmt, stdout);
426 exit(0);
427 break;
428 case 'r':
429 printf("NASM version %s\n", NASM_VER);
430 #ifdef DEBUG
431 printf("Compiled with -DDEBUG on " __DATE__ "\n");
432 #endif
433 exit (0); /* never need usage message here */
434 break;
435 case 'e': /* preprocess only */
436 operating_mode = op_preprocess;
437 break;
438 case 'a': /* assemble only - don't preprocess */
439 preproc = &no_pp;
440 break;
441 case 'w':
442 if (p[2] != '+' && p[2] != '-') {
443 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
444 "invalid option to `-w'");
445 } else {
446 for (i=1; i<=ERR_WARN_MAX; i++)
447 if (!nasm_stricmp(p+3, suppressed_names[i]))
448 break;
449 if (i <= ERR_WARN_MAX)
450 suppressed[i] = (p[2] == '-');
451 else
452 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
453 "invalid option to `-w'");
455 break;
456 case 'M':
457 operating_mode = op_depend;
458 break;
459 default:
460 if (!ofmt->setinfo(GI_SWITCH,&p))
461 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
462 "unrecognised option `-%c'",
463 p[1]);
464 break;
467 else
469 if (*inname) {
470 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
471 "more than one input file specified");
472 } else
473 strcpy(inname, p);
476 return advance;
479 #define ARG_BUF_DELTA 128
481 static void process_respfile (FILE *rfile)
483 char *buffer, *p, *q, *prevarg;
484 int bufsize, prevargsize;
486 bufsize = prevargsize = ARG_BUF_DELTA;
487 buffer = nasm_malloc(ARG_BUF_DELTA);
488 prevarg = nasm_malloc(ARG_BUF_DELTA);
489 prevarg[0] = '\0';
491 while (1) { /* Loop to handle all lines in file */
493 p = buffer;
494 while (1) { /* Loop to handle long lines */
495 q = fgets(p, bufsize-(p-buffer), rfile);
496 if (!q)
497 break;
498 p += strlen(p);
499 if (p > buffer && p[-1] == '\n')
500 break;
501 if (p-buffer > bufsize-10) {
502 int offset;
503 offset = p - buffer;
504 bufsize += ARG_BUF_DELTA;
505 buffer = nasm_realloc(buffer, bufsize);
506 p = buffer + offset;
510 if (!q && p == buffer) {
511 if (prevarg[0])
512 process_arg (prevarg, NULL);
513 nasm_free (buffer);
514 nasm_free (prevarg);
515 return;
519 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
520 * them are present at the end of the line.
522 *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
524 while (p > buffer && isspace(p[-1]))
525 *--p = '\0';
527 p = buffer;
528 while (isspace(*p))
529 p++;
531 if (process_arg (prevarg, p))
532 *p = '\0';
534 if (strlen(p) > prevargsize-10) {
535 prevargsize += ARG_BUF_DELTA;
536 prevarg = nasm_realloc(prevarg, prevargsize);
538 strcpy (prevarg, p);
542 static void parse_cmdline(int argc, char **argv)
544 FILE *rfile;
545 char *envreal, *envcopy=NULL, *p, *q, *arg, *prevarg;
546 char separator = ' ';
548 *inname = *outname = *listname = '\0';
551 * First, process the NASM environment variable.
553 envreal = getenv("NASM");
554 arg = NULL;
555 if (envreal) {
556 envcopy = nasm_strdup(envreal);
557 p = envcopy;
558 if (*p && *p != '-')
559 separator = *p++;
560 while (*p) {
561 q = p;
562 while (*p && *p != separator) p++;
563 while (*p == separator) *p++ = '\0';
564 prevarg = arg;
565 arg = q;
566 if (process_arg (prevarg, arg))
567 arg = NULL;
569 if (arg)
570 process_arg (arg, NULL);
571 nasm_free (envcopy);
575 * Now process the actual command line.
577 while (--argc)
579 int i;
580 argv++;
581 if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
582 if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i)))
583 if ((rfile = fopen(p, "r"))) {
584 process_respfile (rfile);
585 fclose(rfile);
586 } else
587 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
588 "unable to open response file `%s'", p);
589 } else
590 i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
591 argv += i, argc -= i;
594 if (!*inname)
595 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
596 "no input file specified");
599 static void assemble_file (char *fname)
601 char * value, * p, * q, * special, * line, debugid[80];
602 insn output_ins;
603 int i, rn_error, validid;
604 long seg, offs;
605 struct tokenval tokval;
606 expr * e;
609 * pass one
611 pass = 1;
612 in_abs_seg = FALSE;
613 location.segment = ofmt->section(NULL, pass, &sb);
614 preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
615 globallineno = 0;
616 location.known = TRUE;
617 location.offset = offs = get_curr_ofs;
619 while ( (line = preproc->getline()) )
621 globallineno++;
623 /* here we parse our directives; this is not handled by the 'real'
624 * parser. */
625 if ( (i = getkw (line, &value)) )
627 switch (i) {
628 case 1: /* [SEGMENT n] */
629 seg = ofmt->section (value, pass, &sb);
630 if (seg == NO_SEG) {
631 report_error (ERR_NONFATAL,
632 "segment name `%s' not recognised",
633 value);
634 } else {
635 in_abs_seg = FALSE;
636 location.segment = seg;
638 break;
639 case 2: /* [EXTERN label:special] */
640 if (*value == '$')
641 value++; /* skip initial $ if present */
642 q = value;
643 validid = TRUE;
644 if (!isidstart(*q))
645 validid = FALSE;
646 while (*q && *q != ':') {
647 if (!isidchar(*q))
648 validid = FALSE;
649 q++;
651 if (!validid) {
652 report_error (ERR_NONFATAL,
653 "identifier expected after EXTERN");
654 break;
656 if (*q == ':') {
657 *q++ = '\0';
658 special = q;
659 } else
660 special = NULL;
661 if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
662 declare_as_global (value, special, report_error);
663 define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
664 ofmt, report_error);
666 break;
667 case 3: /* [BITS bits] */
668 switch (atoi(value)) {
669 case 16:
670 case 32:
671 sb = atoi(value);
672 break;
673 default:
674 report_error(ERR_NONFATAL,
675 "`%s' is not a valid argument to [BITS]",
676 value);
677 break;
679 break;
680 case 4: /* [GLOBAL symbol:special] */
681 if (*value == '$')
682 value++; /* skip initial $ if present */
683 q = value;
684 validid = TRUE;
685 if (!isidstart(*q))
686 validid = FALSE;
687 while (*q && *q != ':') {
688 if (!isidchar(*q))
689 validid = FALSE;
690 q++;
692 if (!validid) {
693 report_error (ERR_NONFATAL,
694 "identifier expected after GLOBAL");
695 break;
697 if (*q == ':') {
698 *q++ = '\0';
699 special = q;
700 } else
701 special = NULL;
702 declare_as_global (value, special, report_error);
703 break;
704 case 5: /* [COMMON symbol size:special] */
705 p = value;
706 validid = TRUE;
707 if (!isidstart(*p))
708 validid = FALSE;
709 while (*p && !isspace(*p)) {
710 if (!isidchar(*p))
711 validid = FALSE;
712 p++;
714 if (!validid) {
715 report_error (ERR_NONFATAL,
716 "identifier expected after COMMON");
717 break;
719 if (*p) {
720 long size;
722 while (*p && isspace(*p))
723 *p++ = '\0';
724 q = p;
725 while (*q && *q != ':')
726 q++;
727 if (*q == ':') {
728 *q++ = '\0';
729 special = q;
730 } else
731 special = NULL;
732 size = readnum (p, &rn_error);
733 if (rn_error)
734 report_error (ERR_NONFATAL, "invalid size specified"
735 " in COMMON declaration");
736 else
737 define_common (value, seg_alloc(), size,
738 special, ofmt, report_error);
739 } else
740 report_error (ERR_NONFATAL, "no size specified in"
741 " COMMON declaration");
742 break;
743 case 6: /* [ABSOLUTE address] */
744 stdscan_reset();
745 stdscan_bufptr = value;
746 tokval.t_type = TOKEN_INVALID;
747 e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
748 NULL);
749 if (e) {
750 if (!is_reloc(e))
751 report_error (ERR_NONFATAL, "cannot use non-"
752 "relocatable expression as ABSOLUTE"
753 " address");
754 else {
755 abs_seg = reloc_seg(e);
756 abs_offset = reloc_value(e);
758 } else
759 abs_offset = 0x100;/* don't go near zero in case of / */
760 in_abs_seg = TRUE;
761 location.segment = abs_seg;
762 break;
763 case 7:
764 p = value;
765 validid = TRUE;
766 if (!isidstart(*p))
767 validid = FALSE;
768 while (*p && !isspace(*p)) {
769 if (!isidchar(*p))
770 validid = FALSE;
771 p++;
773 if (!validid) {
774 report_error (ERR_NONFATAL,
775 "identifier expected after DEBUG");
776 break;
778 while (*p && isspace(*p)) p++;
779 break;
780 default:
781 if (!ofmt->directive (line+1, value, 1))
782 report_error (ERR_NONFATAL, "unrecognised directive [%s]",
783 line+1);
784 break;
787 else /* it isn't a directive */
789 parse_line (1, line, &output_ins,
790 report_error, evaluate, define_label);
792 if (output_ins.forw_ref)
794 for(i = 0; i < output_ins.operands; i++)
796 if (output_ins.oprs[i].opflags & OPFLAG_FORWARD)
798 struct forwrefinfo *fwinf =
799 (struct forwrefinfo *)saa_wstruct(forwrefs);
800 fwinf->lineno = globallineno;
801 fwinf->operand = i;
806 if (output_ins.opcode == I_EQU)
809 * Special `..' EQUs get processed in pass two,
810 * except `..@' macro-processor EQUs which are done
811 * in the normal place.
813 if (!output_ins.label)
814 report_error (ERR_NONFATAL,
815 "EQU not preceded by label");
817 else if (output_ins.label[0] != '.' ||
818 output_ins.label[1] != '.' ||
819 output_ins.label[2] == '@')
821 if (output_ins.operands == 1 &&
822 (output_ins.oprs[0].type & IMMEDIATE) &&
823 output_ins.oprs[0].wrt == NO_SEG)
825 int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN;
826 define_label (output_ins.label,
827 output_ins.oprs[0].segment,
828 output_ins.oprs[0].offset,
829 NULL, FALSE, isext, ofmt, report_error);
831 else if (output_ins.operands == 2 &&
832 (output_ins.oprs[0].type & IMMEDIATE) &&
833 (output_ins.oprs[0].type & COLON) &&
834 output_ins.oprs[0].segment == NO_SEG &&
835 output_ins.oprs[0].wrt == NO_SEG &&
836 (output_ins.oprs[1].type & IMMEDIATE) &&
837 output_ins.oprs[1].segment == NO_SEG &&
838 output_ins.oprs[1].wrt == NO_SEG)
840 define_label (output_ins.label,
841 output_ins.oprs[0].offset | SEG_ABS,
842 output_ins.oprs[1].offset,
843 NULL, FALSE, FALSE, ofmt, report_error);
845 else
846 report_error(ERR_NONFATAL, "bad syntax for EQU");
849 else /* instruction isn't an EQU */
851 long l = insn_size (location.segment, offs, sb,
852 &output_ins, report_error);
853 if (using_debug_info && output_ins.opcode != -1) {
854 /* this is done here so we can do debug type info */
855 long typeinfo = TYS_ELEMENTS(output_ins.operands);
856 switch (output_ins.opcode) {
857 case I_RESB:
858 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
859 break;
860 case I_RESW:
861 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
862 break;
863 case I_RESD:
864 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
865 break;
866 case I_RESQ:
867 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
868 break;
869 case I_REST:
870 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
871 break;
872 case I_DB:
873 typeinfo |= TY_BYTE;
874 break;
875 case I_DW:
876 typeinfo |= TY_WORD;
877 break;
878 case I_DD:
879 if (output_ins.eops_float)
880 typeinfo |= TY_FLOAT;
881 else
882 typeinfo |= TY_DWORD;
883 break;
884 case I_DQ:
885 typeinfo |= TY_QWORD;
886 break;
887 case I_DT:
888 typeinfo |= TY_TBYTE;
889 break;
890 default:
891 typeinfo = TY_LABEL;
893 ofmt->current_dfmt->debug_typevalue(typeinfo);
895 if (l != -1) {
896 offs += l;
897 set_curr_ofs (offs);
900 * else l == -1 => invalid instruction, which will be
901 * flagged as an error on pass 2
904 cleanup_insn (&output_ins);
906 nasm_free (line);
907 location.offset = offs = get_curr_ofs;
910 preproc->cleanup();
912 if (terminate_after_phase) {
913 fclose(ofile);
914 remove(outname);
915 if (want_usage)
916 usage();
917 exit (1);
921 * pass two
924 pass = 2;
925 saa_rewind (forwrefs);
926 if (*listname)
927 nasmlist.init(listname, report_error);
928 forwref = saa_rstruct (forwrefs);
929 in_abs_seg = FALSE;
930 location.segment = ofmt->section(NULL, pass, &sb);
931 raa_free (offsets);
932 offsets = raa_init();
933 preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
934 globallineno = 0;
935 location.offset = offs = get_curr_ofs;
937 while ( (line = preproc->getline()) )
939 globallineno++;
941 /* here we parse our directives; this is not handled by
942 * the 'real' parser. */
943 if ( (i = getkw (line, &value)) ) {
944 switch (i) {
945 case 1: /* [SEGMENT n] */
946 seg = ofmt->section (value, pass, &sb);
947 if (seg == NO_SEG) {
948 report_error (ERR_PANIC,
949 "invalid segment name on pass two");
950 } else
951 in_abs_seg = FALSE;
952 location.segment = seg;
953 break;
954 case 2: /* [EXTERN label] */
955 q = value;
956 while (*q && *q != ':')
957 q++;
958 if (*q == ':') {
959 *q++ = '\0';
960 ofmt->symdef(value, 0L, 0L, 3, q);
962 break;
963 case 3: /* [BITS bits] */
964 switch (atoi(value)) {
965 case 16:
966 case 32:
967 sb = atoi(value);
968 break;
969 default:
970 report_error(ERR_PANIC,
971 "invalid [BITS] value on pass two",
972 value);
973 break;
975 break;
976 case 4: /* [GLOBAL symbol] */
977 q = value;
978 while (*q && *q != ':')
979 q++;
980 if (*q == ':') {
981 *q++ = '\0';
982 ofmt->symdef(value, 0L, 0L, 3, q);
984 break;
985 case 5: /* [COMMON symbol size] */
986 q = value;
987 while (*q && *q != ':') {
988 if (isspace(*q))
989 *q = '\0';
990 q++;
992 if (*q == ':') {
993 *q++ = '\0';
994 ofmt->symdef(value, 0L, 0L, 3, q);
996 break;
997 case 6: /* [ABSOLUTE addr] */
998 stdscan_reset();
999 stdscan_bufptr = value;
1000 tokval.t_type = TOKEN_INVALID;
1001 e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
1002 NULL);
1003 if (e) {
1004 if (!is_reloc(e))
1005 report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
1006 " in pass two");
1007 else {
1008 abs_seg = reloc_seg(e);
1009 abs_offset = reloc_value(e);
1011 } else
1012 report_error (ERR_PANIC, "invalid ABSOLUTE address "
1013 "in pass two");
1014 in_abs_seg = TRUE;
1015 location.segment = abs_seg;
1016 break;
1017 case 7:
1018 p = value;
1019 q = debugid;
1020 validid = TRUE;
1021 if (!isidstart(*p))
1022 validid = FALSE;
1023 while (*p && !isspace(*p)) {
1024 if (!isidchar(*p))
1025 validid = FALSE;
1026 *q++ = *p++;
1028 *q++ = 0;
1029 if (!validid) {
1030 report_error (ERR_PANIC,
1031 "identifier expected after DEBUG in pass 2");
1032 break;
1034 while (*p && isspace(*p))
1035 p++;
1036 ofmt->current_dfmt->debug_directive (debugid, p);
1037 break;
1038 default:
1039 if (!ofmt->directive (line+1, value, 2))
1040 report_error (ERR_PANIC, "invalid directive on pass two");
1041 break;
1044 else /* not a directive */
1046 parse_line (2, line, &output_ins,
1047 report_error, evaluate, redefine_label);
1048 if (forwref != NULL && globallineno == forwref->lineno) {
1049 output_ins.forw_ref = TRUE;
1050 do {
1051 output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD;
1052 forwref = saa_rstruct (forwrefs);
1053 } while (forwref != NULL && forwref->lineno == globallineno);
1054 } else
1055 output_ins.forw_ref = FALSE;
1058 * Hack to prevent phase error in the code
1059 * rol ax,x
1060 * x equ 1
1062 * If the second operand is a forward reference,
1063 * the UNITY property of the number 1 in that
1064 * operand is cancelled. Otherwise the above
1065 * sequence will cause a phase error.
1067 * This hack means that the above code will
1068 * generate 286+ code.
1070 * The forward reference will mean that the
1071 * operand will not have the UNITY property on
1072 * the first pass, so the pass behaviours will
1073 * be consistent.
1076 if (output_ins.forw_ref &&
1077 output_ins.operands >= 2 &&
1078 (output_ins.oprs[1].opflags & OPFLAG_FORWARD))
1080 output_ins.oprs[1].type &= ~ONENESS;
1083 if (output_ins.opcode == I_EQU)
1086 * Special `..' EQUs get processed here, except
1087 * `..@' macro processor EQUs which are done above.
1089 if (output_ins.label[0] == '.' &&
1090 output_ins.label[1] == '.' &&
1091 output_ins.label[2] != '@')
1093 if (output_ins.operands == 1 &&
1094 (output_ins.oprs[0].type & IMMEDIATE)) {
1095 define_label (output_ins.label,
1096 output_ins.oprs[0].segment,
1097 output_ins.oprs[0].offset,
1098 NULL, FALSE, FALSE, ofmt, report_error);
1100 else if (output_ins.operands == 2 &&
1101 (output_ins.oprs[0].type & IMMEDIATE) &&
1102 (output_ins.oprs[0].type & COLON) &&
1103 output_ins.oprs[0].segment == NO_SEG &&
1104 (output_ins.oprs[1].type & IMMEDIATE) &&
1105 output_ins.oprs[1].segment == NO_SEG)
1107 define_label (output_ins.label,
1108 output_ins.oprs[0].offset | SEG_ABS,
1109 output_ins.oprs[1].offset,
1110 NULL, FALSE, FALSE, ofmt, report_error);
1112 else
1113 report_error(ERR_NONFATAL, "bad syntax for EQU");
1116 offs += assemble (location.segment, offs, sb,
1117 &output_ins, ofmt, report_error, &nasmlist);
1118 cleanup_insn (&output_ins);
1119 set_curr_ofs (offs);
1122 nasm_free (line);
1124 location.offset = offs = get_curr_ofs;
1127 preproc->cleanup();
1128 nasmlist.cleanup();
1131 static int getkw (char *buf, char **value)
1133 char *p, *q;
1135 if (*buf!='[')
1136 return 0;
1138 p = buf;
1140 while (*p && *p != ']') p++;
1142 if (!*p)
1143 return 0;
1145 q = p++;
1147 while (*p && *p != ';') {
1148 if (!isspace(*p))
1149 return 0;
1150 p++;
1152 q[1] = '\0';
1154 p = buf+1;
1155 while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
1156 buf++;
1157 if (*buf==']') {
1158 *buf = '\0';
1159 *value = buf;
1160 } else {
1161 *buf++ = '\0';
1162 while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
1163 *value = buf;
1164 while (*buf!=']') buf++;
1165 *buf++ = '\0';
1167 for (q=p; *q; q++)
1168 *q = tolower(*q);
1169 if (!strcmp(p, "segment") || !strcmp(p, "section"))
1170 return 1;
1171 if (!strcmp(p, "extern"))
1172 return 2;
1173 if (!strcmp(p, "bits"))
1174 return 3;
1175 if (!strcmp(p, "global"))
1176 return 4;
1177 if (!strcmp(p, "common"))
1178 return 5;
1179 if (!strcmp(p, "absolute"))
1180 return 6;
1181 if (!strcmp(p, "debug"))
1182 return 7;
1183 return -1;
1186 static void report_error (int severity, char *fmt, ...)
1188 va_list ap;
1191 * See if it's a suppressed warning.
1193 if ((severity & ERR_MASK) == ERR_WARNING &&
1194 (severity & ERR_WARN_MASK) != 0 &&
1195 suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
1196 return; /* and bail out if so */
1199 * See if it's a pass-one only warning and we're not in pass one.
1201 if ((severity & ERR_PASS1) && pass != 1)
1202 return;
1204 if (severity & ERR_NOFILE)
1205 fputs ("nasm: ", error_file);
1206 else {
1207 char * currentfile = NULL;
1208 long lineno = 0;
1209 src_get (&lineno, &currentfile);
1210 fprintf (error_file, "%s:%ld: ", currentfile, lineno);
1211 nasm_free (currentfile);
1214 if ( (severity & ERR_MASK) == ERR_WARNING)
1215 fputs ("warning: ", error_file);
1216 else if ( (severity & ERR_MASK) == ERR_PANIC)
1217 fputs ("panic: ", error_file);
1219 va_start (ap, fmt);
1220 vfprintf (error_file, fmt, ap);
1221 fputc ('\n', error_file);
1223 if (severity & ERR_USAGE)
1224 want_usage = TRUE;
1226 switch (severity & ERR_MASK) {
1227 case ERR_WARNING:
1228 /* no further action, by definition */
1229 break;
1230 case ERR_NONFATAL:
1231 terminate_after_phase = TRUE;
1232 break;
1233 case ERR_FATAL:
1234 if (ofile) {
1235 fclose(ofile);
1236 remove(outname);
1238 if (want_usage)
1239 usage();
1240 exit(1); /* instantly die */
1241 break; /* placate silly compilers */
1242 case ERR_PANIC:
1243 fflush(NULL);
1244 abort(); /* halt, catch fire, and dump core */
1245 break;
1249 static void usage(void)
1251 fputs("type `nasm -h' for help\n", error_file);
1254 static void register_output_formats(void)
1256 ofmt = ofmt_register (report_error);
1259 #define BUF_DELTA 512
1261 static FILE *no_pp_fp;
1262 static efunc no_pp_err;
1263 static ListGen *no_pp_list;
1264 static long no_pp_lineinc;
1266 static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
1267 ListGen *listgen)
1269 src_set_fname(nasm_strdup(file));
1270 src_set_linnum(0);
1271 no_pp_lineinc = 1;
1272 no_pp_err = error;
1273 no_pp_fp = fopen(file, "r");
1274 if (!no_pp_fp)
1275 no_pp_err (ERR_FATAL | ERR_NOFILE,
1276 "unable to open input file `%s'", file);
1277 no_pp_list = listgen;
1278 (void) pass; /* placate compilers */
1279 (void) eval; /* placate compilers */
1282 static char *no_pp_getline (void)
1284 char *buffer, *p, *q;
1285 int bufsize;
1287 bufsize = BUF_DELTA;
1288 buffer = nasm_malloc(BUF_DELTA);
1289 src_set_linnum(src_get_linnum() + no_pp_lineinc);
1291 while (1) { /* Loop to handle %line */
1293 p = buffer;
1294 while (1) { /* Loop to handle long lines */
1295 q = fgets(p, bufsize-(p-buffer), no_pp_fp);
1296 if (!q)
1297 break;
1298 p += strlen(p);
1299 if (p > buffer && p[-1] == '\n')
1300 break;
1301 if (p-buffer > bufsize-10) {
1302 int offset;
1303 offset = p - buffer;
1304 bufsize += BUF_DELTA;
1305 buffer = nasm_realloc(buffer, bufsize);
1306 p = buffer + offset;
1310 if (!q && p == buffer) {
1311 nasm_free (buffer);
1312 return NULL;
1316 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1317 * them are present at the end of the line.
1319 buffer[strcspn(buffer, "\r\n\032")] = '\0';
1321 if (!strncmp(buffer, "%line", 5)) {
1322 long ln;
1323 int li;
1324 char *nm = nasm_malloc(strlen(buffer));
1325 if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) {
1326 nasm_free( src_set_fname(nm) );
1327 src_set_linnum(ln);
1328 no_pp_lineinc = li;
1329 continue;
1331 nasm_free(nm);
1333 break;
1336 no_pp_list->line (LIST_READ, buffer);
1338 return buffer;
1341 static void no_pp_cleanup (void)
1343 fclose(no_pp_fp);