⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nasm.c

📁 一个汇编语言编译器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 "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 void report_error (int, char *, ...);
static void parse_cmdline (int, char **);
static void assemble_file (char *);
static int getkw (char *buf, char **value);
static void register_output_formats(void);
static void usage(void);

static int using_debug_info;

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;
static struct ofmt *ofmt = NULL;

static FILE *error_file;	       /* Where to write error messages */

static FILE *ofile = NULL;
static int sb = 16;		       /* by default */

static loc_t location;
int          in_abs_seg;	       /* Flag we are in ABSOLUTE seg */
static long  abs_seg;

static struct RAA *offsets;
static long abs_offset;

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;

/* used by error function to report location */

/*
 * 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, FALSE
};

/*
 * The option names for the suppressible warnings. As before, entry
 * zero does nothing.
 */
static char *suppressed_names[1+ERR_WARN_MAX] = {
    NULL, "macro-params", "orphan-labels", "number-overflow"
};

/*
 * The explanations for the suppressible warnings. As before, entry
 * zero does nothing.
 */
static char *suppressed_what[1+ERR_WARN_MAX] = {
    NULL, "macro calls with wrong no. of params",
    "labels alone on lines without trailing `:'",
    "numeric constants greater than 0xFFFFFFFF"
};

/*
 * 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 (void);
static Preproc no_pp = {
    no_pp_reset,
    no_pp_getline,
    no_pp_cleanup
};

/*
 * get/set current offset...
 */
#define get_curr_ofs (in_abs_seg?abs_offset:\
		      raa_read(offsets,location.segment))
#define set_curr_ofs(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;

static void nasm_fputs(char *line, FILE *ofile) 
{
    if (ofile) {
	fputs(line, ofile);
	fputc('\n', ofile);
    } else
	puts(line);
}

int main(int argc, char **argv) 
{
    want_usage = terminate_after_phase = FALSE;

    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 (ofmt->stdmac)
	pp_extra_stdmac (ofmt->stdmac);
    parser_global_info (ofmt, &location);
    eval_global_info (ofmt, lookup_label, &location);

    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;
	printf("%s: %s", outname, inname);
	while ( (line = preproc->getline()) )
	  nasm_free (line);
	preproc->cleanup();
	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;
      
      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();
      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;
}

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 '-':			/* -- => stop processing options */
	      stopoptions = 1;
	      break;
	  case 's':
	      error_file = stdout;
	      break;
	  case 'o':		       /* these parameters take values */
	  case 'f':
	  case 'p':
	  case 'd':
	  case 'D':
	  case 'i':
	  case 'l':
	  case 'E':
	  case 'F':
	    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]=='P' || p[1]=='p') {    /* pre-include */
		pp_pre_include (param);
	    } else if (p[1]=='D' || p[1]=='d') {    /* pre-define */
		pp_pre_define (param);
	    } else if (p[1]=='U' || p[1]=='u') {    /* un-define */
		pp_pre_undefine (param);
	    } else if (p[1]=='I' || p[1]=='i') {    /* include search path */
		pp_include_path (param);
	    } else if (p[1]=='l') {    /* listing file */
		strcpy (listname, param);
	    } else if (p[1]=='E') {    /* error messages file */
	        error_file = fopen(param, "wt");
		if ( !error_file ) {
		  error_file = stderr; /* Revert to default! */
		  report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
				"cannot open file `%s' for error messages",
				param);
		}
	    } else if (p[1] == 'F') {  /* specify debug format */
	        ofmt->current_dfmt = dfmt_find(ofmt, param);
	        if (!ofmt->current_dfmt) {
	            report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
	    	    		  "unrecognized debug format `%s' for"
			    	  " output format `%s'",
				  param, ofmt->shortname);
                }
            }
	    break;
	  case 'g':
	    using_debug_info = TRUE;
	    break;
	  case 'h':
	    printf("usage: nasm [-@ response file] [-o outfile] [-f format] "
		   "[-l listfile]\n"
		   "            [options...] [--] filename\n"
		   "    or nasm -r   for version info\n\n"
		   "    -e          preprocess only (writes output to stdout by default)\n"
		   "    -a          don't preprocess (assemble only)\n"
		   "    -M          generate Makefile dependencies on stdout\n\n"
		   "    -E<file>    redirect error messages to file\n"
		   "    -s          redirect error messages to stdout\n\n"
		   "    -g          enable debug info\n"
		   "    -F format   select a debugging format\n\n"
		   "    -I<path>    adds a pathname to the include file path\n"
		   "    -P<file>    pre-includes a file\n"
		   "    -D<macro>[=<value>] pre-defines a macro\n"
		   "    -U<macro>   undefines a macro\n"
		   "    -w+foo      enables warnings about foo; -w-foo disables them\n"
		   "where foo can be:\n");
	    for (i=1; i<=ERR_WARN_MAX; i++)
		printf("    %-16s%s (default %s)\n",
		       suppressed_names[i], suppressed_what[i],
		       suppressed[i] ? "off" : "on");
	    printf ("\nresponse files should contain command line parameters"
		    ", one per line.\n");
	    if (p[2] == 'f') {
		printf("\nvalid output formats for -f are"
		       " (`*' denotes default):\n");
		ofmt_list(ofmt, stdout);
	    }
	    else {
		printf ("\nFor a list of valid output formats, use -hf.\n");
		printf ("For a list of debug formats, use -f <form> -y.\n");
	    }
	    exit (0);		       /* never need usage message here */
	    break;
          case 'y':
	    printf("\nvalid debug formats for '%s' output format are"
		   " ('*' denotes default):\n",
		ofmt->shortname);
	    dfmt_list(ofmt, stdout);
	    exit(0);
	    break;
	  case 'r':
	    printf("NASM version %s\n", NASM_VER);
#ifdef DEBUG
	    printf("Compiled with -DDEBUG on " __DATE__ "\n");
#endif
	    exit (0);		       /* never need usage message here */
	    break;
	  case 'e':		       /* preprocess only */
	    operating_mode = op_preprocess;
	    break;
	  case 'a':		       /* assemble only - don't preprocess */
	    preproc = &no_pp;
	    break;
	  case 'w':
	    if (p[2] != '+' && p[2] != '-') {
		report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
			      "invalid option to `-w'");
	    } else {
		for (i=1; i<=ERR_WARN_MAX; i++)
		    if (!nasm_stricmp(p+3, suppressed_names[i]))
			break;
		if (i <= ERR_WARN_MAX)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -