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.
24 static void report_error (int, char *, ...);
25 static void parse_cmdline (int, char **);
26 static void assemble_file (char *);
27 static int getkw (char *buf
, char **value
);
28 static void register_output_formats(void);
29 static void usage(void);
32 static char inname
[FILENAME_MAX
];
33 static char outname
[FILENAME_MAX
];
34 static char listname
[FILENAME_MAX
];
35 static char realout
[FILENAME_MAX
];
36 static int lineno
; /* for error reporting */
37 static int lineinc
; /* set by [LINE] or [ONELINE] */
38 static int globallineno
; /* for forward-reference tracking */
40 static struct ofmt
*ofmt
= NULL
;
42 static FILE *ofile
= NULL
;
43 static int sb
= 16; /* by default */
45 static int use_stdout
= FALSE
; /* by default, errors to stderr */
47 static long current_seg
;
48 static struct RAA
*offsets
;
49 static long abs_offset
;
51 static struct SAA
*forwrefs
; /* keep track of forward references */
54 static Preproc
*preproc
;
55 static int preprocess_only
;
57 /* used by error function to report location */
58 static char currentfile
[FILENAME_MAX
];
61 * Which of the suppressible warnings are suppressed. Entry zero
62 * doesn't do anything. Initial defaults are given here.
64 static char suppressed
[1+ERR_WARN_MAX
] = {
69 * The option names for the suppressible warnings. As before, entry
72 static char *suppressed_names
[1+ERR_WARN_MAX
] = {
73 NULL
, "macro-params", "orphan-labels"
77 * The explanations for the suppressible warnings. As before, entry
80 static char *suppressed_what
[1+ERR_WARN_MAX
] = {
81 NULL
, "macro calls with wrong no. of params",
82 "labels alone on lines without trailing `:'"
86 * This is a null preprocessor which just copies lines from input
87 * to output. It's used when someone explicitly requests that NASM
88 * not preprocess their source file.
91 static void no_pp_reset (char *, efunc
, ListGen
*);
92 static char *no_pp_getline (void);
93 static void no_pp_cleanup (void);
94 static Preproc no_pp
= {
101 * get/set current offset...
103 #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
104 raa_read(offsets,current_seg))
105 #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
106 (void)(offsets=raa_write(offsets,current_seg,(x))))
108 static int want_usage
;
109 static int terminate_after_phase
;
111 int main(int argc
, char **argv
) {
112 want_usage
= terminate_after_phase
= FALSE
;
114 nasm_set_malloc_error (report_error
);
115 offsets
= raa_init();
116 forwrefs
= saa_init ((long)sizeof(int));
119 preprocess_only
= FALSE
;
123 register_output_formats();
125 parse_cmdline(argc
, argv
);
127 if (terminate_after_phase
) {
133 if (preprocess_only
) {
137 ofile
= fopen(outname
, "w");
139 report_error (ERR_FATAL
| ERR_NOFILE
,
140 "unable to open output file `%s'", outname
);
143 preproc
->reset (inname
, report_error
, &nasmlist
);
144 strcpy(currentfile
,inname
);
147 while ( (line
= preproc
->getline()) ) {
159 if (ofile
&& terminate_after_phase
)
163 * We must call ofmt->filename _anyway_, even if the user
164 * has specified their own output file, because some
165 * formats (eg OBJ and COFF) use ofmt->filename to find out
166 * the name of the input file and then put that inside the
169 ofmt
->filename (inname
, realout
, report_error
);
171 strcpy(outname
, realout
);
174 ofile
= fopen(outname
, "wb");
176 report_error (ERR_FATAL
| ERR_NOFILE
,
177 "unable to open output file `%s'", outname
);
180 * We must call init_labels() before ofmt->init() since
181 * some object formats will want to define labels in their
182 * init routines. (eg OS/2 defines the FLAT group)
185 ofmt
->init (ofile
, report_error
, define_label
);
186 assemble_file (inname
);
187 if (!terminate_after_phase
) {
192 * We had an fclose on the output file here, but we
193 * actually do that in all the object file drivers as well,
194 * so we're leaving out the one here.
197 if (terminate_after_phase
) {
209 if (terminate_after_phase
)
215 static int process_arg (char *p
, char *q
) {
228 case 'o': /* these parameters take values */
234 if (p
[2]) /* the parameter's in the option */
237 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
238 "option `-%c' requires an argument",
242 advance
= 1, param
= q
;
243 if (p
[1]=='o') { /* output file */
244 strcpy (outname
, param
);
245 } else if (p
[1]=='f') { /* output format */
246 ofmt
= ofmt_find(param
);
248 report_error (ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
249 "unrecognised output format `%s'",
252 } else if (p
[1]=='p') { /* pre-include */
253 pp_pre_include (param
);
254 } else if (p
[1]=='d') { /* pre-define */
255 pp_pre_define (param
);
256 } else if (p
[1]=='i') { /* include search path */
257 pp_include_path (param
);
258 } else if (p
[1]=='l') { /* listing file */
259 strcpy (listname
, param
);
263 fprintf(use_stdout
? stdout
: stderr
,
264 "usage: nasm [-o outfile] [-f format] [-l listfile]"
265 " [options...] filename\n");
266 fprintf(use_stdout
? stdout
: stderr
,
267 " or nasm -r for version info\n\n");
268 fprintf(use_stdout
? stdout
: stderr
,
269 " -e means preprocess only; "
270 "-a means don't preprocess\n");
271 fprintf(use_stdout
? stdout
: stderr
,
272 " -s means send errors to stdout not stderr\n");
273 fprintf(use_stdout
? stdout
: stderr
,
274 " -i<path> adds a pathname to the include file"
275 " path\n -p<file> pre-includes a file;"
276 " -d<macro>[=<value] pre-defines a macro\n");
277 fprintf(use_stdout
? stdout
: stderr
,
278 " -w+foo enables warnings about foo; "
279 "-w-foo disables them\n where foo can be:\n");
280 for (i
=1; i
<=ERR_WARN_MAX
; i
++)
281 fprintf(use_stdout
? stdout
: stderr
,
282 " %-16s%s (default %s)\n",
283 suppressed_names
[i
], suppressed_what
[i
],
284 suppressed
[i
] ? "off" : "on");
285 fprintf(use_stdout
? stdout
: stderr
,
286 "\nvalid output formats for -f are"
287 " (`*' denotes default):\n");
288 ofmt_list(ofmt
, use_stdout
? stdout
: stderr
);
289 exit (0); /* never need usage message here */
292 fprintf(use_stdout
? stdout
: stderr
,
293 "NASM version %s\n", NASM_VER
);
294 exit (0); /* never need usage message here */
296 case 'e': /* preprocess only */
297 preprocess_only
= TRUE
;
299 case 'a': /* assemble only - don't preprocess */
303 if (p
[2] != '+' && p
[2] != '-') {
304 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
305 "invalid option to `-w'");
307 for (i
=1; i
<=ERR_WARN_MAX
; i
++)
308 if (!nasm_stricmp(p
+3, suppressed_names
[i
]))
310 if (i
<= ERR_WARN_MAX
)
311 suppressed
[i
] = (p
[2] == '-');
313 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
314 "invalid option to `-w'");
318 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
319 "unrecognised option `-%c'",
325 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
326 "more than one input file specified");
334 static void parse_cmdline(int argc
, char **argv
) {
335 char *envreal
, *envcopy
, *p
, *q
, *arg
, *prevarg
;
336 char separator
= ' ';
338 *inname
= *outname
= *listname
= '\0';
341 * First, process the NASM environment variable.
343 envreal
= getenv("NASM");
346 envcopy
= nasm_strdup(envreal
);
352 while (*p
&& *p
!= separator
) p
++;
353 while (*p
== separator
) *p
++ = '\0';
356 if (process_arg (prevarg
, arg
))
362 process_arg (arg
, NULL
);
365 * Now process the actual command line.
370 i
= process_arg (argv
[0], argc
> 1 ? argv
[1] : NULL
);
371 argv
+= i
, argc
-= i
;
375 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
376 "no input file specified");
379 static void assemble_file (char *fname
) {
380 char *value
, *p
, *line
;
387 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
388 preproc
->reset(fname
, report_error
, &nasmlist
);
389 strcpy(currentfile
,fname
);
393 while ( (line
= preproc
->getline()) ) {
397 if (line
[0] == '%') {
399 char buf
[FILENAME_MAX
];
402 * This will be a line number directive. They come
403 * straight from the preprocessor, so we'll subject
404 * them to only minimal error checking.
406 if (strncmp(line
, "%line", 5)) {
407 if (preproc
== &no_pp
)
408 report_error (ERR_WARNING
, "unknown `%%' directive in "
409 " preprocessed source");
410 } else if (sscanf(line
, "%%line %d+%d %s", &ln
, &li
, buf
) != 3) {
411 report_error (ERR_WARNING
, "bogus line number directive in"
412 " preprocessed source");
416 strncpy (currentfile
, buf
, FILENAME_MAX
-1);
417 currentfile
[FILENAME_MAX
-1] = '\0';
422 /* here we parse our directives; this is not handled by the 'real'
424 if ( (i
= getkw (line
, &value
)) ) {
426 case 1: /* [SEGMENT n] */
427 seg
= ofmt
->section (value
, pass
, &sb
);
429 report_error (ERR_NONFATAL
,
430 "segment name `%s' not recognised",
436 case 2: /* [EXTERN label] */
438 value
++; /* skip initial $ if present */
439 declare_as_global (value
, report_error
);
440 define_label (value
, seg_alloc(), 0L, ofmt
, report_error
);
442 case 3: /* [BITS bits] */
443 switch (atoi(value
)) {
449 report_error(ERR_NONFATAL
,
450 "`%s' is not a valid argument to [BITS]",
455 case 4: /* [GLOBAL symbol] */
457 value
++; /* skip initial $ if present */
458 declare_as_global (value
, report_error
);
460 case 5: /* [COMMON symbol size] */
462 while (*p
&& !isspace(*p
))
467 while (*p
&& isspace(*p
))
469 size
= readnum (p
, &rn_error
);
471 report_error (ERR_NONFATAL
, "invalid size specified"
472 " in COMMON declaration");
474 define_common (value
, seg_alloc(), size
,
477 report_error (ERR_NONFATAL
, "no size specified in"
478 " COMMON declaration");
480 case 6: /* [ABSOLUTE address] */
481 current_seg
= NO_SEG
;
482 abs_offset
= readnum(value
, &rn_error
);
484 report_error (ERR_NONFATAL
, "invalid address specified"
485 " for ABSOLUTE directive");
486 abs_offset
= 0x100;/* don't go near zero in case of / */
490 if (!ofmt
->directive (line
+1, value
, 1))
491 report_error (ERR_NONFATAL
, "unrecognised directive [%s]",
496 long offs
= get_curr_ofs
;
497 parse_line (current_seg
, offs
, lookup_label
,
498 1, line
, &output_ins
, ofmt
, report_error
);
499 if (output_ins
.forw_ref
)
500 *(int *)saa_wstruct(forwrefs
) = globallineno
;
503 * Hack to prevent phase error in the code
507 * We rule that the presence of a forward reference
508 * cancels out the UNITY property of the number 1. This
509 * isn't _strictly_ necessary in pass one, since the
510 * problem occurs in pass two, but for the sake of
511 * having the passes as near to identical as we can
512 * manage, we do it like this.
514 if (output_ins
.forw_ref
) {
516 for (i
=0; i
<output_ins
.operands
; i
++)
517 output_ins
.oprs
[i
].type
&= ~ONENESS
;
520 if (output_ins
.opcode
== I_EQU
) {
522 * Special `..' EQUs get processed in pass two,
523 * except `..@' macro-processor EQUs which are done
524 * in the normal place.
526 if (!output_ins
.label
)
527 report_error (ERR_NONFATAL
,
528 "EQU not preceded by label");
529 else if (output_ins
.label
[0] != '.' ||
530 output_ins
.label
[1] != '.' ||
531 output_ins
.label
[2] == '@') {
532 if (output_ins
.operands
== 1 &&
533 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
534 output_ins
.oprs
[0].wrt
== NO_SEG
) {
535 define_label (output_ins
.label
,
536 output_ins
.oprs
[0].segment
,
537 output_ins
.oprs
[0].offset
,
539 } else if (output_ins
.operands
== 2 &&
540 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
541 (output_ins
.oprs
[0].type
& COLON
) &&
542 output_ins
.oprs
[0].segment
== NO_SEG
&&
543 output_ins
.oprs
[0].wrt
== NO_SEG
&&
544 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
545 output_ins
.oprs
[1].segment
== NO_SEG
&&
546 output_ins
.oprs
[1].wrt
== NO_SEG
) {
547 define_label (output_ins
.label
,
548 output_ins
.oprs
[0].offset
| SEG_ABS
,
549 output_ins
.oprs
[1].offset
,
552 report_error(ERR_NONFATAL
, "bad syntax for EQU");
555 if (output_ins
.label
)
556 define_label (output_ins
.label
,
559 offs
+= insn_size (current_seg
, offs
, sb
,
560 &output_ins
, report_error
);
563 cleanup_insn (&output_ins
);
569 if (terminate_after_phase
) {
579 saa_rewind (forwrefs
);
581 nasmlist
.init(listname
, report_error
);
583 int *p
= saa_rstruct (forwrefs
);
589 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
591 offsets
= raa_init();
592 preproc
->reset(fname
, report_error
, &nasmlist
);
593 strcpy(currentfile
,fname
);
597 while ( (line
= preproc
->getline()) ) {
601 if (line
[0] == '%') {
603 char buf
[FILENAME_MAX
];
606 * This will be a line number directive. They come
607 * straight from the preprocessor, so we'll subject
608 * them to only minimal error checking.
610 if (!strncmp(line
, "%line", 5) &&
611 sscanf(line
, "%%line %d+%d %s", &ln
, &li
, buf
) == 3) {
614 strncpy (currentfile
, buf
, FILENAME_MAX
-1);
615 currentfile
[FILENAME_MAX
-1] = '\0';
620 /* here we parse our directives; this is not handled by
621 * the 'real' parser. */
623 if ( (i
= getkw (line
, &value
)) ) {
625 case 1: /* [SEGMENT n] */
626 seg
= ofmt
->section (value
, pass
, &sb
);
628 report_error (ERR_PANIC
,
629 "invalid segment name on pass two");
633 case 2: /* [EXTERN label] */
635 case 3: /* [BITS bits] */
636 switch (atoi(value
)) {
642 report_error(ERR_PANIC
,
643 "invalid [BITS] value on pass two",
648 case 4: /* [GLOBAL symbol] */
650 case 5: /* [COMMON symbol size] */
652 case 6: /* [ABSOLUTE addr] */
653 current_seg
= NO_SEG
;
654 abs_offset
= readnum(value
, &rn_error
);
656 report_error (ERR_PANIC
, "invalid ABSOLUTE address "
660 if (!ofmt
->directive (line
+1, value
, 2))
661 report_error (ERR_PANIC
, "invalid directive on pass two");
665 long offs
= get_curr_ofs
;
666 parse_line (current_seg
, offs
, lookup_label
, 2,
667 line
, &output_ins
, ofmt
, report_error
);
668 if (globallineno
== forwline
) {
669 int *p
= saa_rstruct (forwrefs
);
674 output_ins
.forw_ref
= TRUE
;
676 output_ins
.forw_ref
= FALSE
;
679 * Hack to prevent phase error in the code
683 if (output_ins
.forw_ref
) {
685 for (i
=0; i
<output_ins
.operands
; i
++)
686 output_ins
.oprs
[i
].type
&= ~ONENESS
;
690 if (output_ins
.label
)
691 define_label_stub (output_ins
.label
, report_error
);
692 if (output_ins
.opcode
== I_EQU
) {
694 * Special `..' EQUs get processed here, except
695 * `..@' macro processor EQUs which are done above.
697 if (output_ins
.label
[0] == '.' &&
698 output_ins
.label
[1] == '.' &&
699 output_ins
.label
[2] != '@') {
700 if (output_ins
.operands
== 1 &&
701 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
702 define_label (output_ins
.label
,
703 output_ins
.oprs
[0].segment
,
704 output_ins
.oprs
[0].offset
,
706 } else if (output_ins
.operands
== 2 &&
707 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
708 (output_ins
.oprs
[0].type
& COLON
) &&
709 output_ins
.oprs
[0].segment
== NO_SEG
&&
710 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
711 output_ins
.oprs
[1].segment
== NO_SEG
) {
712 define_label (output_ins
.label
,
713 output_ins
.oprs
[0].offset
| SEG_ABS
,
714 output_ins
.oprs
[1].offset
,
717 report_error(ERR_NONFATAL
, "bad syntax for EQU");
720 offs
+= assemble (current_seg
, offs
, sb
,
721 &output_ins
, ofmt
, report_error
, &nasmlist
);
722 cleanup_insn (&output_ins
);
731 static int getkw (char *buf
, char **value
) {
737 while (*p
&& *p
!= ']') p
++;
741 while (*p
&& *p
!= ';') {
749 while (*buf
&& *buf
!=' ' && *buf
!=']' && *buf
!='\t')
756 while (isspace(*buf
)) buf
++; /* beppu - skip leading whitespace */
758 while (*buf
!=']') buf
++;
763 if (!strcmp(p
, "segment") || !strcmp(p
, "section"))
765 if (!strcmp(p
, "extern"))
767 if (!strcmp(p
, "bits"))
769 if (!strcmp(p
, "global"))
771 if (!strcmp(p
, "common"))
773 if (!strcmp(p
, "absolute"))
778 static void report_error (int severity
, char *fmt
, ...) {
782 * See if it's a suppressed warning.
784 if ((severity
& ERR_MASK
) == ERR_WARNING
&&
785 (severity
& ERR_WARN_MASK
) != 0 &&
786 suppressed
[ (severity
& ERR_WARN_MASK
) >> ERR_WARN_SHR
])
787 return; /* and bail out if so */
789 if (severity
& ERR_NOFILE
)
790 fputs ("nasm: ", use_stdout
? stdout
: stderr
);
792 fprintf (use_stdout
? stdout
: stderr
, "%s:%d: ", currentfile
,
793 lineno
+ (severity
& ERR_OFFBY1
? lineinc
: 0));
795 if ( (severity
& ERR_MASK
) == ERR_WARNING
)
796 fputs ("warning: ", use_stdout
? stdout
: stderr
);
797 else if ( (severity
& ERR_MASK
) == ERR_PANIC
)
798 fputs ("panic: ", use_stdout
? stdout
: stderr
);
801 vfprintf (use_stdout
? stdout
: stderr
, fmt
, ap
);
802 fputc ('\n', use_stdout
? stdout
: stderr
);
804 if (severity
& ERR_USAGE
)
807 switch (severity
& ERR_MASK
) {
809 /* no further action, by definition */
812 terminate_after_phase
= TRUE
;
821 exit(1); /* instantly die */
822 break; /* placate silly compilers */
824 abort(); /* halt, catch fire, and dump core */
829 static void usage(void) {
830 fputs("type `nasm -h' for help\n", use_stdout
? stdout
: stderr
);
833 static void register_output_formats(void) {
834 /* Flat-form binary format */
836 extern struct ofmt of_bin
;
838 /* Unix formats: a.out, COFF, ELF */
840 extern struct ofmt of_aout
;
843 extern struct ofmt of_coff
;
846 extern struct ofmt of_elf
;
848 /* Linux strange format: as86 */
850 extern struct ofmt of_as86
;
852 /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
854 extern struct ofmt of_obj
;
857 extern struct ofmt of_win32
;
860 extern struct ofmt of_os2
;
863 extern struct ofmt of_rdf
;
865 #ifdef OF_DBG /* debug format must be included specifically */
866 extern struct ofmt of_dbg
;
870 ofmt_register (&of_bin
);
873 ofmt_register (&of_aout
);
876 ofmt_register (&of_coff
);
879 ofmt_register (&of_elf
);
882 ofmt_register (&of_as86
);
885 ofmt_register (&of_obj
);
888 ofmt_register (&of_win32
);
891 ofmt_register (&of_os2
);
894 ofmt_register (&of_rdf
);
897 ofmt_register (&of_dbg
);
900 * set the default format
905 #define BUF_DELTA 512
907 static FILE *no_pp_fp
;
908 static efunc no_pp_err
;
910 static void no_pp_reset (char *file
, efunc error
, ListGen
*listgen
) {
912 no_pp_fp
= fopen(file
, "r");
914 no_pp_err (ERR_FATAL
| ERR_NOFILE
,
915 "unable to open input file `%s'", file
);
916 (void) listgen
; /* placate compilers */
919 static char *no_pp_getline (void) {
920 char *buffer
, *p
, *q
;
924 buffer
= nasm_malloc(BUF_DELTA
);
927 q
= fgets(p
, bufsize
-(p
-buffer
), no_pp_fp
);
931 if (p
> buffer
&& p
[-1] == '\n')
933 if (p
-buffer
> bufsize
-10) {
934 bufsize
+= BUF_DELTA
;
935 buffer
= nasm_realloc(buffer
, bufsize
);
939 if (!q
&& p
== buffer
) {
945 * Play safe: remove CRs as well as LFs, if any of either are
946 * present at the end of the line.
948 while (p
> buffer
&& (p
[-1] == '\n' || p
[-1] == '\r'))
952 * Handle spurious ^Z, which may be inserted into source files
953 * by some file transfer utilities.
955 buffer
[strcspn(buffer
, "\032")] = '\0';
960 static void no_pp_cleanup (void) {