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.
23 static void report_error (int, char *, ...);
24 static void parse_cmdline (int, char **);
25 static void assemble_file (char *);
26 static int getkw (char *buf
, char **value
);
27 static void register_output_formats(void);
28 static void usage(void);
31 static char inname
[FILENAME_MAX
];
32 static char outname
[FILENAME_MAX
];
33 static char realout
[FILENAME_MAX
];
34 static int lineno
; /* for error reporting */
35 static int lineinc
; /* set by [LINE] or [ONELINE] */
36 static int globallineno
; /* for forward-reference tracking */
38 static struct ofmt
*ofmt
= NULL
;
40 static FILE *ofile
= NULL
;
41 static int sb
= 16; /* by default */
43 static long current_seg
;
44 static struct RAA
*offsets
;
45 static long abs_offset
;
47 static struct SAA
*forwrefs
; /* keep track of forward references */
50 static Preproc
*preproc
;
51 static int preprocess_only
;
53 /* used by error function to report location */
54 static char currentfile
[FILENAME_MAX
];
57 * This is a null preprocessor which just copies lines from input
58 * to output. It's used when someone explicitly requests that NASM
59 * not preprocess their source file.
62 static void no_pp_reset (char *, efunc
);
63 static char *no_pp_getline (void);
64 static void no_pp_cleanup (void);
65 static Preproc no_pp
= {
72 * get/set current offset...
74 #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
75 raa_read(offsets,current_seg))
76 #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
77 (void)(offsets=raa_write(offsets,current_seg,(x))))
79 static int want_usage
;
80 static int terminate_after_phase
;
82 int main(int argc
, char **argv
) {
83 want_usage
= terminate_after_phase
= FALSE
;
85 nasm_set_malloc_error (report_error
);
87 forwrefs
= saa_init ((long)sizeof(int));
90 preprocess_only
= FALSE
;
94 register_output_formats();
96 parse_cmdline(argc
, argv
);
98 if (terminate_after_phase
) {
104 if (preprocess_only
) {
108 ofile
= fopen(outname
, "w");
110 report_error (ERR_FATAL
| ERR_NOFILE
,
111 "unable to open output file `%s'", outname
);
114 preproc
->reset (inname
, report_error
);
115 strcpy(currentfile
,inname
);
118 while ( (line
= preproc
->getline()) ) {
130 if (ofile
&& terminate_after_phase
)
134 ofmt
->filename (inname
, realout
, report_error
);
135 strcpy(outname
, realout
);
138 ofile
= fopen(outname
, "wb");
140 report_error (ERR_FATAL
| ERR_NOFILE
,
141 "unable to open output file `%s'", outname
);
143 ofmt
->init (ofile
, report_error
, define_label
);
144 assemble_file (inname
);
145 if (!terminate_after_phase
) {
150 if (terminate_after_phase
)
162 static void parse_cmdline(int argc
, char **argv
) {
165 *inname
= *outname
= '\0';
170 case 'o': /* these parameters take values */
172 if (p
[2]) /* the parameter's in the option */
175 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
176 "option `-%c' requires an argument",
180 --argc
, param
= *++argv
;
181 if (p
[1]=='o') { /* output file */
182 strcpy (outname
, param
);
183 } else if (p
[1]=='f') { /* output format */
184 ofmt
= ofmt_find(param
);
186 report_error (ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
187 "unrecognised output format `%s'",
194 "usage: nasm [-o outfile] [-f format]"
195 " [-a] [-e] filename\n");
197 " or nasm -r for version info\n\n");
199 " -e means preprocess only; "
200 "-a means don't preprocess\n\n");
202 "valid output formats for -f are"
203 " (`*' denotes default):\n");
205 exit (0); /* never need usage message here */
208 fprintf(stderr
, "NASM version %s\n", NASM_VER
);
209 exit (0); /* never need usage message here */
211 case 'e': /* preprocess only */
212 preprocess_only
= TRUE
;
214 case 'a': /* assemble only - don't preprocess */
218 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
219 "unrecognised option `-%c'",
225 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
226 "more than one input file specified");
232 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
233 "no input file specified");
236 static void assemble_file (char *fname
) {
237 char *value
, *p
, *line
;
246 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
247 preproc
->reset(fname
, report_error
);
248 strcpy(currentfile
,fname
);
252 while ( (line
= preproc
->getline()) ) {
256 if (line
[0] == '%') {
258 char buf
[FILENAME_MAX
];
261 * This will be a line number directive. They come
262 * straight from the preprocessor, so we'll subject
263 * them to only minimal error checking.
265 if (strncmp(line
, "%line", 5)) {
266 if (preproc
== &no_pp
)
267 report_error (ERR_WARNING
, "unknown `%%' directive in "
268 " preprocessed source");
269 } else if (sscanf(line
, "%%line %d+%d %s", &ln
, &li
, buf
) != 3) {
270 report_error (ERR_WARNING
, "bogus line number directive in"
271 " preprocessed source");
275 strncpy (currentfile
, buf
, FILENAME_MAX
-1);
276 currentfile
[FILENAME_MAX
-1] = '\0';
281 /* here we parse our directives; this is not handled by the 'real'
283 if ( (i
= getkw (line
, &value
)) ) {
285 case 1: /* [SEGMENT n] */
286 seg
= ofmt
->section (value
, pass
, &sb
);
288 report_error (ERR_NONFATAL
,
289 "segment name `%s' not recognised",
295 case 2: /* [EXTERN label] */
297 value
++; /* skip initial $ if present */
298 declare_as_global (value
, report_error
);
299 define_label (value
, seg_alloc(), 0L, ofmt
, report_error
);
301 case 3: /* [BITS bits] */
302 switch (atoi(value
)) {
308 report_error(ERR_NONFATAL
,
309 "`%s' is not a valid argument to [BITS]",
314 case 4: /* [GLOBAL symbol] */
316 value
++; /* skip initial $ if present */
317 declare_as_global (value
, report_error
);
319 case 5: /* [COMMON symbol size] */
321 while (*p
&& !isspace(*p
))
326 while (*p
&& isspace(*p
))
328 size
= readnum (p
, &rn_error
);
330 report_error (ERR_NONFATAL
, "invalid size specified"
331 " in COMMON declaration");
333 define_common (value
, seg_alloc(), size
,
336 report_error (ERR_NONFATAL
, "no size specified in"
337 " COMMON declaration");
339 case 6: /* [ABSOLUTE address] */
340 current_seg
= NO_SEG
;
341 abs_offset
= readnum(value
, &rn_error
);
343 report_error (ERR_NONFATAL
, "invalid address specified"
344 " for ABSOLUTE directive");
345 abs_offset
= 0x100;/* don't go near zero in case of / */
349 if (!ofmt
->directive (line
+1, value
, 1))
350 report_error (ERR_NONFATAL
, "unrecognised directive [%s]",
355 long offs
= get_curr_ofs
;
356 parse_line (current_seg
, offs
, lookup_label
,
357 1, line
, &output_ins
, ofmt
, report_error
);
358 if (output_ins
.forw_ref
)
359 *(int *)saa_wstruct(forwrefs
) = globallineno
;
362 * Hack to prevent phase error in the code
366 * We rule that the presence of a forward reference
367 * cancels out the UNITY property of the number 1. This
368 * isn't _strictly_ necessary in pass one, since the
369 * problem occurs in pass two, but for the sake of
370 * having the passes as near to identical as we can
371 * manage, we do it like this.
373 if (output_ins
.forw_ref
) {
375 for (i
=0; i
<output_ins
.operands
; i
++)
376 output_ins
.oprs
[i
].type
&= ~ONENESS
;
379 if (output_ins
.opcode
== I_EQU
) {
381 * Special `..' EQUs get processed in pass two.
383 if (!output_ins
.label
)
384 report_error (ERR_NONFATAL
,
385 "EQU not preceded by label");
386 else if (output_ins
.label
[0] != '.' ||
387 output_ins
.label
[1] != '.') {
388 if (output_ins
.operands
== 1 &&
389 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
390 define_label (output_ins
.label
,
391 output_ins
.oprs
[0].segment
,
392 output_ins
.oprs
[0].offset
,
394 } else if (output_ins
.operands
== 2 &&
395 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
396 (output_ins
.oprs
[0].type
& COLON
) &&
397 output_ins
.oprs
[0].segment
== NO_SEG
&&
398 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
399 output_ins
.oprs
[1].segment
== NO_SEG
) {
400 define_label (output_ins
.label
,
401 output_ins
.oprs
[0].offset
| SEG_ABS
,
402 output_ins
.oprs
[1].offset
,
405 report_error(ERR_NONFATAL
, "bad syntax for EQU");
408 if (output_ins
.label
)
409 define_label (output_ins
.label
,
412 offs
+= insn_size (current_seg
, offs
, sb
,
413 &output_ins
, report_error
);
416 cleanup_insn (&output_ins
);
422 if (terminate_after_phase
) {
432 saa_rewind (forwrefs
);
434 int *p
= saa_rstruct (forwrefs
);
440 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
442 offsets
= raa_init();
443 preproc
->reset(fname
, report_error
);
444 strcpy(currentfile
,fname
);
448 while ( (line
= preproc
->getline()) ) {
452 if (line
[0] == '%') {
454 char buf
[FILENAME_MAX
];
457 * This will be a line number directive. They come
458 * straight from the preprocessor, so we'll subject
459 * them to only minimal error checking.
461 if (!strncmp(line
, "%line", 5) &&
462 sscanf(line
, "%%line %d+%d %s", &ln
, &li
, buf
) == 3) {
465 strncpy (currentfile
, buf
, FILENAME_MAX
-1);
466 currentfile
[FILENAME_MAX
-1] = '\0';
471 /* here we parse our directives; this is not handled by
472 * the 'real' parser. */
474 if ( (i
= getkw (line
, &value
)) ) {
476 case 1: /* [SEGMENT n] */
477 seg
= ofmt
->section (value
, pass
, &sb
);
479 report_error (ERR_PANIC
,
480 "invalid segment name on pass two");
484 case 2: /* [EXTERN label] */
486 case 3: /* [BITS bits] */
487 switch (atoi(value
)) {
493 report_error(ERR_PANIC
,
494 "invalid [BITS] value on pass two",
499 case 4: /* [GLOBAL symbol] */
501 case 5: /* [COMMON symbol size] */
503 case 6: /* [ABSOLUTE addr] */
504 current_seg
= NO_SEG
;
505 abs_offset
= readnum(value
, &rn_error
);
507 report_error (ERR_PANIC
, "invalid ABSOLUTE address "
511 if (!ofmt
->directive (line
+1, value
, 2))
512 report_error (ERR_PANIC
, "invalid directive on pass two");
516 long offs
= get_curr_ofs
;
517 parse_line (current_seg
, offs
, lookup_label
, 2,
518 line
, &output_ins
, ofmt
, report_error
);
519 if (globallineno
== forwline
) {
520 int *p
= saa_rstruct (forwrefs
);
525 output_ins
.forw_ref
= TRUE
;
527 output_ins
.forw_ref
= FALSE
;
530 * Hack to prevent phase error in the code
534 if (output_ins
.forw_ref
) {
536 for (i
=0; i
<output_ins
.operands
; i
++)
537 output_ins
.oprs
[i
].type
&= ~ONENESS
;
541 if (output_ins
.label
)
542 define_label_stub (output_ins
.label
, report_error
);
543 if (output_ins
.opcode
== I_EQU
) {
545 * Special `..' EQUs get processed here.
547 if (output_ins
.label
[0] == '.' &&
548 output_ins
.label
[1] == '.') {
549 if (output_ins
.operands
== 1 &&
550 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
551 define_label (output_ins
.label
,
552 output_ins
.oprs
[0].segment
,
553 output_ins
.oprs
[0].offset
,
555 } else if (output_ins
.operands
== 2 &&
556 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
557 (output_ins
.oprs
[0].type
& COLON
) &&
558 output_ins
.oprs
[0].segment
== NO_SEG
&&
559 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
560 output_ins
.oprs
[1].segment
== NO_SEG
) {
561 define_label (output_ins
.label
,
562 output_ins
.oprs
[0].offset
| SEG_ABS
,
563 output_ins
.oprs
[1].offset
,
566 report_error(ERR_NONFATAL
, "bad syntax for EQU");
569 offs
+= assemble (current_seg
, offs
, sb
,
570 &output_ins
, ofmt
, report_error
);
571 cleanup_insn (&output_ins
);
579 static int getkw (char *buf
, char **value
) {
585 while (*p
&& *p
!= ']') p
++;
589 while (*p
&& *p
!= ';') {
597 while (*buf
&& *buf
!=' ' && *buf
!=']' && *buf
!='\t')
605 while (*buf
!=']') buf
++;
610 if (!strcmp(p
, "segment") || !strcmp(p
, "section"))
612 if (!strcmp(p
, "extern"))
614 if (!strcmp(p
, "bits"))
616 if (!strcmp(p
, "global"))
618 if (!strcmp(p
, "common"))
620 if (!strcmp(p
, "absolute"))
625 static void report_error (int severity
, char *fmt
, ...) {
628 if (severity
& ERR_NOFILE
)
629 fputs ("nasm: ", stderr
);
631 fprintf (stderr
, "%s:%d: ", currentfile
,
632 lineno
+ (severity
& ERR_OFFBY1
? lineinc
: 0));
634 if ( (severity
& ERR_MASK
) == ERR_WARNING
)
635 fputs ("warning: ", stderr
);
636 else if ( (severity
& ERR_MASK
) == ERR_PANIC
)
637 fputs ("panic: ", stderr
);
640 vfprintf (stderr
, fmt
, ap
);
641 fputc ('\n', stderr
);
643 if (severity
& ERR_USAGE
)
646 switch (severity
& ERR_MASK
) {
648 /* no further action, by definition */
651 terminate_after_phase
= TRUE
;
660 exit(1); /* instantly die */
661 break; /* placate silly compilers */
663 abort(); /* halt, catch fire, and dump core */
668 static void usage(void) {
669 fputs("type `nasm -h' for help\n", stderr
);
672 static void register_output_formats(void) {
673 /* Flat-form binary format */
675 extern struct ofmt of_bin
;
677 /* Unix formats: a.out, COFF, ELF */
679 extern struct ofmt of_aout
;
682 extern struct ofmt of_coff
;
685 extern struct ofmt of_elf
;
687 /* Linux strange format: as86 */
689 extern struct ofmt of_as86
;
691 /* DOS formats: OBJ, Win32 */
693 extern struct ofmt of_obj
;
696 extern struct ofmt of_win32
;
699 extern struct ofmt of_rdf
;
701 #ifdef OF_DBG /* debug format must be included specifically */
702 extern struct ofmt of_dbg
;
706 ofmt_register (&of_bin
);
709 ofmt_register (&of_aout
);
712 ofmt_register (&of_coff
);
715 ofmt_register (&of_elf
);
718 ofmt_register (&of_as86
);
721 ofmt_register (&of_obj
);
724 ofmt_register (&of_win32
);
727 ofmt_register (&of_rdf
);
730 ofmt_register (&of_dbg
);
733 * set the default format
738 #define BUF_DELTA 512
740 static FILE *no_pp_fp
;
741 static efunc no_pp_err
;
743 static void no_pp_reset (char *file
, efunc error
) {
745 no_pp_fp
= fopen(file
, "r");
747 no_pp_err (ERR_FATAL
| ERR_NOFILE
,
748 "unable to open input file `%s'", file
);
751 static char *no_pp_getline (void) {
752 char *buffer
, *p
, *q
;
756 buffer
= nasm_malloc(BUF_DELTA
);
759 q
= fgets(p
, bufsize
-(p
-buffer
), no_pp_fp
);
763 if (p
> buffer
&& p
[-1] == '\n')
765 if (p
-buffer
> bufsize
-10) {
766 bufsize
+= BUF_DELTA
;
767 buffer
= nasm_realloc(buffer
, bufsize
);
771 if (!q
&& p
== buffer
) {
777 * Play safe: remove CRs as well as LFs, if any of either are
778 * present at the end of the line.
780 while (p
> buffer
&& (p
[-1] == '\n' || p
[-1] == '\r'))
784 * Handle spurious ^Z, which may be inserted into source files
785 * by some file transfer utilities.
787 buffer
[strcspn(buffer
, "\032")] = '\0';
792 static void no_pp_cleanup (void) {