10554
|
1 /* ----------------------------------------------------------------------- *
|
|
2 *
|
|
3 * Copyright 1996-2017 The NASM Authors - All Rights Reserved
|
|
4 * See the file AUTHORS included with the NASM distribution for
|
|
5 * the specific copyright holders.
|
|
6 *
|
|
7 * Redistribution and use in source and binary forms, with or without
|
|
8 * modification, are permitted provided that the following
|
|
9 * conditions are met:
|
|
10 *
|
|
11 * * Redistributions of source code must retain the above copyright
|
|
12 * notice, this list of conditions and the following disclaimer.
|
|
13 * * Redistributions in binary form must reproduce the above
|
|
14 * copyright notice, this list of conditions and the following
|
|
15 * disclaimer in the documentation and/or other materials provided
|
|
16 * with the distribution.
|
|
17 *
|
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
31 *
|
|
32 * ----------------------------------------------------------------------- */
|
|
33
|
|
34 /*
|
|
35 * The Netwide Assembler main program module
|
|
36 */
|
|
37
|
|
38 #include "compiler.h"
|
|
39
|
|
40 #include <stdio.h>
|
|
41 #include <stdarg.h>
|
|
42 #include <stdlib.h>
|
|
43 #include <string.h>
|
|
44 #include <ctype.h>
|
|
45 #include <limits.h>
|
|
46 #include <time.h>
|
|
47
|
|
48 #include "nasm.h"
|
|
49 #include "nasmlib.h"
|
|
50 #include "error.h"
|
|
51 #include "saa.h"
|
|
52 #include "raa.h"
|
|
53 #include "float.h"
|
|
54 #include "stdscan.h"
|
|
55 #include "insns.h"
|
|
56 #include "preproc.h"
|
|
57 #include "parser.h"
|
|
58 #include "eval.h"
|
|
59 #include "assemble.h"
|
|
60 #include "labels.h"
|
|
61 #include "outform.h"
|
|
62 #include "listing.h"
|
|
63 #include "iflag.h"
|
|
64 #include "ver.h"
|
|
65
|
|
66 /*
|
|
67 * This is the maximum number of optimization passes to do. If we ever
|
|
68 * find a case where the optimizer doesn't naturally converge, we might
|
|
69 * have to drop this value so the assembler doesn't appear to just hang.
|
|
70 */
|
|
71 #define MAX_OPTIMIZE (INT_MAX >> 1)
|
|
72
|
|
73 struct forwrefinfo { /* info held on forward refs. */
|
|
74 int lineno;
|
|
75 int operand;
|
|
76 };
|
|
77
|
|
78 static void parse_cmdline(int, char **, int);
|
|
79 static void assemble_file(char *, StrList **);
|
|
80 static bool is_suppressed_warning(int severity);
|
|
81 static bool skip_this_pass(int severity);
|
|
82 static void nasm_verror_gnu(int severity, const char *fmt, va_list args);
|
|
83 static void nasm_verror_vc(int severity, const char *fmt, va_list args);
|
|
84 static void nasm_verror_common(int severity, const char *fmt, va_list args);
|
|
85 static void usage(void);
|
|
86
|
|
87 static bool using_debug_info, opt_verbose_info;
|
|
88 static const char *debug_format;
|
|
89
|
|
90 bool tasm_compatible_mode = false;
|
|
91 int pass0, passn;
|
|
92 static int pass1, pass2; /* XXX: Get rid of these, they are redundant */
|
|
93 int globalrel = 0;
|
|
94 int globalbnd = 0;
|
|
95
|
|
96 static time_t official_compile_time;
|
|
97
|
|
98 static char inname[FILENAME_MAX];
|
|
99 static char outname[FILENAME_MAX];
|
|
100 static char listname[FILENAME_MAX];
|
|
101 static char errname[FILENAME_MAX];
|
|
102 static int globallineno; /* for forward-reference tracking */
|
|
103 /* static int pass = 0; */
|
|
104 const struct ofmt *ofmt = &OF_DEFAULT;
|
|
105 const struct ofmt_alias *ofmt_alias = NULL;
|
|
106 const struct dfmt *dfmt;
|
|
107
|
|
108 static FILE *error_file; /* Where to write error messages */
|
|
109
|
|
110 FILE *ofile = NULL;
|
|
111 int optimizing = MAX_OPTIMIZE; /* number of optimization passes to take */
|
|
112 static int cmd_sb = 16; /* by default */
|
|
113
|
|
114 iflag_t cpu;
|
|
115 static iflag_t cmd_cpu;
|
|
116
|
|
117 struct location location;
|
|
118 bool in_absolute; /* Flag we are in ABSOLUTE seg */
|
|
119 struct location absolute; /* Segment/offset inside ABSOLUTE */
|
|
120
|
|
121 static struct RAA *offsets;
|
|
122
|
|
123 static struct SAA *forwrefs; /* keep track of forward references */
|
|
124 static const struct forwrefinfo *forwref;
|
|
125
|
|
126 static const struct preproc_ops *preproc;
|
|
127
|
|
128 #define OP_NORMAL (1u << 0)
|
|
129 #define OP_PREPROCESS (1u << 1)
|
|
130 #define OP_DEPEND (1u << 2)
|
|
131
|
|
132 static unsigned int operating_mode;
|
|
133
|
|
134 /* Dependency flags */
|
|
135 static bool depend_emit_phony = false;
|
|
136 static bool depend_missing_ok = false;
|
|
137 static const char *depend_target = NULL;
|
|
138 static const char *depend_file = NULL;
|
|
139
|
|
140 static bool want_usage;
|
|
141 static bool terminate_after_phase;
|
|
142 bool user_nolist = false;
|
|
143
|
|
144 static char *quote_for_make(const char *str);
|
|
145
|
|
146 static int64_t get_curr_offs(void)
|
|
147 {
|
|
148 return in_absolute ? absolute.offset : raa_read(offsets, location.segment);
|
|
149 }
|
|
150
|
|
151 static void set_curr_offs(int64_t l_off)
|
|
152 {
|
|
153 if (in_absolute)
|
|
154 absolute.offset = l_off;
|
|
155 else
|
|
156 offsets = raa_write(offsets, location.segment, l_off);
|
|
157 }
|
|
158
|
|
159 static void nasm_fputs(const char *line, FILE * outfile)
|
|
160 {
|
|
161 if (outfile) {
|
|
162 fputs(line, outfile);
|
|
163 putc('\n', outfile);
|
|
164 } else
|
|
165 puts(line);
|
|
166 }
|
|
167
|
|
168 /* Convert a struct tm to a POSIX-style time constant */
|
|
169 static int64_t make_posix_time(struct tm *tm)
|
|
170 {
|
|
171 int64_t t;
|
|
172 int64_t y = tm->tm_year;
|
|
173
|
|
174 /* See IEEE 1003.1:2004, section 4.14 */
|
|
175
|
|
176 t = (y-70)*365 + (y-69)/4 - (y-1)/100 + (y+299)/400;
|
|
177 t += tm->tm_yday;
|
|
178 t *= 24;
|
|
179 t += tm->tm_hour;
|
|
180 t *= 60;
|
|
181 t += tm->tm_min;
|
|
182 t *= 60;
|
|
183 t += tm->tm_sec;
|
|
184
|
|
185 return t;
|
|
186 }
|
|
187
|
|
188 static void define_macros_early(void)
|
|
189 {
|
|
190 char temp[128];
|
|
191 struct tm lt, *lt_p, gm, *gm_p;
|
|
192 int64_t posix_time;
|
|
193
|
|
194 lt_p = localtime(&official_compile_time);
|
|
195 if (lt_p) {
|
|
196 lt = *lt_p;
|
|
197
|
|
198 strftime(temp, sizeof temp, "__DATE__=\"%Y-%m-%d\"", <);
|
|
199 preproc->pre_define(temp);
|
|
200 strftime(temp, sizeof temp, "__DATE_NUM__=%Y%m%d", <);
|
|
201 preproc->pre_define(temp);
|
|
202 strftime(temp, sizeof temp, "__TIME__=\"%H:%M:%S\"", <);
|
|
203 preproc->pre_define(temp);
|
|
204 strftime(temp, sizeof temp, "__TIME_NUM__=%H%M%S", <);
|
|
205 preproc->pre_define(temp);
|
|
206 }
|
|
207
|
|
208 gm_p = gmtime(&official_compile_time);
|
|
209 if (gm_p) {
|
|
210 gm = *gm_p;
|
|
211
|
|
212 strftime(temp, sizeof temp, "__UTC_DATE__=\"%Y-%m-%d\"", &gm);
|
|
213 preproc->pre_define(temp);
|
|
214 strftime(temp, sizeof temp, "__UTC_DATE_NUM__=%Y%m%d", &gm);
|
|
215 preproc->pre_define(temp);
|
|
216 strftime(temp, sizeof temp, "__UTC_TIME__=\"%H:%M:%S\"", &gm);
|
|
217 preproc->pre_define(temp);
|
|
218 strftime(temp, sizeof temp, "__UTC_TIME_NUM__=%H%M%S", &gm);
|
|
219 preproc->pre_define(temp);
|
|
220 }
|
|
221
|
|
222 if (gm_p)
|
|
223 posix_time = make_posix_time(&gm);
|
|
224 else if (lt_p)
|
|
225 posix_time = make_posix_time(<);
|
|
226 else
|
|
227 posix_time = 0;
|
|
228
|
|
229 if (posix_time) {
|
|
230 snprintf(temp, sizeof temp, "__POSIX_TIME__=%"PRId64, posix_time);
|
|
231 preproc->pre_define(temp);
|
|
232 }
|
|
233 }
|
|
234
|
|
235 static void define_macros_late(void)
|
|
236 {
|
|
237 char temp[128];
|
|
238
|
|
239 /*
|
|
240 * In case if output format is defined by alias
|
|
241 * we have to put shortname of the alias itself here
|
|
242 * otherwise ABI backward compatibility gets broken.
|
|
243 */
|
|
244 snprintf(temp, sizeof(temp), "__OUTPUT_FORMAT__=%s",
|
|
245 ofmt_alias ? ofmt_alias->shortname : ofmt->shortname);
|
|
246 preproc->pre_define(temp);
|
|
247 }
|
|
248
|
|
249 static void emit_dependencies(StrList *list)
|
|
250 {
|
|
251 FILE *deps;
|
|
252 int linepos, len;
|
|
253 StrList *l, *nl;
|
|
254
|
|
255 if (depend_file && strcmp(depend_file, "-")) {
|
|
256 deps = nasm_open_write(depend_file, NF_TEXT);
|
|
257 if (!deps) {
|
|
258 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
|
|
259 "unable to write dependency file `%s'", depend_file);
|
|
260 return;
|
|
261 }
|
|
262 } else {
|
|
263 deps = stdout;
|
|
264 }
|
|
265
|
|
266 linepos = fprintf(deps, "%s:", depend_target);
|
|
267 list_for_each(l, list) {
|
|
268 char *file = quote_for_make(l->str);
|
|
269 len = strlen(file);
|
|
270 if (linepos + len > 62 && linepos > 1) {
|
|
271 fprintf(deps, " \\\n ");
|
|
272 linepos = 1;
|
|
273 }
|
|
274 fprintf(deps, " %s", file);
|
|
275 linepos += len+1;
|
|
276 nasm_free(file);
|
|
277 }
|
|
278 fprintf(deps, "\n\n");
|
|
279
|
|
280 list_for_each_safe(l, nl, list) {
|
|
281 if (depend_emit_phony)
|
|
282 fprintf(deps, "%s:\n\n", l->str);
|
|
283 nasm_free(l);
|
|
284 }
|
|
285
|
|
286 if (deps != stdout)
|
|
287 fclose(deps);
|
|
288 }
|
|
289
|
|
290 int main(int argc, char **argv)
|
|
291 {
|
|
292 StrList *depend_list = NULL, **depend_ptr;
|
|
293
|
|
294 time(&official_compile_time);
|
|
295
|
|
296 iflag_set(&cpu, IF_PLEVEL);
|
|
297 iflag_set(&cmd_cpu, IF_PLEVEL);
|
|
298
|
|
299 pass0 = 0;
|
|
300 want_usage = terminate_after_phase = false;
|
|
301 nasm_set_verror(nasm_verror_gnu);
|
|
302
|
|
303 error_file = stderr;
|
|
304
|
|
305 tolower_init();
|
|
306 src_init();
|
|
307
|
|
308 offsets = raa_init();
|
|
309 forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo));
|
|
310
|
|
311 preproc = &nasmpp;
|
|
312 operating_mode = OP_NORMAL;
|
|
313
|
|
314 parse_cmdline(argc, argv, 1);
|
|
315 if (terminate_after_phase) {
|
|
316 if (want_usage)
|
|
317 usage();
|
|
318 return 1;
|
|
319 }
|
|
320
|
|
321 /*
|
|
322 * Define some macros dependent on the runtime, but not
|
|
323 * on the command line (as those are scanned in cmdline pass 2.)
|
|
324 */
|
|
325 preproc->init();
|
|
326 define_macros_early();
|
|
327
|
|
328 parse_cmdline(argc, argv, 2);
|
|
329 if (terminate_after_phase) {
|
|
330 if (want_usage)
|
|
331 usage();
|
|
332 return 1;
|
|
333 }
|
|
334
|
|
335 /* Save away the default state of warnings */
|
|
336 memcpy(warning_state_init, warning_state, sizeof warning_state);
|
|
337
|
|
338 if (!using_debug_info) {
|
|
339 /* No debug info, redirect to the null backend (empty stubs) */
|
|
340 dfmt = &null_debug_form;
|
|
341 } else if (!debug_format) {
|
|
342 /* Default debug format for this backend */
|
|
343 dfmt = ofmt->default_dfmt;
|
|
344 } else {
|
|
345 dfmt = dfmt_find(ofmt, debug_format);
|
|
346 if (!dfmt) {
|
|
347 nasm_fatal(ERR_NOFILE | ERR_USAGE,
|
|
348 "unrecognized debug format `%s' for"
|
|
349 " output format `%s'",
|
|
350 debug_format, ofmt->shortname);
|
|
351 }
|
|
352 }
|
|
353
|
|
354 if (ofmt->stdmac)
|
|
355 preproc->extra_stdmac(ofmt->stdmac);
|
|
356
|
|
357 /* define some macros dependent of command-line */
|
|
358 define_macros_late();
|
|
359
|
|
360 depend_ptr = (depend_file || (operating_mode & OP_DEPEND)) ? &depend_list : NULL;
|
|
361 if (!depend_target)
|
|
362 depend_target = quote_for_make(outname);
|
|
363
|
|
364 if (operating_mode & OP_DEPEND) {
|
|
365 char *line;
|
|
366
|
|
367 if (depend_missing_ok)
|
|
368 preproc->include_path(NULL); /* "assume generated" */
|
|
369
|
|
370 preproc->reset(inname, 0, depend_ptr);
|
|
371 if (outname[0] == '\0')
|
|
372 ofmt->filename(inname, outname);
|
|
373 ofile = NULL;
|
|
374 while ((line = preproc->getline()))
|
|
375 nasm_free(line);
|
|
376 preproc->cleanup(0);
|
|
377 } else if (operating_mode & OP_PREPROCESS) {
|
|
378 char *line;
|
|
379 const char *file_name = NULL;
|
|
380 int32_t prior_linnum = 0;
|
|
381 int lineinc = 0;
|
|
382
|
|
383 if (*outname) {
|
|
384 ofile = nasm_open_write(outname, NF_TEXT);
|
|
385 if (!ofile)
|
|
386 nasm_fatal(ERR_NOFILE,
|
|
387 "unable to open output file `%s'",
|
|
388 outname);
|
|
389 } else
|
|
390 ofile = NULL;
|
|
391
|
|
392 location.known = false;
|
|
393
|
|
394 /* pass = 1; */
|
|
395 preproc->reset(inname, 3, depend_ptr);
|
|
396
|
|
397 /* Revert all warnings to the default state */
|
|
398 memcpy(warning_state, warning_state_init, sizeof warning_state);
|
|
399
|
|
400 while ((line = preproc->getline())) {
|
|
401 /*
|
|
402 * We generate %line directives if needed for later programs
|
|
403 */
|
|
404 int32_t linnum = prior_linnum += lineinc;
|
|
405 int altline = src_get(&linnum, &file_name);
|
|
406 if (altline) {
|
|
407 if (altline == 1 && lineinc == 1)
|
|
408 nasm_fputs("", ofile);
|
|
409 else {
|
|
410 lineinc = (altline != -1 || lineinc != 1);
|
|
411 fprintf(ofile ? ofile : stdout,
|
|
412 "%%line %"PRId32"+%d %s\n", linnum, lineinc,
|
|
413 file_name);
|
|
414 }
|
|
415 prior_linnum = linnum;
|
|
416 }
|
|
417 nasm_fputs(line, ofile);
|
|
418 nasm_free(line);
|
|
419 }
|
|
420 preproc->cleanup(0);
|
|
421 if (ofile)
|
|
422 fclose(ofile);
|
|
423 if (ofile && terminate_after_phase)
|
|
424 remove(outname);
|
|
425 ofile = NULL;
|
|
426 }
|
|
427
|
|
428 if (operating_mode & OP_NORMAL) {
|
|
429 /*
|
|
430 * We must call ofmt->filename _anyway_, even if the user
|
|
431 * has specified their own output file, because some
|
|
432 * formats (eg OBJ and COFF) use ofmt->filename to find out
|
|
433 * the name of the input file and then put that inside the
|
|
434 * file.
|
|
435 */
|
|
436 ofmt->filename(inname, outname);
|
|
437
|
|
438 ofile = nasm_open_write(outname, (ofmt->flags & OFMT_TEXT) ? NF_TEXT : NF_BINARY);
|
|
439 if (!ofile)
|
|
440 nasm_fatal(ERR_NOFILE,
|
|
441 "unable to open output file `%s'", outname);
|
|
442
|
|
443 /*
|
|
444 * We must call init_labels() before ofmt->init() since
|
|
445 * some object formats will want to define labels in their
|
|
446 * init routines. (eg OS/2 defines the FLAT group)
|
|
447 */
|
|
448 init_labels();
|
|
449
|
|
450 ofmt->init();
|
|
451 dfmt->init();
|
|
452
|
|
453 assemble_file(inname, depend_ptr);
|
|
454
|
|
455 if (!terminate_after_phase) {
|
|
456 ofmt->cleanup();
|
|
457 cleanup_labels();
|
|
458 fflush(ofile);
|
|
459 if (ferror(ofile)) {
|
|
460 nasm_error(ERR_NONFATAL|ERR_NOFILE,
|
|
461 "write error on output file `%s'", outname);
|
|
462 terminate_after_phase = true;
|
|
463 }
|
|
464 }
|
|
465
|
|
466 if (ofile) {
|
|
467 fclose(ofile);
|
|
468 if (terminate_after_phase)
|
|
469 remove(outname);
|
|
470 ofile = NULL;
|
|
471 }
|
|
472 }
|
|
473
|
|
474 if (depend_list && !terminate_after_phase)
|
|
475 emit_dependencies(depend_list);
|
|
476
|
|
477 if (want_usage)
|
|
478 usage();
|
|
479
|
|
480 raa_free(offsets);
|
|
481 saa_free(forwrefs);
|
|
482 eval_cleanup();
|
|
483 stdscan_cleanup();
|
|
484 src_free();
|
|
485
|
|
486 return terminate_after_phase;
|
|
487 }
|
|
488
|
|
489 /*
|
|
490 * Get a parameter for a command line option.
|
|
491 * First arg must be in the form of e.g. -f...
|
|
492 */
|
|
493 static char *get_param(char *p, char *q, bool *advance)
|
|
494 {
|
|
495 *advance = false;
|
|
496 if (p[2]) /* the parameter's in the option */
|
|
497 return nasm_skip_spaces(p + 2);
|
|
498 if (q && q[0]) {
|
|
499 *advance = true;
|
|
500 return q;
|
|
501 }
|
|
502 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
503 "option `-%c' requires an argument", p[1]);
|
|
504 return NULL;
|
|
505 }
|
|
506
|
|
507 /*
|
|
508 * Copy a filename
|
|
509 */
|
|
510 static void copy_filename(char *dst, const char *src)
|
|
511 {
|
|
512 size_t len = strlen(src);
|
|
513
|
|
514 if (len >= (size_t)FILENAME_MAX) {
|
|
515 nasm_fatal(ERR_NOFILE, "file name too long");
|
|
516 return;
|
|
517 }
|
|
518 strncpy(dst, src, FILENAME_MAX);
|
|
519 }
|
|
520
|
|
521 /*
|
|
522 * Convert a string to Make-safe form
|
|
523 */
|
|
524 static char *quote_for_make(const char *str)
|
|
525 {
|
|
526 const char *p;
|
|
527 char *os, *q;
|
|
528
|
|
529 size_t n = 1; /* Terminating zero */
|
|
530 size_t nbs = 0;
|
|
531
|
|
532 if (!str)
|
|
533 return NULL;
|
|
534
|
|
535 for (p = str; *p; p++) {
|
|
536 switch (*p) {
|
|
537 case ' ':
|
|
538 case '\t':
|
|
539 /* Convert N backslashes + ws -> 2N+1 backslashes + ws */
|
|
540 n += nbs + 2;
|
|
541 nbs = 0;
|
|
542 break;
|
|
543 case '$':
|
|
544 case '#':
|
|
545 nbs = 0;
|
|
546 n += 2;
|
|
547 break;
|
|
548 case '\\':
|
|
549 nbs++;
|
|
550 n++;
|
|
551 break;
|
|
552 default:
|
|
553 nbs = 0;
|
|
554 n++;
|
|
555 break;
|
|
556 }
|
|
557 }
|
|
558
|
|
559 /* Convert N backslashes at the end of filename to 2N backslashes */
|
|
560 if (nbs)
|
|
561 n += nbs;
|
|
562
|
|
563 os = q = nasm_malloc(n);
|
|
564
|
|
565 nbs = 0;
|
|
566 for (p = str; *p; p++) {
|
|
567 switch (*p) {
|
|
568 case ' ':
|
|
569 case '\t':
|
|
570 while (nbs--)
|
|
571 *q++ = '\\';
|
|
572 *q++ = '\\';
|
|
573 *q++ = *p;
|
|
574 break;
|
|
575 case '$':
|
|
576 *q++ = *p;
|
|
577 *q++ = *p;
|
|
578 nbs = 0;
|
|
579 break;
|
|
580 case '#':
|
|
581 *q++ = '\\';
|
|
582 *q++ = *p;
|
|
583 nbs = 0;
|
|
584 break;
|
|
585 case '\\':
|
|
586 *q++ = *p;
|
|
587 nbs++;
|
|
588 break;
|
|
589 default:
|
|
590 *q++ = *p;
|
|
591 nbs = 0;
|
|
592 break;
|
|
593 }
|
|
594 }
|
|
595 while (nbs--)
|
|
596 *q++ = '\\';
|
|
597
|
|
598 *q = '\0';
|
|
599
|
|
600 return os;
|
|
601 }
|
|
602
|
|
603 struct textargs {
|
|
604 const char *label;
|
|
605 int value;
|
|
606 };
|
|
607
|
|
608 enum text_options {
|
|
609 OPT_PREFIX,
|
|
610 OPT_POSTFIX
|
|
611 };
|
|
612 static const struct textargs textopts[] = {
|
|
613 {"prefix", OPT_PREFIX},
|
|
614 {"postfix", OPT_POSTFIX},
|
|
615 {NULL, 0}
|
|
616 };
|
|
617
|
|
618 static void show_version(void)
|
|
619 {
|
|
620 printf("NASM version %s compiled on %s%s\n",
|
|
621 nasm_version, nasm_date, nasm_compile_options);
|
|
622 exit(0);
|
|
623 }
|
|
624
|
|
625 static bool stopoptions = false;
|
|
626 static bool process_arg(char *p, char *q, int pass)
|
|
627 {
|
|
628 char *param;
|
|
629 int i;
|
|
630 bool advance = false;
|
|
631
|
|
632 if (!p || !p[0])
|
|
633 return false;
|
|
634
|
|
635 if (p[0] == '-' && !stopoptions) {
|
|
636 if (strchr("oOfpPdDiIlFXuUZwW", p[1])) {
|
|
637 /* These parameters take values */
|
|
638 if (!(param = get_param(p, q, &advance)))
|
|
639 return advance;
|
|
640 }
|
|
641
|
|
642 switch (p[1]) {
|
|
643 case 's':
|
|
644 if (pass == 1)
|
|
645 error_file = stdout;
|
|
646 break;
|
|
647
|
|
648 case 'o': /* output file */
|
|
649 if (pass == 2)
|
|
650 copy_filename(outname, param);
|
|
651 break;
|
|
652
|
|
653 case 'f': /* output format */
|
|
654 if (pass == 1) {
|
|
655 ofmt = ofmt_find(param, &ofmt_alias);
|
|
656 if (!ofmt) {
|
|
657 nasm_fatal(ERR_NOFILE | ERR_USAGE,
|
|
658 "unrecognised output format `%s' - "
|
|
659 "use -hf for a list", param);
|
|
660 }
|
|
661 }
|
|
662 break;
|
|
663
|
|
664 case 'O': /* Optimization level */
|
|
665 if (pass == 2) {
|
|
666 int opt;
|
|
667
|
|
668 if (!*param) {
|
|
669 /* Naked -O == -Ox */
|
|
670 optimizing = MAX_OPTIMIZE;
|
|
671 } else {
|
|
672 while (*param) {
|
|
673 switch (*param) {
|
|
674 case '0': case '1': case '2': case '3': case '4':
|
|
675 case '5': case '6': case '7': case '8': case '9':
|
|
676 opt = strtoul(param, ¶m, 10);
|
|
677
|
|
678 /* -O0 -> optimizing == -1, 0.98 behaviour */
|
|
679 /* -O1 -> optimizing == 0, 0.98.09 behaviour */
|
|
680 if (opt < 2)
|
|
681 optimizing = opt - 1;
|
|
682 else
|
|
683 optimizing = opt;
|
|
684 break;
|
|
685
|
|
686 case 'v':
|
|
687 case '+':
|
|
688 param++;
|
|
689 opt_verbose_info = true;
|
|
690 break;
|
|
691
|
|
692 case 'x':
|
|
693 param++;
|
|
694 optimizing = MAX_OPTIMIZE;
|
|
695 break;
|
|
696
|
|
697 default:
|
|
698 nasm_fatal(0,
|
|
699 "unknown optimization option -O%c\n",
|
|
700 *param);
|
|
701 break;
|
|
702 }
|
|
703 }
|
|
704 if (optimizing > MAX_OPTIMIZE)
|
|
705 optimizing = MAX_OPTIMIZE;
|
|
706 }
|
|
707 }
|
|
708 break;
|
|
709
|
|
710 case 'p': /* pre-include */
|
|
711 case 'P':
|
|
712 if (pass == 2)
|
|
713 preproc->pre_include(param);
|
|
714 break;
|
|
715
|
|
716 case 'd': /* pre-define */
|
|
717 case 'D':
|
|
718 if (pass == 2)
|
|
719 preproc->pre_define(param);
|
|
720 break;
|
|
721
|
|
722 case 'u': /* un-define */
|
|
723 case 'U':
|
|
724 if (pass == 2)
|
|
725 preproc->pre_undefine(param);
|
|
726 break;
|
|
727
|
|
728 case 'i': /* include search path */
|
|
729 case 'I':
|
|
730 if (pass == 2)
|
|
731 preproc->include_path(param);
|
|
732 break;
|
|
733
|
|
734 case 'l': /* listing file */
|
|
735 if (pass == 2)
|
|
736 copy_filename(listname, param);
|
|
737 break;
|
|
738
|
|
739 case 'Z': /* error messages file */
|
|
740 if (pass == 1)
|
|
741 copy_filename(errname, param);
|
|
742 break;
|
|
743
|
|
744 case 'F': /* specify debug format */
|
|
745 if (pass == 2) {
|
|
746 using_debug_info = true;
|
|
747 debug_format = param;
|
|
748 }
|
|
749 break;
|
|
750
|
|
751 case 'X': /* specify error reporting format */
|
|
752 if (pass == 1) {
|
|
753 if (nasm_stricmp("vc", param) == 0)
|
|
754 nasm_set_verror(nasm_verror_vc);
|
|
755 else if (nasm_stricmp("gnu", param) == 0)
|
|
756 nasm_set_verror(nasm_verror_gnu);
|
|
757 else
|
|
758 nasm_fatal(ERR_NOFILE | ERR_USAGE,
|
|
759 "unrecognized error reporting format `%s'",
|
|
760 param);
|
|
761 }
|
|
762 break;
|
|
763
|
|
764 case 'g':
|
|
765 if (pass == 2) {
|
|
766 using_debug_info = true;
|
|
767 if (p[2])
|
|
768 debug_format = nasm_skip_spaces(p + 2);
|
|
769 }
|
|
770 break;
|
|
771
|
|
772 case 'h':
|
|
773 printf
|
|
774 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
|
|
775 "[-l listfile]\n"
|
|
776 " [options...] [--] filename\n"
|
|
777 " or nasm -v (or --v) for version info\n\n"
|
|
778 " -t assemble in SciTech TASM compatible mode\n");
|
|
779 printf
|
|
780 (" -E (or -e) preprocess only (writes output to stdout by default)\n"
|
|
781 " -a don't preprocess (assemble only)\n"
|
|
782 " -M generate Makefile dependencies on stdout\n"
|
|
783 " -MG d:o, missing files assumed generated\n"
|
|
784 " -MF <file> set Makefile dependency file\n"
|
|
785 " -MD <file> assemble and generate dependencies\n"
|
|
786 " -MT <file> dependency target name\n"
|
|
787 " -MQ <file> dependency target name (quoted)\n"
|
|
788 " -MP emit phony target\n\n"
|
|
789 " -Z<file> redirect error messages to file\n"
|
|
790 " -s redirect error messages to stdout\n\n"
|
|
791 " -g generate debugging information\n\n"
|
|
792 " -F format select a debugging format\n\n"
|
|
793 " -gformat same as -g -F format\n\n"
|
|
794 " -o outfile write output to an outfile\n\n"
|
|
795 " -f format select an output format\n\n"
|
|
796 " -l listfile write listing to a listfile\n\n"
|
|
797 " -I<path> adds a pathname to the include file path\n");
|
|
798 printf
|
|
799 (" -O<digit> optimize branch offsets\n"
|
|
800 " -O0: No optimization\n"
|
|
801 " -O1: Minimal optimization\n"
|
|
802 " -Ox: Multipass optimization (default)\n\n"
|
|
803 " -P<file> pre-includes a file\n"
|
|
804 " -D<macro>[=<value>] pre-defines a macro\n"
|
|
805 " -U<macro> undefines a macro\n"
|
|
806 " -X<format> specifies error reporting format (gnu or vc)\n"
|
|
807 " -w+foo enables warning foo (equiv. -Wfoo)\n"
|
|
808 " -w-foo disable warning foo (equiv. -Wno-foo)\n\n"
|
|
809 " -w[+-]error[=foo] can be used to promote warnings to errors\n"
|
|
810 " -h show invocation summary and exit\n\n"
|
|
811 "--prefix,--postfix\n"
|
|
812 " these options prepend or append the given string\n"
|
|
813 " to all extern and global variables\n"
|
|
814 "\n"
|
|
815 "Response files should contain command line parameters,\n"
|
|
816 "one per line.\n"
|
|
817 "\n"
|
|
818 "Warnings for the -W/-w options:\n");
|
|
819 for (i = 0; i <= ERR_WARN_ALL; i++)
|
|
820 printf(" %-23s %s%s\n",
|
|
821 warnings[i].name, warnings[i].help,
|
|
822 i == ERR_WARN_ALL ? "\n" :
|
|
823 warnings[i].enabled ? " (default on)" :
|
|
824 " (default off)");
|
|
825 if (p[2] == 'f') {
|
|
826 printf("valid output formats for -f are"
|
|
827 " (`*' denotes default):\n");
|
|
828 ofmt_list(ofmt, stdout);
|
|
829 } else {
|
|
830 printf("For a list of valid output formats, use -hf.\n");
|
|
831 printf("For a list of debug formats, use -f <form> -y.\n");
|
|
832 }
|
|
833 exit(0); /* never need usage message here */
|
|
834 break;
|
|
835
|
|
836 case 'y':
|
|
837 printf("\nvalid debug formats for '%s' output format are"
|
|
838 " ('*' denotes default):\n", ofmt->shortname);
|
|
839 dfmt_list(ofmt, stdout);
|
|
840 exit(0);
|
|
841 break;
|
|
842
|
|
843 case 't':
|
|
844 if (pass == 2)
|
|
845 tasm_compatible_mode = true;
|
|
846 break;
|
|
847
|
|
848 case 'v':
|
|
849 show_version();
|
|
850 break;
|
|
851
|
|
852 case 'e': /* preprocess only */
|
|
853 case 'E':
|
|
854 if (pass == 1)
|
|
855 operating_mode = OP_PREPROCESS;
|
|
856 break;
|
|
857
|
|
858 case 'a': /* assemble only - don't preprocess */
|
|
859 if (pass == 1)
|
|
860 preproc = &preproc_nop;
|
|
861 break;
|
|
862
|
|
863 case 'w':
|
|
864 case 'W':
|
|
865 if (pass == 2) {
|
|
866 if (!set_warning_status(param)) {
|
|
867 nasm_error(ERR_WARNING|ERR_NOFILE|ERR_WARN_UNK_WARNING,
|
|
868 "unknown warning option: %s", param);
|
|
869 }
|
|
870 }
|
|
871 break;
|
|
872
|
|
873 case 'M':
|
|
874 if (pass == 2) {
|
|
875 switch (p[2]) {
|
|
876 case 0:
|
|
877 operating_mode = OP_DEPEND;
|
|
878 break;
|
|
879 case 'G':
|
|
880 operating_mode = OP_DEPEND;
|
|
881 depend_missing_ok = true;
|
|
882 break;
|
|
883 case 'P':
|
|
884 depend_emit_phony = true;
|
|
885 break;
|
|
886 case 'D':
|
|
887 operating_mode = OP_NORMAL;
|
|
888 depend_file = q;
|
|
889 advance = true;
|
|
890 break;
|
|
891 case 'F':
|
|
892 depend_file = q;
|
|
893 advance = true;
|
|
894 break;
|
|
895 case 'T':
|
|
896 depend_target = q;
|
|
897 advance = true;
|
|
898 break;
|
|
899 case 'Q':
|
|
900 depend_target = quote_for_make(q);
|
|
901 advance = true;
|
|
902 break;
|
|
903 default:
|
|
904 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
|
|
905 "unknown dependency option `-M%c'", p[2]);
|
|
906 break;
|
|
907 }
|
|
908 if (advance && (!q || !q[0])) {
|
|
909 nasm_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
|
|
910 "option `-M%c' requires a parameter", p[2]);
|
|
911 break;
|
|
912 }
|
|
913 }
|
|
914 break;
|
|
915
|
|
916 case '-':
|
|
917 {
|
|
918 int s;
|
|
919
|
|
920 if (p[2] == 0) { /* -- => stop processing options */
|
|
921 stopoptions = 1;
|
|
922 break;
|
|
923 }
|
|
924
|
|
925 if (!nasm_stricmp(p, "--v"))
|
|
926 show_version();
|
|
927
|
|
928 if (!nasm_stricmp(p, "--version"))
|
|
929 show_version();
|
|
930
|
|
931 for (s = 0; textopts[s].label; s++) {
|
|
932 if (!nasm_stricmp(p + 2, textopts[s].label)) {
|
|
933 break;
|
|
934 }
|
|
935 }
|
|
936
|
|
937 switch (s) {
|
|
938
|
|
939 case OPT_PREFIX:
|
|
940 case OPT_POSTFIX:
|
|
941 {
|
|
942 if (!q) {
|
|
943 nasm_error(ERR_NONFATAL | ERR_NOFILE |
|
|
944 ERR_USAGE,
|
|
945 "option `--%s' requires an argument",
|
|
946 p + 2);
|
|
947 break;
|
|
948 } else {
|
|
949 advance = 1, param = q;
|
|
950 }
|
|
951
|
|
952 switch (s) {
|
|
953 case OPT_PREFIX:
|
|
954 if (pass == 2)
|
|
955 strlcpy(lprefix, param, PREFIX_MAX);
|
|
956 break;
|
|
957 case OPT_POSTFIX:
|
|
958 if (pass == 2)
|
|
959 strlcpy(lpostfix, param, POSTFIX_MAX);
|
|
960 break;
|
|
961 default:
|
|
962 nasm_panic(ERR_NOFILE,
|
|
963 "internal error");
|
|
964 break;
|
|
965 }
|
|
966 break;
|
|
967 }
|
|
968
|
|
969 default:
|
|
970 {
|
|
971 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
972 "unrecognised option `--%s'", p + 2);
|
|
973 break;
|
|
974 }
|
|
975 }
|
|
976 break;
|
|
977 }
|
|
978
|
|
979 default:
|
|
980 if (!ofmt->setinfo(GI_SWITCH, &p))
|
|
981 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
982 "unrecognised option `-%c'", p[1]);
|
|
983 break;
|
|
984 }
|
|
985 } else if (pass == 2) {
|
|
986 if (*inname) {
|
|
987 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
988 "more than one input file specified");
|
|
989 } else {
|
|
990 copy_filename(inname, p);
|
|
991 }
|
|
992 }
|
|
993
|
|
994 return advance;
|
|
995 }
|
|
996
|
|
997 #define ARG_BUF_DELTA 128
|
|
998
|
|
999 static void process_respfile(FILE * rfile, int pass)
|
|
1000 {
|
|
1001 char *buffer, *p, *q, *prevarg;
|
|
1002 int bufsize, prevargsize;
|
|
1003
|
|
1004 bufsize = prevargsize = ARG_BUF_DELTA;
|
|
1005 buffer = nasm_malloc(ARG_BUF_DELTA);
|
|
1006 prevarg = nasm_malloc(ARG_BUF_DELTA);
|
|
1007 prevarg[0] = '\0';
|
|
1008
|
|
1009 while (1) { /* Loop to handle all lines in file */
|
|
1010 p = buffer;
|
|
1011 while (1) { /* Loop to handle long lines */
|
|
1012 q = fgets(p, bufsize - (p - buffer), rfile);
|
|
1013 if (!q)
|
|
1014 break;
|
|
1015 p += strlen(p);
|
|
1016 if (p > buffer && p[-1] == '\n')
|
|
1017 break;
|
|
1018 if (p - buffer > bufsize - 10) {
|
|
1019 int offset;
|
|
1020 offset = p - buffer;
|
|
1021 bufsize += ARG_BUF_DELTA;
|
|
1022 buffer = nasm_realloc(buffer, bufsize);
|
|
1023 p = buffer + offset;
|
|
1024 }
|
|
1025 }
|
|
1026
|
|
1027 if (!q && p == buffer) {
|
|
1028 if (prevarg[0])
|
|
1029 process_arg(prevarg, NULL, pass);
|
|
1030 nasm_free(buffer);
|
|
1031 nasm_free(prevarg);
|
|
1032 return;
|
|
1033 }
|
|
1034
|
|
1035 /*
|
|
1036 * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
|
|
1037 * them are present at the end of the line.
|
|
1038 */
|
|
1039 *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
|
|
1040
|
|
1041 while (p > buffer && nasm_isspace(p[-1]))
|
|
1042 *--p = '\0';
|
|
1043
|
|
1044 p = nasm_skip_spaces(buffer);
|
|
1045
|
|
1046 if (process_arg(prevarg, p, pass))
|
|
1047 *p = '\0';
|
|
1048
|
|
1049 if ((int) strlen(p) > prevargsize - 10) {
|
|
1050 prevargsize += ARG_BUF_DELTA;
|
|
1051 prevarg = nasm_realloc(prevarg, prevargsize);
|
|
1052 }
|
|
1053 strncpy(prevarg, p, prevargsize);
|
|
1054 }
|
|
1055 }
|
|
1056
|
|
1057 /* Function to process args from a string of args, rather than the
|
|
1058 * argv array. Used by the environment variable and response file
|
|
1059 * processing.
|
|
1060 */
|
|
1061 static void process_args(char *args, int pass)
|
|
1062 {
|
|
1063 char *p, *q, *arg, *prevarg;
|
|
1064 char separator = ' ';
|
|
1065
|
|
1066 p = args;
|
|
1067 if (*p && *p != '-')
|
|
1068 separator = *p++;
|
|
1069 arg = NULL;
|
|
1070 while (*p) {
|
|
1071 q = p;
|
|
1072 while (*p && *p != separator)
|
|
1073 p++;
|
|
1074 while (*p == separator)
|
|
1075 *p++ = '\0';
|
|
1076 prevarg = arg;
|
|
1077 arg = q;
|
|
1078 if (process_arg(prevarg, arg, pass))
|
|
1079 arg = NULL;
|
|
1080 }
|
|
1081 if (arg)
|
|
1082 process_arg(arg, NULL, pass);
|
|
1083 }
|
|
1084
|
|
1085 static void process_response_file(const char *file, int pass)
|
|
1086 {
|
|
1087 char str[2048];
|
|
1088 FILE *f = nasm_open_read(file, NF_TEXT);
|
|
1089 if (!f) {
|
|
1090 perror(file);
|
|
1091 exit(-1);
|
|
1092 }
|
|
1093 while (fgets(str, sizeof str, f)) {
|
|
1094 process_args(str, pass);
|
|
1095 }
|
|
1096 fclose(f);
|
|
1097 }
|
|
1098
|
|
1099 static void parse_cmdline(int argc, char **argv, int pass)
|
|
1100 {
|
|
1101 FILE *rfile;
|
|
1102 char *envreal, *envcopy = NULL, *p;
|
|
1103 int i;
|
|
1104
|
|
1105 *inname = *outname = *listname = *errname = '\0';
|
|
1106
|
|
1107 /* Initialize all the warnings to their default state */
|
|
1108 for (i = 0; i < ERR_WARN_ALL; i++) {
|
|
1109 warning_state_init[i] = warning_state[i] =
|
|
1110 warnings[i].enabled ? WARN_ST_ENABLED : 0;
|
|
1111 }
|
|
1112
|
|
1113 /*
|
|
1114 * First, process the NASMENV environment variable.
|
|
1115 */
|
|
1116 envreal = getenv("NASMENV");
|
|
1117 if (envreal) {
|
|
1118 envcopy = nasm_strdup(envreal);
|
|
1119 process_args(envcopy, pass);
|
|
1120 nasm_free(envcopy);
|
|
1121 }
|
|
1122
|
|
1123 /*
|
|
1124 * Now process the actual command line.
|
|
1125 */
|
|
1126 while (--argc) {
|
|
1127 bool advance;
|
|
1128 argv++;
|
|
1129 if (argv[0][0] == '@') {
|
|
1130 /*
|
|
1131 * We have a response file, so process this as a set of
|
|
1132 * arguments like the environment variable. This allows us
|
|
1133 * to have multiple arguments on a single line, which is
|
|
1134 * different to the -@resp file processing below for regular
|
|
1135 * NASM.
|
|
1136 */
|
|
1137 process_response_file(argv[0]+1, pass);
|
|
1138 argc--;
|
|
1139 argv++;
|
|
1140 }
|
|
1141 if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
|
|
1142 p = get_param(argv[0], argc > 1 ? argv[1] : NULL, &advance);
|
|
1143 if (p) {
|
|
1144 rfile = nasm_open_read(p, NF_TEXT);
|
|
1145 if (rfile) {
|
|
1146 process_respfile(rfile, pass);
|
|
1147 fclose(rfile);
|
|
1148 } else
|
|
1149 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
1150 "unable to open response file `%s'", p);
|
|
1151 }
|
|
1152 } else
|
|
1153 advance = process_arg(argv[0], argc > 1 ? argv[1] : NULL, pass);
|
|
1154 argv += advance, argc -= advance;
|
|
1155 }
|
|
1156
|
|
1157 /*
|
|
1158 * Look for basic command line typos. This definitely doesn't
|
|
1159 * catch all errors, but it might help cases of fumbled fingers.
|
|
1160 */
|
|
1161 if (pass != 2)
|
|
1162 return;
|
|
1163
|
|
1164 if (!*inname)
|
|
1165 nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
|
|
1166 "no input file specified");
|
|
1167 else if (!strcmp(inname, errname) ||
|
|
1168 !strcmp(inname, outname) ||
|
|
1169 !strcmp(inname, listname) ||
|
|
1170 (depend_file && !strcmp(inname, depend_file)))
|
|
1171 nasm_fatal(ERR_NOFILE | ERR_USAGE,
|
|
1172 "file `%s' is both input and output file",
|
|
1173 inname);
|
|
1174
|
|
1175 if (*errname) {
|
|
1176 error_file = nasm_open_write(errname, NF_TEXT);
|
|
1177 if (!error_file) {
|
|
1178 error_file = stderr; /* Revert to default! */
|
|
1179 nasm_fatal(ERR_NOFILE | ERR_USAGE,
|
|
1180 "cannot open file `%s' for error messages",
|
|
1181 errname);
|
|
1182 }
|
|
1183 }
|
|
1184 }
|
|
1185
|
|
1186 static void assemble_file(char *fname, StrList **depend_ptr)
|
|
1187 {
|
|
1188 char *line;
|
|
1189 insn output_ins;
|
|
1190 int i;
|
|
1191 int64_t offs;
|
|
1192 int pass_max;
|
|
1193 uint64_t prev_offset_changed;
|
|
1194 unsigned int stall_count = 0; /* Make sure we make forward progress... */
|
|
1195
|
|
1196 if (cmd_sb == 32 && iflag_ffs(&cmd_cpu) < IF_386)
|
|
1197 nasm_fatal(0, "command line: 32-bit segment size requires a higher cpu");
|
|
1198
|
|
1199 pass_max = prev_offset_changed = (INT_MAX >> 1) + 2; /* Almost unlimited */
|
|
1200 for (passn = 1; pass0 <= 2; passn++) {
|
|
1201 ldfunc def_label;
|
|
1202
|
|
1203 pass1 = pass0 == 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
|
|
1204 pass2 = passn > 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
|
|
1205 /* pass0 0, 0, 0, ..., 1, 2 */
|
|
1206
|
|
1207 def_label = passn > 1 ? redefine_label : define_label;
|
|
1208
|
|
1209 globalbits = cmd_sb; /* set 'bits' to command line default */
|
|
1210 cpu = cmd_cpu;
|
|
1211 if (pass0 == 2) {
|
|
1212 lfmt->init(listname);
|
|
1213 }
|
|
1214 in_absolute = false;
|
|
1215 global_offset_changed = 0; /* set by redefine_label */
|
|
1216 location.segment = ofmt->section(NULL, pass2, &globalbits);
|
|
1217 if (passn > 1) {
|
|
1218 saa_rewind(forwrefs);
|
|
1219 forwref = saa_rstruct(forwrefs);
|
|
1220 raa_free(offsets);
|
|
1221 offsets = raa_init();
|
|
1222 }
|
|
1223 preproc->reset(fname, pass1, pass1 == 2 ? depend_ptr : NULL);
|
|
1224
|
|
1225 /* Revert all warnings to the default state */
|
|
1226 memcpy(warning_state, warning_state_init, sizeof warning_state);
|
|
1227
|
|
1228 globallineno = 0;
|
|
1229 if (passn == 1)
|
|
1230 location.known = true;
|
|
1231 location.offset = offs = get_curr_offs();
|
|
1232
|
|
1233 while ((line = preproc->getline())) {
|
|
1234 globallineno++;
|
|
1235
|
|
1236 /*
|
|
1237 * Here we parse our directives; this is not handled by the
|
|
1238 * main parser.
|
|
1239 */
|
|
1240 if (process_directives(line))
|
|
1241 goto end_of_line; /* Just do final cleanup */
|
|
1242
|
|
1243 /* Not a directive, or even something that starts with [ */
|
|
1244
|
|
1245 parse_line(pass1, line, &output_ins, def_label);
|
|
1246
|
|
1247 if (optimizing > 0) {
|
|
1248 if (forwref != NULL && globallineno == forwref->lineno) {
|
|
1249 output_ins.forw_ref = true;
|
|
1250 do {
|
|
1251 output_ins.oprs[forwref->operand].opflags |= OPFLAG_FORWARD;
|
|
1252 forwref = saa_rstruct(forwrefs);
|
|
1253 } while (forwref != NULL
|
|
1254 && forwref->lineno == globallineno);
|
|
1255 } else
|
|
1256 output_ins.forw_ref = false;
|
|
1257
|
|
1258 if (output_ins.forw_ref) {
|
|
1259 if (passn == 1) {
|
|
1260 for (i = 0; i < output_ins.operands; i++) {
|
|
1261 if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) {
|
|
1262 struct forwrefinfo *fwinf = (struct forwrefinfo *)saa_wstruct(forwrefs);
|
|
1263 fwinf->lineno = globallineno;
|
|
1264 fwinf->operand = i;
|
|
1265 }
|
|
1266 }
|
|
1267 }
|
|
1268 }
|
|
1269 }
|
|
1270
|
|
1271 /* forw_ref */
|
|
1272 if (output_ins.opcode == I_EQU) {
|
|
1273 if (pass1 == 1) {
|
|
1274 /*
|
|
1275 * Special `..' EQUs get processed in pass two,
|
|
1276 * except `..@' macro-processor EQUs which are done
|
|
1277 * in the normal place.
|
|
1278 */
|
|
1279 if (!output_ins.label)
|
|
1280 nasm_error(ERR_NONFATAL,
|
|
1281 "EQU not preceded by label");
|
|
1282
|
|
1283 else if (output_ins.label[0] != '.' ||
|
|
1284 output_ins.label[1] != '.' ||
|
|
1285 output_ins.label[2] == '@') {
|
|
1286 if (output_ins.operands == 1 &&
|
|
1287 (output_ins.oprs[0].type & IMMEDIATE) &&
|
|
1288 output_ins.oprs[0].wrt == NO_SEG) {
|
|
1289 bool isext = !!(output_ins.oprs[0].opflags & OPFLAG_EXTERN);
|
|
1290 def_label(output_ins.label,
|
|
1291 output_ins.oprs[0].segment,
|
|
1292 output_ins.oprs[0].offset, NULL,
|
|
1293 false, isext);
|
|
1294 } else if (output_ins.operands == 2
|
|
1295 && (output_ins.oprs[0].type & IMMEDIATE)
|
|
1296 && (output_ins.oprs[0].type & COLON)
|
|
1297 && output_ins.oprs[0].segment == NO_SEG
|
|
1298 && output_ins.oprs[0].wrt == NO_SEG
|
|
1299 && (output_ins.oprs[1].type & IMMEDIATE)
|
|
1300 && output_ins.oprs[1].segment == NO_SEG
|
|
1301 && output_ins.oprs[1].wrt == NO_SEG) {
|
|
1302 def_label(output_ins.label,
|
|
1303 output_ins.oprs[0].offset | SEG_ABS,
|
|
1304 output_ins.oprs[1].offset,
|
|
1305 NULL, false, false);
|
|
1306 } else
|
|
1307 nasm_error(ERR_NONFATAL,
|
|
1308 "bad syntax for EQU");
|
|
1309 }
|
|
1310 } else {
|
|
1311 /*
|
|
1312 * Special `..' EQUs get processed here, except
|
|
1313 * `..@' macro processor EQUs which are done above.
|
|
1314 */
|
|
1315 if (output_ins.label[0] == '.' &&
|
|
1316 output_ins.label[1] == '.' &&
|
|
1317 output_ins.label[2] != '@') {
|
|
1318 if (output_ins.operands == 1 &&
|
|
1319 (output_ins.oprs[0].type & IMMEDIATE)) {
|
|
1320 define_label(output_ins.label,
|
|
1321 output_ins.oprs[0].segment,
|
|
1322 output_ins.oprs[0].offset,
|
|
1323 NULL, false, false);
|
|
1324 } else if (output_ins.operands == 2
|
|
1325 && (output_ins.oprs[0].type & IMMEDIATE)
|
|
1326 && (output_ins.oprs[0].type & COLON)
|
|
1327 && output_ins.oprs[0].segment == NO_SEG
|
|
1328 && (output_ins.oprs[1].type & IMMEDIATE)
|
|
1329 && output_ins.oprs[1].segment == NO_SEG) {
|
|
1330 define_label(output_ins.label,
|
|
1331 output_ins.oprs[0].offset | SEG_ABS,
|
|
1332 output_ins.oprs[1].offset,
|
|
1333 NULL, false, false);
|
|
1334 } else
|
|
1335 nasm_error(ERR_NONFATAL,
|
|
1336 "bad syntax for EQU");
|
|
1337 }
|
|
1338 }
|
|
1339 } else { /* instruction isn't an EQU */
|
|
1340
|
|
1341 if (pass1 == 1) {
|
|
1342 int64_t l = insn_size(location.segment, offs, globalbits,
|
|
1343 &output_ins);
|
|
1344 l *= output_ins.times;
|
|
1345
|
|
1346 /* if (using_debug_info) && output_ins.opcode != -1) */
|
|
1347 if (using_debug_info)
|
|
1348 { /* fbk 03/25/01 */
|
|
1349 /* this is done here so we can do debug type info */
|
|
1350 int32_t typeinfo =
|
|
1351 TYS_ELEMENTS(output_ins.operands);
|
|
1352 switch (output_ins.opcode) {
|
|
1353 case I_RESB:
|
|
1354 typeinfo =
|
|
1355 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
|
|
1356 break;
|
|
1357 case I_RESW:
|
|
1358 typeinfo =
|
|
1359 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
|
|
1360 break;
|
|
1361 case I_RESD:
|
|
1362 typeinfo =
|
|
1363 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
|
|
1364 break;
|
|
1365 case I_RESQ:
|
|
1366 typeinfo =
|
|
1367 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
|
|
1368 break;
|
|
1369 case I_REST:
|
|
1370 typeinfo =
|
|
1371 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
|
|
1372 break;
|
|
1373 case I_RESO:
|
|
1374 typeinfo =
|
|
1375 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_OWORD;
|
|
1376 break;
|
|
1377 case I_RESY:
|
|
1378 typeinfo =
|
|
1379 TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_YWORD;
|
|
1380 break;
|
|
1381 case I_DB:
|
|
1382 typeinfo |= TY_BYTE;
|
|
1383 break;
|
|
1384 case I_DW:
|
|
1385 typeinfo |= TY_WORD;
|
|
1386 break;
|
|
1387 case I_DD:
|
|
1388 if (output_ins.eops_float)
|
|
1389 typeinfo |= TY_FLOAT;
|
|
1390 else
|
|
1391 typeinfo |= TY_DWORD;
|
|
1392 break;
|
|
1393 case I_DQ:
|
|
1394 typeinfo |= TY_QWORD;
|
|
1395 break;
|
|
1396 case I_DT:
|
|
1397 typeinfo |= TY_TBYTE;
|
|
1398 break;
|
|
1399 case I_DO:
|
|
1400 typeinfo |= TY_OWORD;
|
|
1401 break;
|
|
1402 case I_DY:
|
|
1403 typeinfo |= TY_YWORD;
|
|
1404 break;
|
|
1405 default:
|
|
1406 typeinfo = TY_LABEL;
|
|
1407
|
|
1408 }
|
|
1409
|
|
1410 dfmt->debug_typevalue(typeinfo);
|
|
1411 }
|
|
1412 if (l != -1) {
|
|
1413 offs += l;
|
|
1414 set_curr_offs(offs);
|
|
1415 }
|
|
1416 /*
|
|
1417 * else l == -1 => invalid instruction, which will be
|
|
1418 * flagged as an error on pass 2
|
|
1419 */
|
|
1420
|
|
1421 } else {
|
|
1422 offs += assemble(location.segment, offs, globalbits, &output_ins);
|
|
1423 set_curr_offs(offs);
|
|
1424
|
|
1425 }
|
|
1426 } /* not an EQU */
|
|
1427 cleanup_insn(&output_ins);
|
|
1428
|
|
1429 end_of_line:
|
|
1430 nasm_free(line);
|
|
1431 location.offset = offs = get_curr_offs();
|
|
1432 } /* end while (line = preproc->getline... */
|
|
1433
|
|
1434 if (pass0 == 2 && global_offset_changed && !terminate_after_phase)
|
|
1435 nasm_error(ERR_NONFATAL,
|
|
1436 "phase error detected at end of assembly.");
|
|
1437
|
|
1438 if (pass1 == 1)
|
|
1439 preproc->cleanup(1);
|
|
1440
|
|
1441 if ((passn > 1 && !global_offset_changed) || pass0 == 2) {
|
|
1442 pass0++;
|
|
1443 } else if (global_offset_changed &&
|
|
1444 global_offset_changed < prev_offset_changed) {
|
|
1445 prev_offset_changed = global_offset_changed;
|
|
1446 stall_count = 0;
|
|
1447 } else {
|
|
1448 stall_count++;
|
|
1449 }
|
|
1450
|
|
1451 if (terminate_after_phase)
|
|
1452 break;
|
|
1453
|
|
1454 if ((stall_count > 997U) || (passn >= pass_max)) {
|
|
1455 /* We get here if the labels don't converge
|
|
1456 * Example: FOO equ FOO + 1
|
|
1457 */
|
|
1458 nasm_error(ERR_NONFATAL,
|
|
1459 "Can't find valid values for all labels "
|
|
1460 "after %d passes, giving up.", passn);
|
|
1461 nasm_error(ERR_NONFATAL,
|
|
1462 "Possible causes: recursive EQUs, macro abuse.");
|
|
1463 break;
|
|
1464 }
|
|
1465 }
|
|
1466
|
|
1467 preproc->cleanup(0);
|
|
1468 lfmt->cleanup();
|
|
1469 if (!terminate_after_phase && opt_verbose_info) {
|
|
1470 /* -On and -Ov switches */
|
|
1471 fprintf(stdout, "info: assembly required 1+%d+1 passes\n", passn-3);
|
|
1472 }
|
|
1473 }
|
|
1474
|
|
1475 /**
|
|
1476 * gnu style error reporting
|
|
1477 * This function prints an error message to error_file in the
|
|
1478 * style used by GNU. An example would be:
|
|
1479 * file.asm:50: error: blah blah blah
|
|
1480 * where file.asm is the name of the file, 50 is the line number on
|
|
1481 * which the error occurs (or is detected) and "error:" is one of
|
|
1482 * the possible optional diagnostics -- it can be "error" or "warning"
|
|
1483 * or something else. Finally the line terminates with the actual
|
|
1484 * error message.
|
|
1485 *
|
|
1486 * @param severity the severity of the warning or error
|
|
1487 * @param fmt the printf style format string
|
|
1488 */
|
|
1489 static void nasm_verror_gnu(int severity, const char *fmt, va_list ap)
|
|
1490 {
|
|
1491 const char *currentfile = NULL;
|
|
1492 int32_t lineno = 0;
|
|
1493
|
|
1494 if (is_suppressed_warning(severity))
|
|
1495 return;
|
|
1496
|
|
1497 if (!(severity & ERR_NOFILE))
|
|
1498 src_get(&lineno, ¤tfile);
|
|
1499
|
|
1500 if (!skip_this_pass(severity)) {
|
|
1501 if (currentfile) {
|
|
1502 fprintf(error_file, "%s:%"PRId32": ", currentfile, lineno);
|
|
1503 } else {
|
|
1504 fputs("nasm: ", error_file);
|
|
1505 }
|
|
1506 }
|
|
1507
|
|
1508 nasm_verror_common(severity, fmt, ap);
|
|
1509 }
|
|
1510
|
|
1511 /**
|
|
1512 * MS style error reporting
|
|
1513 * This function prints an error message to error_file in the
|
|
1514 * style used by Visual C and some other Microsoft tools. An example
|
|
1515 * would be:
|
|
1516 * file.asm(50) : error: blah blah blah
|
|
1517 * where file.asm is the name of the file, 50 is the line number on
|
|
1518 * which the error occurs (or is detected) and "error:" is one of
|
|
1519 * the possible optional diagnostics -- it can be "error" or "warning"
|
|
1520 * or something else. Finally the line terminates with the actual
|
|
1521 * error message.
|
|
1522 *
|
|
1523 * @param severity the severity of the warning or error
|
|
1524 * @param fmt the printf style format string
|
|
1525 */
|
|
1526 static void nasm_verror_vc(int severity, const char *fmt, va_list ap)
|
|
1527 {
|
|
1528 const char *currentfile = NULL;
|
|
1529 int32_t lineno = 0;
|
|
1530
|
|
1531 if (is_suppressed_warning(severity))
|
|
1532 return;
|
|
1533
|
|
1534 if (!(severity & ERR_NOFILE))
|
|
1535 src_get(&lineno, ¤tfile);
|
|
1536
|
|
1537 if (!skip_this_pass(severity)) {
|
|
1538 if (currentfile) {
|
|
1539 fprintf(error_file, "%s(%"PRId32") : ", currentfile, lineno);
|
|
1540 } else {
|
|
1541 fputs("nasm: ", error_file);
|
|
1542 }
|
|
1543 }
|
|
1544
|
|
1545 nasm_verror_common(severity, fmt, ap);
|
|
1546 }
|
|
1547
|
|
1548 /*
|
|
1549 * check to see if this is a suppressable warning
|
|
1550 */
|
|
1551 static inline bool is_valid_warning(int severity)
|
|
1552 {
|
|
1553 /* Not a warning at all */
|
|
1554 if ((severity & ERR_MASK) != ERR_WARNING)
|
|
1555 return false;
|
|
1556
|
|
1557 return WARN_IDX(severity) < ERR_WARN_ALL;
|
|
1558 }
|
|
1559
|
|
1560 /**
|
|
1561 * check for suppressed warning
|
|
1562 * checks for suppressed warning or pass one only warning and we're
|
|
1563 * not in pass 1
|
|
1564 *
|
|
1565 * @param severity the severity of the warning or error
|
|
1566 * @return true if we should abort error/warning printing
|
|
1567 */
|
|
1568 static bool is_suppressed_warning(int severity)
|
|
1569 {
|
|
1570 /* Might be a warning but suppresed explicitly */
|
|
1571 if (is_valid_warning(severity))
|
|
1572 return !(warning_state[WARN_IDX(severity)] & WARN_ST_ENABLED);
|
|
1573 else
|
|
1574 return false;
|
|
1575 }
|
|
1576
|
|
1577 static bool warning_is_error(int severity)
|
|
1578 {
|
|
1579 if (is_valid_warning(severity))
|
|
1580 return !!(warning_state[WARN_IDX(severity)] & WARN_ST_ERROR);
|
|
1581 else
|
|
1582 return false;
|
|
1583 }
|
|
1584
|
|
1585 static bool skip_this_pass(int severity)
|
|
1586 {
|
|
1587 /* See if it's a pass-specific warning which should be skipped. */
|
|
1588
|
|
1589 if ((severity & ERR_MASK) > ERR_WARNING)
|
|
1590 return false;
|
|
1591
|
|
1592 /*
|
|
1593 * passn is 1 on the very first pass only.
|
|
1594 * pass0 is 2 on the code-generation (final) pass only.
|
|
1595 * These are the passes we care about in this case.
|
|
1596 */
|
|
1597 return (((severity & ERR_PASS1) && passn != 1) ||
|
|
1598 ((severity & ERR_PASS2) && pass0 != 2));
|
|
1599 }
|
|
1600
|
|
1601 /**
|
|
1602 * common error reporting
|
|
1603 * This is the common back end of the error reporting schemes currently
|
|
1604 * implemented. It prints the nature of the warning and then the
|
|
1605 * specific error message to error_file and may or may not return. It
|
|
1606 * doesn't return if the error severity is a "panic" or "debug" type.
|
|
1607 *
|
|
1608 * @param severity the severity of the warning or error
|
|
1609 * @param fmt the printf style format string
|
|
1610 */
|
|
1611 static void nasm_verror_common(int severity, const char *fmt, va_list args)
|
|
1612 {
|
|
1613 char msg[1024];
|
|
1614 const char *pfx;
|
|
1615
|
|
1616 switch (severity & (ERR_MASK|ERR_NO_SEVERITY)) {
|
|
1617 case ERR_WARNING:
|
|
1618 pfx = "warning: ";
|
|
1619 break;
|
|
1620 case ERR_NONFATAL:
|
|
1621 pfx = "error: ";
|
|
1622 break;
|
|
1623 case ERR_FATAL:
|
|
1624 pfx = "fatal: ";
|
|
1625 break;
|
|
1626 case ERR_PANIC:
|
|
1627 pfx = "panic: ";
|
|
1628 break;
|
|
1629 case ERR_DEBUG:
|
|
1630 pfx = "debug: ";
|
|
1631 break;
|
|
1632 default:
|
|
1633 pfx = "";
|
|
1634 break;
|
|
1635 }
|
|
1636
|
|
1637 vsnprintf(msg, sizeof msg - 64, fmt, args);
|
|
1638 if (is_valid_warning(severity) && WARN_IDX(severity) != ERR_WARN_OTHER) {
|
|
1639 char *p = strchr(msg, '\0');
|
|
1640 snprintf(p, 64, " [-w+%s]", warnings[WARN_IDX(severity)].name);
|
|
1641 }
|
|
1642
|
|
1643 if (!skip_this_pass(severity))
|
|
1644 fprintf(error_file, "%s%s\n", pfx, msg);
|
|
1645
|
|
1646 /* Are we recursing from error_list_macros? */
|
|
1647 if (severity & ERR_PP_LISTMACRO)
|
|
1648 return;
|
|
1649
|
|
1650 /*
|
|
1651 * Don't suppress this with skip_this_pass(), or we don't get
|
|
1652 * pass1 or preprocessor warnings in the list file
|
|
1653 */
|
|
1654 lfmt->error(severity, pfx, msg);
|
|
1655
|
|
1656 if (severity & ERR_USAGE)
|
|
1657 want_usage = true;
|
|
1658
|
|
1659 preproc->error_list_macros(severity);
|
|
1660
|
|
1661 switch (severity & ERR_MASK) {
|
|
1662 case ERR_DEBUG:
|
|
1663 /* no further action, by definition */
|
|
1664 break;
|
|
1665 case ERR_WARNING:
|
|
1666 /* Treat warnings as errors */
|
|
1667 if (warning_is_error(severity))
|
|
1668 terminate_after_phase = true;
|
|
1669 break;
|
|
1670 case ERR_NONFATAL:
|
|
1671 terminate_after_phase = true;
|
|
1672 break;
|
|
1673 case ERR_FATAL:
|
|
1674 if (ofile) {
|
|
1675 fclose(ofile);
|
|
1676 remove(outname);
|
|
1677 ofile = NULL;
|
|
1678 }
|
|
1679 if (want_usage)
|
|
1680 usage();
|
|
1681 exit(1); /* instantly die */
|
|
1682 break; /* placate silly compilers */
|
|
1683 case ERR_PANIC:
|
|
1684 fflush(NULL);
|
|
1685 /* abort(); */ /* halt, catch fire, and dump core */
|
|
1686 if (ofile) {
|
|
1687 fclose(ofile);
|
|
1688 remove(outname);
|
|
1689 ofile = NULL;
|
|
1690 }
|
|
1691 exit(3);
|
|
1692 break;
|
|
1693 }
|
|
1694 }
|
|
1695
|
|
1696 static void usage(void)
|
|
1697 {
|
|
1698 fputs("type `nasm -h' for help\n", error_file);
|
|
1699 }
|