nasm.c
来自「开源的nasm编译器源码,研究编译器原理很有帮且」· C语言 代码 · 共 1,683 行 · 第 1/4 页
C
1,683 行
/* The Netwide Assembler main program module * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is * redistributable under the licence given in the file "Licence" * distributed in the NASM archive. */#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "nasm.h"#include "nasmlib.h"#include "insns.h"#include "preproc.h"#include "parser.h"#include "eval.h"#include "assemble.h"#include "labels.h"#include "outform.h"#include "listing.h"struct forwrefinfo { /* info held on forward refs. */ int lineno; int operand;};static int get_bits (char *value);static unsigned long get_cpu (char *cpu_str);static void parse_cmdline (int, char **);static void assemble_file (char *);static int getkw (char **directive, char **value);static void register_output_formats(void);static void report_error_gnu (int severity, const char *fmt, ...);static void report_error_vc (int severity, const char *fmt, ...);static void report_error_common (int severity, const char *fmt, va_list args);static int is_suppressed_warning (int severity);static void usage(void);static efunc report_error;static int using_debug_info, opt_verbose_info;int tasm_compatible_mode = FALSE;int pass0;static char inname[FILENAME_MAX];static char outname[FILENAME_MAX];static char listname[FILENAME_MAX];static int globallineno; /* for forward-reference tracking *//* static int pass = 0; */static struct ofmt *ofmt = NULL;static FILE *error_file; /* Where to write error messages */static FILE *ofile = NULL;int optimizing = -1; /* number of optimization passes to take */static int sb, cmd_sb = 16; /* by default */static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */int global_offset_changed; /* referenced in labels.c */static loc_t location;int in_abs_seg; /* Flag we are in ABSOLUTE seg */long abs_seg; /* ABSOLUTE segment basis */long abs_offset; /* ABSOLUTE offset */static struct RAA *offsets;static struct SAA *forwrefs; /* keep track of forward references */static struct forwrefinfo *forwref;static Preproc *preproc;enum op_type { op_normal, /* Preprocess and assemble */ op_preprocess, /* Preprocess only */ op_depend /* Generate dependencies */};static enum op_type operating_mode;/* * Which of the suppressible warnings are suppressed. Entry zero * doesn't do anything. Initial defaults are given here. */static char suppressed[1+ERR_WARN_MAX] = { 0, TRUE, TRUE, TRUE, FALSE, TRUE};/* * The option names for the suppressible warnings. As before, entry * zero does nothing. */static const char *suppressed_names[1+ERR_WARN_MAX] = { NULL, "macro-params", "macro-selfref", "orphan-labels", "number-overflow", "gnu-elf-extensions"};/* * The explanations for the suppressible warnings. As before, entry * zero does nothing. */static const char *suppressed_what[1+ERR_WARN_MAX] = { NULL, "macro calls with wrong no. of params", "cyclic macro self-references", "labels alone on lines without trailing `:'", "numeric constants greater than 0xFFFFFFFF", "using 8- or 16-bit relocation in ELF, a GNU extension"};/* * This is a null preprocessor which just copies lines from input * to output. It's used when someone explicitly requests that NASM * not preprocess their source file. */static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);static char *no_pp_getline (void);static void no_pp_cleanup (int);static Preproc no_pp = { no_pp_reset, no_pp_getline, no_pp_cleanup};/* * get/set current offset... */#define GET_CURR_OFFS (in_abs_seg?abs_offset:\ raa_read(offsets,location.segment))#define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\ (void)(offsets=raa_write(offsets,location.segment,(x))))static int want_usage;static int terminate_after_phase;int user_nolist = 0; /* fbk 9/2/00 */static void nasm_fputs(const char *line, FILE *outfile){ if (outfile) { fputs(line, outfile); fputc('\n', outfile); } else puts(line);}int main(int argc, char **argv){ pass0 = 1; want_usage = terminate_after_phase = FALSE; report_error = report_error_gnu; nasm_set_malloc_error (report_error); offsets = raa_init(); forwrefs = saa_init ((long)sizeof(struct forwrefinfo)); preproc = &nasmpp; operating_mode = op_normal; error_file = stderr; seg_init(); register_output_formats(); parse_cmdline(argc, argv); if (terminate_after_phase) { if (want_usage) usage(); return 1; } /* If debugging info is disabled, suppress any debug calls */ if (!using_debug_info) ofmt->current_dfmt = &null_debug_form; if (ofmt->stdmac) pp_extra_stdmac (ofmt->stdmac); parser_global_info (ofmt, &location); eval_global_info (ofmt, lookup_label, &location); /* define some macros dependent of command-line */ { char temp [64]; sprintf (temp, "__OUTPUT_FORMAT__=%s\n", ofmt->shortname); pp_pre_define (temp); } switch ( operating_mode ) { case op_depend: { char *line; preproc->reset (inname, 0, report_error, evaluate, &nasmlist); if (outname[0] == '\0') ofmt->filename (inname, outname, report_error); ofile = NULL; fprintf(stdout, "%s: %s", outname, inname); while ( (line = preproc->getline()) ) nasm_free (line); preproc->cleanup(0); putc('\n', stdout); } break; case op_preprocess: { char *line; char *file_name = NULL; long prior_linnum=0; int lineinc=0; if (*outname) { ofile = fopen(outname, "w"); if (!ofile) report_error (ERR_FATAL | ERR_NOFILE, "unable to open output file `%s'", outname); } else ofile = NULL; location.known = FALSE;/* pass = 1; */ preproc->reset (inname, 2, report_error, evaluate, &nasmlist); while ( (line = preproc->getline()) ) { /* * We generate %line directives if needed for later programs */ long linnum = prior_linnum += lineinc; int altline = src_get(&linnum, &file_name); if (altline) { if (altline==1 && lineinc==1) nasm_fputs("", ofile); else { lineinc = (altline != -1 || lineinc!=1); fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n", linnum, lineinc, file_name); } prior_linnum = linnum; } nasm_fputs(line, ofile); nasm_free (line); } nasm_free(file_name); preproc->cleanup(0); if (ofile) fclose(ofile); if (ofile && terminate_after_phase) remove(outname); } break; case op_normal: { /* * We must call ofmt->filename _anyway_, even if the user * has specified their own output file, because some * formats (eg OBJ and COFF) use ofmt->filename to find out * the name of the input file and then put that inside the * file. */ ofmt->filename (inname, outname, report_error); ofile = fopen(outname, "wb"); if (!ofile) { report_error (ERR_FATAL | ERR_NOFILE, "unable to open output file `%s'", outname); } /* * We must call init_labels() before ofmt->init() since * some object formats will want to define labels in their * init routines. (eg OS/2 defines the FLAT group) */ init_labels (); ofmt->init (ofile, report_error, define_label, evaluate); assemble_file (inname); if (!terminate_after_phase) { ofmt->cleanup (using_debug_info); cleanup_labels (); } else { /* * We had an fclose on the output file here, but we * actually do that in all the object file drivers as well, * so we're leaving out the one here. * fclose (ofile); */ remove(outname); if (listname[0]) remove(listname); } } break; } if (want_usage) usage(); raa_free (offsets); saa_free (forwrefs); eval_cleanup (); nasmlib_cleanup (); if (terminate_after_phase) return 1; else return 0;}/* * Get a parameter for a command line option. * First arg must be in the form of e.g. -f... */static char *get_param (char *p, char *q, int *advance){ *advance = 0; if (p[2]) /* the parameter's in the option */ { p += 2; while (isspace(*p)) p++; return p; } if (q && q[0]) { *advance = 1; return q; } report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, "option `-%c' requires an argument", p[1]); return NULL;}struct textargs{ const char *label; int value;};#define OPT_PREFIX 0#define OPT_POSTFIX 1struct textargs textopts[] ={ {"prefix",OPT_PREFIX}, {"postfix",OPT_POSTFIX}, {NULL,0}};int stopoptions = 0;static int process_arg (char *p, char *q){ char *param; int i, advance = 0; if (!p || !p[0]) return 0; if (p[0]=='-' && ! stopoptions) { switch (p[1]) { case 's': error_file = stdout; break; case 'o': /* these parameters take values */ case 'O': case 'f': case 'p': case 'P': case 'd': case 'D': case 'i': case 'I': case 'l': case 'E': case 'F': case 'X': case 'u': case 'U': if ( !(param = get_param (p, q, &advance)) ) break; if (p[1]=='o') { /* output file */ strcpy (outname, param); } else if (p[1]=='f') { /* output format */ ofmt = ofmt_find(param); if (!ofmt) { report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, "unrecognised output format `%s' - " "use -hf for a list", param); } else ofmt->current_dfmt = ofmt->debug_formats[0]; } else if (p[1]=='O') { /* Optimization level */ int opt; opt = -99; while (*param) { if (isdigit(*param)) { opt = atoi(param); while(isdigit(*++param)) ; if (opt<=0) optimizing = -1; /* 0.98 behaviour */ else if (opt==1) optimizing = 0; /* Two passes, 0.98.09 behavior */ else optimizing = opt; /* Multiple passes */ } else { if (*param == 'v' || *param == '+') { ++param; opt_verbose_info = TRUE; opt = 0; } else { /* garbage */ opt = -99; break; } } } /* while (*param) */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?