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
;
43 #define OFFSET_DELTA 256
46 * get/set current offset...
48 #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
49 raa_read(offsets,current_seg))
50 #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
51 (void)(offsets=raa_write(offsets,current_seg,(x))))
53 static int want_usage
;
54 static int terminate_after_phase
;
56 int main(int argc
, char **argv
) {
57 want_usage
= terminate_after_phase
= FALSE
;
59 nasm_set_malloc_error (report_error
);
64 register_output_formats();
66 parse_cmdline(argc
, argv
);
68 if (terminate_after_phase
) {
75 ofmt
->filename (inname
, realout
, report_error
);
76 strcpy(outname
, realout
);
79 ofile
= fopen(outname
, "wb");
81 report_error (ERR_FATAL
| ERR_NOFILE
,
82 "unable to open output file `%s'", outname
);
84 ofmt
->init (ofile
, report_error
, define_label
);
85 assemble_file (inname
);
86 if (!terminate_after_phase
) {
91 if (terminate_after_phase
)
100 static void parse_cmdline(int argc
, char **argv
) {
103 *inname
= *outname
= '\0';
108 case 'o': /* these parameters take values */
110 if (p
[2]) /* the parameter's in the option */
113 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
114 "option `-%c' requires an argument",
118 --argc
, param
= *++argv
;
119 if (p
[1]=='o') { /* output file */
120 strcpy (outname
, param
);
121 } else if (p
[1]=='f') { /* output format */
122 ofmt
= ofmt_find(param
);
124 report_error (ERR_FATAL
| ERR_NOFILE
| ERR_USAGE
,
125 "unrecognised output format `%s'",
132 "usage: nasm [-o outfile] [-f format] filename\n");
134 " or nasm -r for version info\n\n");
136 "valid output formats for -f are"
137 " (`*' denotes default):\n");
139 exit (0); /* never need usage message here */
142 fprintf(stderr
, "NASM version %s\n", NASM_VER
);
143 exit (0); /* never need usage message here */
146 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
147 "unrecognised option `-%c'",
153 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
154 "more than one input file specified");
160 report_error (ERR_NONFATAL
| ERR_NOFILE
| ERR_USAGE
,
161 "no input file specified");
164 /* used by error function to report location */
165 static char currentfile
[FILENAME_MAX
];
167 static void assemble_file (char *fname
) {
168 FILE *fp
= fopen (fname
, "r");
169 FILE *oldfile
= NULL
; /* jrh - used when processing include files */
171 char *value
, *p
, buffer
[1024+2]; /* maximum line length defined here */
173 int i
, seg
, rn_error
;
175 if (!fp
) { /* couldn't open file */
176 report_error (ERR_FATAL
| ERR_NOFILE
,
177 "unable to open input file `%s'", fname
);
182 strcpy(currentfile
,fname
);
186 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
189 if (! fgets(buffer
, sizeof(buffer
), fp
)) { /* EOF on current file */
193 lineno
= oldfileline
;
194 strcpy(currentfile
,fname
);
202 if (buffer
[strlen(buffer
)-1] == '\n') {
203 buffer
[strlen(buffer
)-1] = '\0';
206 * We have a line that's too long. Throw an error, read
207 * to EOL, and ignore the line for assembly purposes.
209 report_error (ERR_NONFATAL
, "line is longer than %d characters",
211 while (fgets(buffer
, sizeof(buffer
), fp
) &&
212 buffer
[strlen(buffer
)-1] != '\n');
213 continue; /* read another line */
216 /* here we parse our directives; this is not handled by the 'real'
219 if ( (i
= getkw (buffer
, &value
)) ) {
221 case 1: /* [SEGMENT n] */
222 seg
= ofmt
->section (value
, pass
, &sb
);
224 report_error (ERR_NONFATAL
,
225 "segment name `%s' not recognised",
231 case 2: /* [EXTERN label] */
233 value
++; /* skip initial $ if present */
234 declare_as_global (value
, report_error
);
235 define_label (value
, seg_alloc(), 0L, ofmt
, report_error
);
237 case 3: /* [BITS bits] */
238 switch (atoi(value
)) {
244 report_error(ERR_NONFATAL
,
245 "`%s' is not a valid argument to [BITS]",
250 case 4: /* [INC file] */
252 oldfileline
= lineno
;
254 strcpy(currentfile
,value
);
255 fp
= fopen(value
,"r");
257 lineno
= oldfileline
;
259 strcpy(currentfile
,fname
);
260 report_error (ERR_FATAL
,
261 "unable to open include file `%s'\n",
265 case 5: /* [GLOBAL symbol] */
267 value
++; /* skip initial $ if present */
268 declare_as_global (value
, report_error
);
270 case 6: /* [COMMON symbol size] */
272 while (*p
&& !isspace(*p
))
277 while (*p
&& isspace(*p
))
279 size
= readnum (p
, &rn_error
);
281 report_error (ERR_NONFATAL
, "invalid size specified"
282 " in COMMON declaration");
284 define_common (value
, seg_alloc(), size
,
287 report_error (ERR_NONFATAL
, "no size specified in"
288 " COMMON declaration");
290 case 7: /* [ABSOLUTE address] */
291 current_seg
= NO_SEG
;
292 abs_offset
= readnum(value
, &rn_error
);
294 report_error (ERR_NONFATAL
, "invalid address specified"
295 " for ABSOLUTE directive");
296 abs_offset
= 0x100;/* don't go near zero in case of / */
300 if (!ofmt
->directive (buffer
+1, value
, 1))
301 report_error (ERR_NONFATAL
, "unrecognised directive [%s]",
306 long offs
= get_curr_ofs
;
307 parse_line (current_seg
, offs
, lookup_label
,
308 1, buffer
, &output_ins
, ofmt
, report_error
);
309 if (output_ins
.opcode
== I_EQU
) {
311 * Special `..' EQUs get processed in pass two.
313 if (!output_ins
.label
)
314 report_error (ERR_NONFATAL
,
315 "EQU not preceded by label");
316 else if (output_ins
.label
[0] != '.' ||
317 output_ins
.label
[1] != '.') {
318 if (output_ins
.operands
== 1 &&
319 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
320 define_label (output_ins
.label
,
321 output_ins
.oprs
[0].segment
,
322 output_ins
.oprs
[0].offset
,
324 } else if (output_ins
.operands
== 2 &&
325 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
326 (output_ins
.oprs
[0].type
& COLON
) &&
327 output_ins
.oprs
[0].segment
== NO_SEG
&&
328 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
329 output_ins
.oprs
[1].segment
== NO_SEG
) {
330 define_label (output_ins
.label
,
331 output_ins
.oprs
[0].offset
| SEG_ABS
,
332 output_ins
.oprs
[1].offset
,
335 report_error(ERR_NONFATAL
, "bad syntax for EQU");
338 if (output_ins
.label
)
339 define_label (output_ins
.label
,
342 offs
+= insn_size (current_seg
, offs
, sb
,
343 &output_ins
, report_error
);
346 cleanup_insn (&output_ins
);
350 if (terminate_after_phase
) {
361 current_seg
= ofmt
->section(NULL
, pass
, &sb
);
363 offsets
= raa_init();
366 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
370 lineno
= oldfileline
;
371 strcpy(currentfile
,fname
);
378 if (buffer
[strlen(buffer
)-1] == '\n')
379 buffer
[strlen(buffer
)-1] = '\0';
381 report_error (ERR_PANIC
,
382 "too-long line got through from pass one");
384 /* here we parse our directives; this is not handled by
385 * the 'real' parser. */
387 if ( (i
= getkw (buffer
, &value
)) ) {
389 case 1: /* [SEGMENT n] */
390 seg
= ofmt
->section (value
, pass
, &sb
);
392 report_error (ERR_PANIC
,
393 "invalid segment name on pass two");
397 case 2: /* [EXTERN label] */
399 case 3: /* [BITS bits] */
400 switch (atoi(value
)) {
406 report_error(ERR_PANIC
,
407 "invalid [BITS] value on pass two",
414 oldfileline
= lineno
;
416 strcpy(currentfile
,value
);
417 fp
= fopen(value
,"r");
419 lineno
= oldfileline
;
421 strcpy(currentfile
,fname
);
423 * We don't report this error in the PANIC
424 * class, even though we might expect to have
425 * already picked it up during pass one,
426 * because of the tiny chance that some other
427 * process may have removed the include file
428 * between the passes.
430 report_error (ERR_FATAL
,
431 "unable to open include file `%s'\n",
435 case 5: /* [GLOBAL symbol] */
437 case 6: /* [COMMON symbol size] */
439 case 7: /* [ABSOLUTE addr] */
440 current_seg
= NO_SEG
;
441 abs_offset
= readnum(value
, &rn_error
);
443 report_error (ERR_PANIC
, "invalid ABSOLUTE address "
447 if (!ofmt
->directive (buffer
+1, value
, 2))
448 report_error (ERR_PANIC
, "invalid directive on pass two");
452 long offs
= get_curr_ofs
;
453 parse_line (current_seg
, offs
, lookup_label
, 2,
454 buffer
, &output_ins
, ofmt
, report_error
);
456 if (output_ins
.label
)
457 define_label_stub (output_ins
.label
, report_error
);
458 if (output_ins
.opcode
== I_EQU
) {
460 * Special `..' EQUs get processed here.
462 if (output_ins
.label
[0] == '.' &&
463 output_ins
.label
[1] == '.') {
464 if (output_ins
.operands
== 1 &&
465 (output_ins
.oprs
[0].type
& IMMEDIATE
)) {
466 define_label (output_ins
.label
,
467 output_ins
.oprs
[0].segment
,
468 output_ins
.oprs
[0].offset
,
470 } else if (output_ins
.operands
== 2 &&
471 (output_ins
.oprs
[0].type
& IMMEDIATE
) &&
472 (output_ins
.oprs
[0].type
& COLON
) &&
473 output_ins
.oprs
[0].segment
== NO_SEG
&&
474 (output_ins
.oprs
[1].type
& IMMEDIATE
) &&
475 output_ins
.oprs
[1].segment
== NO_SEG
) {
476 define_label (output_ins
.label
,
477 output_ins
.oprs
[0].offset
| SEG_ABS
,
478 output_ins
.oprs
[1].offset
,
481 report_error(ERR_NONFATAL
, "bad syntax for EQU");
484 offs
+= assemble (current_seg
, offs
, sb
,
485 &output_ins
, ofmt
, report_error
);
486 cleanup_insn (&output_ins
);
492 static int getkw (char *buf
, char **value
) {
498 while (*p
&& *p
!= ']') p
++;
502 while (*p
&& *p
!= ';') {
510 while (*buf
&& *buf
!=' ' && *buf
!=']' && *buf
!='\t')
518 while (*buf
!=']') buf
++;
523 if (!strcmp(p
, "segment") || !strcmp(p
, "section"))
525 if (!strcmp(p
, "extern"))
527 if (!strcmp(p
, "bits"))
529 if (!strcmp(p
, "inc") || !strcmp(p
, "include"))
531 if (!strcmp(p
, "global"))
533 if (!strcmp(p
, "common"))
535 if (!strcmp(p
, "absolute"))
540 static void report_error (int severity
, char *fmt
, ...) {
543 if (severity
& ERR_NOFILE
)
544 fputs ("nasm: ", stderr
);
546 fprintf (stderr
, "%s:%d: ", currentfile
, lineno
);
548 if ( (severity
& ERR_MASK
) == ERR_WARNING
)
549 fputs ("warning: ", stderr
);
550 else if ( (severity
& ERR_MASK
) == ERR_PANIC
)
551 fputs ("panic: ", stderr
);
554 vfprintf (stderr
, fmt
, ap
);
555 fputc ('\n', stderr
);
557 if (severity
& ERR_USAGE
)
560 switch (severity
& ERR_MASK
) {
562 /* no further action, by definition */
565 terminate_after_phase
= TRUE
;
572 exit(1); /* instantly die */
573 break; /* placate silly compilers */
575 abort(); /* panic and dump core */
580 static void usage(void) {
581 fputs("type `nasm -h' for help\n", stderr
);
584 static void register_output_formats(void) {
585 /* Flat-form binary format */
587 extern struct ofmt of_bin
;
589 /* Unix formats: a.out, COFF, ELF */
591 extern struct ofmt of_aout
;
594 extern struct ofmt of_coff
;
597 extern struct ofmt of_elf
;
599 /* Linux strange format: as86 */
601 extern struct ofmt of_as86
;
603 /* DOS formats: OBJ, Win32 */
605 extern struct ofmt of_obj
;
608 extern struct ofmt of_win32
;
611 extern struct ofmt of_rdf
;
613 #ifdef OF_DBG /* debug format must be included specifically */
614 extern struct ofmt of_dbg
;
618 ofmt_register (&of_bin
);
621 ofmt_register (&of_aout
);
624 ofmt_register (&of_coff
);
627 ofmt_register (&of_elf
);
630 ofmt_register (&of_as86
);
633 ofmt_register (&of_obj
);
636 ofmt_register (&of_win32
);
639 ofmt_register (&of_rdf
);
642 ofmt_register (&of_dbg
);
645 * set the default format