]> git.saurik.com Git - apple/boot.git/blame - i386/nasm/nasm.c
boot-111.tar.gz
[apple/boot.git] / i386 / nasm / nasm.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
f083c6c3
A
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14c7c974
A
14 *
15 * The Original Code and all software distributed under the License are
f083c6c3 16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
f083c6c3
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
14c7c974
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* The Netwide Assembler main program module
26 *
27 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
28 * Julian Hall. All rights reserved. The software is
29 * redistributable under the licence given in the file "Licence"
30 * distributed in the NASM archive.
31 */
32
33#include <stdio.h>
34#include <stdarg.h>
35#include <stdlib.h>
36#include <string.h>
37#include <ctype.h>
38
39#include "nasm.h"
40#include "nasmlib.h"
41#include "preproc.h"
42#include "parser.h"
43#include "eval.h"
44#include "assemble.h"
45#include "labels.h"
46#include "outform.h"
47#include "listing.h"
48
49static void report_error (int, char *, ...);
50static void parse_cmdline (int, char **);
51static void assemble_file (char *);
52static int getkw (char *buf, char **value);
53static void register_output_formats(void);
54static void usage(void);
55
56static char *obuf;
57static char inname[FILENAME_MAX];
58static char outname[FILENAME_MAX];
59static char listname[FILENAME_MAX];
60static int lineno; /* for error reporting */
61static int lineinc; /* set by [LINE] or [ONELINE] */
62static int globallineno; /* for forward-reference tracking */
63static int pass;
64static struct ofmt *ofmt = NULL;
65
66static FILE *ofile = NULL;
67static int sb = 16; /* by default */
68
69static int use_stdout = FALSE; /* by default, errors to stderr */
70
71static long current_seg, abs_seg;
72static struct RAA *offsets;
73static long abs_offset;
74
75static struct SAA *forwrefs; /* keep track of forward references */
76static int forwline;
77
78static Preproc *preproc;
79static int preprocess_only;
80
81/* used by error function to report location */
82static char currentfile[FILENAME_MAX];
83
84/*
85 * Which of the suppressible warnings are suppressed. Entry zero
86 * doesn't do anything. Initial defaults are given here.
87 */
88static char suppressed[1+ERR_WARN_MAX] = {
89 0, FALSE, TRUE, FALSE
90};
91
92/*
93 * The option names for the suppressible warnings. As before, entry
94 * zero does nothing.
95 */
96static char *suppressed_names[1+ERR_WARN_MAX] = {
97 NULL, "macro-params", "orphan-labels", "number-overflow"
98};
99
100/*
101 * The explanations for the suppressible warnings. As before, entry
102 * zero does nothing.
103 */
104static char *suppressed_what[1+ERR_WARN_MAX] = {
105 NULL, "macro calls with wrong no. of params",
106 "labels alone on lines without trailing `:'",
107 "numeric constants greater than 0xFFFFFFFF"
108};
109
110/*
111 * This is a null preprocessor which just copies lines from input
112 * to output. It's used when someone explicitly requests that NASM
113 * not preprocess their source file.
114 */
115
116static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
117static char *no_pp_getline (void);
118static void no_pp_cleanup (void);
119static Preproc no_pp = {
120 no_pp_reset,
121 no_pp_getline,
122 no_pp_cleanup
123};
124
125/*
126 * get/set current offset...
127 */
128#define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
129 raa_read(offsets,current_seg))
130#define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
131 (void)(offsets=raa_write(offsets,current_seg,(x))))
132
133static int want_usage;
134static int terminate_after_phase;
135
136int main(int argc, char **argv) {
137 want_usage = terminate_after_phase = FALSE;
138
139 nasm_set_malloc_error (report_error);
140 offsets = raa_init();
141 forwrefs = saa_init ((long)sizeof(int));
142
143 preproc = &nasmpp;
144 preprocess_only = FALSE;
145
146 seg_init();
147
148 register_output_formats();
149
150 parse_cmdline(argc, argv);
151
152 if (terminate_after_phase) {
153 if (want_usage)
154 usage();
155 return 1;
156 }
157
158 if (ofmt->stdmac)
159 pp_extra_stdmac (ofmt->stdmac);
160 eval_global_info (ofmt, lookup_label);
161
162 if (preprocess_only) {
163 char *line;
164
165 if (*outname) {
166 ofile = fopen(outname, "w");
167 if (!ofile)
168 report_error (ERR_FATAL | ERR_NOFILE,
169 "unable to open output file `%s'", outname);
170 } else
171 ofile = NULL;
172
173 eval_info ("%", 0L, 0L); /* disallow labels, $ or $$ in exprs */
174
175 preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
176 strcpy(currentfile,inname);
177 lineno = 0;
178 lineinc = 1;
179 while ( (line = preproc->getline()) ) {
180 int ln, li;
181 char buf[FILENAME_MAX];
182
183 lineno += lineinc;
184 /*
185 * We must still check for %line directives, so that we
186 * can report errors accurately.
187 */
188 if (!strncmp(line, "%line", 5) &&
189 sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
190 lineno = ln - li;
191 lineinc = li;
192 strncpy (currentfile, buf, FILENAME_MAX-1);
193 currentfile[FILENAME_MAX-1] = '\0';
194 }
195 if (ofile) {
196 fputs(line, ofile);
197 fputc('\n', ofile);
198 } else
199 puts(line);
200 nasm_free (line);
201 }
202 preproc->cleanup();
203 if (ofile)
204 fclose(ofile);
205 if (ofile && terminate_after_phase)
206 remove(outname);
207 } else {
208 /*
209 * We must call ofmt->filename _anyway_, even if the user
210 * has specified their own output file, because some
211 * formats (eg OBJ and COFF) use ofmt->filename to find out
212 * the name of the input file and then put that inside the
213 * file.
214 */
215 ofmt->filename (inname, outname, report_error);
216
217 ofile = fopen(outname, "wb");
218 if (!ofile) {
219 report_error (ERR_FATAL | ERR_NOFILE,
220 "unable to open output file `%s'", outname);
221 }
222 /*
223 * We must call init_labels() before ofmt->init() since
224 * some object formats will want to define labels in their
225 * init routines. (eg OS/2 defines the FLAT group)
226 */
227 init_labels ();
228 ofmt->init (ofile, report_error, define_label, evaluate);
229 assemble_file (inname);
230 if (!terminate_after_phase) {
231 ofmt->cleanup ();
232 cleanup_labels ();
233 }
234 /*
235 * We had an fclose on the output file here, but we
236 * actually do that in all the object file drivers as well,
237 * so we're leaving out the one here.
238 * fclose (ofile);
239 */
240 if (terminate_after_phase) {
241 remove(outname);
242 if (listname[0])
243 remove(listname);
244 }
245 }
246
247 if (want_usage)
248 usage();
249 raa_free (offsets);
250 saa_free (forwrefs);
251
252 if (terminate_after_phase)
253 return 1;
254 else
255 return 0;
256}
257
258static int process_arg (char *p, char *q) {
259 char *param;
260 int i;
261 int advance = 0;
262
263 if (!p || !p[0])
264 return 0;
265
266 if (p[0]=='-') {
267 switch (p[1]) {
268 case 's':
269 use_stdout = TRUE;
270 break;
271 case 'o': /* these parameters take values */
272 case 'f':
273 case 'p':
274 case 'd':
275 case 'i':
276 case 'l':
277 if (p[2]) /* the parameter's in the option */
278 param = p+2;
279 else if (!q) {
280 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
281 "option `-%c' requires an argument",
282 p[1]);
283 break;
284 } else
285 advance = 1, param = q;
286 if (p[1]=='o') { /* output file */
287 strcpy (outname, param);
288 } else if (p[1]=='f') { /* output format */
289 ofmt = ofmt_find(param);
290 if (!ofmt) {
291 report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
292 "unrecognised output format `%s'",
293 param);
294 }
295 } else if (p[1]=='p') { /* pre-include */
296 pp_pre_include (param);
297 } else if (p[1]=='d') { /* pre-define */
298 pp_pre_define (param);
299 } else if (p[1]=='i') { /* include search path */
300 pp_include_path (param);
301 } else if (p[1]=='l') { /* listing file */
302 strcpy (listname, param);
303 }
304 break;
305 case 'h':
306 fprintf(use_stdout ? stdout : stderr,
307 "usage: nasm [-o outfile] [-f format] [-l listfile]"
308 " [options...] filename\n");
309 fprintf(use_stdout ? stdout : stderr,
310 " or nasm -r for version info\n\n");
311 fprintf(use_stdout ? stdout : stderr,
312 " -e means preprocess only; "
313 "-a means don't preprocess\n");
314 fprintf(use_stdout ? stdout : stderr,
315 " -s means send errors to stdout not stderr\n");
316 fprintf(use_stdout ? stdout : stderr,
317 " -i<path> adds a pathname to the include file"
318 " path\n -p<file> pre-includes a file;"
319 " -d<macro>[=<value] pre-defines a macro\n");
320 fprintf(use_stdout ? stdout : stderr,
321 " -w+foo enables warnings about foo; "
322 "-w-foo disables them\n where foo can be:\n");
323 for (i=1; i<=ERR_WARN_MAX; i++)
324 fprintf(use_stdout ? stdout : stderr,
325 " %-16s%s (default %s)\n",
326 suppressed_names[i], suppressed_what[i],
327 suppressed[i] ? "off" : "on");
328 fprintf(use_stdout ? stdout : stderr,
329 "\nvalid output formats for -f are"
330 " (`*' denotes default):\n");
331 ofmt_list(ofmt, use_stdout ? stdout : stderr);
332 exit (0); /* never need usage message here */
333 break;
334 case 'r':
335 fprintf(use_stdout ? stdout : stderr,
336 "NASM version %s\n", NASM_VER);
337 exit (0); /* never need usage message here */
338 break;
339 case 'e': /* preprocess only */
340 preprocess_only = TRUE;
341 break;
342 case 'a': /* assemble only - don't preprocess */
343 preproc = &no_pp;
344 break;
345 case 'w':
346 if (p[2] != '+' && p[2] != '-') {
347 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
348 "invalid option to `-w'");
349 } else {
350 for (i=1; i<=ERR_WARN_MAX; i++)
351 if (!nasm_stricmp(p+3, suppressed_names[i]))
352 break;
353 if (i <= ERR_WARN_MAX)
354 suppressed[i] = (p[2] == '-');
355 else
356 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
357 "invalid option to `-w'");
358 }
359 break;
360 default:
361 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
362 "unrecognised option `-%c'",
363 p[1]);
364 break;
365 }
366 } else {
367 if (*inname) {
368 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
369 "more than one input file specified");
370 } else
371 strcpy(inname, p);
372 }
373
374 return advance;
375}
376
377static void parse_cmdline(int argc, char **argv) {
378 char *envreal, *envcopy, *p, *q, *arg, *prevarg;
379 char separator = ' ';
380
381 *inname = *outname = *listname = '\0';
382
383 /*
384 * First, process the NASM environment variable.
385 */
386 envreal = getenv("NASM");
387 arg = NULL;
388 if (envreal) {
389 envcopy = nasm_strdup(envreal);
390 p = envcopy;
391 if (*p && *p != '-')
392 separator = *p++;
393 while (*p) {
394 q = p;
395 while (*p && *p != separator) p++;
396 while (*p == separator) *p++ = '\0';
397 prevarg = arg;
398 arg = q;
399 if (process_arg (prevarg, arg))
400 arg = NULL;
401 }
402 nasm_free (envcopy);
403 }
404 if (arg)
405 process_arg (arg, NULL);
406
407 /*
408 * Now process the actual command line.
409 */
410 while (--argc) {
411 int i;
412 argv++;
413 i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
414 argv += i, argc -= i;
415 }
416
417 if (!*inname)
418 report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
419 "no input file specified");
420}
421
422static void assemble_file (char *fname) {
423 char *value, *p, *q, *special, *line;
424 insn output_ins;
425 int i, rn_error, validid;
426 long seg, offs;
427 struct tokenval tokval;
428 expr *e;
429
430 /* pass one */
431 pass = 1;
432 current_seg = ofmt->section(NULL, pass, &sb);
433 preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
434 strcpy(currentfile,fname);
435 lineno = 0;
436 lineinc = 1;
437 globallineno = 0;
438 offs = get_curr_ofs;
439 eval_info (NULL, current_seg, offs); /* set $ */
440 while ( (line = preproc->getline()) ) {
441 lineno += lineinc;
442 globallineno++;
443
444 if (line[0] == '%') {
445 int ln, li;
446 char buf[FILENAME_MAX];
447
448 /*
449 * This will be a line number directive. They come
450 * straight from the preprocessor, so we'll subject
451 * them to only minimal error checking.
452 */
453 if (strncmp(line, "%line", 5)) {
454 if (preproc == &no_pp)
455 report_error (ERR_WARNING, "unknown `%%' directive in "
456 " preprocessed source");
457 } else if (sscanf(line, "%%line %d+%d %s", &ln, &li, buf) != 3) {
458 report_error (ERR_WARNING, "bogus line number directive in"
459 " preprocessed source");
460 } else {
461 lineno = ln - li;
462 lineinc = li;
463 strncpy (currentfile, buf, FILENAME_MAX-1);
464 currentfile[FILENAME_MAX-1] = '\0';
465 }
466 continue;
467 }
468
469 /* here we parse our directives; this is not handled by the 'real'
470 * parser. */
471 if ( (i = getkw (line, &value)) ) {
472 switch (i) {
473 case 1: /* [SEGMENT n] */
474 seg = ofmt->section (value, pass, &sb);
475 if (seg == NO_SEG) {
476 report_error (ERR_NONFATAL,
477 "segment name `%s' not recognised",
478 value);
479 } else {
480 current_seg = seg;
481 }
482 break;
483 case 2: /* [EXTERN label:special] */
484 if (*value == '$')
485 value++; /* skip initial $ if present */
486 q = value;
487 validid = TRUE;
488 if (!isidstart(*q))
489 validid = FALSE;
490 while (*q && *q != ':') {
491 if (!isidchar(*q))
492 validid = FALSE;
493 q++;
494 }
495 if (!validid) {
496 report_error (ERR_NONFATAL,
497 "identifier expected after EXTERN");
498 break;
499 }
500 if (*q == ':') {
501 *q++ = '\0';
502 special = q;
503 } else
504 special = NULL;
505 if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
506 declare_as_global (value, special, report_error);
507 define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
508 ofmt, report_error);
509 }
510 break;
511 case 3: /* [BITS bits] */
512 switch (atoi(value)) {
513 case 16:
514 case 32:
515 sb = atoi(value);
516 break;
517 default:
518 report_error(ERR_NONFATAL,
519 "`%s' is not a valid argument to [BITS]",
520 value);
521 break;
522 }
523 break;
524 case 4: /* [GLOBAL symbol:special] */
525 if (*value == '$')
526 value++; /* skip initial $ if present */
527 q = value;
528 validid = TRUE;
529 if (!isidstart(*q))
530 validid = FALSE;
531 while (*q && *q != ':') {
532 if (!isidchar(*q))
533 validid = FALSE;
534 q++;
535 }
536 if (!validid) {
537 report_error (ERR_NONFATAL,
538 "identifier expected after GLOBAL");
539 break;
540 }
541 if (*q == ':') {
542 *q++ = '\0';
543 special = q;
544 } else
545 special = NULL;
546 declare_as_global (value, special, report_error);
547 break;
548 case 5: /* [COMMON symbol size:special] */
549 p = value;
550 validid = TRUE;
551 if (!isidstart(*p))
552 validid = FALSE;
553 while (*p && !isspace(*p)) {
554 if (!isidchar(*p))
555 validid = FALSE;
556 p++;
557 }
558 if (!validid) {
559 report_error (ERR_NONFATAL,
560 "identifier expected after COMMON");
561 break;
562 }
563 if (*p) {
564 long size;
565
566 while (*p && isspace(*p))
567 *p++ = '\0';
568 q = p;
569 while (*q && *q != ':')
570 q++;
571 if (*q == ':') {
572 *q++ = '\0';
573 special = q;
574 } else
575 special = NULL;
576 size = readnum (p, &rn_error);
577 if (rn_error)
578 report_error (ERR_NONFATAL, "invalid size specified"
579 " in COMMON declaration");
580 else
581 define_common (value, seg_alloc(), size,
582 special, ofmt, report_error);
583 } else
584 report_error (ERR_NONFATAL, "no size specified in"
585 " COMMON declaration");
586 break;
587 case 6: /* [ABSOLUTE address] */
588 current_seg = NO_SEG;
589 stdscan_reset();
590 stdscan_bufptr = value;
591 tokval.t_type = TOKEN_INVALID;
592 e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
593 NULL);
594 if (e) {
595 if (!is_reloc(e))
596 report_error (ERR_NONFATAL, "cannot use non-"
597 "relocatable expression as ABSOLUTE"
598 " address");
599 else {
600 abs_seg = reloc_seg(e);
601 abs_offset = reloc_value(e);
602 }
603 } else
604 abs_offset = 0x100;/* don't go near zero in case of / */
605 break;
606 default:
607 if (!ofmt->directive (line+1, value, 1))
608 report_error (ERR_NONFATAL, "unrecognised directive [%s]",
609 line+1);
610 break;
611 }
612 } else {
613 parse_line (1, line, &output_ins,
614 report_error, evaluate, eval_info);
615 if (output_ins.forw_ref)
616 *(int *)saa_wstruct(forwrefs) = globallineno;
617
618 /*
619 * Hack to prevent phase error in the code
620 * rol ax,x
621 * x equ 1
622 *
623 * We rule that the presence of a forward reference
624 * cancels out the UNITY property of the number 1. This
625 * isn't _strictly_ necessary in pass one, since the
626 * problem occurs in pass two, but for the sake of
627 * having the passes as near to identical as we can
628 * manage, we do it like this.
629 */
630 if (output_ins.forw_ref) {
631 int i;
632 for (i=0; i<output_ins.operands; i++)
633 output_ins.oprs[i].type &= ~ONENESS;
634 }
635
636 if (output_ins.opcode == I_EQU) {
637 /*
638 * Special `..' EQUs get processed in pass two,
639 * except `..@' macro-processor EQUs which are done
640 * in the normal place.
641 */
642 if (!output_ins.label)
643 report_error (ERR_NONFATAL,
644 "EQU not preceded by label");
645 else if (output_ins.label[0] != '.' ||
646 output_ins.label[1] != '.' ||
647 output_ins.label[2] == '@') {
648 if (output_ins.operands == 1 &&
649 (output_ins.oprs[0].type & IMMEDIATE) &&
650 output_ins.oprs[0].wrt == NO_SEG) {
651 define_label (output_ins.label,
652 output_ins.oprs[0].segment,
653 output_ins.oprs[0].offset,
654 NULL, FALSE, FALSE, ofmt, report_error);
655 } else if (output_ins.operands == 2 &&
656 (output_ins.oprs[0].type & IMMEDIATE) &&
657 (output_ins.oprs[0].type & COLON) &&
658 output_ins.oprs[0].segment == NO_SEG &&
659 output_ins.oprs[0].wrt == NO_SEG &&
660 (output_ins.oprs[1].type & IMMEDIATE) &&
661 output_ins.oprs[1].segment == NO_SEG &&
662 output_ins.oprs[1].wrt == NO_SEG) {
663 define_label (output_ins.label,
664 output_ins.oprs[0].offset | SEG_ABS,
665 output_ins.oprs[1].offset,
666 NULL, FALSE, FALSE, ofmt, report_error);
667 } else
668 report_error(ERR_NONFATAL, "bad syntax for EQU");
669 }
670 } else {
671 if (output_ins.label)
672 define_label (output_ins.label,
673 current_seg==NO_SEG ? abs_seg : current_seg,
674 offs, NULL, TRUE, FALSE, ofmt, report_error);
675 offs += insn_size (current_seg, offs, sb,
676 &output_ins, report_error);
677 set_curr_ofs (offs);
678 }
679 cleanup_insn (&output_ins);
680 }
681 nasm_free (line);
682 offs = get_curr_ofs;
683 eval_info (NULL, current_seg, offs); /* set $ */
684 }
685 preproc->cleanup();
686
687 if (terminate_after_phase) {
688 fclose(ofile);
689 remove(outname);
690 if (want_usage)
691 usage();
692 exit (1);
693 }
694
695 /* pass two */
696 pass = 2;
697 saa_rewind (forwrefs);
698 if (*listname)
699 nasmlist.init(listname, report_error);
700 {
701 int *p = saa_rstruct (forwrefs);
702 if (p)
703 forwline = *p;
704 else
705 forwline = -1;
706 }
707 current_seg = ofmt->section(NULL, pass, &sb);
708 raa_free (offsets);
709 offsets = raa_init();
710 preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
711 strcpy(currentfile,fname);
712 lineno = 0;
713 lineinc = 1;
714 globallineno = 0;
715 offs = get_curr_ofs;
716 eval_info (NULL, current_seg, offs); /* set $ */
717 while ( (line = preproc->getline()) ) {
718 lineno += lineinc;
719 globallineno++;
720
721 if (line[0] == '%') {
722 int ln, li;
723 char buf[FILENAME_MAX];
724
725 /*
726 * This will be a line number directive. They come
727 * straight from the preprocessor, so we'll subject
728 * them to only minimal error checking.
729 */
730 if (!strncmp(line, "%line", 5) &&
731 sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
732 lineno = ln - li;
733 lineinc = li;
734 strncpy (currentfile, buf, FILENAME_MAX-1);
735 currentfile[FILENAME_MAX-1] = '\0';
736 }
737 continue;
738 }
739
740 /* here we parse our directives; this is not handled by
741 * the 'real' parser. */
742 if ( (i = getkw (line, &value)) ) {
743 switch (i) {
744 case 1: /* [SEGMENT n] */
745 seg = ofmt->section (value, pass, &sb);
746 if (seg == NO_SEG) {
747 report_error (ERR_PANIC,
748 "invalid segment name on pass two");
749 } else
750 current_seg = seg;
751 break;
752 case 2: /* [EXTERN label] */
753 q = value;
754 while (*q && *q != ':')
755 q++;
756 if (*q == ':') {
757 *q++ = '\0';
758 ofmt->symdef(value, 0L, 0L, 3, q);
759 }
760 break;
761 case 3: /* [BITS bits] */
762 switch (atoi(value)) {
763 case 16:
764 case 32:
765 sb = atoi(value);
766 break;
767 default:
768 report_error(ERR_PANIC,
769 "invalid [BITS] value on pass two",
770 value);
771 break;
772 }
773 break;
774 case 4: /* [GLOBAL symbol] */
775 q = value;
776 while (*q && *q != ':')
777 q++;
778 if (*q == ':') {
779 *q++ = '\0';
780 ofmt->symdef(value, 0L, 0L, 3, q);
781 }
782 break;
783 case 5: /* [COMMON symbol size] */
784 q = value;
785 while (*q && *q != ':') {
786 if (isspace(*q))
787 *q = '\0';
788 q++;
789 }
790 if (*q == ':') {
791 *q++ = '\0';
792 ofmt->symdef(value, 0L, 0L, 3, q);
793 }
794 break;
795 case 6: /* [ABSOLUTE addr] */
796 current_seg = NO_SEG;
797 stdscan_reset();
798 stdscan_bufptr = value;
799 tokval.t_type = TOKEN_INVALID;
800 e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
801 NULL);
802 if (e) {
803 if (!is_reloc(e))
804 report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
805 " in pass two");
806 else {
807 abs_seg = reloc_seg(e);
808 abs_offset = reloc_value(e);
809 }
810 } else
811 report_error (ERR_PANIC, "invalid ABSOLUTE address "
812 "in pass two");
813 break;
814 default:
815 if (!ofmt->directive (line+1, value, 2))
816 report_error (ERR_PANIC, "invalid directive on pass two");
817 break;
818 }
819 } else {
820 parse_line (2, line, &output_ins,
821 report_error, evaluate, eval_info);
822 if (globallineno == forwline) {
823 int *p = saa_rstruct (forwrefs);
824 if (p)
825 forwline = *p;
826 else
827 forwline = -1;
828 output_ins.forw_ref = TRUE;
829 } else
830 output_ins.forw_ref = FALSE;
831
832 /*
833 * Hack to prevent phase error in the code
834 * rol ax,x
835 * x equ 1
836 */
837 if (output_ins.forw_ref) {
838 int i;
839 for (i=0; i<output_ins.operands; i++)
840 output_ins.oprs[i].type &= ~ONENESS;
841 }
842
843 obuf = line;
844 if (output_ins.label)
845 define_label_stub (output_ins.label, report_error);
846 if (output_ins.opcode == I_EQU) {
847 /*
848 * Special `..' EQUs get processed here, except
849 * `..@' macro processor EQUs which are done above.
850 */
851 if (output_ins.label[0] == '.' &&
852 output_ins.label[1] == '.' &&
853 output_ins.label[2] != '@') {
854 if (output_ins.operands == 1 &&
855 (output_ins.oprs[0].type & IMMEDIATE)) {
856 define_label (output_ins.label,
857 output_ins.oprs[0].segment,
858 output_ins.oprs[0].offset,
859 NULL, FALSE, FALSE, ofmt, report_error);
860 } else if (output_ins.operands == 2 &&
861 (output_ins.oprs[0].type & IMMEDIATE) &&
862 (output_ins.oprs[0].type & COLON) &&
863 output_ins.oprs[0].segment == NO_SEG &&
864 (output_ins.oprs[1].type & IMMEDIATE) &&
865 output_ins.oprs[1].segment == NO_SEG) {
866 define_label (output_ins.label,
867 output_ins.oprs[0].offset | SEG_ABS,
868 output_ins.oprs[1].offset,
869 NULL, FALSE, FALSE, ofmt, report_error);
870 } else
871 report_error(ERR_NONFATAL, "bad syntax for EQU");
872 }
873 }
874 offs += assemble (current_seg, offs, sb,
875 &output_ins, ofmt, report_error, &nasmlist);
876 cleanup_insn (&output_ins);
877 set_curr_ofs (offs);
878 }
879 nasm_free (line);
880
881 offs = get_curr_ofs;
882 eval_info (NULL, current_seg, offs); /* set $ */
883 }
884 preproc->cleanup();
885 nasmlist.cleanup();
886}
887
888static int getkw (char *buf, char **value) {
889 char *p, *q;
890
891 if (*buf!='[')
892 return 0;
893 p = buf;
894 while (*p && *p != ']') p++;
895 if (!*p)
896 return 0;
897 q = p++;
898 while (*p && *p != ';') {
899 if (!isspace(*p))
900 return 0;
901 p++;
902 }
903 q[1] = '\0';
904
905 p = buf+1;
906 while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
907 buf++;
908 if (*buf==']') {
909 *buf = '\0';
910 *value = buf;
911 } else {
912 *buf++ = '\0';
913 while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
914 *value = buf;
915 while (*buf!=']') buf++;
916 *buf++ = '\0';
917 }
918 for (q=p; *q; q++)
919 *q = tolower(*q);
920 if (!strcmp(p, "segment") || !strcmp(p, "section"))
921 return 1;
922 if (!strcmp(p, "extern"))
923 return 2;
924 if (!strcmp(p, "bits"))
925 return 3;
926 if (!strcmp(p, "global"))
927 return 4;
928 if (!strcmp(p, "common"))
929 return 5;
930 if (!strcmp(p, "absolute"))
931 return 6;
932 return -1;
933}
934
935static void report_error (int severity, char *fmt, ...) {
936 va_list ap;
937
938 /*
939 * See if it's a suppressed warning.
940 */
941 if ((severity & ERR_MASK) == ERR_WARNING &&
942 (severity & ERR_WARN_MASK) != 0 &&
943 suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
944 return; /* and bail out if so */
945
946 /*
947 * See if it's a pass-one only warning and we're not in pass one.
948 */
949 if ((severity & ERR_PASS1) && pass != 1)
950 return;
951
952 if (severity & ERR_NOFILE)
953 fputs ("nasm: ", use_stdout ? stdout : stderr);
954 else
955 fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
956 lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
957
958 if ( (severity & ERR_MASK) == ERR_WARNING)
959 fputs ("warning: ", use_stdout ? stdout : stderr);
960 else if ( (severity & ERR_MASK) == ERR_PANIC)
961 fputs ("panic: ", use_stdout ? stdout : stderr);
962
963 va_start (ap, fmt);
964 vfprintf (use_stdout ? stdout : stderr, fmt, ap);
965 fputc ('\n', use_stdout ? stdout : stderr);
966
967 if (severity & ERR_USAGE)
968 want_usage = TRUE;
969
970 switch (severity & ERR_MASK) {
971 case ERR_WARNING:
972 /* no further action, by definition */
973 break;
974 case ERR_NONFATAL:
975 terminate_after_phase = TRUE;
976 break;
977 case ERR_FATAL:
978 if (ofile) {
979 fclose(ofile);
980 remove(outname);
981 }
982 if (want_usage)
983 usage();
984 exit(1); /* instantly die */
985 break; /* placate silly compilers */
986 case ERR_PANIC:
987 abort(); /* halt, catch fire, and dump core */
988 break;
989 }
990}
991
992static void usage(void) {
993 fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr);
994}
995
996static void register_output_formats(void) {
997 /* Flat-form binary format */
998#ifdef OF_BIN
999 extern struct ofmt of_bin;
1000#endif
1001 /* Unix formats: a.out, COFF, ELF */
1002#ifdef OF_AOUT
1003 extern struct ofmt of_aout;
1004#endif
1005#ifdef OF_AOUTB
1006 extern struct ofmt of_aoutb;
1007#endif
1008#ifdef OF_COFF
1009 extern struct ofmt of_coff;
1010#endif
1011#ifdef OF_ELF
1012 extern struct ofmt of_elf;
1013#endif
1014 /* Linux strange format: as86 */
1015#ifdef OF_AS86
1016 extern struct ofmt of_as86;
1017#endif
1018 /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
1019#ifdef OF_OBJ
1020 extern struct ofmt of_obj;
1021#endif
1022#ifdef OF_WIN32
1023 extern struct ofmt of_win32;
1024#endif
1025#ifdef OF_RDF
1026 extern struct ofmt of_rdf;
1027#endif
1028#ifdef OF_DBG /* debug format must be included specifically */
1029 extern struct ofmt of_dbg;
1030#endif
1031
1032#ifdef OF_BIN
1033 ofmt_register (&of_bin);
1034#endif
1035#ifdef OF_AOUT
1036 ofmt_register (&of_aout);
1037#endif
1038#ifdef OF_AOUTB
1039 ofmt_register (&of_aoutb);
1040#endif
1041#ifdef OF_COFF
1042 ofmt_register (&of_coff);
1043#endif
1044#ifdef OF_ELF
1045 ofmt_register (&of_elf);
1046#endif
1047#ifdef OF_AS86
1048 ofmt_register (&of_as86);
1049#endif
1050#ifdef OF_OBJ
1051 ofmt_register (&of_obj);
1052#endif
1053#ifdef OF_WIN32
1054 ofmt_register (&of_win32);
1055#endif
1056#ifdef OF_RDF
1057 ofmt_register (&of_rdf);
1058#endif
1059#ifdef OF_DBG
1060 ofmt_register (&of_dbg);
1061#endif
1062 /*
1063 * set the default format
1064 */
1065 ofmt = &OF_DEFAULT;
1066}
1067
1068#define BUF_DELTA 512
1069
1070static FILE *no_pp_fp;
1071static efunc no_pp_err;
1072static ListGen *no_pp_list;
1073
1074static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
1075 ListGen *listgen) {
1076 no_pp_err = error;
1077 no_pp_fp = fopen(file, "r");
1078 if (!no_pp_fp)
1079 no_pp_err (ERR_FATAL | ERR_NOFILE,
1080 "unable to open input file `%s'", file);
1081 no_pp_list = listgen;
1082 (void) pass; /* placate compilers */
1083 (void) eval; /* placate compilers */
1084}
1085
1086static char *no_pp_getline (void) {
1087 char *buffer, *p, *q;
1088 int bufsize;
1089
1090 bufsize = BUF_DELTA;
1091 buffer = nasm_malloc(BUF_DELTA);
1092 p = buffer;
1093 while (1) {
1094 q = fgets(p, bufsize-(p-buffer), no_pp_fp);
1095 if (!q)
1096 break;
1097 p += strlen(p);
1098 if (p > buffer && p[-1] == '\n')
1099 break;
1100 if (p-buffer > bufsize-10) {
1101 bufsize += BUF_DELTA;
1102 buffer = nasm_realloc(buffer, bufsize);
1103 }
1104 }
1105
1106 if (!q && p == buffer) {
1107 nasm_free (buffer);
1108 return NULL;
1109 }
1110
1111 /*
1112 * Play safe: remove CRs as well as LFs, if any of either are
1113 * present at the end of the line.
1114 */
1115 while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
1116 *--p = '\0';
1117
1118 /*
1119 * Handle spurious ^Z, which may be inserted into source files
1120 * by some file transfer utilities.
1121 */
1122 buffer[strcspn(buffer, "\032")] = '\0';
1123
1124 no_pp_list->line (LIST_READ, buffer);
1125
1126 return buffer;
1127}
1128
1129static void no_pp_cleanup (void) {
1130 fclose(no_pp_fp);
1131}