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 + -
显示快捷键?