X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/e63c594dd01aa39ff3b6cd2c7ce7ca725c4f210f..8c0714dc0d7d62dff6df6f60b3411b4386ac5a99:/gas/as.c diff --git a/gas/as.c b/gas/as.c index 5a937b38eb..fe44212d7a 100644 --- a/gas/as.c +++ b/gas/as.c @@ -1,5 +1,6 @@ /* as.c - GAS main program. - Copyright (C) 1987, 1990, 1991, 1992, 1994 Free Software Foundation, Inc. + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -14,8 +15,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ /* * Main program for AS; a 32-bit assembler of GNU. @@ -33,24 +35,65 @@ */ #include "ansidecl.h" -#include "libiberty.h" #define COMMON #include "as.h" #include "subsegs.h" #include "output-file.h" +#include "sb.h" +#include "macro.h" + +#ifdef HAVE_SBRK +#ifdef NEED_DECLARATION_SBRK +extern PTR sbrk (); +#endif +#endif static void perform_an_assembly_pass PARAMS ((int argc, char **argv)); +static int macro_expr PARAMS ((const char *, int, sb *, int *)); int listing; /* true if a listing is wanted */ +static char *listing_filename = NULL; /* Name of listing file. */ + +/* Maximum level of macro nesting. */ + +int max_macro_nest = 100; + char *myname; /* argv[0] */ #ifdef BFD_ASSEMBLER segT reg_section, expr_section; segT text_section, data_section, bss_section; #endif +int chunksize = 5000; + +/* To monitor memory allocation more effectively, make this non-zero. + Then the chunk sizes for gas and bfd will be reduced. */ +int debug_memory = 0; + +/* We build a list of defsyms as we read the options, and then define + them after we have initialized everything. */ + +struct defsym_list +{ + struct defsym_list *next; + char *name; + valueT value; +}; + +static struct defsym_list *defsyms; + +/* Keep a record of the itbl files we read in. */ + +struct itbl_file_list +{ + struct itbl_file_list *next; + char *name; +}; + +static struct itbl_file_list *itbl_files; void print_version_id () @@ -81,9 +124,11 @@ Options:\n\ h include high-level source\n\ l include assembly\n\ n omit forms processing\n\ - s include symbols\n"); + s include symbols\n\ + =file set listing file name (must be last sub-option)\n"); fprintf (stream, "\ -D produce assembler debugging messages\n\ +--defsym SYM=VAL define symbol SYM to given value\n\ -f skip whitespace and comment preprocessing\n\ --help show this message and exit\n\ -I DIR add DIR to search list for .include directives\n\ @@ -91,17 +136,22 @@ Options:\n\ -K warn when differences altered for long displacements\n\ -L keep local symbols (starting with `L')\n"); fprintf (stream, "\ +-M,--mri assemble in MRI compatibility mode\n\ -nocpp ignored\n\ -o OBJFILE name the object-file output OBJFILE (default a.out)\n\ -R fold data section into text section\n\ ---statistics print maximum bytes and total seconds used\n\ +--statistics print various measured statistics from execution\n\ --version print assembler version number and exit\n\ -W suppress warnings\n\ +--itbl INSTTBL extend instruction set to include instructions\n\ + matching the specifications defined in file INSTTBL\n\ -w ignored\n\ -X ignored\n\ -Z generate object file even after errors\n"); md_show_usage (stream); + + fprintf (stream, "\nReport bugs to bug-gnu-utils@prep.ai.mit.edu\n"); } #ifdef USE_EMULATIONS @@ -110,7 +160,6 @@ Options:\n\ extern struct emulation mipsbelf, mipslelf, mipself; extern struct emulation mipsbecoff, mipslecoff, mipsecoff; -static const char *emulation_name; static struct emulation *const emulations[] = { EMULATIONS }; static const int n_emulations = sizeof (emulations) / sizeof (emulations[0]); @@ -164,6 +213,7 @@ const char * default_emul_bfd_name () { abort (); + return NULL; } void @@ -214,19 +264,31 @@ parse_args (pargc, pargv) char *shortopts; extern CONST char *md_shortopts; -#ifdef VMS - /* -v takes an argument on VMS, so we don't make it a generic option. */ - CONST char *std_shortopts = "-JKLRWZfa::DI:o:wX"; -#else - CONST char *std_shortopts = "-JKLRWZfa::DI:o:vwX"; + static const char std_shortopts[] = + { + '-', 'J', +#ifndef WORKING_DOT_WORD + /* -K is not meaningful if .word is not being hacked. */ + 'K', #endif - + 'L', 'M', 'R', 'W', 'Z', 'f', 'a', ':', ':', 'D', 'I', ':', 'o', ':', +#ifndef VMS + /* -v takes an argument on VMS, so we don't make it a generic + option. */ + 'v', +#endif + 'w', 'X', + /* New option for extending instruction set (see also --itbl below) */ + 't', + '\0' + }; struct option *longopts; extern struct option md_longopts[]; extern size_t md_longopts_size; static const struct option std_longopts[] = { #define OPTION_HELP (OPTION_STD_BASE) {"help", no_argument, NULL, OPTION_HELP}, + {"mri", no_argument, NULL, 'M'}, #define OPTION_NOCPP (OPTION_STD_BASE + 1) {"nocpp", no_argument, NULL, OPTION_NOCPP}, #define OPTION_STATISTICS (OPTION_STD_BASE + 2) @@ -239,6 +301,16 @@ parse_args (pargc, pargv) {"verbose", no_argument, NULL, OPTION_VERBOSE}, #define OPTION_EMULATION (OPTION_STD_BASE + 6) {"emulation", required_argument, NULL, OPTION_EMULATION}, +#define OPTION_DEFSYM (OPTION_STD_BASE + 7) + {"defsym", required_argument, NULL, OPTION_DEFSYM}, +#define OPTION_INSTTBL (OPTION_STD_BASE + 8) + /* New option for extending instruction set (see also -t above). + The "-t file" or "--itbl file" option extends the basic set of + valid instructions by reading "file", a text file containing a + list of instruction formats. The additional opcodes and their + formats are added to the built-in set of instructions, and + mnemonics for new registers may also be defined. */ + {"itbl", required_argument, NULL, OPTION_INSTTBL} }; /* Construct the option lists from the standard list and the @@ -320,7 +392,14 @@ parse_args (pargc, pargv) break; case OPTION_VERSION: - print_version_id (); + /* This output is intended to follow the GNU standards document. */ + printf ("GNU assembler %s\n", GAS_VERSION); + printf ("Copyright 1996 Free Software Foundation, Inc.\n"); + printf ("\ +This program is free software; you may redistribute it under the terms of\n\ +the GNU General Public License. This program has absolutely no warranty.\n"); + printf ("This assembler was configured for a target of `%s'.\n", + TARGET_ALIAS); exit (EXIT_SUCCESS); case OPTION_EMULATION: @@ -344,18 +423,73 @@ parse_args (pargc, pargv) #endif exit (EXIT_SUCCESS); + case OPTION_DEFSYM: + { + char *s; + long i; + struct defsym_list *n; + + for (s = optarg; *s != '\0' && *s != '='; s++) + ; + if (*s == '\0') + as_fatal ("bad defsym; format is --defsym name=value"); + *s++ = '\0'; + i = strtol (s, (char **) NULL, 0); + n = (struct defsym_list *) xmalloc (sizeof *n); + n->next = defsyms; + n->name = optarg; + n->value = i; + defsyms = n; + } + break; + + case OPTION_INSTTBL: + case 't': + { + /* optarg is the name of the file containing the instruction + formats, opcodes, register names, etc. */ + struct itbl_file_list *n; + + n = (struct itbl_file_list *) xmalloc (sizeof *n); + n->next = itbl_files; + n->name = optarg; + itbl_files = n; + + /* Parse the file and add the new instructions to our internal + table. If multiple instruction tables are specified, the + information from this table gets appended onto the existing + internal table. */ + itbl_files->name = xstrdup (optarg); + if (itbl_parse (itbl_files->name) != 0) + { + fprintf (stderr, "Failed to read instruction table %s\n", + itbl_files->name); + exit (EXIT_SUCCESS); + } + } + break; + case 'J': flag_signed_overflow_ok = 1; break; +#ifndef WORKING_DOT_WORD case 'K': flag_warn_displacement = 1; break; +#endif case 'L': flag_keep_locals = 1; break; + case 'M': + flag_mri = 1; +#ifdef TC_M68K + flag_m68k_mri = 1; +#endif + break; + case 'R': flag_readonly_data_in_text = 1; break; @@ -390,6 +524,10 @@ parse_args (pargc, pargv) case 's': listing |= LISTING_SYMBOLS; break; + case '=': + listing_filename = xstrdup (optarg + 1); + optarg += strlen (listing_filename); + break; default: as_fatal ("invalid listing option `%c'", *optarg); break; @@ -413,17 +551,13 @@ parse_args (pargc, pargv) case 'I': { /* Include file directory */ - char *temp = strdup (optarg); - if (!temp) - as_fatal ("virtual memory exhausted"); + char *temp = xstrdup (optarg); add_include_dir (temp); break; } case 'o': - out_file_name = strdup (optarg); - if (!out_file_name) - as_fatal ("virtual memory exhausted"); + out_file_name = xstrdup (optarg); break; case 'w': @@ -442,13 +576,29 @@ parse_args (pargc, pargv) *pargv = new_argv; } +static void dump_statistics (); +static long start_time; + int main (argc, argv) int argc; char **argv; { + int macro_alternate; + int macro_strip_at; int keep_it; - long start_time = get_run_time (); + + start_time = get_run_time (); + + + if (debug_memory) + { +#ifdef BFD_ASSEMBLER + extern long _bfd_chunksize; + _bfd_chunksize = 64; +#endif + chunksize = 64; + } #ifdef HOST_SPECIAL_INIT HOST_SPECIAL_INIT (argc, argv); @@ -468,6 +618,7 @@ main (argc, argv) hex_init (); #ifdef BFD_ASSEMBLER bfd_init (); + bfd_set_error_program_name (myname); #endif #ifdef USE_EMULATIONS @@ -478,10 +629,27 @@ main (argc, argv) symbol_begin (); frag_init (); subsegs_begin (); + parse_args (&argc, &argv); read_begin (); input_scrub_begin (); - PROGRESS (1); - parse_args (&argc, &argv); + expr_begin (); + + if (flag_print_statistics) + xatexit (dump_statistics); + + macro_alternate = 0; + macro_strip_at = 0; +#ifdef TC_I960 + macro_strip_at = flag_mri; +#endif +#ifdef TC_A29K + /* For compatibility with the AMD 29K family macro assembler + specification. */ + macro_alternate = 1; + macro_strip_at = 1; +#endif + + macro_init (macro_alternate, flag_mri, macro_strip_at, macro_expr); PROGRESS (1); @@ -494,21 +662,34 @@ main (argc, argv) tc_init_after_args (); #endif + itbl_init (); + + /* Now that we have fully initialized, and have created the output + file, define any symbols requested by --defsym command line + arguments. */ + while (defsyms != NULL) + { + symbolS *sym; + struct defsym_list *next; + + sym = symbol_new (defsyms->name, absolute_section, defsyms->value, + &zero_address_frag); + symbol_table_insert (sym); + next = defsyms->next; + free (defsyms); + defsyms = next; + } + PROGRESS (1); perform_an_assembly_pass (argc, argv); /* Assemble it. */ -#ifdef TC_I960 - brtab_emit (); -#endif -/* start-sanitize-rce */ -#ifdef TC_RCE - dump_literals(0); + +#ifdef md_end + md_end (); #endif -/* end-sanitize-rce */ if (seen_at_least_1_file () - && !((had_warnings () && flag_always_generate_output) - || had_errors () > 0)) + && (flag_always_generate_output || had_errors () == 0)) keep_it = 1; else keep_it = 0; @@ -517,7 +698,7 @@ main (argc, argv) write_object_file (); #ifndef NO_LISTING - listing_print (""); + listing_print (listing_filename); #endif #ifndef OBJ_VMS /* does its own file handling */ @@ -527,38 +708,50 @@ main (argc, argv) output_file_close (out_file_name); #endif + if (had_errors () > 0 && ! flag_always_generate_output) + keep_it = 0; + if (!keep_it) unlink (out_file_name); input_scrub_end (); -#ifdef md_end - md_end (); -#endif END_PROGRESS (myname); - if (flag_print_statistics) - { - extern char **environ; + /* Use xexit instead of return, because under VMS environments they + may not place the same interpretation on the value given. */ + if (had_errors () > 0) + xexit (EXIT_FAILURE); + xexit (EXIT_SUCCESS); +} + +static void +dump_statistics () +{ + extern char **environ; #ifdef HAVE_SBRK - char *lim = (char *) sbrk (0); + char *lim = (char *) sbrk (0); #endif - long run_time = get_run_time () - start_time; + long run_time = get_run_time () - start_time; - fprintf (stderr, "%s: total time in assembly: %ld.%06ld\n", - myname, run_time / 1000000, run_time % 1000000); + fprintf (stderr, "%s: total time in assembly: %ld.%06ld\n", + myname, run_time / 1000000, run_time % 1000000); #ifdef HAVE_SBRK - fprintf (stderr, "%s: data size %ld\n", - myname, (long) (lim - (char *) &environ)); + fprintf (stderr, "%s: data size %ld\n", + myname, (long) (lim - (char *) &environ)); #endif - } - /* Use exit instead of return, because under VMS environments they - may not place the same interpretation on the value given. */ - if ((had_warnings () && flag_always_generate_output) - || had_errors () > 0) - exit (EXIT_FAILURE); - exit (EXIT_SUCCESS); + subsegs_print_statistics (stderr); + write_print_statistics (stderr); + symbol_print_statistics (stderr); + read_print_statistics (stderr); + +#ifdef tc_print_statistics + tc_print_statistics (stderr); +#endif +#ifdef obj_print_statistics + obj_print_statistics (stderr); +#endif } @@ -646,6 +839,10 @@ perform_an_assembly_pass (argc, argv) and sections already created, in BFD_ASSEMBLER mode. */ md_begin (); +#ifdef obj_begin + obj_begin (); +#endif + argv++; /* skip argv[0] */ argc--; /* skip argv[0] */ while (argc--) @@ -663,4 +860,32 @@ perform_an_assembly_pass (argc, argv) read_a_source_file (""); } /* perform_an_assembly_pass() */ +/* The interface between the macro code and gas expression handling. */ + +static int +macro_expr (emsg, idx, in, val) + const char *emsg; + int idx; + sb *in; + int *val; +{ + char *hold; + expressionS ex; + + sb_terminate (in); + + hold = input_line_pointer; + input_line_pointer = in->ptr + idx; + expression (&ex); + idx = input_line_pointer - in->ptr; + input_line_pointer = hold; + + if (ex.X_op != O_constant) + as_bad ("%s", emsg); + + *val = (int) ex.X_add_number; + + return idx; +} + /* end of as.c */