NASM 0.98-j4
[nasm/avx512.git] / nasm.c
blob1404db15a23382b21cdfd4bbf8413aadf3f77923
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 *ofile = NULL;
47 static int sb = 16; /* by default */
49 static loc_t location;
50 int in_abs_seg; /* Flag we are in ABSOLUTE seg */
51 static long abs_seg;
53 static struct RAA *offsets;
54 static long abs_offset;
56 static struct SAA *forwrefs; /* keep track of forward references */
57 static struct forwrefinfo *forwref;
59 static Preproc *preproc;
60 static int preprocess_only;
62 /* used by error function to report location */
65 * Which of the suppressible warnings are suppressed. Entry zero
66 * doesn't do anything. Initial defaults are given here.
68 static char suppressed[1+ERR_WARN_MAX] = {
69 0, TRUE, TRUE, FALSE
73 * The option names for the suppressible warnings. As before, entry
74 * zero does nothing.
76 static char *suppressed_names[1+ERR_WARN_MAX] = {
77 NULL, "macro-params", "orphan-labels", "number-overflow"
81 * The explanations for the suppressible warnings. As before, entry
82 * zero does nothing.
84 static char *suppressed_what[1+ERR_WARN_MAX] = {
85 NULL, "macro calls with wrong no. of params",
86 "labels alone on lines without trailing `:'",
87 "numeric constants greater than 0xFFFFFFFF"
91 * This is a null preprocessor which just copies lines from input
92 * to output. It's used when someone explicitly requests that NASM
93 * not preprocess their source file.
96 static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
97 static char *no_pp_getline (void);
98 static void no_pp_cleanup (void);
99 static Preproc no_pp = {
100 no_pp_reset,
101 no_pp_getline,
102 no_pp_cleanup
106 * get/set current offset...
108 #define get_curr_ofs (in_abs_seg?abs_offset:\
109 raa_read(offsets,location.segment))
110 #define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\
111 (void)(offsets=raa_write(offsets,location.segment,(x))))
113 static int want_usage;
114 static int terminate_after_phase;
116 static void nasm_fputs(char *line, FILE *ofile)
118 if (ofile) {
119 fputs(line, ofile);
120 fputc('\n', ofile);
121 } else
122 puts(line);
125 int main(int argc, char **argv)
127 want_usage = terminate_after_phase = FALSE;
129 nasm_set_malloc_error (report_error);
130 offsets = raa_init();
131 forwrefs = saa_init ((long)sizeof(struct forwrefinfo));
133 preproc = &nasmpp;
134 preprocess_only = FALSE;
136 seg_init();
138 register_output_formats();
140 parse_cmdline(argc, argv);
142 if (terminate_after_phase)
144 if (want_usage)
145 usage();
146 return 1;
149 if (ofmt->stdmac)
150 pp_extra_stdmac (ofmt->stdmac);
151 parser_global_info (ofmt, &location);
152 eval_global_info (ofmt, lookup_label, &location);
154 if (preprocess_only)
156 char *line;
157 char *file_name = NULL;
158 long prior_linnum=0;
159 int lineinc=0;
161 if (*outname) {
162 ofile = fopen(outname, "w");
163 if (!ofile)
164 report_error (ERR_FATAL | ERR_NOFILE,
165 "unable to open output file `%s'", outname);
166 } else
167 ofile = NULL;
169 location.known = FALSE;
171 preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
172 while ( (line = preproc->getline()) ) {
174 * We generate %line directives if needed for later programs
176 long linnum = prior_linnum += lineinc;
177 int altline = src_get(&linnum, &file_name);
178 if (altline) {
179 if (altline==1 && lineinc==1)
180 nasm_fputs("", ofile);
181 else {
182 lineinc = (altline != -1 || lineinc!=1);
183 fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n",
184 linnum, lineinc, file_name);
186 prior_linnum = linnum;
188 nasm_fputs(line, ofile);
189 nasm_free (line);
191 nasm_free(file_name);
192 preproc->cleanup();
193 if (ofile)
194 fclose(ofile);
195 if (ofile && terminate_after_phase)
196 remove(outname);
198 else /* NOT preprocess only */
201 * We must call ofmt->filename _anyway_, even if the user
202 * has specified their own output file, because some
203 * formats (eg OBJ and COFF) use ofmt->filename to find out
204 * the name of the input file and then put that inside the
205 * file.
207 ofmt->filename (inname, outname, report_error);
209 ofile = fopen(outname, "wb");
210 if (!ofile) {
211 report_error (ERR_FATAL | ERR_NOFILE,
212 "unable to open output file `%s'", outname);
216 * We must call init_labels() before ofmt->init() since
217 * some object formats will want to define labels in their
218 * init routines. (eg OS/2 defines the FLAT group)
220 init_labels ();
222 ofmt->init (ofile, report_error, define_label, evaluate);
224 assemble_file (inname);
226 if (!terminate_after_phase) {
227 ofmt->cleanup (using_debug_info);
228 cleanup_labels ();
230 else {
233 * We had an fclose on the output file here, but we
234 * actually do that in all the object file drivers as well,
235 * so we're leaving out the one here.
236 * fclose (ofile);
239 remove(outname);
240 if (listname[0])
241 remove(listname);
245 if (want_usage)
246 usage();
248 raa_free (offsets);
249 saa_free (forwrefs);
250 eval_cleanup ();
251 nasmlib_cleanup ();
253 if (terminate_after_phase)
254 return 1;
255 else
256 return 0;
261 * Get a parameter for a command line option.
262 * First arg must be in the form of e.g. -f...
264 static char *get_param (char *p, char *q, int *advance)
266 *advance = 0;
267 if (p[2]) /* the parameter's in the option */
269 p += 2;
270 while (isspace(*p))
271 p++;
272 return p;
274 if (q && q[0])
276 *advance = 1;
277 return q;
279 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
280 "option `-%c' requires an argument",
281 p[1]);
282 return NULL;
285 int stopoptions = 0;
286 static int process_arg (char *p, char *q)
288 char *param;
289 int i, advance = 0;
291 if (!p || !p[0])
292 return 0;
294 if (p[0]=='-' && ! stopoptions)
296 switch (p[1]) {
297 case '-': /* -- => stop processing options */
298 stopoptions = 1;
299 break;
300 case 's': /* silently ignored for compatibility */
301 break;
302 case 'o': /* these parameters take values */
303 case 'f':
304 case 'p':
305 case 'd':
306 case 'i':
307 case 'l':
308 case 'F':
309 if ( !(param = get_param (p, q, &advance)) )
310 break;
311 if (p[1]=='o') { /* output file */
312 strcpy (outname, param);
313 } else if (p[1]=='f') { /* output format */
314 ofmt = ofmt_find(param);
315 if (!ofmt) {
316 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
317 "unrecognised output format `%s' - "
318 "use -hf for a list",
319 param);
321 else
322 ofmt->current_dfmt = ofmt->debug_formats[0];
323 } else if (p[1]=='p') { /* pre-include */
324 pp_pre_include (param);
325 } else if (p[1]=='d') { /* pre-define */
326 pp_pre_define (param);
327 } else if (p[1]=='i') { /* include search path */
328 pp_include_path (param);
329 } else if (p[1]=='l') { /* listing file */
330 strcpy (listname, param);
331 } else if (p[1] == 'F') { /* specify debug format */
332 ofmt->current_dfmt = dfmt_find(ofmt, param);
333 if (!ofmt->current_dfmt) {
334 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
335 "unrecognized debug format `%s' for"
336 " output format `%s'",
337 param, ofmt->shortname);
340 break;
341 case 'g':
342 using_debug_info = TRUE;
343 break;
344 case 'h':
345 printf("usage: nasm [-@ response file] [-o outfile] [-f format] "
346 "[-l listfile]\n"
347 " [options...] [--] filename\n");
348 printf(" or nasm -r for version info\n\n");
349 printf(" -e preprocess only (writes output to "
350 "stdout by default)\n"
351 " -a don't preprocess\n\n");
352 printf(" -g enable debug info\n"
353 " -F format select a debugging format\n\n");
354 printf(" -i<path> adds a pathname to the include file path\n"
355 " -p<file> pre-includes a file\n"
356 " -d<macro>[=<value>] pre-defines a macro\n");
357 printf(" -w+foo enables warnings about foo; "
358 "-w-foo disables them\n where foo can be:\n");
359 for (i=1; i<=ERR_WARN_MAX; i++)
360 printf(" %-16s%s (default %s)\n",
361 suppressed_names[i], suppressed_what[i],
362 suppressed[i] ? "off" : "on");
363 printf ("\nresponse files should contain command line parameters"
364 ", one per line.\n");
365 if (p[2] == 'f') {
366 printf("\nvalid output formats for -f are"
367 " (`*' denotes default):\n");
368 ofmt_list(ofmt, stdout);
370 else {
371 printf ("\nFor a list of valid output formats, use -hf.\n");
372 printf ("For a list of debug formats, use -f <form> -y.\n");
374 exit (0); /* never need usage message here */
375 break;
376 case 'y':
377 printf("\nvalid debug formats for '%s' output format are"
378 " ('*' denotes default):\n",
379 ofmt->shortname);
380 dfmt_list(ofmt, stdout);
381 exit(0);
382 break;
383 case 'r':
384 printf("NASM version %s\n", NASM_VER);
385 #ifdef DEBUG
386 printf("Compiled with -DDEBUG on " __DATE__ "\n");
387 #endif
388 exit (0); /* never need usage message here */
389 break;
390 case 'e': /* preprocess only */
391 preprocess_only = TRUE;
392 break;
393 case 'a': /* assemble only - don't preprocess */
394 preproc = &no_pp;
395 break;
396 case 'w':
397 if (p[2] != '+' && p[2] != '-') {
398 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
399 "invalid option to `-w'");
400 } else {
401 for (i=1; i<=ERR_WARN_MAX; i++)
402 if (!nasm_stricmp(p+3, suppressed_names[i]))
403 break;
404 if (i <= ERR_WARN_MAX)
405 suppressed[i] = (p[2] == '-');
406 else
407 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
408 "invalid option to `-w'");
410 break;
411 default:
412 if (!ofmt->setinfo(GI_SWITCH,&p))
413 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
414 "unrecognised option `-%c'",
415 p[1]);
416 break;
419 else
421 if (*inname) {
422 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
423 "more than one input file specified");
424 } else
425 strcpy(inname, p);
428 return advance;
431 #define ARG_BUF_DELTA 128
433 static void process_respfile (FILE *rfile)
435 char *buffer, *p, *q, *prevarg;
436 int bufsize, prevargsize;
438 bufsize = prevargsize = ARG_BUF_DELTA;
439 buffer = nasm_malloc(ARG_BUF_DELTA);
440 prevarg = nasm_malloc(ARG_BUF_DELTA);
441 prevarg[0] = '\0';
443 while (1) { /* Loop to handle all lines in file */
445 p = buffer;
446 while (1) { /* Loop to handle long lines */
447 q = fgets(p, bufsize-(p-buffer), rfile);
448 if (!q)
449 break;
450 p += strlen(p);
451 if (p > buffer && p[-1] == '\n')
452 break;
453 if (p-buffer > bufsize-10) {
454 int offset;
455 offset = p - buffer;
456 bufsize += ARG_BUF_DELTA;
457 buffer = nasm_realloc(buffer, bufsize);
458 p = buffer + offset;
462 if (!q && p == buffer) {
463 if (prevarg[0])
464 process_arg (prevarg, NULL);
465 nasm_free (buffer);
466 nasm_free (prevarg);
467 return;
471 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
472 * them are present at the end of the line.
474 *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
476 while (p > buffer && isspace(p[-1]))
477 *--p = '\0';
479 p = buffer;
480 while (isspace(*p))
481 p++;
483 if (process_arg (prevarg, p))
484 *p = '\0';
486 if (strlen(p) > prevargsize-10) {
487 prevargsize += ARG_BUF_DELTA;
488 prevarg = nasm_realloc(prevarg, prevargsize);
490 strcpy (prevarg, p);
494 static void parse_cmdline(int argc, char **argv)
496 FILE *rfile;
497 char *envreal, *envcopy=NULL, *p, *q, *arg, *prevarg;
498 char separator = ' ';
500 *inname = *outname = *listname = '\0';
503 * First, process the NASM environment variable.
505 envreal = getenv("NASM");
506 arg = NULL;
507 if (envreal) {
508 envcopy = nasm_strdup(envreal);
509 p = envcopy;
510 if (*p && *p != '-')
511 separator = *p++;
512 while (*p) {
513 q = p;
514 while (*p && *p != separator) p++;
515 while (*p == separator) *p++ = '\0';
516 prevarg = arg;
517 arg = q;
518 if (process_arg (prevarg, arg))
519 arg = NULL;
521 if (arg)
522 process_arg (arg, NULL);
523 nasm_free (envcopy);
527 * Now process the actual command line.
529 while (--argc)
531 int i;
532 argv++;
533 if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
534 if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i)))
535 if ((rfile = fopen(p, "r"))) {
536 process_respfile (rfile);
537 fclose(rfile);
538 } else
539 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
540 "unable to open response file `%s'", p);
541 } else
542 i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
543 argv += i, argc -= i;
546 if (!*inname)
547 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
548 "no input file specified");
551 static void assemble_file (char *fname)
553 char * value, * p, * q, * special, * line, debugid[80];
554 insn output_ins;
555 int i, rn_error, validid;
556 long seg, offs;
557 struct tokenval tokval;
558 expr * e;
561 * pass one
563 pass = 1;
564 in_abs_seg = FALSE;
565 location.segment = ofmt->section(NULL, pass, &sb);
566 preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
567 globallineno = 0;
568 location.known = TRUE;
569 location.offset = offs = get_curr_ofs;
571 while ( (line = preproc->getline()) )
573 globallineno++;
575 /* here we parse our directives; this is not handled by the 'real'
576 * parser. */
577 if ( (i = getkw (line, &value)) )
579 switch (i) {
580 case 1: /* [SEGMENT n] */
581 seg = ofmt->section (value, pass, &sb);
582 if (seg == NO_SEG) {
583 report_error (ERR_NONFATAL,
584 "segment name `%s' not recognised",
585 value);
586 } else {
587 in_abs_seg = FALSE;
588 location.segment = seg;
590 break;
591 case 2: /* [EXTERN label:special] */
592 if (*value == '$')
593 value++; /* skip initial $ if present */
594 q = value;
595 validid = TRUE;
596 if (!isidstart(*q))
597 validid = FALSE;
598 while (*q && *q != ':') {
599 if (!isidchar(*q))
600 validid = FALSE;
601 q++;
603 if (!validid) {
604 report_error (ERR_NONFATAL,
605 "identifier expected after EXTERN");
606 break;
608 if (*q == ':') {
609 *q++ = '\0';
610 special = q;
611 } else
612 special = NULL;
613 if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
614 declare_as_global (value, special, report_error);
615 define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
616 ofmt, report_error);
618 break;
619 case 3: /* [BITS bits] */
620 switch (atoi(value)) {
621 case 16:
622 case 32:
623 sb = atoi(value);
624 break;
625 default:
626 report_error(ERR_NONFATAL,
627 "`%s' is not a valid argument to [BITS]",
628 value);
629 break;
631 break;
632 case 4: /* [GLOBAL symbol:special] */
633 if (*value == '$')
634 value++; /* skip initial $ if present */
635 q = value;
636 validid = TRUE;
637 if (!isidstart(*q))
638 validid = FALSE;
639 while (*q && *q != ':') {
640 if (!isidchar(*q))
641 validid = FALSE;
642 q++;
644 if (!validid) {
645 report_error (ERR_NONFATAL,
646 "identifier expected after GLOBAL");
647 break;
649 if (*q == ':') {
650 *q++ = '\0';
651 special = q;
652 } else
653 special = NULL;
654 declare_as_global (value, special, report_error);
655 break;
656 case 5: /* [COMMON symbol size:special] */
657 p = value;
658 validid = TRUE;
659 if (!isidstart(*p))
660 validid = FALSE;
661 while (*p && !isspace(*p)) {
662 if (!isidchar(*p))
663 validid = FALSE;
664 p++;
666 if (!validid) {
667 report_error (ERR_NONFATAL,
668 "identifier expected after COMMON");
669 break;
671 if (*p) {
672 long size;
674 while (*p && isspace(*p))
675 *p++ = '\0';
676 q = p;
677 while (*q && *q != ':')
678 q++;
679 if (*q == ':') {
680 *q++ = '\0';
681 special = q;
682 } else
683 special = NULL;
684 size = readnum (p, &rn_error);
685 if (rn_error)
686 report_error (ERR_NONFATAL, "invalid size specified"
687 " in COMMON declaration");
688 else
689 define_common (value, seg_alloc(), size,
690 special, ofmt, report_error);
691 } else
692 report_error (ERR_NONFATAL, "no size specified in"
693 " COMMON declaration");
694 break;
695 case 6: /* [ABSOLUTE address] */
696 stdscan_reset();
697 stdscan_bufptr = value;
698 tokval.t_type = TOKEN_INVALID;
699 e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
700 NULL);
701 if (e) {
702 if (!is_reloc(e))
703 report_error (ERR_NONFATAL, "cannot use non-"
704 "relocatable expression as ABSOLUTE"
705 " address");
706 else {
707 abs_seg = reloc_seg(e);
708 abs_offset = reloc_value(e);
710 } else
711 abs_offset = 0x100;/* don't go near zero in case of / */
712 in_abs_seg = TRUE;
713 location.segment = abs_seg;
714 break;
715 case 7:
716 p = value;
717 validid = TRUE;
718 if (!isidstart(*p))
719 validid = FALSE;
720 while (*p && !isspace(*p)) {
721 if (!isidchar(*p))
722 validid = FALSE;
723 p++;
725 if (!validid) {
726 report_error (ERR_NONFATAL,
727 "identifier expected after DEBUG");
728 break;
730 while (*p && isspace(*p)) p++;
731 break;
732 default:
733 if (!ofmt->directive (line+1, value, 1))
734 report_error (ERR_NONFATAL, "unrecognised directive [%s]",
735 line+1);
736 break;
739 else /* it isn't a directive */
741 parse_line (1, line, &output_ins,
742 report_error, evaluate, define_label);
744 if (output_ins.forw_ref)
746 for(i = 0; i < output_ins.operands; i++)
748 if (output_ins.oprs[i].opflags & OPFLAG_FORWARD)
750 struct forwrefinfo *fwinf =
751 (struct forwrefinfo *)saa_wstruct(forwrefs);
752 fwinf->lineno = globallineno;
753 fwinf->operand = i;
758 if (output_ins.opcode == I_EQU)
761 * Special `..' EQUs get processed in pass two,
762 * except `..@' macro-processor EQUs which are done
763 * in the normal place.
765 if (!output_ins.label)
766 report_error (ERR_NONFATAL,
767 "EQU not preceded by label");
770 * EQU cannot be used to declare a label relative to
771 * an external symbol.
773 else if ((output_ins.oprs[0].opflags & OPFLAG_EXTERN)
774 || (output_ins.operands > 1
775 && (output_ins.oprs[1].opflags & OPFLAG_EXTERN)))
777 report_error (ERR_NONFATAL,
778 "EQU used relative to external symbol");
781 else if (output_ins.label[0] != '.' ||
782 output_ins.label[1] != '.' ||
783 output_ins.label[2] == '@')
785 if (output_ins.operands == 1 &&
786 (output_ins.oprs[0].type & IMMEDIATE) &&
787 output_ins.oprs[0].wrt == NO_SEG)
789 define_label (output_ins.label,
790 output_ins.oprs[0].segment,
791 output_ins.oprs[0].offset,
792 NULL, FALSE, FALSE, ofmt, report_error);
794 else if (output_ins.operands == 2 &&
795 (output_ins.oprs[0].type & IMMEDIATE) &&
796 (output_ins.oprs[0].type & COLON) &&
797 output_ins.oprs[0].segment == NO_SEG &&
798 output_ins.oprs[0].wrt == NO_SEG &&
799 (output_ins.oprs[1].type & IMMEDIATE) &&
800 output_ins.oprs[1].segment == NO_SEG &&
801 output_ins.oprs[1].wrt == NO_SEG)
803 define_label (output_ins.label,
804 output_ins.oprs[0].offset | SEG_ABS,
805 output_ins.oprs[1].offset,
806 NULL, FALSE, FALSE, ofmt, report_error);
808 else
809 report_error(ERR_NONFATAL, "bad syntax for EQU");
812 else /* instruction isn't an EQU */
814 long l = insn_size (location.segment, offs, sb,
815 &output_ins, report_error);
816 if (using_debug_info && output_ins.opcode != -1) {
817 /* this is done here so we can do debug type info */
818 long typeinfo = TYS_ELEMENTS(output_ins.operands);
819 switch (output_ins.opcode) {
820 case I_RESB:
821 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
822 break;
823 case I_RESW:
824 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
825 break;
826 case I_RESD:
827 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
828 break;
829 case I_RESQ:
830 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
831 break;
832 case I_REST:
833 typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
834 break;
835 case I_DB:
836 typeinfo |= TY_BYTE;
837 break;
838 case I_DW:
839 typeinfo |= TY_WORD;
840 break;
841 case I_DD:
842 if (output_ins.eops_float)
843 typeinfo |= TY_FLOAT;
844 else
845 typeinfo |= TY_DWORD;
846 break;
847 case I_DQ:
848 typeinfo |= TY_QWORD;
849 break;
850 case I_DT:
851 typeinfo |= TY_TBYTE;
852 break;
853 default:
854 typeinfo = TY_LABEL;
856 ofmt->current_dfmt->debug_typevalue(typeinfo);
858 if (l != -1) {
859 offs += l;
860 set_curr_ofs (offs);
863 * else l == -1 => invalid instruction, which will be
864 * flagged as an error on pass 2
867 cleanup_insn (&output_ins);
869 nasm_free (line);
870 location.offset = offs = get_curr_ofs;
873 preproc->cleanup();
875 if (terminate_after_phase) {
876 fclose(ofile);
877 remove(outname);
878 if (want_usage)
879 usage();
880 exit (1);
884 * pass two
887 pass = 2;
888 saa_rewind (forwrefs);
889 if (*listname)
890 nasmlist.init(listname, report_error);
891 forwref = saa_rstruct (forwrefs);
892 in_abs_seg = FALSE;
893 location.segment = ofmt->section(NULL, pass, &sb);
894 raa_free (offsets);
895 offsets = raa_init();
896 preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
897 globallineno = 0;
898 location.offset = offs = get_curr_ofs;
900 while ( (line = preproc->getline()) )
902 globallineno++;
904 /* here we parse our directives; this is not handled by
905 * the 'real' parser. */
906 if ( (i = getkw (line, &value)) ) {
907 switch (i) {
908 case 1: /* [SEGMENT n] */
909 seg = ofmt->section (value, pass, &sb);
910 if (seg == NO_SEG) {
911 report_error (ERR_PANIC,
912 "invalid segment name on pass two");
913 } else
914 in_abs_seg = FALSE;
915 location.segment = seg;
916 break;
917 case 2: /* [EXTERN label] */
918 q = value;
919 while (*q && *q != ':')
920 q++;
921 if (*q == ':') {
922 *q++ = '\0';
923 ofmt->symdef(value, 0L, 0L, 3, q);
925 break;
926 case 3: /* [BITS bits] */
927 switch (atoi(value)) {
928 case 16:
929 case 32:
930 sb = atoi(value);
931 break;
932 default:
933 report_error(ERR_PANIC,
934 "invalid [BITS] value on pass two",
935 value);
936 break;
938 break;
939 case 4: /* [GLOBAL symbol] */
940 q = value;
941 while (*q && *q != ':')
942 q++;
943 if (*q == ':') {
944 *q++ = '\0';
945 ofmt->symdef(value, 0L, 0L, 3, q);
947 break;
948 case 5: /* [COMMON symbol size] */
949 q = value;
950 while (*q && *q != ':') {
951 if (isspace(*q))
952 *q = '\0';
953 q++;
955 if (*q == ':') {
956 *q++ = '\0';
957 ofmt->symdef(value, 0L, 0L, 3, q);
959 break;
960 case 6: /* [ABSOLUTE addr] */
961 stdscan_reset();
962 stdscan_bufptr = value;
963 tokval.t_type = TOKEN_INVALID;
964 e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
965 NULL);
966 if (e) {
967 if (!is_reloc(e))
968 report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
969 " in pass two");
970 else {
971 abs_seg = reloc_seg(e);
972 abs_offset = reloc_value(e);
974 } else
975 report_error (ERR_PANIC, "invalid ABSOLUTE address "
976 "in pass two");
977 in_abs_seg = TRUE;
978 location.segment = abs_seg;
979 break;
980 case 7:
981 p = value;
982 q = debugid;
983 validid = TRUE;
984 if (!isidstart(*p))
985 validid = FALSE;
986 while (*p && !isspace(*p)) {
987 if (!isidchar(*p))
988 validid = FALSE;
989 *q++ = *p++;
991 *q++ = 0;
992 if (!validid) {
993 report_error (ERR_PANIC,
994 "identifier expected after DEBUG in pass 2");
995 break;
997 while (*p && isspace(*p))
998 p++;
999 ofmt->current_dfmt->debug_directive (debugid, p);
1000 break;
1001 default:
1002 if (!ofmt->directive (line+1, value, 2))
1003 report_error (ERR_PANIC, "invalid directive on pass two");
1004 break;
1007 else /* not a directive */
1009 parse_line (2, line, &output_ins,
1010 report_error, evaluate, redefine_label);
1011 if (forwref != NULL && globallineno == forwref->lineno) {
1012 output_ins.forw_ref = TRUE;
1013 do {
1014 output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD;
1015 forwref = saa_rstruct (forwrefs);
1016 } while (forwref != NULL && forwref->lineno == globallineno);
1017 } else
1018 output_ins.forw_ref = FALSE;
1021 * Hack to prevent phase error in the code
1022 * rol ax,x
1023 * x equ 1
1025 * If the second operand is a forward reference,
1026 * the UNITY property of the number 1 in that
1027 * operand is cancelled. Otherwise the above
1028 * sequence will cause a phase error.
1030 * This hack means that the above code will
1031 * generate 286+ code.
1033 * The forward reference will mean that the
1034 * operand will not have the UNITY property on
1035 * the first pass, so the pass behaviours will
1036 * be consistent.
1039 if (output_ins.forw_ref &&
1040 output_ins.operands >= 2 &&
1041 (output_ins.oprs[1].opflags & OPFLAG_FORWARD))
1043 output_ins.oprs[1].type &= ~ONENESS;
1046 if (output_ins.opcode == I_EQU)
1049 * Special `..' EQUs get processed here, except
1050 * `..@' macro processor EQUs which are done above.
1052 if (output_ins.label[0] == '.' &&
1053 output_ins.label[1] == '.' &&
1054 output_ins.label[2] != '@')
1056 if (output_ins.operands == 1 &&
1057 (output_ins.oprs[0].type & IMMEDIATE)) {
1058 define_label (output_ins.label,
1059 output_ins.oprs[0].segment,
1060 output_ins.oprs[0].offset,
1061 NULL, FALSE, FALSE, ofmt, report_error);
1063 else if (output_ins.operands == 2 &&
1064 (output_ins.oprs[0].type & IMMEDIATE) &&
1065 (output_ins.oprs[0].type & COLON) &&
1066 output_ins.oprs[0].segment == NO_SEG &&
1067 (output_ins.oprs[1].type & IMMEDIATE) &&
1068 output_ins.oprs[1].segment == NO_SEG)
1070 define_label (output_ins.label,
1071 output_ins.oprs[0].offset | SEG_ABS,
1072 output_ins.oprs[1].offset,
1073 NULL, FALSE, FALSE, ofmt, report_error);
1075 else
1076 report_error(ERR_NONFATAL, "bad syntax for EQU");
1079 offs += assemble (location.segment, offs, sb,
1080 &output_ins, ofmt, report_error, &nasmlist);
1081 cleanup_insn (&output_ins);
1082 set_curr_ofs (offs);
1085 nasm_free (line);
1087 location.offset = offs = get_curr_ofs;
1090 preproc->cleanup();
1091 nasmlist.cleanup();
1094 static int getkw (char *buf, char **value)
1096 char *p, *q;
1098 if (*buf!='[')
1099 return 0;
1101 p = buf;
1103 while (*p && *p != ']') p++;
1105 if (!*p)
1106 return 0;
1108 q = p++;
1110 while (*p && *p != ';') {
1111 if (!isspace(*p))
1112 return 0;
1113 p++;
1115 q[1] = '\0';
1117 p = buf+1;
1118 while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
1119 buf++;
1120 if (*buf==']') {
1121 *buf = '\0';
1122 *value = buf;
1123 } else {
1124 *buf++ = '\0';
1125 while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
1126 *value = buf;
1127 while (*buf!=']') buf++;
1128 *buf++ = '\0';
1130 for (q=p; *q; q++)
1131 *q = tolower(*q);
1132 if (!strcmp(p, "segment") || !strcmp(p, "section"))
1133 return 1;
1134 if (!strcmp(p, "extern"))
1135 return 2;
1136 if (!strcmp(p, "bits"))
1137 return 3;
1138 if (!strcmp(p, "global"))
1139 return 4;
1140 if (!strcmp(p, "common"))
1141 return 5;
1142 if (!strcmp(p, "absolute"))
1143 return 6;
1144 if (!strcmp(p, "debug"))
1145 return 7;
1146 return -1;
1149 static void report_error (int severity, char *fmt, ...)
1151 va_list ap;
1154 * See if it's a suppressed warning.
1156 if ((severity & ERR_MASK) == ERR_WARNING &&
1157 (severity & ERR_WARN_MASK) != 0 &&
1158 suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
1159 return; /* and bail out if so */
1162 * See if it's a pass-one only warning and we're not in pass one.
1164 if ((severity & ERR_PASS1) && pass != 1)
1165 return;
1167 if (severity & ERR_NOFILE)
1168 fputs ("nasm: ", stdout);
1169 else {
1170 char * currentfile = NULL;
1171 long lineno = 0;
1172 src_get (&lineno, &currentfile);
1173 fprintf (stdout, "%s:%ld: ", currentfile, lineno);
1174 nasm_free (currentfile);
1177 if ( (severity & ERR_MASK) == ERR_WARNING)
1178 fputs ("warning: ", stdout);
1179 else if ( (severity & ERR_MASK) == ERR_PANIC)
1180 fputs ("panic: ", stdout);
1182 va_start (ap, fmt);
1183 vfprintf (stdout, fmt, ap);
1184 fputc ('\n', stdout);
1186 if (severity & ERR_USAGE)
1187 want_usage = TRUE;
1189 switch (severity & ERR_MASK) {
1190 case ERR_WARNING:
1191 /* no further action, by definition */
1192 break;
1193 case ERR_NONFATAL:
1194 terminate_after_phase = TRUE;
1195 break;
1196 case ERR_FATAL:
1197 if (ofile) {
1198 fclose(ofile);
1199 remove(outname);
1201 if (want_usage)
1202 usage();
1203 exit(1); /* instantly die */
1204 break; /* placate silly compilers */
1205 case ERR_PANIC:
1206 abort(); /* halt, catch fire, and dump core */
1207 break;
1211 static void usage(void)
1213 fputs("type `nasm -h' for help\n", stdout);
1216 static void register_output_formats(void)
1218 ofmt = ofmt_register (report_error);
1221 #define BUF_DELTA 512
1223 static FILE *no_pp_fp;
1224 static efunc no_pp_err;
1225 static ListGen *no_pp_list;
1226 static long no_pp_lineinc;
1228 static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
1229 ListGen *listgen)
1231 src_set_fname(nasm_strdup(file));
1232 src_set_linnum(0);
1233 no_pp_lineinc = 1;
1234 no_pp_err = error;
1235 no_pp_fp = fopen(file, "r");
1236 if (!no_pp_fp)
1237 no_pp_err (ERR_FATAL | ERR_NOFILE,
1238 "unable to open input file `%s'", file);
1239 no_pp_list = listgen;
1240 (void) pass; /* placate compilers */
1241 (void) eval; /* placate compilers */
1244 static char *no_pp_getline (void)
1246 char *buffer, *p, *q;
1247 int bufsize;
1249 bufsize = BUF_DELTA;
1250 buffer = nasm_malloc(BUF_DELTA);
1251 src_set_linnum(src_get_linnum() + no_pp_lineinc);
1253 while (1) { /* Loop to handle %line */
1255 p = buffer;
1256 while (1) { /* Loop to handle long lines */
1257 q = fgets(p, bufsize-(p-buffer), no_pp_fp);
1258 if (!q)
1259 break;
1260 p += strlen(p);
1261 if (p > buffer && p[-1] == '\n')
1262 break;
1263 if (p-buffer > bufsize-10) {
1264 int offset;
1265 offset = p - buffer;
1266 bufsize += BUF_DELTA;
1267 buffer = nasm_realloc(buffer, bufsize);
1268 p = buffer + offset;
1272 if (!q && p == buffer) {
1273 nasm_free (buffer);
1274 return NULL;
1278 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1279 * them are present at the end of the line.
1281 buffer[strcspn(buffer, "\r\n\032")] = '\0';
1283 if (!strncmp(buffer, "%line", 5)) {
1284 long ln;
1285 int li;
1286 char *nm = nasm_malloc(strlen(buffer));
1287 if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) {
1288 nasm_free( src_set_fname(nm) );
1289 src_set_linnum(ln);
1290 no_pp_lineinc = li;
1291 continue;
1293 nasm_free(nm);
1295 break;
1298 no_pp_list->line (LIST_READ, buffer);
1300 return buffer;
1303 static void no_pp_cleanup (void)
1305 fclose(no_pp_fp);