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.
22 static void report_error (int, char *, ...);
23 static void parse_cmdline (int, char **);
24 static void assemble_file (char *);
25 static int getkw (char *buf
, char **value
);
26 static void register_output_formats(void);
27 static void usage(void);
30 static char inname
[FILENAME_MAX
];
31 static char outname
[FILENAME_MAX
];
32 static char realout
[FILENAME_MAX
];
33 static int lineno
; /* for error reporting */
35 static struct ofmt
*ofmt
= NULL
;
37 static FILE *ofile
= NULL
;
38 static int sb
= 16; /* by default */
40 static long current_seg
;
41 static struct RAA
*offsets
;
42 static long abs_offset
;
44 static struct SAA
*forwrefs
; /* keep track of forward references */
48 * get/set current offset...
50 #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
51 raa_read(offsets,current_seg))
52 #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
53 (void)(offsets=raa_write(offsets,current_seg,(x))))
55 static int want_usage
;
56 static int terminate_after_phase
;
58 int main(int argc
, char **argv
) {
59 want_usage
= terminate_after_phase
= FALSE
;
61 nasm_set_malloc_error (report_error
);
63 forwrefs
= saa_init ((long)sizeof(int));
67 register_output_formats();
69 parse_cmdline(argc
, argv
);
71 if (terminate_after_phase
) {
78 ofmt
->filename (inname
, realout
, report_error
);
79 strcpy(outname
, realout
);
82 ofile
= fopen(outname
, "wb");
84 report_error (ERR_FATAL
| ERR_NOFILE
,
85 "unable to open output file `%s'", outname
);
87 ofmt
->init (ofile
, report_error
, define_label
);
88 assemble_file (inname
);
89 if (!terminate_after_phase
) {
94 if (terminate_after_phase
)
103 static void parse_cmdline(int argc
, char **argv
) {
106 *inname
= *outname
= '\0';
111 case 'o': /* these parameters take values */
113 if (p
[2]) /* the parameter's in the option */
116 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
117 "option `-%c' requires an argument",
121 --argc
, param
= *++argv
;
122 if (p
[1]=='o') { /* output file */
123 strcpy (outname
, param
);
124 } else if (p
[1]=='f') { /* output format */
125 ofmt
= ofmt_find(param
);
127 report_error (ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
128 "unrecognised output format `%s'",
135 "usage: nasm [-o outfile] [-f format] filename\n");
137 " or nasm -r for version info\n\n");
139 "valid output formats for -f are"
140 " (`*' denotes default):\n");
142 exit (0); /* never need usage message here */
145 fprintf(stderr
, "NASM version %s\n", NASM_VER
);
146 exit (0); /* never need usage message here */
149 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
150 "unrecognised option `-%c'",
156 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
157 "more than one input file specified");
163 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
164 "no input file specified");
167 /* used by error function to report location */
168 static char currentfile
[FILENAME_MAX
];
170 static void assemble_file (char *fname
) {
171 FILE *fp
= fopen (fname
, "r");
172 FILE *oldfile
= NULL
; /* jrh - used when processing include files */
174 char *value
, *p
, buffer
[1024+2]; /* maximum line length defined here */
176 int i
, seg
, rn_error
;
178 if (!fp
) { /* couldn't open file */
179 report_error (ERR_FATAL
| ERR_NOFILE
,
180 "unable to open input file `%s'", fname
);
185 strcpy(currentfile
,fname
);
189 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
192 if (! fgets(buffer
, sizeof(buffer
), fp
)) { /* EOF on current file */
196 lineno
= oldfileline
;
197 strcpy(currentfile
,fname
);
205 if (buffer
[strlen(buffer
)-1] == '\n') {
206 buffer
[strlen(buffer
)-1] = '\0';
207 } else if (!feof(fp
)) {
209 * We have a line that's too long. Throw an error, read
210 * to EOL, and ignore the line for assembly purposes.
212 report_error (ERR_NONFATAL
, "line is longer than %d characters",
214 while (fgets(buffer
, sizeof(buffer
), fp
) &&
215 buffer
[strlen(buffer
)-1] != '\n');
216 continue; /* read another line */
219 * Handle spurious ^Z, which may be inserted by some file
220 * transfer utilities.
222 buffer
[strcspn(buffer
, "\032")] = '\0';
224 /* here we parse our directives; this is not handled by the 'real'
226 if ( (i
= getkw (buffer
, &value
)) ) {
228 case 1: /* [SEGMENT n] */
229 seg
= ofmt
->section (value
, pass
, &sb
);
231 report_error (ERR_NONFATAL
,
232 "segment name `%s' not recognised",
238 case 2: /* [EXTERN label] */
240 value
++; /* skip initial $ if present */
241 declare_as_global (value
, report_error
);
242 define_label (value
, seg_alloc(), 0L, ofmt
, report_error
);
244 case 3: /* [BITS bits] */
245 switch (atoi(value
)) {
251 report_error(ERR_NONFATAL
,
252 "`%s' is not a valid argument to [BITS]",
257 case 4: /* [INC file] */
259 oldfileline
= lineno
;
261 strcpy(currentfile
,value
);
262 fp
= fopen(value
,"r");
264 lineno
= oldfileline
;
266 strcpy(currentfile
,fname
);
267 report_error (ERR_FATAL
,
268 "unable to open include file `%s'\n",
272 case 5: /* [GLOBAL symbol] */
274 value
++; /* skip initial $ if present */
275 declare_as_global (value
, report_error
);
277 case 6: /* [COMMON symbol size] */
279 while (*p
&& !isspace(*p
))
284 while (*p
&& isspace(*p
))
286 size
= readnum (p
, &rn_error
);
288 report_error (ERR_NONFATAL
, "invalid size specified"
289 " in COMMON declaration");
291 define_common (value
, seg_alloc(), size
,
294 report_error (ERR_NONFATAL
, "no size specified in"
295 " COMMON declaration");
297 case 7: /* [ABSOLUTE address] */
298 current_seg
= NO_SEG
;
299 abs_offset
= readnum(value
, &rn_error
);
301 report_error (ERR_NONFATAL
, "invalid address specified"
302 " for ABSOLUTE directive");
303 abs_offset
= 0x100;/* don't go near zero in case of / */
307 if (!ofmt
->directive (buffer
+1, value
, 1))
308 report_error (ERR_NONFATAL
, "unrecognised directive [%s]",
313 long offs
= get_curr_ofs
;
314 parse_line (current_seg
, offs
, lookup_label
,
315 1, buffer
, &output_ins
, ofmt
, report_error
);
316 if (output_ins
.forw_ref
)
317 *(int *)saa_wstruct(forwrefs
) = lineno
;
318 if (output_ins
.opcode
== I_EQU
) {
320 * Special `..' EQUs get processed in pass two.
322 if (!output_ins
.label
)
323 report_error (ERR_NONFATAL
,
324 "EQU not preceded by label");
325 else if (output_ins
.label
[0] != '.' ||
326 output_ins
.label
[1] != '.') {
327 if (output_ins
.operands
== 1 &&
328 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
329 define_label (output_ins
.label
,
330 output_ins
.oprs
[0].segment
,
331 output_ins
.oprs
[0].offset
,
333 } else if (output_ins
.operands
== 2 &&
334 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
335 (output_ins
.oprs
[0].type
& COLON
) &&
336 output_ins
.oprs
[0].segment
== NO_SEG
&&
337 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
338 output_ins
.oprs
[1].segment
== NO_SEG
) {
339 define_label (output_ins
.label
,
340 output_ins
.oprs
[0].offset
| SEG_ABS
,
341 output_ins
.oprs
[1].offset
,
344 report_error(ERR_NONFATAL
, "bad syntax for EQU");
347 if (output_ins
.label
)
348 define_label (output_ins
.label
,
351 offs
+= insn_size (current_seg
, offs
, sb
,
352 &output_ins
, report_error
);
355 cleanup_insn (&output_ins
);
359 if (terminate_after_phase
) {
370 saa_rewind (forwrefs
);
372 int *p
= saa_rstruct (forwrefs
);
378 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
380 offsets
= raa_init();
383 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
387 lineno
= oldfileline
;
388 strcpy(currentfile
,fname
);
395 if (buffer
[strlen(buffer
)-1] == '\n')
396 buffer
[strlen(buffer
)-1] = '\0';
398 report_error (ERR_PANIC
,
399 "too-long line got through from pass one");
401 * Handle spurious ^Z, which may be inserted by some file
402 * transfer utilities.
404 buffer
[strcspn(buffer
, "\032")] = '\0';
406 /* here we parse our directives; this is not handled by
407 * the 'real' parser. */
409 if ( (i
= getkw (buffer
, &value
)) ) {
411 case 1: /* [SEGMENT n] */
412 seg
= ofmt
->section (value
, pass
, &sb
);
414 report_error (ERR_PANIC
,
415 "invalid segment name on pass two");
419 case 2: /* [EXTERN label] */
421 case 3: /* [BITS bits] */
422 switch (atoi(value
)) {
428 report_error(ERR_PANIC
,
429 "invalid [BITS] value on pass two",
436 oldfileline
= lineno
;
438 strcpy(currentfile
,value
);
439 fp
= fopen(value
,"r");
441 lineno
= oldfileline
;
443 strcpy(currentfile
,fname
);
445 * We don't report this error in the PANIC
446 * class, even though we might expect to have
447 * already picked it up during pass one,
448 * because of the tiny chance that some other
449 * process may have removed the include file
450 * between the passes.
452 report_error (ERR_FATAL
,
453 "unable to open include file `%s'\n",
457 case 5: /* [GLOBAL symbol] */
459 case 6: /* [COMMON symbol size] */
461 case 7: /* [ABSOLUTE addr] */
462 current_seg
= NO_SEG
;
463 abs_offset
= readnum(value
, &rn_error
);
465 report_error (ERR_PANIC
, "invalid ABSOLUTE address "
469 if (!ofmt
->directive (buffer
+1, value
, 2))
470 report_error (ERR_PANIC
, "invalid directive on pass two");
474 long offs
= get_curr_ofs
;
475 parse_line (current_seg
, offs
, lookup_label
, 2,
476 buffer
, &output_ins
, ofmt
, report_error
);
477 if (lineno
== forwline
) {
478 int *p
= saa_rstruct (forwrefs
);
483 output_ins
.forw_ref
= TRUE
;
485 output_ins
.forw_ref
= FALSE
;
487 if (output_ins
.label
)
488 define_label_stub (output_ins
.label
, report_error
);
489 if (output_ins
.opcode
== I_EQU
) {
491 * Special `..' EQUs get processed here.
493 if (output_ins
.label
[0] == '.' &&
494 output_ins
.label
[1] == '.') {
495 if (output_ins
.operands
== 1 &&
496 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
497 define_label (output_ins
.label
,
498 output_ins
.oprs
[0].segment
,
499 output_ins
.oprs
[0].offset
,
501 } else if (output_ins
.operands
== 2 &&
502 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
503 (output_ins
.oprs
[0].type
& COLON
) &&
504 output_ins
.oprs
[0].segment
== NO_SEG
&&
505 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
506 output_ins
.oprs
[1].segment
== NO_SEG
) {
507 define_label (output_ins
.label
,
508 output_ins
.oprs
[0].offset
| SEG_ABS
,
509 output_ins
.oprs
[1].offset
,
512 report_error(ERR_NONFATAL
, "bad syntax for EQU");
515 offs
+= assemble (current_seg
, offs
, sb
,
516 &output_ins
, ofmt
, report_error
);
517 cleanup_insn (&output_ins
);
523 static int getkw (char *buf
, char **value
) {
529 while (*p
&& *p
!= ']') p
++;
533 while (*p
&& *p
!= ';') {
541 while (*buf
&& *buf
!=' ' && *buf
!=']' && *buf
!='\t')
549 while (*buf
!=']') buf
++;
554 if (!strcmp(p
, "segment") || !strcmp(p
, "section"))
556 if (!strcmp(p
, "extern"))
558 if (!strcmp(p
, "bits"))
560 if (!strcmp(p
, "inc") || !strcmp(p
, "include"))
562 if (!strcmp(p
, "global"))
564 if (!strcmp(p
, "common"))
566 if (!strcmp(p
, "absolute"))
571 static void report_error (int severity
, char *fmt
, ...) {
574 if (severity
& ERR_NOFILE
)
575 fputs ("nasm: ", stderr
);
577 fprintf (stderr
, "%s:%d: ", currentfile
, lineno
);
579 if ( (severity
& ERR_MASK
) == ERR_WARNING
)
580 fputs ("warning: ", stderr
);
581 else if ( (severity
& ERR_MASK
) == ERR_PANIC
)
582 fputs ("panic: ", stderr
);
585 vfprintf (stderr
, fmt
, ap
);
586 fputc ('\n', stderr
);
588 if (severity
& ERR_USAGE
)
591 switch (severity
& ERR_MASK
) {
593 /* no further action, by definition */
596 terminate_after_phase
= TRUE
;
603 exit(1); /* instantly die */
604 break; /* placate silly compilers */
606 abort(); /* panic and dump core */
611 static void usage(void) {
612 fputs("type `nasm -h' for help\n", stderr
);
615 static void register_output_formats(void) {
616 /* Flat-form binary format */
618 extern struct ofmt of_bin
;
620 /* Unix formats: a.out, COFF, ELF */
622 extern struct ofmt of_aout
;
625 extern struct ofmt of_coff
;
628 extern struct ofmt of_elf
;
630 /* Linux strange format: as86 */
632 extern struct ofmt of_as86
;
634 /* DOS formats: OBJ, Win32 */
636 extern struct ofmt of_obj
;
639 extern struct ofmt of_win32
;
642 extern struct ofmt of_rdf
;
644 #ifdef OF_DBG /* debug format must be included specifically */
645 extern struct ofmt of_dbg
;
649 ofmt_register (&of_bin
);
652 ofmt_register (&of_aout
);
655 ofmt_register (&of_coff
);
658 ofmt_register (&of_elf
);
661 ofmt_register (&of_as86
);
664 ofmt_register (&of_obj
);
667 ofmt_register (&of_win32
);
670 ofmt_register (&of_rdf
);
673 ofmt_register (&of_dbg
);
676 * set the default format