diff options
author | jdp <jdp@FreeBSD.org> | 1998-03-01 22:58:51 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1998-03-01 22:58:51 +0000 |
commit | 2cbd0590cd191c81b59e94970f4c40c371f9e415 (patch) | |
tree | b7676f996414b979dcbb7de92a3e86b97320d023 /contrib/binutils/gas | |
download | FreeBSD-src-2cbd0590cd191c81b59e94970f4c40c371f9e415.zip FreeBSD-src-2cbd0590cd191c81b59e94970f4c40c371f9e415.tar.gz |
Initial import of GNU binutils version 2.8.1. Believe it or not,
this is heavily stripped down.
Diffstat (limited to 'contrib/binutils/gas')
117 files changed, 77931 insertions, 0 deletions
diff --git a/contrib/binutils/gas/CONTRIBUTORS b/contrib/binutils/gas/CONTRIBUTORS new file mode 100644 index 0000000..14ef05c --- /dev/null +++ b/contrib/binutils/gas/CONTRIBUTORS @@ -0,0 +1,100 @@ +(This file is under construction.) -*- text -*- + +If you've contributed to gas and your name isn't listed here, it is +not meant as a slight. I just don't know about it. Email me, +raeburn@cygnus.com and I'll correct the situation. + +This file will eventually be deleted: The general info will go into +the documentation, and info on specific files will go into an AUTHORS +file, as requested by the FSF. + +++++++++++++++++ + +Dean Elsner wrote the original gas for vax. [more details?] + +Jay Fenlason maintained gas for a while, adding support for +gdb-specific debug information and the 68k series machines, most of +the preprocessing pass, and extensive changes in messages.c, +input-file.c, write.c. + +K. Richard Pixley maintained gas for a while, adding various +enhancements and many bug fixes, including merging support for several +processors, breaking gas up to handle multiple object file format +backends (including heavy rewrite, testing, an integration of the coff +and b.out backends), adding configuration including heavy testing and +verification of cross assemblers and file splits and renaming, +converted gas to strictly ansi C including full prototypes, added +support for m680[34]0 & cpu32, considerable work on i960 including a +coff port (including considerable amounts of reverse engineering), a +sparc opcode file rewrite, decstation, rs6000, and hp300hpux host +ports, updated "know" assertions and made them work, much other +reorganization, cleanup, and lint. + +Ken Raeburn currently maintains gas, and wrote the high-level BFD +interface code to replace most of the code in format-specific I/O +modules. + +The original Vax-VMS support was contributed by David L. Kashtan. +Eric Youngdale and Pat Rankin have done much work with it since. + +The Intel 80386 machine description was written by Eliot Dresselhaus. + +Minh Tran-Le at IntelliCorp contributed some AIX 386 support. + +The Motorola 88k machine description was contributed by Devon Bowen of +Buffalo University and Torbjorn Granlund of the Swedish Institute of +Computer Science. + +Keith Knowles at the Open Software Foundation wrote the original MIPS +back end (tc-mips.c, tc-mips.h), and contributed Rose format support +that hasn't been merged in yet. Ralph Campbell worked with the MIPS +code to support a.out format. + +Support for the Zilog Z8k and Hitachi H8/300, H8/500 and SH processors +(tc-z8k, tc-h8300, tc-h8500, tc-sh), and IEEE 695 object file format +(obj-ieee), was written by Steve Chamberlain of Cygnus Support. Steve +also modified the COFF back end (obj-coffbfd) to use BFD for some +low-level operations, for use with the Hitachi, 29k and Zilog targets. + +John Gilmore built the AMD 29000 support, added .include support, and +simplified the configuration of which versions accept which +pseudo-ops. He updated the 68k machine description so that Motorola's +opcodes always produced fixed-size instructions (e.g. jsr), while +synthetic instructions remained shrinkable (jbsr). John fixed many +bugs, including true tested cross-compilation support, and one bug in +relaxation that took a week and required the proverbial one-bit fix. + +Ian Lance Taylor of Cygnus Support merged the Motorola and MIT +syntaxes for the 68k, completed support for some COFF targets (68k, +i386 SVR3, and SCO Unix), wrote the ECOFF support based on Michael +Meissner's mips-tfile program, wrote the PowerPC and RS/6000 support, +and made a few other minor patches. + +David Edelsohn contributed fixes for the PowerPC and AIX support. + +Steve Chamberlain made gas able to generate listings. + +Support for the HP9000/300 was contributed by Glenn Engel of HP. + +Support for ELF format files has been worked on by Mark Eichin of +Cygnus Support (original, incomplete implementation), Pete Hoogenboom +at the University of Utah (HPPA mainly), Michael Meissner of the Open +Software Foundation (i386 mainly), and Ken Raeburn of Cygnus Support +(sparc, initial 64-bit support). + +Several engineers at Cygnus Support have also provided many small bug +fixes and configuration enhancements. + +The initial Alpha support was contributed by Carnegie-Mellon +University. Additional work was done by Ken Raeburn of Cygnus +Support. Richard Henderson then rewrote much of the Alpha support. + +Ian Dall updated the support code for the National Semiconductor 32000 +series, and added support for Mach 3 and NetBSD running on the PC532. + +Klaus Kaempf ported the assembler and the binutils to openVMS/Alpha. + +Many others have contributed large or small bugfixes and enhancements. If +you've contributed significant work and are not mentioned on this list, and +want to be, let us know. Some of the history has been lost; we aren't +intentionally leaving anyone out. diff --git a/contrib/binutils/gas/ChangeLog b/contrib/binutils/gas/ChangeLog new file mode 100644 index 0000000..d513e07 --- /dev/null +++ b/contrib/binutils/gas/ChangeLog @@ -0,0 +1,4849 @@ +Mon May 26 13:24:25 1997 Ian Lance Taylor <ian@cygnus.com> + + * doc/as.texinfo: Don't use @value in section names or index + entries; it confuses texinfo.tex. + +Tue May 13 10:42:20 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (VERSION): Set to 2.8.1. + +Mon May 12 13:33:08 1997 H.J. Lu <hjl@gnu.ai.mit.edu> + + * config/tc-i386.c (pi): Check for RegMMX. + +Thu May 8 11:10:15 1997 Ian Lance Taylor <ian@cygnus.com> + + * expr.c (expr): When subtracting values in the same frag, + subtract X_add_number rather than adding it. + +Wed May 7 15:39:48 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (write_object_file): Just pass NULL to + md_do_align, not the address of a char holding NOP_OPCODE. + +Tue May 6 12:18:09 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i386.c (md_section_align): If a.out and BFD, force + section size to be aligned. + +Mon May 5 17:16:55 1997 Ian Lance Taylor <ian@cygnus.com> + + * cond.c: Include "macro.h". + (struct conditional_frame): Add macro_nest field. + (initialize_cframe): Initialize macro_nest. + (cond_finish_check): Add nest parameter. Change all callers. + (cond_exit_macro): New function. + * as.h (cond_finish_check): Update declaration. + (cond_exit_macro): Declare. + * input-scrub.c (macro_nest): Make globally visible. + (input_scrub_next_buffer): Call cond_finish_check. + * macro.h (macro_nest): Declare. + * read.c (s_mexit): Call cond_exit_macro. + + * config/tc-i386.h (RegMMX): Define. + * config/tc-i386.c (pi): Check for all register types. + (type_names): Add RegMMX. + (md_assemble): Handle RegMMX. + +Wed Apr 30 12:47:00 1997 Manfred Hollstein <manfred@s-direktnet.de> + + * config/obj-coff.c (c_section_symbol): Clear the LOCAL bit #ifdef + TE_DELTA. + +Tue Apr 29 20:23:10 1997 Jim Wilson <wilson@cygnus.com> + + * config/tc-mips.c (nopic_need_relax): Add new parameter + before_relaxing. Use it when testing ecoff_extern_size. + (load_address, macro, md_estimate_size_before_relax): Fix all + callers. + +Tue Apr 29 19:52:47 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (coff_header_append): Don't reset string_size + each time through the loop. + +Fri Apr 25 14:17:46 1997 H.J. Lu <hjl@gnu.ai.mit.edu> + + * Makefile.in (DISTSTUFF): Add itbl-parse.h. + +Fri Apr 25 12:03:15 1997 Ian Lance Taylor <ian@cygnus.com> + + * doc/internals.texi (Porting GAS): Correct documentation for + current configure handling of targ-cpu.h, et. al. + (CPU backend): Document listing macros. + +Sat Apr 19 23:09:25 1997 Niklas Hallqvist <niklas@petra.appli.se> + + * configure.in (i386-*-openbsd*, m68k-*-openbsd*, + mips-dec-openbsd*, ppc-*-*bsd*, ns32k-pc532-openbsd*, + sparc-*-openbsd*): New targets. + * configure: Rebuild. + +Sat Apr 19 22:52:03 1997 Jim Wilson <wilson@cygnus.com> + + * config/obj-elf.c (elf_frob_symbol): If TC_MIPS, set BSF_OBJECT + for all undefined symbols. + +Fri Apr 18 11:51:35 1997 Niklas Hallqvist <niklas@appli.se> + + * configure.in (alpha*-*-openbsd*): New target. + * configure: Rebuild. + +Thu Apr 17 13:59:47 1997 Per Fogelstrom <pefo@openbsd.org> + + * configure.in (mips-*-openbsd*): New target. + * configure: Rebuild. + +Tue Apr 15 18:11:44 1997 Gavin Koch <gavin@cygnus.com> + + * config/tc-mips.c (insn_uses_reg): Correct test for fpr pairs. + +Mon Apr 14 11:59:08 1997 Ian Lance Taylor <ian@cygnus.com> + + From Thomas Graichen <graichen@rzpd.de>: + * Makefile.in: Always use $(SHELL) when running move-if-change. + * configure.in: Use ${CONFIG_SHELL} when running $ac_config_sub. + * configure: Rebuild. + +Thu Apr 10 14:40:00 1997 Doug Evans <dje@canuck.cygnus.com> + + * cgen.c (cgen_parse_operand): Renamed from cgen_asm_parse_operand. + New argument `want'. Update enum cgen_parse_operand_result values. + Initialize if CGEN_PARSE_OPERAND_INIT. + * config/tc-m32r.c (md_begin): Set cgen_parse_operand_fn. + (md_assemble): Call cgen_asm_init_parse. + Update call to m32r_cgen_assemble_insn, call as_bad if assembly failed. + +Wed Apr 9 11:49:41 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (m68k_ip): Handle #j. + +Mon Apr 7 14:58:22 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (pa_subspace_start): If OBJ_ELF, then always return + zero. + * config/tc-hppa.h (tc_frob_symbol): Don't reset the value of the + symbol for OBJ_ELF anymore. + +Mon Apr 7 10:54:59 1997 Doug Evans <dje@canuck.cygnus.com> + + * Makefile.in: Regenerate dependencies. + (TARG_CPU): New variable. + (cgen.o): Depend on cgen.h, $(TARG_CPU)-opc.h. + (.dep1): Delete creating of cgen-opc.h. + (.tcdep): Put proper contents in cgen-opc.h. + * configure.in (m32r): Delete setting of extra_files, extra_links. + (AC_OUTPUT): Create cgen-opc.h. + * configure: Regenerated. + +Sat Apr 5 13:19:12 1997 Klaus Kaempf <kkaempf@progis.de> + + * makefile.vms: Update to build gasp.exe. + +Fri Apr 4 16:10:02 1997 Doug Evans <dje@canuck.cygnus.com> + + * write.c (relax_frag): Make non-static. + * write.h (relax_frag): Add prototype for. + * config/tc-m32r.h (md_do_align): New arg `max'. + * config/tc-m32r.c (m32r_do_align): Likewise. + Update calls to frag_align, frag_align_pattern. + (fill_insn): Update call to m32r_do_align. + (m32r_scomm): Update call to frag_align. + + * config/tc-m32r.[ch]: New files. + * cgen.c: New file. + * Makefile.in (CPU_TYPES): Add m32r. + (TARGET_CPU_CFILES): Add tc-m32r.c. + (TARGET_CPU_HFILES): Add tc-m32r.h. + (DISTCLEAN_HERE): Add cgen-opc.h. + (.dep1,.tcdep): Create empty cgen-opc.h. + (cgen.o): Add dependencies. + (dependencies): Regenerate. + * as.h (struct frag): New member fr_targ. + (fr_pcrel_adjust,fr_bsr): Move into union fr_targ.ns32k. + * conf.in (USING_CGEN): New macro. + * configure.in (m32r-*-*): Add entry for. + Add cgen.o to extra_objects. + * configure: Regenerate. + * frags.c (frag_var): fr_pcrel_adjust renamed to + fr_targ.ns32k.pcrel_adjust. fr_bsr renamed to fr_targ.ns32k.bsr. + (frag_variant): Likewise. + * write.c (relax_frag): Likewise. + * config/tc-ns32k.c (*): Likewise. + +Fri Apr 4 13:26:10 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-hppa.h (TC_EOL_IN_INSN): Check explicitly for '!', + rather than for any end of line character. + + * config/tc-mips.c: Protect uses of STO_MIPS16 with an ifdef of + OBJ_ELF, rather than of S_GET_OTHER. + + * Makefile.in (DISTCLEAN_HERE): Add site.exp and site.bak. + +Thu Apr 3 18:52:39 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (VERSION): Set to 2.8. + +Wed Apr 2 12:24:10 1997 Ian Lance Taylor <ian@cygnus.com> + + * COPYING: Update FSF address. + + * config/tc-mips.c (mips16_macro): Handle M_DMUL and M_MUL. + +Tue Apr 1 18:29:47 1997 Jim Wilson <wilson@cygnus.com> + + * config/tc-mips.c (md_begin): Don't set interlocks for 4100. + +Tue Apr 1 16:24:28 1997 Klaus Kaempf <kkaempf@progis.de> + + * config-gas.com: Update to handle both vax and alpha. + * makefile.vms: Update to use config-gas. + * conf-a-gas.com: Remove file. + +Tue Apr 1 16:08:21 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in: Remove unnecessary itbl-parse.h, ibtl-parse.c, and + itbl-lex.c dependencies. Remove rules for itbl-lex.o, + itbl-parse.o, and itbl-ops.o; just use the normal .c.o rule. + +Tue Apr 1 00:07:30 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c: Only compile tc_coff_symbol_emit_hook and + tc_coff_sizemachdep if OBJ_COFF. + +Mon Mar 31 23:53:44 1997 H.J. Lu <hjl@gnu.ai.mit.edu> + + * config/tc-ppc.c (register_name): Declare. + +Mon Mar 31 16:31:04 1997 Joel Sherrill <joel@oarcorp.com> + + * configure.in (hppa*-*-rtems*): New target, like hppa-*-*elf*. + * configure: Rebuild. + +Mon Mar 31 14:15:19 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_pseudo_table): Add "stabn". + (mips16_mark_labels): New static function. + (append_insn): Call mips16_mark_labels. + (mips_emit_delays): Likewise. + (s_insn): Likewise. Don't call mips_clear_insn_labels. + (s_mips_stab): New static function. + + * configure.in: Use ELF for mips-*-gnu*. + * configure: Rebuild. + +Mon Mar 31 14:01:40 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/tc-m68k.h (TARGET_FORMAT): Set to "coff-m68k-sysv" if + TE_DELTA. + +Fri Mar 28 18:03:19 1997 Alan Modra <alan@spri.levels.unisa.edu.au> + + * configure.in: Add AC_ARG_ENABLE for commonbfdlib. If it is set, + set OPCODES_LIB to empty. + * configure: Rebuild. + +Fri Mar 28 15:25:24 1997 H.J. Lu <hjl@gnu.ai.mit.edu> + + * configure.in (sparc-*-linux*aout*, sparc-*-linux*): New + targets. + * configure: Rebuild. + +Fri Mar 28 13:08:33 1997 Ian Lance Taylor <ian@cygnus.com> + + * itbl-parse.y (yyerror): Make static. Declare. + + From Ralf Baechle <ralf@gnu.ai.mit.edu>: + * configure.in: Set emulations for mips-*-linux*-*. + * configure: Rebuild. + + * config/tc-mips.c (struct mips_set_options): Define. + (mips_opts): New static variable. + (mips_isa): Remove. Now a field in mips_opts. Change all + references. + (mips16, mips16_autoextend, mips_warn_about_macros): Likewise. + (mips_noreorder, mips_nomove, mips_noat, mips_nobopt): Likewise. + (struct mips_option_stack): Define. + (mips_opts_stack): New static variable. + (s_mipsset): Add support for .set push and .set pop. + * doc/c-mips.texi: Document .set push and .set pop. + + * config/obj-elf.c (obj_elf_section_change_hook): New function. + * config/obj-elf.h (obj_elf_section_change_hook): Declare it. + * config/tc-mips.c (s_change_sec): Call it if OBJ_ELF. + +Thu Mar 27 12:23:56 1997 Ian Lance Taylor <ian@cygnus.com> + + * as.c (parse_args): Update copyright date in version message. + + * Makefile.in (clean-here): Remove dependency files. + + * read.c (s_comm): Check S_IS_COMMON as well as S_IS_DEFINED. + (s_mri_common): Check S_IS_COMMON unconditionally. + * symbols.c (colon): Check S_IS_COMMON as well as S_IS_DEFINED. + * config/tc-alpha.c (s_alpha_comm): Likewise. + * config/tc-mips.c (nopic_need_relax): Likewise. + * config/tc-ppc.c (ppc_elf_lcomm): Likewise. + (ppc_pe_comm): Likewise. + * config/obj-elf.c (obj_elf_common): Likewise. Set segment of + common symbol to bfd_com_section_ptr. + * config/tc-sparc.c (s_common): Likewise. + (tc_gen_reloc): Likewise. + +Wed Mar 26 13:35:15 1997 H.J. Lu <hjl@lucon.org> + + * config/tc-i386.c (tc_i386_fix_adjustable): Only define if + BFD_ASSEMBLER. + +Wed Mar 26 11:32:51 1997 Ian Lance Taylor <ian@cygnus.com> + + * input-scrub.c (input_scrub_next_buffer): Handle very long input + lines correctly. + + * listing.c (print_lines): Add lineno parameter. Change all + callers. + (listing_listing): Only call calc_hex for the right line. + (listing_list): Set the new edict based on the current edict, in + order to handle listing commands in macros correctly. + + * config/tc-mips.c (insn_uses_reg): Map register numbers in mips16 + instructions. + + * cond.c (cond_finish_check): New function. + * as.h (cond_finish_check): Declare. + * as.c (main): Call cond_finish_check. + +Mon Mar 24 12:11:18 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i386.h (iclrKludge): Define. + * config/tc-i386.c (md_assemble): Handle iclrKludge. + + * config/tc-alpha.h (tc_frob_file_before_adjust): Define if + OBJ_ECOFF. + (alpha_frob_file_before_adjust): Declare if OBJ_ECOFF. + * config/tc-alpha.c (alpha_debug): New static variable. + (md_parse_option): Set alpha_debug if -g is seen. + (alpha_frob_file_before_adjust): New function if OBJ_ECOFF. + +Sat Mar 22 13:44:28 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in: Added automatic dependency building. + * dep-in.sed: New file. + +Fri Mar 21 15:42:37 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-ieee.c (segment_name): Don't define function if this + is a macro. + + * config/obj-coff.h (DO_STRIP): Don't define. + * config/tc-h8300.h (DO_STRIP): Don't define. + * config/tc-h8500.h (DO_STRIP): Don't define. + * config/tc-w65.h (DO_STRIP): Don't define. + * config/tc-z8k.h (DO_STRIP): Don't define. + + * symbols.c (colon): Call obj_frob_label if it is defined. + * config/obj-vms.h (obj_frob_label): Rename from tc_frob_label. + + * configure.in: Don't set files and links. Don't call + AC_LINK_FILES. Substitute te_file. Create targ-cpu.h, + obj-format.h, targ-env.h, and itbl-cpu.h in AC_OUTPUT. + * configure: Rebuild. + * Makefile.in (TARG_CPU_C): New variable. + (TARG_CPU_O, TARG_CPU_H): New variables. + (OBJ_FORMAT_C, OBJ_FORMAT_O, OBJ_FORMAT_H): New variables. + (TARG_ENV_H, ATOF_TARG_C, ATOF_TARG_O): New variables. + (SOURCES): Rename from REAL_SOURCES. Delete old definition. + (LINKED_SOURCES): Remove. + (HEADERS): Rename from REAL_HEADERS. Delete old definition. + (LINKED_HEADERS): Remove. + (OBJS): Use $(TARG_CPU_O), etc., rather than targ-cpu.o, etc. + ($(OBJS)): Depend upon $(TARG_ENV_H), etc., rather than + targ-cpu.h, etc. + ($(TARG_CPU_O), $(OBJ_FORMAT_O) $(ATOF_TARG_O)): New targets. + (targ-cpu.o, obj-format.o, atof-targ.o): Remove targets. + (itbl-cpu.h): Remove target. + (DISTCLEAN_HERE): Remove targ-cpu.c, obj-format.c, atof-targ.c, + atof-targ.h. + +Thu Mar 20 19:18:58 1997 Ian Lance Taylor <ian@cygnus.com> + + * doc/as.texinfo (Symbol Names): Don't use obsolete @ctrl macro. + +Thu Mar 20 16:49:14 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/tc-m68k.c (mri_chip): Replace calls to get_symbol_end by + open coded loop that does not require the name to start with a + name beginner. + +Thu Mar 20 13:42:01 1997 H.J. Lu <hjl@lucon.org> + + * frags.c (frag_var): Change offset parameter to offsetT. + (frag_variant): Likewise. + * frags.h (frag_variant, frag_var): Update declarations. + * config/tc-m68k.c (struct m68k_it): Change foff field to + offsetT. + (add_frag): Change off parameter to offsetT. + * Several files: Add casts to calls to frag_var. + + * Makefile.in (m68k-parse.c): Depend upon itbl-parse.c, to + serialize a parallel make. + (itbl-parse.h): Split target out from itbl-parse.c. + +Thu Mar 20 12:48:45 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/m68k-parse.y (motorola_operand): Allow (zdireg,EXPR). + + * config/te-delta.h (COFF_COMMON_ADDEND): Define. + * config/obj-coff.c (fixup_segment): Check COFF_COMMON_ADDEND when + storing the value of a common symbol. + +Wed Mar 19 11:37:57 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/obj-coff.c (glue_symbols): Unused variable symbolP + removed. + (crawl_symbols): Do not modify symbol_rootP and symbol_lastP here; + that is done by symbol_remove and symbol_insert. + + * config/obj-coff.h (S_IS_LOCAL): Return 0 for a debugging + symbol. + +Wed Mar 19 11:06:29 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (load_register): In 32 bit mode, when not + dealing with a 64 bit number, permit the upper 32 bits to be set + even if bit 31 is not set. + +Tue Mar 18 23:30:14 1997 Ian Lance Taylor <ian@cygnus.com> + + * read.c (potable): Add "equiv". + (s_set): Handle .equiv based on argument. + * doc/as.texinfo (Equiv): New node to document .equiv. + (Err): New node to document .err. + +Tue Mar 18 15:50:13 1997 H.J. Lu <hjl@lucon.org> + + * Many files: Add function prototypes. + * as.c (show_usage, parse_args): Make static. + * frags.h (frag_alloc): Declare. + * subsegs.c (subseg_set_rest): Don't declare frag_alloc. + * symbols.c (dollar_label_instance): Change return type to long. + * symbols.h (print_symbol_value): Declare. + (print_expr, print_expr_1, print_symbol_value_1): Declare. + * write.c (fix_new_exp): Don't declare make_expr_symbol. + (remove_subsegs, relax_frag): Make static. + * config/atof-vax.c (atof_vax_sizeof): Change letter to int. + (what_kind_of_float): Likewise. + (atof_vax): Make static. Change what_kind to int. + (md_atof): Change what_statement_type to int. + * config/obj-ecoff.h (obj_ecoff_set_ext): Declare. + * config/tc-alpha.c (vax_md_atof): Declare. + (md_atof): Don't declare atof_ieee and vax_md_atof. + * config/tc-i386.c (set_16bit_code_flag): Make static. + * config/tc-i386.h (tc_i386_fix_adjustable): Declare. + * config/tc-m68k.c (add_fix): Change width to int. + (insert_reg): Change regname to const. + (md_atof): Don't declare atof_ieee. + (demand_empty_rest_of_line): Don't declare. + * config/tc-m88k.c (md_atof): Don't declare atof_ieee. + * config/tc-sparc.c (cmp_reg_entry): Change args to const PTR. + (parse_keyword_arg): Change lookup_fn to take const arg. + (md_atof): Don't declare atof_ieee. + * config/tc-sparc.h: Add ifdef for multiple inclusion. + (tc_aout_pre_write_hook): Don't declare. + +Mon Mar 17 11:21:09 1997 Ian Lance Taylor <ian@cygnus.com> + + * as.h (bfd_alloc_by_size_t): Don't declare. + * Many files: Use xmalloc rather than bfd_alloc_by_size_t. + +Sun Mar 16 13:49:21 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * symbols.c (symbol_new): Don't call debug_verify_symchain. + (symbol_append): Set sy_next and sy_previous when adding a single + symbol to an empty list. Call debug_verify_symchain. + (verify_symbol_chain): Use assert, not know. + +Sat Mar 15 20:27:12 1997 Fred Fish <fnf@cygnus.com> + + * NEWS: Note BeOS support. + * configure.in: (ppc-*-beos): New target, use coff as object format. + * configure: Regenerate with autoconf. + +Sat Mar 15 19:14:02 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_apply_fix): Improve error message for out + of range branch. + + * Makefile.in: Add dependencies on obstack.h where needed. + +Fri Mar 14 15:33:38 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_estimate_size_before_relax): Handle the + case of a symbol equated to another symbol when using SVR4_PIC. + + * Makefile.in (TARG_CPU_DEP_sparc): Add opcode/sparc.h. + +Thu Mar 13 11:20:51 1997 Ian Lance Taylor <ian@cygnus.com> + + * read.c (read_a_source_file): Call LISTING_NEWLINE before + HANDLE_CONDITIONAL_ASSEMBLY when handling an MRI line label. + + * config/obj-elf.c (obj_elf_data): Call md_flush_pending_output + and md_elf_section_change_hook if they are defined. + (obj_elf_text, obj_elf_previous): Likewise. + +Wed Mar 12 11:40:20 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-multi.h (struct elf_obj_sy): Define if + OBJ_MAYBE_ELF. + (OBJ_SYMFIELD_TYPE): Define as struct elf_obj_sy if + OBJ_MAYBE_ELF. + * config/obj-elf.h (struct elf_obj_sy): Don't define if + OBJ_SYMFIELD_TYPE is defined. + + * doc/as.texinfo (bss): Improve description of .bss section. In + ELF or COFF, you are permitted to switch into the section. + (Comm): Rewrite description of common symbols. + (Lcomm): Mention that some targets permit a third argument. + +Tue Mar 11 01:13:31 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_elf_lcomm): Don't call S_CLEAR_EXTERNAL. + + * symbols.c (colon): Change type of local to int. From Alan Modra + <alan@spri.levels.unisa.edu.au>. + + * config/tc-m88k.c (m88k_do_align): Don't use a special nop + alignment if a zero fill pattern was explicitly specified. + * config/tc-sh.c (sh_do_align): Likewise. + + * read.c (equals): Always permit register names to be redefined. + + * config/tc-mips.c (mips_fix_adjustable): Permit a reloc against a + mips16 symbol to be adjusted if a symbol is being subtracted from + it. + + From Eric Youngdale <eric@andante.jic.com>: + * config/obj-elf.c (obj_elf_symver): Check for duplicate or + illegal symbol version names. + (elf_frob_symbol): Check for external default versions. + +Sun Mar 9 23:49:12 1997 Ian Lance Taylor <ian@cygnus.com> + + From Eric Youngdale <eric@andante.jic.com>: + * config/obj-elf.h (struct elf_obj_sy): Define. + (OBJ_SYMFIELD_TYPE): Define to elf_obj_sy struct. Change all + users. + * config/obj-elf.c (obj_elf_symver): Just record the name. + (obj_symbol_new_hook): Initialized versioned_name field. + (elf_frob_symbol): If there is a versioned_name, either rename the + symbol, or add an alias with that name. + +Thu Mar 6 13:55:32 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (md_relax_table): Define. + (md_convert_frag): Implement. + (md_assemble): Handle relaxable operands/instructions correctly. + (md_estimate_size_before_relax): Implement. + * config/tc-mn10300.h (TC_GENERIC_RELAX_TABLE): Define. + + * config/tc-mn10200.c (md_relax_table): Fix typos. + + * config/tc-mn10300.c (md_assemble): Don't use any MN10300 specific + relocs anymore. Tweak fx_offset for pc-relative relocs. + +Wed Mar 5 15:46:16 1997 Ian Lance Taylor <ian@cygnus.com> + + * cond.c (s_ifc): Call mri_comment_field and mri_comment_end when + in MRI mode. + +Tue Mar 4 10:01:04 1997 Ian Lance Taylor <ian@cygnus.com> + + * read.c (equals): Add reassign parameter. Change all callers. + * read.h (equals): Update declaration. + +Sat Mar 1 01:04:04 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips16_extended_frag): Don't assume that we + can rely on the frag address to determine whether a frag is + earlier or later. + +Fri Feb 28 14:40:00 1997 Ian Lance Taylor <ian@cygnus.com> + + * write.h (LOCAL_LABEL): Only define if not BFD_ASSEMBLER. + (S_LOCAL_NAME): Likewise. + (FAKE_LABEL_NAME): Define unconditionally. + * symbols.c (colon): Call bfd_is_local_label, not LOCAL_LABEL, if + BFD_ASSEMBLER. + (S_IS_LOCAL): Call bfd_is_local_label_name, not LOCAL_LABEL. + * config/tc-*.h: Only define LOCAL_LABEL if not BFD_ASSEMBLER. + Don't define FAKE_LABEL_NAME. + * config/te-ic960.h: Likewise. + * config/tc-mips.h (tc_frob_file_before_adjust): Define. + (mips_frob_file_before_adjust): Declare. + * config/tc-mips.c (mips_frob_file_before_adjust): New function. + (mips_local_label): Remove. + + * config/te-sco386.h: Remove; not used. + +Thu Feb 27 13:29:04 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (md_assemble): Handle a reloc width of 'W'. + + * gasp.c (hash_add_to_string_table): Correct misspelling in error + message, and add newline. + (process_file): Don't process assignments in the label if this is + a equ or assign pseudo-op. + (process_pseudo_op): Swap first argument to do_assign for K_ASSIGN + and K_EQU, to match documentation. + +Thu Feb 27 12:00:03 1997 Michael Meissner <meissner@cygnus.com> + + * config/obj-coff.c (obj_coff_section): Add 'r' section attribute + to denote read-only data sections. + +Thu Feb 27 00:26:33 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-elf.c (obj_elf_common): Set BSF_OBJECT in flags. + * config/tc-sparc.c (s_common): Likewise, if BFD_ASSEMBLER. + + * expr.c (operand): Simplify 0b handling. Don't treat 0b as a + binary number if the next character is '+' or '-'. + +Wed Feb 26 18:19:00 1997 Stan Shebs <shebs@andros.cygnus.com> + + * configure.in (mips*-*-lnews*): New target, also make empty + emulation list for this target. + * configure: Update. + * tc-mips.c (ECOFF_LITTLE_FORMAT): Define. + (mips_target_format): Use. + * te-lnews.h: New file. + +Wed Feb 26 11:56:11 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (itbl-parse.c itbl-parse.h): Use $(BISON) and + $(BISONFLAGS), not $(YACC) and $(YACCFLAGS). + +Tue Feb 25 22:02:23 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/tc-m68k.c (instring): Useless local declaration of + crack_operand removed. + * expr.h (expressionS): Changed type of X_op field to operatorT if + __GNUC__. + +Tue Feb 25 13:17:27 1997 Ian Lance Taylor <ian@cygnus.com> + + Based on patches from Robert Lipe <robertl@dgii.com>: + * configure.in: Add i386coff and i386elf to emulation list. + * configure: Rebuild. + * as.c (i386coff, i386elf): Declare. + * obj.h (coff_format_ops): Declare. + * config/obj-coff.c (OBJ_HEADER): Define. + (coff_obj_symbol_new_hook): Rename from obj_symbol_new_hook. + (coff_obj_read_begin_hook): Rename from obj_read_begin_hook. + (obj_pseudo_table): Add "version". + (coff_pop_insert): New static function. + (coff_sec_sym_ok_for_reloc): New static function. + (no_func): New static function. + (coff_format_ops): New variable. + * config/obj-coff.h (coff_obj_symbol_new_hook): Declare. + (obj_symbol_new_hook): Define. + (coff_obj_read_begin_hook): Declare. + (obj_read_begin_hook): Define. + * config/tc-i386.h (i386_target_format): Declare. + * config/tc-i386.c: Check OBJ_MAYBE_ELF as well as OBJ_ELF; check + OUTPUT_FLAVOR when appropriate. + (i386_target_format): New function. + * Makefile.in (obj-coff.o): New target. + (e-i386coff.o, e-i386elf.o): New targets. + + From Stephen Williams <steve@icarus.icarus.com>: + * config/tc-i960.h (TC_SYMFIELD_TYPE): Define if OBJ_COFF. + (_tc_get_bal_of_call): Don't declare. + (tc_get_bal_of_call): Declare as function, don't define as macro. + * config/tc-i960.c (tc_set_bal_of_call): If OBJ_COFF, store balP + in sy_tc field, not x_balntry field. + (tc_get_bal_of_call): Rename from _tc_get_bal_of_call. Change + return type to symbolS *. If OBJ_COFF, retrieve value from sy_tc + field, not x_balntry field. + + * config/obj-elf.c (obj_elf_section): Permit a .note section to + have the SHF_ALLOC attribute. + + * Makefile.in ($(OBJS)): Don't depend upon $(IT_HDRS). + (TARG_CPU_DEP_mips): Depend upon $(srcdir)/itbl-ops.h. + (itbl-lex.o): Depend upon itbl-parse.h. + + * itbl-parse.y (yyerror): Change return type to int. Change to + use old style function declaration. + + * Makefile.in (itbl-lex.o): Remove -Wall. + (itbl-parse.o): Likewise. + + * cond.c (s_ifdef): If we should omit conditionals from listings, + call listing_list. + (s_if, s_ifc, s_endif, s_else, s_ifeqs): Likewise. + * listing.c (list_info_struct): Add EDICT_NOLIST_NEXT. + (listing_listing): Handle EDICT_NOLIST_NEXT. + (listing_list): An argument of 2 means EDICT_NOLIST_NEXT. + * listing.h (LISTING_NOCOND): Define. + (LISTING_SKIP_COND): Define. + * as.c (show_usage): Mention c as a suboption of -a. + (parse_args): Handle c as a suboption of -a. + * doc/as.texinfo: Document -alc. + +Mon Feb 24 18:27:43 1997 Eric Youngdale <eric@andante.jic.com> + + * doc/as.texinfo: Document .symver. + +Mon Feb 24 15:19:57 1997 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Change pre_defined_registers to + d10v_predefined_registers and reg_name_cnt to d10v_reg_name_cnt. + +Mon Feb 24 10:40:45 1997 Fred Fish <fnf@cygnus.com> + + * config/obj-coff.c: Fix typo in comment section. + +Mon Feb 24 02:23:00 1997 Dawn Perchik <dawn@cygnus.com> + + * Makefile.in: Remove dependancies on itbl-cpu.h. + * as.c: Define stubs for itbl_parse and itbl_init if HAVE_ITBL_CPU + is not defined. + +Mon Feb 24 02:03:00 1997 Dawn Perchik <dawn@cygnus.com> + + * itbl-ops.h: Include as.h. + +Mon Feb 24 01:04:00 1997 Dawn Perchik <dawn@cygnus.com> + + * as.c: Remove -t option. + * configure, configure.in: Move itbl-cpu.h to mips specific configure. + * itbl-ops.h: Include itbl-cpu.h only if HAVE_ITBL_CPU is defined. + * config/tc-mips.h: Define HAVE_ITBL_CPU. + +Sun Feb 23 18:01:00 1997 Dawn Perchik <dawn@cygnus.com> + + * itbl-ops.c: Don't define DEBUG. + +Sun Feb 23 17:49:00 1997 Dawn Perchik <dawn@cygnus.com> + + * Makefile.in: Update itbl-test.c to reflect its new location. + +Sun Feb 23 15:50:00 1997 Dawn Perchik <dawn@cygnus.com> + + * itbl-ops.c: Add test for itbl_have_entries. + * config/tc-mips.c: Remove test for itbl_have_entries. + * config/tc-mips.h: Define tc_init_after_args to mips_init_after_args. + +Sun Feb 23 18:13:19 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (DISTSTUFF): Remove itbl-parse.y, itbl-lex.l, and + itbl-ops.c. Add itbl-parse.c and itbl-lex.c. + (LEX, LEXFLAGS): Define. + * itbl-ops.c (append_insns_as_macros): Remove bogus ASSERT. + +Sat Feb 22 21:25:00 1997 Dawn Perchik <dawn@cygnus.com> + + * itbl-parse.y: Fix indentation mistakes from indent program. + * itbl-lex.l: Fix indentation mistakes from indent program. + * itbl-ops.h: Add include for ansidecl.h. + Add PARAMS around function arguments. + Add declaration for itbl_have_entries. + * itbl-ops.c: Add PARAMS around function arguments. + * Makefile.in: Add itbl build rules. + Add dependancies for itbl files to mips target. + * as.c: Add itbl support. + Add new option "--insttbl" for dynamically extending instruction set. + * as.h: Declare insttbl_file_name; + the name of file defining extensions to the basic instruction set + * configure.in, configure: Add itbl-parse.o, itbl-lex.o, and + itbl-ops.o to extra_objects for mips configuration. + Add include file link from itbl-cpu.h to + config/itbl-${target_cpu_type}.h. + * config/tc-mips.c: Allow copz instructions. + Add notes for future additions to the itbl support. + Add debug macros. + (macro): Call itbl_assemble to assemble itbl instructions. + See if an unknown register is specified in an itbl entry. + +Sat Feb 22 20:53:01 1997 Fred Fish <fnf@cygnus.com> + * doc/internals.texi (CPU backend): Fix typo in md_section_align + description. + +Fri Feb 21 14:34:31 1997 Martin M. Hunt <hunt@pizza.cygnus.com> + * config/tc-d10v.c (md_pcrel_from_section): Return 0 if + relocation is in different section. Fixes PR11574. + +Fri Feb 21 10:08:25 1997 Jim Wilson <wilson@cygnus.com> + + * tc-mips.c (mips_ip): If configured for an embedded ELF system, + don't set the section alignment to 2**4. + +Fri Feb 21 11:55:03 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (line_comment_chars): Add '*'. + + * app.c (LEX_IS_TWOCHAR_COMMENT_2ND): Don't define. + (do_scrub_begin): Don't set lex['*']. + (do_scrub_chars): When handling LEX_IS_TWOCHAR_COMMENT_1ST, don't + check for LEX_IS_TWOCHAR_COMMENT_2ND. Instead, just check for + a literal '*'. + + * configure.in: Set em=svr4 for m68k-*-sysv4*. + * configure: Rebuild. + * config/te-svr4.h: New file. + * config/tc-m68k.c (m68k_comment_chars): Only include `#' if + TE_SVR4 or TE_DELTA. + +Thu Feb 20 22:24:39 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_convert_frag): Create a fixup for the + short conditional branch around a long unconditional branch. + +Thu Feb 20 13:56:00 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (obj_coff_ln [both versions]): Call + new_logical_line. + + * config/tc-arm.c (fix_new_arm): Use make_expr_symbol to handle a + complex expression. + + * symbols.c (resolve_symbol_value): If both left and right + operands are undefined, warn about both of them. + +Wed Feb 19 00:53:28 1997 Ian Lance Taylor <ian@cygnus.com> + + Based on patches from Eric Youngdale <eric@andante.jic.com>: + * config/obj-elf.c (elf_pseudo_table): Add "symver". + (obj_elf_symver): New static function. + * config/obj-elf.h (OBJ_COPY_SYMBOL_ATTRIBUTES): Copy the st_other + field. + + * write.c (relax_segment): Make type and printf format agree. + + * read.c (get_line_sb): Don't end the line on a semicolon inside a + string. + +Sun Feb 16 17:47:29 1997 Fred Fish <fnf@toadfish.ninemoons.com> + + * config/tc-alpha.h (md_operand): Define with a null expansion, + like all the other targets. + * doc/internals.texi (CPU backend): Add missing word in + md_flush_pending_output description. Fix typo in md_convert_frag + description. + +Fri Feb 14 18:09:59 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/tc-m68k.c (LOCAL_LABEL): Macro redefined if TE_DELTA. + (tc_canonicalize_symbol_name): Macro defined if TE_DELTA. + * config/obj-coff.c (obj_coff_def): Use + tc_canonicalize_symbol_name if defined. + (obj_coff_tag, obj_coff_val): Likewise. + * expr.c (operand): Reject '~' as operator if is_name_beginner. + +Fri Feb 14 17:24:48 1997 Ian Lance Taylor <ian@cygnus.com> + + Based on notes from Peter Eriksson <peter@ifm.liu.se>. The target + does not actually work, though: + * configure.in (i386-sequent-bsd*): New target. + * configure: Rebuild. + * config/tc-dynix.h: New file. + * config/tc-i386.h: Define TARGET_FORMAT if TE_DYNIX. + + * read.c (do_align): Add max parameter. Change all callers. + Remove useless static variables. + (s_align): New static function. Do common portion of + s_align_bytes and s_align_ptwo. + (s_align_bytes, s_align_ptwo): Just call s_align. + * frags.c (frag_align): Add max parameter. Change all callers. + (frag_align_pattern): Likewise. + * frags.h (frag_align, frag_align_pattern): Update declarations. + * write.c (relax_segment): Limit alignment change to fr_subtype. + Fix some types to be addressT. + * config/obj-coff.c (size_section): Likewise. + * config/obj-ieee.c (size_section): Likewise. + * config/tc-d10v.h (md_do_align): Add max parameter. + * config/tc-i386.h (md_do_align): Likewise. + * config/tc-m88k.h (md_do_align): Likewise. + * config/tc-m88k.c (m88k_do_align): Likewise. + * config/tc-sh.h (md_do_align): Likewise. + * config/tc-sh.c (sh_do_align): Likewise. + * as.h: Improve comments on rs_align and rs_align_code. + * doc/as.texinfo: Document new alignment arguments. + * doc/internals.texi (Frags): Document use of fr_subtype field for + rs_align and rs_align_code. + +Fri Feb 14 15:56:06 1997 Gavin Koch <gavin@cygnus.com> + + * config/tc-mips.c: Changed opcode parsing. + +Thu Feb 13 20:02:16 1997 Fred Fish <fnf@cygnus.com> + + * config/{tc-alpha.h, tc-arc.h, tc-d10v.h, tc-generic.h, tc-i960.h, + tc-mn10200.h, tc-mn10300.h, tc-sh.h, tc-vax.h, tc-w65.h}: + Add default definition of zero for TARGET_BYTES_BIG_ENDIAN. + * config/{tc-arm.h, tc-hppa.h, tc-i386.h, tc-mips.h, tc-ns32k.h, + tc-ppc.h, tc-sparc.h}: Move definition of TARGET_BYTES_BIG_ENDIAN + to a location consistent with the rest of the target include files. + * config/tc-i386.c: Remove misleading comment. + * doc/internals.texi (CPU backend): Add description of function + md_undefined_symbol. + +Thu Feb 13 21:44:18 1997 Klaus Kaempf <kkaempf@progis.de> + + * as.h: GNU c provides unlink() function. + + Unify section handling on openVMS/Alpha: + * config/tc-alpha.c(s_alpha_link): Remove. + (s_alpha_section): New function. + Remove case-hacking of symbols + Add .code_address pseudo-op. + (BFD_RELOC_ALPHA_CODEADDR): New relocation. + (s_alpha_code_address): New function. + (alpha_ctors_section, alpha_dtors_section): New sections for C++ + static constructors/destructors. + Add debug code for crash debugs, to be removed when traceback code + is added to object code. + (s_alpha_name): New function for .name pseudo-op. + (alpha_print_token): New function to print token expressions with + alpha specific extensions. + + * makefile.vms: Allow compilation with current gcc snapshot. + +Thu Feb 13 16:29:04 1997 Fred Fish <fnf@cygnus.com> + + * doc/Makefile.in (TEXI2DVI): Set to just name of program. + (DVIPS): Set to dvips. + (ps, as.ps, gasp.ps): New targets. + (internals.info, gasp.dvi, internals.dvi): Set both TEXINPUTS + and MAKEINFO env variables. + (internals.ps): Use DVIPS macro. + (clean): Remove core and backup files. + (distclean): Remove temporary files from building internals. + (clean-dvi): Ditto. + * doc/internals.texi (Frags): Fix typo. + (GAS processing): Ditto. + (CPU backend): Ditto. + * ecoff.c (init_file): Use TARGET_BYTES_BIG_ENDIAN value directly. + * mpw-config.in: Define TARGET_BYTES_BIG_ENDIAN as 1. + * read.c: Remove ugly hack that dealt with config files not + correctly defining TARGET_BYTES_BIG_ENDIAN. + (target_big_endian): Use TARGET_BYTES_BIG_ENDIAN directly. + * config/arm-big.mt: Define TARGET_BYTES_BIG_ENDIAN to 1. + * config/arm-lit.mt: Define TARGET_BYTES_BIG_ENDIAN to 0. + * config/mips-big.mt: Define TARGET_BYTES_BIG_ENDIAN to 1. + * config/mips-lit.mt: Define TARGET_BYTES_BIG_ENDIAN to 0. + * config/ppc-lit.mt: Define TARGET_BYTES_BIG_ENDIAN to 1. + * config/ppc-sol.mt: Replace TARGET_BYTES_LITTLE_ENDIAN + with TARGET_BYTES_BIG_ENDIAN defined to 0. + * config/tc-arm.h: Remove use of TARGET_BYTES_LITTLE_ENDIAN + and simplify. Test value of TARGET_BYTES_BIG_ENDIAN, not just + whether it is defined or not. + * config/tc-mips.h: Remove use of TARGET_BYTES_LITTLE_ENDIAN. + * config/tc-ppc.h: Remove use of TARGET_BYTES_LITTLE_ENDIAN + and simplify. Test value of TARGET_BYTES_BIG_ENDIAN, not just + whether it is defined or not. + +Thu Feb 13 14:40:16 1997 Doug Evans <dje@canuck.cygnus.com> + + * write.c (write_relocs): Correct text in as_fatal error message, + bfd_perform_relocation -> bfd_install_relocation. + +Thu Feb 13 14:48:03 1997 Philippe De Muyter <phdm@info.ucl.ac.be> + + * config/tc-m68k.c (LEX_TILDE): Define if TE_DELTA. + * read.c (LEX_TILDE): Define if not defined. + (lex_type): Use LEX_TILDE. + * expr.c (get_symbol_end): Check first char with is_name_beginner, + not is_part_of_name. + +Thu Feb 13 11:40:58 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.c (md_show_usage): Add missing backslash at end + of continued line. + + * config/tc-mips.c (mips16_extended_frag): Correct base address + for an extended PC relative instruction. + (md_convert_frag): Likewise. + + * config/tc-mips.c (prev_nop_frag): New static variable. + (prev_nop_frag_holds): New static variable. + (prev_nop_frag_required): New static variable. + (prev_nop_frag_since): New static variable. + (append_insn): If we aren't reordering, and prev_nop_frag is not + NULL, and we don't need any nops, then decrease the size of + prev_nop_frag. Don't insert nops because of instructions in + noreorder sections. Remember whether the previous instructions + where in noreorder sections even when not reordering. + (mips_no_prev_insn): Add preserver parameter. Change all + callers. Refer prev_nop_frag variables when appropriate. + (mips_emit_delays): Set up prev_nop_frag. + (s_mipsset): Clear prev_nop_frag if reordering. + +Wed Feb 12 14:36:29 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (append_insn): Remove useless code which + handled swapping a mips16 jump with a mips16 instruction with a + reloc. + + * config/tc-mips.c (md_parse_option): When debugging, set + mips_optimize to 1, not 0. + + * config/tc-mips.c (mips16_ip): Handle an extend operand. + + * config/tc-mips.c (my_getExpression): In mips16 mode, if it looks + like the expression was based on `.', adjust the value of the + symbol. + + * config/tc-mips.c (append_insn): Warn about an attempt to put an + extended instruction in a delay slot when not reordering. + (md_convert_frag): Warn if an extended instruction appears in a + delay slot. + + * config/tc-mips.c (mips_pseudo_table): Add "insn". + (s_insn): New static function. + * doc/c-mips.texi: Document .insn. + + * config/tc-mips.c (md_begin): Add the general registers to the + symbol table. + (mips16_ip): First parse the expression, and then see whether it + came up with a register, rather than trying to first see whether + we are looking at a register. + +Tue Feb 11 15:52:22 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips16_ip): Handle %gprel modifier. + (md_apply_fix): Handle BFD_RELOC_MIPS16_GPREL. + + * config/tc-mips.c (append_insn): Output jump instruction as a + pair of 2 byte instructions, rather than as a single 4 byte + instruction. + +Mon Feb 10 22:06:00 1997 Dawn Perchik (dawn@cygnus.com) + + * itbl-ops.c, itbl-lex.l, itbl-parse.y, itbl-ops.h, + config/itbl-mips.h: Add copyright message and fix indentation. + +Mon Feb 10 18:09:00 1997 Dawn Perchik (dawn@cygnus.com) + + * itbl-ops.c: New file. Add support for dynamically read + instruction registers, opcodes and formats. Build internal table + for new instructions and provide callbacks for assembler and + disassembler. + * itbl-lex.l, itbl-parse.y: Lex and yacc parsers for instruction + spec table. + * itbl-ops.h: New file. Header file for itbl support. + * config/itbl-mips.h: New file. Mips specific definitions for + itbl support. + +Fri Feb 7 09:52:34 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_assemble): If a constant operand won't + fit into the constant field of a relaxable operand, then it does + not match. + +Thu Feb 6 20:08:12 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_estimate_size_before_relax): Treat + a jsr target in a different section just like a jsr to + an undefined target. + +Thu Feb 6 16:52:57 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_fix_adjustable): Don't adjust relocations + against any mips16 symbols, not just externally visible ones. + (md_apply_fix): Corresponding change. + +Wed Feb 5 11:11:06 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips16_ip): Accept floating point registers in + the operand of the exit instruction. + +Tue Feb 4 14:12:39 1997 Ian Lance Taylor <ian@cygnus.com> + + * symbols.c (resolve_symbol_value): If we leave an equated symbol + as O_symbol, copy over the segment. + +Mon Feb 3 12:35:54 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_apply_fix): If we aren't adjusting this + fixup to be against the section symbol, adjust the value + accordingly. + + * symbols.c (resolve_symbol_value): Don't change X_add_number for + an equated symbol. + * write.c (write_relocs): Avoid looping on equated symbols. + Adjust fx_offset by X_add_number for each symbol. + * config/obj-coff.c (do_relocs_for): Avoid looping on equated + symbols. + (fixup_segment): Add a loop to track down equated symbols and + adjust fx_offset appropriately. + +Fri Jan 31 15:21:02 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_relax_table): Add entries to allow + jmp -> bra relaxing. + (md_convert_frag): Handle jmp->bra relaxing. + (md_assemble): Handle jmp->bra relaxing. + (md_estimate_size_before_relax): Likewise. + +Fri Jan 31 13:15:05 1997 Alan Modra <alan@spri.levels.unisa.edu.au> + + * config/tc-i386.c (i386_align_code): Add comments explaining the + nop instructions. + +Fri Jan 31 10:46:14 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.c (enforce_aligned_data): New static variable. + (sparc_cons_align): Don't do anything unless enforce_aligned_data + is set. + (md_longopts): Add "enforce-aligned-data". + (md_show_usage): Mention --enforce-aligned-data. + * doc/c-sparc.texi (Sparc-Aligned-Data): New node; document + enforce-aligned-data. + + * config/tc-ppc.c (md_pseudo_table): If OBJ_XCOFF, add "long", + "word", and "short". + (ppc_xcoff_cons): New static function. + + * write.c (relax_segment): Give an error if a .space symbol is + common or undefined. + + * read.c (read_a_source_file): Don't handle mri_pending_align if + the handler is s_globl or s_ignore. + +Thu Jan 30 11:46:59 1997 Fred Fish <fnf@cygnus.com> + + * config/tc-d10v.c (find_opcode): Remove unused variable "numops". + +Thu Jan 30 12:28:18 1997 Alan Modra <alan@spri.levels.unisa.edu.au> + + * config/tc-i386.c (i386_align_code): Improve the nop patterns. + +Thu Jan 30 12:08:40 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_fix_adjustable): New function. + * config/tc-mips.h (tc_fix_adjustable): Call mips_fix_adjustable. + (mips_fix_adjustable): Declare. + + Ideas from Srinivas Addagarla <srinivas@cdotd.ernet.in>: + * read.c (read_a_source_file): After doing an mri_pending_align, + adjust the line_label if there is one. + (s_space): Set mri_pending_align if an odd number of bytes were + output. + +Wed Jan 29 15:31:12 1997 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.h (md_do_align): Add this hook to call + d10v_cleanup() when a ".align" is detected. Fixes PR11487. + + * config/tc-d10v.c (find_opcode): Correctly calculate + branch displacement when .aligns are present. + +Wed Jan 29 09:42:11 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_relax_table): Define. + (md_convert_frag): Implement. + (md_assemble): Handle relaxable operands/instructions correctly. + (md_estimate_size_before_relax): Implement. + * config/tc-mn10200.h (TC_GENERIC_RELAX_TABLE): Define. + +Tue Jan 28 15:27:28 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (append_insn): Give an error for jumps to a + misaligned address. + (md_apply_fix): Make a branch to an odd address an error rather + than a warning. + + * config/tc-mips.c (md_convert_frag): If the user explicitly + requested an extended opcode, pass warn as true to mips16_immed. + + * config/tc-mips.c (mips16_ip): Handle a missing expression like + an explicit 0, so that explicitly extended instructions work + correctly. + +Mon Jan 27 17:41:20 1997 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (ecoff_build_symbols): Don't generate a local ECOFF + symbol for a common symbol. + +Wed Jan 22 10:39:39 1997 Doug Evans <dje@canuck.cygnus.com> + + Patch presumed to have been checked in awhile ago but wasn't. + Mon Nov 25 10:45:14 1996 Doug Evans <dje@seba.cygnus.com> + * write.c: Delete "ifndef md_relax_frag" around is_dnrange. + (relax_segment, case rs_org): Move code inside braces. Move locals + target,after inside too. + (relax_segment, case rs_machine_dependent): Guts moved to ... + (relax_frag): New function. + Call md_prepare_relax_scan if defined. + +Mon Jan 20 10:56:47 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/tc-m68k.c (m68k_ip): Reject pc-relative addresses for the + 'p' operand specifier. + +Mon Jan 20 10:39:36 1997 J.T. Conklin <jtc@cygnus.com> + + * config/tc-m68k.c (HAVE_LONG_BRANCH): New macro, returns true for + m68k family cpus which support long branch addressing modes. + (m68k_ip, md_convert_frag_1, md_estimate_size_before_relax, + md_create_long_jump): Use it. + +Mon Jan 20 12:42:06 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_begin): Don't set SEC_ALLOC or SEC_LOAD for + the .reginfo or .MIPS.options section if configured for an + embedded target. + + * config/tc-mips.c (md_begin): Don't set interlocks for + mips_4650. + +Wed Jan 15 13:51:50 1997 Ian Lance Taylor <ian@cygnus.com> + + * read.c (read_a_source_file): Make sure the symbol ends with + whitespace before checking whether the next character is '='. + +Tue Jan 14 15:07:27 1997 Robert Lipe <robertl@dgii.com> + + * config/tc-i386.c (sco_id): Moved from here... + * config/obj-elf.c (sco_id): ...to here. Adding the identifier + really is an SCO ELF specific thing, not just a SCO x86 specific + thing. + +Thu Jan 9 09:08:43 1997 Ian Lance Taylor <ian@cygnus.com> + + * read.c (emit_expr): Check for overflow of a negative value + correctly. + * write.c (fixup_segment): Likewise. + * config/obj-coff.c (fixup_segment): Likewise. + + * config/tc-m68k.c (struct label_line): Define. + (labels, current_label): New static variables. + (md_assemble): Mark current_label as text, and clear it. + (m68k_frob_label): New function. + (m68k_flush_pending_output): New function. + (m68k_frob_symbol): New function. + * config/tc-m68k.h (tc_frob_label): Define. + (md_flush_pending_output): Define. + (tc_frob_symbol): Don't warn, just call m68k_frob_symbol. + (tc_frob_coff_symbol): Likewise. + + * read.c (read_a_source_file): When defining a macro in MRI mode, + don't add the symbol to the symbol table. + +Tue Jan 7 11:21:42 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (tc_gen_reloc): Handle sym1-sym2 fixups + here since fixup_segment doesn't (linkrelax is set). + * config/tc-mn10200.c (tc_gen_reloc): Likewise. + +Mon Jan 6 15:19:32 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (md_assemble): Tweak fx_offset for pc-relative + relocs. + +Fri Jan 3 16:47:08 1997 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (struct hppa_fix_struct): Tweak fx_r_field's type + to avoid warnings with the native HP compiler. + (fix_new_hppa): Similarly for the r_type argument. + (pa_build_unwind_subspace, hppa_elf_mark_end_of_function): Enclose + in an #if OBJ_ELF to keep gcc -Wall quiet. + (md_apply_fix): Always initialize "result". + + * config/tc-mn10200.c (md_assemble): Generate relocations. + +Fri Jan 3 18:17:23 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/tc-m68k.c (s_even): Adjust the alignment of the current + section. + +Fri Jan 3 17:10:33 1997 Richard Henderson <rth@tamu.edu> + + * config/obj-elf.c (elf_file_symbol): When using ECOFF debugging, + pass on the new file hook. + + * config/tc-alpha.c (alpha_fix_adjustable): Not quite the same as + !alpha_force_relocation, as local LITERALs can be adjusted to be + relative to the section. + +Fri Jan 3 12:09:24 1997 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (yank_symbols): If tc_frob_coff_symbol is + defined, call it. + * config/tc-m68k.h (tc_frob_symbol): Check whether text label is + aligned to odd boundary. + (tc_frob_coff_symbol): Define. + + * doc/as.texinfo (Set): Change parenthesized @xref to @pxref. + + * macro.c (macro_expand_body): In MRI mode, just copy a single &. + + * config/tc-m68k.c (m68k_ip): Call frag_grow before adding a + PCINDEX frag. From Ronald F. Guilmette <rfg@monkeys.com>. + + * config/tc-m68k.c (m68k_ip): Accept 'B' as a size for an + immediate value. + (md_assemble): If the size is 'B', set fx_signed. + (md_apply_fix_2): Use fx_signed when checking for overflow. + + * write.h (struct fix): Add fx_signed field. + * write.c (fix_new_internal): Initialize fx_no_overflow and + fx_signed fields. + (fixup_segment): Use fx_signed when checking for overflow. + * config/obj-coff.c (fixup_segment): Check fx_no_overflow and + fx_signed when checking for overflow. + +Thu Jan 2 13:37:29 1997 Ian Lance Taylor <ian@cygnus.com> + + * NOTES, NOTES.config: Removed. These are rarely, if ever, + updated, and all the useful information is in doc/internals.texi. + + Based on patch from Ronald F. Guilmette <rfg@monkeys.com>: + * read.c (read_a_source_file): Check for conditional operators + before doing an MRI pending alignment. + * config/tc-m68k.h (m68k_conditional_pseudoop): Declare. + (tc_conditional_pseudop): Define. + * config/tc-m68k.c (m68k_conditional_pseudop): New function. + * doc/internals.texi (CPU backend): Describe + tc_conditional_pseudoop. + + Based on patch from Ronald F. Guilmette <rfg@monkeys.com>: + * config/tc-m68k.c (m68k_rel32_from_cmdline): New static + variable. + (md_begin): Check m68k_rel32_from_cmdline before setting + m68k_rel32. + (m68k_mri_mode_change): Likewise. + (md_longopts): Add --disp-size-default-16 and + --disp-size-default-32. + (md_parse_option): Handle new options. + (md_show_usage): Mention new options. + * doc/c-m68k.texi (M68K-Opts): Document new options. + + Based on patch from Ronald F. Guilmette <rfg@monkeys.com>: + * config/tc-m68k.c (m68k_index_width_default): New static + variable. + (m68k_ip): Use m68k_index_width_default to set the size of a base + register whose size was not given. + (md_longopts): Add --base-size-default-16 and + --base-size-default-32. + (md_parse_option): Handle new options. + (md_show_usage): Mention new options. + * doc/c-m68k.texi (M68K-Opts): Document new options. + + * doc/c-mips.texi: Mention ISA level 4, and the -mips16 option. + + * configure.in: Recognize mips-*-linux* target. + * configure: Rebuild. + + * config/tc-mips.c (load_register): Rewrite 64 bit handling to + work if valueT is only 32 bits. + + * config/tc-mips.c: Throughout, check target_big_endian rather + than byte_order. + (byte_order): Remove. + (mips_init_after_args): Remove. + * config/tc-mips.h (LITTLE_ENDIAN, BIG_ENDIAN): Don't define. + (mips_init_after_args): Don't declare. + (tc_init_after_args): Don't define. + + * config/tc-mips.h (tc_frob_after_relocs): Define if + OBJ_MAYBE_ELF. + (mips_elf_final_processing): Likewise. + (ELF_TC_SPECIAL_SECTIONS): Likewise. + +Tue Dec 31 12:56:41 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (read_a_source_file): Check mri_pending_align after + checking for a macro. From Ronald F. Guilmette + <rfg@monkeys.com>. + + * Makefile.in (ALL_CFLAGS): Add -D_GNU_SOURCE. + + * config/tc-sparc.c (md_apply_fix3): Rename from md_apply_fix, and + add segment argument. If OBJ_ELF, treat a relocation against a + symbol in a linkonce section like a relocation against an external + symbol. + * config/tc-sparc.h (MD_APPLY_FIX3): Define. + +Mon Dec 30 11:35:40 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips16_macro): Add case for M_ABS. + +Fri Dec 27 22:51:51 1996 Fred Fish <fnf@cygnus.com> + + * NOTES.config (Implementation): as.h #define's "GAS" not "gas", + includes config.h instead of host.h, tc.h instead of tp.h, and + targ-env.h instead of target-environment.h. + Also, obj-format.h includes targ-cpu.h instead of + target-processor.h. + +Fri Dec 27 11:42:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * doc/as.texinfo (M): Mention explicitly that -M changes macro + handling. + +Thu Dec 19 12:06:08 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (adjust_reloc_syms): If the fixup symbol has been + equated to an undefined symbol, convert the fixup to being against + the target symbol. Remove obsolete code handling a special case + for i386 PIC. + +Wed Dec 18 22:54:39 1996 Stan Shebs <shebs@andros.cygnus.com> + + * mpw-make.sed: Use NewFolderRecursive for installation. + +Wed Dec 18 16:00:42 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (do_assemble): Correct previous bug fix. + +Wed Dec 18 15:27:40 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (md_assemble): Fix bug which caused + second instruction in a line to be case sensitize. PR11312 + +Wed Dec 18 10:08:46 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (mn10200_insert_operand): Don't + range check operands with MN10200_OPERAND_NOCHECK set. + (check_operand): Likewise. + +Tue Dec 17 10:59:32 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c: Undo part of last Friday's alignment changes. + (md_begin): Always align the text section to a four byte + boundary. + (append_insn): Remove call to record_align. + + * config/tc-mips.c (insn_label): Remove. + (struct insn_label_list): Define. + (insn_labels, free_insn_labels): New static variables. + (mips_clear_insn_labels): New static function. + (append_insn): Mark all mips16 text labels, and make them odd. + Handle all labels after emitting a nop, not just one. Call + mips_clear_insn_labels rather than just clearing insn_label. + (mips_emit_delays): Add insns parameter, and use it to decide + whether to mark mips16 labels. Handle all labels, not just one. + Force mips16 labels to be odd. Change all callers. + (mips16_immed): Don't check for an odd branch target. + (md_apply_fix): Don't check mips16 mode for a branch reloc. + (mips16_extended_frag): Ignore the low bit in a branch target. + (md_convert_frag): Likewise. + (mips_no_prev_insn): Call mips_clear_insn_labels rather than just + clearing insn_label. + (mips_align, mips_flush_pending_output, s_cons): Likewise. + (s_float_cons, s_gpword): Likewise. + (s_align): Use insn_labels rather than insn_label. + (s_cons, s_float_cons, s_gpword): Likewise. + (mips_frob_file_after_relocs): New function. + (mips_define_label): Rewrite to add to insn_labels list. + * config/tc-mips.h (tc_frob_file_after_relocs): Define. + * ecoff.c (ecoff_build_symbols): If the size of a function comes + out odd, increment it. + + * config/tc-mips.c (append_insn): Only update prev_insn when not + reordering if place is NULL. + + * config/tc-mips.c (mips16_ip): Check for a missing expression + when using the register indirect addressing mode. + +Mon Dec 16 10:08:46 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c (mn10200_insert_operand): Don't + check 24bit operands for overflow. + (check_operand): Likewise. + +Mon Dec 16 11:50:40 1996 Ian Lance Taylor <ian@cygnus.com> + + * doc/as.texinfo (Section): Document how to use the .section + pseudo-op for COFF and ELF. + +Sun Dec 15 15:26:37 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (adjust_reloc_syms): Fix linkonce check for ELF. + +Sat Dec 14 22:37:27 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (prev_insn_reloc_type): New static variable. + (RELAX_MIPS16_ENCODE): Add dslot and jal_dslot arguments, and + store them. Adjust other RELAX_MIPS16 macros. + (RELAX_MIPS16_DSLOT): Define. + (RELAX_MIPS16_JAL_DSLOT): Define. + (append_insn): Pass new arguments to RELAX_MIPS16_ENCODE. Correct + handling of whether previous instruction has a fixup. Set + prev_insn_reloc_type. + (mips_no_prev_insn): Clear prev_insn_reloc_type. + (mips16_extended_frag): Use the right base address for a PC + relative add or load. + (md_convert_frag): Likewise. If a PC relative add or load is + used, record the alignment for the section. + +Fri Dec 13 13:00:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (adjust_reloc_syms): Don't reduce a reloc against a + linkonce section into a reloc against the section symbol. + + * config/tc-mips.c (mips16_macro): Remove nop instructions after + branch instructions. + + * config/tc-mips.c (md_begin): If configured for an embedded ELF + system, don't set the section alignment to 2**4. + (s_change_sec): Likewise. + (append_insn): Call record_alignment for the section. + (md_section_align): Don't align the section size for an embedded + ELF system. + +Thu Dec 12 16:40:47 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (adjust_reloc_syms): Make sure that symbols are + resolved; expression symbols may have been skipped. + * config/obj-coff.c (fixup_segment): Likewise. + +Thu Dec 12 15:18:21 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_suffix): Move @plt to + BFD_RELOC_24_PLT_PCREL relocation. + (md_apply_fix3): Support BFD_RELOC_24_PLT_PCREL. + +Tue Dec 10 13:51:55 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (write_2_short): Remove code that called + parallel_ok() when the programmer specified parallel instructions. + +Tue Dec 10 12:23:19 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (md_assemble): Update to handle endianness + issues correctly. + + * config/tc-mn10200.c (md_assemble): Opcode 0x0 is valid! + * config/tc-mn10300.c (md_assemble): Likewise. + +Tue Dec 10 11:37:14 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (append_insn): Make sure there is enough room + in a frag after a mips16 instruction to switch it with a jump + instruction. + + * config/tc-mips.c (mips16_extended_frag): Give an error for an + attempt to use a non absolute symbol in an extending frag. + +Mon Dec 9 16:48:20 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10200.c: Flesh out assembler support for MN10200. + * config/tc-mn10200.h: Likewise. + +Mon Dec 9 17:09:42 1996 Ian Lance Taylor <ian@cygnus.com> + + * app.c (do_scrub_chars): At the end of a C comment, pass space to + UNGET rather than PUT. Set old_state before setting state to -2. + + * config/tc-mips.c (mips16_extended_frag): Avoid an infinite loop + when extending because the value is exactly maxtiny + 1. + + * config/tc-mips.c (RELAX_MIPS16_ENCODE): Add small and ext + arguments, and store them. Adjust other RELAX_MIPS16 macros. + (RELAX_MIPS16_USER_SMALL): Define. + (RELAX_MIPS16_USER_EXT): Define. + (mips16_small, mips16_ext): New static variables. + (append_insn): Pass mips16_small and mips16_ext to + RELAX_MIPS16_ENCODE. + (mips16_ip): Set mips16_small and mips16_ext. + (mips16_immed): Don't check mips16_autoextend. + (mips16_extended_frag): Check USER_SMALL and USER_EXT. + + * write.c (write_relocs): Print an error for an out of range + fixup, rather than calling abort. + + * as.c (main): Unlink the output file if there are errors while + generating the fixups. + +Fri Dec 6 18:48:13 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips16_extended_frag): Don't call + S_GET_VALUE. + (md_convert_frag): Call resolve_symbol_value before calling + S_GET_VALUE, and don't add in the frag address. + + * config/tc-mips.c (mips16_immed): Add file and line parameters, + and use them when reporting errors. Change all callers. + +Fri Dec 6 15:36:32 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c: Fix various gcc -Wall warnings. + Remove '$' prefixing for registers. + +Fri Dec 6 00:55:48 1996 Martin <hunt@cygnus.com> + + * config/tc-d10v.c (md_assemble): Check to see if prev_seg + is initialized before using it. + (d10v_cleanup): No longer uses its argument, so make it void. + + * config/tc-d10v.h (d10v_cleanup): Change prototype. + +Thu Dec 5 11:03:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (fixup_segment): Don't discard the symbol for a PC + relative fixup to an absolute symbol. + +Wed Dec 4 15:42:41 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (md_assemble, d10v_cleanup): Fix bug + with multiple sections. + +Wed Dec 4 13:00:07 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_longopts): Rename mips-16 to mips16, and + no-mips-16 to no-mips16. + (s_mipsset): Accept .set mips16 and .set nomips16. + +Wed Dec 4 10:35:33 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_suffix): Take expressionS pointer + argument, and check for +/- constant following the suffix, folding + it into the expression. + (ppc_elf_cons): Change ppc_elf_suffix calls. + (md_assemble): Ditto. + (shlib): Replace boolean mrelocatable with enumeration shlib. + (md_parse_option): Discriminate between PIC style shared libraries + and -mrelocatable. + (ppc_elf_validate_fix): Don't report warnings for PIC style shared + libraries. + +Tue Dec 3 23:18:29 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.h ({tc,ppc}_comment_chars): Define, so that we can + change the comment characters. + + * config/tc-ppc.c (comment_chars): Delete in favor of + tc_comment_chars. + (ppc_{eabi,solaris}_comment_chars): Eabi and Solaris versions of + comment chars. + (ppc_comment_chars): Select appropriate comment chars by default. + (msolaris): New flag for -m{,no-}solaris. + (md_parse_option): Recognize -K pic. Add support for + -m{,no-}solaris. + (md_show_usage): Update. + (md_begin): Do not set ELF flags if Solaris. + (ppc_elf_suffix): @local sets R_PPC_LOCAL24PC relocation. + (md_apply_fix3): Add support for R_PPC_LOCAL24PC. + +Mon Dec 2 13:48:57 1996 Ian Lance Taylor <ian@cygnus.com> + + * as.c (main): Correct handling of flag_always_generate_output. + +Sun Dec 1 21:46:05 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (tc_gen_reloc): Get the addend from + fx_offset, not fx_addnumber. + + * config/tc-mn10300.h (tc_fix_adjustable): Don't do any + reloc adjustments. + +Sat Nov 30 17:34:48 1996 Eliot Dresselhaus <eliot@wally.edc.com> + + * config/tc-i386.c: Correct misspelling: balenced to balanced. + +Wed Nov 27 13:25:39 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_section_align): Check for an alignment of + 4, not an alignment of 16. Corrects August 7 patch. + +Tue Nov 26 10:33:16 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure, conf.in: Rebuild with autoconf 2.12. + + * config/tc-ppc.c (ppc_elf_lcomm): Don't give an error if no + alignment is specified. + + Add support for mips16 (16 bit MIPS implementation): + * config/tc-mips.c: Extensive additions for mips16 support, not + listed here. + (RELAX_OLD, RELAX_NEW): Use only 7 bits each. + (insn_uses_reg): Change last parameter to an enum. + * config/tc-mips.h (LOCAL_LABELS_DOLLAR): Define as 0. + (md_relax_frag): Define as mips_relax_frag. + (mips_relax_frag): Declare. + (struct mips_cl_insn): Add use_extend and extend fields. + (tc_fix_adjustable): Define. + * config/obj-elf.h (S_GET_OTHER): Define. + (S_SET_OTHER): Define. + +Mon Nov 25 18:02:29 1996 J.T. Conklin <jtc@beauty.cygnus.com> + + * config/tc-m68k.c (m68k_ip): Implement cases for new <, >, m, n, + o and p operand specifiers. + +Mon Nov 25 10:45:14 1996 Doug Evans <dje@seba.cygnus.com> + + * write.c: Delete "ifndef md_relax_frag" around is_dnrange. + (relax_segment, case rs_org): Move code inside braces. Move locals + target,after inside too. + (relax_segment, case rs_machine_dependent): Guts moved to ... + (relax_frag): New function. + Call md_prepare_relax_scan if defined. + * config/tc-m68k.h (md_prepare_relax_scan): Renamed from + M68K_AIM_KLUDGE. + +Mon Nov 25 08:49:36 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (address_registers): Use '$' as register + prefix instead of '%'. + (data_registers, other_registers, md_assemble): Likewise. + + * config/tc-mn10300.c (address_registers): Use '%' prefix for regs. + (data_registers, other_registers, md_assemble): Likewise. + + * config/tc-mn10300.c (md_assemble): Correctly determine the + correct location and type for each relocation. + (md_pcrel_from): Simplify. + +Fri Nov 22 15:42:26 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.c (md_convert_frag): Improve warning when branch is + converted into branch around branch. + +Thu Nov 21 11:56:11 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.h (DIFF_EXPR_OK): Don't define this. + (tc_fix_adjustable): Don't adjust relocs against weak symbols or + pc-relative relocs. + * config/tc-mn10300.c (md_begin): Set linkrelax. + (md_assemble): Create fixups as needed. + (md_apply_fix3): Gut. It shouldn't ever get called anymore. + +Tue Nov 19 17:48:06 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-d10v.c (parallel_ok): When automatically converting + serial ops to parallel, do not consider a branch as the first + instruction. + +Tue Nov 19 13:35:22 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (md_assemble): Handle MN10300_OPERAND_REG_LIST. + +Mon Nov 18 15:26:55 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (mn10300_insert_operand): Provide prototype + via PARAMS. + (check_operand): Likewise. + +Mon Nov 18 15:22:28 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-d10v.c (parallel_ok): Branch and link instructions + modify r13. + (write_2_short): Call parallel_ok to check whether two short + instructions the user requested execute in parallel, can be + executed that way. + +Thu Nov 14 11:17:49 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (write_2_short): Fix bug that wouldn't + allow a branch and link in parallel with an exe instruction. + +Fri Nov 8 13:55:03 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * doc/c-d10v.texi: Add info on @word modifier. + +Wed Nov 6 13:46:07 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (mn10300_insert_operand): MN10300_OPERAND_SPLIT + operands are assumed to be 32bits. Use "bits" field to hold the + number of bits in the main instruction word for MN10300_OPERAND_SPLIT. + (mn10300_check_operand): MN10300_OPERAND_SPLIT operands are assumed + to be 32bits. + + * config/tc-mn10300.c (mn10300_insert_operand): Shift low part + of a MN10300_OPERAND_SPLIT operand by operand->shift. + + * config/tc-mn10300.c (mn10300_insert_operand): Handle + MN10300_OPERAND_SPLIT. + +Tue Nov 5 13:30:40 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (md_assemble): Insert operands into + the extension part of the instruction if necessary. + (mn10300_insert_operand): Accept pointer to extension word + argument. Make insn a pointer argument too. Return type + is now void. All callers changed. + +Mon Nov 4 12:53:40 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (mn10300_insert_operand): Handle + repeated register operands. + +Fri Nov 1 10:42:49 1996 Ian Lance Taylor <ian@cygnus.com> + + * doc/as.texinfo: Added section on reporting bugs. + + * config/tc-alpha.c: Change uses of void * to PTR. Change the + alpha_macro emit field to expect a const argument, and change the + arg field to be const. Fix some spacing to follow the GNU + standard. + +Fri Nov 1 10:32:03 1996 Richard Henderson <rth@tamu.edu> + + * config/tc-alpha.c (md_parse_option): Add knowledge of 21164pc + (pca56) and 21264 (ev6) cpus. + (md_apply_fix): Private relocation types are now negative. + (alpha_force_relocation): Likewise. + (tc_gen_reloc): Likewise. + (emit_insn): Likewise. + (emit_ldXu): Do the right thing when the hardware can do byte insns. + (emit_stX): Likewise. + (emit_sextX): Likewise. + +Thu Oct 31 16:33:21 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (do_relocs_for): Call resolve_symbol_value on + a symbol found in a reloc. + + * symbols.c (resolve_symbol_value): Improve the error message if + an undefined symbol is used in an expression. + +Wed Oct 30 20:15:35 1996 Ian Lance Taylor <ian@cygnus.com> + + * doc/internals.texi: Rewrite, and add a lot of documentation. + * doc/Makefile.in (internals.info): New target. + +Mon Oct 28 10:48:40 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.h (md_cleanup): New function. This is needed to + write out any buffered instructions when a ".end" is found. + +Mon Oct 28 10:43:45 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * read.c (read_a_source_file): New hook md_cleanup(). + +Fri Oct 25 00:01:00 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (fix_new_exp): Use make_expr_symbol to build an + expression symbol for a complex fixup. + +Wed Oct 23 18:20:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (md_apply_fix3): Give a better warning message + for an unknown relocation type. + +Tue Oct 22 17:09:32 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-d10v.c (parallel_ok): Don't allow illegal combinations + of instructions. + +Tue Oct 22 11:28:39 1996 Ian Lance Taylor <ian@cygnus.com> + + * obj.h (struct format_ops): Add frob_file_after_relocs field. + * config/obj-multi.h (obj_frob_file_after_relocs): Define. + * config/obj-ecoff.c (ecoff_format_ops): Initialize new + frob_file_after_relocs field. + * config/obj-elf.c (elf_format_ops): Likewise. + * config/tc-mips.c: Undefine obj_frob_file_after_relocs before + including obj-elf.h. + +Mon Oct 21 11:38:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (cons_fix_new_mips): Only treat 8 byte reloc + specially if not ELF. + (md_apply_fix): Handle BFD_RELOC_64. + (tc_gen_reloc): Handle BFD_RELOC_64. + + * config/tc-i386.c (md_apply_fix3): Don't increment value for a PC + relative reloc when BFD_ASSEMBLER and OBJ_AOUT (more ugly gas + reloc hacking). + + * config/obj-aout.h (S_IS_DEFINE): non BFD_ASSEMBLER version: + Don't check S_GET_OTHER. + +Fri Oct 18 14:06:26 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_ip): Accept an odd floating point + register with l.s or s.s. + + * config/obj-aout.c (obj_pseudo_table): Use obj_aout_type for + .type pseudo-op. + (obj_aout_type): New static function. + +Thu Oct 17 17:55:17 1996 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in ($(OBJS)): Depend upon libiberty.h. + +Mon Oct 14 13:59:12 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (load_register): Add cast to offsetT when using + a constant with &~. + +Mon Oct 14 11:24:28 1996 Richard Henderson <rth@tamu.edu> + + * config/obj-elf.c (elf_frob_file): Move ECOFF debug processing to ... + (elf_frob_file_after_relocs): ... here. New function. + * config/obj-elf.h (obj_from_file_after_relocs): New macro. + * write.c (write_object_file): Call *frob_after_relocs after the + call to write_relocs. + + * config/tc-alpha.c: Use new BFD_RELOC_ALPHA_ELF_LITERAL reloc. + + * config/tc-alpha.c (load_expression): Don't SET_VALUE on the section + symbol, as this messes up linking. Instead, expand the recursive call + inline and change up the appropriate bits to get the 0x8000 offset + in the reloc addend. + +Thu Oct 10 17:30:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.h (tc_fix_adjustable): Permit the difference of + two symbols in the same segment to be adjusted. + + * configure.in: Don't get confused by CPU-VENDOR-linux-gnu. + * configure: Rebuild. + +Thu Oct 10 17:22:18 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_insert_operand): Change most warnings into + errors. + (ppc_elf_validate_fix): Ditto. + (md_assemble): Ditto. + (ppc_tc): Ditto. + (ppc_pe_section): Ditto. + (ppc_frob_symbol): Ditto. + +Thu Oct 10 12:05:45 1996 Jeffrey A Law (law@cygnus.com) + + * config/mn10300.c (md_assemble): Pass an extra shift count + to mn10300_insert_operand based on the opcode format. + (mn10300_insert_operand): Accept and use extra shift count + parameter. + + * config/tc-mn10300.c (md_assemble): Use FMT_* macros for + formats rather than hard-coded constants. + + * config/tc-mn10300.c (md_assemble): Format D5 instructions + are 7 bytes long. Write out instructions in big-endian format. + +Tue Oct 8 14:56:15 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.c (md_assemble): Tweak further so + that all instructions are parsed correctly. + +Tue Oct 8 13:02:21 1996 Ian Lance Taylor <ian@cygnus.com> + + * as.h: Include libiberty.h. + (xmalloc, xrealloc): Don't declare. + * as.c: Don't include libiberty.h. + * expr.c, read.c, stabs.c, config/obj-coff.c: Likewise. + * config/tc-mips.c: Likewise. + * messages.c: Likewise. + (xstrerror): Don't declare. + * xmalloc.c: Remove. + +Mon Oct 7 16:53:23 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10300.h (pre_defined_registers) Remove. + (system_registers, cc_names): Likewise. + (address_registers, data_registers, other_registers): New register + arrays. + (register_name, system_register_name, cc_name): Remove. + (mn10300_reloc_prefix): Likewise. + (data_register_name): New function. + (address_register_name, other_register_name): Likewise. + (md_assemble): Rough cut at parsing operands. Remove lots of + unwanted code. + (md_apply_fix3): Disable for now. + +Mon Oct 7 11:38:34 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/tc-m68k.c (select_control_regs): New function, extracted + out of m68k_init_after_args. + (m68k_init_after_args): Use it. + (mri_chip): Use it here as well to update set of allowed control + regs for movec. + +Mon Oct 7 11:24:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-elf.c (elf_begin): New function. + (obj_elf_section): Add the section symbol to the symbol table. + * config/obj-elf.h (obj_begin): Define. + (elf_begin): Declare. + * as.c (perform_an_assembly_pass): Call obj_begin if it is + defined. + +Fri Oct 4 18:37:32 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (fixup_segment): Subtract the section address + from a PC relative reloc if TC_M68K. + +Thu Oct 3 15:15:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.c (md_pseudo_table): Make .uahalf, .uaword, and + .uaxword available even if not OBJ_ELF. + (md_atof): Remove unused local variable wordP. + +Thu Oct 3 00:16:50 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-mn10x00.c, config/tc-mn10x00.h: New files + for Matsushita MN10x00 support. + * configure.in: Recognize mn10x00-*-* + * configure: Rebuilt. + +Wed Oct 2 15:54:03 1996 Klaus Kaempf <kkaempf@progis.de> + + * obj-evax.h: move openvms definitions from here to tc-alpha.c. + * tc-alpha.c: add support for vms_case_hack like in vax/vms. + (load_expression): track clobbering of base reg before jmp/jsr. + (s_alpha_file): pass case_hack flags and source filename via + symbol table to bfd. + * tc-alpha.h (TC_CONS_FIX_NEW): define + +Tue Oct 1 16:16:01 1996 Joel Sherrill <joel@oarcorp.com> + + * configure.in (mips-*-rtems*): New target, like mips-*-elf*. + * configure: Rebuild. + +Tue Oct 1 12:37:48 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (s_macro): Warn if a macro has the same name as a + pseudo-op. + (s_space): In m68k MRI mode, align to a word boundary. + * macro.c (define_macro): Add namep parameter. Change all + callers. + * macro.h (define_macro): Update declaration. + + * as.c (show_usage): Print bug report address. + (parse_args): Change version printing to match current GNU + standards. + * gasp.c (show_usage): Print bug report address. + (main): Change version printing to match current GNU standards. + + * config/tc-m68k.c (init_table): Correct access control unit + register numbers. From Ken Rose <rose@netcom.com>. + + * config/tc-alpha.c: Add some static function prototypes. + (alpha_macros): Move to top of file. Make static. + (alpha_num_macros): Move to top of file. + +Sat Sep 28 03:38:08 1996 Ian Lance Taylor <ian@cygnus.com> + + * listing.c (list_symbol_table): Remove bogus code in BFD64 case, + and just call sprintf_vma. + +Thu Sep 26 16:04:11 1996 Ian Lance Taylor <ian@cygnus.com> + + * expr.c (expr): Change >>= to >> (fix typo). (From meissner). + +Tue Sep 24 19:05:08 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (float_cons): Call md_flush_pending_output if it is + defined. + +Tue Sep 24 12:22:18 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (md_operand): Created. Allows operands to + start with '#'. + * config/tc-d10v.h (md_operand): Undefined. + +Mon Sep 23 12:13:18 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (add_fix): Treat a width of '3' like 'B'. + (md_assemble): A fixup width of '3' means a 1 byte reloc. + +Thu Sep 19 12:21:24 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (fixup_segment): Don't adjust PC relative + reloc for the i960 for a reloc in the same section. This undoes + one of the two changes made Aug 19. + +Wed Sep 18 12:11:58 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (obj_coff_endef): Both versions: Move C_STAT + symbols to the position of the debugging information. + +Mon Sep 16 11:41:40 1996 Ian Lance Taylor <ian@cygnus.com> + + * expr.c (expr): Always use unsigned right shifts for >>. + +Thu Sep 12 10:25:45 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-arm.c (md_apply_fix3): Update two thumb instruction + slots when processing BL fixups. + + * config/tc-arm.c (output_inst): Ensure Thumb BL fixup is marked + on the first half of the instruction. + +Wed Sep 11 00:09:35 1996 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (ecoff_stab): Create an expression symbol for a complex + stabs expression, rather than giving an error. + + * ecoff.c (ecoff_new_file): Don't do anything if we are still in + the same file. + +Tue Sep 10 11:45:37 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (append_insn): Fill in the value for a constant + jump, rather than creating a reloc. + +Mon Sep 9 10:57:42 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (append_insn): Don't swap an instruction which + sets a condition code with an instruction which uses a condition + code. + (mips_ip): In cases 'N' and 'M', look for $fccN rather than an + immediate value. + + * config/tc-mips.c (md_begin): Recognize r5000 for cpu. + (mips_ip): Give a better error message if the ISA level is wrong. + (md_parse_option): Recognize -mcpu=[v][r]5000. + +Sat Sep 7 13:25:55 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c (COUNT_TOP_ZEROES): Added macro to count + leading zeroes. + (load_register): Ensure hi32 bits are not lost during lo32bit + processing. Fix shift offset that was overflowing into the next + instruction field. Add code to generate shorter sequences for + constants with a single contiguous seqeuence of ones. + +Fri Sep 6 17:07:12 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (d10v_dot_word): New function to support + "@word" with the word pseudo-op. + (md_apply_fix3): Cleanup and changes to support correct sizes + for 16 and 18-bit relocs. + +Fri Sep 6 16:00:29 1996 Doug Evans <dje@canuck.cygnus.com> + + * configure.in (sparc-*-aout): Set `em'. + * configure: Regenerated. + * config/te-sparcaout.h: New file. + * config/tc-sparc.h (TARGET_BYTES_BIG_ENDIAN): Define. + Ifdef TE_SPARCOUT define TARGET_FORMAT and SPARC_BIENDIAN. + * config/tc-sparc.c (INSN_BIG_ENDIAN): New macro. + (SPECIAL_CASE_{SETSW,SETX}): Define. + ({NOP,OR,FMOVS,SETHI,SLLX,SRA}_INSN): Define. + (md_begin): Delete setting of `target_big_endian'. + (output_insn): New function. + (md_assemble): Rewrite. Add `setx' support. + (sparc_ip): Handle `0' operand char. Recognize setuw, setsw, setx + special cases. + (md_atof): Add little endian support. + (md_number_to_chars): Likewise. + (md_apply_fix): Likewise. + (md_longopts): Recognize -EL,-EB ifdef SPARC_BIENDIAN. + (md_parse_option): Likewise. + (md_show_usage): Print -EL, -EB ifdef SPARC_BIENDIAN. + +Thu Sep 5 13:40:29 1996 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (ecoff_new_file): New function. + * ecoff.h (ecoff_new_file): Declare. + * config/obj-ecoff.h (obj_app_file): Define. + +Thu Sep 5 13:39:25 1996 Richard Henderson <rth@tamu.edu> + + * config/tc-alpha.c (load_expression): Bias the .lit8 section + symbol by 32k so that our 16-bit signed offset can address the + entire chunk. Reported by <matt@lkg.dec.com>. + +Wed Sep 4 10:23:20 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (load_register): Remove unused variable tmp. + +Wed Sep 4 11:24:29 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c (load_register): Remove unnecessary code that + was causing the high 32bits of 64bit constants to be lost. + +Tue Sep 3 13:52:56 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Added changes to support function + pointers and "@word" syntax. + +Fri Aug 30 18:12:00 1996 Ian Lance Taylor <ian@cygnus.com> + + Add SH ELF support. + * configure.in (sh-*-elf*): New target. + * config/tc-sh.h (TARGET_ARCH): Define. + (WORKING_DOT_WORD): Define. + (TC_COFF_FIX2RTYPE): Only define if OBJ_COFF. + (BFD_ARCH, COFF_MAGIC, TC_COUNT_RELOC): Likewise. + (TC_RELOC_MANGLE, tc_coff_symbol_emit_hook): Likewise. + (DO_NOT_STRIP, NEED_FX_R_TYPE, TC_KEEP_FX_OFFSET): Likewise. + (TC_COFF_SIZEMACHDEP, tc_frob_file): Likewise. + (SUB_SEGMENT_ALIGN): Likewise. + (RELOC_32): Don't define. + (tc_frob_file_before_adjust): Define if BFD_ASSEMBLER. + (target_big_endian): Declare if OBJ_ELF. + (TARGET_FORMAT): Define if OBJ_ELF. + * config/tc-sh.c: Use BFD reloc codes instead of SH COFF reloc + numbers throughout. + (tc_crawl_symbol_chain): Only define if OBJ_COFF. + (tc_headers_hook, tc_coff_sizemachdep): Likewise. + (struct sh_count_relocs): Define. + (sh_count_relocs): New static function, broken out of + sh_frob_file. Add BFD_ASSEMBLER code. + (sh_frob_section): Likewise. + (sh_frob_file): Call sh_frob_section. + (md_convert_frag): If BFD_ASSEMBLER, change type of headers, and + call section_symbol rather than seg_info (seg)->dot. + (md_section_align): Add OBJ_ELF version. + (SWITCH_TABLE_CONS): Define. + (SWITCH_TABLE): Use SWITCH_TABLE_CONS. + (md_apply_fix): Change parameter types if BFD_ASSEMBLER. Only + handle fx_r_type == 0 if not BFD_ASSEMBLER. Return 0 if + BFD_ASSEMBLER. + (struct reloc_map): Define if not BFD_ASSEMBLER. + (coff_reloc_map): Likewise. + (sh_coff_reloc_mangle): Use coff_reloc_map to convert fx_r_type. + (tc_gen_reloc): New function if BFD_ASSEMBLER. + * write.c (write_relocs): Ifdef out fx_where test which triggers + inappropriately for SH ELF. + (write_object_file): Call tc_frob_file_before_adjust and + obj_frob_file_before_adjust if they are defined. + + * write.c (write_object_file): Use BFD_RELOC_16, not + BFD_RELOC_NONE, when calling fix_new_exp for a broken word. + + * read.c (emit_expr): Fix conversion of byte count to BFD reloc + code. + +Fri Aug 30 14:47:38 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (find_opcode): Fix problem with calculating + branch sizes in across sections. + +Wed Aug 28 19:20:04 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (find_opcode): Fix a bug which could generate + the wrong opcode for cases like st2w where there are many forms + of the same instruction. + +Tue Aug 27 13:53:22 1996 Ian Lance Taylor <ian@cygnus.com> + + * expr.c (operand): If md_parse_name is defined, call it before + calling symbol_find_or_make. + * config/tc-ppc.h (md_parse_name): Define. + (ppc_parse_name): Declare. + * config/tc-ppc.c (reg_name_search): Add regs and regcount + parameters. + (register_name): Update call to reg_name_search. + (cr_operand): New static variable. + (cr_names): New static const array. + (ppc_parse_name): New function. + (md_assemble): If PPC_OPERAND_CR is set in the operand flags, set + cr_operand before calling expression. + +Tue Aug 27 09:05:50 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (tc_gen_reloc): Add new argument to + hppa_gen_reloc_type call. + +Mon Aug 26 18:24:51 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Fixed ".word". Fixed problem with range checking + on addresses. Improved error messages. + * doc/c-d10v.texi: Added docs for register pairs. + +Mon Aug 26 13:39:27 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (parallel_ok): Fix bug in parallel + checking code. + +Mon Aug 26 14:38:22 1996 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (init_file): Initialize fMerge to 1. + (add_file): Restore old file merging code, but only merge files if + fMerge is set. + (ecoff_directive_loc): Clear fMerge field of current file. + (ecoff_generate_asm_lineno): Likewise. + +Fri Aug 23 11:40:47 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * doc/c-d10v.texi: Fix typo. + +Thu Aug 22 10:20:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Set and substitute HLDENV. + * configure: Rebuild. + * Makefile.in (HLDENV): New variable. + (as.new): Use $(HLDENV). + + * ecoff.c (ecoff_directive_endef): Avoid a division by zero error + if an array dimension is not known. + +Thu Aug 22 10:50:00 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Fix a reloc bug caused by my last change. + * doc/c-d10v.texi: Cleanup. + +Wed Aug 21 15:50:54 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * doc/c-d10v.texi: New file. + * doc/all.texi: Added D10V stuff. + * doc/as.texinfo: Added D10V stuff. + +Tue Aug 20 14:10:02 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: All references to defined symbols should + now use the optimal instruction. .float and .double now work. + +Mon Aug 19 14:41:36 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (fixup_segment): Adjust PC relative reloc by + section address for the i960 as is done for the i386. + +Thu Aug 15 16:37:59 1996 Stan Shebs <shebs@andros.cygnus.com> + + * mpw-config.in: Add wildcards for config matching, add mips-*-* + case, forward-include bfd/elf-bfd.h. + +Thu Aug 15 13:24:30 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Add additional information to the opcode + table to help determinine which instructions can be done + in parallel. + +Thu Aug 15 17:01:31 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-arm.c: Major changes to add Thumb support, with lots + of change input from <rearnsha@armltd.co.uk>. + Reverted to INSN_SIZE macro, rather than insn_size variable. + (insns): Added ARM "bx" instruction support. + (tinsns): Added Thumb instruction definition structure. + (arm_tops_hsh): Added hash structure for Thumb opcodes. + (md_pseudo_table): Added ".arm", ".thumb" and ".code" pseudo-ops. + (opcode_select,s_arm,s_thumb,s_code): Added. + (decode_shift): Allow upper-case RRX. + (do_ldst): Simpler halfword support. + (do_ldmstm): Improved. + (reg_list, do_bx, thumb_reg, thumb_add_sub, thumb_shift, + thumb_mov_compare, thumb_load_store, do_t_arit, do_t_add, + do_t_asr, do_t_branch, do_t_bx, do_t_compare, do_t_ldmstm, + do_t_ldrb, do_t_ldrh, do_t_lds, do_t_lsl, do_t_lsr, do_t_mov, + do_t_push_pop, do_t_str, do_t_strb, do_t_strh, do_t_sub, do_t_swi, + do_t_adr): Added. + (md_apply_fix3): Add support for BFD_RELOC_ARM_THUMB_* relocations. + (md_parse_option): Add support for -mthumb. + (md_show_usage): Updated to reflect new command line option. + (arm_data_in_code, arm_canonicalize_symbol_name): Added. + * config/tc-arm.h: Provide TC_FIX_TYPE to allow private ARM + fragment information to be held. + +Thu Aug 15 16:12:00 1996 Richard Earnshaw (rearnsha@armltd.co.uk) + + * tc-arm.c (md_apply_fix3): Also set fixP->fx_done if fx_addsy is + non-null, but is a constant. + (fix_new_arm): Call make_expr_symbol to make the expression symbol + so that error reporting will work correctly. + +Wed Aug 14 10:37:21 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i386.c (tc_i386_fix_adjustable): Don't adjust relocs + against weak symbols. + +Tue Aug 13 17:39:24 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.h (TC_FORCE_RELOCTION): Define if OBJ_XCOFF. + (ppc_force_relocation): Declare if OBJ_XCOFF. + * config/tc-ppc.c (ppc_force_relocation): New function if + OBJ_XCOFF. + +Mon Aug 12 16:49:43 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.h (BYTE_ORDER): Don't define. No longer used. + +Fri Aug 9 17:48:28 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Fix problem with relocs. + +Fri Aug 9 14:16:14 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.c (sh_do_align): If not BFD_ASSEMBLER, always align + with nops if not in data_section or bss_section. + +Thu Aug 8 12:32:56 1996 Klaus Kaempf <kkaempf@progis.de> + + Add support for openVMS/Alpha. + * as.h (PRINTF_LIKE): Don't define if VMS, for now. + * config/obj-evax.c: New file. + * config/obj-evax.h: New file. + * config/tc-alpha.c: Add support for EVAX format if OBJ_EVAX is + defined. + * config/tc-alpha.h: Add support for EVAX format if OBJ_EVAX is + defined. Add case for bfd_target_evax_flavour. + * config/vms-a-conf.h: New file. + * conf-a-gas.com: New file. + * configure.in: Add target alpha-*-*vms*. + * configure: Rebuild. + * makefile.vms: New file. + * read.c (s_lcomm): Align bss_seg on 8 byte boundary if OBJ_EVAX. + Don't call ffs on openVMS/Alpha. + +Wed Aug 7 14:19:03 1996 Philippe De Muyter <phdm@info.ucl.ac.be> + + * configure.in: Make GAS_CHECK_DECL_NEEDED include <string.h> or + <strings.h> if they exist. Call GAS_CHECK_DECL_NEEDED on strstr + and sbrk. + * acconfig.h (NEED_DECLARATION_STRSTR): New macro. + (NEED_DECLARATION_SBRK): New macro. + * configure, conf.in: Rebuild. + * as.h: Only include <strings.h> if HAVE_STRINGS_H. + (strstr): Declare if NEED_DECLARATION_STRSTR. + * as.c: If HAVE_SBRK and NEED_DECLARATION_SBRK, declare sbrk. + +Wed Aug 7 11:50:26 1996 Ian Lance Taylor <ian@cygnus.com> + + * symbols.c (resolve_symbol_value): Handle addition or subtraction + by a constant before entering the main switch. Reject attempts to + apply an arithmetic function to non-absolute symbols, except for + the special case of subtraction of two symbols in the same + section. + + * config/tc-mips.c (md_section_align): Do align if OBJ_ELF, but + not to more than a 16 byte boundary. + + * config/tc-i386.c (tc_gen_reloc): Accept all relocs; remove + #ifndef OBJ_ELF lines. From Eric Valette <valette@crf.canon.fr>. + (tc_gen_reloc): If out of memory call as_fatal rather than + assert. If no howto found, call as_bad_where rather than + as_fatal. Change the error message slightly. Set howto to a + non-NULL value in order to keep going. + +Tue Aug 6 12:58:03 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Added code to support 32-bit fixups for stabs. + +Tue Aug 6 11:15:26 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (get_specific): New operand "size" derived + from ".b", ".w" and ".l" extensions. All callers changed. If + the base instruction has no operands, then use the size to + determine which specific instruction to use. + +Mon Aug 5 14:21:10 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i960.c (mem_fmt): Call parse_expr before emit. + +Fri Aug 2 11:23:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_section_align): Don't change addr if + OBJ_ELF. + +Thu Aug 1 23:51:52 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c: Revert yesterday's changes. + +Wed Jul 31 14:46:11 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Disable range checking on 16-bit values. + +Wed Jul 31 16:27:19 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (m68k_ip): Set ok_arch for every instruction, + not just the ones that don't match. + +Wed Jul 31 11:45:15 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Fixed bugs in short relocs and range checking. + +Wed Jul 31 15:41:42 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-arm.c: Changed INSN_SIZE to variable insn_size, as + pre-cursor to adding Thumb support. Also added cpu_variant flag + information to each of the asm_flg structures. + (md_parse_option): Updated ARM7 parsing to allow 't' for + thumb/halfword support, aswell as 'm' for long multiply. + (md_show_usage): Updated help message. + (md_assemble): Check that instruction flags are applicated to the + current cpu variant. + (md_apply_fix3, tc_gen_reloc): Add BFD_RELOC_ARM_OFFSET_IMM8 and + BFD_RELOC_ARM_HWLITERAL relocation support for new halfword and + signextension instructions. + (do_ldst): Generate halfword and signextension variants if + mnemonic flags match. + (ldst_extend): Do not allow shifts in the offset field of halfword + or signextension instructions. + (validate_offset_imm): Provide check on halfword and signextension + immediate range. + (add_to_lit_pool): Merge identical literal pool values. + +Tue Jul 30 14:28:23 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (selector_table): Add 'E' selector. + (cons_fix_new_hppa): Don't coke on e_esel. + (tc_gen_reloc, SOM version): Handle R_COMP2 when used + to help generate exception handling tables. + (md_apply_fix): Don't try to apply fixups with an e_esel + selector. + (hppa_fix_adjustable): Fixups with e_esel selectors + are not adjustable. + +Tue Jul 30 15:51:41 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.c (md_pseudo_table): Add 2byte, 4byte, and 8byte + pseudo-ops. + +Fri Jul 26 11:43:03 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Added lots of error checking. Added hacks + to support accumulator shifts. + +Fri Jul 26 11:56:08 1996 Ian Lance Taylor <ian@cygnus.com> + + * symbols.c (S_SET_EXTERNAL): Let .weak override. + (S_CLEAR_EXTERNAL): Likewise. + (S_SET_WEAK): Remove error; just let .weak override. + +Thu Jul 25 15:22:51 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (md_assemble): Now handles multiline + instructions. + +Thu Jul 25 12:03:33 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Fix packaging bug. Added range checking. + Added kludge for divs instruction. Fixed minor problem with + multiple text sections. + * config/tc-d10v.h (d10v_cleanup): Change prototype. + +Tue Jul 23 10:49:36 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c (md_apply_fix3): Fix all instruction + addresses to be right-shifted by 2. + +Mon Jul 22 11:32:36 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: Many changes to get relocs working. + (register_name): No longer creates a symbol for register names. + (pre_defined_registers): moved to opcodes/d10v-opc.c. + (d10v_insert_operand): Now works correctly for either container. + * config/tc-d10v.h (d10v_cleanup): Declare. + +Mon Jul 22 14:01:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (tc_gen_reloc): BFD_RELOC_PCREL_HI16_S and + BFD_RELOC_PCREL_LO16 are expected to be PC relative. + +Mon Jul 22 12:46:55 1996 Richard Henderson <rth@tamu.edu> + + * tc-alpha.c: Patches to track current minimum alignment to reduce + the number of fragments created with frag_align. + (alpha_current_align): New static variable. + (s_alpha_text): Reset alignment to 0. + (s_alpha_data, s_alpha_rdata, s_alpha_sdata): Likewise. + (s_alpha_stringer, s_alpha_space): New functions. + (s_alpha_cons, alpha_flush_pending_output): Remove functions. + (alpha_cons_align): New function to replace both of them. + (emit_insn): Only align if alpha_current_align is less than 2; + reset alpha_current_align to 2. + (s_alpha_gprel32): Likewise. + (s_alpha_section): New function. Basically duplicate the other + alpha section change hooks. Only define for ELF. + (s_alpha_float_cons): Simplify alignment handling. + (md_pseudo_table): Only define "rdata" and "sdata" if OBJ_ECOFF. + If OBJ_ELF, define "section", "section.s", "sect", and "sect.s". + Don't define the s_alpha_cons pseudo-ops. Do define + s_alpha_stringer and s_alpha_space pseudo-ops. + (alpha_align): Skip if less than current default alignment. Set + default alignment. + * tc-alpha.h (md_flush_pending_output): Remove. + (md_cons_align): Add. + + * tc-alpha.c: Add oodles of function description comments. + (md_bignum_to_chars): Remove; there are no callers. + (md_show_usage): Mention some more variants. + +Thu Jul 18 15:54:54 1996 Ian Lance Taylor <ian@cygnus.com> + + From Andrew Gierth <ANDREWG@microlise.co.uk>: + * configure.in (sparc-*-sysv4*): New target. + * configure: Rebuild. + + * config/tc-sparc.c (md_pseudo_table): Change uahalf, uaword, and + uaxword to use s_uacons. + (sparc_no_align_cons): New static variable. + (s_uacons): New static function. + (sparc_cons_align): If sparc_no_align_cons is set, just clear it + and return. + + * config/tc-sparc.c (s_common): Remove unused label allocate_bss. + + * configure.in: Add mips-*-irix6* target. Handle Irix 6 like Irix + 5 with regard to shared libraries. + * configure: Rebuild. + + * config/tc-m68k.c (m68k_ip): Use the correct length when + allocating space for the unsupported architecture error message. + +Thu Jul 18 12:57:10 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * configure.in (d10v-*-*): Allow d10v-*-*, don't require d10v-*-elf*. + +Wed Jul 17 14:25:13 1996 Martin M. Hunt <hunt@pizza.cygnus.com> + + * config/tc-d10v.c: New file. + * config/tc-d10v.h: New file. + * configure (d10v-*-elf): New target. + * configure.in (d10v-*-elf): New target. + +Fri Jul 12 20:54:19 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (md_parse_option): Recognize -K PIC. + +Wed Jul 10 12:39:08 1996 Richard Henderson <rth@tamu.edu> + + * config/tc-alpha.c (alpha_align): Change fill parameter + to a pointer. Take NULL as 0 or nop depending on section. Change + all callers. + (s_alpha_align): Rename local variables. + + * doc/as.texinfo (.align): Document action of omitted + fill parameter. + +Wed Jul 10 00:23:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (md_apply_fix3): Give a useful error message + when an unsupported PC relative reloc is seen, rather than calling + abort. + + * app.c (do_scrub_chars): Remove not_cpp_line local variable. + Instead, check state when '#' comment is seen. + +Mon Jul 8 14:11:49 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_regmask_frag): Only define if OBJ_ELF or + OBJ_MAYBE_ELF. + (tc_gen_reloc): If fixup was changed to be PC relative, change + reloc type accordingly. Use name of reloc in error message. + + * as.h: Don't define const or volatile. + * flonum.h: Don't define const. + + * config/tc-m68k.c (tc_gen_reloc): Change the code appropriately + if fx_pcrel is set. Correct setting the addend case in the + OBJ_ELF case (from Andreas Schwab + <schwab@issan.informatik.uni-dortmund.de>). + (md_show_usage): Correct -mfc5200 to -m5200. + +Fri Jul 5 10:32:58 1996 J.T. Conklin <jtc@rtl.cygnus.com> + + * doc/c-m68k.texi: Document -m5200 flag. + * doc/as.texinfo: Likewise. + + * config/tc-m68k.c (m68k_ip): The coldfire does not support 8x + scale factor. + +Fri Jul 5 11:07:24 1996 Ian Lance Taylor <ian@cygnus.com> + + * symbols.c (S_SET_EXTERNAL): Change as_warn to as_bad. + (S_CLEAR_EXTERNAL, S_SET_WEAK): Likewise. + +Thu Jul 4 11:59:46 1996 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (VERSION): Set to cygnus-2.7.1. + + * Released binutils 2.7. + +Thu Jul 4 10:11:33 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c (mips_ip): Only perform range check when + dealing with O_constant expressions. + +Wed Jul 3 15:02:21 1996 J.T. Conklin <jtc@rtl.cygnus.com> + + * m68k-parse.h (m68k_register): Add new coldfile control + registers. + + * config/tc-m68k.c (mcf5200_control_regs): New variable, + array of control registers for the coldfire. + (cpu_of_arch): Added mcf5200. + (archs): Added mcf5200. + (init_table): Add new control registers. + (m68k_ip): Added support for new control registers. + (m68k_init_after_args): Likewise. + + * config/tc-m68k.c (md_show_usage): Add -m5200 to usage text. + +Wed Jul 3 16:05:50 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.h (is_it_end_of_statement): Declare. + * read.c (is_it_end_of_statement): Remove declaration. + + * config/tc-ppc.c (ppc_elf_suffix): Correct parenthesization of || + within &&. + (md_assemble): Fix handling of @l with an unsigned constant. Add + default case to reloc switch. + + * config/tc-i386.h (AOUT_MACHTYPE): Define as 0 if TE_386BSD. + + Based on patches from Tom Quiggle <quiggle@sgi.com>: + * ecoff.c (last_lineno): New static variable. + (add_procedure): Set last_lineno. + (ecoff_directive_loc): Likewise. + (ecoff_generate_asm_lineno): Likewise. + (ecoff_fix_loc): New function. + * ecoff.h (ecoff_fix_loc): Declare. + * config/tc-mips.c (append_insn): When inserting nops, and using + ECOFF debugging, call ecoff_fix_loc. + +Tue Jul 2 23:02:12 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (build_bytes): If an operand type is + marked as SRC_IN_DST retrieve it from the "destination" op. + +Sat Jun 29 13:38:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in (arm-*-riscix*): Set emulation to riscix. + * configure: Rebuild. + * config/te-riscix.h: New file to define TE_RISCIX. + + * config/tc-sh.h (SUB_SEGMENT_ALIGN): Define. + +Fri Jun 28 15:14:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (config.status): Just run config.status as other + tools do. + +Fri Jun 28 11:09:38 1996 Stan Shebs <shebs@andros.cygnus.com> + + * mpw-config.in (TARGET_OS): Add definition to conf. + +Thu Jun 27 20:39:40 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c (append_insn): Parenthesize + cop_interlocks expressions. + +Thu Jun 27 12:18:26 1996 Ian Lance Taylor <ian@cygnus.com> + + * listing.c (listing_print): Close the listing file if it is not + stdout. Close the other files opened for the listing. + + * config/tc-sparc.h (md_cons_align): Define. + (sparc_cons_align): Declare. + (HANDLE_ALIGN): Define. + (sparc_handle_align): Declare. + * config/tc-sparc.c (sparc_cons_align): New function. + (sparc_handle_align): New function. + * read.c (cons_worker): Call md_cons_align if it is defined. + + * as.h (struct frag): Add fr_file and fr_line fields. + * frags.c (frag_new): Set fr_file and fr_line. + (frag_var): Likewise. + (frag_variant): Likewise. + + * as.h (struct frag): Remove unused align_mask and align_offset + fields. + + * listing.c (calc_hex): Offset by fr_fix when examining fr_var. + From <uddeborg@carmen.se>. + +Wed Jun 26 13:21:34 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in (mips-*-osf*): New target. + * configure: Rebuild. + + * config/tc-m68k.c: Add 68ec060 as a synonym for 68060. + +Wed Jun 26 16:23:08 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c: Added cop_interlocks, to avoid NOP insertion + between co-processor comparisons and branches for the VR4300. + +Mon Jun 24 18:02:50 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) + + * Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir, + INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values. + (docdir): Removed. + * configure.in (AC_PREREQ): autoconf 2.5 or higher. + * doc/Makefile.in (bindir, libdir, datadir, mandir, infodir, + includedir): Use autoconf set values. + (docdir): Removed. + +Mon Jun 24 11:58:14 1996 Ian Lance Taylor <ian@cygnus.com> + + * listing.c (listing_eject): Don't do anything if listing is 0. + (listing_list): Likewise. + (listing_source_line): Likewise. + (listing_title): Don't save title if listing is 0. + (listing_source_file): Check listing rather than listing_tail. + + * configure.in: On alpha*-*-osf*, link against libbfd.a if not + using shared libraries. + * configure: Rebuild. + +Fri Jun 21 18:22:23 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_ip): In case 'i'/'j', don't require an + absolute expression if a relocation type was specified. + +Fri Jun 21 17:40:16 1996 Joel Sherrill <joel@merlin.gcs.redstone.army.mil> + + * configure.in: Add support for *-*-rtems* configurations. + * configure: Rebuild. + +Fri Jun 21 16:01:18 1996 Richard Henderson <rth@tamu.edu> + + * configure.in: Add alpha-*-linuxecoff* target. Use elf for + alpha-*-linux* target. Force bfd_gas for alpha-*. Require + opcodes library for alpha. + * configure: Rebuild with autoconf 2.10. + * config/tc-alpha.c: Substantial rewrite to add ELF support and + use new opcode table. + * config/tc-alpha.h (md_undefined_symbol): Don't define. + (LOCAL_LABEL): Define differently if OBJ_ELF. + (FAKE_LABEL_NAME): Define if OBJ_ELF. + * config/alpha-opcode.h: Remove. + * config/obj-elf.h: If TC_ALPHA, define ECOFF_DEBUGGING. + * Makefile.in (TARG_CPU_DEP_alpha): Depend upon + include/opcode/alpha.h rather than config/alpha-opcode.h. + +Thu Jun 20 19:10:28 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-aout.c (obj_emit_relocations): Give an error if the + relocation symbol was not resolved. + * config/obj-coff.c (do_relocs_for): Likewise. + + * write.c (adjust_reloc_syms): Refetch the symbol section after + calling S_GET_VALUE, since it may have changed. + + * expr.c (struct expr_symbol_line): Define. + (expr_symbol_lines): New static variable. + (make_expr_symbol): Add entry to expr_symbol_lines. + (expr_symbol_where): New function. + * expr.h: Use extern on function declarations. + (expr_symbol_where): Declare. + * symbols.c (resolve_symbol_value): Try to use expr_symbol_where + rather than printing the meaningless name of an expression + symbol. + +Thu Jun 20 15:57:41 1996 Ken Raeburn <raeburn@cygnus.com> + + * config/tc-i386.c (md_number_to_chars): Deleted. + * config/tc-i386.h (md_number_to_chars): New macro. + + * config/tc-alpha.c (build_operate_n, build_mem): Moved earlier in + the file. + (load_symbol_address, load_expression): Use build_mem. + (build_operate): New function. + (emit_addq_r): Use it. + + Wed Mar 13 22:14:14 1996 Pat Rankin <rankin@eql.caltech.edu> + + * symbols.c (colon): #if VMS, use S_SET_OTHER to store `const_flag'. + + Tue Mar 5 14:31:45 1996 Pat Rankin <rankin@eql.caltech.edu> + + * config/tc-vax.h (NOP_OPCODE): Define. + + Sun Feb 4 21:01:03 1996 Pat Rankin <rankin@eql.caltech.edu> + + * config/obj-vms.h (S_IS_COMMON): Define. + (S_IS_LOCAL): Check for \002 as well as \001. + (LONGWORD_ALIGNMENT): New macro. + (SUB_SEGMENT_ALIGN): Use it. + + Fri Jan 26 17:44:09 1996 Pat Rankin <rankin@eql.caltech.edu> + + * config/vms-conf.h: Reconcile with conf.in. + +Wed Jun 19 11:31:50 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (is_dnrange): Only define if TC_GENERIC_RELAX_TABLE is + defined. + + * doc/as.texinfo: Document that any number of hex digits can + follow \x. + + * as.c (struct defsym_list): Define. + (defsyms): New static variable. + (parse_args): Just put --defsym arguments on defsyms list, rather + than defining them. + (main): Define defsyms after output file is created. + + * config/tc-m68k.c (m68k_ip): Reject PRE and POST indexing mode on + cpu32. From Eric Norum <Eric.Norum@usask.ca>. + + * config/tc-mips.c (mips_ip): In cases 'I', 'i', and 'j', set + insn_error rather than calling check_absolute_expr. + + * as.c (emulation_name): Remove unused static variable. + (default_emul_bfd_name): Add return NULL to avoid warning. + * ecoff.c (ecoff_stab): Remove unused variables name and + name_end. + * frags.c (frag_new): Remove unused variable tmp. + * hash.c (hash_grow): Parenthesize + within <<. + (hash_print_statistics): Use %lu, not %d, to print unsigned + long variables. + * messages.c: Include "libiberty.h". + (fprint_value): Add cast to avoid printf warning. + (sprint_value): Likewise. + * read.c: Include "ecoff.h". + (emit_expr): Add casts to avoid printf warnings. + * read.h: Use extern for function declarations. + (pop_insert): Declare. + * stabs.c: Include "ecoff.h". + * subsegs.c (subseg_set_rest): Remove unused variables tmp, + former_last_fragP, and new_fragP. + * subsegs.h (subsegs_print_statistics): Declare. + * symbols.c (debug_verify_symchain): Change macro to discard + arguments. + * write.c (dump_section_relocs): Likewise. + * write.h: Use extern for function declarations. + (write_print_statistics): Declare. + * config/e-mipsecoff.c (mipsecoff_bfd_name): Return NULL to avoid + warning. + * config/e-mipself.c (mipself_bfd_name): Likewise. + * config/obj-elf.h (elf_ecoff_set_ext): Declare. + + * config/tc-sparc.h (TC_RELOC_RTSYM_LOC_FIXUP): If OBJ_ELF, always + emit relocations against external symbols. + + * config/tc-alpha.c (tc_gen_reloc): Output a sensible error + message if bfd_reloc_type_lookup fails, rather than calling + assert. + + * config/tc-alpha.c (alpha_force_relocation): Add + BFD_RELOC_12_PCREL to switch. + +Tue Jun 18 20:29:57 1996 Doug Evans <dje@canuck.cygnus.com> + + * config/tc-i386.h (LOCAL_LABEL,FAKE_LABEL_NAME): Use defaults for + TE_PE (Lfoo, not .Lfoo). + +Tue Jun 18 17:13:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (s_fill): Don't warn about a zero repeat count. + + * config/tc-mips.c (mips_ip): Don't warn about using AT as a + coprocessor register. + + * config/tc-i386.c (md_assemble): When checking the size of a + register to set the size of an instruction, do a bitwise and with + Reg8 and Reg16 rather than requiring the type to be exactly Reg8 + or Reg16. + +Tue Jun 18 13:19:51 1996 Jeffrey A. Law <law@rtl.cygnus.com> + + * config/tc-h8300.c (parse_reg): Tweak error messages. + (build_bytes): Likewise. + (skip_colonthing): Handle :32 suffix. + (get_specific): Promote L_24 to L_32 if it makes a match. + Don't always promote L_8 to L_16. + (do_a_fix_imm): Clean up L_32 and L_24 handling. + + * config/tc-h8300.c (Smode): New variable. + (h8300hmode): Turn off Hmode. + (h8300smode): New function. Turn on Smode and Hmode. + (md_pseudo_table): New ".h8300s" pseudo-op. + (parse_reg): Handle "exr" register. + (get_operand): Handle bizarre syntax for "stm.l" and "ldm.l". + Handle "mach" and "machl" operands for ldmac. + (get_specific): Handle "stm.l" and "ldm.l". + (build_bytes): Handle "stm.l" and "ldm.l"; handle MACREG operands. + * config/tc-h8300.h (COFF_MAGIC): Handle H8/S magic number. + (Smode): Declare. + +Mon Jun 17 15:50:53 1996 J.T. Conklin <jtc@rtl.cygnus.com> + + * doc/as.texinfo: Reorder chapter of machine dependent options so + that it is sorted by chip name. + + * doc/as.texinfo: Use consistant spelling of Vax. + * doc/c-vax.texi: Likewise. + +Mon Jun 17 11:26:56 1996 Jeffrey A. Law <law@rtl.cygnus.com> + + * config/tc-hppa.c (md_pseudo_table): Add ".begin_try" and ".end_try" + pseudo ops. + (tc_gen_reloc, SOM version): Handle R_BEGIN_TRY and R_END_TRY. + (md_apply_fix): Likewise. + (pa_try): New function. + (hppa_force_relocation): Force relocs for BEGIN_TRY and END_TRY. + +Sun Jun 16 22:57:47 1996 Jeffrey A. Law <law@rtl.cygnus.com> + + * config/tc-hppa.c (md_pseudo_table): Add ".level" pseudo op. + (pa_level): New function. + +Fri Jun 14 20:06:44 1996 Ian Lance Taylor <ian@cygnus.com> + + * listing.c (listing_newline): Don't do anything if listing is 0. + +Thu Jun 13 17:50:54 1996 Ian Lance Taylor <ian@cygnus.com> + + * subsegs.c (section_symbol): If symbol_table_frozen is set, call + symbol_create, not symbol_new. + +Wed Jun 12 14:10:44 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (adjust_reloc_syms): Don't set sy_used_in_reloc for an + absolute symbol unless TC_FORCE_RELOCATION returns true. + + * config/obj-coff.c (previous_file_symbol): Remove BFD_ASSEMBLER + version. + (c_dot_file_symbol): BFD_ASSEMBLER version: Don't set the value of + the symbol to a pointer. Don't set previous_file_symbol. + Simplify symbol list rearrangement. + (coff_frob_symbol): Don't do anything with C_FILE symbols. + (coff_adjust_symtab): Don't check previous_file_symbol. + +Mon Jun 10 14:52:29 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_lcomm): New function for .lcomm + directive. + (md_pseudo_table): Add ppc_elf_lcomm. + +Mon Jun 10 11:45:51 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (m68k_ip): Accept ABSL for 'O', so that `bfextu + d0{24:1},d0' works without an immediate prefix on the bit numbers. + (md_begin): Add digits to alt_notend_table. + (md_parse_option): Make s a const pointer. + + * config/tc-sparc.c (md_pseudo_table): Add "empty". + (s_empty): New static function. + + * config/obj-coff.c (struct filename_list): Only define if not + BFD_ASSEMBLER. + (filename_list_head, filename_list_tail): Likewise. + (c_section_symbol): Remove unused BFD_ASSEMBLER version. + (obj_coff_endef, BFD_ASSEMBLER version): Don't set the debugging + flag for C_MOS, C_MOE, C_MOU, or C_EOS symbols, since they should + have a section of N_ABS rather than N_DEBUG. If we do a merge, + remove the new symbol from the list. + (obj_coff_endef, both versions): Call tag_insert even if there is + an old symbol with the same name, if the old symbol does not + happen to be a tag. + (coff_frob_symbol): Check SF_GET_TAG, C_EOF, and C_FILE outside of + the SF_GET_DEBUG condition. Don't call SA_SET_SYM_ENDNDX with a + symbol that will be moved to the end of the symbol list. + (coff_adjust_section_syms): Always call section_symbol for .text, + .data, and .bss. + (coff_frob_section): Likewise. Also, remove unused variable + strname. + + * config/tc-ns32k.c (convert_iif): Call frag_grow rather than + manipulating frags directly. + (md_number_to_field): Adjust mem_ptr correctly if ENDIAN is + defined. + + * app.c (do_scrub_chars): If '/' is LINE_COMMENT_START, check + whether the next character is '*' before checking whether we are + at the start of a line. Permit LINE_COMMENT_START to start a + comment in state 1 (seen some whitespace) as well, to match the + documentation. + + * gasp.c (do_align): Permit a fill value for .align. + +Wed Jun 5 17:09:26 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (next_char_of_string): Warn if a newline is seen in the + middle of a string. Call bump_line_counters when appropriate. + +Wed Jun 5 17:08:36 1996 Richard Henderson <rth@tamu.edu> + + * symbols.c (colon): Use LOCAL_LABEL. + +Tue Jun 4 10:55:16 1996 Tom Tromey <tromey@csk3.cygnus.com> + + * Makefile.in (install): Don't check to see if tooldir exists. + Make $(tooldir) and $(tooldir)/bin. + +Tue Jun 4 10:14:53 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/ppc-sol.mt (TDEFINES): Don't turn on -mregnames by + default. + +Mon Jun 3 11:34:41 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_ip): Don't call as_warn if we are setting + insn_error. Don't put the string "ERROR" in insn_error. Set + insn_error rather than calling as_warn for an unsupported opcode. + +Sat Jun 1 21:51:55 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_parse_option): Check for a 64 bit format + before permitting -64. + * output-file.c (output_file_create): Remove duplicate + bfd_perror. + +Fri May 31 01:08:06 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (md_begin): If -64, create a .MIPS.options + section rather than a .reginfo section. + (mips_elf_final_processing): If -64, write out 64 bit RegInfo + information. + + * config/tc-mips.c (load_register): If mips_isa < 3, permit a 32 + bit value with the high bit set. + +Thu May 30 19:00:19 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (s_lcomm): Set section flags for .sbss section. + + * config/tc-mips.c (mips_64): New static variable. + (mips_target_format): If mips_64, return elf64 targets rather than + elf32 ones. + (md_longopts): Add "32" and "64". + (md_parse_option): Handle -32 and -64. + (md_show_usage): Mention -32 and -64. + (cons_fix_new_mips): If mips_64, don't convert an 8 byte reloc to + a 4 byte one. + +Thu May 30 10:36:19 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (comment_chars): Make '!' a comment character + for Solaris compatibility. + + * stabs.c (s_stab_generic): Under PowerPC Solaris, convert a + .stabd with 4 arguments into a .stabn. + +Wed May 29 16:43:16 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (macro): When passing X_add_number to + macro_build, cast it to int first. + +Tue May 28 13:29:39 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-z8k.c (md_apply_fix): Handle fx_r_type of 0, as + created by emit_expr. + + * symbols.c (symbol_create): If bfd_make_empty_symbol fails, call + as_perror rather than assert. + +Fri May 24 18:24:11 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_ip): Mark sections created to hold + floating point information as read only. + +Fri May 24 12:07:54 1996 David Edelsohn <edelsohn@mhpcc.edu> + + * config/tc-ppc.c (ppc_set_cpu): Change defaults to match AIX. + +Thu May 23 17:34:24 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * read.c (potable): Add .skip as a synonym for .space. + + * stabs.c (s_stab_generic): For PowerPC ELF, allow .stabd to take + 4 arguments, providing the 4th argument is 0, to allow + compatibility with the Solaris assembler. + +Thu May 16 15:51:48 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.h (struct sh_segment_info_type): Define. + (TC_SEGMENT_INFO_TYPE): Define. + (sh_frob_label): Declare. + (tc_frob_label): Define. + (sh_flush_pending_output): Declare. + (md_flush_pending_output): Define. + * config/tc-sh.c (md_assemble): If relaxing, emit a R_SH_CODE + reloc before the instruction if necessary. + (sh_frob_label): New function. + (sh_flush_pending_output): New function. + (sh_coff_frob_file): Ignore ALIGN, CODE, DATA, and LABEL relocs + when looking for the reloc for the target of .uses. + (md_convert_frag): Fix printf format (%0xlx to 0x%lx). + (sh_force_relocation): Force CODE, DATA, and LABEL relocs to be + emitted. + (md_apply_fix): Ignore CODE, DATA, and LABEL relocs. + (sh_coff_reloc_mangle): Force CODE, DATA, and LABEL relocs to use + the absolute symbol. + + * subsegs.h (segment_info_type): Add tc_segment_info_data field if + TC_SEGMENT_INFO_TYPE is defined. + +Wed May 15 12:23:53 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i386.c (md_assemble): Make sure the opcode suffix + matches the register size. + +Wed May 15 08:33:37 1996 Jeffrey A Law (law@cygnus.com) + + * config/obj-coff.c (count_entries_in_chain): Ignore Fixups with + fx_done set. + (do_relocs_for): Likewise. + (fixup_segment): Don't just quit if linkrelax is set. Try to + apply non pc-relative sym1-sym2 fixups, even if linkrelax is + nonzero. + +Fri May 10 14:16:59 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_validate_fix): Allow GOT and section + relative relocations with -mrelocatable. Also allow unfixed + relocs in .ex_shared. + +Tue May 7 11:24:10 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (yank_symbols): Check that FNAME_OFFSET is + non-zero before assuming this is a long file name. + (w_strings): Likewise. + (c_dot_file_symbol): Set FNAME_OFFSET to 1 for a long file name. + + * config/obj-coff.c (w_strings): Move declaration of i inside + #ifdef block which uses it. + +Tue May 7 00:49:58 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (do_a_fix_imm): Rename last argument to + "relaxmode". Output relocs which identify various relaxing + possibilities for mov.[bwl] instructions. + (build_bytes): Pass in a relaxing mode to do_a_fix_imm. + +Mon May 6 15:26:28 1996 Doug Evans <dje@canuck.cygnus.com> + + * config/tc-arm.h (TC_HANDLES_FX_DONE): Define. + (MD_APPLY_FIX3): Define. + * config/tc-arm.c (my_get_expression): Only watch for bad segments + if OBJ_AOUT. + (md_apply_fix3): Renamed from md_apply_fix. + If pcrel reloc and symbol is in different section, undo effects + of md_pcrel_from. + +Sat May 4 12:49:35 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (hppa_fix_adjustable): Don't adjust + any reloc with an LR% or RR% field selector for SOM. + +Sat May 4 11:26:19 1996 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in: Add subsegs.h to appropriate TARG_CPU_DEP_* + variables. + +Fri May 3 17:58:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (coff_frob_symbol): Don't merge a symbol with + SF_GET_STATICS set. + (yank_symbols): Likewise. + +Wed May 1 13:38:17 1996 Ian Lance Taylor <ian@cygnus.com> + + * subsegs.h (segment_info_type): If MANY_SEGMENTS and not + BFD_ASSEMBLER, add name field. + * config/obj-coff.c: Include "libiberty.h". + (coff_header_append): Handle long section names. + (crawl_symbols): Just use the name field for the symbol name, + without worrying about null byte termination. + (w_strings): Handle long section names. + (write_object_file): Likewise. Also, use the name field, rather + than scnhdr.s_name. + (obj_coff_add_segment): Permit long section names. + (obj_coff_init_stab_section): Use the name field, rather than + scnhdr.s_name. + (adjust_stab_section): Likewise. + * config/te-pe.h (COFF_LONG_SECTION_NAMES): Define. + + * config/tc-i960.c (brtab_emit): Don't set fx_im_disp field. + (mem_fmt): Likewise. + (md_apply_fix): Don't check fx_im_disp field. + +Thu Apr 25 11:39:51 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Add * after sparc*-*-vxworks. + * configure: Rebuild. + + * app.c (do_scrub_begin): If tc_comment_chars is not defined, + define it to comment_chars. Use tc_comment_chars rather than + comment_chars. + (do_scrub_chars): Use tc_comment_chars rather than comment_chars. + * config/tc-m68k.h (tc_comment_chars): Define. + (m68k_comment_chars): Declare. + * config/tc-m68k.c (m68k_comment_chars): Rename from + comment_chars. Change into a pointer rather than an array. + (md_longopts): Add "bitwise-or". + (md_parse_option): Handle OPTION_BITWISE_OR. + (md_show_usage): Mention --bitwise-or. + * doc/c-m68k.texi: Document --bitwise-or. + +Wed Apr 24 11:28:38 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (m68k_ip): Prevent attempts to use long offsets + in 68000 mode. + + * config/obj-coff.c (obj_coff_section): BFD_ASSEMBLER version: + call demand_empty_rest_of_line. Non BFD_ASSEMBLER version: + correct handling of input line pointer, and call + demand_empty_rest_of_line. + +Mon Apr 22 18:02:37 1996 Doug Evans <dje@blues.cygnus.com> + + * config/tc-sparc.c (in_bitfield_range): New static function. + (sparc_ip): New cases X,Y. Use SPARC_OPCODE_ARCH_V9_P. + (md_apply_fix, cases BFD_RELOC_32_PCREL_S2, + BFD_RELOC_SPARC_{WDISP16,WDISP19}): Fix undefined code. + (md_apply_fix): New cases BFD_RELOC_SPARC_[56]. + (tc_gen_reloc): New cases BFD_RELOC_SPARC_[56]. + +Thu Apr 18 18:58:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c: BFD_ASSEMBLER: + (coff_last_bf): New static variable. + (coff_frob_symbol): Set endndx of a .bf symbol. + Non BFD_ASSEMBLER: + (obj_coff_endef): Call SF_SET_PROCESS on a .bf symbol. + (last_bfP): New static variable. + (yank_symbols): Set endndx of a .bf symbol. + +Thu Apr 18 11:53:58 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (md_parse_option): Add support for Solaris's -le + and -s options. Add -be for good measure. + +Wed Apr 17 12:31:01 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (s_space): Support non-constant fill value. Handle fill + value correctly for a size other than 1. + +Tue Apr 16 15:17:40 1996 Doug Evans <dje@canuck.cygnus.com> + + * config/tc-arm.c (my_get_float_expression): Update call to + gen_to_words, X_PRECISION changed from 6 to 5. + +Tue Apr 16 10:25:42 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (register_name,reg_name_search): Move register + name lookup from PE specific code to all targets. Add support for + -mregnames/-mno-regnames to control whether register names are + expanded or not. + (md_assemble): Call register_name for all platforms. + (md_parse_option): Add support for -mregnames/-mno-regnames. + + * configure.in (powerpcle*-*-solaris): Add support. + (powerpc*-*-linux): Ditto. + * configure: Regenerate. + + * config/ppc-sol.mt: New config file for PowerPC Solaris. + +Mon Apr 15 12:26:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_frob_file): Permit multiple %hi relocs to + be associated with a single %lo reloc. + + * config/tc-mips.c (load_address): Cast X_add_number to valueT + before comparing against MAX_GPREL_OFFSET, so that negative + numbers are handled correctly. + (macro): Likewise. + +Thu Apr 11 12:39:02 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.c (last_insn): New static variable. + (md_assemble): Warn about putting floating point branches in a + delay slot. If architecture is less than v9, insert NOP + instructions between floating point instructions and floating + point branches. (The SunOS assembler does both these operations.) + Save the last instruction opcode. + (sparc_ip): Add pinsn parameter. Change caller. + + * config/tc-m68k.c (md_estimate_size_before_relax): Correct check + for byte jump to next instruction to skip empty frags. + +Wed Apr 10 16:48:12 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-alpha.c (alpha_ip): If we are going to call emit_add64 + for addq with a 16 bit signed value, just emit a lda instruction + instead. + +Wed Apr 10 14:34:49 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (do_a_fix_imm): Don't cut off high bits + of a 32bit operand. + +Mon Apr 8 14:42:53 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Permit --enable-shared to specify a list of + directories. + * configure: Rebuild. + +Fri Apr 5 17:01:35 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (get_specific): Remove some #if 0 code. + (build_bytes): Remove all ABSMOV related code; it's unnecessary. + +Fri Apr 5 15:13:10 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/atof-ieee.c: Fix handling of denormalized extended + precision numbers and overflow/underflow detection. + (MAX_PRECISION, X_PRECISION, P_PRECISION): Changed from 6 to 5, to + not include the 16 bit gap in the m68k extended precision format. + +Fri Apr 5 14:29:23 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Add i386-*-freebsdelf* target; from John Polstra + <jdp@polstra.com>. + * configure: Rebuild. + +Fri Apr 5 18:39:28 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c: Allow non-zero offsets from .sdata symbols to + be accessed using the $gp register. + * config/tc-mips.h (MAX_GPREL_OFFSET): Added. + +Wed Apr 3 10:56:14 1996 Doug Evans <dje@canuck.cygnus.com> + + * config/tc-sparc.c (sparc_md_end): Set bfd machine number to + bfd_mach_sparc_sparclet if current_architecture is sparclet. + +Mon Apr 1 16:55:44 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (get_line_sb): Bump line counters based on + input_line_pointer[-1], not *input_line_pointer. Don't bother to + call LISTING_NEWLINE. + (s_macro): Don't call demand_empty_rest_of_line. + * app.c (do_scrub_chars): When handling C style comments, unget + ch2 rather than ch. + +Fri Mar 29 16:15:06 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.h (enum linkonce_type): Define. + (s_linkonce): Declare. + * read.c (potable): Add "linkonce". + (s_linkonce): New function. + * subsegs.h (segment_info_type): Add linkonce field to + MANY_SEGMENTS && ! BFD_ASSEMBLER section. + * config/obj-coff.h (obj_handle_link_once): Define if TE_PE. + (obj_coff_pe_handle_link_once): Declare if TE_PE. + * config/obj-coff.c: If TE_PE and not BFD_ASSEMBLER, #include + "coff/pe.h". + (obj_coff_pe_handle_link_once): New function, defined if TE_PE. + (c_section_symbol): If TE_PE, set the x_comdat field in the aux + entry based on the linkonce field in segment_info. + * doc/as.texinfo: Document .linkonce. + +Fri Mar 29 11:31:27 1996 J.T. Conklin (jtc@lisa.cygnus.com) + + * doc/as.1: Changed to be recognized by catman -w on Solaris. + +Thu Mar 28 15:27:47 1996 Ian Lance Taylor <ian@cygnus.com> + + * stabs.c (s_stab_generic): Call the listing functions before + doing the rest of the processing, which may involve freeing the + string. Pass string, not string + stroff, to OBJ_PROCESS_STAB in + SEPARATE_STAB_SECTIONS case. + + * config/tc-hppa.c: Remove nested comment. + (tc_gen_reloc): Move label done inside the ifdef in which it is + used. + (md_apply_fix): Pass pointers to correct types to libhppa.h + functions. Always return a value. + + * config/tc-mips.h (tc_frob_file): Define. + (mips_frob_file): Declare. + * config/tc-mips.c (struct mips_hi_fixup): Define. + (mips_hi_fixup_list): New static variable. + (imm_unmatched_hi): New static variable. + (md_assemble): Clear imm_reloc, imm_unmatched_hi, and + offset_reloc. Pass imm_unmatched_hi to append_insn. + (append_insn): Add unmatched_hi parameter. If it is set, add the + new fixup to mips_hi_fixup_list. Change all callers. + (mips_ip): Set imm_unmatched_hi when appropriate. + (mips_frob_file): New function. + +Thu Mar 28 11:47:59 1996 Doug Evans <dje@canuck.cygnus.com> + + * configure.in (sparc-*-solaris2*): Renamed from sparc*-*-solaris2*. + * configure: Regenerated. + +Tue Mar 26 18:19:12 1996 Ian Lance Taylor <ian@cygnus.com> + + * as.c (main): Call bfd_set_error_program_name. + +Fri Mar 22 11:13:00 1996 Ian Lance Taylor <ian@cygnus.com> + + * as.h (strdup): Don't declare. + * stabs.c: Include libiberty.h + (get_stab_string_offset): Use xstrdup rather than strdup. + (s_stab_generic): Likewise. + * as.c (parse_args): Likewise. + * read.c (s_mri_sect): Likewise. + + * gasp.c (change_base): Recognize \(...) construct documented to + pass through enclosed characters literally through to the output. + (process_assigns): Likewise. Also, be more careful to avoid + looking past the end of the buffer. + +Thu Mar 21 13:18:43 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i386.c (md_parse_option): If OBJ_ELF, ignore -k for + FreeBSD compatibility. From John Polstra <jdp@polstra.com>. + +Wed Mar 20 18:13:32 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * doc/as.texinfo, doc/c-i960.texi: Fix typos. + +Wed Mar 20 17:05:16 1996 David Mosberger-Tang <davidm@azstarnet.com> + + * config/alpha-opcode.h: Added cvtst instruction. + +Mon Mar 18 13:12:46 1996 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (ecoff_stab): Don't try to make a symbol out of the stab + string. Extract the addend from the result of expression. + +Fri Mar 15 17:10:43 1996 Ian Lance Taylor <ian@cygnus.com> + + * app.c (do_scrub_chars): If whitespace is seen in state 11, and + LABELS_WITHOUT_COLONS is not defined, and we are not in m68k MRI + mode, change the state to 3 rather than 1. + +Thu Mar 14 18:18:25 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.h (C_REGISTER_SECTION): Change from 20 to 50, to + correspond to 11 March change. + +Thu Mar 14 15:27:10 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-h8300.c (build_bytes, MEMIND case): Generate + an R_MEM_INDIRECT reloc rather than R_RELBYTE. + +Tue Mar 12 12:21:10 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure: Rebuild with autoconf 2.8. + +Mon Mar 11 18:57:12 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/atof-ieee.c (gen_to_words): Improve handling of + X_PRECISION numbers. Based on patches from Andreas Schwab + <schwab@issan.informatik.uni-dortmund.de>. + +Mon Mar 11 09:59:53 1996 Steve Chamberlain <sac@slash.cygnus.com> + + * as.h (SEG_NORMAL, SEG_LIST): Bump segment limit from 10 to 40. + (SEG_LAST): New. + * subsegs.c (MANY_SEGMENTS): Increase segment limit. + * obj-coff.c (seg_N_TYPE, seg_info_off_by_4): Likewise. + (do_relocs_for, w_symbols, obj_coff_add_segment, do_linenos_for, + crawl_symbols, coff_header_append): Loop to SEG_LAST rather than + SEG_E9. + +Thu Mar 7 15:17:39 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (sparc_ip): Handle operand char 'O' (neg reg). + +Thu Mar 7 09:19:15 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (SUBSEG_MILLI): Define. + (pa_def_subspaces): Add $MILLICODE$. + (pa_spaces_begin): Set section flags for $MILLICODE$. + +Wed Mar 6 14:11:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-elf.c (obj_elf_section): Only SEC_LOAD if the type is + not SHT_NOBITS. Don't tamper with flags based on type if a + special section was found (revert Feb 29 change). + + * config/tc-sh.c (sh_do_align): Only align using the nop pattern + if aligning to a longword boundary or greater. + +Tue Mar 5 15:10:43 1996 Jim Wilson <wilson@chestnut.cygnus.com> + + * config/tc-sh.c (sh_do_align): Pass 1 not 2 to frag_align. + +Mon Mar 4 20:50:57 1996 Steve Chamberlain <sac@slash.cygnus.com> + + * configure.in (i386-*-cygwin32): Don't use bfd_gas. + * configure: Regenerated. + +Mon Mar 4 10:13:06 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c: Add default definitions for R_N0SEL and + R_N1SEL since they're not defined for old versions of hpux. + + * config/tc-hppa.c (tc_gen_reloc): Fix typo in R_COMP2 code. + Set "sym_ptr_ptr" and "addend" fields to dummy values for + R_N0SEL and R_N1SEL. + +Fri Mar 1 10:20:52 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * flonum-konst.c: Add two more constants for 1e+-2048 and + 1e+-4096, and correct the other constants. + + * symbols.c (resolve_symbol_value): Handle O_logical_not. + +Thu Feb 29 13:58:35 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/obj-elf.c (obj_elf_section): Allow predefined section + types to set the nobits type. Avoid a shadowed declaration. + +Wed Feb 28 15:38:56 1996 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (hppa_fix_adjustable): For SOM, don't + reduce relocs using e_nlrsel field selectors. + + * write.c (fix_new_exp): Don't use #elif. Some compilers + don't handle it. + + * config/tc-hppa.c (selector_table): Add "n", "nl", and "nlr" to + the selector table. + (pa_chk_field_selector): Handle new field selectors for SOM. + +Tue Feb 27 14:42:27 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * configure.in (m68k-*-linux*aout*, m68k-*-linux*): New targets. + * configure: Rebuild. + * config/te-linux.h (LOCAL_LABELS_FB): Define. + * config/tc-m68k.h (TARGET_FORMAT) [TE_LINUX]: Define to + "a.out-m68k-linux". + * config/tc-m68k.c (comment_chars): Don't include '#' if TE_LINUX + is defined. + +Mon Feb 26 18:58:58 1996 Stan Shebs <shebs@andros.cygnus.com> + + * mpw-make.sed: Update to handle shared library support. + +Mon Feb 26 10:34:10 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (sparc_ip): Print all architectures that support + the insn on mismatch. + +Fri Feb 23 21:44:39 1996 Rob Savoye <rob@chinadoll.cygnus.com> + + * configure.in: Add support for a29-coff. + * configure: Rebuild. + +Thu Feb 22 16:39:43 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.c (sh_coff_frob_file): Don't consider the address + of the section when looking for the R_SH_USES fixup, because the + frag addresses have not yet been adjusted. + + * gdbinit.in: Set a breakpoint on as_warn_where. + + * config/tc-mips.c (macro): Add missing arguments to macro_build + omitted in last change. From Jim Wilson <wilson@cygnus.com>. + +Wed Feb 21 17:00:32 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-h8300.c (tc_reloc_mangle): Change reloc based on size + if it is TC_CONS_RELOC. Set a size of 4 to R_RELLONG. + +Wed Feb 21 09:25:39 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (sparc_ip): Recognize %asr0 for v8. + +Tue Feb 20 21:48:03 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (parse_keyword_arg): Accept leading '%'. + (sparc_ip): Accept %asr[1..31] for v8 and %asr[%16..31] for v9. + Recognize [uU] format args as sparclet cpregs. + +Tue Feb 20 22:25:55 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.c (sh_handle_align): Don't emit R_SH_ALIGN relocs + in bss_section. + +Mon Feb 19 14:16:24 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sparc.h (TC_RELOC_RTSYM_LOC_FIXUP): Check S_IS_WEAK as + well as S_IS_EXTERNAL. + (tc_fix_adjustable): Likewise. + * config/tc-sparc.c (md_apply_fix): In OBJ_ELF case, check for + S_IS_WEAK as well as S_IS_EXTERNAL when deciding whether to return + early. + (tc_gen_reloc): Check S_IS_WEAK as wel as S_IS_EXTERNAL when + deciding whether to convert BFD_RELOC_32_PCREL_S2 if PIC. + +Mon Feb 19 02:15:57 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (max_architecture): Change to sparclite for + 32 bit arch. + (default_compatible): Delete. + (sparc_ffs): New function. + (md_begin): Only call SPARC_OPCODE_CONFLICT_P once. + (sparc_ip): Rewrite architecture match and bump logic. + +Sun Feb 18 15:03:50 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Check for 'do not mix' from native linker before + trying to use -rpath. + * configure: Rebuild. + +Fri Feb 16 16:53:31 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.h (SF_ADJ_LNNOPTR): Define (non BFD_ASSEMBLER). + (SF_GET_ADJ_LNNOPTR): Define (non BFD_ASSEMBLER). + (SF_SET_ADJ_LNNOPTR): Define (non BFD_ASSEMBLER). + * config/obj-coff.c (obj_coff_endef): Set ADJ_LNNOPTR when LNNOPTR + is set. + (w_symbols): If ADJ_LNNOPTR is set, add the section lnnoptr field + to the symbol lnnoptr field, to get the correct file offset. + +Thu Feb 15 14:48:38 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/obj-elf.c (elf_frob_symbol): On the PowerPC, force all + symbols that are not function, file, or section symbols to be + object types. + +Thu Feb 15 11:20:18 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure: Set and substitute RPATH_ENVVAR. + * configure: Rebuild. + * Makefile.in (RPATH_ENVVAR): New variable. + (check): Use $(RPATH_ENVVAR) rather than LD_LIBRARY_PATH. + + * configure.in: Accept i686. From H.J. Lu <hjl@zoom.com>: i386 + doesn't need opcodes. If configuring shared, opcodes needs bfd. + * configure: Rebuild. + +Wed Feb 14 16:33:12 1996 Martin Anantharaman <martin@mail.imech.uni-duisburg.de> + + * read.c (s_mri_sect): Don't return '\0' in type. Set all + appropriate flags in BFD section. + + * configure.in (m68k-*-psos*): New target. + * configure: Rebuild. + * config/te-psos.h: New file. + * config/tc-m68k.c (comment_chars): Don't include '#' if TE_PSOS + is defined. + +Wed Feb 14 13:43:24 1996 Ian Lance Taylor <ian@cygnus.com> + + From Alan Modra <alan@spri.levels.unisa.edu.au>: + * configure.in: Remove duplicate setting of cpu_type. Check + whether opcodes library is required for on all targets, not just + primary one. + * configure: Rebuild. + + * config/tc-mips.c (mips_big_got): New static variable. + (s_extern): Don't declare. + (reg_needs_delay): New static function. + (macro_build): Permit GOT/CALL_HI/LO relocs. + (macro_build_lui): If place is not NULL, use the number in the + expression. + (load_address): Handle mips_big_got case. + (macro): Handle mips_big_got for M_LA_AB, M_JAL_A, and load and + store macros. + (OPTION_XGOT): Define. + (md_longopts): Add "xgot" if OBJ_ELF. + (md_parse_option): Handle -xgot. + (md_show_usage): Mention -xgot. + (md_apply_fix): Permit GOT/CALL_HI/LO relocs. + (tc_gen_reloc): Handle GOT/CALL_HI/LO relocs. + +Wed Feb 14 11:22:27 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * config/tc-m68k.c (m68k_ip) [operand kind '#']: When fixing + the byte relocation, point it to the low byte of the word. + +Tue Feb 13 15:31:18 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Set HDLFLAGS for *-*-hpux with --enable-shared. + * configure: Rebuild. + +Mon Feb 12 15:53:46 1996 Doug Evans <dje@charmed.cygnus.com> + + * configure.in: Recognize any sparc* cpu. + * configure: Regenerated. + +Mon Feb 12 15:41:21 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (potable): Add "mri" and ".mri". + (s_mri): New function. + * read.h (s_mri): Declare. + * app.c (scrub_m68k_mri): New static variable. + (mri_pseudo): New static variable. + (do_scrub_begin): Add m68k_mri parameter. Use it rather than + flag_m68k_mri. Initialize scrub_m68k_mri. + (mri_state, mri_last_ch): New static variables. + (struct app_save): Add scrub_m68k_mri, mri_state, and mri_last_ch + fields. + (app_push): Save new fields. + (app_pop): Restore new fields. + (do_scrub_chars): Check scrub_m68k_mri rather than flag_mri_mri. + If TC_M68K, use a trivial state machine to look for occurrences of + the .mri pseudo-op, and change the mode appropriately. + * as.h (do_scrub_begin): Update prototype. + * input-scrub.c (input_scrub_begin): Pass flag_m68k_mri to + do_scrub_begin. + * config/tc-m68k.c (reg_prefix_optional_seen): New static + variable. + (m68k_mri_mode_change): New function. + (md_parse_option): Set reg_prefix_optional_seen. + * config/tc-m68k.h (m68k_mri_mode_change): Declare. + (MRI_MODE_CHANGE): Define. + * doc/as.texinfo: Document .mri pseudo-op. + + * app.c (do_scrub_chars): In MRI mode, don't treat '#' as a + comment character. + +Mon Feb 12 15:16:29 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + Support for OBJ_ELF on m68k, mostly inside #ifdef OBJ_ELF: + * config/m68k-parse.h (enum pic_relocation): Define. + (struct m68k_exp): Add pic_reloc field. + * config/tc-m68k.h (TC_RELOC_RTSYM_LOC_FIXUP): Define. + (tc_fix_adjustable): Define to call tc_m68k_fix_adjustable. + (NO_RELOC): Define to BFD_RELOC_NONE if BFD_ASSEMBLER, to zero + otherwise. + * config/tc-m68k.c: Delete definition of NO_RELOC. + (struct m68k_it): Add pic_reloc field. + (add_fix): Copy over pic_reloc field. + (md_pseudo_table): Interpret .align parameter as byte count. + (mote_pseudo_table): Likewise. + (tc_m68k_fix_adjustable): New function. + (get_reloc_code): New function. + (md_assemble): Use it as last argument to fix_new_exp. + (md_apply_fix_2): For a relocation against a symbol don't put the + addend into the data. + (tc_gen_reloc): Different addend computation for OBJ_ELF. + (m68k_ip): Don't relax an operand that requires pic relocation. + (md_begin): Align .text, .data and .bss on 4 byte boundary by + default. + * write.c (fixup_segment): Don't add symbol value to addend if + TC_M68K and OBJ_ELF. + * config/m68k-parse.y (yylex): Handle @PLTPC, etc. + (motorola_operand): Add rule for `(zapc, EXPR)'. + +Mon Feb 12 10:07:33 1996 David Mosberger-Tang <davidm@azstarnet.com> + + * ecoff.c (ecoff_directive_weakext): Fixed so that whitespace + *really* is permissible before the comma. + +Mon Feb 12 00:12:13 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-sh.c (sh_do_align): Align to a 2 byte boundary before + inserting nop instructions. + +Fri Feb 9 10:54:19 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/te-aux.h: Change include of aux.h to aux-coff.h. + +Thu Feb 8 20:02:58 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i960.c (tc_coff_symbol_emit_hook): Correct storage + class setting for a CALLNAME symbol in COFF. + + * read.c (potable): Pass negative numbers for new .balign[wl] and + .p2align[wl] pseudo-ops. + (s_align_bytes): Treat a negative argument as specifying the fill + length. + (s_align_ptwo): Likewise. + +Wed Feb 7 14:12:03 1996 Ian Lance Taylor <ian@cygnus.com> + + * read.c (potable): Add balignw, balignl, p2alignw, and p2alignl. + (do_align): Take new len parameter. Change all callers. Pass it + to md_do_align. + (s_align_bytes): Arg now indicates the length of the fill pattern. + (s_align_ptwo): Likewise. + * config/obj-coff.c (write_object_file): Pass length to + md_do_align. + * config/tc-i386.h (md_do_align): Take new len parameter. + * config/tc-m88k.h (md_do_align): Likewise. + * config/tc-m88k.c (m88k_do_align): Likewise. + * config/tc-sh.h (md_do_align): Likewise. + * config/tc-sh.c (sh_do_align): Likewise. + * doc/as.texinfo: Document new pseudo-ops. + + * config/obj-coff.c (fixup_mdeps): Divide offset by fr_var, as is + done in cvt_frag_to_fill. + + * config/tc-sh.h (sh_do_align): Declare. + (md_do_align): Define. + * config/tc-sh.c (sh_do_align): New function. + + * ecoff.c (ecoff_build_lineno): Don't try to store the address + difference if the next address is before the current one. + + * config/tc-m68k.c (struct m68k_cpu): Add alias field. + (archs): Initialize new field. + (m68k_ip): Don't list alias names when listing CPUs which support + an instruction. + + * as.c (main): Call parse_args before read_begin. + * app.c (do_scrub_chars): If flag_m68k_mri, don't put a dot in + front of generated pseudo-ops. + * read.c (potable): Ignore "name". + (s_app_file): Permit a single quote after the string, since one + may appear in m68k MRI mode. + + * configure.in: Check for --enable-shared. If linking against + shared BFD and opcodes, fix library name on SunOS, and try to set + -rpath reasonably. + * configure: Rebuild. + +Tue Feb 6 15:16:17 1996 Ian Lance Taylor <ian@cygnus.com> + + * as.h (flag_m68k_mri): Declare. + * as.c (parse_args): If TC_M68K, set flag_m68k_mri for -M. + * Many files: For MRI syntax that is specific to the m68k MRI + assembler, check flag_m68k_mri rather than flag_mri or + MRI_MODE_NEEDS_PSEUDO_DOT. + +Mon Feb 5 16:29:11 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-i960.c (ARCH_HX): Define. + (arch_tab): Add HX. + (targ_has_sfr): Handle ARCH_HX. + (targ_has_iclass): Handle ARCH_HX. + (tc_coff_fix2rtype): Add return 0 to avoid warning. + (tc_headers_hook): If the architecture was specified explicitly, + use it when setting the flags. Set the extern variable coff_flags + rather than headers->filehdr.f_flags, since the latter is set + unconditionally in obj-coff.c. + (i960_handle_align): Remove unused variable fixp. + + Support for building bfd and opcodes as shared libraries, based on + patches from Alan Modra <alan@spri.levels.unisa.edu.au>: + * configure.in: Set OPCODES and BFD to search directories. + Substitute OPCODES_DEP and BFDDEP. On SunOS, set HLDFLAGS. + * configure: Rebuild. + * Makefile.in (LDFLAGS, HLDFLAGS): New variables. + (LIBDEPS): New variable. + (as.new0: Depend upon $(LIBDEPS) rather than $(LIBS). Use + $(HLDFLAGS) in link. + (check): Set LD_LIBRARY_PATH in the environment. + +Fri Feb 2 17:41:53 1996 Michael Meissner <meissner@wogglebug.tiac.net> + + * config/tc-ppc.h (ELF_TC_SPECIAL_SECTIONS): Make .sdata2, .sbss2, + .PPC.EMB.sdata0, and .PPC.EMB.sbss0 sections all default to + read-only, not read/write. + +Fri Feb 2 14:09:25 1996 Alan Modra <alan@spri.levels.unisa.edu.au> + + * Makefile.in (INSTALL_XFORM): Remove -e. + +Fri Feb 2 12:32:15 1996 Ian Lance Taylor <ian@cygnus.com> + + * write.c (write_relocs): Use S_IS_DEFINED and S_IS_COMMON rather + than comparing S_GET_SEGMENT to undefined_section. + (write_object_file): Skip symbols which were equated to an + undefined or common symbol. + * symbols.c (resolve_symbol_value): Use S_IS_DEFINED and + S_IS_COMMON rather than comparing S_GET_SEGMENT to + undefined_section. + (S_GET_VALUE): Likewise. Avoid recursion problems if S_IS_DEFINED + or S_IS_COMMON call S_GET_VALUE. + * config/obj-aout.h (S_IS_COMMON): Define if not BFD_ASSEMBLER. + * config/obj-aout.c (obj_emit_relocations): If a reloc is equated + to an undefined or common symbol, convert the reloc to be against + the target symbol. + (obj_crawl_symbol_chain): Skip symbols which were equated to an + undefined or common symbol. + * config/obj-bout.h (S_IS_COMMON): Define if not BFD_ASSEMBLER. + * config/obj-bout.c (obj_emit_relocations): If a reloc is equated + to an undefined or common symbol, convert the reloc to be against + the target symbol. + (obj_crawl_symbol_chain): Skip symbols which were equated to an + undefined or common symbol. + * config/obj-coff.c (do_relocs_for): Use S_IS_DEFINED and + S_IS_COMMON rather than comparing S_GET_SEGMENT to + undefined_section. + (yank_symbols): Skip symbols which were equated to an undefined or + common symbol. + +Thu Feb 1 15:34:32 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-aout.h (S_IS_LOCAL): Check for \002 as well as \001. + * config/obj-bout.h (S_IS_LOCAL): Likewise. + + * configure.in: Make sure we only add m68k-parse.o to + ${extra_objects} once, no matter how many m68k targets have been + enabled. + * configure: Rebuild. + +Wed Jan 31 18:31:46 1996 Steve Chamberlain <sac@slash.cygnus.com> + + * configure.in (i386-*-cygwin32, ppc-*-cygwin32): New. + * configure: Rebuild. + +Wed Jan 31 14:03:17 1996 Richard Henderson <rth@tamu.edu> + + * config/tc-m68k.c (md_pseudo_table): Add "extend" and "ldouble". + * doc/c-m68k.texi: Document .extend and .ldouble. + + * configure.in (m68*-apple-aux*): New target. + * config/te-aux.h: New file. + * config/obj-coff.c (compare_external_relocs): New static function + if TE_AUX. + (do_relocs_for): Sort relocs if TE_AUX. + (fixup_segment): If TE_AUX, store common symbol value in segment. + * config/tc-m68k.h (TARGET_FORMAT): Define if TE_AUX. + +Wed Jan 31 12:24:58 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.h (S_IS_LOCAL): Check for \002 as well as \001. + + * config/tc-mips.c (s_mips_globl): Set BSF_OBJECT if it is not + BSF_FUNCTION. + (s_cpload): Set BSF_OBJECT for _gp_disp symbol. + * read.c (s_lcomm): If S_SET_SIZE is defined, set the size of the + symbol. + * ecoff.c (add_procedure): Set the BSF_FUNCTION flag. + (ecoff_build_symbols): If S_SET_SIZE is defined, set the size of + an undefined symbol and the size of a function symbol. + * config/obj-elf.c (elf_frob_symbol): If TC_MIPS, set BSF_OBJECT + for all common symbols. + +Tue Jan 30 12:35:24 1996 Ken Raeburn <raeburn@cygnus.com> + + * config/tc-i960.c (parse_memop): In MRI mode, don't use implicit + scaling of index. + + * expr.c (operand): Accept 0x hex constants in MRI mode if not on + m68k. + +Mon Jan 29 12:21:30 1996 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-elf.c (obj_elf_type): Set BSF_OBJECT flag for a type + of object. From Ronald F. Guilmette <rfg@monkeys.com>. + + * ecoff.c (localsym_t): Add addend field. + (add_ecoff_symbol): Add addend argument. Change all callers. + (coff_sym_value): Make static. + (coff_sym_addend): New static variable. + (ecoff_directive_def): Initialize coff_sym_addend. + (ecoff_directive_val): Accept symbol + constant. + (ecoff_directive_endef): Pass coff_sym_addend to add_ecoff_symbol. + (ecoff_build_symbols): Include the addend in the symbol value. + +Fri Jan 26 19:28:52 1996 Kim Knuttila <krk@cygnus.com> + + * config/tc-ppc.c (md_assemble): Ignore overflow on + BFD_RELOC_16_GOTOFF and BFD_RELOC_PPC_TOC16. + +Fri Jan 26 16:14:17 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (md_apply_fix3): SDA21 relocations are now 4 + bytes in size, so offset appropriately in big endian mode when + writing the bottom 2 bytes. + +Thu Jan 25 20:26:23 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (default_compatible): New static local. + (md_begin): Initialize it. Rewrite warn_on_bump handling. + (sparc_ip): If no architecture or -bump specified, don't mark as + mismatched those in default_compatible. + +Thu Jan 25 12:21:53 1996 Ian Lance Taylor <ian@cygnus.com> + + SCO ELF support from Robert Lipe <robertl@arnet.com>: + * configure.in (i386-*-sco*elf*): Use fmt elf, targ sco5. + * configure: Rebuild. + * config/sco5.mt: New file; set TDEFINES to -DSCO_ELF. + * config/tc-i386.c (sco_id): New function, if SCO_ELF. + * config/tc-i386.h (tc_init_after_args): Define if SCO_ELF. + (sco_id): Declare if SCO_ELF. + +Thu Jan 25 03:10:53 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.c (initial_architecture,can_bump_v9_p): Deleted. + ({max,warn_after}_architecture): New static locals. + (md_begin): Replace NUMOPCODES with sparc_num_opcodes. + If both architecture and -bump requested, set max_architecture to max. + (sparc_md_end): Simplify. + (sparc_ip): Replace references to can_bump_v9_p with max_architecture. + Rewrite code to bump architecture and check for conflicts. + (md_longopts): Recognize -xarch={v8plus,v8plusa} for compatibility + with Solaris assembler. + (md_parse_option): Likewise. Call sparc_opcode_lookup_arch. + (md_show_usage): Update. + +Wed Jan 24 22:11:03 1996 Doug Evans <dje@charmed.cygnus.com> + + * Makefile.in (RUNTEST): Fix reference to $${srcdir}. + +Mon Jan 22 09:21:36 1996 Doug Evans <dje@charmed.cygnus.com> + + * config/tc-sparc.h (TARGET_FORMAT): Use #ifdef SPARC_ARCH64 instead of + #ifdef sparcv9 when choosing value. + (ENV64): Delete. + (md_end): Define. + (sparc_md_end): Declare. + * config/tc-sparc.c (SPARC_V9): Renamed from sparcv9. + (initial_architecture): New static local. + (can_bump_v9_p): Likewise. + (NO_V9): Delete all occurrences. + (sparc_md_end): New function. + (sparc_ip): New local v9_arg_p. Rework fp reg number test. + Don't bump architecture to v9 unless can_bump_v9_p set. + (md_parse_option): -A<arch> passed, set can_bump_v9_p accordingly. + * configure.in (sparc64 target cpu): Don't set obj_format here. + (SPARC_V9): Renamed from sparcv9. + (sparc64-*-elf*): Define SPARC_ARCH64. + * configure: Regenerated. + * acconfig.h (SPARC_V9): Renamed from sparcv9. + (SPARC_ARCH64): Add. + * conf.in: Regenerated. + * config/vmsconf.h: Update. + +Mon Jan 22 17:24:47 1996 James G. Smith <jsmith@cygnus.co.uk> + + * config/tc-mips.c (load_register): Optimise "dli" loads. + (md_show_usage): add "-mcpu=vr4100" to help text. + +Mon Jan 22 11:53:00 1996 Ian Lance Taylor <ian@cygnus.com> + + * symbols.c (resolve_symbol_value): If a symbol is equated to an + undefined symbol, preserve the X_op of O_symbol. + (S_GET_VALUE): Fix check to permit this case. + * write.c (write_relocs): If a reloc is against an undefined + symbol equated to another symbol, change the reloc to be against + the latter symbol. + * config/obj-coff.c (do_relocs_for): Likewise. + + * config/tc-ppc.c (ppc_csect): An unnamed csect is storage class + XMC_PR. + +Mon Jan 22 10:59:48 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/obj-elf.c (elf/ppc.h): Include elf/ppc.h if target + computer is PowerPC. + + * config/tc-ppc.c (md_apply_fix3): Add more embedded relocations. + + * config/tc-ppc.h (ELF_TC_SPECIAL_SECTIONS): Add sections + mentioned in the eabi. + +Thu Jan 18 17:58:19 1996 Kim Knuttila <krk@cygnus.com> + + * config/tc-ppc.c (ppc_reldata): Changed alignement on reldata_section + * config/tc-ppc.c (ppc_pdata): Changed the alignment on pdata_section + +Mon Jan 15 17:43:42 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (mapping): Add more relocation suffixes. + +Sun Jan 14 21:29:36 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_validate_fix): Allow .gcc_except_table + as a section it is ok to have unadorned -mrelocatable pointers in. + +Sat Jan 13 11:09:08 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_section*): Wrap these functions inside + #ifdef OBJ_ELF. + +Fri Jan 12 15:32:07 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/obj-elf.c (obj_elf_section): Add hooks so machine + dependent section attributes can be handled. + + * config/tc-ppc.h: (md_elf_section_{letter,type,word,flags}): New + macros to add support for exclude section flag and ordered section + type. + + * config/tc-ppc.c (ppc_elf_section_{letter,type,word,flags}): New + functions to add support for exclude section flag and ordered + section type. + +Fri Jan 12 12:04:00 1996 Ian Lance Taylor <ian@cygnus.com> + + * subsegs.c (section_symbol): Don't try to look up the section + symbol in the hash table. It should be possible to have a symbol + with the same name as a section, but no connection to it. + + * read.c (cons_worker): Only call mri_comment_end from flag_mri. + From James Carlson <carlson@xylogics.com>. + + * expr.c (operand): Skip whitespace after a close parenthesis. + From James Carlson <carlson@xylogics.com>. + +Tue Jan 2 12:43:23 1996 Jim Wilson <wilson@chestnut.cygnus.com> + + * config/tc-sh.c (md_apply_fix): Call as_bad_where instead of + as_warn_where for relocation overflow. + (parse_reg): Accept register name only if next character is + not alphanumeric. + +Sat Dec 30 23:42:51 1995 Jeffrey A Law (law@cygnus.com) + + * ecoff.c (ecoff_stab): Simplify. Correctly handle sym + offset + addresses for static variables. + +Thu Dec 21 12:54:32 1995 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (mapping): Make @got give a real GOT relocation, + and xgot give the old toc16 relocation. + (md_apply_fix3): Support all GOT relocations. + +Wed Dec 20 14:57:17 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (load_address): Correctly handle a constant in + SVR4_PIC case. From Richard Kenner <kenner@vlsi1.ultra.nyu.edu>. + +Fri Dec 15 14:25:07 1995 J.T. Conklin <jtc@rtl.cygnus.com> + + * config/tc-sh.c (parse_reg): Recognize SH3 registers. + (get_specific): Handle A_SSR, A_SPC and A_REG_B. + (build_Mbytes): Handle REG_B. + +Fri Dec 15 16:07:25 1995 Ian Lance Taylor <ian@cygnus.com> + + * ecoff.c (ecoff_build_aux): Use new bfd_big_endian macro. + +Fri Dec 15 12:11:48 1995 Raymond Jou <rjou@mexican.cygnus.com> + + * mpw-make.sed: If linking, edit ALL_CFLAGS to CFLAGS. + +Thu Dec 14 15:09:52 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (write_object_file): Set the s_align field to + the number of bytes, rather than to the power of 2. + +Tue Dec 12 12:19:37 1995 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (DISTCLEAN_HERE): New variable. + (distclean): Use it. + (maintainer-clean): Depend upon clean-here rather than clean, + distclean, and clean-info. Run make maintainer-clean in doc. + Remove files listed in DISTCLEAN_HERE. + * doc/Makefile.in (maintainer-clean realclean): Split out from + distclean. Depend upon clean-info and distclean. + +Mon Dec 11 16:23:51 1995 Stan Shebs <shebs@andros.cygnus.com> + + * mac-as.r: Fix copyright and version strings. + (cfrg): Use PROG_NAME instead of literal name. + +Mon Dec 11 14:14:08 1995 Ian Lance Taylor <ian@cygnus.com> + + * read.c (read_a_source_file): If tc_unrecognized_line is defined, + call it. + * config/tc-a29k.h (tc_unrecognized_line): Define. + * config/tc-a29k.c (a29k_unrecognized_line): New function. + (md_operand): Handle a29k style local dollar labels. + +Wed Dec 6 17:52:52 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-multi.h: If OBJ_MAYBE_ELF, define OBJ_SYMFIELD_TYPE. + +Tue Dec 5 13:26:34 1995 Ken Raeburn <raeburn@cygnus.com> + + * read.c (s_fill): If md_flush_pending_output is defined, call + it. + +Mon Dec 4 15:10:53 1995 Ken Raeburn <raeburn@cygnus.com> + + * config/obj-coff.c (size_section, fill_section, fixup_mdeps): + Treat rs_align_code like rs_align. + +Sun Dec 3 16:46:54 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * config/tc-arm.c (cp_address_required_here): Set pre_inc when + converting an absolute address into a PC-relative one. + +Fri Dec 1 11:57:56 1995 Stan Shebs <shebs@andros.cygnus.com> + + * mpw-config.in: Don't always use te-generic.h for emulation. + (powerpc-apple-macos): Use emulation te-macos.h. + * mpw-make.sed (install, install-only): Edit in Mac-specific + install procedure. + +Fri Dec 1 10:59:25 1995 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Improve message about unsupported ELF targets. + * configure: Rebuild. + + * config/tc-m88k.c (m88k_do_align): Correct check for whether fill + pattern is zero. From Manfred Hollstein. + +Thu Nov 30 13:25:49 1995 Kim Knuttila <krk@cygnus.com> + + * config/tc-ppc.c (ppc_pe_section): To get the alignment right for + the various idata sections, we check the name on the .section pseudo. + +Thu Nov 30 11:23:42 1995 Manfred Hollstein KS/EF4A 60/1F/110 #40283 <manfred@lts.sel.alcatel.de> + + * config/obj-coff.c (fixup_segment): If TC_M88K is defined, do not + add section's paddr to add_number; compatibility to native as and + ld forbids. + +Wed Nov 29 23:14:27 1995 Ken Raeburn <raeburn@cygnus.com> + + * configure.in: Treat m68k-sysv4 like m68k-elf, not m68k-sysv3. + + * hash.c (struct hash_entry): Moved here... + * hash.h (struct hash_entry): ...from here. + + * config/obj-elf.c (elf_frob_symbol): Don't free and clear sy_obj + if it's already known to be null. + +Wed Nov 29 13:00:20 1995 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (md_apply_fix3): Don't adjust the value for 32 + bit relocs converted to PC relative relocs. This turned out to + add the offset from the beginning of .text twice. + +Tue Nov 28 10:42:36 1995 Ken Raeburn <raeburn@cygnus.com> + + * stabs.c (s_stab_generic): In 's' case, free string from + obstack. + + * config/obj-elf.h (ELF_TARGET_SYMBOL_FIELDS): Remove unused field + sy_name_offset. + * config/obj-multi.h (ELF_TARGET_SYMBOL_FIELDS) [OBJ_MAYBE_ELF]: + Ditto. + + * subsegs.h (segment_info_type): Make bitfields unsigned. + + * expr.h (struct expressionS): Make X_op and X_unsigned bitfields, + and move them together. On most systems this will reduce the + structure size by one word. + (operatorT): Define O_max. + * expr.c (expr_begin): Verify that X_op is wide enough to hold + O_max. + + * read.c (pop_insert): Print error returned by hash table + insertion code. + + * as.c (dump_statistics): Split out from main; dump some hash + table stats and target-specific stats. + (start_time): No longer automatic to main. + (main): Set file-level start_time and call dump_statistics at + exit. Exit by calling xexit. + (show_usage): Make --statistics description less specific. + * subsegs.c (subsegs_print_statistics): New function. + * write.c (write_print_statistics): New function. + (n_fixups): New static variable. + (fix_new_internal): Increment it. + * read.c (read_print_statistics): New function. + * read.h (read_print_statistics): Declare. + * symbol.c (symbol_print_statistics): New function. + * symbol.h (symbol_print_statistics): Declare. + * hash.c (hash_print_statistics): New function. + * hash.h (hash_print_statistics): Declare. + * config/tc-i386.c (i386_print_statistics): New function. + * config/tc-i386.h (i386_print_statistics): Declare. + (tc_print_statistics): New macro. + * messages.c (as_fatal, as_assert, as_abort): Use xexit, not + exit. + + * hash.c (DELETED): Rewrite to use a valid but unique address. + (START_POWER): Reduce to 10. + (enum stat_enum): New enumerator, replacing STAT_* index macros. + Add new values for counting strcmp calls. + (GROW_FACTOR): New macro. + (hash_grow): Use GROW_FACTOR. Rewrite for quick returns instead + of nesting blocks. + (FULL_VALUE): New macro. Use 1/4 of table size instead of 1/2. + (hash_new): Use FULL_VALUE. + (struct hash_control): Definition moved here. + (hash_code): Don't mask to low bits. + (hash_ask): Mask returned hash code here. Check hash value before + calling strcmp; count strcmp calls. + * hash.h (struct hash_control): Declare, don't define, here. + (HASH_STATLENGTH): Deleted. + (struct hash_entry): Add field for hash code. + (hash_say, hash_apply): Don't declare. + + * hash.c (destroy): Return void. + (applicatee): Ditto. + (main): Fix declarations. + (hash_apply): Return void. Argument `function' returns void. Put + inside "#ifdef TEST". + (hash_say): Define only if TEST is defined. + * hash.h (hash_apply, hash_say): Declarations deleted. + +Mon Nov 27 13:18:25 1995 Ian Lance Taylor <ian@cygnus.com> + + * configure: Rebuild with autoconf 2.7. + +Tue Nov 21 18:39:01 1995 Ian Lance Taylor <ian@cygnus.com> + + * aclocal.m4 (AC_PROG_CC): Remove local definition. + * configure: Rebuild with autoconf 2.6. + +Mon Nov 20 17:26:00 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_debug_name_section_size): Remove. + (ppc_stabx): Don't increment ppc_debug_name_section_size. + (ppc_bc): Likewise. + (ppc_frob_file): Remove. + * config/tc-ppc.h (tc_frob_file): Don't define. + (ppc_frob_file): Don't declare. + +Mon Nov 20 13:37:05 1995 Ken Raeburn <raeburn@cygnus.com> + + * Makefile.in (TARG_CPU_DEP_alpha): Mention alpha-opcode.h. + * config/alpha-opcode.h: Include one-operand variants of jmp and + jsr. + + * config/te-delt88.h: Renamed from te-delta88.h, to avoid conflict + with te-delta.h in 8.3 file systems. + * configure.in: Adjusted. + +Thu Nov 16 12:49:38 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (s_err): Remove; just use the one in read.c. + + * config/m68k-parse.y (yylex): In MRI mode, '@' can start an octal + number. + * expr.c (operand): Handle MRI suffixes after unadorned 0. + +Thu Nov 16 00:21:44 1995 Ken Raeburn <raeburn@cygnus.com> + + Version 2.6 released. + * Makefile.in (VERSION): Updated to 2.6. + + * config/obj-coff.c (write_object_file): Change use of md_do_align + to pass a pointer rather than a fill value, to match other uses. + +Wed Nov 15 03:52:00 1995 Ken Raeburn <raeburn@cygnus.com> + + * config/tc-ns32k.h (TC_FIX_TYPE): Add missing semicolon. + + * as.c (main): Move md_end call to just after call to + perform_an_assembly_pass. Delete cpu-specific code here. + * config/tc-i960.h (md_end): New macro, calls brtab_emit. + * config/tc-arm.c (md_end): Unused function deleted. + * config/tc-ns32k.c (md_end): Ditto. + + * config/tc-i386.c (i386_align_code): New function, moved here + from HANDLE_ALIGN macro. + * config/tc-i386.h (HANDLE_ALIGN): Call it. + + Mon Jul 31 14:53:19 1995 Alan Modra <alan@spri.levels.unisa.edu.au> + + * config/tc-i386.h (md_do_align): cast fill and 0x90 to char + before comparing + + Mon May 1 10:91:49 1995 Alan Modra <alan@spri.levels.unisa.edu.au> + + * config/tc-i386.h (md_do_align): Make ".align n,0x90" generate + multi-byte nops to avoid changing gcc. The necessary gcc change + might break old assemblers. + + Sat Apr 22 20:53:05 1995 Alan Modra <alan@spri.levels.unisa.edu.au> + + * config/tc-i386.h (md_do_align, HANDLE_ALIGN): Add macros to + generate optimal multi-byte nop instructions for ".align n" + ".align n,0x90", and aligns requiring more than 15 bytes of + padding still generate multiple 0x90's as before. + +Mon Nov 13 17:40:21 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (s_mri_until): Call pop_mri_control. + +Mon Nov 13 20:39:06 1995 Stan Shebs <shebs@andros.cygnus.com> + + * configure.in (ppc-*-macos*, ppc-*-mpw*): New configurations. + * configure: Update. + * mpw-make.sed: Reorder commands to make sed happier. + * config/te-macos.h: New file. + * config/tc-ppc.h (TARGET_FORMAT): Set correctly for PowerMac. + +Sun Nov 12 21:14:56 1995 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (pa_ip): Fix off-by-2 bug in length check for + conditional branches. + (md_apply_fix): Likewise. + +Thu Nov 9 16:14:01 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-a29k.c (md_apply_fix): Warn if an attempt is made to + generate a reloc which the linker will not handle correctly. Fix + overflow checking--R_IREL is 18 bits, not 17. + +Wed Nov 8 19:59:36 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (fixup_segment): Don't subtract md_pcrel_from + from a PC relative reloc if TC_A29K. + + * config/tc-a29k.c (line_separator_chars): Restore '@'. Existing + code depends upon it. + + * config/tc-a29k.c (md_operand): Handle $float, $double, and + $extend. Based on code from Eric Freudenthal + <freudenthal@nyu.edu>. + * config/tc-a29k.h (LEX_DOLLAR): Define. + * read.c (LEX_DOLLAR): Define if not defined. + (lex_type): Use LEX_DOLLAR. + +Wed Nov 8 16:38:14 1995 Eric Freudenthal <freudenthal@nyu.edu> + + * configure.in (a29k-nyu-sym1): New target, just like other a29k + targets. + +Wed Nov 8 11:38:48 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/obj-coff.c (c_dot_file_symbol): Cast xmalloc return. + +Tue Nov 7 09:14:35 1995 Kim Knuttila <krk@cygnus.com> + + * config/tc-ppc.c (md_apply_fix3): Added BFD_RELOC_RVA. Currently + used only by "dlltool.c". + +Mon Nov 6 18:51:26 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-alpha.c: Undefine inline if not __GNUC__. + (md_pseudo_table): Don't define "extern". + +Sat Nov 4 00:51:21 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_biei): Force symbol into text_section. + + * config/tc-ppc.c (md_show_usage): Put backslash at end of line. + +Fri Nov 3 13:02:59 1995 Ian Lance Taylor <ian@cygnus.com> + + * macro.c (macro_expand_body): Don't warn about == with a + nonexistent parameter, in case it is in a comment field. + + * as.c (main): On TC_A29K, call macro_init with macro_alternate + set to 1. + * macro.c (get_any_string): Don't keep quotes if macro_strip_at is + set, even if macro_alternate is set. + (get_apost_token): If macro_strip_at, only skip kind if it is '@'. + (sub_actual): If macro_strip_at, and kind is '@', don't look up + the token unless it ended in '@'. + * config/tc-a29k.c (line_separator_chars): Remove '@'. + * doc/c-a29k.texi: Document macro usage on A29K. + +Thu Nov 2 23:07:57 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (m68k_ip): Handle new 'W' place, meaning a + signed word. + (install_operand): Likewise. + + * config/obj-elf.c (ecoff_debug_pseudo_table): Add "extern". + +Wed Nov 1 15:17:02 1995 Manfred Hollstein KS/EF4A 60/1F/110 #40283 <manfred@lts.sel.alcatel.de> + + * configure.in (m88k-motorola-sysv*): New target. + * configure: Rebuild. + * config/te-delta88.h: New file. + * config/obj-coff.c (write_object_file): Use md_do_align if it is + defined. + * config/tc-m88k.h (SUB_SEGMENT_ALIGN): Define. + (md_do_align): Define. + * config/tc-m88k.c: Include "subsegs.h". + (m88k_do_align): New function. + + * config/te-delta.h (STRIP_UNDERSCORE): Don't define. + (COFF_NOLOAD_PROBLEM): Define. + (LOCAL_LABELS_DOLLAR, LOCAL_LABELS_FB): Define. + +Wed Nov 1 16:07:43 1995 Ken Raeburn <raeburn@cygnus.com> + + * config/tc-i386.c (md_assemble): For a jump instruction with + non-constant target, require 7 available bytes in the current + frag, not 6. + +Tue Oct 31 15:37:16 1995 Fred Fish <fnf@rtl.cygnus.com> + + * config/obj-elf.h: Include bfd/elf-bfd.h rather than + bfd/libelf.h. + +Tue Oct 31 16:34:28 1995 David Mosberger-Tang <davidm@azstarnet.com> + + * configure.in (alpha-*-linux*): Use ecoff. + * configure: Rebuild. + * ecoff.c (ecoff_directive_extern): New function. + (ecoff_directive_weakext): New function. + (ecoff_build_symbols): Handle weak symbols. + (ecoff_setup_ext): Likewise. + (ecoff_frob_symbol): Warn about weak common symbols. + * ecoff.h (ecoff_directive_extern): Declare. + (ecoff_directive_weakext): Declare. + * symbols.c (S_IS_WEAK): New function. + * symbols.h (S_IS_WEAK): Declare. + * config/obj-ecoff.c (obj_pseudo_table): Add "extern" and + "weakext". + * config/tc-mips.c (mips_pseudo_table): Remove "extern". + (s_extern): Remove. + +Tue Oct 31 13:29:08 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_lglobl): Do the right thing. + + * config/tc-ppc.c (ppc_bb): Call SF_SET_PROCESS. + (ppc_eb): Likewise. Set the storage class to C_BLOCK, not C_FCN. + (ppc_frob_symbol): Don't change C_BLOCK symbols to C_HIDEXT. + * config/obj-coff.c (coff_frob_symbol): Don't call + SA_SET_SYM_ENDNDX with the current symbol; call it with the next + one. If OBJ_XCOFF, try to figure out whether the symbol is going + to be dropped. + + * config/tc-ppc.c (md_pseudo_table): Add "bc" and "ec". + (ppc_stab_symbol): New static variable. + (ppc_change_csect): Check that ppc_toc_csect is not NULL. + (ppc_stabx): Set ppc_stab_symbol around call to symbol_make. Set + sy_tc.real_name to the stab string. + (ppc_bc, ppc_ec): New static functions. + (ppc_canonicalize_symbol_name): If ppc_stab_symbol is set, don't + do anything. + (ppc_symbol_new_hook): If ppc_stab_symbol is set, don't look for a + suffix. + (ppc_frob_symbol): Set BSF_NOT_AT_END for symbols with csect aux + entries. + + * input-scrub.c (input_scrub_push): Reset sb_index. + +Mon Oct 30 17:52:46 1995 Ian Lance Taylor <ian@cygnus.com> + + * listing.c (listing_newline): Don't create a frag in the absolute + section. + +Sat Oct 28 01:02:05 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (md_pseudo_table): Add "data" and "text". + (ppc_csect): Move most of the code to ppc_change_csect, and call + it. + (ppc_change_csect): New static function, taken from ppc_csect. + (ppc_section): New static function. + (ppc_saw_abs): New static varable. + (ppc_frob_symbol): Create aux entry for absolute symbols. Warn if + a symbol has no csect. + (ppc_adjust_symtab): New function. + * config/tc-ppc.h (tc_adjust_symtab): Define if OBJ_XCOFF. + (ppc_adjust_symtab): Declare if OBJ_XCOFF. + + * write.c (write_object_file): If tc_adjust_symtab is defined, + call it just before the call to obj_adjust_symtab. + + * symbols.c (symbol_find_or_make): Change name to be const. + * symbols.h (symbol_find_or_make): Update declaration. + +Thu Oct 26 19:18:27 1995 Ken Raeburn <raeburn@cygnus.com> + + * doc/as.texinfo (Align): Mention SH. + * doc/c-m68k.texi (M68K-Directives, .even): Describe behavior, not + .align value. + * doc/c-z8k.texi (Z8000 Directives, global): Fix minor typo. + (Z8000 Directives, even): Don't give numeric align value, instead + explain behavior. + +Thu Oct 26 11:45:03 1995 Richard Earnshaw (rearnsha@armltd.co.uk) + + * tc-arm.c (do_ldst): Assemble ldr/str r0, [r1] as a pre-increment + instruction. + +Wed Oct 25 11:59:24 1995 Per Bothner <bothner@kalessin.cygnus.com> + + * Makefile.in (diststuff): Also make info. + (maintainer-clean realclean): Also make clean-info. + +Tue Oct 24 15:21:33 1995 Jeffrey A Law (law@cygnus.com) + + * config/tc-hppa.c (md_pseudo_table): Add new ".nsubspa" opcode. + (pa_subspace): For ".nsubspa", always create a new subspace + with the given attributes, even if one already exists with the + same name. + +Tue Oct 24 14:50:38 1995 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.h (TC_FORCE_RELOCATION_SECTION): Rename from + TC_FORCE_RELOCATION, taking an additional section argument. If + the section of the target symbol is not the same as the current + section, always force the relocation to be used. + (MD_PCREL_FROM_SECTION): New macro to call md_pcrel_from_section. + + * config/tc-ppc.c (md_pcrel_from_section): Rename from the + md_pcrel_from function, taking an additional section argument. + Invoke TC_FORCE_RELOCATION_SECTION instead of TC_FORCE_RELOCATION. + + * write.c (TC_FORCE_RELOCATION_SECTION): Define in terms of the + older TC_FORCE_RELOCATION if not defined. + (MD_PCREL_FROM_SECTION): If not defined, invoke md_pcrel_from. + (fixup_segment): Use MD_PCREL_FROM_SECTION instead of + md_pcrel_from, and TC_FORCE_RELOCATION_SECTION instead of + TC_FORCE_RELOCATION. + +Mon Oct 23 16:20:04 1995 Ken Raeburn <raeburn@cygnus.com> + + * input-scrub.c (as_where): Set name to null pointer if we don't + have a file name. + * messages.c (identify): Only print filename if non-null. + (as_show_where): Ditto, for line number too. + (as_warn_internal, as_bad_internal): Ditto. + + * input-file.c (input_file_open): If the input file can't be + opened, consider it an error. + +Mon Oct 23 11:15:44 1995 James G. Smith <jsmith@pasanda.cygnus.co.uk> + + * config/tc-mips.c: Added mips_4100 control, and support for + accepting the 4100 as a MIPS architecture variant (md_begin, + macro_build, mips_ip, md_parse_option). Adding suitable + command-line OPTIONs, and updating the help text (md_show_usage). + +Wed Oct 18 13:20:32 1995 Ken Raeburn <raeburn@cygnus.com> + + * subsegs.c (subseg_begin): Only set absolute_frchain.fix_* when + BFD_ASSEMBLER is defined. + + * Use one active frag and one obstack per frag chain: + * frags.c (frags): Variable deleted. + (frag_alloc): New function. + (frag_grow, frag_more, frag_variant, frag_now_fix, + frag_append_1_char): Refer to frchain_now->frch_obstack instead of + frags variable. + (frag_new): Ditto. Verify that frch_last and frag_now match on + entry and exit, and that old frag_now has non-zero type. Replace + "know" uses with "assert". Use frag_alloc instead of mucking with + obstack alignment. + * frags.h (frags): Declaration deleted. + * subsegs.h (struct frchain): Add new field frch_frag_now. + * subsegs.c (frchains, dummy_frag, absolute_frchain): New static + variables. + (subsegs_begin): Initialize frchains obstack. Under gcc, don't + give it any stricter alignment than frchainS structures need. Do + not initialize frags obstack. Set frag_now to point to + dummy_obstack. Initialize absolute_frchain. + (subseg_set_rest): Save and restore frag_now in frch_frag_now + field of frchainS. Don't create new frags on section switch, and + use frag_alloc when creating a new frag chain. For absolute + section, set frchain_now to absolute_frchain. Verify that + frch_last and frag_now match on entry and exit. Initialize + per-chain obstack, and under gcc, set required alignment to that + needed by fragS structure. + + * write.c (chain_frchains_together_1): Verify fr_type is nonzero. + + * stabs.c (get_stab_string_offset): Only copy input string if a + fresh copy is needed, not if the section already exists. + (s_stab_generic): Cache stab section name to bypass lookups, since + usually it will match. Could be made faster still by changing the + memory allocation rules. + (s_xstab): Cache section name to bypass repeated string + allocation. + + * frags.c (frag_new): Deleted register declarations. + + * listing.c (frag_now): Don't declare. + + * as.c (chunksize): New variable. + (debug_memory): New variable. + (main): If debug_memory is set, reduce chunksize and + _bfd_chunksize. + * as.h (chunksize): Declare it. + * read.c (read_begin): Use it. + + * config/tc-alpha.c (md_shortopts): Include 'g'. + (md_parse_option): Ignore it. + + * Makefile.in (distclean): Remove Makefile and config.status from + testsuite directory. + (clean-here): Don't delete testsuite. Instead, delete only the + files within it that would be generated by running tests. + + * config/tc-hppa.c (hppa_elf_mark_end_of_function): Call + frag_now_fix instead of accessing obstack info directly. + * config/tc-arm.c (s_ltorg): Ditto. + (md_assemble): Ditto. + + * config/tc-i386.c (md_assemble): Call frag_grow instead of + obstack_room. + +Wed Oct 18 12:22:59 1995 Ken Raeburn <raeburn@cygnus.com> + + * stabs.c (aout_process_stab): Insert debug symbol into symbol + chain after parsing value expression, if any, to avoid separating + continued .stabs lines. + +Mon Oct 16 10:56:41 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c (mips_elf_pseudo_table): Remove. + (mips_pop_insert): Don't call pop_insert on mips_elf_pseudo_table. + +Mon Oct 16 07:07:37 1995 Michael Meissner <meissner@wogglebug.tiac.net> + + * config/tc-ppc.c (md_begin): Use new flags PPC_OPCODE_COMMON for + -mcom support and PPC_OPCODE_ANY for -many. + (md_parse_option): Ditto. + (ppc_arch): Ditto. + (md_begin): For duplicate instructions, print all duplicates + before aborting. + +Sun Oct 15 22:06:14 1995 Michael Meissner <meissner@cygnus.com> + + * config/tc-ppc.c (md_parse_option): Support for -mcom to turn on + common mode operation. + (md_show_usage): Add -mcom to usage message. + +Fri Oct 13 13:32:45 1995 steve chamberlain <sac@slash.cygnus.com> + + * expr.c (op_rank): Add O_symbol_rva. + * expr.h (operatorT): Add O_symbol_rva. + * read.c (cons_worker): Set O_symbol_rva when necessary. + * write.c (fix_new_exp): Understand O_symbol_rva. + +Tue Oct 10 11:34:14 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-mips.c: Correct s_cons arguments. From Michael + Joosten <joost@ori.cadlab.de>. + +Mon Oct 9 19:59:53 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_macro): Make count unsigned. + (ppc_biei): Set segment to now_seg and value to coff_n_line_nos. + (ppc_frob_symbol): Handle C_BINCL and C_EINCL symbols by setting + the fix_line field. + * config/obj-coff.c (coff_n_line_nos): Rename from n_line_nos, and + make non-static. Change all users. + * config/obj-coff.h (coff_n_line_nos): Declare. + +Fri Oct 6 16:24:27 1995 Ken Raeburn <raeburn@cygnus.com> + + Mon Sep 25 22:49:32 1995 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> + + * configure.in (AC_ARG_WITH(bfd-assembler)): Fix help message. + + * config/obj-elf.c (obj_elf_common): Convert specified byte + alignment to power of two. Set size of local bss symbol. + + * config/tc-m68k.c (tc_gen_reloc): Fix typo in variable name. + +Fri Oct 6 15:22:25 1995 Ian Lance Taylor <ian@cygnus.com> + + * sb.c, macro.c: Decide whether to include <string.h> or + <strings.h> just as as.h does. + +Fri Oct 6 09:55:33 1995 Doug Evans <dje@canuck.cygnus.com> + + * Makefile.in (site.exp): Fix setting of $srcdir. + + * config/tc-arm.c (md_atof): Fix little-endian output. + * config/tc-arm.h (ARM_BI_ENDIAN): Move definition so defined for + all coff targets. + +Thu Oct 5 20:17:30 1995 Ken Raeburn <raeburn@cygnus.com> + + * doc/as.texinfo: Split out the NS32k family documentation, + despite its being commented out for now. + * doc/c-ns32k.texi: New file. + + * sb.c, macro.c: Include string.h. + + * Makefile.in (comparison): Only check *.o; we don't care if + timestamps inserted by the native linker differ. + + * config/tc-alpha.c (alpha_align): Only fill with a no-op pattern + if alignment stricter than 4 bytes is requested; in that case, + align to a 4-byte boundary first. + + Thu Sep 28 19:35:27 1995 Pat Rankin <rankin@eql.caltech.edu> + + * config/obj-vms.c (VMS_RSYM_Parse): eliminate "might be used + uninitialized" warning for `Max_Source_Offset'. + +Wed Oct 4 16:17:02 1995 Kim Knuttila <krk@cygnus.com> + + * config/tc-ppc.c (parse_toc_entry): New function to parse [toc] + qualifiers and detect errors if present. + (md_assemble): Add call to parse_toc_entry. Also added some support + for the [tocv] qualifier. + (ppc_pe_tocd): New function to support data in the toc section. + +Wed Oct 4 14:03:39 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-ppc.c (ppc_frob_symbol): Don't create an aux entry for + an absolute symbol. + +Tue Oct 3 12:18:19 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/tc-m68k.c (isword): Accept all values from -65536 to + +65535, so ~VAL will not be rejected. + + * cond.c (s_endif): Call demand_empty_rest_of_line. In MRI mode, + skip characters after the pseudo-op. + (s_else): Likewise. + * read.c (get_line_sb): Don't look past buffer_limit. + (s_include): In MRI mode, skip characters after the file name. + +Mon Oct 2 16:15:27 1995 Ian Lance Taylor <ian@cygnus.com> + + * config/m68k-parse.y (m68k_reg_parse): In MRI mode, permit + periods in register names. + +For older changes see ChangeLog.1. diff --git a/contrib/binutils/gas/Makefile.in b/contrib/binutils/gas/Makefile.in new file mode 100644 index 0000000..f381c3f --- /dev/null +++ b/contrib/binutils/gas/Makefile.in @@ -0,0 +1,1644 @@ +# Makefile for GNU Assembler +# Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 1997 +# Free Software Foundation, Inc. + +# This file is part of GNU GAS. + +# GNU GAS is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# GNU GAS is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU GAS; see the file COPYING. If not, write to the Free +# Software Foundation, 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, mostlyclean, distclean, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +VPATH = @srcdir@ +srcdir = @srcdir@ +srcroot = $(srcdir)/.. + +target_alias = @target_alias@ +prefix = @prefix@ + +program_transform_name = @program_transform_name@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +tooldir = $(exec_prefix)/$(target_alias) + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = @infodir@ +includedir = @includedir@ + +VERSION=2.8.1 + +SHELL = /bin/sh + +INSTALL = $${srcroot}/install.sh -c +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' +INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1 + +DISTSTUFF= make-gas.com m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c + +AR = ar +AR_FLAGS = qv +BISON = bison -y +BISONFLAGS = +LEX = `if [ -f ../flex/flex ] ; then echo ../flex/flex ; else echo flex ; fi` +LEXFLAGS = +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +RANLIB = ranlib +CC = @CC@ +HLDFLAGS = @HLDFLAGS@ +HLDENV = @HLDENV@ +RPATH_ENVVAR = @RPATH_ENVVAR@ +CFLAGS = -g +LDFLAGS = +DEP = mkdep + +MAKEOVERRIDES= + +EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \ + echo $${rootme}/../expect/expect ; \ + else echo expect ; fi` + +FLAGS_TO_PASS = \ + "prefix=$(prefix)" \ + "exec_prefix=$(exec_prefix)" \ + "tooldir=$(tooldir)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "LOADLIBES=$(LOADLIBES)" \ + "LDFLAGS=$(LDFLAGS)" \ + "BISON=$(BISON)" \ + "LEX=$(LEX)" \ + "MAKEINFO=$(MAKEINFO)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" + +RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \ + echo $${srcdir}/../dejagnu/runtest ; else echo runtest; \ + fi` +RUNTESTFLAGS= + +TARG_CPU = @target_cpu_type@ +TARG_CPU_C = $(srcdir)/config/tc-@target_cpu_type@.c +TARG_CPU_O = tc-@target_cpu_type@.o +TARG_CPU_H = $(srcdir)/config/tc-@target_cpu_type@.h +OBJ_FORMAT_C = $(srcdir)/config/obj-@obj_format@.c +OBJ_FORMAT_O = obj-@obj_format@.o +OBJ_FORMAT_H = $(srcdir)/config/obj-@obj_format@.h +TARG_ENV_H = $(srcdir)/config/te-@te_file@.h +ATOF_TARG_C = $(srcdir)/config/atof-@atof@.c +ATOF_TARG_O = atof-@atof@.o + +# use @target_cpu_type@ for refering to configured target name +IT_HDRS=itbl-parse.h $(srcdir)/itbl-ops.h +IT_SRCS=itbl-parse.c itbl-lex.c $(srcdir)/itbl-ops.c +IT_DEPS=$(srcdir)/itbl-parse.y $(srcdir)/itbl-lex.l $(srcdir)/config/itbl-@target_cpu_type@.h +IT_OBJS=itbl-parse.o itbl-lex.o itbl-ops.o + +# CPU types. This is only used for dependency information. + +CPU_TYPES = \ + a29k \ + alpha \ + arm \ + d10v \ + h8300 \ + h8500 \ + hppa \ + i386 \ + i860 \ + i960 \ + m32r \ + m68k \ + m88k \ + mips \ + mn10200 \ + mn10300 \ + ns32k \ + ppc \ + sh \ + sparc \ + tahoe \ + vax \ + w65 \ + z8k + +# Object format types. This is only used for dependency information. +# We deliberately omit som, since it does not work as a cross assembler. + +OBJ_FORMATS = \ + aout \ + bout \ + coff \ + ecoff \ + elf \ + evax \ + hp300 \ + ieee \ + vms + +# This is an sh case which sets valid according to whether the CPU +# type in the shell variable c and the OS type in the shell variable o +# are supported. This helps cuts down on the amount of dependency +# information. + +CPU_OBJ_VALID = \ + valid= ; \ + case $$o in \ + aout) \ + case $$c in \ + a29k | arm | i386 | i860 | m68k | mips | ns32k | sparc | tahoe | vax) \ + valid=yes ;; \ + esac ;; \ + bout) \ + case $$c in \ + i960) valid=yes ;; \ + esac ;; \ + coff) valid=yes ;; \ + ecoff) \ + case $$c in \ + mips | alpha) valid=yes ;; \ + esac ;; \ + elf) valid=yes ;; \ + evax) \ + case $$c in \ + alpha) valid=yes ;; \ + esac ;; \ + hp300) \ + case $$c in \ + m68k) valid=yes ;; \ + esac ;; \ + vms) \ + case $$c in \ + vax) valid=yes ;; \ + esac ;; \ + esac; + +# This is like CPU_OBJ_VALID, for the obj=multi case. + +CPU_MULTI_VALID = \ + valid= ; \ + case $$c in \ + i386 | mips) valid=yes ;; \ + esac; + +# Regular source files. + +CFILES = \ + app.c \ + as.c \ + atof-generic.c \ + bignum-copy.c \ + cond.c \ + ecoff.c \ + expr.c \ + flonum-copy.c \ + flonum-konst.c \ + flonum-mult.c \ + frags.c \ + gasp.c \ + hash.c \ + input-file.c \ + input-scrub.c \ + itbl-ops.c \ + listing.c \ + literal.c \ + macro.c \ + messages.c \ + output-file.c \ + read.c \ + sb.c \ + stabs.c \ + subsegs.c \ + symbols.c \ + write.c + +HFILES = \ + as.h \ + bignum.h \ + bit_fix.h \ + ecoff.h \ + emul-target.h \ + emul.h \ + expr.h \ + flonum.h \ + frags.h \ + hash.h \ + input-file.h \ + itbl-ops.h \ + listing.h \ + macro.h \ + obj.h \ + output-file.h \ + read.h \ + sb.h \ + struc-symbol.h \ + subsegs.h \ + symbols.h \ + tc.h \ + write.h + +# CPU files in config. + +TARGET_CPU_CFILES = \ + config/tc-a29k.c \ + config/tc-alpha.c \ + config/tc-arm.c \ + config/tc-d10v.c \ + config/tc-h8300.c \ + config/tc-h8500.c \ + config/tc-hppa.c \ + config/tc-i386.c \ + config/tc-i860.c \ + config/tc-i960.c \ + config/tc-m32r.c \ + config/tc-m68k.c \ + config/tc-m88k.c \ + config/tc-mips.c \ + config/tc-mn10200.c \ + config/tc-mn10300.c \ + config/tc-ns32k.c \ + config/tc-ppc.c \ + config/tc-sh.c \ + config/tc-sparc.c \ + config/tc-tahoe.c \ + config/tc-vax.c \ + config/tc-w65.c \ + config/tc-z8k.c + +TARGET_CPU_HFILES = \ + config/tc-a29k.h \ + config/tc-alpha.h \ + config/tc-arm.h \ + config/tc-d10v.h \ + config/tc-h8300.h \ + config/tc-h8500.h \ + config/tc-hppa.h \ + config/tc-i386.h \ + config/tc-i860.h \ + config/tc-i960.h \ + config/tc-m32r.h \ + config/tc-m68k.h \ + config/tc-m88k.h \ + config/tc-mips.h \ + config/tc-mn10200.h \ + config/tc-mn10300.h \ + config/tc-ns32k.h \ + config/tc-ppc.h \ + config/tc-sh.h \ + config/tc-sparc.h \ + config/tc-tahoe.h \ + config/tc-vax.h \ + config/tc-w65.h \ + config/tc-z8k.h + +# OBJ files in config + +OBJ_FORMAT_CFILES = \ + config/obj-aout.c \ + config/obj-bout.c \ + config/obj-coff.c \ + config/obj-ecoff.c \ + config/obj-elf.c \ + config/obj-evax.c \ + config/obj-hp300.c \ + config/obj-ieee.c \ + config/obj-som.c \ + config/obj-vms.c + +OBJ_FORMAT_HFILES = \ + config/obj-aout.h \ + config/obj-bout.h \ + config/obj-coff.h \ + config/obj-ecoff.h \ + config/obj-elf.h \ + config/obj-evax.h \ + config/obj-hp300.h \ + config/obj-ieee.h \ + config/obj-som.h \ + config/obj-vms.h + +# Emulation header files in config + +TARG_ENV_HFILES = \ + config/te-386bsd.h \ + config/te-aux.h \ + config/te-delta.h \ + config/te-delt88.h \ + config/te-dpx2.h \ + config/te-dynix.h \ + config/te-generic.h \ + config/te-go32.h \ + config/te-hp300.h \ + config/te-hppa.h \ + config/te-i386aix.h \ + config/te-ic960.h \ + config/te-linux.h \ + config/te-lnews.h \ + config/te-lynx.h \ + config/te-mach.h \ + config/te-macos.h \ + config/te-multi.h \ + config/te-nbsd.h \ + config/te-nbsd532.h \ + config/te-pc532mach.h \ + config/te-pe.h \ + config/te-ppcnw.h \ + config/te-psos.h \ + config/te-riscix.h \ + config/te-sparcaout.h \ + config/te-sun3.h \ + config/te-svr4.h \ + config/te-sysv32.h + +# Multi files in config + +MULTI_CFILES = \ + config/e-i386coff.c \ + config/e-i386elf.c \ + config/e-mipsecoff.c \ + config/e-mipself.c + +# @target_frag@ + +OBJS = \ + $(TARG_CPU_O) \ + $(OBJ_FORMAT_O) \ + $(ATOF_TARG_O) \ + app.o \ + as.o \ + atof-generic.o \ + bignum-copy.o \ + cond.o \ + expr.o \ + flonum-konst.o \ + flonum-copy.o \ + flonum-mult.o \ + frags.o \ + hash.o \ + input-file.o \ + input-scrub.o \ + literal.o \ + messages.o \ + output-file.o \ + read.o \ + subsegs.o \ + symbols.o \ + write.o \ + listing.o \ + ecoff.o \ + stabs.o \ + sb.o \ + macro.o \ + @extra_objects@ + +GASPOBJS = \ + gasp.o \ + macro.o \ + sb.o \ + hash.o + +all: .gdbinit as.new gasp.new + @srcroot=`cd $(srcroot); pwd`; export srcroot; \ + (cd doc ; $(MAKE) $(FLAGS_TO_PASS) all) + +dvi info install-info clean-info: + @srcroot=`cd $(srcroot); pwd`; export srcroot; \ + (cd doc ; $(MAKE) $(FLAGS_TO_PASS) $@) + +make-gas.com: stamp-mk.com +stamp-mk.com: vmsconf.sh Makefile + sh $(srcdir)/vmsconf.sh $(OBJS) > new-make.com + $(SHELL) $(srcdir)/../move-if-change new-make.com $(srcdir)/make-gas.com + touch stamp-mk.com + +# Now figure out from those variables how to compile and link. + +# This is the variable actually used when we compile. +ALL_CFLAGS = -D_GNU_SOURCE $(INTERNAL_CFLAGS) $(CROSS) $(CFLAGS) $(HDEFINES) $(TDEFINES) + +# How to link with both our special library facilities +# and the system's installed libraries. + +LIBDEPS = @OPCODES_DEP@ @BFDDEP@ $(LOCAL_LOADLIBES) ../libiberty/libiberty.a +LIBS = @OPCODES_LIB@ @BFDLIB@ $(LOCAL_LOADLIBES) ../libiberty/libiberty.a + +BASEDIR = $(srcdir)/.. +BFDDIR = $(BASEDIR)/bfd +INCDIR = $(BASEDIR)/include + +# Specify the directories to be searched for header files. +# Both . and srcdir are used, in that order, +# so that tm.h and config.h will be found in the compilation +# subdirectory rather than in the source directory. +INCLUDES = -I. -I$(srcdir) -I../bfd -I$(srcdir)/config -I$(INCDIR) -I$(srcdir)/.. -I$(BFDDIR) + +# Always use -I$(srcdir)/config when compiling. +.c.o: + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $< + +# This tells GNU make version 3 not to export all the variables +# defined in this file into the environment. +.NOEXPORT: + +# Files to be copied away after each stage in building. +STAGESTUFF = *.o as.new gasp.new + +$(OBJS): @ALL_OBJ_DEPS@ + +as.new: $(OBJS) $(LIBDEPS) + $(HLDENV) $(CC) $(HLDFLAGS) $(ALL_CFLAGS) $(LDFLAGS) -o as.new $(OBJS) $(LIBS) $(LOADLIBES) + +# Stuff that every object file depends upon. If anything is removed +# from this list, remove it from dep-in.sed as well. +$(OBJS): config.h as.h $(TARG_ENV_H) $(OBJ_FORMAT_H) $(TARG_CPU_H) flonum.h \ + expr.h struc-symbol.h write.h frags.h hash.h read.h symbols.h tc.h \ + obj.h listing.h bignum.h bit_fix.h $(INCDIR)/libiberty.h + +gasp.new: $(GASPOBJS) ../libiberty/libiberty.a + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gasp.new $(GASPOBJS) ../libiberty/libiberty.a $(LOADLIBES) + +installcheck: + @echo No installcheck target is available yet for the GNU assembler. + +site.exp: ./Makefile + @echo "Making a new config file..." + -@rm -f ./tmp? + @touch site.exp + -@mv site.exp site.bak + @echo "## these variables are automatically generated by make ##" > ./tmp0 + @echo "# Do not edit here. If you wish to override these values," >> ./tmp0 + @echo "# do so in the last section." >> ./tmp0 + @echo set host_os @host_os@ >> ./tmp0 + @echo set host_alias @host_alias@ >> ./tmp0 + @echo set host_cpu @host_cpu@ >> ./tmp0 + @echo set host_vendor @host_vendor@ >> ./tmp0 + @echo set target_os @target_os@ >> ./tmp0 + @echo set target_alias @target_alias@ >> ./tmp0 + @echo set target_cpu @target_cpu@ >> ./tmp0 + @echo set target_vendor @target_vendor@ >> ./tmp0 + @echo set host_triplet @host@ >> ./tmp0 + @echo set target_triplet @target@ >> ./tmp0 + @echo set target_canonical @target@ >> ./tmp0 + @echo set srcdir ${srcdir}/testsuite >> ./tmp0 + @echo set exec_prefix ${exec_prefix} >> ./tmp0 + @echo set objdir `pwd` >> ./tmp0 + @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./tmp0 + @sed -e '1,/^## All variables above are.*##/ d' < site.bak >> ./tmp0 + @mv -f ./tmp0 site.exp + +check: site.exp + if [ -d testsuite ]; then \ + true; \ + else \ + mkdir testsuite; \ + fi + rm -f testsuite/site.exp + cp site.exp testsuite/site.exp + rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + $(RPATH_ENVVAR)=$$rootme/../bfd:$$rootme/../opcodes:$$$(RPATH_ENVVAR); \ + export $(RPATH_ENVVAR); \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=$${srcdir}/../tcl/library ; \ + export TCL_LIBRARY ; fi ; \ + $(RUNTEST) --tool gas --srcdir $${srcdir}/testsuite $(RUNTESTFLAGS) + +config.status: configure + $(SHELL) config.status --recheck + +config.h: config-stamp ; @true +config-stamp: Makefile conf + -rm -f config.new config-stamp + echo '/* config.h. Generated automatically by make. */' > config.new + echo '#ifndef GAS_VERSION' >> config.new + echo '#define GAS_VERSION "$(VERSION)"' >> config.new + echo '' >> config.new + cat conf >> config.new + echo '#endif /* GAS_VERSION */' >> config.new + $(SHELL) $(srcdir)/../move-if-change config.new config.h + touch config-stamp + +# The implicit .c.o rule doesn't work for these, perhaps because of +# the variables, or perhaps because the sources are not on vpath. +$(TARG_CPU_O): $(TARG_CPU_C) $(TARG_CPU_DEP_@target_cpu_type@) + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(TARG_CPU_C) +$(ATOF_TARG_O): $(ATOF_TARG_C) + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(ATOF_TARG_C) + +# ecoff.c only has full dependencies when ECOFF_DEBUGGING is defined, +# so the automatic dependency stuff doesn't work. +ecoff.o : ecoff.c ecoff.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/sym.h \ + $(INCDIR)/coff/ecoff.h $(INCDIR)/coff/symconst.h \ + $(INCDIR)/aout/stab_gnu.h + +# We need all these explicit rules for the multi stuff. Because of +# these rules, we don't need one for OBJ_FORMAT_O. + +obj-aout.o : $(srcdir)/config/obj-aout.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-aout.c +obj-bout.o : $(srcdir)/config/obj-bout.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-bout.c +obj-coff.o: $(srcdir)/config/obj-coff.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-coff.c +obj-ecoff.o : $(srcdir)/config/obj-ecoff.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-ecoff.c +obj-elf.o : $(srcdir)/config/obj-elf.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-elf.c +obj-evax.o : $(srcdir)/config/obj-evax.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-evax.c +obj-hp300.o : $(srcdir)/config/obj-hp300.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-hp300.c +obj-ieee.o : $(srcdir)/config/obj-ieee.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-ieee.c +obj-multi.o : $(srcdir)/config/obj-multi.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-multi.c +obj-som.o : $(srcdir)/config/obj-som.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-som.c +obj-vms.o : $(srcdir)/config/obj-vms.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/obj-vms.c + +e-mipself.o : $(srcdir)/config/e-mipself.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/e-mipself.c +e-mipsecoff.o : $(srcdir)/config/e-mipsecoff.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/e-mipsecoff.c +e-i386coff.o: $(srcdir)/config/e-i386coff.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/e-i386coff.c +e-i386elf.o: $(srcdir)/config/e-i386elf.c + $(CC) -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/config/e-i386elf.c + +# The m68k operand parser. + +# Depend upon itbl-parse.c to serialize a parallel make. +m68k-parse.c: $(srcdir)/config/m68k-parse.y itbl-parse.c + $(BISON) $(BISONFLAGS) $(srcdir)/config/m68k-parse.y + mv -f y.tab.c m68k-parse.c +m68k-parse.o: m68k-parse.c $(srcdir)/config/m68k-parse.h + +# The instruction table specification lexical analyzer and parser. + +itbl-lex.c: $(srcdir)/itbl-lex.l + $(LEX) $(LEXFLAGS) $(srcdir)/itbl-lex.l + mv -f lex.yy.c itbl-lex.c + +itbl-lex.o: itbl-lex.c itbl-parse.h + +itbl-parse.c: $(srcdir)/itbl-parse.y + $(BISON) -d $(BISONFLAGS) $(srcdir)/itbl-parse.y + mv -f y.tab.c itbl-parse.c + mv -f y.tab.h itbl-parse.h + +itbl-parse.h: itbl-parse.c + +itbl-parse.o: itbl-parse.c itbl-parse.h $(srcdir)/itbl-ops.h + +itbl-ops.o: $(srcdir)/itbl-ops.c $(srcdir)/itbl-ops.h itbl-parse.h + +# stand-alone itbl assembler & disassembler +itbl-test-ops.o: $(srcdir)/itbl-ops.c \ + $(srcdir)/itbl-ops.h itbl-parse.h + $(CC) -o itbl-test-ops.o -DSTAND_ALONE -c $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $(srcdir)/itbl-ops.c + +itbl-test.o: $(srcdir)/testsuite/gas/all/itbl-test.c $(srcdir)/itbl-ops.h + $(CC) -c -DSTAND_ALONE $(ALL_CFLAGS) $(INCLUDES)\ + $(srcdir)/testsuite/gas/all/itbl-test.c + +IT_TEST_OBJS= itbl-parse.o itbl-lex.o itbl-test-ops.o +itbl-test: $(IT_TEST_OBJS) itbl-test.o $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o itbl-test itbl-test.o $(IT_TEST_OBJS) $(LIBS) + +# CGEN interface. + +cgen.o: cgen.c cgen-opc.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/cgen.h \ + $(srcdir)/../opcodes/$(TARG_CPU)-opc.h + +# Remake the info files. + +doc: $(srcdir)/as.info + +$(srcdir)/as.info: $(srcdir)/doc/as.texinfo + @(cd doc; $(MAKE) $(FLAGS_TO_PASS) as.info; mv as.info $srcdir) + +diststuff: $(DISTSTUFF) info + +clean-here: + -rm -f $(STAGESTUFF) core stamp-mk.com + -rm -f testsuite/*.o testsuite/*.out \ + testsuite/gas.log testsuite/gas.sum testsuite/site.exp + -rm -rf dep.sed .tcdep .objdep .dep2 .dep1 .depa .dep .depdir + +clean mostlyclean: clean-here + @cd doc ; $(MAKE) $(FLAGS_TO_PASS) $@ + +# Like clean but also delete the links made to configure gas. + +DISTCLEAN_HERE = config.status Makefile targ-env.h targ-cpu.h obj-format.h \ + TAGS itbl-cpu.h cgen-opc.h site.exp site.bak \ + config-stamp config.h conf config.log config.cache .gdbinit \ + testsuite/Makefile testsuite/config.status + +distclean: clean-here + @cd doc ; $(MAKE) $(FLAGS_TO_PASS) $@ + -rm -f $(DISTCLEAN_HERE) + +maintainer-clean realclean: clean-here + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + @cd doc ; $(MAKE) $(FLAGS_TO_PASS) $@ + -rm -rf $(DISTCLEAN_HERE) $(DISTSTUFF) + +# Entry points `install', `includes' and `uninstall'. + +# Copy the files into directories where they will be run. +install: + srcroot=`cd $(srcroot); pwd`; export srcroot; \ + $(INSTALL_XFORM) as.new $(bindir)/as; \ + $(INSTALL_XFORM1) $(srcdir)/doc/as.1 $(man1dir)/as.1; \ + test -d $(tooldir) || mkdir $(tooldir); \ + test -d $(tooldir)/bin || mkdir $(tooldir)/bin; \ + n=`echo as | sed '$(program_transform_name)'`; \ + rm -f $(tooldir)/bin/as; \ + ln $(bindir)/$$n $(tooldir)/bin/as >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) as.new $(tooldir)/bin/as + srcroot=`cd $(srcroot); pwd`; export srcroot; \ + $(INSTALL_XFORM) gasp.new $(bindir)/gasp + +# Cancel installation by deleting the installed files. +uninstall: + -n=`t='$(program_transform_name)'; echo as | sed $$t`; \ + rm -f $(bindir)/$$n; \ + rm -f $(mandir)/$$n.1 + -n=`t='$(program_transform_name)'; echo gasp | sed $$t`; \ + rm -f $(bindir)/$$n; \ + +# These exist for maintenance purposes. + +tags TAGS: force + etags $(HFILES) $(CFILES) $(srcdir)/config/*.[hc] $(srcdir)/README $(srcdir)/Makefile.in + +bootstrap: as.new force + $(MAKE) stage1 + rm -f stage && ln -s stage1 stage + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new gasp.new + $(MAKE) stage2 + rm -f stage && ln -s stage2 stage + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new gasp.new + $(MAKE) comparison against=stage2 + +bootstrap2: force + rm -f stage && ln -s stage1 stage + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new gasp.new + $(MAKE) stage2 + rm -f stage && ln -s stage2 stage + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new gasp.new + $(MAKE) comparison against=stage2 + +bootstrap3: force + rm -f stage && ln -s stage2 stage + $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage/ $(CFLAGS)" libdir=$(libdir) ALLOCA= as.new gasp.new + $(MAKE) comparison against=stage2 + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) stage1 + if [ -f stage1/as.new -a ! -f stage1/as ] ; then (cd stage1 ; ln -s as.new as) ; fi + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) stage2 + if [ -f stage2/as.new -a ! -f stage2/as ] ; then (cd stage2 ; ln -s as.new as) ; fi + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) stage3 + if [ -f stage3/as.new -a ! -f stage3/as ] ; then (cd stage3 ; ln -s as.new as) ; fi + +against=stage2 + +# This rule is derived from corresponding code in the Makefile.in for gcc. +# The "tail +16c" is to bypass headers which may include timestamps or +# temporary assembly file names. +comparison: force + x=0 ; \ + for file in *.o ; do \ + tail +16c ./$$file > tmp-foo1; \ + if tail +16c ${against}/$$file > tmp-foo2 2>/dev/null ; then \ + if cmp tmp-foo1 tmp-foo2 ; then \ + true ; \ + else \ + echo $$file differs ; \ + x=1 ; \ + fi ; \ + else true; fi ; \ + done ; \ + exit $$x + -rm -f tmp-foo* + +de-stage1: force + - (cd stage1 ; rm -f as ; mv -f * ..) + - rmdir stage1 + +de-stage2: force + - (cd stage2 ; rm -f as ; mv -f * ..) + - rmdir stage2 + +de-stage3: force + - (cd stage3 ; rm -f as ; mv -f * ..) + - rmdir stage3 + +#In GNU Make, ignore whether `stage*' exists. +.PHONY: stage1 stage2 stage3 stage4 clean mostlyclean realclean distclean +.PHONY: TAGS bootstrap + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) \ + $(srcdir)/configure.in config.status conf.in + $(SHELL) ./config.status +.gdbinit: $(srcdir)/gdbinit.in config.status + $(SHELL) ./config.status + +# Automatic dependency computation. This is a real pain, because the +# dependencies change based on target_cpu_type and obj_format. We +# currently ignore any dependencies caused by emulation files. + +DEP_FILE_DEPS = $(CFILES) $(HFILES) $(TARGET_CPU_CFILES) \ + $(TARGET_CPU_HFILES) $(OBJ_FORMAT_CFILES) $(OBJ_FORMAT_HFILES) + +.dep: dep.sed $(DEP_FILE_DEPS) .tcdep .objdep .dep2 + rm -f .dep1 + $(MAKE) DEP=$(DEP) .dep1 + rm -rf .depdir + sed -f dep.sed < .dep1 > .depa + sed -f dep.sed < .tcdep >> .depa + sed -f dep.sed < .objdep >> .depa + sed -f dep.sed < .dep2 >> .depa + echo '$$(OBJS): $$(DEP_@target''_cpu_type@_@obj''_format@)' >> .depa + echo '$$(TARG_CPU_O): $$(TCDEP_@target''_cpu_type@_@obj''_format@)' >> .depa + echo '$$(OBJ_FORMAT_O): $$(OBJDEP_@target''_cpu_type@_@obj''_format@)' >> .depa + echo '# IF YOU PUT ANYTHING HERE IT WILL GO AWAY' >> .depa + $(SHELL) $(srcdir)/../move-if-change .depa .dep + +# This rule needs a mkdep that runs "gcc -MM". +# FIXME: This only works correctly if $(srcdir) is an absolute path. +.dep1: $(CFILES) $(MULTI_CFILES) + if [ -d .depdir ]; then true; else mkdir .depdir; fi + cd .depdir; \ + echo '' > targ-cpu.h; \ + echo '' > obj-format.h; \ + echo '' > targ-env.h; \ + echo '' > itbl-cpu.h; \ + echo '# DO NOT DELETE THIS LINE -- mkdep uses it.' > .dep; \ + $(DEP) -f .dep -DBFD_ASSEMBLER -I. -I.. -I$(srcdir) -I../../bfd $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) $? + mv -f .depdir/.dep .dep1 + +# Work out the special dependencies for the tc-*.c files. +.tcdep: $(TARGET_CPU_CFILES) + rm -f .tcdepa + if [ -d .depdir ]; then true; else mkdir .depdir; fi + cd .depdir; \ + for c in $(CPU_TYPES); do \ + for o in $(OBJ_FORMATS); do \ + $(CPU_OBJ_VALID) \ + if [ x$${valid} = xyes ]; then \ + echo '#include "tc-'"$${c}"'.h"' > targ-cpu.h; \ + echo '#include "obj-'"$${o}"'.h"' > obj-format.h; \ + echo '#include "te-generic.h"' > targ-env.h; \ + echo '' > itbl-cpu.h; \ + echo '#include "opcodes/'"$${c}"'-opc.h"' > cgen-opc.h; \ + rm -f dummy.c; \ + cp $(srcdir)/config/tc-$${c}.c dummy.c; \ + echo '# DO NOT DELETE THIS LINE -- mkdep uses it.' > .dep; \ + $(DEP) -f .dep -DBFD_ASSEMBLER -I. -I.. -I$(srcdir) -I../../bfd $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) dummy.c; \ + sed -e "s/dummy.o: dummy.c/TCDEP_$${c}_$${o} =/" \ + -e '1,/DO NOT PUT ANYTHING AFTER/d' \ + -e '/IF YOU PUT ANYTHING/,$$d' \ + -e '/^$$/d' < .dep >> ../.tcdepa; \ + rm -f dummy.c; \ + else true; fi; \ + done; \ + done + echo 'TCDEP_hppa_som = $(srcdir)/config/tc-hppa.h subsegs.h \' >> .tcdepa + echo ' $(INCDIR)/obstack.h $(BFDDIR)/libhppa.h \' >> .tcdepa + echo ' $(INCDIR)/opcode/hppa.h $(BFDDIR)/som.h' >> .tcdepa + # We don't try to handle all multi cases. + for c in $(CPU_TYPES); do \ + $(CPU_MULTI_VALID) \ + if [ x$${valid} = xyes ]; then \ + o=ecoff; \ + $(CPU_OBJ_VALID) \ + echo 'TCDEP_'"$${c}"'_multi = \' >> .tcdepa; \ + echo '$$(TCDEP_'"$${c}"'_coff) \' >> .tcdepa; \ + if [ x$${valid} = xyes ]; then \ + echo '$$(TCDEP_'"$${c}"'_ecoff) \' >> .tcdepa; \ + else true; fi; \ + echo '$$(TCDEP_'"$${c}"'_elf)' >> .tcdepa; \ + else true; fi; \ + done + mv -f .tcdepa .tcdep + +# Work out the special dependencies for the obj-*.c files. +.objdep: $(OBJ_FORMAT_CFILES) + rm -f .objdepa + if [ -d .depdir ]; then true; else mkdir .depdir; fi + cd .depdir; \ + for c in $(CPU_TYPES); do \ + for o in $(OBJ_FORMATS); do \ + $(CPU_OBJ_VALID) \ + if [ x$${valid} = xyes ]; then \ + echo '#include "tc-'"$${c}"'.h"' > targ-cpu.h; \ + echo '#include "obj-'"$${o}"'.h"' > obj-format.h; \ + echo '#include "te-generic.h"' > targ-env.h; \ + echo '' > itbl-cpu.h; \ + rm -f dummy.c; \ + cp $(srcdir)/config/obj-$${o}.c dummy.c; \ + echo '# DO NOT DELETE THIS LINE -- mkdep uses it.' > .dep; \ + $(DEP) -f .dep -DBFD_ASSEMBLER -I. -I.. -I$(srcdir) -I../../bfd $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) dummy.c; \ + sed -e "s/dummy.o: dummy.c/OBJDEP_$${c}_$${o} =/" \ + -e '1,/DO NOT PUT ANYTHING AFTER/d' \ + -e '/IF YOU PUT ANYTHING/,$$d' \ + -e '/^$$/d' < .dep >> ../.objdepa; \ + rm -f dummy.c; \ + else true; fi; \ + done; \ + done + echo 'OBJDEP_hppa_som = $(srcdir)/config/obj-som.h subsegs.h \' >> .objdepa + echo ' $(INCDIR)/obstack.h $(BFDDIR)/libhppa.h \' >> .objdepa + echo ' $(BFDDIR)/som.h $(INCDIR)/aout/stab_gnu.h \' >> .objdepa + echo ' $(INCDIR)/aout/stab.def' >> .objdepa + # We don't try to handle all multi cases. + for c in $(CPU_TYPES); do \ + $(CPU_MULTI_VALID) \ + if [ x$${valid} = xyes ]; then \ + o=ecoff; \ + $(CPU_OBJ_VALID) \ + echo 'OBJDEP_'"$${c}"'_multi = \' >> .objdepa; \ + echo '$$(OBJDEP_'"$${c}"'_coff) \' >> .objdepa; \ + if [ x$${valid} = xyes ]; then \ + echo '$$(OBJDEP_'"$${c}"'_ecoff) \' >> .objdepa; \ + else true; fi; \ + echo '$$(OBJDEP_'"$${c}"'_elf)' >> .objdepa; \ + else true; fi; \ + done + mv -f .objdepa .objdep + +# Work out the dependencies for each CPU/OBJ combination. +# Note that SOM is a special case, because it only works native. +# FIXME: This only works correctly if $(srcdir) is an absolute path. +.dep2: $(TARGET_CPU_HFILES) $(OBJ_FORMAT_HFILES) + rm -f .dep2a + if [ -d .depdir ]; then true; else mkdir .depdir; fi + cd .depdir; \ + for c in $(CPU_TYPES); do \ + for o in $(OBJ_FORMATS); do \ + $(CPU_OBJ_VALID) \ + if [ x$${valid} = xyes ]; then \ + echo '#include "tc-'"$${c}"'.h"' > targ-cpu.h; \ + echo '#include "obj-'"$${o}"'.h"' > dummy.c; \ + echo '# DO NOT DELETE THIS LINE -- mkdep uses it.' > .dep; \ + $(DEP) -f .dep -DBFD_ASSEMBLER -I. -I.. -I$(srcdir) -I../../bfd $(ALL_CFLAGS) $(CPPFLAGS) $(INCLUDES) dummy.c; \ + sed -e "s/dummy.o: dummy.c/DEP_$${c}_$${o} =/" \ + -e '1,/DO NOT PUT ANYTHING AFTER/d' \ + -e '/IF YOU PUT ANYTHING/,$$d' \ + -e '/^$$/d' < .dep >> ../.dep2a; \ + else true; fi; \ + done; \ + done + echo 'DEP_hppa_som = $(srcdir)/../bfd/som.h' >> .dep2a + # We don't try to handle all multi cases. + for c in $(CPU_TYPES); do \ + $(CPU_MULTI_VALID) \ + if [ x$${valid} = xyes ]; then \ + o=ecoff; \ + $(CPU_OBJ_VALID) \ + echo 'DEP_'"$${c}"'_multi = \' >> .dep2a; \ + echo '$$(DEP_'"$${c}"'_coff) \' >> .dep2a; \ + if [ x$${valid} = xyes ]; then \ + echo '$$(DEP_'"$${c}"'_ecoff) \' >> .dep2a; \ + else true; fi; \ + echo '$$(DEP_'"$${c}"'_elf)' >> .dep2a; \ + else true; fi; \ + done + mv -f .dep2a .dep2 + +dep.sed: dep-in.sed config.status + sed <$(srcdir)/dep-in.sed >dep.sed \ + -e 's!@INCDIR@!$(INCDIR)!' \ + -e 's!@BFDDIR@!$(BFDDIR)!' \ + -e 's!@SRCDIR@!$(srcdir)!' + +dep: .dep + sed -e '/^..DO NOT DELETE THIS LINE/,$$d' < Makefile > tmp-Makefile + cat .dep >> tmp-Makefile + $(SHELL) $(srcdir)/../move-if-change tmp-Makefile Makefile + +dep-in: .dep + sed -e '/^..DO NOT DELETE THIS LINE/,$$d' < $(srcdir)/Makefile.in > tmp-Makefile.in + cat .dep >> tmp-Makefile.in + $(SHELL) $(srcdir)/../move-if-change tmp-Makefile.in $(srcdir)/Makefile.in + +.PHONY: dep dep-in + + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +app.o: app.c +as.o: as.c subsegs.h $(INCDIR)/obstack.h output-file.h \ + sb.h macro.h +atof-generic.o: atof-generic.c +bignum-copy.o: bignum-copy.c +cond.o: cond.c $(INCDIR)/obstack.h +ecoff.o: ecoff.c +expr.o: expr.c $(INCDIR)/obstack.h +flonum-copy.o: flonum-copy.c +flonum-konst.o: flonum-konst.c +flonum-mult.o: flonum-mult.c +frags.o: frags.c subsegs.h $(INCDIR)/obstack.h +gasp.o: gasp.c sb.h macro.h +hash.o: hash.c +input-file.o: input-file.c input-file.h +input-scrub.o: input-scrub.c input-file.h sb.h +listing.o: listing.c input-file.h subsegs.h +literal.o: literal.c subsegs.h $(INCDIR)/obstack.h +macro.o: macro.c sb.h macro.h +messages.o: messages.c +output-file.o: output-file.c output-file.h +read.o: read.c subsegs.h $(INCDIR)/obstack.h sb.h macro.h \ + ecoff.h +sb.o: sb.c sb.h +stabs.o: stabs.c $(INCDIR)/obstack.h subsegs.h ecoff.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def +subsegs.o: subsegs.c subsegs.h $(INCDIR)/obstack.h +symbols.o: symbols.c $(INCDIR)/obstack.h subsegs.h +write.o: write.c subsegs.h $(INCDIR)/obstack.h output-file.h +e-i386coff.o: $(srcdir)/config/e-i386coff.c emul.h \ + emul-target.h +e-i386elf.o: $(srcdir)/config/e-i386elf.c emul.h emul-target.h +e-mipsecoff.o: $(srcdir)/config/e-mipsecoff.c emul.h \ + emul-target.h +e-mipself.o: $(srcdir)/config/e-mipself.c emul.h emul-target.h + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +TCDEP_a29k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-a29k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/opcode/a29k.h +TCDEP_a29k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-a29k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/a29k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/opcode/a29k.h +TCDEP_a29k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-a29k.h $(INCDIR)/opcode/a29k.h +TCDEP_alpha_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-alpha.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/alpha.h \ + $(srcdir)/config/atof-vax.c +TCDEP_alpha_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-alpha.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/alpha.h \ + $(srcdir)/config/atof-vax.c +TCDEP_alpha_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-alpha.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/alpha.h $(INCDIR)/elf/alpha.h \ + $(srcdir)/config/atof-vax.c +TCDEP_alpha_evax = $(srcdir)/config/obj-evax.h $(srcdir)/config/tc-alpha.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/alpha.h \ + $(srcdir)/config/atof-vax.c +TCDEP_arm_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-arm.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h +TCDEP_arm_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-arm.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/arm.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h +TCDEP_arm_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-arm.h subsegs.h \ + $(INCDIR)/obstack.h +TCDEP_d10v_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-d10v.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/d10v.h \ + $(INCDIR)/elf/ppc.h +TCDEP_d10v_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-d10v.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/d10v.h $(INCDIR)/elf/ppc.h +TCDEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/opcode/h8300.h +TCDEP_h8300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8300.h $(INCDIR)/opcode/h8300.h +TCDEP_h8500_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8500.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8500.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/h8500-opc.h +TCDEP_h8500_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8500.h subsegs.h \ + $(INCDIR)/obstack.h $(srcdir)/../opcodes/h8500-opc.h +TCDEP_hppa_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-hppa.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(BFDDIR)/libhppa.h $(BFDDIR)/libbfd.h \ + $(INCDIR)/opcode/hppa.h +TCDEP_hppa_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-hppa.h $(BFDDIR)/elf32-hppa.h \ + $(BFDDIR)/libhppa.h $(INCDIR)/elf/hppa.h subsegs.h \ + $(INCDIR)/obstack.h $(BFDDIR)/libbfd.h $(INCDIR)/opcode/hppa.h +TCDEP_i386_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i386.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/i386.h +TCDEP_i386_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i386.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i386.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/i386.h +TCDEP_i386_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i386.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/i386.h +TCDEP_i860_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i860.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/opcode/i860.h +TCDEP_i860_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i860.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/opcode/i860.h +TCDEP_i860_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i860.h $(INCDIR)/opcode/i860.h +TCDEP_i960_bout = $(srcdir)/config/obj-bout.h $(srcdir)/config/tc-i960.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/i960.h +TCDEP_i960_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i960.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i960.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h $(INCDIR)/opcode/i960.h +TCDEP_i960_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i960.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/i960.h +TCDEP_m32r_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m32r.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h cgen-opc.h $(srcdir)/../opcodes/m32r-opc.h \ + $(INCDIR)/opcode/cgen.h +TCDEP_m32r_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m32r.h subsegs.h \ + $(INCDIR)/obstack.h cgen-opc.h $(srcdir)/../opcodes/m32r-opc.h \ + $(INCDIR)/opcode/cgen.h +TCDEP_m68k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-m68k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \ + subsegs.h $(INCDIR)/opcode/m68k.h $(srcdir)/config/m68k-parse.h +TCDEP_m68k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m68k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m68k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h $(INCDIR)/opcode/m68k.h \ + $(srcdir)/config/m68k-parse.h +TCDEP_m68k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m68k.h $(INCDIR)/obstack.h \ + subsegs.h $(INCDIR)/opcode/m68k.h $(srcdir)/config/m68k-parse.h +TCDEP_m68k_hp300 = $(srcdir)/config/obj-hp300.h $(srcdir)/config/obj-aout.h \ + $(srcdir)/config/tc-m68k.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h $(INCDIR)/opcode/m68k.h \ + $(srcdir)/config/m68k-parse.h +TCDEP_m88k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m88k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m88k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(srcdir)/config/m88k-opcode.h +TCDEP_m88k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m88k.h subsegs.h \ + $(INCDIR)/obstack.h $(srcdir)/config/m88k-opcode.h +TCDEP_mips_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-mips.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/mips.h itbl-ops.h ecoff.h $(INCDIR)/coff/sym.h \ + $(INCDIR)/coff/ecoff.h +TCDEP_mips_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mips.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/mips.h \ + itbl-ops.h ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h +TCDEP_mips_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-mips.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/mips.h \ + itbl-ops.h +TCDEP_mips_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mips.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/mips.h itbl-ops.h \ + $(INCDIR)/elf/mips.h ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h +TCDEP_mn10200_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10200.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/mn10200.h +TCDEP_mn10200_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10200.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/mn10200.h +TCDEP_mn10300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10300.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/mn10300.h +TCDEP_mn10300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10300.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/mn10300.h +TCDEP_ns32k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-ns32k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/opcode/ns32k.h \ + $(INCDIR)/obstack.h +TCDEP_ns32k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ns32k.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/opcode/ns32k.h $(INCDIR)/obstack.h +TCDEP_ns32k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ns32k.h $(INCDIR)/opcode/ns32k.h \ + $(INCDIR)/obstack.h +TCDEP_ppc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ppc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/rs6000.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/ppc.h +TCDEP_ppc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ppc.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/ppc.h $(INCDIR)/elf/ppc.h +TCDEP_sh_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sh.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sh.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/sh-opc.h +TCDEP_sh_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sh.h subsegs.h \ + $(INCDIR)/obstack.h $(srcdir)/../opcodes/sh-opc.h +TCDEP_sparc_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-sparc.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/sparc.h +TCDEP_sparc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sparc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sparc.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/sparc.h +TCDEP_sparc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sparc.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/sparc.h +TCDEP_tahoe_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-tahoe.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/tahoe.h +TCDEP_tahoe_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-tahoe.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/tahoe.h +TCDEP_tahoe_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-tahoe.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/tahoe.h +TCDEP_vax_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-vax.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(srcdir)/config/vax-inst.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/vax.h +TCDEP_vax_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(srcdir)/config/vax-inst.h $(INCDIR)/obstack.h $(INCDIR)/opcode/vax.h +TCDEP_vax_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-vax.h $(srcdir)/config/vax-inst.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/vax.h +TCDEP_vax_vms = $(srcdir)/config/obj-vms.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def $(srcdir)/config/vax-inst.h \ + $(INCDIR)/obstack.h $(INCDIR)/opcode/vax.h +TCDEP_w65_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-w65.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/w65.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/w65-opc.h +TCDEP_w65_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-w65.h subsegs.h \ + $(INCDIR)/obstack.h $(srcdir)/../opcodes/w65-opc.h +TCDEP_z8k_coff = $(srcdir)/../opcodes/z8k-opc.h $(srcdir)/config/obj-coff.h \ + $(srcdir)/config/tc-z8k.h $(INCDIR)/coff/internal.h \ + $(INCDIR)/coff/z8k.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +TCDEP_z8k_elf = $(srcdir)/../opcodes/z8k-opc.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-z8k.h +TCDEP_hppa_som = $(srcdir)/config/tc-hppa.h subsegs.h \ + $(INCDIR)/obstack.h $(BFDDIR)/libhppa.h $(INCDIR)/opcode/hppa.h \ + $(BFDDIR)/som.h +TCDEP_i386_multi = $(TCDEP_i386_coff) $(TCDEP_i386_elf) +TCDEP_mips_multi = $(TCDEP_mips_coff) $(TCDEP_mips_ecoff) \ + $(TCDEP_mips_elf) +OBJDEP_a29k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-a29k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_a29k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-a29k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/a29k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_a29k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-a29k.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_alpha_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-alpha.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_alpha_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-alpha.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(BFDDIR)/libecoff.h +OBJDEP_alpha_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-alpha.h subsegs.h \ + $(INCDIR)/obstack.h ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/aout/aout64.h +OBJDEP_alpha_evax = $(srcdir)/config/obj-evax.h $(srcdir)/config/tc-alpha.h +OBJDEP_arm_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-arm.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_arm_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-arm.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/arm.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_arm_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-arm.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_d10v_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-d10v.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_d10v_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-d10v.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_h8300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8300.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_h8500_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8500.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8500.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_h8500_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8500.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_hppa_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-hppa.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_hppa_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-hppa.h $(BFDDIR)/elf32-hppa.h \ + $(BFDDIR)/libhppa.h $(INCDIR)/elf/hppa.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_i386_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i386.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_i386_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i386.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i386.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_i386_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i386.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_i860_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i860.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_i860_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i860.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_i860_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i860.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_i960_bout = $(srcdir)/config/obj-bout.h $(srcdir)/config/tc-i960.h \ + $(INCDIR)/obstack.h +OBJDEP_i960_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i960.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i960.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_i960_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i960.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_m32r_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m32r.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_m32r_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m32r.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_m68k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-m68k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_m68k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m68k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m68k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_m68k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m68k.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_m68k_hp300 = $(srcdir)/config/obj-aout.c $(srcdir)/config/obj-hp300.h \ + $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-m68k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_m88k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m88k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m88k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_m88k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m88k.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_mips_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-mips.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_mips_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mips.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_mips_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-mips.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(BFDDIR)/libecoff.h +OBJDEP_mips_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mips.h subsegs.h \ + $(INCDIR)/obstack.h ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h \ + $(INCDIR)/elf/mips.h $(INCDIR)/aout/aout64.h +OBJDEP_mn10200_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10200.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_mn10200_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10200.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_mn10300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10300.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_mn10300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10300.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_ns32k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-ns32k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_ns32k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ns32k.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_ns32k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ns32k.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_ppc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ppc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/rs6000.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_ppc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ppc.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/elf/ppc.h $(INCDIR)/aout/aout64.h +OBJDEP_sh_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sh.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sh.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_sh_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sh.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_sparc_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-sparc.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_sparc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sparc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sparc.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_sparc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sparc.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_tahoe_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-tahoe.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_tahoe_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-tahoe.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_tahoe_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-tahoe.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_vax_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-vax.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h $(INCDIR)/aout/aout64.h \ + $(INCDIR)/obstack.h +OBJDEP_vax_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h \ + $(INCDIR)/obstack.h subsegs.h +OBJDEP_vax_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-vax.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_vax_vms = $(srcdir)/config/obj-vms.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def subsegs.h \ + $(INCDIR)/obstack.h +OBJDEP_w65_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-w65.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/w65.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_w65_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-w65.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_z8k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-z8k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/z8k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h subsegs.h +OBJDEP_z8k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-z8k.h subsegs.h \ + $(INCDIR)/obstack.h $(INCDIR)/aout/aout64.h +OBJDEP_hppa_som = $(srcdir)/config/obj-som.h subsegs.h \ + $(INCDIR)/obstack.h $(BFDDIR)/libhppa.h $(BFDDIR)/som.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def +OBJDEP_i386_multi = $(OBJDEP_i386_coff) $(OBJDEP_i386_elf) +OBJDEP_mips_multi = $(OBJDEP_mips_coff) $(OBJDEP_mips_ecoff) \ + $(OBJDEP_mips_elf) +DEP_a29k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-a29k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_a29k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-a29k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/a29k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_a29k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-a29k.h +DEP_alpha_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-alpha.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_alpha_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-alpha.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h +DEP_alpha_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-alpha.h +DEP_alpha_evax = $(srcdir)/config/obj-evax.h $(srcdir)/config/tc-alpha.h +DEP_arm_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-arm.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_arm_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-arm.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/arm.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_arm_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-arm.h +DEP_d10v_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-d10v.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_d10v_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-d10v.h +DEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_h8300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8300.h +DEP_h8500_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8500.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8500.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_h8500_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-h8500.h +DEP_hppa_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-hppa.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_hppa_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-hppa.h $(BFDDIR)/elf32-hppa.h \ + $(BFDDIR)/libhppa.h $(INCDIR)/elf/hppa.h +DEP_i386_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i386.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_i386_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i386.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i386.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_i386_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i386.h +DEP_i860_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-i860.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_i860_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i860.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_i860_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i860.h +DEP_i960_bout = $(srcdir)/config/obj-bout.h $(srcdir)/config/tc-i960.h +DEP_i960_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-i960.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/i960.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_i960_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-i960.h +DEP_m32r_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m32r.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_m32r_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m32r.h +DEP_m68k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-m68k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_m68k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m68k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m68k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_m68k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m68k.h +DEP_m68k_hp300 = $(srcdir)/config/obj-hp300.h $(srcdir)/config/obj-aout.h \ + $(srcdir)/config/tc-m68k.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_m88k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-m88k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/m88k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_m88k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-m88k.h +DEP_mips_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-mips.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_mips_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mips.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_mips_ecoff = $(srcdir)/config/obj-ecoff.h $(srcdir)/config/tc-mips.h \ + ecoff.h $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h +DEP_mips_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mips.h +DEP_mn10200_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10200.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_mn10200_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10200.h +DEP_mn10300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-mn10300.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_mn10300_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-mn10300.h +DEP_ns32k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-ns32k.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_ns32k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ns32k.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_ns32k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ns32k.h +DEP_ppc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-ppc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/rs6000.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_ppc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-ppc.h +DEP_sh_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sh.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sh.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_sh_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sh.h +DEP_sparc_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-sparc.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_sparc_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sparc.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/sparc.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_sparc_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-sparc.h +DEP_tahoe_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-tahoe.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_tahoe_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-tahoe.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_tahoe_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-tahoe.h +DEP_vax_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-vax.h \ + $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h +DEP_vax_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h +DEP_vax_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-vax.h +DEP_vax_vms = $(srcdir)/config/obj-vms.h $(srcdir)/config/tc-vax.h \ + $(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def +DEP_w65_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-w65.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/w65.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_w65_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-w65.h +DEP_z8k_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-z8k.h \ + $(INCDIR)/coff/internal.h $(INCDIR)/coff/z8k.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h +DEP_z8k_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.h \ + $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ + $(INCDIR)/bfdlink.h $(srcdir)/config/tc-z8k.h +DEP_hppa_som = $(BFDDIR)/som.h +DEP_i386_multi = $(DEP_i386_coff) $(DEP_i386_elf) +DEP_mips_multi = $(DEP_mips_coff) $(DEP_mips_ecoff) \ + $(DEP_mips_elf) +$(OBJS): $(DEP_@target_cpu_type@_@obj_format@) +$(TARG_CPU_O): $(TCDEP_@target_cpu_type@_@obj_format@) +$(OBJ_FORMAT_O): $(OBJDEP_@target_cpu_type@_@obj_format@) +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/contrib/binutils/gas/NEWS b/contrib/binutils/gas/NEWS new file mode 100644 index 0000000..c60c8b8 --- /dev/null +++ b/contrib/binutils/gas/NEWS @@ -0,0 +1,251 @@ +-*- text -*- + +Changes in 2.8: + +BeOS support added. + +MIPS16 support added. + +Motorola ColdFire 5200 support added (configure for m68k and use -m5200). + +Alpha/VMS support added. + +m68k options --base-size-default-16, --base-size-default-32, +--disp-size-default-16, and --disp-size-default-32 added. + +The alignment directives now take an optional third argument, which is the +maximum number of bytes to skip. If doing the alignment would require skipping +more than the given number of bytes, the alignment is not done at all. + +The ELF assembler has a new pseudo-op, .symver, used for symbol versioning. + +The -a option takes a new suboption, c (e.g., -alc), to skip false conditionals +in listings. + +Added new pseudo-op, .equiv; it's like .equ, except that it is an error if the +symbol is already defined. + +Changes in 2.7: + +The PowerPC assembler now allows the use of symbolic register names (r0, etc.) +if -mregnames is used. Symbolic names preceded by a '%' (%r0, etc.) can be +used any time. PowerPC 860 move to/from SPR instructions have been added. + +Alpha Linux (ELF) support added. + +PowerPC ELF support added. + +m68k Linux (ELF) support added. + +i960 Hx/Jx support added. + +i386/PowerPC gnu-win32 support added. + +SCO ELF support added. For OpenServer 5 targets (i386-unknown-sco3.2v5) the +default is to build COFF-only support. To get a set of tools that generate ELF +(they'll understand both COFF and ELF), you must configure with +target=i386-unknown-sco3.2v5elf. + +m88k-motorola-sysv* support added. + +Changes in 2.6: + +Gas now directly supports macros, without requiring GASP. + +Gas now has an MRI assembler compatibility mode. Use -M or --mri to select MRI +mode. The pseudo-op ``.mri 1'' will switch into the MRI mode until the ``.mri +0'' is seen; this can be convenient for inline assembler code. + +Added --defsym SYM=VALUE option. + +Added -mips4 support to MIPS assembler. + +Added PIC support to Solaris and SPARC SunOS 4 assembler. + +Changes in 2.4: + +Converted this directory to use an autoconf-generated configure script. + +ARM support, from Richard Earnshaw. + +Updated VMS support, from Pat Rankin, including considerably improved debugging +support. + +Support for the control registers in the 68060. + +Handles (ignores) a new directive ".this_GCC_requires_the_GNU_assembler", to +provide for possible future gcc changes, for targets where gas provides some +features not available in the native assembler. If the native assembler is +used, it should become obvious pretty quickly what the problem is. + +Usage message is available with "--help". + +The GNU Assembler Preprocessor (gasp) is included. (Actually, it was in 2.3 +also, but didn't get into the NEWS file.) + +Weak symbol support for a.out. + +A bug in the listing code which could cause an infinite loop has been fixed. +Bugs in listings when generating a COFF object file have also been fixed. + +Initial i386-svr4 PIC implementation from Eric Youngdale, based on code by Paul +Kranenburg. + +Improved Alpha support. Immediate constants can have a much larger range now. +Support for the 21164 has been contributed by Digital. + +Updated ns32k (pc532-mach, netbsd532) support from Ian Dall. + +Changes in 2.3: + +Mach i386 support, by David Mackenzie and Ken Raeburn. + +RS/6000 and PowerPC support by Ian Taylor. + +VMS command scripts (make-gas.com, config-gas.com) have been worked on a bit, +based on mail received from various people. The `-h#' option should work again +too. + +HP-PA work, by Jeff Law. Note, for the PA, gas-2.3 has been designed to work +with gdb-4.12 and gcc-2.6. As gcc-2.6 has not been released yet, a special +version of gcc-2.5.8 has been patched to work with gas-2.3. You can retrieve +this special version of gcc-2.5.8 via anonymous ftp from jaguar.cs.utah.edu +in the "dist" directory. + +Vax support in gas fixed for BSD, so it builds and seems to run a couple simple +tests okay. I haven't put it through extensive testing. (GNU make is +currently required for BSD 4.3 builds.) + +Support for the DEC Alpha, running OSF/1 (ECOFF format). The gas support is +based on code donated by CMU, which used an a.out-based format. I'm afraid the +alpha-a.out support is pretty badly mangled, and much of it removed; making it +work will require rewriting it as BFD support for the format anyways. + +Irix 5 support. + +The test suites have been fixed up a bit, so that they should work with a +couple different versions of expect and dejagnu. + +Symbols' values are now handled internally as expressions, permitting more +flexibility in evaluating them in some cases. Some details of relocation +handling have also changed, and simple constant pool management has been added, +to make the Alpha port easier. + +New option "--statistics" for printing out program run times. This is intended +to be used with the gcc "-Q" option, which prints out times spent in various +phases of compilation. (You should be able to get all of them printed out with +"gcc -Q -Wa,--statistics", I think.) + +---------------------------------------------------------------- + +Changes in 2.2: + +RS/6000 AIX and MIPS SGI Irix 5 support has been added. + +Configurations that are still in development (and therefore are convenient to +have listed in configure.in) still get rejected without a minor change to +gas/Makefile.in, so people not doing development work shouldn't get the +impression that support for such configurations is actually believed to be +reliable. + +The program name (usually "as") is printed when a fatal error message is +displayed. This should prevent some confusion about the source of occasional +messages about "internal errors". + +ELF support is falling into place. Support for the 386 should be working. +Support for SPARC Solaris is in. HPPA support from Utah is being integrated. + +Symbol values are maintained as expressions instead of being immediately boiled +down to add-symbol, sub-symbol, and constant. This permits slightly more +complex calculations involving symbols whose values are not alreadey known. + +DBX-style debugging info ("stabs") is now supported for COFF formats. +If any stabs directives are seen in the source, GAS will create two new +sections: a ".stab" and a ".stabstr" section. The format of the .stab +section is nearly identical to the a.out symbol format, and .stabstr is +its string table. For this to be useful, you must have configured GCC +to generate stabs (by defining DBX_DEBUGGING_INFO), and must have a GDB +that can use the stab sections (4.11 or later). + +LynxOS, on i386 and m68k platforms, is now supported. SPARC LynxOS +support is in progress. + +---------------------------------------------------------------- + +Changes in 2.1: + +Several small fixes for i386-aix (PS/2) support from Minh Tran-Le have been +incorporated, but not well tested yet. + +Altered the opcode table split for m68k; it should require less VM to compile +with gcc now. + +Some minor adjustments to add (Convergent Technologies') Miniframe support, +suggested by Ronald Cole. + +HPPA support (running OSF only, not HPUX) has been contributed by Utah. This +includes improved ELF support, which I've started adapting for SPARC Solaris +2.x. Integration isn't completely, so it probably won't work. + +HP9000/300 support, donated by HP, has been merged in. + +Ian Taylor has finished the MIPS ECOFF (Ultrix, Irix) support. + +Better error messages for unsupported configurations (e.g., hppa-hpux). + +Test suite framework is starting to become reasonable. + +---------------------------------------------------------------- + +Changes in 2.0: + +Mostly bug fixes. + +Some more merging of BFD and ELF code, but ELF still doesn't work. + +---------------------------------------------------------------- + +Changes in 1.94: + +BFD merge is partly done. Adventurous souls may try giving configure the +"--with-bfd-assembler" option. Currently, ELF format requires it, a.out format +accepts it; SPARC CPU accepts it. It's the default only for OS "elf" or +"solaris". (ELF isn't really supported yet. It needs work. I've got some +code from Utah for HP-PA ELF, and from DG for m88k ELF, but they're not fully +merged yet.) + +The 68K opcode table has been split in half. It should now compile under gcc +without consuming ridiculous amounts of memory. + +A couple data structures have been reduced in size. This should result in +saving a little bit of space at runtime. + +Support for MIPS, from OSF and Ralph Campbell, has been merged in. The OSF +code provided ROSE format support, which I haven't merged in yet. (I can make +it available, if anyone wants to try it out.) Ralph's code, for BSD 4.4, +supports a.out format. We don't have ECOFF support in just yet; it's coming. + +Support for the Hitachi H8/500 has been added. + +VMS host and target support should be working now, thanks chiefly to Eric +Youngdale. + +---------------------------------------------------------------- + +Changes in 1.93.01: + +For m68k, support for more processors has been added: 68040, CPU32, 68851. + +For i386, .align is now power-of-two; was number-of-bytes. + +For m68k, "%" is now accepted before register names. For COFF format, which +doesn't use underscore prefixes for C labels, it is required, so variable "a0" +can be distinguished from the register. + +Last public release was 1.38. Lots of configuration changes since then, lots +of new CPUs and formats, lots of bugs fixed. + + +Local variables: +fill-column: 79 +End: diff --git a/contrib/binutils/gas/README b/contrib/binutils/gas/README new file mode 100644 index 0000000..418b8bd --- /dev/null +++ b/contrib/binutils/gas/README @@ -0,0 +1,271 @@ + README for GAS + +A number of things have changed since version 1 and the wonderful world of gas +looks very different. There's still a lot of irrelevant garbage lying around +that will be cleaned up in time. Documentation is scarce, as are logs of the +changes made since the last gas release. My apologies, and I'll try to get +something useful. + +Unpacking and Installation - Summary +==================================== + +See ../binutils/README. + +To build just the assembler, make the target all-gas. + +Documentation +============= + +The GAS release includes texinfo source for its manual, which can be processed +into `info' or `dvi' forms. + +The DVI form is suitable for printing or displaying; the commands for doing +this vary from system to system. On many systems, `lpr -d' will print a DVI +file. On others, you may need to run a program such as `dvips' to convert the +DVI file into a form your system can print. + +If you wish to build the DVI file, you will need to have TeX installed on your +system. You can rebuild it by typing: + + cd gas/doc + make as.dvi + +The Info form is viewable with the GNU Emacs `info' subsystem, or the +standalone `info' program, available as part of the GNU Texinfo distribution. +To build the info files, you will need the `makeinfo' program. Type: + + cd gas/doc + make info + +Specifying names for hosts and targets +====================================== + + The specifications used for hosts and targets in the `configure' +script are based on a three-part naming scheme, but some short +predefined aliases are also supported. The full naming scheme encodes +three pieces of information in the following pattern: + + ARCHITECTURE-VENDOR-OS + + For example, you can use the alias `sun4' as a HOST argument or in a +`--target=TARGET' option. The equivalent full name is +`sparc-sun-sunos4'. + + The `configure' script accompanying GAS does not provide any query +facility to list all supported host and target names or aliases. +`configure' calls the Bourne shell script `config.sub' to map +abbreviations to full names; you can read the script, if you wish, or +you can use it to test your guesses on abbreviations--for example: + + % sh config.sub sun4 + sparc-sun-sunos411 + % sh config.sub sun3 + m68k-sun-sunos411 + % sh config.sub decstation + mips-dec-ultrix42 + % sh config.sub hp300bsd + m68k-hp-bsd + % sh config.sub i386v + i386-unknown-sysv + % sh config.sub i786v + Invalid configuration `i786v': machine `i786v' not recognized + + +`configure' options +=================== + + Here is a summary of the `configure' options and arguments that are +most often useful for building GAS. `configure' also has several other +options not listed here. + + configure [--help] + [--prefix=DIR] + [--srcdir=PATH] + [--host=HOST] + [--target=TARGET] + [--with-OPTION] + [--enable-OPTION] + +You may introduce options with a single `-' rather than `--' if you +prefer; but you may abbreviate option names if you use `--'. + +`--help' + Print a summary of the options to `configure', and exit. + +`-prefix=DIR' + Configure the source to install programs and files under directory + `DIR'. + +`--srcdir=PATH' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--host=HOST' + Configure GAS to run on the specified HOST. Normally the + configure script can figure this out automatically. + + There is no convenient way to generate a list of all available + hosts. + +`--target=TARGET' + Configure GAS for cross-assembling programs for the specified + TARGET. Without this option, GAS is configured to assemble .o files + that run on the same machine (HOST) as GAS itself. + + There is no convenient way to generate a list of all available + targets. + +`--enable-OPTION' + These flags tell the program or library being configured to + configure itself differently from the default for the specified + host/target combination. See below for a list of `--enable' + options recognized in the gas distribution. + +`configure' accepts other options, for compatibility with configuring +other GNU tools recursively; but these are the only options that affect +GAS or its supporting libraries. + +The `--enable' options recognized by software in the gas distribution are: + +`--enable-targets=...' + This causes one or more specified configurations to be added to those for + which BFD support is compiled. Currently gas cannot use any format other + than its compiled-in default, so this option is not very useful. + +`--enable-bfd-assembler' + This causes the assembler to use the new code being merged into it to use + BFD data structures internally, and use BFD for writing object files. + For most targets, this isn't supported yet. For most targets where it has + been done, it's already the default. So generally you won't need to use + this option. + +Supported platforms +=================== + +At this point I believe gas to be ansi only code for most target cpu's. That +is, there should be relatively few, if any host system dependencies. So +porting (as a cross-assembler) to hosts not yet supported should be fairly +easy. Porting to a new target shouldn't be too tough if it's a variant of one +already supported. + +Native assembling should work on: + + sun3 + sun4 + 386bsd + bsd/386 + delta (m68k-sysv from Motorola) + delta88 (m88k-sysv from Motorola) + GNU/linux + m68k hpux 8.0 (hpux 7.0 may be a problem) + vax bsd, ultrix, vms + hp9000s300 + decstation + irix 4 + irix 5 + miniframe (m68k-sysv from Convergent Technologies) + i386-aix (ps/2) + hppa (hpux 4.3bsd, osf1) + AIX + unixware + sco 3.2v4.2 + sco openserver 5.0 (a.k.a. 3.2v5.0 ) + sparc solaris + +I believe that gas as a cross-assembler can currently be targetted for +most of the above hosts, plus + + decstation-bsd (a.out format, to be used in BSD 4.4) + ebmon29k + go32 (DOS on i386, with DJGPP -- old a.out version) + h8/300, h8/500 (Hitachi) + i386-aix (ps/2) + i960-coff + mips ecoff (decstation-ultrix, iris, mips magnum, mips-idt-ecoff) + nindy960 + powerpc EABI + SH (Hitachi) + sco386 + vax bsd or ultrix? + vms + vxworks68k + vxworks960 + z8000 (Zilog) + +MIPS ECOFF support has been added, but GAS will not run a C-style +preprocessor. If you want that, rename your file to have a ".S" suffix, and +run gcc on it. Or run "gcc -xassembler-with-cpp foo.s". + +Support for ELF should work now for sparc, hppa, i386, alpha, m68k, +MIPS, powerpc. + +Support for ns32k, tahoe, i860, m88k may be suffering from bitrot. + +If you try out gas on some host or target not listed above, please let me know +the results, so I can update the list. + +Compiler Support Hacks +====================== + +On a few targets, the assembler has been modified to support a feature +that is potentially useful when assembling compiler output, but which +may confuse assembly language programmers. If assembler encounters a +.word pseudo-op of the form symbol1-symbol2 (the difference of two +symbols), and the difference of those two symbols will not fit in 16 +bits, the assembler will create a branch around a long jump to +symbol1, and insert this into the output directly before the next +label: The .word will (instead of containing garbage, or giving an +error message) contain (the address of the long jump)-symbol2. This +allows the assembler to assemble jump tables that jump to locations +very far away into code that works properly. If the next label is +more than 32K away from the .word, you lose (silently); RMS claims +this will never happen. If the -K option is given, you will get a +warning message when this happens. + + +REPORTING BUGS IN GAS +===================== + +Bugs in gas should be reported to bug-gnu-utils@prep.ai.mit.edu. They may be +cross-posted to bug-gcc if they affect the use of gas with gcc. They should +not be reported just to bug-gcc, since I don't read that list, and therefore +wouldn't see them. + +If you report a bug in GAS, please remember to include: + +A description of exactly what went wrong, and exactly what should have +happened instead. + +The type of machine (VAX, 68020, etc) and operating system (BSD, SunOS, DYNIX, +VMS, etc) GAS was running on. + +The configuration name(s) given to the "configure" script. The +"config.status" file should have this information. + +The options given to GAS at run time. + +The actual input file that caused the problem. + +It is silly to report a bug in GAS without including an input file for GAS. +Don't ask us to generate the file just because you made it from files you +think we have access to. + +1. You might be mistaken. +2. It might take us a lot of time to install things to regenerate that file. +3. We might get a different file from the one you got, and might not see any + bug. + +To save us these delays and uncertainties, always send the input file for the +program that failed. A smaller test case that demonstrates the problem is of +course preferable, but be sure it is a complete input file, and that it really +does demonstrate the problem; but if paring it down would cause large delays +in filing the bug report, don't bother. + +If the input file is very large, and you are on the internet, you may want to +make it avaliable for anonymous FTP instead of mailing it. If you do, include +instructions for FTP'ing it in your bug report. + +If you expect to be contributing a large number of test cases, it would be +helpful if you would look at the test suite included in the release (based on +the Deja Gnu testing framework, available from the usual ftp sites) and write +test cases to fit into that framework. This is certainly not required. diff --git a/contrib/binutils/gas/acconfig.h b/contrib/binutils/gas/acconfig.h new file mode 100644 index 0000000..d2ca454 --- /dev/null +++ b/contrib/binutils/gas/acconfig.h @@ -0,0 +1,61 @@ +/* Should gas use high-level BFD interfaces? */ +#undef BFD_ASSEMBLER + +/* Some assert/preprocessor combinations are incapable of handling + certain kinds of constructs in the argument of assert. For example, + quoted strings (if requoting isn't done right) or newlines. */ +#undef BROKEN_ASSERT + +/* If we aren't doing cross-assembling, some operations can be optimized, + since byte orders and value sizes don't need to be adjusted. */ +#undef CROSS_COMPILE + +/* Some gas code wants to know these parameters. */ +#undef TARGET_ALIAS +#undef TARGET_CPU +#undef TARGET_CANONICAL +#undef TARGET_OS +#undef TARGET_VENDOR + +/* Sometimes the system header files don't declare strstr. */ +#undef NEED_DECLARATION_STRSTR + +/* Sometimes the system header files don't declare malloc and realloc. */ +#undef NEED_DECLARATION_MALLOC + +/* Sometimes the system header files don't declare free. */ +#undef NEED_DECLARATION_FREE + +/* Sometimes the system header files don't declare sbrk. */ +#undef NEED_DECLARATION_SBRK + +/* Sometimes errno.h doesn't declare errno itself. */ +#undef NEED_DECLARATION_ERRNO + +#undef MANY_SEGMENTS + +/* Needed only for sparc configuration. */ +#undef SPARC_V9 +#undef SPARC_ARCH64 + +/* Needed only for some configurations that can produce multiple output + formats. */ +#undef DEFAULT_EMULATION +#undef EMULATIONS +#undef USE_EMULATIONS +#undef OBJ_MAYBE_AOUT +#undef OBJ_MAYBE_BOUT +#undef OBJ_MAYBE_COFF +#undef OBJ_MAYBE_ECOFF +#undef OBJ_MAYBE_ELF +#undef OBJ_MAYBE_GENERIC +#undef OBJ_MAYBE_HP300 +#undef OBJ_MAYBE_IEEE +#undef OBJ_MAYBE_SOM +#undef OBJ_MAYBE_VMS + +/* Used for some of the COFF configurations, when the COFF code needs + to select something based on the CPU type before it knows it... */ +#undef I386COFF +#undef M68KCOFF +#undef M88KCOFF diff --git a/contrib/binutils/gas/aclocal.m4 b/contrib/binutils/gas/aclocal.m4 new file mode 100644 index 0000000..60f54e9 --- /dev/null +++ b/contrib/binutils/gas/aclocal.m4 @@ -0,0 +1,58 @@ +dnl GAS_CHECK_DECL_NEEDED(name, typedefname, typedef, headers) +AC_DEFUN(GAS_CHECK_DECL_NEEDED,[ +AC_MSG_CHECKING(whether declaration is required for $1) +AC_CACHE_VAL(gas_cv_decl_needed_$1, +AC_TRY_LINK([$4], +[ +typedef $3; +$2 x; +x = ($2) $1; +], gas_cv_decl_needed_$1=no, gas_cv_decl_needed_$1=yes))dnl +AC_MSG_RESULT($gas_cv_decl_needed_$1) +test $gas_cv_decl_needed_$1 = no || { + ifelse(index($1,[$]),-1, + [AC_DEFINE([NEED_DECLARATION_]translit($1, [a-z], [A-Z]))], + [gas_decl_name_upcase=`echo $1 | tr '[a-z]' '[A-Z]'` + AC_DEFINE_UNQUOTED(NEED_DECLARATION_$gas_decl_name_upcase)]) +} +])dnl +dnl +dnl Some non-ANSI preprocessors botch requoting inside strings. That's bad +dnl enough, but on some of those systems, the assert macro relies on requoting +dnl working properly! +dnl GAS_WORKING_ASSERT +AC_DEFUN(GAS_WORKING_ASSERT, +[AC_MSG_CHECKING([for working assert macro]) +AC_CACHE_VAL(gas_cv_assert_ok, +AC_TRY_LINK([#include <assert.h> +#include <stdio.h>], [ +/* check for requoting problems */ +static int a, b, c, d; +static char *s; +assert (!strcmp(s, "foo bar baz quux")); +/* check for newline handling */ +assert (a == b + || c == d); +], gas_cv_assert_ok=yes, gas_cv_assert_ok=no))dnl +AC_MSG_RESULT($gas_cv_assert_ok) +test $gas_cv_assert_ok = yes || AC_DEFINE(BROKEN_ASSERT) +])dnl +dnl +dnl Since many Bourne shell implementations lack subroutines, use this +dnl hack to simplify the code in configure.in. +dnl GAS_UNIQ(listvar) +AC_DEFUN(GAS_UNIQ, +[_gas_uniq_list="[$]$1" +_gas_uniq_newlist="" +dnl Protect against empty input list. +for _gas_uniq_i in _gas_uniq_dummy [$]_gas_uniq_list ; do + case [$]_gas_uniq_i in + _gas_uniq_dummy) ;; + *) case " [$]_gas_uniq_newlist " in + *" [$]_gas_uniq_i "*) ;; + *) _gas_uniq_newlist="[$]_gas_uniq_newlist [$]_gas_uniq_i" ;; + esac ;; + esac +done +$1=[$]_gas_uniq_newlist +])dnl diff --git a/contrib/binutils/gas/app.c b/contrib/binutils/gas/app.c new file mode 100644 index 0000000..a2551c6 --- /dev/null +++ b/contrib/binutils/gas/app.c @@ -0,0 +1,1104 @@ +/* This is the Assembler Pre-Processor + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 */ +/* App, the assembler pre-processor. This pre-processor strips out excess + spaces, turns single-quoted characters into a decimal constant, and turns + # <number> <filename> <garbage> into a .line <number>\n.file <filename> + pair. This needs better error-handling. */ + +#include <stdio.h> +#include "as.h" /* For BAD_CASE() only */ + +#if (__STDC__ != 1) +#ifndef const +#define const /* empty */ +#endif +#endif + +/* Whether we are scrubbing in m68k MRI mode. This is different from + flag_m68k_mri, because the two flags will be affected by the .mri + pseudo-op at different times. */ +static int scrub_m68k_mri; + +/* The pseudo-op which switches in and out of MRI mode. See the + comment in do_scrub_chars. */ +static const char mri_pseudo[] = ".mri 0"; + +static char lex[256]; +static const char symbol_chars[] = +"$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +#define LEX_IS_SYMBOL_COMPONENT 1 +#define LEX_IS_WHITESPACE 2 +#define LEX_IS_LINE_SEPARATOR 3 +#define LEX_IS_COMMENT_START 4 +#define LEX_IS_LINE_COMMENT_START 5 +#define LEX_IS_TWOCHAR_COMMENT_1ST 6 +#define LEX_IS_STRINGQUOTE 8 +#define LEX_IS_COLON 9 +#define LEX_IS_NEWLINE 10 +#define LEX_IS_ONECHAR_QUOTE 11 +#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT) +#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE) +#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR) +#define IS_COMMENT(c) (lex[c] == LEX_IS_COMMENT_START) +#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START) +#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE) + +static int process_escape PARAMS ((int)); + +/* FIXME-soon: The entire lexer/parser thingy should be + built statically at compile time rather than dynamically + each and every time the assembler is run. xoxorich. */ + +void +do_scrub_begin (m68k_mri) + int m68k_mri; +{ + const char *p; + + scrub_m68k_mri = m68k_mri; + + lex[' '] = LEX_IS_WHITESPACE; + lex['\t'] = LEX_IS_WHITESPACE; + lex['\n'] = LEX_IS_NEWLINE; + lex[';'] = LEX_IS_LINE_SEPARATOR; + lex[':'] = LEX_IS_COLON; + + if (! m68k_mri) + { + lex['"'] = LEX_IS_STRINGQUOTE; + +#ifndef TC_HPPA + lex['\''] = LEX_IS_ONECHAR_QUOTE; +#endif + +#ifdef SINGLE_QUOTE_STRINGS + lex['\''] = LEX_IS_STRINGQUOTE; +#endif + } + + /* Note: if any other character can be LEX_IS_STRINGQUOTE, the loop + in state 5 of do_scrub_chars must be changed. */ + + /* Note that these override the previous defaults, e.g. if ';' is a + comment char, then it isn't a line separator. */ + for (p = symbol_chars; *p; ++p) + { + lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT; + } /* declare symbol characters */ + + /* The m68k backend wants to be able to change comment_chars. */ +#ifndef tc_comment_chars +#define tc_comment_chars comment_chars +#endif + for (p = tc_comment_chars; *p; p++) + { + lex[(unsigned char) *p] = LEX_IS_COMMENT_START; + } /* declare comment chars */ + + for (p = line_comment_chars; *p; p++) + { + lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START; + } /* declare line comment chars */ + + for (p = line_separator_chars; *p; p++) + { + lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR; + } /* declare line separators */ + + /* Only allow slash-star comments if slash is not in use. + FIXME: This isn't right. We should always permit them. */ + if (lex['/'] == 0) + { + lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST; + } + + if (m68k_mri) + { + lex['\''] = LEX_IS_STRINGQUOTE; + lex[';'] = LEX_IS_COMMENT_START; + lex['*'] = LEX_IS_LINE_COMMENT_START; + /* The MRI documentation says '!' is LEX_IS_COMMENT_START, but + then it can't be used in an expression. */ + lex['!'] = LEX_IS_LINE_COMMENT_START; + } +} /* do_scrub_begin() */ + +/* Saved state of the scrubber */ +static int state; +static int old_state; +static char *out_string; +static char out_buf[20]; +static int add_newlines; +static char *saved_input; +static int saved_input_len; +static const char *mri_state; +static char mri_last_ch; + +/* Data structure for saving the state of app across #include's. Note that + app is called asynchronously to the parsing of the .include's, so our + state at the time .include is interpreted is completely unrelated. + That's why we have to save it all. */ + +struct app_save + { + int state; + int old_state; + char *out_string; + char out_buf[sizeof (out_buf)]; + int add_newlines; + char *saved_input; + int saved_input_len; + int scrub_m68k_mri; + const char *mri_state; + char mri_last_ch; + }; + +char * +app_push () +{ + register struct app_save *saved; + + saved = (struct app_save *) xmalloc (sizeof (*saved)); + saved->state = state; + saved->old_state = old_state; + saved->out_string = out_string; + memcpy (saved->out_buf, out_buf, sizeof (out_buf)); + saved->add_newlines = add_newlines; + saved->saved_input = saved_input; + saved->saved_input_len = saved_input_len; + saved->scrub_m68k_mri = scrub_m68k_mri; + saved->mri_state = mri_state; + saved->mri_last_ch = mri_last_ch; + + /* do_scrub_begin() is not useful, just wastes time. */ + + state = 0; + saved_input = NULL; + + return (char *) saved; +} + +void +app_pop (arg) + char *arg; +{ + register struct app_save *saved = (struct app_save *) arg; + + /* There is no do_scrub_end (). */ + state = saved->state; + old_state = saved->old_state; + out_string = saved->out_string; + memcpy (out_buf, saved->out_buf, sizeof (out_buf)); + add_newlines = saved->add_newlines; + saved_input = saved->saved_input; + saved_input_len = saved->saved_input_len; + scrub_m68k_mri = saved->scrub_m68k_mri; + mri_state = saved->mri_state; + mri_last_ch = saved->mri_last_ch; + + free (arg); +} /* app_pop() */ + +/* @@ This assumes that \n &c are the same on host and target. This is not + necessarily true. */ +static int +process_escape (ch) + int ch; +{ + switch (ch) + { + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case '\'': + return '\''; + case '"': + return '\"'; + default: + return ch; + } +} + +/* This function is called to process input characters. The GET + parameter is used to retrieve more input characters. GET should + set its parameter to point to a buffer, and return the length of + the buffer; it should return 0 at end of file. The scrubbed output + characters are put into the buffer starting at TOSTART; the TOSTART + buffer is TOLEN bytes in length. The function returns the number + of scrubbed characters put into TOSTART. This will be TOLEN unless + end of file was seen. This function is arranged as a state + machine, and saves its state so that it may return at any point. + This is the way the old code used to work. */ + +int +do_scrub_chars (get, tostart, tolen) + int (*get) PARAMS ((char **)); + char *tostart; + int tolen; +{ + char *to = tostart; + char *toend = tostart + tolen; + char *from; + char *fromend; + int fromlen; + register int ch, ch2 = 0; + + /*State 0: beginning of normal line + 1: After first whitespace on line (flush more white) + 2: After first non-white (opcode) on line (keep 1white) + 3: after second white on line (into operands) (flush white) + 4: after putting out a .line, put out digits + 5: parsing a string, then go to old-state + 6: putting out \ escape in a "d string. + 7: After putting out a .appfile, put out string. + 8: After putting out a .appfile string, flush until newline. + 9: After seeing symbol char in state 3 (keep 1white after symchar) + 10: After seeing whitespace in state 9 (keep white before symchar) + 11: After seeing a symbol character in state 0 (eg a label definition) + -1: output string in out_string and go to the state in old_state + -2: flush text until a '*' '/' is seen, then go to state old_state + */ + + /* I added states 9 and 10 because the MIPS ECOFF assembler uses + constructs like ``.loc 1 20''. This was turning into ``.loc + 120''. States 9 and 10 ensure that a space is never dropped in + between characters which could appear in a identifier. Ian + Taylor, ian@cygnus.com. + + I added state 11 so that something like "Lfoo add %r25,%r26,%r27" works + correctly on the PA (and any other target where colons are optional). + Jeff Law, law@cs.utah.edu. */ + + /* This macro gets the next input character. */ + +#define GET() \ + (from < fromend \ + ? *from++ \ + : ((saved_input != NULL \ + ? (free (saved_input), \ + saved_input = NULL, \ + 0) \ + : 0), \ + fromlen = (*get) (&from), \ + fromend = from + fromlen, \ + (fromlen == 0 \ + ? EOF \ + : *from++))) + + /* This macro pushes a character back on the input stream. */ + +#define UNGET(uch) (*--from = (uch)) + + /* This macro puts a character into the output buffer. If this + character fills the output buffer, this macro jumps to the label + TOFULL. We use this rather ugly approach because we need to + handle two different termination conditions: EOF on the input + stream, and a full output buffer. It would be simpler if we + always read in the entire input stream before processing it, but + I don't want to make such a significant change to the assembler's + memory usage. */ + +#define PUT(pch) \ + do \ + { \ + *to++ = (pch); \ + if (to >= toend) \ + goto tofull; \ + } \ + while (0) + + if (saved_input != NULL) + { + from = saved_input; + fromend = from + saved_input_len; + } + else + { + fromlen = (*get) (&from); + if (fromlen == 0) + return 0; + fromend = from + fromlen; + } + + while (1) + { + /* The cases in this switch end with continue, in order to + branch back to the top of this while loop and generate the + next output character in the appropriate state. */ + switch (state) + { + case -1: + ch = *out_string++; + if (*out_string == '\0') + { + state = old_state; + old_state = 3; + } + PUT (ch); + continue; + + case -2: + for (;;) + { + do + { + ch = GET (); + + if (ch == EOF) + { + as_warn ("end of file in comment"); + goto fromeof; + } + + if (ch == '\n') + PUT ('\n'); + } + while (ch != '*'); + + while ((ch = GET ()) == '*') + ; + + if (ch == EOF) + { + as_warn ("end of file in comment"); + goto fromeof; + } + + if (ch == '/') + break; + + UNGET (ch); + } + + state = old_state; + UNGET (' '); + continue; + + case 4: + ch = GET (); + if (ch == EOF) + goto fromeof; + else if (ch >= '0' && ch <= '9') + PUT (ch); + else + { + while (ch != EOF && IS_WHITESPACE (ch)) + ch = GET (); + if (ch == '"') + { + UNGET (ch); + if (scrub_m68k_mri) + out_string = "\n\tappfile "; + else + out_string = "\n\t.appfile "; + old_state = 7; + state = -1; + PUT (*out_string++); + } + else + { + while (ch != EOF && ch != '\n') + ch = GET (); + state = 0; + PUT (ch); + } + } + continue; + + case 5: + /* We are going to copy everything up to a quote character, + with special handling for a backslash. We try to + optimize the copying in the simple case without using the + GET and PUT macros. */ + { + char *s; + int len; + + for (s = from; s < fromend; s++) + { + ch = *s; + /* This condition must be changed if the type of any + other character can be LEX_IS_STRINGQUOTE. */ + if (ch == '\\' + || ch == '"' + || ch == '\'' + || ch == '\n') + break; + } + len = s - from; + if (len > toend - to) + len = toend - to; + if (len > 0) + { + memcpy (to, from, len); + to += len; + from += len; + } + } + + ch = GET (); + if (ch == EOF) + { + as_warn ("end of file in string: inserted '\"'"); + state = old_state; + UNGET ('\n'); + PUT ('"'); + } + else if (lex[ch] == LEX_IS_STRINGQUOTE) + { + state = old_state; + PUT (ch); + } +#ifndef NO_STRING_ESCAPES + else if (ch == '\\') + { + state = 6; + PUT (ch); + } +#endif + else if (scrub_m68k_mri && ch == '\n') + { + /* Just quietly terminate the string. This permits lines like + bne label loop if we haven't reach end yet + */ + state = old_state; + UNGET (ch); + PUT ('\''); + } + else + { + PUT (ch); + } + continue; + + case 6: + state = 5; + ch = GET (); + switch (ch) + { + /* Handle strings broken across lines, by turning '\n' into + '\\' and 'n'. */ + case '\n': + UNGET ('n'); + add_newlines++; + PUT ('\\'); + continue; + + case '"': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + case 'x': + case 'X': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; +#if defined(IGNORE_NONSTANDARD_ESCAPES) | defined(ONLY_STANDARD_ESCAPES) + default: + as_warn ("Unknown escape '\\%c' in string: Ignored", ch); + break; +#else /* ONLY_STANDARD_ESCAPES */ + default: + /* Accept \x as x for any x */ + break; +#endif /* ONLY_STANDARD_ESCAPES */ + + case EOF: + as_warn ("End of file in string: '\"' inserted"); + PUT ('"'); + continue; + } + PUT (ch); + continue; + + case 7: + ch = GET (); + state = 5; + old_state = 8; + if (ch == EOF) + goto fromeof; + PUT (ch); + continue; + + case 8: + do + ch = GET (); + while (ch != '\n' && ch != EOF); + if (ch == EOF) + goto fromeof; + state = 0; + PUT (ch); + continue; + } + + /* OK, we are somewhere in states 0 through 4 or 9 through 11 */ + + /* flushchar: */ + ch = GET (); + + recycle: + +#ifdef TC_M68K + /* We want to have pseudo-ops which control whether we are in + MRI mode or not. Unfortunately, since m68k MRI mode affects + the scrubber, that means that we need a special purpose + recognizer here. */ + if (mri_state == NULL) + { + if ((state == 0 || state == 1) + && ch == mri_pseudo[0]) + mri_state = mri_pseudo + 1; + } + else + { + /* We advance to the next state if we find the right + character, or if we need a space character and we get any + whitespace character, or if we need a '0' and we get a + '1' (this is so that we only need one state to handle + ``.mri 0'' and ``.mri 1''). */ + if (ch != '\0' + && (*mri_state == ch + || (*mri_state == ' ' + && lex[ch] == LEX_IS_WHITESPACE) + || (*mri_state == '0' + && ch == '1'))) + { + mri_last_ch = ch; + ++mri_state; + } + else if (*mri_state != '\0' + || (lex[ch] != LEX_IS_WHITESPACE + && lex[ch] != LEX_IS_NEWLINE)) + { + /* We did not get the expected character, or we didn't + get a valid terminating character after seeing the + entire pseudo-op, so we must go back to the + beginning. */ + mri_state = NULL; + } + else + { + /* We've read the entire pseudo-op. mips_last_ch is + either '0' or '1' indicating whether to enter or + leave MRI mode. */ + do_scrub_begin (mri_last_ch == '1'); + + /* We continue handling the character as usual. The + main gas reader must also handle the .mri pseudo-op + to control expression parsing and the like. */ + } + } +#endif + + if (ch == EOF) + { + if (state != 0) + { + as_warn ("end of file not at end of a line; newline inserted"); + state = 0; + PUT ('\n'); + } + goto fromeof; + } + + switch (lex[ch]) + { + case LEX_IS_WHITESPACE: + do + { + ch = GET (); + } + while (ch != EOF && IS_WHITESPACE (ch)); + if (ch == EOF) + goto fromeof; + + if (state == 0) + { + /* Preserve a single whitespace character at the + beginning of a line. */ + state = 1; + UNGET (ch); + PUT (' '); + break; + } + + if (IS_COMMENT (ch) + || ch == '/' + || IS_LINE_SEPARATOR (ch)) + { + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + UNGET (ch); + PUT (' '); + break; + } + goto recycle; + } + + /* If we're in state 2 or 11, we've seen a non-white + character followed by whitespace. If the next character + is ':', this is whitespace after a label name which we + normally must ignore. In MRI mode, though, spaces are + not permitted between the label and the colon. */ + if ((state == 2 || state == 11) + && lex[ch] == LEX_IS_COLON + && ! scrub_m68k_mri) + { + state = 1; + PUT (ch); + break; + } + + switch (state) + { + case 0: + state++; + goto recycle; /* Punted leading sp */ + case 1: + /* We can arrive here if we leave a leading whitespace + character at the beginning of a line. */ + goto recycle; + case 2: + state = 3; + if (to + 1 < toend) + { + /* Optimize common case by skipping UNGET/GET. */ + PUT (' '); /* Sp after opco */ + goto recycle; + } + UNGET (ch); + PUT (' '); + break; + case 3: + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + UNGET (ch); + PUT (' '); + break; + } + goto recycle; /* Sp in operands */ + case 9: + case 10: + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + state = 3; + UNGET (ch); + PUT (' '); + break; + } + state = 10; /* Sp after symbol char */ + goto recycle; + case 11: + if (flag_m68k_mri +#ifdef LABELS_WITHOUT_COLONS + || 1 +#endif + ) + state = 1; + else + { + /* We know that ch is not ':', since we tested that + case above. Therefore this is not a label, so it + must be the opcode, and we've just seen the + whitespace after it. */ + state = 3; + } + UNGET (ch); + PUT (' '); /* Sp after label definition. */ + break; + default: + BAD_CASE (state); + } + break; + + case LEX_IS_TWOCHAR_COMMENT_1ST: + ch2 = GET (); + if (ch2 == '*') + { + for (;;) + { + do + { + ch2 = GET (); + if (ch2 != EOF && IS_NEWLINE (ch2)) + add_newlines++; + } + while (ch2 != EOF && ch2 != '*'); + + while (ch2 == '*') + ch2 = GET (); + + if (ch2 == EOF || ch2 == '/') + break; + + /* This UNGET will ensure that we count newlines + correctly. */ + UNGET (ch2); + } + + if (ch2 == EOF) + as_warn ("end of file in multiline comment"); + + ch = ' '; + goto recycle; + } + else + { + if (ch2 != EOF) + UNGET (ch2); + if (state == 9 || state == 10) + state = 3; + PUT (ch); + } + break; + + case LEX_IS_STRINGQUOTE: + if (state == 10) + { + /* Preserve the whitespace in foo "bar" */ + UNGET (ch); + state = 3; + PUT (' '); + + /* PUT didn't jump out. We could just break, but we + know what will happen, so optimize a bit. */ + ch = GET (); + old_state = 3; + } + else if (state == 9) + old_state = 3; + else + old_state = state; + state = 5; + PUT (ch); + break; + +#ifndef IEEE_STYLE + case LEX_IS_ONECHAR_QUOTE: + if (state == 10) + { + /* Preserve the whitespace in foo 'b' */ + UNGET (ch); + state = 3; + PUT (' '); + break; + } + ch = GET (); + if (ch == EOF) + { + as_warn ("end of file after a one-character quote; \\0 inserted"); + ch = 0; + } + if (ch == '\\') + { + ch = GET (); + if (ch == EOF) + { + as_warn ("end of file in escape character"); + ch = '\\'; + } + else + ch = process_escape (ch); + } + sprintf (out_buf, "%d", (int) (unsigned char) ch); + + /* None of these 'x constants for us. We want 'x'. */ + if ((ch = GET ()) != '\'') + { +#ifdef REQUIRE_CHAR_CLOSE_QUOTE + as_warn ("Missing close quote: (assumed)"); +#else + if (ch != EOF) + UNGET (ch); +#endif + } + if (strlen (out_buf) == 1) + { + PUT (out_buf[0]); + break; + } + if (state == 9) + old_state = 3; + else + old_state = state; + state = -1; + out_string = out_buf; + PUT (*out_string++); + break; +#endif + + case LEX_IS_COLON: + if (state == 9 || state == 10) + state = 3; + else if (state != 3) + state = 1; + PUT (ch); + break; + + case LEX_IS_NEWLINE: + /* Roll out a bunch of newlines from inside comments, etc. */ + if (add_newlines) + { + --add_newlines; + UNGET (ch); + } + /* fall thru into... */ + + case LEX_IS_LINE_SEPARATOR: + state = 0; + PUT (ch); + break; + + case LEX_IS_LINE_COMMENT_START: + /* FIXME-someday: The two character comment stuff was badly + thought out. On i386, we want '/' as line comment start + AND we want C style comments. hence this hack. The + whole lexical process should be reworked. xoxorich. */ + if (ch == '/') + { + ch2 = GET (); + if (ch2 == '*') + { + old_state = 3; + state = -2; + break; + } + else + { + UNGET (ch2); + } + } /* bad hack */ + + if (state == 0 || state == 1) /* Only comment at start of line. */ + { + int startch; + + startch = ch; + + do + { + ch = GET (); + } + while (ch != EOF && IS_WHITESPACE (ch)); + if (ch == EOF) + { + as_warn ("end of file in comment; newline inserted"); + PUT ('\n'); + break; + } + if (ch < '0' || ch > '9' || state != 0 || startch != '#') + { + /* Not a cpp line. */ + while (ch != EOF && !IS_NEWLINE (ch)) + ch = GET (); + if (ch == EOF) + as_warn ("EOF in Comment: Newline inserted"); + state = 0; + PUT ('\n'); + break; + } + /* Loks like `# 123 "filename"' from cpp. */ + UNGET (ch); + old_state = 4; + state = -1; + if (scrub_m68k_mri) + out_string = "\tappline "; + else + out_string = "\t.appline "; + PUT (*out_string++); + break; + } + + /* We have a line comment character which is not at the + start of a line. If this is also a normal comment + character, fall through. Otherwise treat it as a default + character. */ + if (strchr (tc_comment_chars, ch) == NULL + && (! scrub_m68k_mri + || (ch != '!' && ch != '*'))) + goto de_fault; + if (scrub_m68k_mri + && (ch == '!' || ch == '*' || ch == '#') + && state != 1 + && state != 10) + goto de_fault; + /* Fall through. */ + case LEX_IS_COMMENT_START: + do + { + ch = GET (); + } + while (ch != EOF && !IS_NEWLINE (ch)); + if (ch == EOF) + as_warn ("end of file in comment; newline inserted"); + state = 0; + PUT ('\n'); + break; + + case LEX_IS_SYMBOL_COMPONENT: + if (state == 10) + { + /* This is a symbol character following another symbol + character, with whitespace in between. We skipped + the whitespace earlier, so output it now. */ + UNGET (ch); + state = 3; + PUT (' '); + break; + } + + if (state == 3) + state = 9; + + /* This is a common case. Quickly copy CH and all the + following symbol component or normal characters. */ + if (to + 1 < toend && mri_state == NULL) + { + char *s; + int len; + + for (s = from; s < fromend; s++) + { + int type; + + ch2 = *s; + type = lex[ch2]; + if (type != 0 + && type != LEX_IS_SYMBOL_COMPONENT) + break; + } + if (s > from) + { + /* Handle the last character normally, for + simplicity. */ + --s; + } + len = s - from; + if (len > (toend - to) - 1) + len = (toend - to) - 1; + if (len > 0) + { + PUT (ch); + if (len > 8) + { + memcpy (to, from, len); + to += len; + from += len; + } + else + { + switch (len) + { + case 8: *to++ = *from++; + case 7: *to++ = *from++; + case 6: *to++ = *from++; + case 5: *to++ = *from++; + case 4: *to++ = *from++; + case 3: *to++ = *from++; + case 2: *to++ = *from++; + case 1: *to++ = *from++; + } + } + ch = GET (); + } + } + + /* Fall through. */ + default: + de_fault: + /* Some relatively `normal' character. */ + if (state == 0) + { + state = 11; /* Now seeing label definition */ + } + else if (state == 1) + { + state = 2; /* Ditto */ + } + else if (state == 9) + { + if (lex[ch] != LEX_IS_SYMBOL_COMPONENT) + state = 3; + } + else if (state == 10) + { + state = 3; + } + PUT (ch); + break; + } + } + + /*NOTREACHED*/ + + fromeof: + /* We have reached the end of the input. */ + return to - tostart; + + tofull: + /* The output buffer is full. Save any input we have not yet + processed. */ + if (fromend > from) + { + char *save; + + save = (char *) xmalloc (fromend - from); + memcpy (save, from, fromend - from); + if (saved_input != NULL) + free (saved_input); + saved_input = save; + saved_input_len = fromend - from; + } + else + { + if (saved_input != NULL) + { + free (saved_input); + saved_input = NULL; + } + } + return to - tostart; +} + +/* end of app.c */ diff --git a/contrib/binutils/gas/as.c b/contrib/binutils/gas/as.c new file mode 100644 index 0000000..e1929e6 --- /dev/null +++ b/contrib/binutils/gas/as.c @@ -0,0 +1,906 @@ +/* as.c - GAS main program. + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * Main program for AS; a 32-bit assembler of GNU. + * Understands command arguments. + * Has a few routines that don't fit in other modules because they + * are shared. + * + * + * bugs + * + * : initialisers + * Since no-one else says they will support them in future: I + * don't support them now. + * + */ + +#include "ansidecl.h" + +#define COMMON + +#include "as.h" +#include "subsegs.h" +#include "output-file.h" +#include "sb.h" +#include "macro.h" +#ifndef HAVE_ITBL_CPU +#define itbl_parse(itbl_file) 1 +#define itbl_init() +#endif + +#ifdef HAVE_SBRK +#ifdef NEED_DECLARATION_SBRK +extern PTR sbrk (); +#endif +#endif + +static void show_usage PARAMS ((FILE *)); +static void parse_args PARAMS ((int *, char ***)); +static void dump_statistics PARAMS ((void)); +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 () +{ + static int printed; + if (printed) + return; + printed = 1; + + fprintf (stderr, "GNU assembler version %s (%s)", GAS_VERSION, TARGET_ALIAS); +#ifdef BFD_ASSEMBLER + fprintf (stderr, ", using BFD version %s", BFD_VERSION); +#endif + fprintf (stderr, "\n"); +} + +static void +show_usage (stream) + FILE *stream; +{ + fprintf (stream, "Usage: %s [option...] [asmfile...]\n", myname); + + fprintf (stream, "\ +Options:\n\ +-a[sub-option...] turn on listings\n\ + Sub-options [default hls]:\n\ + c omit false conditionals\n\ + d omit debugging directives\n\ + h include high-level source\n\ + l include assembly\n\ + n omit forms processing\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\ +-J don't warn about signed overflow\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 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 +#define EMULATION_ENVIRON "AS_EMULATION" + +extern struct emulation mipsbelf, mipslelf, mipself; +extern struct emulation mipsbecoff, mipslecoff, mipsecoff; +extern struct emulation i386coff, i386elf; + +static struct emulation *const emulations[] = { EMULATIONS }; +static const int n_emulations = sizeof (emulations) / sizeof (emulations[0]); + +static void select_emulation_mode PARAMS ((int, char **)); + +static void +select_emulation_mode (argc, argv) + int argc; + char **argv; +{ + int i; + char *p, *em = 0; + + for (i = 1; i < argc; i++) + if (!strncmp ("--em", argv[i], 4)) + break; + + if (i == argc) + goto do_default; + + p = strchr (argv[i], '='); + if (p) + p++; + else + p = argv[i+1]; + + if (!p || !*p) + as_fatal ("missing emulation mode name"); + em = p; + + do_default: + if (em == 0) + em = getenv (EMULATION_ENVIRON); + if (em == 0) + em = DEFAULT_EMULATION; + + if (em) + { + for (i = 0; i < n_emulations; i++) + if (!strcmp (emulations[i]->name, em)) + break; + if (i == n_emulations) + as_fatal ("unrecognized emulation name `%s'", em); + this_emulation = emulations[i]; + } + else + this_emulation = emulations[0]; + + this_emulation->init (); +} + +const char * +default_emul_bfd_name () +{ + abort (); + return NULL; +} + +void +common_emul_init () +{ + this_format = this_emulation->format; + + if (this_emulation->leading_underscore == 2) + this_emulation->leading_underscore = this_format->dfl_leading_underscore; + + if (this_emulation->default_endian != 2) + target_big_endian = this_emulation->default_endian; + + if (this_emulation->fake_label_name == 0) + { + if (this_emulation->leading_underscore) + this_emulation->fake_label_name = "L0\001"; + else + /* What other parameters should we test? */ + this_emulation->fake_label_name = ".L0\001"; + } +} +#endif + +/* + * Since it is easy to do here we interpret the special arg "-" + * to mean "use stdin" and we set that argv[] pointing to "". + * After we have munged argv[], the only things left are source file + * name(s) and ""(s) denoting stdin. These file names are used + * (perhaps more than once) later. + * + * check for new machine-dep cmdline options in + * md_parse_option definitions in config/tc-*.c + */ + +static void +parse_args (pargc, pargv) + int *pargc; + char ***pargv; +{ + int old_argc, new_argc; + char **old_argv, **new_argv; + + /* Starting the short option string with '-' is for programs that + expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. */ + + char *shortopts; + extern CONST char *md_shortopts; + 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) + {"statistics", no_argument, NULL, OPTION_STATISTICS}, +#define OPTION_VERSION (OPTION_STD_BASE + 3) + {"version", no_argument, NULL, OPTION_VERSION}, +#define OPTION_DUMPCONFIG (OPTION_STD_BASE + 4) + {"dump-config", no_argument, NULL, OPTION_DUMPCONFIG}, +#define OPTION_VERBOSE (OPTION_STD_BASE + 5) + {"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 + target dependent list. */ + shortopts = concat (std_shortopts, md_shortopts, (char *) NULL); + longopts = (struct option *) xmalloc (sizeof (std_longopts) + md_longopts_size); + memcpy (longopts, std_longopts, sizeof (std_longopts)); + memcpy ((char *) longopts + sizeof (std_longopts), + md_longopts, md_longopts_size); + + /* Make a local copy of the old argv. */ + old_argc = *pargc; + old_argv = *pargv; + + /* Initialize a new argv that contains no options. */ + new_argv = (char **) xmalloc (sizeof (char *) * (old_argc + 1)); + new_argv[0] = old_argv[0]; + new_argc = 1; + new_argv[new_argc] = NULL; + + while (1) + { + /* getopt_long_only is like getopt_long, but '-' as well as '--' can + indicate a long option. */ + int longind; + int optc = getopt_long_only (old_argc, old_argv, shortopts, longopts, + &longind); + + if (optc == -1) + break; + + switch (optc) + { + default: + /* md_parse_option should return 1 if it recognizes optc, + 0 if not. */ + if (md_parse_option (optc, optarg) != 0) + break; + /* `-v' isn't included in the general short_opts list, so check for + it explicity here before deciding we've gotten a bad argument. */ + if (optc == 'v') + { +#ifdef VMS + /* Telling getopt to treat -v's value as optional can result + in it picking up a following filename argument here. The + VMS code in md_parse_option can return 0 in that case, + but it has no way of pushing the filename argument back. */ + if (optarg && *optarg) + new_argv[new_argc++] = optarg, new_argv[new_argc] = NULL; + else +#else + case 'v': +#endif + case OPTION_VERBOSE: + print_version_id (); + break; + } + /*FALLTHRU*/ + + case '?': + exit (EXIT_FAILURE); + + case 1: /* File name. */ + if (!strcmp (optarg, "-")) + optarg = ""; + new_argv[new_argc++] = optarg; + new_argv[new_argc] = NULL; + break; + + case OPTION_HELP: + show_usage (stdout); + exit (EXIT_SUCCESS); + + case OPTION_NOCPP: + break; + + case OPTION_STATISTICS: + flag_print_statistics = 1; + break; + + case OPTION_VERSION: + /* This output is intended to follow the GNU standards document. */ + printf ("GNU assembler %s\n", GAS_VERSION); + printf ("Copyright 1997 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: +#ifdef USE_EMULATIONS + if (strcmp (optarg, this_emulation->name)) + as_fatal ("multiple emulation names specified"); +#else + as_fatal ("emulations not handled in this configuration"); +#endif + break; + + case OPTION_DUMPCONFIG: + fprintf (stderr, "alias = %s\n", TARGET_ALIAS); + fprintf (stderr, "canonical = %s\n", TARGET_CANONICAL); + fprintf (stderr, "cpu-type = %s\n", TARGET_CPU); +#ifdef TARGET_OBJ_FORMAT + fprintf (stderr, "format = %s\n", TARGET_OBJ_FORMAT); +#endif +#ifdef TARGET_FORMAT + fprintf (stderr, "bfd-target = %s\n", TARGET_FORMAT); +#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; + + case 'W': + flag_no_warnings = 1; + break; + + case 'Z': + flag_always_generate_output = 1; + break; + + case 'a': + if (optarg) + { + while (*optarg) + { + switch (*optarg) + { + case 'c': + listing |= LISTING_NOCOND; + break; + case 'd': + listing |= LISTING_NODEBUG; + break; + case 'h': + listing |= LISTING_HLL; + break; + case 'l': + listing |= LISTING_LISTING; + break; + case 'n': + listing |= LISTING_NOFORM; + break; + 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; + } + optarg++; + } + } + if (!listing) + listing = LISTING_DEFAULT; + break; + + case 'D': + /* DEBUG is implemented: it debugs different */ + /* things from other people's assemblers. */ + flag_debug = 1; + break; + + case 'f': + flag_no_comments = 1; + break; + + case 'I': + { /* Include file directory */ + char *temp = xstrdup (optarg); + add_include_dir (temp); + break; + } + + case 'o': + out_file_name = xstrdup (optarg); + break; + + case 'w': + break; + + case 'X': + /* -X means treat warnings as errors */ + break; + } + } + + free (shortopts); + free (longopts); + + *pargc = new_argc; + *pargv = new_argv; +} + +static long start_time; + +int +main (argc, argv) + int argc; + char **argv; +{ + int macro_alternate; + int macro_strip_at; + int keep_it; + + 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); +#endif + + myname = argv[0]; + xmalloc_set_program_name (myname); + + START_PROGRESS (myname, 0); + +#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME +#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out" +#endif + + out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME; + + hex_init (); +#ifdef BFD_ASSEMBLER + bfd_init (); + bfd_set_error_program_name (myname); +#endif + +#ifdef USE_EMULATIONS + select_emulation_mode (argc, argv); +#endif + + PROGRESS (1); + symbol_begin (); + frag_init (); + subsegs_begin (); + parse_args (&argc, &argv); + read_begin (); + input_scrub_begin (); + 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); + +#ifdef BFD_ASSEMBLER + output_file_create (out_file_name); + assert (stdoutput != 0); +#endif + +#ifdef tc_init_after_args + 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. */ + + cond_finish_check (-1); + +#ifdef md_end + md_end (); +#endif + + if (seen_at_least_1_file () + && (flag_always_generate_output || had_errors () == 0)) + keep_it = 1; + else + keep_it = 0; + + if (keep_it) + write_object_file (); + +#ifndef NO_LISTING + listing_print (listing_filename); +#endif + +#ifndef OBJ_VMS /* does its own file handling */ +#ifndef BFD_ASSEMBLER + if (keep_it) +#endif + 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 (); + + END_PROGRESS (myname); + + /* 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); +#endif + 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); +#ifdef HAVE_SBRK + fprintf (stderr, "%s: data size %ld\n", + myname, (long) (lim - (char *) &environ)); +#endif + + 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 +} + + +/* perform_an_assembly_pass() + * + * Here to attempt 1 pass over each input file. + * We scan argv[*] looking for filenames or exactly "" which is + * shorthand for stdin. Any argv that is NULL is not a file-name. + * We set need_pass_2 TRUE if, after this, we still have unresolved + * expressions of the form (unknown value)+-(unknown value). + * + * Note the un*x semantics: there is only 1 logical input file, but it + * may be a catenation of many 'physical' input files. + */ +static void +perform_an_assembly_pass (argc, argv) + int argc; + char **argv; +{ + int saw_a_file = 0; +#ifdef BFD_ASSEMBLER + flagword applicable; +#endif + + need_pass_2 = 0; + +#ifndef BFD_ASSEMBLER +#ifdef MANY_SEGMENTS + { + unsigned int i; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + segment_info[i].fix_root = 0; + } + /* Create the three fixed ones */ + { + segT seg; + +#ifdef TE_APOLLO + seg = subseg_new (".wtext", 0); +#else + seg = subseg_new (".text", 0); +#endif + assert (seg == SEG_E0); + seg = subseg_new (".data", 0); + assert (seg == SEG_E1); + seg = subseg_new (".bss", 0); + assert (seg == SEG_E2); +#ifdef TE_APOLLO + create_target_segments (); +#endif + } + +#else /* not MANY_SEGMENTS */ + text_fix_root = NULL; + data_fix_root = NULL; + bss_fix_root = NULL; +#endif /* not MANY_SEGMENTS */ +#else /* BFD_ASSEMBLER */ + /* Create the standard sections, and those the assembler uses + internally. */ + text_section = subseg_new (".text", 0); + data_section = subseg_new (".data", 0); + bss_section = subseg_new (".bss", 0); + /* @@ FIXME -- we're setting the RELOC flag so that sections are assumed + to have relocs, otherwise we don't find out in time. */ + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, text_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_CODE | SEC_READONLY)); + /* @@ FIXME -- SEC_CODE seems to mean code only, rather than code possibly.*/ + bfd_set_section_flags (stdoutput, data_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)); + bfd_set_section_flags (stdoutput, bss_section, applicable & SEC_ALLOC); + seg_info (bss_section)->bss = 1; + subseg_new (BFD_ABS_SECTION_NAME, 0); + subseg_new (BFD_UND_SECTION_NAME, 0); + reg_section = subseg_new ("*GAS `reg' section*", 0); + expr_section = subseg_new ("*GAS `expr' section*", 0); + +#endif /* BFD_ASSEMBLER */ + + subseg_set (text_section, 0); + + /* This may add symbol table entries, which requires having an open BFD, + 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--) + { + if (*argv) + { /* Is it a file-name argument? */ + PROGRESS (1); + saw_a_file++; + /* argv->"" if stdin desired, else->filename */ + read_a_source_file (*argv); + } + argv++; /* completed that argv */ + } + if (!saw_a_file) + 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 */ diff --git a/contrib/binutils/gas/as.h b/contrib/binutils/gas/as.h new file mode 100644 index 0000000..60fccaa --- /dev/null +++ b/contrib/binutils/gas/as.h @@ -0,0 +1,662 @@ +/* as.h - global header file + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef GAS +#define GAS 1 +/* + * I think this stuff is largely out of date. xoxorich. + * + * CAPITALISED names are #defined. + * "lowercaseH" is #defined if "lowercase.h" has been #include-d. + * "lowercaseT" is a typedef of "lowercase" objects. + * "lowercaseP" is type "pointer to object of type 'lowercase'". + * "lowercaseS" is typedef struct ... lowercaseS. + * + * #define DEBUG to enable all the "know" assertion tests. + * #define SUSPECT when debugging hash code. + * #define COMMON as "extern" for all modules except one, where you #define + * COMMON as "". + * If TEST is #defined, then we are testing a module: #define COMMON as "". + */ + +#include "config.h" + +/* This is the code recommended in the autoconf documentation, almost + verbatim. If it doesn't work for you, let me know, and notify + djm@gnu.ai.mit.edu as well. */ +/* Added #undef for DJ Delorie. The right fix is to ensure that as.h + is included first, before even any system header files, in all files + that use it. KR 1994.11.03 */ +/* Added void* version for STDC case. This is to be compatible with + the declaration in bison.simple, used for m68k operand parsing. + --KR 1995.08.08 */ +/* Force void* decl for hpux. This is what Bison uses. --KR 1995.08.16 */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +# undef alloca +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if !defined (__STDC__) && !defined (__hpux) +char *alloca (); +# else +void *alloca (); +# endif /* __STDC__, __hpux */ +# endif /* alloca */ +# endif /* _AIX */ +# endif /* HAVE_ALLOCA_H */ +#endif + +/* Now, tend to the rest of the configuration. */ + +/* System include files first... */ +#include <stdio.h> +#include <ctype.h> +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_TYPES_H +/* for size_t, pid_t */ +#include <sys/types.h> +#endif + +#include <getopt.h> +/* The first getopt value for machine-independent long options. + 150 isn't special; it's just an arbitrary non-ASCII char value. */ +#define OPTION_STD_BASE 150 +/* The first getopt value for machine-dependent long options. + 170 gives the standard options room to grow. */ +#define OPTION_MD_BASE 170 + +#ifdef DEBUG +#undef NDEBUG +#endif +#if !defined (__GNUC__) || __GNUC_MINOR__ <= 5 +#define __PRETTY_FUNCTION__ ((char*)0) +#endif +#if 0 + +/* Handle lossage with assert.h. */ +#ifndef BROKEN_ASSERT +#include <assert.h> +#else /* BROKEN_ASSERT */ +#ifndef NDEBUG +#define assert(p) ((p) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)) +#else +#define assert(p) ((p), 0) +#endif +#endif /* BROKEN_ASSERT */ + +#else + +#define assert(P) ((P) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)) +#undef abort +#define abort() as_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#endif + + +/* Now GNU header files... */ +#include <ansidecl.h> +#ifdef BFD_ASSEMBLER +#include <bfd.h> +#endif +#include <libiberty.h> + +/* Define the standard progress macros. */ +#include <progress.h> + +/* This doesn't get taken care of anywhere. */ +#ifndef __MWERKS__ /* Metrowerks C chokes on the "defined (inline)" */ +#if !defined (__GNUC__) && !defined (inline) +#define inline +#endif +#endif /* !__MWERKS__ */ + +/* Other stuff from config.h. */ +#ifdef NEED_DECLARATION_STRSTR +extern char *strstr (); +#endif +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +extern PTR realloc (); +#endif +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif + +/* This is needed for VMS with DEC C. */ +#if ! defined (__GNUC__) && ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE) +#define unlink remove +#endif + +/* Hack to make "gcc -Wall" not complain about obstack macros. */ +#if !defined (memcpy) && !defined (bcopy) +#define bcopy(src,dest,size) memcpy(dest,src,size) +#endif + +/* Make Saber happier on obstack.h. */ +#ifdef SABER +#undef __PTR_TO_INT +#define __PTR_TO_INT(P) ((int)(P)) +#undef __INT_TO_PTR +#define __INT_TO_PTR(P) ((char *)(P)) +#endif + +#ifndef __LINE__ +#define __LINE__ "unknown" +#endif /* __LINE__ */ + +#ifndef __FILE__ +#define __FILE__ "unknown" +#endif /* __FILE__ */ + +#ifndef FOPEN_WB +#ifdef GO32 +#include "fopen-bin.h" +#else +#include "fopen-same.h" +#endif +#endif + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#endif + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free xfree + +#define xfree free + +#define BAD_CASE(val) \ +{ \ + as_fatal("Case value %ld unexpected at line %d of file \"%s\"\n", \ + (long) val, __LINE__, __FILE__); \ + } + +#include "flonum.h" + +/* These are assembler-wide concepts */ + +#ifdef BFD_ASSEMBLER +extern bfd *stdoutput; +typedef bfd_vma addressT; +typedef bfd_signed_vma offsetT; +#else +typedef unsigned long addressT; +typedef long offsetT; +#endif + +/* Type of symbol value, etc. For use in prototypes. */ +typedef addressT valueT; + +#ifndef COMMON +#ifdef TEST +#define COMMON /* declare our COMMONs storage here. */ +#else +#define COMMON extern /* our commons live elswhere */ +#endif +#endif +/* COMMON now defined */ + +#ifdef DEBUG +#ifndef know +#define know(p) assert(p) /* Verify our assumptions! */ +#endif /* not yet defined */ +#else +#define know(p) /* know() checks are no-op.ed */ +#endif + +/* input_scrub.c */ + +/* + * Supplies sanitised buffers to read.c. + * Also understands printing line-number part of error messages. + */ + + +/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/ + +#ifndef BFD_ASSEMBLER + +#ifdef MANY_SEGMENTS +#include "bfd.h" +#define N_SEGMENTS 40 +#define SEG_NORMAL(x) ((x) >= SEG_E0 && (x) <= SEG_E39) +#define SEG_LIST SEG_E0,SEG_E1,SEG_E2,SEG_E3,SEG_E4,SEG_E5,SEG_E6,SEG_E7,SEG_E8,SEG_E9,\ + SEG_E10,SEG_E11,SEG_E12,SEG_E13,SEG_E14,SEG_E15,SEG_E16,SEG_E17,SEG_E18,SEG_E19,\ + SEG_E20,SEG_E21,SEG_E22,SEG_E23,SEG_E24,SEG_E25,SEG_E26,SEG_E27,SEG_E28,SEG_E29,\ + SEG_E30,SEG_E31,SEG_E32,SEG_E33,SEG_E34,SEG_E35,SEG_E36,SEG_E37,SEG_E38,SEG_E39 +#define SEG_TEXT SEG_E0 +#define SEG_DATA SEG_E1 +#define SEG_BSS SEG_E2 +#define SEG_LAST SEG_E39 +#else +#define N_SEGMENTS 3 +#define SEG_NORMAL(x) ((x) == SEG_TEXT || (x) == SEG_DATA || (x) == SEG_BSS) +#define SEG_LIST SEG_TEXT,SEG_DATA,SEG_BSS +#endif + +typedef enum _segT + { + SEG_ABSOLUTE = 0, + SEG_LIST, + SEG_UNKNOWN, + SEG_GOOF, /* Only happens if AS has a logic error. */ + /* Invented so we don't crash printing */ + /* error message involving weird segment. */ + SEG_EXPR, /* Intermediate expression values. */ + SEG_DEBUG, /* Debug segment */ + SEG_NTV, /* Transfert vector preload segment */ + SEG_PTV, /* Transfert vector postload segment */ + SEG_REGISTER /* Mythical: a register-valued expression */ + } segT; + +#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER) +#else +typedef asection *segT; +#define SEG_NORMAL(SEG) ((SEG) != absolute_section \ + && (SEG) != undefined_section \ + && (SEG) != reg_section \ + && (SEG) != expr_section) +#endif +typedef int subsegT; + +/* What subseg we are accreting now? */ +COMMON subsegT now_subseg; + +/* Segment our instructions emit to. */ +COMMON segT now_seg; + +#ifdef BFD_ASSEMBLER +#define segment_name(SEG) bfd_get_section_name (stdoutput, SEG) +#else +extern char const *const seg_name[]; +#define segment_name(SEG) seg_name[(int) (SEG)] +#endif + +#ifndef BFD_ASSEMBLER +extern int section_alignment[]; +#endif + +#ifdef BFD_ASSEMBLER +extern segT reg_section, expr_section; +/* Shouldn't these be eliminated someday? */ +extern segT text_section, data_section, bss_section; +#define absolute_section bfd_abs_section_ptr +#define undefined_section bfd_und_section_ptr +#else +#define reg_section SEG_REGISTER +#define expr_section SEG_EXPR +#define text_section SEG_TEXT +#define data_section SEG_DATA +#define bss_section SEG_BSS +#define absolute_section SEG_ABSOLUTE +#define undefined_section SEG_UNKNOWN +#endif + +/* relax() */ + +enum _relax_state + { + /* Variable chars to be repeated fr_offset times. + Fr_symbol unused. Used with fr_offset == 0 for a + constant length frag. */ + rs_fill = 1, + + /* Align. The fr_offset field holds the power of 2 to which to + align. The fr_var field holds the number of characters in the + fill pattern. The fr_subtype field holds the maximum number of + bytes to skip when aligning, or 0 if there is no maximum. */ + rs_align, + + /* Align code. The fr_offset field holds the power of 2 to which + to align. This type is only generated by machine specific + code, which is normally responsible for handling the fill + pattern. The fr_subtype field holds the maximum number of + bytes to skip when aligning, or 0 if there is no maximum. */ + rs_align_code, + + /* Org: Fr_offset, fr_symbol: address. 1 variable char: fill + character. */ + rs_org, + +#ifndef WORKING_DOT_WORD + /* JF: gunpoint */ + rs_broken_word, +#endif + + /* machine-specific relaxable (or similarly alterable) instruction */ + rs_machine_dependent, + + /* .space directive with expression operand that needs to be computed + later. Similar to rs_org, but different. + fr_symbol: operand + 1 variable char: fill character */ + rs_space + }; + +typedef enum _relax_state relax_stateT; + +/* This type is used in prototypes, so it can't be a type that will be + widened for argument passing. */ +typedef unsigned int relax_substateT; + +/* Enough bits for address, but still an integer type. + Could be a problem, cross-assembling for 64-bit machines. */ +typedef addressT relax_addressT; + + +/* frags.c */ + +/* + * A code fragment (frag) is some known number of chars, followed by some + * unknown number of chars. Typically the unknown number of chars is an + * instruction address whose size is yet unknown. We always know the greatest + * possible size the unknown number of chars may become, and reserve that + * much room at the end of the frag. + * Once created, frags do not change address during assembly. + * We chain the frags in (a) forward-linked list(s). The object-file address + * of the 1st char of a frag is generally not known until after relax(). + * Many things at assembly time describe an address by {object-file-address + * of a particular frag}+offset. + + BUG: it may be smarter to have a single pointer off to various different + notes for different frag kinds. See how code pans + */ +struct frag +{ + /* Object file address. */ + addressT fr_address; + /* Chain forward; ascending address order. Rooted in frch_root. */ + struct frag *fr_next; + + /* (Fixed) number of chars we know we have. May be 0. */ + offsetT fr_fix; + /* (Variable) number of chars after above. May be 0. */ + offsetT fr_var; + /* For variable-length tail. */ + struct symbol *fr_symbol; + /* For variable-length tail. */ + offsetT fr_offset; + /* Points to opcode low addr byte, for relaxation. */ + char *fr_opcode; + +#ifndef NO_LISTING + struct list_info_struct *line; +#endif + + /* What state is my tail in? */ + relax_stateT fr_type; + relax_substateT fr_subtype; + + union { + /* These are needed only on the NS32K machines. But since we don't + include targ-cpu.h until after this structure has been defined, + we can't really conditionalize it. This code should be + rearranged a bit to make that possible. */ + struct { + char pcrel_adjust, bsr; + } ns32k; +#ifdef USING_CGEN + /* Don't include this unless using CGEN to keep frag size down. */ + struct { + const struct cgen_insn *insn; + unsigned char opindex, opinfo; + } cgen; +#endif + } fr_targ; + + /* Where the frag was created, or where it became a variant frag. */ + char *fr_file; + unsigned int fr_line; + + /* Data begins here. */ + char fr_literal[1]; +}; + +#define SIZEOF_STRUCT_FRAG \ +((char *)zero_address_frag.fr_literal-(char *)&zero_address_frag) +/* We want to say fr_literal[0] above. */ + +typedef struct frag fragS; + +/* Current frag we are building. This frag is incomplete. It is, however, + included in frchain_now. The fr_fix field is bogus; instead, use: + obstack_next_free(&frags)-frag_now->fr_literal. */ +COMMON fragS *frag_now; +extern int frag_now_fix PARAMS ((void)); + +/* For foreign-segment symbol fixups. */ +COMMON fragS zero_address_frag; +/* For local common (N_BSS segment) fixups. */ +COMMON fragS bss_address_frag; + +/* main program "as.c" (command arguments etc) */ + +COMMON unsigned char flag_no_comments; /* -f */ +COMMON unsigned char flag_debug; /* -D */ +COMMON unsigned char flag_signed_overflow_ok; /* -J */ +#ifndef WORKING_DOT_WORD +COMMON unsigned char flag_warn_displacement; /* -K */ +#endif + +/* True if local symbols should be retained. */ +COMMON int flag_keep_locals; /* -L */ + +/* True if we are assembling in MRI mode. */ +COMMON int flag_mri; + +/* True if we are assembling in m68k MRI mode. */ +COMMON int flag_m68k_mri; + +/* Should the data section be made read-only and appended to the text + section? */ +COMMON unsigned char flag_readonly_data_in_text; /* -R */ + +/* True if warnings should be inhibited. */ +COMMON int flag_no_warnings; /* -W */ + +/* True if we should attempt to generate output even if non-fatal errors + are detected. */ +COMMON unsigned char flag_always_generate_output; /* -Z */ + +/* This is true if the assembler should output time and space usage. */ + +COMMON unsigned char flag_print_statistics; + +/* name of emitted object file */ +COMMON char *out_file_name; + +/* name of file defining extensions to the basic instruction set */ +COMMON char *insttbl_file_name; + +/* TRUE if we need a second pass. */ +COMMON int need_pass_2; + +/* TRUE if we should do no relaxing, and + leave lots of padding. */ +COMMON int linkrelax; + +/* TRUE if we should produce a listing. */ +extern int listing; + +/* Maximum level of macro nesting. */ +extern int max_macro_nest; + +/* Obstack chunk size. Keep large for efficient space use, make small to + increase malloc calls for monitoring memory allocation. */ +extern int chunksize; + +struct _pseudo_type + { + /* assembler mnemonic, lower case, no '.' */ + const char *poc_name; + /* Do the work */ + void (*poc_handler) PARAMS ((int)); + /* Value to pass to handler */ + int poc_val; + }; + +typedef struct _pseudo_type pseudo_typeS; + +/* Prefer varargs for non-ANSI compiler, since some will barf if the + ellipsis definition is used with a no-arguments declaration. */ +#if defined (HAVE_VARARGS_H) && !defined (__STDC__) +#undef HAVE_STDARG_H +#endif + +#if defined (HAVE_STDARG_H) +#define USE_STDARG +#endif +#if !defined (USE_STDARG) && defined (HAVE_VARARGS_H) +#define USE_VARARGS +#endif + +#ifdef USE_STDARG +#if (__GNUC__ >= 2) && !defined(VMS) +/* for use with -Wformat */ +#define PRINTF_LIKE(FCN) void FCN (const char *format, ...) \ + __attribute__ ((format (printf, 1, 2))) +#define PRINTF_WHERE_LIKE(FCN) void FCN (char *file, unsigned int line, \ + const char *format, ...) \ + __attribute__ ((format (printf, 3, 4))) +#else /* ANSI C with stdarg, but not GNU C */ +#define PRINTF_LIKE(FCN) void FCN PARAMS ((const char *format, ...)) +#define PRINTF_WHERE_LIKE(FCN) void FCN PARAMS ((char *file, \ + unsigned int line, \ + const char *format, ...)) +#endif +#else /* not using stdarg */ +#define PRINTF_LIKE(FCN) void FCN () +#define PRINTF_WHERE_LIKE(FCN) void FCN () +#endif + +PRINTF_LIKE (as_bad); +PRINTF_LIKE (as_fatal); +PRINTF_LIKE (as_tsktsk); +PRINTF_LIKE (as_warn); +PRINTF_WHERE_LIKE (as_bad_where); +PRINTF_WHERE_LIKE (as_warn_where); +void as_assert PARAMS ((const char *, int, const char *)); +void as_abort PARAMS ((const char *, int, const char *)); + +void fprint_value PARAMS ((FILE *file, addressT value)); +void sprint_value PARAMS ((char *buf, addressT value)); + +int had_errors PARAMS ((void)); +int had_warnings PARAMS ((void)); + +void print_version_id PARAMS ((void)); +char *app_push PARAMS ((void)); +char *atof_ieee PARAMS ((char *str, int what_kind, LITTLENUM_TYPE * words)); +char *input_scrub_include_file PARAMS ((char *filename, char *position)); +char *input_scrub_new_file PARAMS ((char *filename)); +char *input_scrub_next_buffer PARAMS ((char **bufp)); +int do_scrub_chars PARAMS ((int (*get) (char **), char *to, int tolen)); +int gen_to_words PARAMS ((LITTLENUM_TYPE * words, int precision, + long exponent_bits)); +int had_err PARAMS ((void)); +int ignore_input PARAMS ((void)); +void cond_finish_check PARAMS ((int)); +void cond_exit_macro PARAMS ((int)); +int seen_at_least_1_file PARAMS ((void)); +void app_pop PARAMS ((char *arg)); +void as_howmuch PARAMS ((FILE * stream)); +void as_perror PARAMS ((const char *gripe, const char *filename)); +void as_where PARAMS ((char **namep, unsigned int *linep)); +void bump_line_counters PARAMS ((void)); +void do_scrub_begin PARAMS ((int)); +void input_scrub_begin PARAMS ((void)); +void input_scrub_close PARAMS ((void)); +void input_scrub_end PARAMS ((void)); +void new_logical_line PARAMS ((char *fname, int line_number)); +void subsegs_begin PARAMS ((void)); +void subseg_change PARAMS ((segT seg, int subseg)); +segT subseg_new PARAMS ((const char *name, subsegT subseg)); +segT subseg_force_new PARAMS ((const char *name, subsegT subseg)); +void subseg_set PARAMS ((segT seg, subsegT subseg)); +#ifdef BFD_ASSEMBLER +segT subseg_get PARAMS ((const char *, int)); +#endif + +struct expressionS; +struct fix; +struct symbol; +struct relax_type; + +#ifdef BFD_ASSEMBLER +/* literal.c */ +valueT add_to_literal_pool PARAMS ((struct symbol *, valueT, segT, int)); +#endif + +#include "expr.h" /* Before targ-*.h */ + +/* this one starts the chain of target dependant headers */ +#include "targ-env.h" + +#include "struc-symbol.h" +#include "write.h" +#include "frags.h" +#include "hash.h" +#include "read.h" +#include "symbols.h" + +#include "tc.h" +#include "obj.h" + +#ifdef USE_EMULATIONS +#include "emul.h" +#endif +#include "listing.h" + +#ifndef LOCAL_LABELS_DOLLAR +#define LOCAL_LABELS_DOLLAR 0 +#endif + +#ifndef LOCAL_LABELS_FB +#define LOCAL_LABELS_FB 0 +#endif + +#endif /* GAS */ + +/* end of as.h */ diff --git a/contrib/binutils/gas/atof-generic.c b/contrib/binutils/gas/atof-generic.c new file mode 100644 index 0000000..9a00f04 --- /dev/null +++ b/contrib/binutils/gas/atof-generic.c @@ -0,0 +1,636 @@ +/* atof_generic.c - turn a string of digits into a Flonum + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <ctype.h> +#include <string.h> + +#include "as.h" + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif + +#ifdef TRACE +static void flonum_print PARAMS ((const FLONUM_TYPE *)); +#endif + +#define ASSUME_DECIMAL_MARK_IS_DOT + +/***********************************************************************\ + * * + * Given a string of decimal digits , with optional decimal * + * mark and optional decimal exponent (place value) of the * + * lowest_order decimal digit: produce a floating point * + * number. The number is 'generic' floating point: our * + * caller will encode it for a specific machine architecture. * + * * + * Assumptions * + * uses base (radix) 2 * + * this machine uses 2's complement binary integers * + * target flonums use " " " " * + * target flonums exponents fit in a long * + * * + \***********************************************************************/ + +/* + + Syntax: + + <flonum> ::= <optional-sign> <decimal-number> <optional-exponent> + <optional-sign> ::= '+' | '-' | {empty} + <decimal-number> ::= <integer> + | <integer> <radix-character> + | <integer> <radix-character> <integer> + | <radix-character> <integer> + + <optional-exponent> ::= {empty} + | <exponent-character> <optional-sign> <integer> + + <integer> ::= <digit> | <digit> <integer> + <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + <exponent-character> ::= {one character from "string_of_decimal_exponent_marks"} + <radix-character> ::= {one character from "string_of_decimal_marks"} + + */ + +int +atof_generic (address_of_string_pointer, + string_of_decimal_marks, + string_of_decimal_exponent_marks, + address_of_generic_floating_point_number) + /* return pointer to just AFTER number we read. */ + char **address_of_string_pointer; + /* At most one per number. */ + const char *string_of_decimal_marks; + const char *string_of_decimal_exponent_marks; + FLONUM_TYPE *address_of_generic_floating_point_number; +{ + int return_value; /* 0 means OK. */ + char *first_digit; + int number_of_digits_before_decimal; + int number_of_digits_after_decimal; + long decimal_exponent; + int number_of_digits_available; + char digits_sign_char; + + /* + * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent. + * It would be simpler to modify the string, but we don't; just to be nice + * to caller. + * We need to know how many digits we have, so we can allocate space for + * the digits' value. + */ + + char *p; + char c; + int seen_significant_digit; + +#ifdef ASSUME_DECIMAL_MARK_IS_DOT + assert (string_of_decimal_marks[0] == '.' + && string_of_decimal_marks[1] == 0); +#define IS_DECIMAL_MARK(c) ((c) == '.') +#else +#define IS_DECIMAL_MARK(c) (0 != strchr (string_of_decimal_marks, (c))) +#endif + + first_digit = *address_of_string_pointer; + c = *first_digit; + + if (c == '-' || c == '+') + { + digits_sign_char = c; + first_digit++; + } + else + digits_sign_char = '+'; + + switch (first_digit[0]) + { + case 'n': + case 'N': + if (!strncasecmp ("nan", first_digit, 3)) + { + address_of_generic_floating_point_number->sign = 0; + address_of_generic_floating_point_number->exponent = 0; + address_of_generic_floating_point_number->leader = + address_of_generic_floating_point_number->low; + *address_of_string_pointer = first_digit + 3; + return 0; + } + break; + + case 'i': + case 'I': + if (!strncasecmp ("inf", first_digit, 3)) + { + address_of_generic_floating_point_number->sign = + digits_sign_char == '+' ? 'P' : 'N'; + address_of_generic_floating_point_number->exponent = 0; + address_of_generic_floating_point_number->leader = + address_of_generic_floating_point_number->low; + + first_digit += 3; + if (!strncasecmp ("inity", first_digit, 5)) + first_digit += 5; + + *address_of_string_pointer = first_digit; + + return 0; + } + break; + } + + number_of_digits_before_decimal = 0; + number_of_digits_after_decimal = 0; + decimal_exponent = 0; + seen_significant_digit = 0; + for (p = first_digit; + (((c = *p) != '\0') + && (!c || !IS_DECIMAL_MARK (c)) + && (!c || !strchr (string_of_decimal_exponent_marks, c))); + p++) + { + if (isdigit (c)) + { + if (seen_significant_digit || c > '0') + { + ++number_of_digits_before_decimal; + seen_significant_digit = 1; + } + else + { + first_digit++; + } + } + else + { + break; /* p -> char after pre-decimal digits. */ + } + } /* For each digit before decimal mark. */ + +#ifndef OLD_FLOAT_READS + /* Ignore trailing 0's after the decimal point. The original code here + * (ifdef'd out) does not do this, and numbers like + * 4.29496729600000000000e+09 (2**31) + * come out inexact for some reason related to length of the digit + * string. + */ + if (c && IS_DECIMAL_MARK (c)) + { + int zeros = 0; /* Length of current string of zeros */ + + for (p++; (c = *p) && isdigit (c); p++) + { + if (c == '0') + { + zeros++; + } + else + { + number_of_digits_after_decimal += 1 + zeros; + zeros = 0; + } + } + } +#else + if (c && IS_DECIMAL_MARK (c)) + { + for (p++; + (((c = *p) != '\0') + && (!c || !strchr (string_of_decimal_exponent_marks, c))); + p++) + { + if (isdigit (c)) + { + /* This may be retracted below. */ + number_of_digits_after_decimal++; + + if ( /* seen_significant_digit || */ c > '0') + { + seen_significant_digit = TRUE; + } + } + else + { + if (!seen_significant_digit) + { + number_of_digits_after_decimal = 0; + } + break; + } + } /* For each digit after decimal mark. */ + } + + while (number_of_digits_after_decimal + && first_digit[number_of_digits_before_decimal + + number_of_digits_after_decimal] == '0') + --number_of_digits_after_decimal; +#endif + + if (flag_m68k_mri) + { + while (c == '_') + c = *++p; + } + if (c && strchr (string_of_decimal_exponent_marks, c)) + { + char digits_exponent_sign_char; + + c = *++p; + if (flag_m68k_mri) + { + while (c == '_') + c = *++p; + } + if (c && strchr ("+-", c)) + { + digits_exponent_sign_char = c; + c = *++p; + } + else + { + digits_exponent_sign_char = '+'; + } + + for (; (c); c = *++p) + { + if (isdigit (c)) + { + decimal_exponent = decimal_exponent * 10 + c - '0'; + /* + * BUG! If we overflow here, we lose! + */ + } + else + { + break; + } + } + + if (digits_exponent_sign_char == '-') + { + decimal_exponent = -decimal_exponent; + } + } + + *address_of_string_pointer = p; + + + + number_of_digits_available = + number_of_digits_before_decimal + number_of_digits_after_decimal; + return_value = 0; + if (number_of_digits_available == 0) + { + address_of_generic_floating_point_number->exponent = 0; /* Not strictly necessary */ + address_of_generic_floating_point_number->leader + = -1 + address_of_generic_floating_point_number->low; + address_of_generic_floating_point_number->sign = digits_sign_char; + /* We have just concocted (+/-)0.0E0 */ + + } + else + { + int count; /* Number of useful digits left to scan. */ + + LITTLENUM_TYPE *digits_binary_low; + unsigned int precision; + unsigned int maximum_useful_digits; + unsigned int number_of_digits_to_use; + unsigned int more_than_enough_bits_for_digits; + unsigned int more_than_enough_littlenums_for_digits; + unsigned int size_of_digits_in_littlenums; + unsigned int size_of_digits_in_chars; + FLONUM_TYPE power_of_10_flonum; + FLONUM_TYPE digits_flonum; + + precision = (address_of_generic_floating_point_number->high + - address_of_generic_floating_point_number->low + + 1); /* Number of destination littlenums. */ + + /* Includes guard bits (two littlenums worth) */ +#if 0 /* The integer version below is very close, and it doesn't + require floating point support (which is currently buggy on + the Alpha). */ + maximum_useful_digits = (((double) (precision - 2)) + * ((double) (LITTLENUM_NUMBER_OF_BITS)) + / (LOG_TO_BASE_2_OF_10)) + + 2; /* 2 :: guard digits. */ +#else + maximum_useful_digits = (((precision - 2)) + * ( (LITTLENUM_NUMBER_OF_BITS)) + * 1000000 / 3321928) + + 2; /* 2 :: guard digits. */ +#endif + + if (number_of_digits_available > maximum_useful_digits) + { + number_of_digits_to_use = maximum_useful_digits; + } + else + { + number_of_digits_to_use = number_of_digits_available; + } + + /* Cast these to SIGNED LONG first, otherwise, on systems with + LONG wider than INT (such as Alpha OSF/1), unsignedness may + cause unexpected results. */ + decimal_exponent += ((long) number_of_digits_before_decimal + - (long) number_of_digits_to_use); + +#if 0 + more_than_enough_bits_for_digits + = ((((double) number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1); +#else + more_than_enough_bits_for_digits + = (number_of_digits_to_use * 3321928 / 1000000 + 1); +#endif + + more_than_enough_littlenums_for_digits + = (more_than_enough_bits_for_digits + / LITTLENUM_NUMBER_OF_BITS) + + 2; + + /* Compute (digits) part. In "12.34E56" this is the "1234" part. + Arithmetic is exact here. If no digits are supplied then this + part is a 0 valued binary integer. Allocate room to build up + the binary number as littlenums. We want this memory to + disappear when we leave this function. Assume no alignment + problems => (room for n objects) == n * (room for 1 + object). */ + + size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits; + size_of_digits_in_chars = size_of_digits_in_littlenums + * sizeof (LITTLENUM_TYPE); + + digits_binary_low = (LITTLENUM_TYPE *) + alloca (size_of_digits_in_chars); + + memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars); + + /* Digits_binary_low[] is allocated and zeroed. */ + + /* + * Parse the decimal digits as if * digits_low was in the units position. + * Emit a binary number into digits_binary_low[]. + * + * Use a large-precision version of: + * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit + */ + + for (p = first_digit, count = number_of_digits_to_use; count; p++, --count) + { + c = *p; + if (isdigit (c)) + { + /* + * Multiply by 10. Assume can never overflow. + * Add this digit to digits_binary_low[]. + */ + + long carry; + LITTLENUM_TYPE *littlenum_pointer; + LITTLENUM_TYPE *littlenum_limit; + + littlenum_limit = digits_binary_low + + more_than_enough_littlenums_for_digits + - 1; + + carry = c - '0'; /* char -> binary */ + + for (littlenum_pointer = digits_binary_low; + littlenum_pointer <= littlenum_limit; + littlenum_pointer++) + { + long work; + + work = carry + 10 * (long) (*littlenum_pointer); + *littlenum_pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + + if (carry != 0) + { + /* + * We have a GROSS internal error. + * This should never happen. + */ + as_fatal ("failed sanity check."); + } + } + else + { + ++count; /* '.' doesn't alter digits used count. */ + } + } + + + /* + * Digits_binary_low[] properly encodes the value of the digits. + * Forget about any high-order littlenums that are 0. + */ + while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0 + && size_of_digits_in_littlenums >= 2) + size_of_digits_in_littlenums--; + + digits_flonum.low = digits_binary_low; + digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1; + digits_flonum.leader = digits_flonum.high; + digits_flonum.exponent = 0; + /* + * The value of digits_flonum . sign should not be important. + * We have already decided the output's sign. + * We trust that the sign won't influence the other parts of the number! + * So we give it a value for these reasons: + * (1) courtesy to humans reading/debugging + * these numbers so they don't get excited about strange values + * (2) in future there may be more meaning attached to sign, + * and what was + * harmless noise may become disruptive, ill-conditioned (or worse) + * input. + */ + digits_flonum.sign = '+'; + + { + /* + * Compute the mantssa (& exponent) of the power of 10. + * If sucessful, then multiply the power of 10 by the digits + * giving return_binary_mantissa and return_binary_exponent. + */ + + LITTLENUM_TYPE *power_binary_low; + int decimal_exponent_is_negative; + /* This refers to the "-56" in "12.34E-56". */ + /* FALSE: decimal_exponent is positive (or 0) */ + /* TRUE: decimal_exponent is negative */ + FLONUM_TYPE temporary_flonum; + LITTLENUM_TYPE *temporary_binary_low; + unsigned int size_of_power_in_littlenums; + unsigned int size_of_power_in_chars; + + size_of_power_in_littlenums = precision; + /* Precision has a built-in fudge factor so we get a few guard bits. */ + + decimal_exponent_is_negative = decimal_exponent < 0; + if (decimal_exponent_is_negative) + { + decimal_exponent = -decimal_exponent; + } + + /* From now on: the decimal exponent is > 0. Its sign is separate. */ + + size_of_power_in_chars = size_of_power_in_littlenums + * sizeof (LITTLENUM_TYPE) + 2; + + power_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); + temporary_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); + memset ((char *) power_binary_low, '\0', size_of_power_in_chars); + *power_binary_low = 1; + power_of_10_flonum.exponent = 0; + power_of_10_flonum.low = power_binary_low; + power_of_10_flonum.leader = power_binary_low; + power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1; + power_of_10_flonum.sign = '+'; + temporary_flonum.low = temporary_binary_low; + temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1; + /* + * (power) == 1. + * Space for temporary_flonum allocated. + */ + + /* + * ... + * + * WHILE more bits + * DO find next bit (with place value) + * multiply into power mantissa + * OD + */ + { + int place_number_limit; + /* Any 10^(2^n) whose "n" exceeds this */ + /* value will fall off the end of */ + /* flonum_XXXX_powers_of_ten[]. */ + int place_number; + const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */ + + place_number_limit = table_size_of_flonum_powers_of_ten; + + multiplicand = (decimal_exponent_is_negative + ? flonum_negative_powers_of_ten + : flonum_positive_powers_of_ten); + + for (place_number = 1;/* Place value of this bit of exponent. */ + decimal_exponent;/* Quit when no more 1 bits in exponent. */ + decimal_exponent >>= 1, place_number++) + { + if (decimal_exponent & 1) + { + if (place_number > place_number_limit) + { + /* The decimal exponent has a magnitude so great + that our tables can't help us fragment it. + Although this routine is in error because it + can't imagine a number that big, signal an + error as if it is the user's fault for + presenting such a big number. */ + return_value = ERROR_EXPONENT_OVERFLOW; + /* quit out of loop gracefully */ + decimal_exponent = 0; + } + else + { +#ifdef TRACE + printf ("before multiply, place_number = %d., power_of_10_flonum:\n", + place_number); + + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif +#ifdef TRACE + printf ("multiplier:\n"); + flonum_print (multiplicand + place_number); + (void) putchar ('\n'); +#endif + flonum_multip (multiplicand + place_number, + &power_of_10_flonum, &temporary_flonum); +#ifdef TRACE + printf ("after multiply:\n"); + flonum_print (&temporary_flonum); + (void) putchar ('\n'); +#endif + flonum_copy (&temporary_flonum, &power_of_10_flonum); +#ifdef TRACE + printf ("after copy:\n"); + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif + } /* If this bit of decimal_exponent was computable.*/ + } /* If this bit of decimal_exponent was set. */ + } /* For each bit of binary representation of exponent */ +#ifdef TRACE + printf ("after computing power_of_10_flonum:\n"); + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif + } + + } + + /* + * power_of_10_flonum is power of ten in binary (mantissa) , (exponent). + * It may be the number 1, in which case we don't NEED to multiply. + * + * Multiply (decimal digits) by power_of_10_flonum. + */ + + flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number); + /* Assert sign of the number we made is '+'. */ + address_of_generic_floating_point_number->sign = digits_sign_char; + + } + return return_value; +} + +#ifdef TRACE +static void +flonum_print (f) + const FLONUM_TYPE *f; +{ + LITTLENUM_TYPE *lp; + char littlenum_format[10]; + sprintf (littlenum_format, " %%0%dx", sizeof (LITTLENUM_TYPE) * 2); +#define print_littlenum(LP) (printf (littlenum_format, LP)) + printf ("flonum @%p %c e%ld", f, f->sign, f->exponent); + if (f->low < f->high) + for (lp = f->high; lp >= f->low; lp--) + print_littlenum (*lp); + else + for (lp = f->low; lp <= f->high; lp++) + print_littlenum (*lp); + printf ("\n"); + fflush (stdout); +} +#endif + +/* end of atof_generic.c */ diff --git a/contrib/binutils/gas/bignum-copy.c b/contrib/binutils/gas/bignum-copy.c new file mode 100644 index 0000000..2bffcbf --- /dev/null +++ b/contrib/binutils/gas/bignum-copy.c @@ -0,0 +1,80 @@ +/* bignum_copy.c - copy a bignum + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "as.h" + +/* + * bignum_copy () + * + * Copy a bignum from in to out. + * If the output is shorter than the input, copy lower-order littlenums. + * Return 0 or the number of significant littlenums dropped. + * Assumes littlenum arrays are densely packed: no unused chars between + * the littlenums. Uses memcpy() to move littlenums, and wants to + * know length (in chars) of the input bignum. + */ + +/* void */ +int +bignum_copy (in, in_length, out, out_length) + register LITTLENUM_TYPE *in; + register int in_length; /* in sizeof(littlenum)s */ + register LITTLENUM_TYPE *out; + register int out_length; /* in sizeof(littlenum)s */ +{ + int significant_littlenums_dropped; + + if (out_length < in_length) + { + LITTLENUM_TYPE *p; /* -> most significant (non-zero) input + littlenum. */ + + memcpy ((void *) out, (void *) in, + (unsigned int) out_length << LITTLENUM_SHIFT); + for (p = in + in_length - 1; p >= in; --p) + { + if (*p) + break; + } + significant_littlenums_dropped = p - in - in_length + 1; + + if (significant_littlenums_dropped < 0) + { + significant_littlenums_dropped = 0; + } + } + else + { + memcpy ((char *) out, (char *) in, + (unsigned int) in_length << LITTLENUM_SHIFT); + + if (out_length > in_length) + { + memset ((char *) (out + in_length), + '\0', + (unsigned int) (out_length - in_length) << LITTLENUM_SHIFT); + } + + significant_littlenums_dropped = 0; + } + + return (significant_littlenums_dropped); +} /* bignum_copy() */ + +/* end of bignum-copy.c */ diff --git a/contrib/binutils/gas/bignum.h b/contrib/binutils/gas/bignum.h new file mode 100644 index 0000000..e3b2f16 --- /dev/null +++ b/contrib/binutils/gas/bignum.h @@ -0,0 +1,52 @@ +/* bignum.h-arbitrary precision integers + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/***********************************************************************\ + * * + * Arbitrary-precision integer arithmetic. * + * For speed, we work in groups of bits, even though this * + * complicates algorithms. * + * Each group of bits is called a 'littlenum'. * + * A bunch of littlenums representing a (possibly large) * + * integer is called a 'bignum'. * + * Bignums are >= 0. * + * * + \***********************************************************************/ + +#define LITTLENUM_NUMBER_OF_BITS (16) +#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS) +#define LITTLENUM_MASK (0xFFFF) +#define LITTLENUM_SHIFT (1) +#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT) +#ifndef BITS_PER_CHAR +#define BITS_PER_CHAR (8) +#endif + +typedef unsigned short LITTLENUM_TYPE; + +/* JF truncated this to get around a problem with GCC */ +#define LOG_TO_BASE_2_OF_10 (3.3219280948873623478703194294893901758651) +/* WARNING: I haven't checked that the trailing digits are correct! */ + +/* lengths are in sizeof(littlenum)s */ + +int bignum_copy PARAMS ((LITTLENUM_TYPE * in, int in_length, + LITTLENUM_TYPE * out, int out_length)); + +/* end of bignum.h */ diff --git a/contrib/binutils/gas/bit_fix.h b/contrib/binutils/gas/bit_fix.h new file mode 100644 index 0000000..6a729a7 --- /dev/null +++ b/contrib/binutils/gas/bit_fix.h @@ -0,0 +1,51 @@ +/* write.h + + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The bit_fix was implemented to support machines that need variables + to be inserted in bitfields other than 1, 2 and 4 bytes. + Furthermore it gives us a possibillity to mask in bits in the symbol + when it's fixed in the objectcode and check the symbols limits. + + The or-mask is used to set the huffman bits in displacements for the + ns32k port. + The acbi, addqi, movqi, cmpqi instruction requires an assembler that + can handle bitfields. Ie handle an expression, evaluate it and insert + the result in an some bitfield. ( ex: 5 bits in a short field of a opcode) + */ + +#ifndef __bit_fix_h__ +#define __bit_fix_h__ + +struct bit_fix + { + int fx_bit_size; /* Length of bitfield */ + int fx_bit_offset; /* Bit offset to bitfield */ + long fx_bit_base; /* Where do we apply the bitfix. + If this is zero, default is assumed. */ + long fx_bit_base_adj; /* Adjustment of base */ + long fx_bit_max; /* Signextended max for bitfield */ + long fx_bit_min; /* Signextended min for bitfield */ + long fx_bit_add; /* Or mask, used for huffman prefix */ + }; +typedef struct bit_fix bit_fixS; + +#endif /* __bit_fix_h__ */ + +/* end of bit_fix.h */ diff --git a/contrib/binutils/gas/cgen.c b/contrib/binutils/gas/cgen.c new file mode 100644 index 0000000..e9024e4 --- /dev/null +++ b/contrib/binutils/gas/cgen.c @@ -0,0 +1,527 @@ +/* GAS interface for targets using CGEN: Cpu tools GENerator. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "ansidecl.h" +#include "bfd.h" +#include "cgen-opc.h" +#include "as.h" +#include "subsegs.h" + +/* Callback to insert a register into the symbol table. + A target may choose to let GAS parse the registers. + ??? Not currently used. */ + +void +cgen_asm_record_register (name, number) + char *name; + int number; +{ + /* Use symbol_create here instead of symbol_new so we don't try to + output registers into the object file's symbol table. */ + symbol_table_insert (symbol_create (name, reg_section, + number, &zero_address_frag)); +} + +/* We need to keep a list of fixups. We can't simply generate them as + we go, because that would require us to first create the frag, and + that would screw up references to ``.''. + + This is used by cpu's with simple operands. It keeps knowledge of what + an `expressionS' is and what a `fixup' is out of CGEN which for the time + being is preferable. + + OPINDEX is the index in the operand table. + OPINFO is something the caller chooses to help in reloc determination. */ + +struct fixup +{ + int opindex; + int opinfo; + expressionS exp; +}; + +#define MAX_FIXUPS 5 + +static struct fixup fixups[MAX_FIXUPS]; +static int num_fixups; + +/* Prepare to parse an instruction. + ??? May wish to make this static and delete calls in md_assemble. */ + +void +cgen_asm_init_parse () +{ + num_fixups = 0; +} + +/* Queue a fixup. */ + +void +cgen_queue_fixup (opindex, opinfo, expP) + int opindex; + expressionS *expP; +{ + /* We need to generate a fixup for this expression. */ + if (num_fixups >= MAX_FIXUPS) + as_fatal ("too many fixups"); + fixups[num_fixups].exp = *expP; + fixups[num_fixups].opindex = opindex; + fixups[num_fixups].opinfo = opinfo; + ++num_fixups; +} + +/* Default routine to record a fixup. + This is a cover function to fix_new. + It exists because we record INSN with the fixup. + + FRAG and WHERE are their respective arguments to fix_new_exp. + LENGTH is in bits. + OPINFO is something the caller chooses to help in reloc determination. + + At this point we do not use a bfd_reloc_code_real_type for + operands residing in the insn, but instead just use the + operand index. This lets us easily handle fixups for any + operand type. We pick a BFD reloc type in md_apply_fix. */ + +fixS * +cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) + fragS *frag; + int where; + const struct cgen_insn *insn; + int length; + const struct cgen_operand *operand; + int opinfo; + symbolS *symbol; + offsetT offset; +{ + fixS *fixP; + + /* It may seem strange to use operand->attrs and not insn->attrs here, + but it is the operand that has a pc relative relocation. */ + + fixP = fix_new (frag, where, length / 8, symbol, offset, + CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0, + (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand))); + fixP->tc_fix_data.insn = (PTR) insn; + fixP->tc_fix_data.opinfo = opinfo; + + return fixP; +} + +/* Default routine to record a fixup given an expression. + This is a cover function to fix_new_exp. + It exists because we record INSN with the fixup. + + FRAG and WHERE are their respective arguments to fix_new_exp. + LENGTH is in bits. + OPINFO is something the caller chooses to help in reloc determination. + + At this point we do not use a bfd_reloc_code_real_type for + operands residing in the insn, but instead just use the + operand index. This lets us easily handle fixups for any + operand type. We pick a BFD reloc type in md_apply_fix. */ + +fixS * +cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) + fragS *frag; + int where; + const struct cgen_insn *insn; + int length; + const struct cgen_operand *operand; + int opinfo; + expressionS *exp; +{ + fixS *fixP; + + /* It may seem strange to use operand->attrs and not insn->attrs here, + but it is the operand that has a pc relative relocation. */ + + fixP = fix_new_exp (frag, where, length / 8, exp, + CGEN_OPERAND_ATTR (operand, CGEN_OPERAND_PCREL_ADDR) != 0, + (bfd_reloc_code_real_type) ((int) BFD_RELOC_UNUSED + CGEN_OPERAND_INDEX (operand))); + fixP->tc_fix_data.insn = (PTR) insn; + fixP->tc_fix_data.opinfo = opinfo; + + return fixP; +} + +/* Callback for cgen interface. Parse the expression at *STRP. + The result is an error message or NULL for success (in which case + *STRP is advanced past the parsed text). + WANT is an indication of what the caller is looking for. + If WANT == CGEN_ASM_PARSE_INIT the caller is beginning to try to match + a table entry with the insn, reset the queued fixups counter. + An enum cgen_parse_operand_result is stored in RESULTP. + OPINDEX is the operand's table entry index. + OPINFO is something the caller chooses to help in reloc determination. + The resulting value is stored in VALUEP. */ + +const char * +cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) + enum cgen_parse_operand_type want; + const char **strP; + int opindex; + int opinfo; + enum cgen_parse_operand_result *resultP; + bfd_vma *valueP; +{ + char *hold; + const char *errmsg = NULL; + expressionS exp; + + if (want == CGEN_PARSE_OPERAND_INIT) + { + cgen_asm_init_parse (); + return NULL; + } + + hold = input_line_pointer; + input_line_pointer = (char *) *strP; + expression (&exp); + *strP = input_line_pointer; + input_line_pointer = hold; + + /* FIXME: Need to check `want'. */ + + switch (exp.X_op) + { + case O_illegal : + errmsg = "illegal operand"; + *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; + break; + case O_absent : + errmsg = "missing operand"; + *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; + break; + case O_constant : + *valueP = exp.X_add_number; + *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; + break; + case O_register : + *valueP = exp.X_add_number; + *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; + break; + default : + cgen_queue_fixup (opindex, opinfo, &exp); + *valueP = 0; + *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; + break; + } + + return errmsg; +} + +/* Finish assembling instruction INSN. + BUF contains what we've built up so far. + LENGTH is the size of the insn in bits. */ + +void +cgen_asm_finish_insn (insn, buf, length) + const struct cgen_insn *insn; + cgen_insn_t *buf; + unsigned int length; +{ + int i, relax_operand; + char *f; + unsigned int byte_len = length / 8; + + /* ??? Target foo issues various warnings here, so one might want to provide + a hook here. However, our caller is defined in tc-foo.c so there + shouldn't be a need for a hook. */ + + /* Write out the instruction. + It is important to fetch enough space in one call to `frag_more'. + We use (f - frag_now->fr_literal) to compute where we are and we + don't want frag_now to change between calls. + + Relaxable instructions: We need to ensure we allocate enough + space for the largest insn. */ + + if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0) + abort (); /* These currently shouldn't get here. */ + + /* Is there a relaxable insn with the relaxable operand needing a fixup? */ + + relax_operand = -1; + if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0) + { + /* Scan the fixups for the operand affected by relaxing + (i.e. the branch address). */ + + for (i = 0; i < num_fixups; ++i) + { + if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex], + CGEN_OPERAND_RELAX) != 0) + { + relax_operand = i; + break; + } + } + } + + if (relax_operand != -1) + { + int max_len; + fragS *old_frag; + +#ifdef TC_CGEN_MAX_RELAX + max_len = TC_CGEN_MAX_RELAX (insn, byte_len); +#else + max_len = CGEN_MAX_INSN_SIZE; +#endif + /* Ensure variable part and fixed part are in same fragment. */ + /* FIXME: Having to do this seems like a hack. */ + frag_grow (max_len); + /* Allocate space for the fixed part. */ + f = frag_more (byte_len); + /* Create a relaxable fragment for this instruction. */ + old_frag = frag_now; + frag_var (rs_machine_dependent, + max_len - byte_len /* max chars */, + 0 /* variable part already allocated */, + /* FIXME: When we machine generate the relax table, + machine generate a macro to compute subtype. */ + 1 /* subtype */, + fixups[relax_operand].exp.X_add_symbol, + fixups[relax_operand].exp.X_add_number, + f); + /* Record the operand number with the fragment so md_convert_frag + can use cgen_md_record_fixup to record the appropriate reloc. */ + /* FIXME: fr_targ.cgen is used pending deciding whether to + allow a target to add members to fragS. For more info + see the comment above fr_targ in as.h. */ + old_frag->fr_targ.cgen.insn = insn; + old_frag->fr_targ.cgen.opindex = fixups[relax_operand].opindex; + old_frag->fr_targ.cgen.opinfo = fixups[relax_operand].opinfo; + } + else + f = frag_more (byte_len); + + /* If we're recording insns as numbers (rather than a string of bytes), + target byte order handling is deferred until now. */ +#if 0 /*def CGEN_INT_INSN*/ + switch (length) + { + case 16: + if (cgen_big_endian_p) + bfd_putb16 ((bfd_vma) *buf, f); + else + bfd_putl16 ((bfd_vma) *buf, f); + break; + case 32: + if (cgen_big_endian_p) + bfd_putb32 ((bfd_vma) *buf, f); + else + bfd_putl32 ((bfd_vma) *buf, f); + break; + default: + abort (); + } +#else + memcpy (f, buf, byte_len); +#endif + + /* Create any fixups. */ + for (i = 0; i < num_fixups; ++i) + { + /* Don't create fixups for these. That's done during relaxation. + We don't need to test for CGEN_INSN_RELAX as they can't get here + (see above). */ + if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0 + && CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex], + CGEN_OPERAND_RELAX) != 0) + continue; + +#ifndef md_cgen_record_fixup_exp +#define md_cgen_record_fixup_exp cgen_record_fixup_exp +#endif + + md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal, + insn, length, + & CGEN_SYM (operand_table) [fixups[i].opindex], + fixups[i].opinfo, + &fixups[i].exp); + } +} + +/* Apply a fixup to the object code. This is called for all the + fixups we generated by the call to fix_new_exp, above. In the call + above we used a reloc code which was the largest legal reloc code + plus the operand index. Here we undo that to recover the operand + index. At this point all symbol values should be fully resolved, + and we attempt to completely resolve the reloc. If we can not do + that, we determine the correct reloc code and put it back in the fixup. */ + +/* FIXME: This function handles some of the fixups and bfd_install_relocation + handles the rest. bfd_install_relocation (or some other bfd function) + should handle them all. */ + +int +cgen_md_apply_fix3 (fixP, valueP, seg) + fixS *fixP; + valueT *valueP; + segT seg; +{ + char *where = fixP->fx_frag->fr_literal + fixP->fx_where; + valueT value; + + /* FIXME FIXME FIXME: The value we are passed in *valuep includes + the symbol values. Since we are using BFD_ASSEMBLER, if we are + doing this relocation the code in write.c is going to call + bfd_install_relocation, which is also going to use the symbol + value. That means that if the reloc is fully resolved we want to + use *valuep since bfd_install_relocation is not being used. + However, if the reloc is not fully resolved we do not want to use + *valuep, and must use fx_offset instead. However, if the reloc + is PC relative, we do want to use *valuep since it includes the + result of md_pcrel_from. This is confusing. */ + + if (fixP->fx_addsy == (symbolS *) NULL) + { + value = *valueP; + fixP->fx_done = 1; + } + else if (fixP->fx_pcrel) + value = *valueP; + else + { + value = fixP->fx_offset; + if (fixP->fx_subsy != (symbolS *) NULL) + { + if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section) + value -= S_GET_VALUE (fixP->fx_subsy); + else + { + /* We don't actually support subtracting a symbol. */ + as_bad_where (fixP->fx_file, fixP->fx_line, + "expression too complex"); + } + } + } + + if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) + { + int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; + const struct cgen_operand *operand = & CGEN_SYM (operand_table) [opindex]; + const char *errmsg; + bfd_reloc_code_real_type reloc_type; + struct cgen_fields fields; + const struct cgen_insn *insn = (struct cgen_insn *) fixP->tc_fix_data.insn; + + /* If the reloc has been fully resolved finish the operand here. */ + /* FIXME: This duplicates the capabilities of code in BFD. */ + if (fixP->fx_done + /* FIXME: If partial_inplace isn't set bfd_install_relocation won't + finish the job. Testing for pcrel is a temporary hack. */ + || fixP->fx_pcrel) + { + /* This may seem like overkill, and using bfd_install_relocation or + some such may be preferable, but this is simple. */ + CGEN_FIELDS_BITSIZE (&fields) = CGEN_INSN_BITSIZE (insn); + CGEN_SYM (set_operand) (opindex, &value, &fields); + errmsg = CGEN_SYM (validate_operand) (opindex, &fields); + if (errmsg) + as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg); + CGEN_SYM (insert_operand) (opindex, &fields, where); + } + + if (fixP->fx_done) + return 1; + + /* The operand isn't fully resolved. Determine a BFD reloc value + based on the operand information and leave it to + bfd_install_relocation. Note that this doesn't work when + partial_inplace == false. */ + + reloc_type = CGEN_SYM (lookup_reloc) (insn, operand, fixP); + if (reloc_type != BFD_RELOC_NONE) + { + fixP->fx_r_type = reloc_type; + } + else + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "unresolved expression that must be resolved"); + fixP->fx_done = 1; + return 1; + } + } + else if (fixP->fx_done) + { + /* We're finished with this fixup. Install it because + bfd_install_relocation won't be called to do it. */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + md_number_to_chars (where, value, 1); + break; + case BFD_RELOC_16: + md_number_to_chars (where, value, 2); + break; + case BFD_RELOC_32: + md_number_to_chars (where, value, 4); + break; + /* FIXME: later add support for 64 bits. */ + default: + abort (); + } + } + else + { + /* bfd_install_relocation will be called to finish things up. */ + } + + /* Tuck `value' away for use by tc_gen_reloc. + See the comment describing fx_addnumber in write.h. + This field is misnamed (or misused :-). */ + fixP->fx_addnumber = value; + + return 1; +} + +/* Translate internal representation of relocation info to BFD target format. + + FIXME: To what extent can we get all relevant targets to use this? */ + +arelent * +cgen_tc_gen_reloc (section, fixP) + asection *section; + fixS *fixP; +{ + arelent *reloc; + + reloc = (arelent *) bfd_alloc (stdoutput, sizeof (arelent)); + + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + if (reloc->howto == (reloc_howto_type *) NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "internal error: can't export reloc type %d (`%s')", + fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); + return NULL; + } + + assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); + + reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym; + reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; + reloc->addend = fixP->fx_addnumber; + + return reloc; +} diff --git a/contrib/binutils/gas/cond.c b/contrib/binutils/gas/cond.c new file mode 100644 index 0000000..855848c --- /dev/null +++ b/contrib/binutils/gas/cond.c @@ -0,0 +1,451 @@ +/* cond.c - conditional assembly pseudo-ops, and .include + Copyright (C) 1990, 91, 92, 93, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" +#include "macro.h" + +#include "obstack.h" + +/* This is allocated to grow and shrink as .ifdef/.endif pairs are scanned. */ +struct obstack cond_obstack; + +struct file_line +{ + char *file; + unsigned int line; +}; + +/* We push one of these structures for each .if, and pop it at the + .endif. */ + +struct conditional_frame +{ + /* The source file & line number of the "if". */ + struct file_line if_file_line; + /* The source file & line of the "else". */ + struct file_line else_file_line; + /* The previous conditional. */ + struct conditional_frame *previous_cframe; + /* Have we seen an else yet? */ + int else_seen; + /* Whether we are currently ignoring input. */ + int ignoring; + /* Whether a conditional at a higher level is ignoring input. */ + int dead_tree; + /* Macro nesting level at which this conditional was created. */ + int macro_nest; +}; + +static void initialize_cframe PARAMS ((struct conditional_frame *cframe)); +static char *get_mri_string PARAMS ((int, int *)); + +static struct conditional_frame *current_cframe = NULL; + +void +s_ifdef (arg) + int arg; +{ + register char *name; /* points to name of symbol */ + register struct symbol *symbolP; /* Points to symbol */ + struct conditional_frame cframe; + + SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ + name = input_line_pointer; + + if (!is_name_beginner (*name)) + { + as_bad ("invalid identifier for \".ifdef\""); + obstack_1grow (&cond_obstack, 0); + ignore_rest_of_line (); + } + else + { + char c; + + c = get_symbol_end (); + symbolP = symbol_find (name); + *input_line_pointer = c; + + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || !((symbolP != 0) ^ arg); + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, + sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + demand_empty_rest_of_line (); + } /* if a valid identifyer name */ +} /* s_ifdef() */ + +void +s_if (arg) + int arg; +{ + expressionS operand; + struct conditional_frame cframe; + int t; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ + + if (current_cframe != NULL && current_cframe->ignoring) + { + operand.X_add_number = 0; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + else + { + expression (&operand); + if (operand.X_op != O_constant) + as_bad ("non-constant expression in \".if\" statement"); + } + + switch ((operatorT) arg) + { + case O_eq: t = operand.X_add_number == 0; break; + case O_ne: t = operand.X_add_number != 0; break; + case O_lt: t = operand.X_add_number < 0; break; + case O_le: t = operand.X_add_number <= 0; break; + case O_ge: t = operand.X_add_number >= 0; break; + case O_gt: t = operand.X_add_number > 0; break; + default: + abort (); + } + + /* If the above error is signaled, this will dispatch + using an undefined result. No big deal. */ + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! t; + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} /* s_if() */ + +/* Get a string for the MRI IFC or IFNC pseudo-ops. */ + +static char * +get_mri_string (terminator, len) + int terminator; + int *len; +{ + char *ret; + char *s; + + SKIP_WHITESPACE (); + s = ret = input_line_pointer; + if (*input_line_pointer == '\'') + { + ++s; + ++input_line_pointer; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + { + *s++ = *input_line_pointer++; + if (s[-1] == '\'') + { + if (*input_line_pointer != '\'') + break; + ++input_line_pointer; + } + } + SKIP_WHITESPACE (); + } + else + { + while (*input_line_pointer != terminator + && ! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + s = input_line_pointer; + while (s > ret && (s[-1] == ' ' || s[-1] == '\t')) + --s; + } + + *len = s - ret; + return ret; +} + +/* The MRI IFC and IFNC pseudo-ops. */ + +void +s_ifc (arg) + int arg; +{ + char *stop = NULL; + char stopc; + char *s1, *s2; + int len1, len2; + int res; + struct conditional_frame cframe; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + s1 = get_mri_string (',', &len1); + + if (*input_line_pointer != ',') + as_bad ("bad format for ifc or ifnc"); + else + ++input_line_pointer; + + s2 = get_mri_string (';', &len2); + + res = len1 == len2 && strncmp (s1, s2, len1) == 0; + + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! (res ^ arg); + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +void +s_endif (arg) + int arg; +{ + struct conditional_frame *hold; + + if (current_cframe == NULL) + { + as_bad ("\".endif\" without \".if\""); + } + else + { + if (LISTING_SKIP_COND () + && current_cframe->ignoring + && (current_cframe->previous_cframe == NULL + || ! current_cframe->previous_cframe->ignoring)) + listing_list (1); + + hold = current_cframe; + current_cframe = current_cframe->previous_cframe; + obstack_free (&cond_obstack, hold); + } /* if one pop too many */ + + if (flag_mri) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + + demand_empty_rest_of_line (); +} /* s_endif() */ + +void +s_else (arg) + int arg; +{ + if (current_cframe == NULL) + { + as_bad (".else without matching .if - ignored"); + + } + else if (current_cframe->else_seen) + { + as_bad ("duplicate \"else\" - ignored"); + as_bad_where (current_cframe->else_file_line.file, + current_cframe->else_file_line.line, + "here is the previous \"else\""); + as_bad_where (current_cframe->if_file_line.file, + current_cframe->if_file_line.line, + "here is the previous \"if\""); + } + else + { + as_where (¤t_cframe->else_file_line.file, + ¤t_cframe->else_file_line.line); + + if (!current_cframe->dead_tree) + { + current_cframe->ignoring = !current_cframe->ignoring; + if (LISTING_SKIP_COND () + && ! current_cframe->ignoring) + listing_list (1); + } /* if not a dead tree */ + + current_cframe->else_seen = 1; + } /* if error else do it */ + + if (flag_mri) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + + demand_empty_rest_of_line (); +} /* s_else() */ + +void +s_ifeqs (arg) + int arg; +{ + char *s1, *s2; + int len1, len2; + int res; + struct conditional_frame cframe; + + s1 = demand_copy_C_string (&len1); + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (".ifeqs syntax error"); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + + s2 = demand_copy_C_string (&len2); + + res = len1 == len2 && strncmp (s1, s2, len1) == 0; + + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! (res ^ arg); + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + demand_empty_rest_of_line (); +} /* s_ifeqs() */ + +int +ignore_input () +{ + char *s; + + s = input_line_pointer; + + if (flag_m68k_mri +#ifdef NO_PSEUDO_DOT + || 1 +#endif + ) + { + if (s[-1] != '.') + --s; + } + else + { + if (s[-1] != '.') + return (current_cframe != NULL) && (current_cframe->ignoring); + } + + /* We cannot ignore certain pseudo ops. */ + if (((s[0] == 'i' + || s[0] == 'I') + && (!strncasecmp (s, "if", 2) + || !strncasecmp (s, "ifdef", 5) + || !strncasecmp (s, "ifndef", 6))) + || ((s[0] == 'e' + || s[0] == 'E') + && (!strncasecmp (s, "else", 4) + || !strncasecmp (s, "endif", 5) + || !strncasecmp (s, "endc", 4)))) + return 0; + + return (current_cframe != NULL) && (current_cframe->ignoring); +} /* ignore_input() */ + +static void +initialize_cframe (cframe) + struct conditional_frame *cframe; +{ + memset (cframe, 0, sizeof (*cframe)); + as_where (&cframe->if_file_line.file, + &cframe->if_file_line.line); + cframe->previous_cframe = current_cframe; + cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; + cframe->macro_nest = macro_nest; +} + +/* Give an error if a conditional is unterminated inside a macro or + the assembly as a whole. If NEST is non negative, we are being + called because of the end of a macro expansion. If NEST is + negative, we are being called at the of the input files. */ + +void +cond_finish_check (nest) + int nest; +{ + if (current_cframe != NULL && current_cframe->macro_nest >= nest) + { + as_bad ("end of %s inside conditional", + nest >= 0 ? "macro" : "file"); + as_bad_where (current_cframe->if_file_line.file, + current_cframe->if_file_line.line, + "here is the start of the unterminated conditional"); + if (current_cframe->else_seen) + as_bad_where (current_cframe->else_file_line.file, + current_cframe->else_file_line.line, + "here is the \"else\" of the unterminated conditional"); + } +} + +/* This function is called when we exit out of a macro. We assume + that any conditionals which began within the macro are correctly + nested, and just pop them off the stack. */ + +void +cond_exit_macro (nest) + int nest; +{ + while (current_cframe != NULL && current_cframe->macro_nest >= nest) + { + struct conditional_frame *hold; + + hold = current_cframe; + current_cframe = current_cframe->previous_cframe; + obstack_free (&cond_obstack, hold); + } +} + +/* end of cond.c */ diff --git a/contrib/binutils/gas/conf.in b/contrib/binutils/gas/conf.in new file mode 100644 index 0000000..d56807c --- /dev/null +++ b/contrib/binutils/gas/conf.in @@ -0,0 +1,127 @@ +/* conf.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Should gas use high-level BFD interfaces? */ +#undef BFD_ASSEMBLER + +/* Some assert/preprocessor combinations are incapable of handling + certain kinds of constructs in the argument of assert. For example, + quoted strings (if requoting isn't done right) or newlines. */ +#undef BROKEN_ASSERT + +/* If we aren't doing cross-assembling, some operations can be optimized, + since byte orders and value sizes don't need to be adjusted. */ +#undef CROSS_COMPILE + +/* Some gas code wants to know these parameters. */ +#undef TARGET_ALIAS +#undef TARGET_CPU +#undef TARGET_CANONICAL +#undef TARGET_OS +#undef TARGET_VENDOR + +/* Sometimes the system header files don't declare strstr. */ +#undef NEED_DECLARATION_STRSTR + +/* Sometimes the system header files don't declare malloc and realloc. */ +#undef NEED_DECLARATION_MALLOC + +/* Sometimes the system header files don't declare free. */ +#undef NEED_DECLARATION_FREE + +/* Sometimes the system header files don't declare sbrk. */ +#undef NEED_DECLARATION_SBRK + +/* Sometimes errno.h doesn't declare errno itself. */ +#undef NEED_DECLARATION_ERRNO + +#undef MANY_SEGMENTS + +/* Needed only for sparc configuration. */ +#undef SPARC_V9 +#undef SPARC_ARCH64 + +/* Defined if using CGEN. */ +#undef USING_CGEN + +/* Needed only for some configurations that can produce multiple output + formats. */ +#undef DEFAULT_EMULATION +#undef EMULATIONS +#undef USE_EMULATIONS +#undef OBJ_MAYBE_AOUT +#undef OBJ_MAYBE_BOUT +#undef OBJ_MAYBE_COFF +#undef OBJ_MAYBE_ECOFF +#undef OBJ_MAYBE_ELF +#undef OBJ_MAYBE_GENERIC +#undef OBJ_MAYBE_HP300 +#undef OBJ_MAYBE_IEEE +#undef OBJ_MAYBE_SOM +#undef OBJ_MAYBE_VMS + +/* Used for some of the COFF configurations, when the COFF code needs + to select something based on the CPU type before it knows it... */ +#undef I386COFF +#undef M68KCOFF +#undef M88KCOFF + +/* Define if you have the remove function. */ +#undef HAVE_REMOVE + +/* Define if you have the sbrk function. */ +#undef HAVE_SBRK + +/* Define if you have the unlink function. */ +#undef HAVE_UNLINK + +/* Define if you have the <errno.h> header file. */ +#undef HAVE_ERRNO_H + +/* Define if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the <stdarg.h> header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the <varargs.h> header file. */ +#undef HAVE_VARARGS_H diff --git a/contrib/binutils/gas/config/aout_gnu.h b/contrib/binutils/gas/config/aout_gnu.h new file mode 100644 index 0000000..badf9cb --- /dev/null +++ b/contrib/binutils/gas/config/aout_gnu.h @@ -0,0 +1,455 @@ +/* This file is aout_gnu.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +/* There are two main flavours of a.out, one which uses the standard + relocations, and one which uses extended relocations. + + Today, the extended reloc uses are + TC_SPARC, TC_A29K + + each must define the enum reloc_type + +*/ + +#define USE_EXTENDED_RELOC (defined(TC_SPARC) || defined(TC_A29K)) + +#if defined(TC_SPARC) || defined(TC_A29K) +enum reloc_type + { + RELOC_8, RELOC_16, RELOC_32,/* simple relocations */ + RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */ + RELOC_WDISP30, RELOC_WDISP22, + RELOC_HI22, RELOC_22, + RELOC_13, RELOC_LO10, + RELOC_SFA_BASE, RELOC_SFA_OFF13, + RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */ + RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */ + RELOC_JMP_TBL, /* P.I.C. jump table */ + RELOC_SEGOFF16, /* reputedly for shared libraries somehow */ + RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, + RELOC_10, RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, + RELOC_HLO10, + + /* 29K relocation types */ + RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH, + + RELOC_WDISP14, RELOC_WDISP21, + + NO_RELOC + }; + +#endif /* TC_SPARC or TC_A29K */ + + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +/* This is the layout on disk of a Unix V7, Berkeley, SunOS, Vax Ultrix + "struct exec". Don't assume that on this machine, the "struct exec" + will lay out the same sizes or alignments. */ + +struct exec_bytes + { + unsigned char a_info[4]; + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_syms[4]; + unsigned char a_entry[4]; + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; + }; + +/* How big the "struct exec" is on disk */ +#define EXEC_BYTES_SIZE (8 * 4) + +/* This is the layout in memory of a "struct exec" while we process it. */ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +/* These symbols could be defined by code from Suns...punt 'em */ +#undef M_UNKNOWN +#undef M_68010 +#undef M_68020 +#undef M_SPARC +enum machine_type + { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100, + M_29K = 101, + M_RS6000 = 102, /* IBM RS/6000 */ + /* HP/BSD formats */ + M_HP200 = 200, /* hp200 (68010) BSD binary */ + M_HP300 = 300, /* hp300 (68020+68881) BSD binary */ + M_HPUX23 = 0x020C /* hp200/300 HPUX binary */ + }; + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +/* Code indicating object file or impure executable. */ +#ifndef OMAGIC +#define OMAGIC 0407 +#endif +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 + +/* Virtual Address of text segment from the a.out file. For OMAGIC, + (almost always "unlinked .o's" these days), should be zero. + For linked files, should reflect reality if we know it. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(x) (N_MAGIC(x)==OMAGIC? 0 : TEXT_START_ADDR) +#endif + +#ifndef N_BADMAG +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#endif + +/* By default, segment size is constant. But on some machines, it can + be a function of the a.out header (e.g. machine type). */ +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + +/* This complexity is for encapsulated COFF support */ +#ifndef _N_HDROFF +#define _N_HDROFF(x) (N_SEGSIZE(x) - sizeof (struct exec)) +#endif + +#ifndef N_TXTOFF +#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? \ + _N_HDROFF((x)) + sizeof (struct exec) : \ + sizeof (struct exec)) +#endif + + +#ifndef N_DATOFF +#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#endif + +#ifndef N_DRELOFF +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#endif + +#ifndef N_SYMOFF +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#endif + +#ifndef N_STROFF +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#endif + +/* Address of text segment in memory after it is loaded. */ +#ifndef N_TXTADDR +#define N_TXTADDR(x) 0 +#endif + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+(x).a_text-1) & ~(N_SEGSIZE(x)-1)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +struct nlist + { + union + { + char *n_name; + struct nlist *n_next; + long n_strx; + } + n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; + }; + +#define N_UNDF 0 +#define N_ABS 2 +#define N_TEXT 4 +#define N_DATA 6 +#define N_BSS 8 +#define N_COMM 0x12 /* common (visible in shared lib commons) */ +#define N_FN 0x1F /* File name of a .o file */ + +/* Note: N_EXT can only usefully be OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 +#define N_TYPE 036 +#define N_STAB 0340 + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ + +#define N_INDR 0xa + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Weak symbols. These are a GNU extension to the a.out format. The + semantics are those of ELF weak symbols. Weak symbols are always + externally visible. The N_WEAK? values are squeezed into the + available slots. The value of a N_WEAKU symbol is 0. The values + of the other types are the definitions. */ +#define N_WEAKU 0x0d /* Weak undefined symbol. */ +#define N_WEAKA 0x0e /* Weak absolute symbol. */ +#define N_WEAKT 0x0f /* Weak text symbol. */ +#define N_WEAKD 0x10 /* Weak data symbol. */ +#define N_WEAKB 0x11 /* Weak bss symbol. */ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +/* The following enum and struct were borrowed from SunOS's + /usr/include/sun4/a.out.h and extended to handle + other machines. It is currently used on SPARC and AMD 29000. + + reloc_ext_bytes is how it looks on disk. reloc_info_extended is + how we might process it on a native host. */ +#if USE_EXTENDED_RELOC + +struct reloc_ext_bytes + { + unsigned char r_address[4]; + unsigned char r_index[3]; + unsigned char r_bits[1]; + unsigned char r_addend[4]; + }; + + +#define RELOC_EXT_BITS_EXTERN_BIG 0x80 +#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01 + +#define RELOC_EXT_BITS_TYPE_BIG 0x1F +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8 +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +#define RELOC_EXT_SIZE 12 /* Bytes per relocation entry */ + +struct reloc_info_extended +{ + unsigned long r_address; + unsigned int r_index:24; +# define r_symbolnum r_index + unsigned r_extern:1; + unsigned:2; + /* RS/6000 compiler does not support enum bitfield + enum reloc_type r_type:5; */ + enum reloc_type r_type; + long int r_addend; +}; + +#else + +/* The standard, old-fashioned, Berkeley compatible relocation struct */ + + + +#ifdef TC_I860 +/* NOTE: three bits max, see struct reloc_info_i860.r_type */ +enum i860_reloc_type + { + NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32, + }; + +typedef enum i860_reloc_type reloc_type; + +/* NOTE: two bits max, see reloc_info_i860.r_type */ +enum highlow_type + { + NO_SPEC = 0, PAIR, HIGH, HIGHADJ, + }; + + +struct reloc_info_i860 +{ + unsigned long r_address; + /* + * Using bit fields here is a bad idea because the order is not portable. :-( + */ + unsigned int r_symbolnum:24; + unsigned int r_pcrel:1; + unsigned int r_extern:1; + /* combining the two field simplifies the argument passing in "new_fix()" */ + /* and is compatible with the existing Sparc #ifdef's */ + /* r_type: highlow_type - bits 5,4; reloc_type - bits 3-0 */ + unsigned int r_type:6; + long r_addend; +}; + +#endif /* TC_I860 */ + + +struct reloc_std_bytes + { + unsigned char r_address[4]; + unsigned char r_index[3]; + unsigned char r_bits[1]; + }; + +#define RELOC_STD_BITS_PCREL_BIG 0x80 +#define RELOC_STD_BITS_PCREL_LITTLE 0x01 + +#define RELOC_STD_BITS_LENGTH_BIG 0x60 +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */ +#define RELOC_STD_BITS_LENGTH_LITTLE 0x06 +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG 0x10 +#define RELOC_STD_BITS_EXTERN_LITTLE 0x08 + +#define RELOC_STD_BITS_BASEREL_BIG 0x08 +#define RELOC_STD_BITS_BASEREL_LITTLE 0x08 + +#define RELOC_STD_BITS_JMPTABLE_BIG 0x04 +#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04 + +#define RELOC_STD_BITS_RELATIVE_BIG 0x02 +#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02 + +#define RELOC_STD_SIZE 8 /* Bytes per relocation entry */ + +#endif /* USE_EXTENDED_RELOC */ + +#ifndef CUSTOM_RELOC_FORMAT +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ +#ifdef TC_NS32K + unsigned int r_bsr:1; + unsigned int r_disp:2; +#else + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + unsigned int r_relative:1; /* "relative relocation" */ +#endif /* TC_NS32K */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; + +#endif /* CUSTOM_RELOC_FORMAT */ + +#endif /* __A_OUT_GNU_H__ */ + +/* end of aout_gnu.h */ diff --git a/contrib/binutils/gas/config/atof-ieee.c b/contrib/binutils/gas/config/atof-ieee.c new file mode 100644 index 0000000..e0726b7 --- /dev/null +++ b/contrib/binutils/gas/config/atof-ieee.c @@ -0,0 +1,679 @@ +/* atof_ieee.c - turn a Flonum into an IEEE floating point number + Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +/* Flonums returned here. */ +extern FLONUM_TYPE generic_floating_point_number; + +static int next_bits PARAMS ((int)); +static void unget_bits PARAMS ((int)); +static void make_invalid_floating_point_number PARAMS ((LITTLENUM_TYPE *)); + +extern const char EXP_CHARS[]; +/* Precision in LittleNums. */ +/* Don't count the gap in the m68k extended precision format. */ +#define MAX_PRECISION (5) +#define F_PRECISION (2) +#define D_PRECISION (4) +#define X_PRECISION (5) +#define P_PRECISION (5) + +/* Length in LittleNums of guard bits. */ +#define GUARD (2) + +static const unsigned long mask[] = +{ + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff, +}; + + +static int bits_left_in_littlenum; +static int littlenums_left; +static LITTLENUM_TYPE *littlenum_pointer; + +static int +next_bits (number_of_bits) + int number_of_bits; +{ + int return_value; + + if (!littlenums_left) + return (0); + if (number_of_bits >= bits_left_in_littlenum) + { + return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + + if (--littlenums_left) + { + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + --littlenum_pointer; + return_value |= (*littlenum_pointer >> bits_left_in_littlenum) & mask[number_of_bits]; + } + } + else + { + bits_left_in_littlenum -= number_of_bits; + return_value = mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum); + } + return (return_value); +} + +/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */ +static void +unget_bits (num) + int num; +{ + if (!littlenums_left) + { + ++littlenum_pointer; + ++littlenums_left; + bits_left_in_littlenum = num; + } + else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS) + { + bits_left_in_littlenum = num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum); + ++littlenum_pointer; + ++littlenums_left; + } + else + bits_left_in_littlenum += num; +} + +static void +make_invalid_floating_point_number (words) + LITTLENUM_TYPE *words; +{ + as_bad ("cannot create floating-point number"); + words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1; /* Zero the leftmost bit */ + words[1] = (LITTLENUM_TYPE) -1; + words[2] = (LITTLENUM_TYPE) -1; + words[3] = (LITTLENUM_TYPE) -1; + words[4] = (LITTLENUM_TYPE) -1; + words[5] = (LITTLENUM_TYPE) -1; +} + +/************************************************************************\ + * Warning: this returns 16-bit LITTLENUMs. It is up to the caller * + * to figure out any alignment problems and to conspire for the * + * bytes/word to be emitted in the right order. Bigendians beware! * + * * +\************************************************************************/ + +/* Note that atof-ieee always has X and P precisions enabled. it is up + to md_atof to filter them out if the target machine does not support + them. */ + +/* Returns pointer past text consumed. */ +char * +atof_ieee (str, what_kind, words) + char *str; /* Text to convert to binary. */ + char what_kind; /* 'd', 'f', 'g', 'h' */ + LITTLENUM_TYPE *words; /* Build the binary here. */ +{ + /* Extra bits for zeroed low-order bits. The 1st MAX_PRECISION are + zeroed, the last contain flonum bits. */ + static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; + char *return_value; + /* Number of 16-bit words in the format. */ + int precision; + long exponent_bits; + FLONUM_TYPE save_gen_flonum; + + /* We have to save the generic_floating_point_number because it + contains storage allocation about the array of LITTLENUMs where + the value is actually stored. We will allocate our own array of + littlenums below, but have to restore the global one on exit. */ + save_gen_flonum = generic_floating_point_number; + + return_value = str; + generic_floating_point_number.low = bits + MAX_PRECISION; + generic_floating_point_number.high = NULL; + generic_floating_point_number.leader = NULL; + generic_floating_point_number.exponent = 0; + generic_floating_point_number.sign = '\0'; + + /* Use more LittleNums than seems necessary: the highest flonum may + have 15 leading 0 bits, so could be useless. */ + + memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); + + switch (what_kind) + { + case 'f': + case 'F': + case 's': + case 'S': + precision = F_PRECISION; + exponent_bits = 8; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + precision = D_PRECISION; + exponent_bits = 11; + break; + + case 'x': + case 'X': + case 'e': + case 'E': + precision = X_PRECISION; + exponent_bits = 15; + break; + + case 'p': + case 'P': + + precision = P_PRECISION; + exponent_bits = -1; + break; + + default: + make_invalid_floating_point_number (words); + return (NULL); + } + + generic_floating_point_number.high + = generic_floating_point_number.low + precision - 1 + GUARD; + + if (atof_generic (&return_value, ".", EXP_CHARS, + &generic_floating_point_number)) + { + make_invalid_floating_point_number (words); + return (NULL); + } + gen_to_words (words, precision, exponent_bits); + + /* Restore the generic_floating_point_number's storage alloc (and + everything else). */ + generic_floating_point_number = save_gen_flonum; + + return return_value; +} + +/* Turn generic_floating_point_number into a real float/double/extended. */ +int +gen_to_words (words, precision, exponent_bits) + LITTLENUM_TYPE *words; + int precision; + long exponent_bits; +{ + int return_value = 0; + + long exponent_1; + long exponent_2; + long exponent_3; + long exponent_4; + int exponent_skippage; + LITTLENUM_TYPE word1; + LITTLENUM_TYPE *lp; + LITTLENUM_TYPE *words_end; + + words_end = words + precision; +#ifdef TC_M68K + if (precision == X_PRECISION) + /* On the m68k the extended precision format has a gap of 16 bits + between the exponent and the mantissa. */ + words_end++; +#endif + + if (generic_floating_point_number.low > generic_floating_point_number.leader) + { + /* 0.0e0 seen. */ + if (generic_floating_point_number.sign == '+') + words[0] = 0x0000; + else + words[0] = 0x8000; + memset (&words[1], '\0', + (words_end - words - 1) * sizeof (LITTLENUM_TYPE)); + return (return_value); + } + + /* NaN: Do the right thing */ + if (generic_floating_point_number.sign == 0) + { + if (precision == F_PRECISION) + { + words[0] = 0x7fff; + words[1] = 0xffff; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0x7fff; + words[1] = 0; + words[2] = 0xffff; + words[3] = 0xffff; + words[4] = 0xffff; + words[5] = 0xffff; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0xffff; + words[1] = 0xc000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0x7fff; + words[1] = 0xffff; + words[2] = 0xffff; + words[3] = 0xffff; + } + return return_value; + } + else if (generic_floating_point_number.sign == 'P') + { + /* +INF: Do the right thing */ + if (precision == F_PRECISION) + { + words[0] = 0x7f80; + words[1] = 0; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0x7fff; + words[1] = 0; + words[2] = 0; + words[3] = 0; + words[4] = 0; + words[5] = 0; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0x7fff; + words[1] = 0x8000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0x7ff0; + words[1] = 0; + words[2] = 0; + words[3] = 0; + } + return (return_value); + } + else if (generic_floating_point_number.sign == 'N') + { + /* Negative INF */ + if (precision == F_PRECISION) + { + words[0] = 0xff80; + words[1] = 0x0; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0xffff; + words[1] = 0; + words[2] = 0; + words[3] = 0; + words[4] = 0; + words[5] = 0; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0xffff; + words[1] = 0x8000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0xfff0; + words[1] = 0x0; + words[2] = 0x0; + words[3] = 0x0; + } + return (return_value); + } + /* + * The floating point formats we support have: + * Bit 15 is sign bit. + * Bits 14:n are excess-whatever exponent. + * Bits n-1:0 (if any) are most significant bits of fraction. + * Bits 15:0 of the next word(s) are the next most significant bits. + * + * So we need: number of bits of exponent, number of bits of + * mantissa. + */ + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = generic_floating_point_number.leader; + littlenums_left = (1 + + generic_floating_point_number.leader + - generic_floating_point_number.low); + /* Seek (and forget) 1st significant bit */ + for (exponent_skippage = 0; !next_bits (1); ++exponent_skippage);; + exponent_1 = (generic_floating_point_number.exponent + + generic_floating_point_number.leader + + 1 + - generic_floating_point_number.low); + /* Radix LITTLENUM_RADIX, point just higher than + generic_floating_point_number.leader. */ + exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; + /* Radix 2. */ + exponent_3 = exponent_2 - exponent_skippage; + /* Forget leading zeros, forget 1st bit. */ + exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2); + /* Offset exponent. */ + + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + word1 = ((generic_floating_point_number.sign == '+') + ? 0 + : (1 << (LITTLENUM_NUMBER_OF_BITS - 1))); + + /* Assume 2's complement integers. */ + if (exponent_4 <= 0) + { + int prec_bits; + int num_bits; + + unget_bits (1); + num_bits = -exponent_4; + prec_bits = LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits); +#ifdef TC_I386 + if (precision == X_PRECISION && exponent_bits == 15) + { + /* On the i386 a denormalized extended precision float is + shifted down by one, effectively decreasing the exponent + bias by one. */ + prec_bits -= 1; + num_bits += 1; + } +#endif + + if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits) + { + /* Bigger than one littlenum */ + num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits; + *lp++ = word1; + if (num_bits + exponent_bits + 1 >= precision * LITTLENUM_NUMBER_OF_BITS) + { + /* Exponent overflow */ + make_invalid_floating_point_number (words); + return (return_value); + } +#ifdef TC_M68K + if (precision == X_PRECISION && exponent_bits == 15) + *lp++ = 0; +#endif + while (num_bits >= LITTLENUM_NUMBER_OF_BITS) + { + num_bits -= LITTLENUM_NUMBER_OF_BITS; + *lp++ = 0; + } + if (num_bits) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - (num_bits)); + } + else + { + if (precision == X_PRECISION && exponent_bits == 15) + { + *lp++ = word1; +#ifdef TC_M68K + *lp++ = 0; +#endif + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - num_bits); + } + else + { + word1 |= next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - (exponent_bits + num_bits)); + *lp++ = word1; + } + } + while (lp < words_end) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); + + /* Round the mantissa up, but don't change the number */ + if (next_bits (1)) + { + --lp; + if (prec_bits > LITTLENUM_NUMBER_OF_BITS) + { + int n = 0; + int tmp_bits; + + n = 0; + tmp_bits = prec_bits; + while (tmp_bits > LITTLENUM_NUMBER_OF_BITS) + { + if (lp[n] != (LITTLENUM_TYPE) - 1) + break; + --n; + tmp_bits -= LITTLENUM_NUMBER_OF_BITS; + } + if (tmp_bits > LITTLENUM_NUMBER_OF_BITS || (lp[n] & mask[tmp_bits]) != mask[tmp_bits]) + { + unsigned long carry; + + for (carry = 1; carry && (lp >= words); lp--) + { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + } + } + else if ((*lp & mask[prec_bits]) != mask[prec_bits]) + *lp += 1; + } + + return return_value; + } + else if (exponent_4 >= mask[exponent_bits]) + { + /* + * Exponent overflow. Lose immediately. + */ + + /* + * We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + make_invalid_floating_point_number (words); + return return_value; + } + else + { + word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits)) + | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits); + } + + *lp++ = word1; + + /* X_PRECISION is special: on the 68k, it has 16 bits of zero in the + middle. Either way, it is then followed by a 1 bit. */ + if (exponent_bits == 15 && precision == X_PRECISION) + { +#ifdef TC_M68K + *lp++ = 0; +#endif + *lp++ = (1 << (LITTLENUM_NUMBER_OF_BITS - 1) + | next_bits (LITTLENUM_NUMBER_OF_BITS - 1)); + } + + /* The rest of the words are just mantissa bits. */ + while (lp < words_end) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); + + if (next_bits (1)) + { + unsigned long carry; + /* + * Since the NEXT bit is a 1, round UP the mantissa. + * The cunning design of these hidden-1 floats permits + * us to let the mantissa overflow into the exponent, and + * it 'does the right thing'. However, we lose if the + * highest-order bit of the lowest-order word flips. + * Is that clear? + */ + + /* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) + Please allow at least 1 more bit in carry than is in a LITTLENUM. + We need that extra bit to hold a carry during a LITTLENUM carry + propagation. Another extra bit (kept 0) will assure us that we + don't get a sticky sign bit after shifting right, and that + permits us to propagate the carry without any masking of bits. + #endif */ + for (carry = 1, lp--; carry && (lp >= words); lp--) + { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + if (precision == X_PRECISION && exponent_bits == 15) + { + /* Extended precision numbers have an explicit integer bit + that we may have to restore. */ + if (lp == words) + { +#ifdef TC_M68K + /* On the m68k there is a gap of 16 bits. We must + explicitly propagate the carry into the exponent. */ + words[0] += words[1]; + words[1] = 0; + lp++; +#endif + /* Put back the integer bit. */ + lp[1] |= 1 << (LITTLENUM_NUMBER_OF_BITS - 1); + } + } + if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) + { + /* We leave return_value alone: admit we read the + * number, but return a floating exception + * because we can't encode the number. + */ + *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1)); + /* make_invalid_floating_point_number (words); */ + /* return return_value; */ + } + } + return (return_value); +} + +#if 0 /* unused */ +/* This routine is a real kludge. Someone really should do it better, + but I'm too lazy, and I don't understand this stuff all too well + anyway. (JF) */ +static void +int_to_gen (x) + long x; +{ + char buf[20]; + char *bufp; + + sprintf (buf, "%ld", x); + bufp = &buf[0]; + if (atof_generic (&bufp, ".", EXP_CHARS, &generic_floating_point_number)) + as_bad ("Error converting number to floating point (Exponent overflow?)"); +} +#endif + +#ifdef TEST +char * +print_gen (gen) + FLONUM_TYPE *gen; +{ + FLONUM_TYPE f; + LITTLENUM_TYPE arr[10]; + double dv; + float fv; + static char sbuf[40]; + + if (gen) + { + f = generic_floating_point_number; + generic_floating_point_number = *gen; + } + gen_to_words (&arr[0], 4, 11); + memcpy (&dv, &arr[0], sizeof (double)); + sprintf (sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv); + gen_to_words (&arr[0], 2, 8); + memcpy (&fv, &arr[0], sizeof (float)); + sprintf (sbuf + strlen (sbuf), "%x %x %.12g\n", arr[0], arr[1], fv); + + if (gen) + { + generic_floating_point_number = f; + } + + return (sbuf); +} + +#endif + +/* end of atof-ieee.c */ diff --git a/contrib/binutils/gas/config/e-i386coff.c b/contrib/binutils/gas/config/e-i386coff.c new file mode 100644 index 0000000..afed728 --- /dev/null +++ b/contrib/binutils/gas/config/e-i386coff.c @@ -0,0 +1,17 @@ +#include "as.h" +#include "emul.h" + +static const char * +i386coff_bfd_name () +{ + abort (); + return NULL; +} + +#define emul_bfd_name i386coff_bfd_name +#define emul_format &coff_format_ops + +#define emul_name "i386coff" +#define emul_struct_name i386coff +#define emul_default_endian 0 +#include "emul-target.h" diff --git a/contrib/binutils/gas/config/e-i386elf.c b/contrib/binutils/gas/config/e-i386elf.c new file mode 100644 index 0000000..a16701e --- /dev/null +++ b/contrib/binutils/gas/config/e-i386elf.c @@ -0,0 +1,17 @@ +#include "as.h" +#include "emul.h" + +static const char * +i386elf_bfd_name () +{ + abort (); + return NULL; +} + +#define emul_bfd_name i386elf_bfd_name +#define emul_format &elf_format_ops + +#define emul_name "i386elf" +#define emul_struct_name i386elf +#define emul_default_endian 0 +#include "emul-target.h" diff --git a/contrib/binutils/gas/config/i386coff.mt b/contrib/binutils/gas/config/i386coff.mt new file mode 100644 index 0000000..efda833 --- /dev/null +++ b/contrib/binutils/gas/config/i386coff.mt @@ -0,0 +1 @@ +TDEFINES=-DI386COFF diff --git a/contrib/binutils/gas/config/obj-aout.c b/contrib/binutils/gas/config/obj-aout.c new file mode 100644 index 0000000..bb566e1 --- /dev/null +++ b/contrib/binutils/gas/config/obj-aout.c @@ -0,0 +1,629 @@ +/* a.out object file format + Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, +or (at your option) any later version. + +GAS is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "as.h" +#ifdef BFD_ASSEMBLER +#undef NO_RELOC +#include "aout/aout64.h" +#endif +#include "obstack.h" + +#ifndef BFD_ASSEMBLER +/* in: segT out: N_TYPE bits */ +const short seg_N_TYPE[] = +{ + N_ABS, + N_TEXT, + N_DATA, + N_BSS, + N_UNDF, /* unknown */ + N_UNDF, /* error */ + N_UNDF, /* expression */ + N_UNDF, /* debug */ + N_UNDF, /* ntv */ + N_UNDF, /* ptv */ + N_REGISTER, /* register */ +}; + +const segT N_TYPE_seg[N_TYPE + 2] = +{ /* N_TYPE == 0x1E = 32-2 */ + SEG_UNKNOWN, /* N_UNDF == 0 */ + SEG_GOOF, + SEG_ABSOLUTE, /* N_ABS == 2 */ + SEG_GOOF, + SEG_TEXT, /* N_TEXT == 4 */ + SEG_GOOF, + SEG_DATA, /* N_DATA == 6 */ + SEG_GOOF, + SEG_BSS, /* N_BSS == 8 */ + SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, + SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ + SEG_GOOF, +}; +#endif + +static void obj_aout_line PARAMS ((int)); +static void obj_aout_weak PARAMS ((int)); +static void obj_aout_type PARAMS ((int)); + +const pseudo_typeS obj_pseudo_table[] = +{ + {"line", obj_aout_line, 0}, /* source code line number */ + {"ln", obj_aout_line, 0}, /* coff line number that we use anyway */ + + {"weak", obj_aout_weak, 0}, /* mark symbol as weak. */ + + {"type", obj_aout_type, 0}, + + /* coff debug pseudos (ignored) */ + {"def", s_ignore, 0}, + {"dim", s_ignore, 0}, + {"endef", s_ignore, 0}, + {"ident", s_ignore, 0}, + {"line", s_ignore, 0}, + {"ln", s_ignore, 0}, + {"scl", s_ignore, 0}, + {"size", s_ignore, 0}, + {"tag", s_ignore, 0}, + {"val", s_ignore, 0}, + {"version", s_ignore, 0}, + + {"optim", s_ignore, 0}, /* For sun386i cc (?) */ + + /* other stuff */ + {"ABORT", s_abort, 0}, + + {NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + + +#ifdef BFD_ASSEMBLER + +void +obj_aout_frob_symbol (sym, punt) + symbolS *sym; + int *punt; +{ + flagword flags; + asection *sec; + int desc, type, other; + + flags = sym->bsym->flags; + desc = S_GET_DESC (sym); + type = S_GET_TYPE (sym); + other = S_GET_OTHER (sym); + sec = sym->bsym->section; + + /* Only frob simple symbols this way right now. */ + if (! (type & ~ (N_TYPE | N_EXT))) + { + if (type == (N_UNDF | N_EXT) + && sec == &bfd_abs_section) + sym->bsym->section = sec = bfd_und_section_ptr; + + if ((type & N_TYPE) != N_INDR + && (type & N_TYPE) != N_SETA + && (type & N_TYPE) != N_SETT + && (type & N_TYPE) != N_SETD + && (type & N_TYPE) != N_SETB + && type != N_WARNING + && (sec == &bfd_abs_section + || sec == &bfd_und_section)) + return; + if (flags & BSF_EXPORT) + type |= N_EXT; + + switch (type & N_TYPE) + { + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + /* Set the debugging flag for constructor symbols so that + BFD leaves them alone. */ + sym->bsym->flags |= BSF_DEBUGGING; + + /* You can't put a common symbol in a set. The way a set + element works is that the symbol has a definition and a + name, and the linker adds the definition to the set of + that name. That does not work for a common symbol, + because the linker can't tell which common symbol the + user means. FIXME: Using as_bad here may be + inappropriate, since the user may want to force a + particular type without regard to the semantics of sets; + on the other hand, we certainly don't want anybody to be + mislead into thinking that their code will work. */ + if (S_IS_COMMON (sym)) + as_bad ("Attempt to put a common symbol into set %s", + S_GET_NAME (sym)); + /* Similarly, you can't put an undefined symbol in a set. */ + else if (! S_IS_DEFINED (sym)) + as_bad ("Attempt to put an undefined symbol into set %s", + S_GET_NAME (sym)); + + break; + case N_INDR: + /* Put indirect symbols in the indirect section. */ + sym->bsym->section = bfd_ind_section_ptr; + sym->bsym->flags |= BSF_INDIRECT; + if (type & N_EXT) + { + sym->bsym->flags |= BSF_EXPORT; + sym->bsym->flags &=~ BSF_LOCAL; + } + break; + case N_WARNING: + /* Mark warning symbols. */ + sym->bsym->flags |= BSF_WARNING; + break; + } + } + else + { + sym->bsym->flags |= BSF_DEBUGGING; + } + + S_SET_TYPE (sym, type); + + /* Double check weak symbols. */ + if (sym->bsym->flags & BSF_WEAK) + { + if (S_IS_COMMON (sym)) + as_bad ("Symbol `%s' can not be both weak and common", + S_GET_NAME (sym)); + } +} + +void +obj_aout_frob_file () +{ + /* Relocation processing may require knowing the VMAs of the sections. + Since writing to a section will cause the BFD back end to compute the + VMAs, fake it out here.... */ + bfd_byte b = 0; + boolean x = true; + if (bfd_section_size (stdoutput, text_section) != 0) + { + x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0, + (bfd_size_type) 1); + } + else if (bfd_section_size (stdoutput, data_section) != 0) + { + x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0, + (bfd_size_type) 1); + } + assert (x == true); +} + +#else + +/* Relocation. */ + +/* + * emit_relocations() + * + * Crawl along a fixS chain. Emit the segment's relocations. + */ +void +obj_emit_relocations (where, fixP, segment_address_in_file) + char **where; + fixS *fixP; /* Fixup chain for this segment. */ + relax_addressT segment_address_in_file; +{ + for (; fixP; fixP = fixP->fx_next) + if (fixP->fx_done == 0) + { + symbolS *sym; + + sym = fixP->fx_addsy; + while (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + sym = sym->sy_value.X_add_symbol; + fixP->fx_addsy = sym; + + if (! sym->sy_resolved && ! S_IS_DEFINED (sym)) + { + char *file; + unsigned int line; + + if (expr_symbol_where (sym, &file, &line)) + as_bad_where (file, line, "unresolved relocation"); + else + as_bad ("bad relocation: symbol `%s' not in symbol table", + S_GET_NAME (sym)); + } + + tc_aout_fix_to_chars (*where, fixP, segment_address_in_file); + *where += md_reloc_size; + } +} + +#ifndef obj_header_append +/* Aout file generation & utilities */ +void +obj_header_append (where, headers) + char **where; + object_headers *headers; +{ + tc_headers_hook (headers); + +#ifdef CROSS_COMPILE + md_number_to_chars (*where, headers->header.a_info, sizeof (headers->header.a_info)); + *where += sizeof (headers->header.a_info); + md_number_to_chars (*where, headers->header.a_text, sizeof (headers->header.a_text)); + *where += sizeof (headers->header.a_text); + md_number_to_chars (*where, headers->header.a_data, sizeof (headers->header.a_data)); + *where += sizeof (headers->header.a_data); + md_number_to_chars (*where, headers->header.a_bss, sizeof (headers->header.a_bss)); + *where += sizeof (headers->header.a_bss); + md_number_to_chars (*where, headers->header.a_syms, sizeof (headers->header.a_syms)); + *where += sizeof (headers->header.a_syms); + md_number_to_chars (*where, headers->header.a_entry, sizeof (headers->header.a_entry)); + *where += sizeof (headers->header.a_entry); + md_number_to_chars (*where, headers->header.a_trsize, sizeof (headers->header.a_trsize)); + *where += sizeof (headers->header.a_trsize); + md_number_to_chars (*where, headers->header.a_drsize, sizeof (headers->header.a_drsize)); + *where += sizeof (headers->header.a_drsize); + +#else /* CROSS_COMPILE */ + + append (where, (char *) &headers->header, sizeof (headers->header)); +#endif /* CROSS_COMPILE */ + +} +#endif + +void +obj_symbol_to_chars (where, symbolP) + char **where; + symbolS *symbolP; +{ + md_number_to_chars ((char *) &(S_GET_OFFSET (symbolP)), S_GET_OFFSET (symbolP), sizeof (S_GET_OFFSET (symbolP))); + md_number_to_chars ((char *) &(S_GET_DESC (symbolP)), S_GET_DESC (symbolP), sizeof (S_GET_DESC (symbolP))); + md_number_to_chars ((char *) &(symbolP->sy_symbol.n_value), S_GET_VALUE (symbolP), sizeof (symbolP->sy_symbol.n_value)); + + append (where, (char *) &symbolP->sy_symbol, sizeof (obj_symbol_type)); +} + +void +obj_emit_symbols (where, symbol_rootP) + char **where; + symbolS *symbol_rootP; +{ + symbolS *symbolP; + + /* Emit all symbols left in the symbol chain. */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + register char *temp; + + temp = S_GET_NAME (symbolP); + S_SET_OFFSET (symbolP, symbolP->sy_name_offset); + + /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */ + if (!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP)) + S_SET_EXTERNAL (symbolP); + + /* Adjust the type of a weak symbol. */ + if (S_GET_WEAK (symbolP)) + { + switch (S_GET_TYPE (symbolP)) + { + case N_UNDF: S_SET_TYPE (symbolP, N_WEAKU); break; + case N_ABS: S_SET_TYPE (symbolP, N_WEAKA); break; + case N_TEXT: S_SET_TYPE (symbolP, N_WEAKT); break; + case N_DATA: S_SET_TYPE (symbolP, N_WEAKD); break; + case N_BSS: S_SET_TYPE (symbolP, N_WEAKB); break; + default: as_bad ("%s: bad type for weak symbol", temp); break; + } + } + + obj_symbol_to_chars (where, symbolP); + S_SET_NAME (symbolP, temp); + } +} + +#endif /* ! BFD_ASSEMBLER */ + +static void +obj_aout_line (ignore) + int ignore; +{ + /* Assume delimiter is part of expression. + BSD4.2 as fails with delightful bug, so we + are not being incompatible here. */ + new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); + demand_empty_rest_of_line (); +} /* obj_aout_line() */ + +/* Handle .weak. This is a GNU extension. */ + +static void +obj_aout_weak (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolP; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_SET_WEAK (symbolP); + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +/* Handle .type. On {Net,Open}BSD, this is used to set the n_other field, + which is then apparently used when doing dynamic linking. Older + versions ogas ignored the .type pseudo-op, so we also ignore it if + we can't parse it. */ + +static void +obj_aout_type (ignore) + int ignore; +{ + char *name; + int c; + symbolS *sym; + + name = input_line_pointer; + c = get_symbol_end (); + sym = symbol_find (name); + *input_line_pointer = c; + if (sym != NULL) + { + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + if (*input_line_pointer == '@') + { + ++input_line_pointer; + if (strncmp (input_line_pointer, "object", 6) == 0) + S_SET_OTHER (sym, 1); + else if (strncmp (input_line_pointer, "function", 8) == 0) + S_SET_OTHER (sym, 2); + } + } + } + + /* Ignore everything else on the line. */ + s_ignore (0); +} + +void +obj_read_begin_hook () +{ +} + +#ifndef BFD_ASSEMBLER + +void +obj_crawl_symbol_chain (headers) + object_headers *headers; +{ + symbolS *symbolP; + symbolS **symbolPP; + int symbol_number = 0; + + tc_crawl_symbol_chain (headers); + + symbolPP = &symbol_rootP; /*->last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + if (symbolP->sy_mri_common) + { + if (S_IS_EXTERNAL (symbolP)) + as_bad ("%s: global symbols not supported in common sections", + S_GET_NAME (symbolP)); + *symbolPP = symbol_next (symbolP); + continue; + } + + if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_DATA)) + { + S_SET_SEGMENT (symbolP, SEG_TEXT); + } /* if pusing data into text */ + + resolve_symbol_value (symbolP); + + /* Skip symbols which were equated to undefined or common + symbols. */ + if (symbolP->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))) + { + *symbolPP = symbol_next (symbolP); + continue; + } + + /* OK, here is how we decide which symbols go out into the brave + new symtab. Symbols that do are: + + * symbols with no name (stabd's?) + * symbols with debug info in their N_TYPE + + Symbols that don't are: + * symbols that are registers + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" as defined by S_LOCAL_NAME(name) if the -L + switch was passed to gas. + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + + if (!S_IS_REGISTER (symbolP) + && (!S_GET_NAME (symbolP) + || S_IS_DEBUG (symbolP) + || !S_IS_DEFINED (symbolP) + || S_IS_EXTERNAL (symbolP) + || (S_GET_NAME (symbolP)[0] != '\001' + && (flag_keep_locals || !S_LOCAL_NAME (symbolP))))) + { + symbolP->sy_number = symbol_number++; + + /* The + 1 after strlen account for the \0 at the + end of each string */ + if (!S_IS_STABD (symbolP)) + { + /* Ordinary case. */ + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen (S_GET_NAME (symbolP)) + 1; + } + else /* .Stabd case. */ + symbolP->sy_name_offset = 0; + symbolPP = &(symbol_next (symbolP)); + } + else + { + if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) + /* This warning should never get triggered any more. + Well, maybe if you're doing twisted things with + register names... */ + { + as_bad ("Local symbol %s never defined.", decode_local_label_name (S_GET_NAME (symbolP))); + } /* oops. */ + + /* Unhook it from the chain */ + *symbolPP = symbol_next (symbolP); + } /* if this symbol should be in the output */ + } /* for each symbol */ + + H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); +} + +/* + * Find strings by crawling along symbol table chain. + */ + +void +obj_emit_strings (where) + char **where; +{ + symbolS *symbolP; + +#ifdef CROSS_COMPILE + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars (*where, string_byte_count, sizeof (string_byte_count)); + *where += sizeof (string_byte_count); +#else /* CROSS_COMPILE */ + append (where, (char *) &string_byte_count, (unsigned long) sizeof (string_byte_count)); +#endif /* CROSS_COMPILE */ + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + if (S_GET_NAME (symbolP)) + append (&next_object_file_charP, S_GET_NAME (symbolP), + (unsigned long) (strlen (S_GET_NAME (symbolP)) + 1)); + } /* walk symbol chain */ +} + +#ifndef AOUT_VERSION +#define AOUT_VERSION 0 +#endif + +void +obj_pre_write_hook (headers) + object_headers *headers; +{ + H_SET_DYNAMIC (headers, 0); + H_SET_VERSION (headers, AOUT_VERSION); + H_SET_MACHTYPE (headers, AOUT_MACHTYPE); + tc_aout_pre_write_hook (headers); +} + +void +DEFUN_VOID (s_sect) +{ + /* Strip out the section name */ + char *section_name; + char *section_name_end; + char c; + + unsigned int len; + unsigned int exp; + char *save; + + section_name = input_line_pointer; + c = get_symbol_end (); + section_name_end = input_line_pointer; + + len = section_name_end - section_name; + input_line_pointer++; + save = input_line_pointer; + + SKIP_WHITESPACE (); + if (c == ',') + { + exp = get_absolute_expression (); + } + else if (*input_line_pointer == ',') + { + input_line_pointer++; + exp = get_absolute_expression (); + } + else + { + input_line_pointer = save; + exp = 0; + } + if (exp >= 1000) + { + as_bad ("subsegment index too high"); + } + + if (strcmp (section_name, ".text") == 0) + { + subseg_set (SEG_TEXT, (subsegT) exp); + } + + if (strcmp (section_name, ".data") == 0) + { + if (flag_readonly_data_in_text) + subseg_set (SEG_TEXT, (subsegT) exp + 1000); + else + subseg_set (SEG_DATA, (subsegT) exp); + } + + *section_name_end = c; +} + +#endif /* ! BFD_ASSEMBLER */ + +/* end of obj-aout.c */ diff --git a/contrib/binutils/gas/config/obj-aout.h b/contrib/binutils/gas/config/obj-aout.h new file mode 100644 index 0000000..ab47ab6 --- /dev/null +++ b/contrib/binutils/gas/config/obj-aout.h @@ -0,0 +1,235 @@ +/* obj-aout.h, a.out object file format for gas, the assembler. + Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Tag to validate a.out object file format processing */ +#define OBJ_AOUT 1 + +#include "targ-cpu.h" + +#ifdef BFD_ASSEMBLER + +#include "bfd/libaout.h" + +#define OUTPUT_FLAVOR bfd_target_aout_flavour + +#else /* ! BFD_ASSEMBLER */ + +#ifndef VMS +#include "aout_gnu.h" /* Needed to define struct nlist. Sigh. */ +#else +#include "a_out.h" +#endif + +#ifndef AOUT_MACHTYPE +#define AOUT_MACHTYPE 0 +#endif /* AOUT_MACHTYPE */ + +extern const short seg_N_TYPE[]; +extern const segT N_TYPE_seg[]; + +#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC) +#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */ + +#endif /* ! BFD_ASSEMBLER */ + +/* SYMBOL TABLE */ +/* Symbol table entry data type */ + +typedef struct nlist obj_symbol_type; /* Symbol table entry */ + +/* Symbol table macros and constants */ + +#ifdef BFD_ASSEMBLER + +#define S_SET_OTHER(S,V) (aout_symbol((S)->bsym)->other = (V)) +#define S_SET_TYPE(S,T) (aout_symbol((S)->bsym)->type = (T)) +#define S_SET_DESC(S,D) (aout_symbol((S)->bsym)->desc = (D)) +#define S_GET_OTHER(S) (aout_symbol((S)->bsym)->other) +#define S_GET_TYPE(S) (aout_symbol((S)->bsym)->type) +#define S_GET_DESC(S) (aout_symbol((S)->bsym)->desc) + +asection *text_section, *data_section, *bss_section; + +#define obj_frob_symbol(S,PUNT) obj_aout_frob_symbol (S, &PUNT) +#define obj_frob_file() obj_aout_frob_file () +extern void obj_aout_frob_symbol PARAMS ((struct symbol *, int *)); +extern void obj_aout_frob_file PARAMS ((void)); + +#define obj_sec_sym_ok_for_reloc(SEC) (1) + +#else + +/* We use the sy_obj field to record whether a symbol is weak. */ +#define OBJ_SYMFIELD_TYPE char + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT) + +/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */ +#define S_IS_DEFINED(s) \ + (S_GET_TYPE (s) != N_UNDF || S_GET_DESC (s) != 0) + +#define S_IS_COMMON(s) \ + (S_GET_TYPE (s) == N_UNDF && S_GET_VALUE (s) != 0) + +#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER) + +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB) +/* True if a symbol is local symbol name */ +#define S_IS_LOCAL(s) \ + (S_GET_NAME (s) \ + && !S_IS_DEBUG (s) \ + && (strchr (S_GET_NAME (s), '\001') != NULL \ + || strchr (S_GET_NAME (s), '\002') != NULL \ + || (S_LOCAL_NAME(s) && !flag_keep_locals))) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT) +/* True if the symbol has been generated because of a .stabd directive */ +#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0) + +/* Accessors */ +/* The name of the symbol */ +#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx) +/* The type of the symbol */ +#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)]) +/* The n_other expression value */ +#define S_GET_OTHER(s) ((s)->sy_symbol.n_other) +/* The n_desc expression value */ +#define S_GET_DESC(s) ((s)->sy_symbol.n_desc) +/* Whether the symbol is weak. */ +#define S_GET_WEAK(s) ((s)->sy_obj) + +/* Modifiers */ +/* Assume that a symbol cannot be simultaneously in more than on segment */ +/* set segment */ +#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg)) +/* The symbol is external */ +#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT) +/* The symbol is not external */ +#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT) +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v)) +/* Set the offset in the string table */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v)) +/* Set the n_type field */ +#define S_SET_TYPE(s,t) ((s)->sy_symbol.n_type = (t)) +/* Set the n_other expression value */ +#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v)) +/* Set the n_desc expression value */ +#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v)) +/* Mark the symbol as weak. This causes n_type to be adjusted when + the symbol is written out. */ +#define S_SET_WEAK(s) ((s)->sy_obj = 1) + +/* File header macro and type definition */ + +#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \ + + H_GET_TEXT_SIZE(h) \ + + H_GET_DATA_SIZE(h) \ + + H_GET_SYMBOL_TABLE_SIZE(h) \ + + H_GET_TEXT_RELOCATION_SIZE(h) \ + + H_GET_DATA_RELOCATION_SIZE(h) \ + + H_GET_STRING_SIZE(h)) + +#define H_GET_HEADER_SIZE(h) (EXEC_BYTES_SIZE) +#define H_GET_TEXT_SIZE(h) ((h)->header.a_text) +#define H_GET_DATA_SIZE(h) ((h)->header.a_data) +#define H_GET_BSS_SIZE(h) ((h)->header.a_bss) +#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize) +#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize) +#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms) +#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) (0) + +#define H_GET_DYNAMIC(h) ((h)->header.a_info >> 31) +#define H_GET_VERSION(h) (((h)->header.a_info >> 24) & 0x7f) +#define H_GET_MACHTYPE(h) (((h)->header.a_info >> 16) & 0xff) +#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info & 0xffff) + +#define H_SET_DYNAMIC(h,v) ((h)->header.a_info = (((v) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_VERSION(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | ((v) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_MACHTYPE(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | ((v) << 16) \ + | (H_GET_MAGIC_NUMBER(h)))) + +#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ + | (H_GET_VERSION(h) << 24) \ + | (H_GET_MACHTYPE(h) << 16) \ + | ((v)))) + +#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v))) +#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v))) +#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v))) + +#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\ + H_SET_DATA_RELOCATION_SIZE((h),(d))) + +#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v)) +#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * 12) + +#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) + +typedef struct + { + struct exec header; /* a.out header */ + long string_table_size; /* names + '\0' + sizeof(int) */ + } + +object_headers; + +/* line numbering stuff. */ +#define OBJ_EMIT_LINENO(a, b, c) {;} + +struct fix; +void tc_aout_fix_to_chars PARAMS ((char *where, struct fix *fixP, relax_addressT segment_address)); + +#endif + +#define obj_symbol_new_hook(s) {;} + +#define EMIT_SECTION_SYMBOLS 0 + +#define AOUT_STABS + +/* end of obj-aout.h */ diff --git a/contrib/binutils/gas/config/obj-coff.c b/contrib/binutils/gas/config/obj-coff.c new file mode 100644 index 0000000..2fe0cb8 --- /dev/null +++ b/contrib/binutils/gas/config/obj-coff.c @@ -0,0 +1,4378 @@ +/* coff object file format + Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define OBJ_HEADER "obj-coff.h" + +#include "as.h" +#include "obstack.h" +#include "subsegs.h" + +/* I think this is probably always correct. */ +#ifndef KEEP_RELOC_INFO +#define KEEP_RELOC_INFO +#endif + +const char *s_get_name PARAMS ((symbolS * s)); +static symbolS *def_symbol_in_progress; + + +/* stack stuff */ +typedef struct + { + unsigned long chunk_size; + unsigned long element_size; + unsigned long size; + char *data; + unsigned long pointer; + } +stack; + +static stack * +stack_init (chunk_size, element_size) + unsigned long chunk_size; + unsigned long element_size; +{ + stack *st; + + st = (stack *) malloc (sizeof (stack)); + if (!st) + return 0; + st->data = malloc (chunk_size); + if (!st->data) + { + free (st); + return 0; + } + st->pointer = 0; + st->size = chunk_size; + st->chunk_size = chunk_size; + st->element_size = element_size; + return st; +} + +#if 0 +/* Not currently used. */ +static void +stack_delete (st) + stack *st; +{ + free (st->data); + free (st); +} +#endif + +static char * +stack_push (st, element) + stack *st; + char *element; +{ + if (st->pointer + st->element_size >= st->size) + { + st->size += st->chunk_size; + if ((st->data = xrealloc (st->data, st->size)) == (char *) 0) + return (char *) 0; + } + memcpy (st->data + st->pointer, element, st->element_size); + st->pointer += st->element_size; + return st->data + st->pointer; +} + +static char * +stack_pop (st) + stack *st; +{ + if (st->pointer < st->element_size) + { + st->pointer = 0; + return (char *) 0; + } + st->pointer -= st->element_size; + return st->data + st->pointer; +} + +/* + * Maintain a list of the tagnames of the structres. + */ + +static struct hash_control *tag_hash; + +static void +tag_init () +{ + tag_hash = hash_new (); +} + +static void +tag_insert (name, symbolP) + const char *name; + symbolS *symbolP; +{ + const char *error_string; + + if ((error_string = hash_jam (tag_hash, name, (char *) symbolP))) + { + as_fatal ("Inserting \"%s\" into structure table failed: %s", + name, error_string); + } +} + +static symbolS * +tag_find (name) + char *name; +{ +#ifdef STRIP_UNDERSCORE + if (*name == '_') + name++; +#endif /* STRIP_UNDERSCORE */ + return (symbolS *) hash_find (tag_hash, name); +} + +static symbolS * +tag_find_or_make (name) + char *name; +{ + symbolS *symbolP; + + if ((symbolP = tag_find (name)) == NULL) + { + symbolP = symbol_new (name, undefined_section, + 0, &zero_address_frag); + + tag_insert (S_GET_NAME (symbolP), symbolP); +#ifdef BFD_ASSEMBLER + symbol_table_insert (symbolP); +#endif + } /* not found */ + + return symbolP; +} + + + +#ifdef BFD_ASSEMBLER + +static void SA_SET_SYM_TAGNDX PARAMS ((symbolS *, symbolS *)); + +#define GET_FILENAME_STRING(X) \ +((char*)(&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1]) + +/* @@ Ick. */ +static segT +fetch_coff_debug_section () +{ + static segT debug_section; + if (!debug_section) + { + CONST asymbol *s; + s = bfd_make_debug_symbol (stdoutput, (char *) 0, 0); + assert (s != 0); + debug_section = s->section; + } + return debug_section; +} + +void +SA_SET_SYM_ENDNDX (sym, val) + symbolS *sym; + symbolS *val; +{ + combined_entry_type *entry, *p; + + entry = &coffsymbol (sym->bsym)->native[1]; + p = coffsymbol (val->bsym)->native; + entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p; + entry->fix_end = 1; +} + +static void +SA_SET_SYM_TAGNDX (sym, val) + symbolS *sym; + symbolS *val; +{ + combined_entry_type *entry, *p; + + entry = &coffsymbol (sym->bsym)->native[1]; + p = coffsymbol (val->bsym)->native; + entry->u.auxent.x_sym.x_tagndx.p = p; + entry->fix_tag = 1; +} + +static int +S_GET_DATA_TYPE (sym) + symbolS *sym; +{ + return coffsymbol (sym->bsym)->native->u.syment.n_type; +} + +int +S_SET_DATA_TYPE (sym, val) + symbolS *sym; + int val; +{ + coffsymbol (sym->bsym)->native->u.syment.n_type = val; + return val; +} + +int +S_GET_STORAGE_CLASS (sym) + symbolS *sym; +{ + return coffsymbol (sym->bsym)->native->u.syment.n_sclass; +} + +int +S_SET_STORAGE_CLASS (sym, val) + symbolS *sym; + int val; +{ + coffsymbol (sym->bsym)->native->u.syment.n_sclass = val; + return val; +} + +/* Merge a debug symbol containing debug information into a normal symbol. */ + +void +c_symbol_merge (debug, normal) + symbolS *debug; + symbolS *normal; +{ + S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug)); + S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug)); + + if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal)) + /* take the most we have */ + S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug)); + + if (S_GET_NUMBER_AUXILIARY (debug) > 0) + { + /* Move all the auxiliary information. */ + /* @@ How many fields do we want to preserve? Would it make more + sense to pick and choose those we want to copy? Should look + into this further.... [raeburn:19920512.2209EST] */ + alent *linenos; + linenos = coffsymbol (normal->bsym)->lineno; + memcpy ((char *) &coffsymbol (normal->bsym)->native, + (char *) &coffsymbol (debug->bsym)->native, + S_GET_NUMBER_AUXILIARY(debug) * AUXESZ); + coffsymbol (normal->bsym)->lineno = linenos; + } + + /* Move the debug flags. */ + SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug)); +} + +void +c_dot_file_symbol (filename) + char *filename; +{ + symbolS *symbolP; + + symbolP = symbol_new (filename, bfd_abs_section_ptr, 0, &zero_address_frag); + + S_SET_STORAGE_CLASS (symbolP, C_FILE); + S_SET_NUMBER_AUXILIARY (symbolP, 1); + + symbolP->bsym->flags = BSF_DEBUGGING; + +#ifndef NO_LISTING + { + extern int listing; + if (listing) + { + listing_source_file (filename); + } + } +#endif + + /* Make sure that the symbol is first on the symbol chain */ + if (symbol_rootP != symbolP) + { + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); + } /* if not first on the list */ +} + +/* Line number handling */ + +struct line_no { + struct line_no *next; + fragS *frag; + alent l; +}; + +int coff_line_base; + +/* Symbol of last function, which we should hang line#s off of. */ +static symbolS *line_fsym; + +#define in_function() (line_fsym != 0) +#define clear_function() (line_fsym = 0) +#define set_function(F) (line_fsym = (F), coff_add_linesym (F)) + + +void +coff_obj_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + char underscore = 0; /* Symbol has leading _ */ + + { + long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type); + char *s = (char *) xmalloc (sz); + memset (s, 0, sz); + coffsymbol (symbolP->bsym)->native = (combined_entry_type *) s; + } + S_SET_DATA_TYPE (symbolP, T_NULL); + S_SET_STORAGE_CLASS (symbolP, 0); + S_SET_NUMBER_AUXILIARY (symbolP, 0); + + if (S_IS_STRING (symbolP)) + SF_SET_STRING (symbolP); + if (!underscore && S_IS_LOCAL (symbolP)) + SF_SET_LOCAL (symbolP); +} + + +/* + * Handle .ln directives. + */ + +static symbolS *current_lineno_sym; +static struct line_no *line_nos; +/* @@ Blindly assume all .ln directives will be in the .text section... */ +int coff_n_line_nos; + +static void +add_lineno (frag, offset, num) + fragS *frag; + int offset; + int num; +{ + struct line_no *new_line = + (struct line_no *) xmalloc (sizeof (struct line_no)); + if (!current_lineno_sym) + { + abort (); + } + new_line->next = line_nos; + new_line->frag = frag; + new_line->l.line_number = num; + new_line->l.u.offset = offset; + line_nos = new_line; + coff_n_line_nos++; +} + +void +coff_add_linesym (sym) + symbolS *sym; +{ + if (line_nos) + { + coffsymbol (current_lineno_sym->bsym)->lineno = (alent *) line_nos; + coff_n_line_nos++; + line_nos = 0; + } + current_lineno_sym = sym; +} + +static void +obj_coff_ln (appline) + int appline; +{ + int l; + + if (! appline && def_symbol_in_progress != NULL) + { + as_warn (".ln pseudo-op inside .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } + + l = get_absolute_expression (); + if (!appline) + { + add_lineno (frag_now, frag_now_fix (), l); + } + + if (appline) + new_logical_line ((char *) NULL, l - 1); + +#ifndef NO_LISTING + { + extern int listing; + + if (listing) + { + if (! appline) + l += coff_line_base - 1; + listing_source_line (l); + } + } +#endif + + demand_empty_rest_of_line (); +} + +/* + * def() + * + * Handle .def directives. + * + * One might ask : why can't we symbol_new if the symbol does not + * already exist and fill it with debug information. Because of + * the C_EFCN special symbol. It would clobber the value of the + * function symbol before we have a chance to notice that it is + * a C_EFCN. And a second reason is that the code is more clear this + * way. (at least I think it is :-). + * + */ + +#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') +#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ + *input_line_pointer == '\t') \ + input_line_pointer++; + +static void +obj_coff_def (what) + int what; +{ + char name_end; /* Char after the end of name */ + char *symbol_name; /* Name of the debug symbol */ + char *symbol_name_copy; /* Temporary copy of the name */ + unsigned int symbol_name_length; + + if (def_symbol_in_progress != NULL) + { + as_warn (".def pseudo-op used inside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + SKIP_WHITESPACES (); + + symbol_name = input_line_pointer; +#ifdef STRIP_UNDERSCORE + if (symbol_name[0] == '_' && symbol_name[1] != 0) + symbol_name++; +#endif /* STRIP_UNDERSCORE */ + + name_end = get_symbol_end (); + symbol_name_length = strlen (symbol_name); + symbol_name_copy = xmalloc (symbol_name_length + 1); + strcpy (symbol_name_copy, symbol_name); +#ifdef tc_canonicalize_symbol_name + symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy); +#endif + + /* Initialize the new symbol */ + def_symbol_in_progress = symbol_make (symbol_name_copy); + def_symbol_in_progress->sy_frag = &zero_address_frag; + S_SET_VALUE (def_symbol_in_progress, 0); + + if (S_IS_STRING (def_symbol_in_progress)) + SF_SET_STRING (def_symbol_in_progress); + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +unsigned int dim_index; + +static void +obj_coff_endef (ignore) + int ignore; +{ + symbolS *symbolP; + /* DIM BUG FIX sac@cygnus.com */ + dim_index = 0; + if (def_symbol_in_progress == NULL) + { + as_warn (".endef pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + /* Set the section number according to storage class. */ + switch (S_GET_STORAGE_CLASS (def_symbol_in_progress)) + { + case C_STRTAG: + case C_ENTAG: + case C_UNTAG: + SF_SET_TAG (def_symbol_in_progress); + /* intentional fallthrough */ + case C_FILE: + case C_TPDEF: + SF_SET_DEBUG (def_symbol_in_progress); + S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ()); + break; + + case C_EFCN: + SF_SET_LOCAL (def_symbol_in_progress); /* Do not emit this symbol. */ + /* intentional fallthrough */ + case C_BLOCK: + SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing */ + /* intentional fallthrough */ + case C_FCN: + { + CONST char *name; + S_SET_SEGMENT (def_symbol_in_progress, text_section); + + name = bfd_asymbol_name (def_symbol_in_progress->bsym); + if (name[1] == 'b' && name[2] == 'f') + { + if (! in_function ()) + as_warn ("`%s' symbol without preceding function", name); +/* SA_SET_SYM_LNNO (def_symbol_in_progress, 12345);*/ + /* Will need relocating */ + SF_SET_PROCESS (def_symbol_in_progress); + clear_function (); + } + } + break; + +#ifdef C_AUTOARG + case C_AUTOARG: +#endif /* C_AUTOARG */ + case C_AUTO: + case C_REG: + case C_ARG: + case C_REGPARM: + case C_FIELD: + SF_SET_DEBUG (def_symbol_in_progress); + S_SET_SEGMENT (def_symbol_in_progress, absolute_section); + break; + + case C_MOS: + case C_MOE: + case C_MOU: + case C_EOS: + S_SET_SEGMENT (def_symbol_in_progress, absolute_section); + break; + + case C_EXT: + case C_STAT: + case C_LABEL: + /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ + break; + + case C_USTATIC: + case C_EXTDEF: + case C_ULABEL: + as_warn ("unexpected storage class %d", + S_GET_STORAGE_CLASS (def_symbol_in_progress)); + break; + } /* switch on storage class */ + + /* Now that we have built a debug symbol, try to find if we should + merge with an existing symbol or not. If a symbol is C_EFCN or + SEG_ABSOLUTE or untagged SEG_DEBUG it never merges. */ + + /* Two cases for functions. Either debug followed by definition or + definition followed by debug. For definition first, we will + merge the debug symbol into the definition. For debug first, the + lineno entry MUST point to the definition function or else it + will point off into space when obj_crawl_symbol_chain() merges + the debug symbol into the real symbol. Therefor, let's presume + the debug symbol is a real function reference. */ + + /* FIXME-SOON If for some reason the definition label/symbol is + never seen, this will probably leave an undefined symbol at link + time. */ + + if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN + || (!strcmp (bfd_get_section_name (stdoutput, + S_GET_SEGMENT (def_symbol_in_progress)), + "*DEBUG*") + && !SF_GET_TAG (def_symbol_in_progress)) + || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section + || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL) + { + if (def_symbol_in_progress != symbol_lastP) + symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, + &symbol_lastP); + } + else + { + /* This symbol already exists, merge the newly created symbol + into the old one. This is not mandatory. The linker can + handle duplicate symbols correctly. But I guess that it save + a *lot* of space if the assembly file defines a lot of + symbols. [loic] */ + + /* The debug entry (def_symbol_in_progress) is merged into the + previous definition. */ + + c_symbol_merge (def_symbol_in_progress, symbolP); + symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP); + + def_symbol_in_progress = symbolP; + + if (SF_GET_FUNCTION (def_symbol_in_progress) + || SF_GET_TAG (def_symbol_in_progress) + || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT) + { + /* For functions, and tags, and static symbols, the symbol + *must* be where the debug symbol appears. Move the + existing symbol to the current place. */ + /* If it already is at the end of the symbol list, do nothing */ + if (def_symbol_in_progress != symbol_lastP) + { + symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP); + symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); + } + } + } + + if (SF_GET_TAG (def_symbol_in_progress)) + { + symbolS *oldtag; + + oldtag = symbol_find_base (S_GET_NAME (def_symbol_in_progress), + DO_NOT_STRIP); + if (oldtag == NULL || ! SF_GET_TAG (oldtag)) + tag_insert (S_GET_NAME (def_symbol_in_progress), + def_symbol_in_progress); + } + + if (SF_GET_FUNCTION (def_symbol_in_progress)) + { + know (sizeof (def_symbol_in_progress) <= sizeof (long)); + set_function (def_symbol_in_progress); + SF_SET_PROCESS (def_symbol_in_progress); + + if (symbolP == NULL) + { + /* That is, if this is the first time we've seen the + function... */ + symbol_table_insert (def_symbol_in_progress); + } /* definition follows debug */ + } /* Create the line number entry pointing to the function being defined */ + + def_symbol_in_progress = NULL; + demand_empty_rest_of_line (); +} + +static void +obj_coff_dim (ignore) + int ignore; +{ + int dim_index; + + if (def_symbol_in_progress == NULL) + { + as_warn (".dim pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + + for (dim_index = 0; dim_index < DIMNUM; dim_index++) + { + SKIP_WHITESPACES (); + SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index, + get_absolute_expression ()); + + switch (*input_line_pointer) + { + case ',': + input_line_pointer++; + break; + + default: + as_warn ("badly formed .dim directive ignored"); + /* intentional fallthrough */ + case '\n': + case ';': + dim_index = DIMNUM; + break; + } + } + + demand_empty_rest_of_line (); +} + +static void +obj_coff_line (ignore) + int ignore; +{ + int this_base; + + if (def_symbol_in_progress == NULL) + { + /* Probably stabs-style line? */ + obj_coff_ln (0); + return; + } + + this_base = get_absolute_expression (); + if (!strcmp (".bf", S_GET_NAME (def_symbol_in_progress))) + coff_line_base = this_base; + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + SA_SET_SYM_LNNO (def_symbol_in_progress, coff_line_base); + + demand_empty_rest_of_line (); + +#ifndef NO_LISTING + if (strcmp (".bf", S_GET_NAME (def_symbol_in_progress)) == 0) + { + extern int listing; + + if (listing) + listing_source_line ((unsigned int) coff_line_base); + } +#endif +} + +static void +obj_coff_size (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".size pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ()); + demand_empty_rest_of_line (); +} + +static void +obj_coff_scl (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".scl pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ()); + demand_empty_rest_of_line (); +} + +static void +obj_coff_tag (ignore) + int ignore; +{ + char *symbol_name; + char name_end; + + if (def_symbol_in_progress == NULL) + { + as_warn (".tag pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + symbol_name = input_line_pointer; + name_end = get_symbol_end (); + +#ifdef tc_canonicalize_symbol_name + symbol_name = tc_canonicalize_symbol_name (symbol_name); +#endif + + /* Assume that the symbol referred to by .tag is always defined. + This was a bad assumption. I've added find_or_make. xoxorich. */ + SA_SET_SYM_TAGNDX (def_symbol_in_progress, + tag_find_or_make (symbol_name)); + if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L) + { + as_warn ("tag not found for .tag %s", symbol_name); + } /* not defined */ + + SF_SET_TAGGED (def_symbol_in_progress); + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +static void +obj_coff_type (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".type pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ()); + + if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) && + S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF) + { + SF_SET_FUNCTION (def_symbol_in_progress); + } /* is a function */ + + demand_empty_rest_of_line (); +} + +static void +obj_coff_val (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".val pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + if (is_name_beginner (*input_line_pointer)) + { + char *symbol_name = input_line_pointer; + char name_end = get_symbol_end (); + +#ifdef tc_canonicalize_symbol_name + symbol_name = tc_canonicalize_symbol_name (symbol_name); +#endif + if (!strcmp (symbol_name, ".")) + { + def_symbol_in_progress->sy_frag = frag_now; + S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); + /* If the .val is != from the .def (e.g. statics) */ + } + else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name)) + { + def_symbol_in_progress->sy_value.X_op = O_symbol; + def_symbol_in_progress->sy_value.X_add_symbol = + symbol_find_or_make (symbol_name); + def_symbol_in_progress->sy_value.X_op_symbol = NULL; + def_symbol_in_progress->sy_value.X_add_number = 0; + + /* If the segment is undefined when the forward reference is + resolved, then copy the segment id from the forward + symbol. */ + SF_SET_GET_SEGMENT (def_symbol_in_progress); + } + /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */ + *input_line_pointer = name_end; + } + else + { + S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ()); + } /* if symbol based */ + + demand_empty_rest_of_line (); +} + +void +coff_obj_read_begin_hook () +{ + /* These had better be the same. Usually 18 bytes. */ +#ifndef BFD_HEADERS + know (sizeof (SYMENT) == sizeof (AUXENT)); + know (SYMESZ == AUXESZ); +#endif + tag_init (); +} + + +symbolS *coff_last_function; +static symbolS *coff_last_bf; + +void +coff_frob_symbol (symp, punt) + symbolS *symp; + int *punt; +{ + static symbolS *last_tagP; + static stack *block_stack; + static symbolS *set_end; + symbolS *next_set_end = NULL; + + if (symp == &abs_symbol) + { + *punt = 1; + return; + } + + if (current_lineno_sym) + coff_add_linesym ((symbolS *) 0); + + if (!block_stack) + block_stack = stack_init (512, sizeof (symbolS*)); + + if (!S_IS_DEFINED (symp) && S_GET_STORAGE_CLASS (symp) != C_STAT) + S_SET_STORAGE_CLASS (symp, C_EXT); + + if (!SF_GET_DEBUG (symp)) + { + symbolS *real; + if (!SF_GET_LOCAL (symp) + && !SF_GET_STATICS (symp) + && (real = symbol_find_base (S_GET_NAME (symp), DO_NOT_STRIP)) + && real != symp) + { + c_symbol_merge (symp, real); + *punt = 1; + } + if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp)) + { + assert (S_GET_VALUE (symp) == 0); + S_SET_EXTERNAL (symp); + } + else if (S_GET_STORAGE_CLASS (symp) == C_NULL) + { + if (S_GET_SEGMENT (symp) == text_section + && symp != seg_info (text_section)->sym) + S_SET_STORAGE_CLASS (symp, C_LABEL); + else + S_SET_STORAGE_CLASS (symp, C_STAT); + } + if (SF_GET_PROCESS (symp)) + { + if (S_GET_STORAGE_CLASS (symp) == C_BLOCK) + { + if (!strcmp (S_GET_NAME (symp), ".bb")) + stack_push (block_stack, (char *) &symp); + else + { + symbolS *begin; + begin = *(symbolS **) stack_pop (block_stack); + if (begin == 0) + as_warn ("mismatched .eb"); + else + next_set_end = begin; + } + } + if (coff_last_function == 0 && SF_GET_FUNCTION (symp)) + { + union internal_auxent *auxp; + coff_last_function = symp; + if (S_GET_NUMBER_AUXILIARY (symp) < 1) + S_SET_NUMBER_AUXILIARY (symp, 1); + auxp = &coffsymbol (symp->bsym)->native[1].u.auxent; + memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0, + sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen)); + } + if (S_GET_STORAGE_CLASS (symp) == C_EFCN) + { + if (coff_last_function == 0) + as_fatal ("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE (coff_last_function, + (long) (S_GET_VALUE (symp) + - S_GET_VALUE (coff_last_function))); + next_set_end = coff_last_function; + coff_last_function = 0; + } + } + if (S_IS_EXTERNAL (symp)) + S_SET_STORAGE_CLASS (symp, C_EXT); + else if (SF_GET_LOCAL (symp)) + *punt = 1; + + if (SF_GET_FUNCTION (symp)) + symp->bsym->flags |= BSF_FUNCTION; + + /* more ... */ + } + + if (SF_GET_TAG (symp)) + last_tagP = symp; + else if (S_GET_STORAGE_CLASS (symp) == C_EOS) + next_set_end = last_tagP; + +#ifdef OBJ_XCOFF + /* This is pretty horrible, but we have to set *punt correctly in + order to call SA_SET_SYM_ENDNDX correctly. */ + if (! symp->sy_used_in_reloc + && ((symp->bsym->flags & BSF_SECTION_SYM) != 0 + || (! S_IS_EXTERNAL (symp) + && ! symp->sy_tc.output + && S_GET_STORAGE_CLASS (symp) != C_FILE))) + *punt = 1; +#endif + + if (set_end != (symbolS *) NULL + && ! *punt + && ((symp->bsym->flags & BSF_NOT_AT_END) != 0 + || (S_IS_DEFINED (symp) + && ! S_IS_COMMON (symp) + && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp))))) + { + SA_SET_SYM_ENDNDX (set_end, symp); + set_end = NULL; + } + + if (next_set_end != NULL + && ! *punt) + set_end = next_set_end; + + if (! *punt + && S_GET_STORAGE_CLASS (symp) == C_FCN + && strcmp (S_GET_NAME (symp), ".bf") == 0) + { + if (coff_last_bf != NULL) + SA_SET_SYM_ENDNDX (coff_last_bf, symp); + coff_last_bf = symp; + } + + if (coffsymbol (symp->bsym)->lineno) + { + int i; + struct line_no *lptr; + alent *l; + + lptr = (struct line_no *) coffsymbol (symp->bsym)->lineno; + for (i = 0; lptr; lptr = lptr->next) + i++; + lptr = (struct line_no *) coffsymbol (symp->bsym)->lineno; + + /* We need i entries for line numbers, plus 1 for the first + entry which BFD will override, plus 1 for the last zero + entry (a marker for BFD). */ + l = (alent *) xmalloc ((i + 2) * sizeof (alent)); + coffsymbol (symp->bsym)->lineno = l; + l[i + 1].line_number = 0; + l[i + 1].u.sym = NULL; + for (; i > 0; i--) + { + if (lptr->frag) + lptr->l.u.offset += lptr->frag->fr_address; + l[i] = lptr->l; + lptr = lptr->next; + } + } +} + +void +coff_adjust_section_syms (abfd, sec, x) + bfd *abfd; + asection *sec; + PTR x; +{ + symbolS *secsym; + segment_info_type *seginfo = seg_info (sec); + int nlnno, nrelocs = 0; + + /* RS/6000 gas creates a .debug section manually in ppc_frob_file in + tc-ppc.c. Do not get confused by it. */ + if (seginfo == NULL) + return; + + if (!strcmp (sec->name, ".text")) + nlnno = coff_n_line_nos; + else + nlnno = 0; + { + /* @@ Hope that none of the fixups expand to more than one reloc + entry... */ + fixS *fixp = seginfo->fix_root; + while (fixp) + { + fixp = fixp->fx_next; + nrelocs++; + } + } + if (bfd_get_section_size_before_reloc (sec) == 0 + && nrelocs == 0 + && nlnno == 0 + && sec != text_section + && sec != data_section + && sec != bss_section) + return; + secsym = section_symbol (sec); + SA_SET_SCN_NRELOC (secsym, nrelocs); + SA_SET_SCN_NLINNO (secsym, nlnno); +} + +void +coff_frob_file () +{ + bfd_map_over_sections (stdoutput, coff_adjust_section_syms, (char*) 0); +} + +/* + * implement the .section pseudo op: + * .section name {, "flags"} + * ^ ^ + * | +--- optional flags: 'b' for bss + * | 'i' for info + * +-- section name 'l' for lib + * 'n' for noload + * 'o' for over + * 'w' for data + * 'd' (apparently m88k for data) + * 'x' for text + * 'r' for read-only data + * But if the argument is not a quoted string, treat it as a + * subsegment number. + */ + +void +obj_coff_section (ignore) + int ignore; +{ + /* Strip out the section name */ + char *section_name; + char c; + char *name; + unsigned int exp; + flagword flags; + asection *sec; + + if (flag_mri) + { + char type; + + s_mri_sect (&type); + return; + } + + section_name = input_line_pointer; + c = get_symbol_end (); + + name = xmalloc (input_line_pointer - section_name + 1); + strcpy (name, section_name); + + *input_line_pointer = c; + + SKIP_WHITESPACE (); + + exp = 0; + flags = SEC_NO_FLAGS; + + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + if (*input_line_pointer != '"') + exp = get_absolute_expression (); + else + { + ++input_line_pointer; + while (*input_line_pointer != '"' + && ! is_end_of_line[(unsigned char) *input_line_pointer]) + { + switch (*input_line_pointer) + { + case 'b': flags |= SEC_ALLOC; flags &=~ SEC_LOAD; break; + case 'n': flags &=~ SEC_LOAD; break; + case 'd': + case 'w': flags &=~ SEC_READONLY; break; + case 'x': flags |= SEC_CODE; break; + case 'r': flags |= SEC_READONLY; break; + + case 'i': /* STYP_INFO */ + case 'l': /* STYP_LIB */ + case 'o': /* STYP_OVER */ + as_warn ("unsupported section attribute '%c'", + *input_line_pointer); + break; + + default: + as_warn("unknown section attribute '%c'", + *input_line_pointer); + break; + } + ++input_line_pointer; + } + if (*input_line_pointer == '"') + ++input_line_pointer; + } + } + + sec = subseg_new (name, (subsegT) exp); + + if (flags != SEC_NO_FLAGS) + { + if (! bfd_set_section_flags (stdoutput, sec, flags)) + as_warn ("error setting flags for \"%s\": %s", + bfd_section_name (stdoutput, sec), + bfd_errmsg (bfd_get_error ())); + } + + demand_empty_rest_of_line (); +} + +void +coff_adjust_symtab () +{ + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE) + c_dot_file_symbol ("fake"); +} + +void +coff_frob_section (sec) + segT sec; +{ + segT strsec; + char *p; + fragS *fragp; + bfd_vma size, n_entries, mask; + + /* The COFF back end in BFD requires that all section sizes be + rounded up to multiples of the corresponding section alignments. + Seems kinda silly to me, but that's the way it is. */ + size = bfd_get_section_size_before_reloc (sec); + mask = ((bfd_vma) 1 << (bfd_vma) sec->alignment_power) - 1; + if (size & mask) + { + size = (size + mask) & ~mask; + bfd_set_section_size (stdoutput, sec, size); + } + + /* If the section size is non-zero, the section symbol needs an aux + entry associated with it, indicating the size. We don't know + all the values yet; coff_frob_symbol will fill them in later. */ + if (size != 0 + || sec == text_section + || sec == data_section + || sec == bss_section) + { + symbolS *secsym = section_symbol (sec); + + S_SET_STORAGE_CLASS (secsym, C_STAT); + S_SET_NUMBER_AUXILIARY (secsym, 1); + SF_SET_STATICS (secsym); + SA_SET_SCN_SCNLEN (secsym, size); + } + + /* @@ these should be in a "stabs.h" file, or maybe as.h */ +#ifndef STAB_SECTION_NAME +#define STAB_SECTION_NAME ".stab" +#endif +#ifndef STAB_STRING_SECTION_NAME +#define STAB_STRING_SECTION_NAME ".stabstr" +#endif + if (strcmp (STAB_STRING_SECTION_NAME, sec->name)) + return; + + strsec = sec; + sec = subseg_get (STAB_SECTION_NAME, 0); + /* size is already rounded up, since other section will be listed first */ + size = bfd_get_section_size_before_reloc (strsec); + + n_entries = bfd_get_section_size_before_reloc (sec) / 12 - 1; + + /* Find first non-empty frag. It should be large enough. */ + fragp = seg_info (sec)->frchainP->frch_root; + while (fragp && fragp->fr_fix == 0) + fragp = fragp->fr_next; + assert (fragp != 0 && fragp->fr_fix >= 12); + + /* Store the values. */ + p = fragp->fr_literal; + bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6); + bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8); +} + +void +obj_coff_init_stab_section (seg) + segT seg; +{ + char *file; + char *p; + char *stabstr_name; + unsigned int stroff; + + /* Make space for this first symbol. */ + p = frag_more (12); + /* Zero it out. */ + memset (p, 0, 12); + as_where (&file, (unsigned int *) NULL); + stabstr_name = (char *) alloca (strlen (seg->name) + 4); + strcpy (stabstr_name, seg->name); + strcat (stabstr_name, "str"); + stroff = get_stab_string_offset (file, stabstr_name); + know (stroff == 1); + md_number_to_chars (p, stroff, 4); +} + +#ifdef DEBUG +/* for debugging */ +const char * +s_get_name (s) + symbolS *s; +{ + return ((s == NULL) ? "(NULL)" : S_GET_NAME (s)); +} + +void +symbol_dump () +{ + symbolS *symbolP; + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + printf("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n", + (unsigned long) symbolP, + S_GET_NAME(symbolP), + (long) S_GET_DATA_TYPE(symbolP), + S_GET_STORAGE_CLASS(symbolP), + (int) S_GET_SEGMENT(symbolP)); + } +} + +#endif /* DEBUG */ + +#else /* not BFD_ASSEMBLER */ + +#include "frags.h" +/* This is needed because we include internal bfd things. */ +#include <time.h> + +#include "libbfd.h" +#include "libcoff.h" + +#ifdef TE_PE +#include "coff/pe.h" +#endif + +/* The NOP_OPCODE is for the alignment fill value. Fill with nop so + that we can stick sections together without causing trouble. */ +#ifndef NOP_OPCODE +#define NOP_OPCODE 0x00 +#endif + +/* The zeroes if symbol name is longer than 8 chars */ +#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v)) + +#define MIN(a,b) ((a) < (b)? (a) : (b)) +/* This vector is used to turn an internal segment into a section # + suitable for insertion into a coff symbol table + */ + +const short seg_N_TYPE[] = +{ /* in: segT out: N_TYPE bits */ + C_ABS_SECTION, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + C_UNDEF_SECTION, /* SEG_UNKNOWN */ + C_UNDEF_SECTION, /* SEG_GOOF */ + C_UNDEF_SECTION, /* SEG_EXPR */ + C_DEBUG_SECTION, /* SEG_DEBUG */ + C_NTV_SECTION, /* SEG_NTV */ + C_PTV_SECTION, /* SEG_PTV */ + C_REGISTER_SECTION, /* SEG_REGISTER */ +}; + +int function_lineoff = -1; /* Offset in line#s where the last function + started (the odd entry for line #0) */ + +/* structure used to keep the filenames which + are too long around so that we can stick them + into the string table */ +struct filename_list +{ + char *filename; + struct filename_list *next; +}; + +static struct filename_list *filename_list_head; +static struct filename_list *filename_list_tail; + +static symbolS *last_line_symbol; + +/* Add 4 to the real value to get the index and compensate the + negatives. This vector is used by S_GET_SEGMENT to turn a coff + section number into a segment number +*/ +static symbolS *previous_file_symbol; +void c_symbol_merge (); +static int line_base; + +symbolS *c_section_symbol (); +bfd *abfd; + +static void fixup_segment PARAMS ((segment_info_type *segP, + segT this_segment_type)); + + +static void fixup_mdeps PARAMS ((fragS *, + object_headers *, + segT)); + + +static void fill_section PARAMS ((bfd * abfd, + object_headers *, + unsigned long *)); + + +static int c_line_new PARAMS ((symbolS * symbol, long paddr, + int line_number, + fragS * frag)); + + +static void w_symbols PARAMS ((bfd * abfd, char *where, + symbolS * symbol_rootP)); + +static void adjust_stab_section PARAMS ((bfd *abfd, segT seg)); + +static void obj_coff_lcomm PARAMS ((int)); +static void obj_coff_text PARAMS ((int)); +static void obj_coff_data PARAMS ((int)); +static void obj_coff_bss PARAMS ((int)); +static void obj_coff_ident PARAMS ((int)); +void obj_coff_section PARAMS ((int)); + +/* Section stuff + + We allow more than just the standard 3 sections, infact, we allow + 40 sections, (though the usual three have to be there). + + This structure performs the mappings for us: +*/ + + +typedef struct +{ + segT seg_t; + int i; +} seg_info_type; + +static const seg_info_type seg_info_off_by_4[] = +{ + {SEG_PTV, }, + {SEG_NTV, }, + {SEG_DEBUG, }, + {SEG_ABSOLUTE, }, + {SEG_UNKNOWN, }, + {SEG_E0}, {SEG_E1}, {SEG_E2}, {SEG_E3}, {SEG_E4}, + {SEG_E5}, {SEG_E6}, {SEG_E7}, {SEG_E8}, {SEG_E9}, + {SEG_E10},{SEG_E11},{SEG_E12},{SEG_E13},{SEG_E14}, + {SEG_E15},{SEG_E16},{SEG_E17},{SEG_E18},{SEG_E19}, + {SEG_E20},{SEG_E21},{SEG_E22},{SEG_E23},{SEG_E24}, + {SEG_E25},{SEG_E26},{SEG_E27},{SEG_E28},{SEG_E29}, + {SEG_E30},{SEG_E31},{SEG_E32},{SEG_E33},{SEG_E34}, + {SEG_E35},{SEG_E36},{SEG_E37},{SEG_E38},{SEG_E39}, + {(segT)40}, + {(segT)41}, + {(segT)42}, + {(segT)43}, + {(segT)44}, + {(segT)45}, + {(segT)0}, + {(segT)0}, + {(segT)0}, + {SEG_REGISTER} +}; + + + +#define SEG_INFO_FROM_SECTION_NUMBER(x) (seg_info_off_by_4[(x)+4]) + +static relax_addressT +relax_align (address, alignment) + relax_addressT address; + long alignment; +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~((~0) << alignment); + new_address = (address + mask) & (~mask); + return (new_address - address); +} + + +segT +s_get_segment (x) + symbolS * x; +{ + return SEG_INFO_FROM_SECTION_NUMBER (x->sy_symbol.ost_entry.n_scnum).seg_t; +} + +/* calculate the size of the frag chain and fill in the section header + to contain all of it, also fill in the addr of the sections */ +static unsigned int +size_section (abfd, idx) + bfd * abfd; + unsigned int idx; +{ + + unsigned int size = 0; + fragS *frag = segment_info[idx].frchainP->frch_root; + while (frag) + { + size = frag->fr_address; + if (frag->fr_address != size) + { + fprintf (stderr, "Out of step\n"); + size = frag->fr_address; + } + + switch (frag->fr_type) + { +#ifdef TC_COFF_SIZEMACHDEP + case rs_machine_dependent: + size += TC_COFF_SIZEMACHDEP (frag); + break; +#endif + case rs_space: + assert (frag->fr_symbol == 0); + case rs_fill: + case rs_org: + size += frag->fr_fix; + size += frag->fr_offset * frag->fr_var; + break; + case rs_align: + case rs_align_code: + { + addressT off; + + size += frag->fr_fix; + off = relax_align (size, frag->fr_offset); + if (frag->fr_subtype != 0 && off > frag->fr_subtype) + off = 0; + size += off; + } + break; + default: + BAD_CASE (frag->fr_type); + break; + } + frag = frag->fr_next; + } + segment_info[idx].scnhdr.s_size = size; + return size; +} + + +static unsigned int +count_entries_in_chain (idx) + unsigned int idx; +{ + unsigned int nrelocs; + fixS *fixup_ptr; + + /* Count the relocations */ + fixup_ptr = segment_info[idx].fix_root; + nrelocs = 0; + while (fixup_ptr != (fixS *) NULL) + { + if (fixup_ptr->fx_done == 0 && TC_COUNT_RELOC (fixup_ptr)) + { +#ifdef TC_A29K + if (fixup_ptr->fx_r_type == RELOC_CONSTH) + nrelocs += 2; + else + nrelocs++; +#else + nrelocs++; +#endif + } + + fixup_ptr = fixup_ptr->fx_next; + } + return nrelocs; +} + +#ifdef TE_AUX + +static int compare_external_relocs PARAMS ((const PTR, const PTR)); + +/* AUX's ld expects relocations to be sorted */ +static int +compare_external_relocs (x, y) + const PTR x; + const PTR y; +{ + struct external_reloc *a = (struct external_reloc *) x; + struct external_reloc *b = (struct external_reloc *) y; + bfd_vma aadr = bfd_getb32 (a->r_vaddr); + bfd_vma badr = bfd_getb32 (b->r_vaddr); + return (aadr < badr ? -1 : badr < aadr ? 1 : 0); +} + +#endif + +/* output all the relocations for a section */ +void +do_relocs_for (abfd, h, file_cursor) + bfd * abfd; + object_headers * h; + unsigned long *file_cursor; +{ + unsigned int nrelocs; + unsigned int idx; + unsigned long reloc_start = *file_cursor; + + for (idx = SEG_E0; idx < SEG_LAST; idx++) + { + if (segment_info[idx].scnhdr.s_name[0]) + { + struct external_reloc *ext_ptr; + struct external_reloc *external_reloc_vec; + unsigned int external_reloc_size; + unsigned int base = segment_info[idx].scnhdr.s_paddr; + fixS *fix_ptr = segment_info[idx].fix_root; + nrelocs = count_entries_in_chain (idx); + + if (nrelocs) + /* Bypass this stuff if no relocs. This also incidentally + avoids a SCO bug, where free(malloc(0)) tends to crash. */ + { + external_reloc_size = nrelocs * RELSZ; + external_reloc_vec = + (struct external_reloc *) malloc (external_reloc_size); + + ext_ptr = external_reloc_vec; + + /* Fill in the internal coff style reloc struct from the + internal fix list. */ + while (fix_ptr) + { + struct internal_reloc intr; + + /* Only output some of the relocations */ + if (fix_ptr->fx_done == 0 && TC_COUNT_RELOC (fix_ptr)) + { +#ifdef TC_RELOC_MANGLE + TC_RELOC_MANGLE (&segment_info[idx], fix_ptr, &intr, + base); + +#else + symbolS *dot; + symbolS *symbol_ptr = fix_ptr->fx_addsy; + + intr.r_type = TC_COFF_FIX2RTYPE (fix_ptr); + intr.r_vaddr = + base + fix_ptr->fx_frag->fr_address + fix_ptr->fx_where; + +#ifdef TC_KEEP_FX_OFFSET + intr.r_offset = fix_ptr->fx_offset; +#else + intr.r_offset = 0; +#endif + + while (symbol_ptr->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (symbol_ptr) + || S_IS_COMMON (symbol_ptr))) + { + symbolS *n; + + /* We must avoid looping, as that can occur + with a badly written program. */ + n = symbol_ptr->sy_value.X_add_symbol; + if (n == symbol_ptr) + break; + symbol_ptr = n; + } + + /* Turn the segment of the symbol into an offset. */ + if (symbol_ptr) + { + resolve_symbol_value (symbol_ptr); + if (! symbol_ptr->sy_resolved) + { + char *file; + unsigned int line; + + if (expr_symbol_where (symbol_ptr, &file, &line)) + as_bad_where (file, line, + "unresolved relocation"); + else + as_bad ("bad relocation: symbol `%s' not in symbol table", + S_GET_NAME (symbol_ptr)); + } + dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; + if (dot) + { + intr.r_symndx = dot->sy_number; + } + else + { + intr.r_symndx = symbol_ptr->sy_number; + } + + } + else + { + intr.r_symndx = -1; + } +#endif + + (void) bfd_coff_swap_reloc_out (abfd, &intr, ext_ptr); + ext_ptr++; + +#if defined(TC_A29K) + + /* The 29k has a special kludge for the high 16 bit + reloc. Two relocations are emited, R_IHIHALF, + and R_IHCONST. The second one doesn't contain a + symbol, but uses the value for offset. */ + + if (intr.r_type == R_IHIHALF) + { + /* now emit the second bit */ + intr.r_type = R_IHCONST; + intr.r_symndx = fix_ptr->fx_addnumber; + (void) bfd_coff_swap_reloc_out (abfd, &intr, ext_ptr); + ext_ptr++; + } +#endif + } + + fix_ptr = fix_ptr->fx_next; + } + +#ifdef TE_AUX + /* Sort the reloc table */ + qsort ((PTR) external_reloc_vec, nrelocs, + sizeof (struct external_reloc), compare_external_relocs); +#endif + + /* Write out the reloc table */ + bfd_write ((PTR) external_reloc_vec, 1, external_reloc_size, + abfd); + free (external_reloc_vec); + + /* Fill in section header info. */ + segment_info[idx].scnhdr.s_relptr = *file_cursor; + *file_cursor += external_reloc_size; + segment_info[idx].scnhdr.s_nreloc = nrelocs; + } + else + { + /* No relocs */ + segment_info[idx].scnhdr.s_relptr = 0; + } + } + } + /* Set relocation_size field in file headers */ + H_SET_RELOCATION_SIZE (h, *file_cursor - reloc_start, 0); +} + + +/* run through a frag chain and write out the data to go with it, fill + in the scnhdrs with the info on the file postions +*/ +static void +fill_section (abfd, h, file_cursor) + bfd * abfd; + object_headers *h; + unsigned long *file_cursor; +{ + + unsigned int i; + unsigned int paddr = 0; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + unsigned int offset = 0; + struct internal_scnhdr *s = &(segment_info[i].scnhdr); + + PROGRESS (1); + + if (s->s_name[0]) + { + fragS *frag = segment_info[i].frchainP->frch_root; + char *buffer; + + if (s->s_size == 0) + s->s_scnptr = 0; + else + { + buffer = xmalloc (s->s_size); + s->s_scnptr = *file_cursor; + } + know (s->s_paddr == paddr); + + if (strcmp (s->s_name, ".text") == 0) + s->s_flags |= STYP_TEXT; + else if (strcmp (s->s_name, ".data") == 0) + s->s_flags |= STYP_DATA; + else if (strcmp (s->s_name, ".bss") == 0) + { + s->s_scnptr = 0; + s->s_flags |= STYP_BSS; + + /* @@ Should make the i386 and a29k coff targets define + COFF_NOLOAD_PROBLEM, and have only one test here. */ +#ifndef TC_I386 +#ifndef TC_A29K +#ifndef COFF_NOLOAD_PROBLEM + /* Apparently the SVR3 linker (and exec syscall) and UDI + mondfe progrem are confused by noload sections. */ + s->s_flags |= STYP_NOLOAD; +#endif +#endif +#endif + } + else if (strcmp (s->s_name, ".lit") == 0) + s->s_flags = STYP_LIT | STYP_TEXT; + else if (strcmp (s->s_name, ".init") == 0) + s->s_flags |= STYP_TEXT; + else if (strcmp (s->s_name, ".fini") == 0) + s->s_flags |= STYP_TEXT; + else if (strncmp (s->s_name, ".comment", 8) == 0) + s->s_flags |= STYP_INFO; + + while (frag) + { + unsigned int fill_size; + switch (frag->fr_type) + { + case rs_machine_dependent: + if (frag->fr_fix) + { + memcpy (buffer + frag->fr_address, + frag->fr_literal, + (unsigned int) frag->fr_fix); + offset += frag->fr_fix; + } + + break; + case rs_space: + assert (frag->fr_symbol == 0); + case rs_fill: + case rs_align: + case rs_align_code: + case rs_org: + if (frag->fr_fix) + { + memcpy (buffer + frag->fr_address, + frag->fr_literal, + (unsigned int) frag->fr_fix); + offset += frag->fr_fix; + } + + fill_size = frag->fr_var; + if (fill_size && frag->fr_offset > 0) + { + unsigned int count; + unsigned int off = frag->fr_fix; + for (count = frag->fr_offset; count; count--) + { + if (fill_size + frag->fr_address + off <= s->s_size) + { + memcpy (buffer + frag->fr_address + off, + frag->fr_literal + frag->fr_fix, + fill_size); + off += fill_size; + offset += fill_size; + } + } + } + break; + case rs_broken_word: + break; + default: + abort (); + } + frag = frag->fr_next; + } + + if (s->s_size != 0) + { + if (s->s_scnptr != 0) + { + bfd_write (buffer, s->s_size, 1, abfd); + *file_cursor += s->s_size; + } + free (buffer); + } + paddr += s->s_size; + } + } +} + +/* Coff file generation & utilities */ + +static void +coff_header_append (abfd, h) + bfd * abfd; + object_headers * h; +{ + unsigned int i; + char buffer[1000]; + char buffero[1000]; +#ifdef COFF_LONG_SECTION_NAMES + unsigned long string_size = 4; +#endif + + bfd_seek (abfd, 0, 0); + +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER + H_SET_MAGIC_NUMBER (h, COFF_MAGIC); + H_SET_VERSION_STAMP (h, 0); + H_SET_ENTRY_POINT (h, 0); + H_SET_TEXT_START (h, segment_info[SEG_E0].frchainP->frch_root->fr_address); + H_SET_DATA_START (h, segment_info[SEG_E1].frchainP->frch_root->fr_address); + H_SET_SIZEOF_OPTIONAL_HEADER (h, bfd_coff_swap_aouthdr_out(abfd, &h->aouthdr, + buffero)); +#else /* defined (OBJ_COFF_OMIT_OPTIONAL_HEADER) */ + H_SET_SIZEOF_OPTIONAL_HEADER (h, 0); +#endif /* defined (OBJ_COFF_OMIT_OPTIONAL_HEADER) */ + + i = bfd_coff_swap_filehdr_out (abfd, &h->filehdr, buffer); + + bfd_write (buffer, i, 1, abfd); + bfd_write (buffero, H_GET_SIZEOF_OPTIONAL_HEADER (h), 1, abfd); + + for (i = SEG_E0; i < SEG_LAST; i++) + { + if (segment_info[i].scnhdr.s_name[0]) + { + unsigned int size; + +#ifdef COFF_LONG_SECTION_NAMES + /* Support long section names as found in PE. This code + must coordinate with that in write_object_file and + w_strings. */ + if (strlen (segment_info[i].name) > SCNNMLEN) + { + memset (segment_info[i].scnhdr.s_name, 0, SCNNMLEN); + sprintf (segment_info[i].scnhdr.s_name, "/%lu", string_size); + string_size += strlen (segment_info[i].name) + 1; + } +#endif + + size = bfd_coff_swap_scnhdr_out (abfd, + &(segment_info[i].scnhdr), + buffer); + if (size == 0) + as_bad ("bfd_coff_swap_scnhdr_out failed"); + bfd_write (buffer, size, 1, abfd); + } + } +} + + +char * +symbol_to_chars (abfd, where, symbolP) + bfd * abfd; + char *where; + symbolS * symbolP; +{ + unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux; + unsigned int i; + valueT val; + + /* Turn any symbols with register attributes into abs symbols */ + if (S_GET_SEGMENT (symbolP) == reg_section) + { + S_SET_SEGMENT (symbolP, absolute_section); + } + /* At the same time, relocate all symbols to their output value */ + + val = (segment_info[S_GET_SEGMENT (symbolP)].scnhdr.s_paddr + + S_GET_VALUE (symbolP)); + + S_SET_VALUE (symbolP, val); + + symbolP->sy_symbol.ost_entry.n_value = val; + + where += bfd_coff_swap_sym_out (abfd, &symbolP->sy_symbol.ost_entry, + where); + + for (i = 0; i < numaux; i++) + { + where += bfd_coff_swap_aux_out (abfd, + &symbolP->sy_symbol.ost_auxent[i], + S_GET_DATA_TYPE (symbolP), + S_GET_STORAGE_CLASS (symbolP), + i, numaux, where); + } + return where; + +} + +void +coff_obj_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + char underscore = 0; /* Symbol has leading _ */ + + /* Effective symbol */ + /* Store the pointer in the offset. */ + S_SET_ZEROES (symbolP, 0L); + S_SET_DATA_TYPE (symbolP, T_NULL); + S_SET_STORAGE_CLASS (symbolP, 0); + S_SET_NUMBER_AUXILIARY (symbolP, 0); + /* Additional information */ + symbolP->sy_symbol.ost_flags = 0; + /* Auxiliary entries */ + memset ((char *) &symbolP->sy_symbol.ost_auxent[0], 0, AUXESZ); + + if (S_IS_STRING (symbolP)) + SF_SET_STRING (symbolP); + if (!underscore && S_IS_LOCAL (symbolP)) + SF_SET_LOCAL (symbolP); +} + +/* + * Handle .ln directives. + */ + +static void +obj_coff_ln (appline) + int appline; +{ + int l; + + if (! appline && def_symbol_in_progress != NULL) + { + as_warn (".ln pseudo-op inside .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* wrong context */ + + l = get_absolute_expression (); + c_line_new (0, frag_now_fix (), l, frag_now); + + if (appline) + new_logical_line ((char *) NULL, l - 1); + +#ifndef NO_LISTING + { + extern int listing; + + if (listing) + { + if (! appline) + l += line_base - 1; + listing_source_line ((unsigned int) l); + } + + } +#endif + demand_empty_rest_of_line (); +} + +/* + * def() + * + * Handle .def directives. + * + * One might ask : why can't we symbol_new if the symbol does not + * already exist and fill it with debug information. Because of + * the C_EFCN special symbol. It would clobber the value of the + * function symbol before we have a chance to notice that it is + * a C_EFCN. And a second reason is that the code is more clear this + * way. (at least I think it is :-). + * + */ + +#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') +#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ + *input_line_pointer == '\t') \ + input_line_pointer++; + +static void +obj_coff_def (what) + int what; +{ + char name_end; /* Char after the end of name */ + char *symbol_name; /* Name of the debug symbol */ + char *symbol_name_copy; /* Temporary copy of the name */ + unsigned int symbol_name_length; + + if (def_symbol_in_progress != NULL) + { + as_warn (".def pseudo-op used inside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + SKIP_WHITESPACES (); + + def_symbol_in_progress = (symbolS *) obstack_alloc (¬es, sizeof (*def_symbol_in_progress)); + memset (def_symbol_in_progress, 0, sizeof (*def_symbol_in_progress)); + + symbol_name = input_line_pointer; + name_end = get_symbol_end (); + symbol_name_length = strlen (symbol_name); + symbol_name_copy = xmalloc (symbol_name_length + 1); + strcpy (symbol_name_copy, symbol_name); +#ifdef tc_canonicalize_symbol_name + symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy); +#endif + + /* Initialize the new symbol */ +#ifdef STRIP_UNDERSCORE + S_SET_NAME (def_symbol_in_progress, (*symbol_name_copy == '_' + ? symbol_name_copy + 1 + : symbol_name_copy)); +#else /* STRIP_UNDERSCORE */ + S_SET_NAME (def_symbol_in_progress, symbol_name_copy); +#endif /* STRIP_UNDERSCORE */ + /* free(symbol_name_copy); */ + def_symbol_in_progress->sy_name_offset = (unsigned long) ~0; + def_symbol_in_progress->sy_number = ~0; + def_symbol_in_progress->sy_frag = &zero_address_frag; + S_SET_VALUE (def_symbol_in_progress, 0); + + if (S_IS_STRING (def_symbol_in_progress)) + SF_SET_STRING (def_symbol_in_progress); + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +unsigned int dim_index; + + +static void +obj_coff_endef (ignore) + int ignore; +{ + symbolS *symbolP = 0; + /* DIM BUG FIX sac@cygnus.com */ + dim_index = 0; + if (def_symbol_in_progress == NULL) + { + as_warn (".endef pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + /* Set the section number according to storage class. */ + switch (S_GET_STORAGE_CLASS (def_symbol_in_progress)) + { + case C_STRTAG: + case C_ENTAG: + case C_UNTAG: + SF_SET_TAG (def_symbol_in_progress); + /* intentional fallthrough */ + case C_FILE: + case C_TPDEF: + SF_SET_DEBUG (def_symbol_in_progress); + S_SET_SEGMENT (def_symbol_in_progress, SEG_DEBUG); + break; + + case C_EFCN: + SF_SET_LOCAL (def_symbol_in_progress); /* Do not emit this symbol. */ + /* intentional fallthrough */ + case C_BLOCK: + SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing */ + /* intentional fallthrough */ + case C_FCN: + S_SET_SEGMENT (def_symbol_in_progress, SEG_E0); + + if (strcmp (S_GET_NAME (def_symbol_in_progress), ".bf") == 0) + { /* .bf */ + if (function_lineoff < 0) + { + fprintf (stderr, "`.bf' symbol without preceding function\n"); + } /* missing function symbol */ + SA_GET_SYM_LNNOPTR (last_line_symbol) = function_lineoff; + + SF_SET_PROCESS (last_line_symbol); + SF_SET_ADJ_LNNOPTR (last_line_symbol); + SF_SET_PROCESS (def_symbol_in_progress); + function_lineoff = -1; + } + /* Value is always set to . */ + def_symbol_in_progress->sy_frag = frag_now; + S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); + break; + +#ifdef C_AUTOARG + case C_AUTOARG: +#endif /* C_AUTOARG */ + case C_AUTO: + case C_REG: + case C_MOS: + case C_MOE: + case C_MOU: + case C_ARG: + case C_REGPARM: + case C_FIELD: + case C_EOS: + SF_SET_DEBUG (def_symbol_in_progress); + S_SET_SEGMENT (def_symbol_in_progress, absolute_section); + break; + + case C_EXT: + case C_STAT: + case C_LABEL: + /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ + break; + + case C_USTATIC: + case C_EXTDEF: + case C_ULABEL: + as_warn ("unexpected storage class %d", S_GET_STORAGE_CLASS (def_symbol_in_progress)); + break; + } /* switch on storage class */ + + /* Now that we have built a debug symbol, try to find if we should + merge with an existing symbol or not. If a symbol is C_EFCN or + absolute_section or untagged SEG_DEBUG it never merges. We also + don't merge labels, which are in a different namespace, nor + symbols which have not yet been defined since they are typically + unique, nor do we merge tags with non-tags. */ + + /* Two cases for functions. Either debug followed by definition or + definition followed by debug. For definition first, we will + merge the debug symbol into the definition. For debug first, the + lineno entry MUST point to the definition function or else it + will point off into space when crawl_symbols() merges the debug + symbol into the real symbol. Therefor, let's presume the debug + symbol is a real function reference. */ + + /* FIXME-SOON If for some reason the definition label/symbol is + never seen, this will probably leave an undefined symbol at link + time. */ + + if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN + || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL + || (S_GET_SEGMENT (def_symbol_in_progress) == SEG_DEBUG + && !SF_GET_TAG (def_symbol_in_progress)) + || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section + || def_symbol_in_progress->sy_value.X_op != O_constant + || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL + || (SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))) + { + symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, + &symbol_lastP); + } + else + { + /* This symbol already exists, merge the newly created symbol + into the old one. This is not mandatory. The linker can + handle duplicate symbols correctly. But I guess that it save + a *lot* of space if the assembly file defines a lot of + symbols. [loic] */ + + /* The debug entry (def_symbol_in_progress) is merged into the + previous definition. */ + + c_symbol_merge (def_symbol_in_progress, symbolP); + /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */ + def_symbol_in_progress = symbolP; + + if (SF_GET_FUNCTION (def_symbol_in_progress) + || SF_GET_TAG (def_symbol_in_progress) + || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT) + { + /* For functions, and tags, and static symbols, the symbol + *must* be where the debug symbol appears. Move the + existing symbol to the current place. */ + /* If it already is at the end of the symbol list, do nothing */ + if (def_symbol_in_progress != symbol_lastP) + { + symbol_remove (def_symbol_in_progress, &symbol_rootP, + &symbol_lastP); + symbol_append (def_symbol_in_progress, symbol_lastP, + &symbol_rootP, &symbol_lastP); + } /* if not already in place */ + } /* if function */ + } /* normal or mergable */ + + if (SF_GET_TAG (def_symbol_in_progress)) + { + symbolS *oldtag; + + oldtag = symbol_find_base (S_GET_NAME (def_symbol_in_progress), + DO_NOT_STRIP); + if (oldtag == NULL || ! SF_GET_TAG (oldtag)) + tag_insert (S_GET_NAME (def_symbol_in_progress), + def_symbol_in_progress); + } + + if (SF_GET_FUNCTION (def_symbol_in_progress)) + { + know (sizeof (def_symbol_in_progress) <= sizeof (long)); + function_lineoff + = c_line_new (def_symbol_in_progress, 0, 0, &zero_address_frag); + + SF_SET_PROCESS (def_symbol_in_progress); + + if (symbolP == NULL) + { + /* That is, if this is the first time we've seen the + function... */ + symbol_table_insert (def_symbol_in_progress); + } /* definition follows debug */ + } /* Create the line number entry pointing to the function being defined */ + + def_symbol_in_progress = NULL; + demand_empty_rest_of_line (); +} + +static void +obj_coff_dim (ignore) + int ignore; +{ + int dim_index; + + if (def_symbol_in_progress == NULL) + { + as_warn (".dim pseudo-op used outside of .def/.endef: ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + + for (dim_index = 0; dim_index < DIMNUM; dim_index++) + { + SKIP_WHITESPACES (); + SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index, + get_absolute_expression ()); + + switch (*input_line_pointer) + { + case ',': + input_line_pointer++; + break; + + default: + as_warn ("badly formed .dim directive ignored"); + /* intentional fallthrough */ + case '\n': + case ';': + dim_index = DIMNUM; + break; + } + } + + demand_empty_rest_of_line (); +} + +static void +obj_coff_line (ignore) + int ignore; +{ + int this_base; + const char *name; + + if (def_symbol_in_progress == NULL) + { + obj_coff_ln (0); + return; + } + + name = S_GET_NAME (def_symbol_in_progress); + this_base = get_absolute_expression (); + + /* Only .bf symbols indicate the use of a new base line number; the + line numbers associated with .ef, .bb, .eb are relative to the + start of the containing function. */ + if (!strcmp (".bf", name)) + { +#if 0 /* XXX Can we ever have line numbers going backwards? */ + if (this_base > line_base) +#endif + { + line_base = this_base; + } + +#ifndef NO_LISTING + { + extern int listing; + if (listing) + { + listing_source_line ((unsigned int) line_base); + } + } +#endif + } + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + SA_SET_SYM_LNNO (def_symbol_in_progress, this_base); + + demand_empty_rest_of_line (); +} + +static void +obj_coff_size (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".size pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ()); + demand_empty_rest_of_line (); +} + +static void +obj_coff_scl (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".scl pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ()); + demand_empty_rest_of_line (); +} + +static void +obj_coff_tag (ignore) + int ignore; +{ + char *symbol_name; + char name_end; + + if (def_symbol_in_progress == NULL) + { + as_warn (".tag pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } + + S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); + symbol_name = input_line_pointer; + name_end = get_symbol_end (); +#ifdef tc_canonicalize_symbol_name + symbol_name = tc_canonicalize_symbol_name (symbol_name); +#endif + + /* Assume that the symbol referred to by .tag is always defined. + This was a bad assumption. I've added find_or_make. xoxorich. */ + SA_SET_SYM_TAGNDX (def_symbol_in_progress, + (long) tag_find_or_make (symbol_name)); + if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L) + { + as_warn ("tag not found for .tag %s", symbol_name); + } /* not defined */ + + SF_SET_TAGGED (def_symbol_in_progress); + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +static void +obj_coff_type (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".type pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ()); + + if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) && + S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF) + { + SF_SET_FUNCTION (def_symbol_in_progress); + } /* is a function */ + + demand_empty_rest_of_line (); +} + +static void +obj_coff_val (ignore) + int ignore; +{ + if (def_symbol_in_progress == NULL) + { + as_warn (".val pseudo-op used outside of .def/.endef ignored."); + demand_empty_rest_of_line (); + return; + } /* if not inside .def/.endef */ + + if (is_name_beginner (*input_line_pointer)) + { + char *symbol_name = input_line_pointer; + char name_end = get_symbol_end (); + +#ifdef tc_canonicalize_symbol_name + symbol_name = tc_canonicalize_symbol_name (symbol_name); +#endif + + if (!strcmp (symbol_name, ".")) + { + def_symbol_in_progress->sy_frag = frag_now; + S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); + /* If the .val is != from the .def (e.g. statics) */ + } + else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name)) + { + def_symbol_in_progress->sy_value.X_op = O_symbol; + def_symbol_in_progress->sy_value.X_add_symbol = + symbol_find_or_make (symbol_name); + def_symbol_in_progress->sy_value.X_op_symbol = NULL; + def_symbol_in_progress->sy_value.X_add_number = 0; + + /* If the segment is undefined when the forward reference is + resolved, then copy the segment id from the forward + symbol. */ + SF_SET_GET_SEGMENT (def_symbol_in_progress); + + /* FIXME: gcc can generate address expressions + here in unusual cases (search for "obscure" + in sdbout.c). We just ignore the offset + here, thus generating incorrect debugging + information. We ignore the rest of the + line just below. */ + } + /* Otherwise, it is the name of a non debug symbol and + its value will be calculated later. */ + *input_line_pointer = name_end; + + /* FIXME: this is to avoid an error message in the + FIXME case mentioned just above. */ + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + else + { + S_SET_VALUE (def_symbol_in_progress, + (valueT) get_absolute_expression ()); + } /* if symbol based */ + + demand_empty_rest_of_line (); +} + +#ifdef TE_PE + +/* Handle the .linkonce pseudo-op. This is parsed by s_linkonce in + read.c, which then calls this object file format specific routine. */ + +void +obj_coff_pe_handle_link_once (type) + enum linkonce_type type; +{ + seg_info (now_seg)->scnhdr.s_flags |= IMAGE_SCN_LNK_COMDAT; + + /* We store the type in the seg_info structure, and use it to set up + the auxiliary entry for the section symbol in c_section_symbol. */ + seg_info (now_seg)->linkonce = type; +} + +#endif /* TE_PE */ + +void +coff_obj_read_begin_hook () +{ + /* These had better be the same. Usually 18 bytes. */ +#ifndef BFD_HEADERS + know (sizeof (SYMENT) == sizeof (AUXENT)); + know (SYMESZ == AUXESZ); +#endif + tag_init (); +} + +/* This function runs through the symbol table and puts all the + externals onto another chain */ + +/* The chain of globals. */ +symbolS *symbol_globalP; +symbolS *symbol_global_lastP; + +/* The chain of externals */ +symbolS *symbol_externP; +symbolS *symbol_extern_lastP; + +stack *block_stack; +symbolS *last_functionP; +static symbolS *last_bfP; +symbolS *last_tagP; + +static unsigned int +yank_symbols () +{ + symbolS *symbolP; + unsigned int symbol_number = 0; + unsigned int last_file_symno = 0; + + struct filename_list *filename_list_scan = filename_list_head; + + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbolP ? symbol_next (symbolP) : symbol_rootP) + { + if (symbolP->sy_mri_common) + { + if (S_GET_STORAGE_CLASS (symbolP) == C_EXT) + as_bad ("%s: global symbols not supported in common sections", + S_GET_NAME (symbolP)); + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + continue; + } + + if (!SF_GET_DEBUG (symbolP)) + { + /* Debug symbols do not need all this rubbish */ + symbolS *real_symbolP; + + /* L* and C_EFCN symbols never merge. */ + if (!SF_GET_LOCAL (symbolP) + && !SF_GET_STATICS (symbolP) + && S_GET_STORAGE_CLASS (symbolP) != C_LABEL + && symbolP->sy_value.X_op == O_constant + && (real_symbolP = symbol_find_base (S_GET_NAME (symbolP), DO_NOT_STRIP)) + && real_symbolP != symbolP) + { + /* FIXME-SOON: where do dups come from? + Maybe tag references before definitions? xoxorich. */ + /* Move the debug data from the debug symbol to the + real symbol. Do NOT do the oposite (i.e. move from + real symbol to debug symbol and remove real symbol from the + list.) Because some pointers refer to the real symbol + whereas no pointers refer to the debug symbol. */ + c_symbol_merge (symbolP, real_symbolP); + /* Replace the current symbol by the real one */ + /* The symbols will never be the last or the first + because : 1st symbol is .file and 3 last symbols are + .text, .data, .bss */ + symbol_remove (real_symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert (real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + symbolP = real_symbolP; + } /* if not local but dup'd */ + + if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_E1)) + { + S_SET_SEGMENT (symbolP, SEG_E0); + } /* push data into text */ + + resolve_symbol_value (symbolP); + + if (S_GET_STORAGE_CLASS (symbolP) == C_NULL) + { + if (!S_IS_DEFINED (symbolP) && !SF_GET_LOCAL (symbolP)) + { + S_SET_EXTERNAL (symbolP); + } + else if (S_GET_SEGMENT (symbolP) == SEG_E0) + { + S_SET_STORAGE_CLASS (symbolP, C_LABEL); + } + else + { + S_SET_STORAGE_CLASS (symbolP, C_STAT); + } + } + + /* Mainly to speed up if not -g */ + if (SF_GET_PROCESS (symbolP)) + { + /* Handle the nested blocks auxiliary info. */ + if (S_GET_STORAGE_CLASS (symbolP) == C_BLOCK) + { + if (!strcmp (S_GET_NAME (symbolP), ".bb")) + stack_push (block_stack, (char *) &symbolP); + else + { /* .eb */ + register symbolS *begin_symbolP; + begin_symbolP = *(symbolS **) stack_pop (block_stack); + if (begin_symbolP == (symbolS *) 0) + as_warn ("mismatched .eb"); + else + SA_SET_SYM_ENDNDX (begin_symbolP, symbol_number + 2); + } + } + /* If we are able to identify the type of a function, and we + are out of a function (last_functionP == 0) then, the + function symbol will be associated with an auxiliary + entry. */ + if (last_functionP == (symbolS *) 0 && + SF_GET_FUNCTION (symbolP)) + { + last_functionP = symbolP; + + if (S_GET_NUMBER_AUXILIARY (symbolP) < 1) + { + S_SET_NUMBER_AUXILIARY (symbolP, 1); + } /* make it at least 1 */ + + /* Clobber possible stale .dim information. */ +#if 0 + /* Iffed out by steve - this fries the lnnoptr info too */ + bzero (symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen, + sizeof (symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen)); +#endif + } + if (S_GET_STORAGE_CLASS (symbolP) == C_FCN) + { + if (strcmp (S_GET_NAME (symbolP), ".bf") == 0) + { + if (last_bfP != NULL) + SA_SET_SYM_ENDNDX (last_bfP, symbol_number); + last_bfP = symbolP; + } + } + else if (S_GET_STORAGE_CLASS (symbolP) == C_EFCN) + { + /* I don't even know if this is needed for sdb. But + the standard assembler generates it, so... */ + if (last_functionP == (symbolS *) 0) + as_fatal ("C_EFCN symbol out of scope"); + SA_SET_SYM_FSIZE (last_functionP, + (long) (S_GET_VALUE (symbolP) - + S_GET_VALUE (last_functionP))); + SA_SET_SYM_ENDNDX (last_functionP, symbol_number); + last_functionP = (symbolS *) 0; + } + } + } + else if (SF_GET_TAG (symbolP)) + { + /* First descriptor of a structure must point to + the first slot after the structure description. */ + last_tagP = symbolP; + + } + else if (S_GET_STORAGE_CLASS (symbolP) == C_EOS) + { + /* +2 take in account the current symbol */ + SA_SET_SYM_ENDNDX (last_tagP, symbol_number + 2); + } + else if (S_GET_STORAGE_CLASS (symbolP) == C_FILE) + { + /* If the filename was too long to fit in the + auxent, put it in the string table */ + if (SA_GET_FILE_FNAME_ZEROS (symbolP) == 0 + && SA_GET_FILE_FNAME_OFFSET (symbolP) != 0) + { + SA_SET_FILE_FNAME_OFFSET (symbolP, string_byte_count); + string_byte_count += strlen (filename_list_scan->filename) + 1; + filename_list_scan = filename_list_scan->next; + } + if (S_GET_VALUE (symbolP)) + { + S_SET_VALUE (symbolP, last_file_symno); + last_file_symno = symbol_number; + } /* no one points at the first .file symbol */ + } /* if debug or tag or eos or file */ + +#ifdef tc_frob_coff_symbol + tc_frob_coff_symbol (symbolP); +#endif + + /* We must put the external symbols apart. The loader + does not bomb if we do not. But the references in + the endndx field for a .bb symbol are not corrected + if an external symbol is removed between .bb and .be. + I.e in the following case : + [20] .bb endndx = 22 + [21] foo external + [22] .be + ld will move the symbol 21 to the end of the list but + endndx will still be 22 instead of 21. */ + + + if (SF_GET_LOCAL (symbolP)) + { + /* remove C_EFCN and LOCAL (L...) symbols */ + /* next pointer remains valid */ + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + + } + else if (symbolP->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))) + { + /* Skip symbols which were equated to undefined or common + symbols. */ + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + } + else if (!S_IS_DEFINED (symbolP) + && !S_IS_DEBUG (symbolP) + && !SF_GET_STATICS (symbolP) && + S_GET_STORAGE_CLASS (symbolP) == C_EXT) + { /* C_EXT && !SF_GET_FUNCTION(symbolP)) */ + /* if external, Remove from the list */ + symbolS *hold = symbol_previous (symbolP); + + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers (symbolP); + symbol_append (symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP); + symbolP = hold; + } + else if (! S_IS_DEBUG (symbolP) + && ! SF_GET_STATICS (symbolP) + && ! SF_GET_FUNCTION (symbolP) + && S_GET_STORAGE_CLASS (symbolP) == C_EXT) + { + symbolS *hold = symbol_previous (symbolP); + + /* The O'Reilly COFF book says that defined global symbols + come at the end of the symbol table, just before + undefined global symbols. */ + + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + symbol_clear_list_pointers (symbolP); + symbol_append (symbolP, symbol_global_lastP, &symbol_globalP, + &symbol_global_lastP); + symbolP = hold; + } + else + { + if (SF_GET_STRING (symbolP)) + { + symbolP->sy_name_offset = string_byte_count; + string_byte_count += strlen (S_GET_NAME (symbolP)) + 1; + } + else + { + symbolP->sy_name_offset = 0; + } /* fix "long" names */ + + symbolP->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY (symbolP); + } /* if local symbol */ + } /* traverse the symbol list */ + return symbol_number; + +} + + +static unsigned int +glue_symbols (head, tail) + symbolS **head; + symbolS **tail; +{ + unsigned int symbol_number = 0; + + while (*head != NULL) + { + symbolS *tmp = *head; + + /* append */ + symbol_remove (tmp, head, tail); + symbol_append (tmp, symbol_lastP, &symbol_rootP, &symbol_lastP); + + /* and process */ + if (SF_GET_STRING (tmp)) + { + tmp->sy_name_offset = string_byte_count; + string_byte_count += strlen (S_GET_NAME (tmp)) + 1; + } + else + { + tmp->sy_name_offset = 0; + } /* fix "long" names */ + + tmp->sy_number = symbol_number; + symbol_number += 1 + S_GET_NUMBER_AUXILIARY (tmp); + } /* append the entire extern chain */ + + return symbol_number; +} + +static unsigned int +tie_tags () +{ + unsigned int symbol_number = 0; + symbolS *symbolP; + + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + symbolP->sy_number = symbol_number; + + if (SF_GET_TAGGED (symbolP)) + { + SA_SET_SYM_TAGNDX + (symbolP, + ((symbolS *) SA_GET_SYM_TAGNDX (symbolP))->sy_number); + } + + symbol_number += 1 + S_GET_NUMBER_AUXILIARY (symbolP); + } + + return symbol_number; +} + +static void +crawl_symbols (h, abfd) + object_headers *h; + bfd * abfd; +{ + unsigned int i; + + /* Initialize the stack used to keep track of the matching .bb .be */ + + block_stack = stack_init (512, sizeof (symbolS *)); + + /* The symbol list should be ordered according to the following sequence + * order : + * . .file symbol + * . debug entries for functions + * . fake symbols for the sections, including .text .data and .bss + * . defined symbols + * . undefined symbols + * But this is not mandatory. The only important point is to put the + * undefined symbols at the end of the list. + */ + + /* Is there a .file symbol ? If not insert one at the beginning. */ + if (symbol_rootP == NULL + || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE) + { + c_dot_file_symbol ("fake"); + } + + /* + * Build up static symbols for the sections, they are filled in later + */ + + + for (i = SEG_E0; i < SEG_LAST; i++) + if (segment_info[i].scnhdr.s_name[0]) + segment_info[i].dot = c_section_symbol (segment_info[i].name, + i - SEG_E0 + 1); + + /* Take all the externals out and put them into another chain */ + H_SET_SYMBOL_TABLE_SIZE (h, yank_symbols ()); + /* Take the externals and glue them onto the end.*/ + H_SET_SYMBOL_TABLE_SIZE (h, + (H_GET_SYMBOL_COUNT (h) + + glue_symbols (&symbol_globalP, + &symbol_global_lastP) + + glue_symbols (&symbol_externP, + &symbol_extern_lastP))); + + H_SET_SYMBOL_TABLE_SIZE (h, tie_tags ()); + know (symbol_globalP == NULL); + know (symbol_global_lastP == NULL); + know (symbol_externP == NULL); + know (symbol_extern_lastP == NULL); +} + +/* + * Find strings by crawling along symbol table chain. + */ + +void +w_strings (where) + char *where; +{ + symbolS *symbolP; + struct filename_list *filename_list_scan = filename_list_head; + + /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ + md_number_to_chars (where, (valueT) string_byte_count, 4); + where += 4; + +#ifdef COFF_LONG_SECTION_NAMES + /* Support long section names as found in PE. This code must + coordinate with that in coff_header_append and write_object_file. */ + { + unsigned int i; + + for (i = SEG_E0; i < SEG_LAST; i++) + { + if (segment_info[i].scnhdr.s_name[0] + && strlen (segment_info[i].name) > SCNNMLEN) + { + unsigned int size; + + size = strlen (segment_info[i].name) + 1; + memcpy (where, segment_info[i].name, size); + where += size; + } + } + } +#endif /* COFF_LONG_SECTION_NAMES */ + + for (symbolP = symbol_rootP; + symbolP; + symbolP = symbol_next (symbolP)) + { + unsigned int size; + + if (SF_GET_STRING (symbolP)) + { + size = strlen (S_GET_NAME (symbolP)) + 1; + memcpy (where, S_GET_NAME (symbolP), size); + where += size; + } + if (S_GET_STORAGE_CLASS (symbolP) == C_FILE + && SA_GET_FILE_FNAME_ZEROS (symbolP) == 0 + && SA_GET_FILE_FNAME_OFFSET (symbolP) != 0) + { + size = strlen (filename_list_scan->filename) + 1; + memcpy (where, filename_list_scan->filename, size); + filename_list_scan = filename_list_scan ->next; + where += size; + } + } +} + +static void +do_linenos_for (abfd, h, file_cursor) + bfd * abfd; + object_headers * h; + unsigned long *file_cursor; +{ + unsigned int idx; + unsigned long start = *file_cursor; + + for (idx = SEG_E0; idx < SEG_LAST; idx++) + { + segment_info_type *s = segment_info + idx; + + + if (s->scnhdr.s_nlnno != 0) + { + struct lineno_list *line_ptr; + + struct external_lineno *buffer = + (struct external_lineno *) xmalloc (s->scnhdr.s_nlnno * LINESZ); + + struct external_lineno *dst = buffer; + + /* Run through the table we've built and turn it into its external + form, take this chance to remove duplicates */ + + for (line_ptr = s->lineno_list_head; + line_ptr != (struct lineno_list *) NULL; + line_ptr = line_ptr->next) + { + + if (line_ptr->line.l_lnno == 0) + { + /* Turn a pointer to a symbol into the symbols' index */ + line_ptr->line.l_addr.l_symndx = + ((symbolS *) line_ptr->line.l_addr.l_symndx)->sy_number; + } + else + { + line_ptr->line.l_addr.l_paddr += ((struct frag *) (line_ptr->frag))->fr_address; + } + + + (void) bfd_coff_swap_lineno_out (abfd, &(line_ptr->line), dst); + dst++; + + } + + s->scnhdr.s_lnnoptr = *file_cursor; + + bfd_write (buffer, 1, s->scnhdr.s_nlnno * LINESZ, abfd); + free (buffer); + + *file_cursor += s->scnhdr.s_nlnno * LINESZ; + } + } + H_SET_LINENO_SIZE (h, *file_cursor - start); +} + + +/* Now we run through the list of frag chains in a segment and + make all the subsegment frags appear at the end of the + list, as if the seg 0 was extra long */ + +static void +remove_subsegs () +{ + unsigned int i; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + frchainS *head = segment_info[i].frchainP; + fragS dummy; + fragS *prev_frag = &dummy; + + while (head && head->frch_seg == i) + { + prev_frag->fr_next = head->frch_root; + prev_frag = head->frch_last; + head = head->frch_next; + } + prev_frag->fr_next = 0; + } +} + +unsigned long machine; +int coff_flags; +extern void +write_object_file () +{ + int i; + const char *name; + struct frchain *frchain_ptr; + + object_headers headers; + unsigned long file_cursor; + bfd *abfd; + unsigned int addr; + abfd = bfd_openw (out_file_name, TARGET_FORMAT); + + + if (abfd == 0) + { + as_perror ("FATAL: Can't create %s", out_file_name); + exit (EXIT_FAILURE); + } + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, BFD_ARCH, machine); + + string_byte_count = 4; + + for (frchain_ptr = frchain_root; + frchain_ptr != (struct frchain *) NULL; + frchain_ptr = frchain_ptr->frch_next) + { + /* Run through all the sub-segments and align them up. Also + close any open frags. We tack a .fill onto the end of the + frag chain so that any .align's size can be worked by looking + at the next frag. */ + + subseg_set (frchain_ptr->frch_seg, frchain_ptr->frch_subseg); +#ifndef SUB_SEGMENT_ALIGN +#define SUB_SEGMENT_ALIGN(SEG) 1 +#endif +#ifdef md_do_align + md_do_align (SUB_SEGMENT_ALIGN (now_seg), (char *) NULL, 0, 0, + alignment_done); +#endif + frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE, 0); +#ifdef md_do_align + alignment_done: +#endif + frag_wane (frag_now); + frag_now->fr_fix = 0; + know (frag_now->fr_next == NULL); + } + + + remove_subsegs (); + + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + relax_segment (segment_info[i].frchainP->frch_root, i); + } + + H_SET_NUMBER_OF_SECTIONS (&headers, 0); + + /* Find out how big the sections are, and set the addresses. */ + addr = 0; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + long size; + + segment_info[i].scnhdr.s_paddr = addr; + segment_info[i].scnhdr.s_vaddr = addr; + + if (segment_info[i].scnhdr.s_name[0]) + { + H_SET_NUMBER_OF_SECTIONS (&headers, + H_GET_NUMBER_OF_SECTIONS (&headers) + 1); + +#ifdef COFF_LONG_SECTION_NAMES + /* Support long section names as found in PE. This code + must coordinate with that in coff_header_append and + w_strings. */ + { + unsigned int len; + + len = strlen (segment_info[i].name); + if (len > SCNNMLEN) + string_byte_count += len + 1; + } +#endif /* COFF_LONG_SECTION_NAMES */ + } + + size = size_section (abfd, (unsigned int) i); + addr += size; + + /* I think the section alignment is only used on the i960; the + i960 needs it, and it should do no harm on other targets. */ + segment_info[i].scnhdr.s_align = 1 << section_alignment[i]; + + if (i == SEG_E0) + H_SET_TEXT_SIZE (&headers, size); + else if (i == SEG_E1) + H_SET_DATA_SIZE (&headers, size); + else if (i == SEG_E2) + H_SET_BSS_SIZE (&headers, size); + } + + /* Turn the gas native symbol table shape into a coff symbol table */ + crawl_symbols (&headers, abfd); + + if (string_byte_count == 4) + string_byte_count = 0; + + H_SET_STRING_SIZE (&headers, string_byte_count); + +#ifdef tc_frob_file + tc_frob_file (); +#endif + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + fixup_mdeps (segment_info[i].frchainP->frch_root, &headers, i); + fixup_segment (&segment_info[i], i); + } + + /* Look for ".stab" segments and fill in their initial symbols + correctly. */ + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + name = segment_info[i].name; + + if (name != NULL + && strncmp (".stab", name, 5) == 0 + && strncmp (".stabstr", name, 8) != 0) + adjust_stab_section (abfd, i); + } + + file_cursor = H_GET_TEXT_FILE_OFFSET (&headers); + + bfd_seek (abfd, (file_ptr) file_cursor, 0); + + /* Plant the data */ + + fill_section (abfd, &headers, &file_cursor); + + do_relocs_for (abfd, &headers, &file_cursor); + + do_linenos_for (abfd, &headers, &file_cursor); + + H_SET_FILE_MAGIC_NUMBER (&headers, COFF_MAGIC); +#ifndef OBJ_COFF_OMIT_TIMESTAMP + H_SET_TIME_STAMP (&headers, (long)time((time_t *)0)); +#else + H_SET_TIME_STAMP (&headers, 0); +#endif +#ifdef TC_COFF_SET_MACHINE + TC_COFF_SET_MACHINE (&headers); +#endif + +#ifndef COFF_FLAGS +#define COFF_FLAGS 0 +#endif + +#ifdef KEEP_RELOC_INFO + H_SET_FLAGS (&headers, ((H_GET_LINENO_SIZE(&headers) ? 0 : F_LNNO) | + COFF_FLAGS | coff_flags)); +#else + H_SET_FLAGS (&headers, ((H_GET_LINENO_SIZE(&headers) ? 0 : F_LNNO) | + (H_GET_RELOCATION_SIZE(&headers) ? 0 : F_RELFLG) | + COFF_FLAGS | coff_flags)); +#endif + + { + unsigned int symtable_size = H_GET_SYMBOL_TABLE_SIZE (&headers); + char *buffer1 = xmalloc (symtable_size + string_byte_count + 1); + + H_SET_SYMBOL_TABLE_POINTER (&headers, bfd_tell (abfd)); + w_symbols (abfd, buffer1, symbol_rootP); + if (string_byte_count > 0) + w_strings (buffer1 + symtable_size); + bfd_write (buffer1, 1, symtable_size + string_byte_count, abfd); + free (buffer1); + } + + coff_header_append (abfd, &headers); +#if 0 + /* Recent changes to write need this, but where it should + go is up to Ken.. */ + if (bfd_close_all_done (abfd) == false) + as_fatal ("Can't close %s: %s", out_file_name, + bfd_errmsg (bfd_get_error ())); +#else + { + extern bfd *stdoutput; + stdoutput = abfd; + } +#endif + +} + +/* Add a new segment. This is called from subseg_new via the + obj_new_segment macro. */ + +segT +obj_coff_add_segment (name) + const char *name; +{ + unsigned int i; + +#ifndef COFF_LONG_SECTION_NAMES + char buf[SCNNMLEN + 1]; + + strncpy (buf, name, SCNNMLEN); + buf[SCNNMLEN] = '\0'; + name = buf; +#endif + + for (i = SEG_E0; i < SEG_LAST && segment_info[i].scnhdr.s_name[0]; i++) + if (strcmp (name, segment_info[i].name) == 0) + return (segT) i; + + if (i == SEG_LAST) + { + as_bad ("Too many new sections; can't add \"%s\"", name); + return now_seg; + } + + /* Add a new section. */ + strncpy (segment_info[i].scnhdr.s_name, name, + sizeof (segment_info[i].scnhdr.s_name)); + segment_info[i].scnhdr.s_flags = STYP_REG; + segment_info[i].name = xstrdup (name); + + return (segT) i; +} + +/* + * implement the .section pseudo op: + * .section name {, "flags"} + * ^ ^ + * | +--- optional flags: 'b' for bss + * | 'i' for info + * +-- section name 'l' for lib + * 'n' for noload + * 'o' for over + * 'w' for data + * 'd' (apparently m88k for data) + * 'x' for text + * 'r' for read-only data + * But if the argument is not a quoted string, treat it as a + * subsegment number. + */ + +void +obj_coff_section (ignore) + int ignore; +{ + /* Strip out the section name */ + char *section_name, *name; + char c; + unsigned int exp; + long flags; + + if (flag_mri) + { + char type; + + s_mri_sect (&type); + flags = 0; + if (type == 'C') + flags = STYP_TEXT; + else if (type == 'D') + flags = STYP_DATA; + segment_info[now_seg].scnhdr.s_flags |= flags; + + return; + } + + section_name = input_line_pointer; + c = get_symbol_end (); + + name = xmalloc (input_line_pointer - section_name + 1); + strcpy (name, section_name); + + *input_line_pointer = c; + + exp = 0; + flags = 0; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + + if (*input_line_pointer != '"') + exp = get_absolute_expression (); + else + { + ++input_line_pointer; + while (*input_line_pointer != '"' + && ! is_end_of_line[(unsigned char) *input_line_pointer]) + { + switch (*input_line_pointer) + { + case 'b': flags |= STYP_BSS; break; + case 'i': flags |= STYP_INFO; break; + case 'l': flags |= STYP_LIB; break; + case 'n': flags |= STYP_NOLOAD; break; + case 'o': flags |= STYP_OVER; break; + case 'd': + case 'w': flags |= STYP_DATA; break; + case 'x': flags |= STYP_TEXT; break; + case 'r': flags |= STYP_LIT; break; + default: + as_warn("unknown section attribute '%c'", + *input_line_pointer); + break; + } + ++input_line_pointer; + } + if (*input_line_pointer == '"') + ++input_line_pointer; + } + } + + subseg_new (name, (subsegT) exp); + + segment_info[now_seg].scnhdr.s_flags |= flags; + + demand_empty_rest_of_line (); +} + + +static void +obj_coff_text (ignore) + int ignore; +{ + subseg_new (".text", get_absolute_expression ()); +} + + +static void +obj_coff_data (ignore) + int ignore; +{ + if (flag_readonly_data_in_text) + subseg_new (".text", get_absolute_expression () + 1000); + else + subseg_new (".data", get_absolute_expression ()); +} + +static void +obj_coff_bss (ignore) + int ignore; +{ + if (*input_line_pointer == '\n') /* .bss */ + subseg_new(".bss", get_absolute_expression()); + else /* .bss id,expr */ + obj_coff_lcomm(0); +} + +static void +obj_coff_ident (ignore) + int ignore; +{ + segT current_seg = now_seg; /* save current seg */ + subsegT current_subseg = now_subseg; + subseg_new (".comment", 0); /* .comment seg */ + stringer (1); /* read string */ + subseg_set (current_seg, current_subseg); /* restore current seg */ +} + +void +c_symbol_merge (debug, normal) + symbolS *debug; + symbolS *normal; +{ + S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug)); + S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug)); + + if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal)) + { + S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug)); + } /* take the most we have */ + + if (S_GET_NUMBER_AUXILIARY (debug) > 0) + { + memcpy ((char *) &normal->sy_symbol.ost_auxent[0], + (char *) &debug->sy_symbol.ost_auxent[0], + (unsigned int) (S_GET_NUMBER_AUXILIARY (debug) * AUXESZ)); + } /* Move all the auxiliary information */ + + /* Move the debug flags. */ + SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug)); +} /* c_symbol_merge() */ + +static int +c_line_new (symbol, paddr, line_number, frag) + symbolS * symbol; + long paddr; + int line_number; + fragS * frag; +{ + struct lineno_list *new_line = + (struct lineno_list *) xmalloc (sizeof (struct lineno_list)); + + segment_info_type *s = segment_info + now_seg; + new_line->line.l_lnno = line_number; + + if (line_number == 0) + { + last_line_symbol = symbol; + new_line->line.l_addr.l_symndx = (long) symbol; + } + else + { + new_line->line.l_addr.l_paddr = paddr; + } + + new_line->frag = (char *) frag; + new_line->next = (struct lineno_list *) NULL; + + + if (s->lineno_list_head == (struct lineno_list *) NULL) + { + s->lineno_list_head = new_line; + } + else + { + s->lineno_list_tail->next = new_line; + } + s->lineno_list_tail = new_line; + return LINESZ * s->scnhdr.s_nlnno++; +} + +void +c_dot_file_symbol (filename) + char *filename; +{ + symbolS *symbolP; + + symbolP = symbol_new (".file", + SEG_DEBUG, + 0, + &zero_address_frag); + + S_SET_STORAGE_CLASS (symbolP, C_FILE); + S_SET_NUMBER_AUXILIARY (symbolP, 1); + + if (strlen (filename) > FILNMLEN) + { + /* Filename is too long to fit into an auxent, + we stick it into the string table instead. We keep + a linked list of the filenames we find so we can emit + them later.*/ + struct filename_list *f = ((struct filename_list *) + xmalloc (sizeof (struct filename_list))); + + f->filename = filename; + f->next = 0; + + SA_SET_FILE_FNAME_ZEROS (symbolP, 0); + SA_SET_FILE_FNAME_OFFSET (symbolP, 1); + + if (filename_list_tail) + filename_list_tail->next = f; + else + filename_list_head = f; + filename_list_tail = f; + } + else + { + SA_SET_FILE_FNAME (symbolP, filename); + } +#ifndef NO_LISTING + { + extern int listing; + if (listing) + { + listing_source_file (filename); + } + + } + +#endif + SF_SET_DEBUG (symbolP); + S_SET_VALUE (symbolP, (valueT) previous_file_symbol); + + previous_file_symbol = symbolP; + + /* Make sure that the symbol is first on the symbol chain */ + if (symbol_rootP != symbolP) + { + symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); + symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); + } +} /* c_dot_file_symbol() */ + +/* + * Build a 'section static' symbol. + */ + +symbolS * +c_section_symbol (name, idx) + char *name; + int idx; +{ + symbolS *symbolP; + + symbolP = symbol_new (name, idx, + 0, + &zero_address_frag); + + S_SET_STORAGE_CLASS (symbolP, C_STAT); + S_SET_NUMBER_AUXILIARY (symbolP, 1); + + SF_SET_STATICS (symbolP); + +#ifdef TE_DELTA + /* manfred@s-direktnet.de: section symbols *must* have the LOCAL bit cleared, + which is set by the new definition of LOCAL_LABEL in tc-m68k.h. */ + SF_CLEAR_LOCAL (symbolP); +#endif +#ifdef TE_PE + /* If the .linkonce pseudo-op was used for this section, we must + store the information in the auxiliary entry for the section + symbol. */ + if (segment_info[idx].linkonce != LINKONCE_UNSET) + { + int type; + + switch (segment_info[idx].linkonce) + { + default: + abort (); + case LINKONCE_DISCARD: + type = IMAGE_COMDAT_SELECT_ANY; + break; + case LINKONCE_ONE_ONLY: + type = IMAGE_COMDAT_SELECT_NODUPLICATES; + break; + case LINKONCE_SAME_SIZE: + type = IMAGE_COMDAT_SELECT_SAME_SIZE; + break; + case LINKONCE_SAME_CONTENTS: + type = IMAGE_COMDAT_SELECT_EXACT_MATCH; + break; + } + + SYM_AUXENT (symbolP)->x_scn.x_comdat = type; + } +#endif /* TE_PE */ + + return symbolP; +} /* c_section_symbol() */ + +static void +w_symbols (abfd, where, symbol_rootP) + bfd * abfd; + char *where; + symbolS * symbol_rootP; +{ + symbolS *symbolP; + unsigned int i; + + /* First fill in those values we have only just worked out */ + for (i = SEG_E0; i < SEG_LAST; i++) + { + symbolP = segment_info[i].dot; + if (symbolP) + { + SA_SET_SCN_SCNLEN (symbolP, segment_info[i].scnhdr.s_size); + SA_SET_SCN_NRELOC (symbolP, segment_info[i].scnhdr.s_nreloc); + SA_SET_SCN_NLINNO (symbolP, segment_info[i].scnhdr.s_nlnno); + } + } + + /* + * Emit all symbols left in the symbol chain. + */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + /* Used to save the offset of the name. It is used to point + to the string in memory but must be a file offset. */ + register char *temp; + + /* We can't fix the lnnoptr field in yank_symbols with the other + adjustments, because we have to wait until we know where they + go in the file. */ + if (SF_GET_ADJ_LNNOPTR (symbolP)) + { + SA_GET_SYM_LNNOPTR (symbolP) += + segment_info[S_GET_SEGMENT (symbolP)].scnhdr.s_lnnoptr; + } + + tc_coff_symbol_emit_hook (symbolP); + + temp = S_GET_NAME (symbolP); + if (SF_GET_STRING (symbolP)) + { + S_SET_OFFSET (symbolP, symbolP->sy_name_offset); + S_SET_ZEROES (symbolP, 0); + } + else + { + memset (symbolP->sy_symbol.ost_entry.n_name, 0, SYMNMLEN); + strncpy (symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN); + } + where = symbol_to_chars (abfd, where, symbolP); + S_SET_NAME (symbolP, temp); + } + +} /* w_symbols() */ + +static void +obj_coff_lcomm (ignore) + int ignore; +{ + s_lcomm(0); + return; +#if 0 + char *name; + char c; + int temp; + char *p; + + symbolS *symbolP; + + name = input_line_pointer; + + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("Expected comma after name"); + ignore_rest_of_line (); + return; + } + if (*input_line_pointer == '\n') + { + as_bad ("Missing size expression"); + return; + } + input_line_pointer++; + if ((temp = get_absolute_expression ()) < 0) + { + as_warn ("lcomm length (%d.) <0! Ignored.", temp); + ignore_rest_of_line (); + return; + } + *p = 0; + + symbolP = symbol_find_or_make(name); + + if (S_GET_SEGMENT(symbolP) == SEG_UNKNOWN && + S_GET_VALUE(symbolP) == 0) + { + if (! need_pass_2) + { + char *p; + segT current_seg = now_seg; /* save current seg */ + subsegT current_subseg = now_subseg; + + subseg_set (SEG_E2, 1); + symbolP->sy_frag = frag_now; + p = frag_var(rs_org, 1, 1, (relax_substateT)0, symbolP, + (offsetT) temp, (char *) 0); + *p = 0; + subseg_set (current_seg, current_subseg); /* restore current seg */ + S_SET_SEGMENT(symbolP, SEG_E2); + S_SET_STORAGE_CLASS(symbolP, C_STAT); + } + } + else + as_bad("Symbol %s already defined", name); + + demand_empty_rest_of_line(); +#endif +} + +static void +fixup_mdeps (frags, h, this_segment) + fragS * frags; + object_headers * h; + segT this_segment; +{ + subseg_change (this_segment, 0); + while (frags) + { + switch (frags->fr_type) + { + case rs_align: + case rs_align_code: + case rs_org: +#ifdef HANDLE_ALIGN + HANDLE_ALIGN (frags); +#endif + frags->fr_type = rs_fill; + frags->fr_offset = + ((frags->fr_next->fr_address - frags->fr_address - frags->fr_fix) + / frags->fr_var); + break; + case rs_machine_dependent: + md_convert_frag (h, this_segment, frags); + frag_wane (frags); + break; + default: + ; + } + frags = frags->fr_next; + } +} + +#if 1 + +#ifndef TC_FORCE_RELOCATION +#define TC_FORCE_RELOCATION(fix) 0 +#endif + +static void +fixup_segment (segP, this_segment_type) + segment_info_type * segP; + segT this_segment_type; +{ + register fixS * fixP; + register symbolS *add_symbolP; + register symbolS *sub_symbolP; + long add_number; + register int size; + register char *place; + register long where; + register char pcrel; + register fragS *fragP; + register segT add_symbol_segment = absolute_section; + + for (fixP = segP->fix_root; fixP; fixP = fixP->fx_next) + { + fragP = fixP->fx_frag; + know (fragP); + where = fixP->fx_where; + place = fragP->fr_literal + where; + size = fixP->fx_size; + add_symbolP = fixP->fx_addsy; + sub_symbolP = fixP->fx_subsy; + add_number = fixP->fx_offset; + pcrel = fixP->fx_pcrel; + + /* We want function-relative stabs to work on systems which + may use a relaxing linker; thus we must handle the sym1-sym2 + fixups function-relative stabs generates. + + Of course, if you actually enable relaxing in the linker, the + line and block scoping information is going to be incorrect + in some cases. The only way to really fix this is to support + a reloc involving the difference of two symbols. */ + if (linkrelax + && (!sub_symbolP || pcrel)) + continue; + +#ifdef TC_I960 + if (fixP->fx_tcbit && SF_GET_CALLNAME (add_symbolP)) + { + /* Relocation should be done via the associated 'bal' entry + point symbol. */ + + if (!SF_GET_BALNAME (tc_get_bal_of_call (add_symbolP))) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "No 'bal' entry point for leafproc %s", + S_GET_NAME (add_symbolP)); + continue; + } + fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP); + } +#endif + + /* Make sure the symbols have been resolved; this may not have + happened if these are expression symbols. */ + if (add_symbolP != NULL && ! add_symbolP->sy_resolved) + resolve_symbol_value (add_symbolP); + + if (add_symbolP != NULL) + { + /* If this fixup is against a symbol which has been equated + to another symbol, convert it to the other symbol. */ + if (add_symbolP->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (add_symbolP) + || S_IS_COMMON (add_symbolP))) + { + while (add_symbolP->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (add_symbolP) + || S_IS_COMMON (add_symbolP))) + { + symbolS *n; + + /* We must avoid looping, as that can occur with a + badly written program. */ + n = add_symbolP->sy_value.X_add_symbol; + if (n == add_symbolP) + break; + add_number += add_symbolP->sy_value.X_add_number; + add_symbolP = n; + } + fixP->fx_addsy = add_symbolP; + fixP->fx_offset = add_number; + } + } + + if (sub_symbolP != NULL && ! sub_symbolP->sy_resolved) + resolve_symbol_value (sub_symbolP); + + if (add_symbolP != NULL + && add_symbolP->sy_mri_common) + { + know (add_symbolP->sy_value.X_op == O_symbol); + add_number += S_GET_VALUE (add_symbolP); + fixP->fx_offset = add_number; + add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol; + } + + if (add_symbolP) + { + add_symbol_segment = S_GET_SEGMENT (add_symbolP); + } /* if there is an addend */ + + if (sub_symbolP) + { + if (add_symbolP == NULL || add_symbol_segment == absolute_section) + { + if (add_symbolP != NULL) + { + add_number += S_GET_VALUE (add_symbolP); + add_symbolP = NULL; + fixP->fx_addsy = NULL; + } + + /* It's just -sym. */ + if (S_GET_SEGMENT (sub_symbolP) == absolute_section) + { + add_number -= S_GET_VALUE (sub_symbolP); + fixP->fx_subsy = 0; + fixP->fx_done = 1; + } + else + { +#ifndef TC_M68K + as_bad_where (fixP->fx_file, fixP->fx_line, + "Negative of non-absolute symbol %s", + S_GET_NAME (sub_symbolP)); +#endif + add_number -= S_GET_VALUE (sub_symbolP); + } /* not absolute */ + + /* if sub_symbol is in the same segment that add_symbol + and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */ + } + else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment + && SEG_NORMAL (add_symbol_segment)) + { + /* Difference of 2 symbols from same segment. Can't + make difference of 2 undefineds: 'value' means + something different for N_UNDF. */ +#ifdef TC_I960 + /* Makes no sense to use the difference of 2 arbitrary symbols + as the target of a call instruction. */ + if (fixP->fx_tcbit) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "callj to difference of 2 symbols"); + } +#endif /* TC_I960 */ + add_number += S_GET_VALUE (add_symbolP) - + S_GET_VALUE (sub_symbolP); + add_symbolP = NULL; + + if (!TC_FORCE_RELOCATION (fixP)) + { + fixP->fx_addsy = NULL; + fixP->fx_subsy = NULL; + fixP->fx_done = 1; +#ifdef TC_M68K /* is this right? */ + pcrel = 0; + fixP->fx_pcrel = 0; +#endif + } + } + else + { + /* Different segments in subtraction. */ + know (!(S_IS_EXTERNAL (sub_symbolP) && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); + + if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) + { + add_number -= S_GET_VALUE (sub_symbolP); + } +#ifdef DIFF_EXPR_OK + else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type +#if 0 /* Okay for 68k, at least... */ + && !pcrel +#endif + ) + { + /* Make it pc-relative. */ + add_number += (md_pcrel_from (fixP) + - S_GET_VALUE (sub_symbolP)); + pcrel = 1; + fixP->fx_pcrel = 1; + sub_symbolP = 0; + fixP->fx_subsy = 0; + } +#endif + else + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %ld.", + segment_name (S_GET_SEGMENT (sub_symbolP)), + S_GET_NAME (sub_symbolP), + (long) (fragP->fr_address + where)); + } /* if absolute */ + } + } /* if sub_symbolP */ + + if (add_symbolP) + { + if (add_symbol_segment == this_segment_type && pcrel) + { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ +#ifdef TC_I960 + /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal', + * in which cases it modifies *fixP as appropriate. In the case + * of a 'calls', no further work is required, and *fixP has been + * set up to make the rest of the code below a no-op. + */ + reloc_callj (fixP); +#endif /* TC_I960 */ + + add_number += S_GET_VALUE (add_symbolP); + add_number -= md_pcrel_from (fixP); +#if defined (TC_I386) || defined (TE_LYNX) + /* On the 386 we must adjust by the segment vaddr as + well. Ian Taylor. */ + add_number -= segP->scnhdr.s_vaddr; +#endif + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + if (!TC_FORCE_RELOCATION (fixP)) + { + fixP->fx_addsy = NULL; + fixP->fx_done = 1; + } + } + else + { + switch (add_symbol_segment) + { + case absolute_section: +#ifdef TC_I960 + reloc_callj (fixP); /* See comment about reloc_callj() above*/ +#endif /* TC_I960 */ + add_number += S_GET_VALUE (add_symbolP); + add_symbolP = NULL; + + if (!TC_FORCE_RELOCATION (fixP)) + { + fixP->fx_addsy = NULL; + fixP->fx_done = 1; + } + break; + default: + + +#if defined(TC_A29K) || (defined(TE_PE) && defined(TC_I386)) || defined(TC_M88K) + /* This really should be handled in the linker, but + backward compatibility forbids. */ + add_number += S_GET_VALUE (add_symbolP); +#else + add_number += S_GET_VALUE (add_symbolP) + + segment_info[S_GET_SEGMENT (add_symbolP)].scnhdr.s_paddr; +#endif + break; + + case SEG_UNKNOWN: +#ifdef TC_I960 + if ((int) fixP->fx_bit_fixP == 13) + { + /* This is a COBR instruction. They have only a + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ + as_bad_where (fixP->fx_file, fixP->fx_line, + "can't use COBR format with external label"); + fixP->fx_addsy = NULL; + fixP->fx_done = 1; + continue; + } /* COBR */ +#endif /* TC_I960 */ +#if ((defined (TC_I386) || defined (TE_LYNX) || defined (TE_AUX)) && !defined(TE_PE)) || defined (COFF_COMMON_ADDEND) + /* 386 COFF uses a peculiar format in which the + value of a common symbol is stored in the .text + segment (I've checked this on SVR3.2 and SCO + 3.2.2) Ian Taylor <ian@cygnus.com>. */ + /* This is also true for 68k COFF on sysv machines + (Checked on Motorola sysv68 R3V6 and R3V7.1, and also on + UNIX System V/M68000, Release 1.0 from ATT/Bell Labs) + Philippe De Muyter <phdm@info.ucl.ac.be>. */ + if (S_IS_COMMON (add_symbolP)) + add_number += S_GET_VALUE (add_symbolP); +#endif + break; + + + } /* switch on symbol seg */ + } /* if not in local seg */ + } /* if there was a + symbol */ + + if (pcrel) + { +#if !defined(TC_M88K) && !(defined(TE_PE) && defined(TC_I386)) && !defined(TC_A29K) + /* This adjustment is not correct on the m88k, for which the + linker does all the computation. */ + add_number -= md_pcrel_from (fixP); +#endif + if (add_symbolP == 0) + { + fixP->fx_addsy = &abs_symbol; + } /* if there's an add_symbol */ +#if defined (TC_I386) || defined (TE_LYNX) || defined (TC_I960) || defined (TC_M68K) + /* On the 386 we must adjust by the segment vaddr as well. + Ian Taylor. + + I changed the i960 to work this way as well. This is + compatible with the current GNU linker behaviour. I do + not know what other i960 COFF assemblers do. This is not + a common case: normally, only assembler code will contain + a PC relative reloc, and only branches which do not + originate in the .text section will have a non-zero + address. + + I changed the m68k to work this way as well. This will + break existing PC relative relocs from sections which do + not start at address 0, but it will make ld -r work. + Ian Taylor, 4 Oct 96. */ + + add_number -= segP->scnhdr.s_vaddr; +#endif + } /* if pcrel */ + + if (!fixP->fx_bit_fixP && ! fixP->fx_no_overflow) + { +#ifndef TC_M88K + /* The m88k uses the offset field of the reloc to get around + this problem. */ + if ((size == 1 + && ((add_number & ~0xFF) + || (fixP->fx_signed && (add_number & 0x80))) + && ((add_number & ~0xFF) != (-1 & ~0xFF) + || (add_number & 0x80) == 0)) + || (size == 2 + && ((add_number & ~0xFFFF) + || (fixP->fx_signed && (add_number & 0x8000))) + && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF) + || (add_number & 0x8000) == 0))) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + "Value of %ld too large for field of %d bytes at 0x%lx", + (long) add_number, size, + (unsigned long) (fragP->fr_address + where)); + } +#endif +#ifdef WARN_SIGNED_OVERFLOW_WORD + /* Warn if a .word value is too large when treated as a + signed number. We already know it is not too negative. + This is to catch over-large switches generated by gcc on + the 68k. */ + if (!flag_signed_overflow_ok + && size == 2 + && add_number > 0x7fff) + as_bad_where (fixP->fx_file, fixP->fx_line, + "Signed .word overflow; switch may be too large; %ld at 0x%lx", + (long) add_number, + (unsigned long) (fragP->fr_address + where)); +#endif + } /* not a bit fix */ + /* Once this fix has been applied, we don't have to output + anything nothing more need be done. */ +#ifdef MD_APPLY_FIX3 + md_apply_fix3 (fixP, &add_number, this_segment_type); +#else + md_apply_fix (fixP, add_number); +#endif + } /* For each fixS in this segment. */ +} /* fixup_segment() */ + +#endif + +/* The first entry in a .stab section is special. */ + +void +obj_coff_init_stab_section (seg) + segT seg; +{ + char *file; + char *p; + char *stabstr_name; + unsigned int stroff; + + /* Make space for this first symbol. */ + p = frag_more (12); + /* Zero it out. */ + memset (p, 0, 12); + as_where (&file, (unsigned int *) NULL); + stabstr_name = (char *) alloca (strlen (segment_info[seg].name) + 4); + strcpy (stabstr_name, segment_info[seg].name); + strcat (stabstr_name, "str"); + stroff = get_stab_string_offset (file, stabstr_name); + know (stroff == 1); + md_number_to_chars (p, stroff, 4); +} + +/* Fill in the counts in the first entry in a .stab section. */ + +static void +adjust_stab_section(abfd, seg) + bfd *abfd; + segT seg; +{ + segT stabstrseg = SEG_UNKNOWN; + const char *secname, *name2; + char *name; + char *p = NULL; + int i, strsz = 0, nsyms; + fragS *frag = segment_info[seg].frchainP->frch_root; + + /* Look for the associated string table section. */ + + secname = segment_info[seg].name; + name = (char *) alloca (strlen (secname) + 4); + strcpy (name, secname); + strcat (name, "str"); + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + name2 = segment_info[i].name; + if (name2 != NULL && strncmp(name2, name, 8) == 0) + { + stabstrseg = i; + break; + } + } + + /* If we found the section, get its size. */ + if (stabstrseg != SEG_UNKNOWN) + strsz = size_section (abfd, stabstrseg); + + nsyms = size_section (abfd, seg) / 12 - 1; + + /* Look for the first frag of sufficient size for the initial stab + symbol, and collect a pointer to it. */ + while (frag && frag->fr_fix < 12) + frag = frag->fr_next; + assert (frag != 0); + p = frag->fr_literal; + assert (p != 0); + + /* Write in the number of stab symbols and the size of the string + table. */ + bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); + bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); +} + +#endif /* not BFD_ASSEMBLER */ + +const pseudo_typeS obj_pseudo_table[] = +{ + {"def", obj_coff_def, 0}, + {"dim", obj_coff_dim, 0}, + {"endef", obj_coff_endef, 0}, + {"line", obj_coff_line, 0}, + {"ln", obj_coff_ln, 0}, + {"appline", obj_coff_ln, 1}, + {"scl", obj_coff_scl, 0}, + {"size", obj_coff_size, 0}, + {"tag", obj_coff_tag, 0}, + {"type", obj_coff_type, 0}, + {"val", obj_coff_val, 0}, + {"section", obj_coff_section, 0}, + {"sect", obj_coff_section, 0}, + /* FIXME: We ignore the MRI short attribute. */ + {"section.s", obj_coff_section, 0}, + {"sect.s", obj_coff_section, 0}, +#ifndef BFD_ASSEMBLER + {"use", obj_coff_section, 0}, + {"text", obj_coff_text, 0}, + {"data", obj_coff_data, 0}, + {"bss", obj_coff_bss, 0}, + {"lcomm", obj_coff_lcomm, 0}, + {"ident", obj_coff_ident, 0}, +#else + {"optim", s_ignore, 0}, /* For sun386i cc (?) */ + {"ident", s_ignore, 0}, /* we don't yet handle this. */ +#endif + {"version", s_ignore, 0}, + {"ABORT", s_abort, 0}, +#ifdef TC_M88K + /* The m88k uses sdef instead of def. */ + {"sdef", obj_coff_def, 0}, +#endif + {NULL} /* end sentinel */ +}; /* obj_pseudo_table */ + +#ifdef BFD_ASSEMBLER + +/* Support for a COFF emulation. */ + +static void +coff_pop_insert () +{ + pop_insert (obj_pseudo_table); +} + +static int +coff_sec_sym_ok_for_reloc (sec) + asection *sec; +{ + return 0; +} + +static void +no_func () +{ + abort (); +} + +const struct format_ops coff_format_ops = +{ + bfd_target_coff_flavour, + 0, + 1, + coff_frob_symbol, + coff_frob_file, + no_func, + 0, 0, + 0, 0, + 0, +#if 0 + obj_generate_asm_lineno, +#else + no_func, +#endif +#if 0 + obj_stab, +#else + no_func, +#endif + coff_sec_sym_ok_for_reloc, + coff_pop_insert, +#if 0 + obj_set_ext, +#else + no_func, +#endif + coff_obj_read_begin_hook, + coff_obj_symbol_new_hook, +}; + +#endif diff --git a/contrib/binutils/gas/config/obj-coff.h b/contrib/binutils/gas/config/obj-coff.h new file mode 100644 index 0000000..1cc5d2d --- /dev/null +++ b/contrib/binutils/gas/config/obj-coff.h @@ -0,0 +1,798 @@ +/* coff object file format + Copyright (C) 1989, 90, 91, 92, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef OBJ_FORMAT_H +#define OBJ_FORMAT_H + +#define OBJ_COFF 1 + +#ifndef BFD_ASSEMBLER + +#define WORKING_DOT_WORD +#define WARN_SIGNED_OVERFLOW_WORD +#define OBJ_COFF_OMIT_OPTIONAL_HEADER +#define BFD_HEADERS +#define BFD + +#endif + +#include "targ-cpu.h" + +#include "bfd.h" + +/* This internal_lineno crap is to stop namespace pollution from the + bfd internal coff headerfile. */ +#define internal_lineno bfd_internal_lineno +#include "coff/internal.h" +#undef internal_lineno + +/* CPU-specific setup: */ + +#ifdef TC_ARM +#include "coff/arm.h" +#ifndef TARGET_FORMAT +#define TARGET_FORMAT "coff-arm" +#endif +#endif + +#ifdef TC_PPC +#ifdef TE_PE +#include "coff/powerpc.h" +#else +#include "coff/rs6000.h" +#endif +#endif + +#ifdef TC_SPARC +#include "coff/sparc.h" +#ifdef TE_LYNX +#define TARGET_FORMAT "coff-sparc-lynx" +#else +#define TARGET_FORMAT "coff-sparc" +#endif +#endif + +#ifdef TC_I386 +#include "coff/i386.h" + +#ifdef TE_PE +#define TARGET_FORMAT "pe-i386" +#endif + +#ifndef TARGET_FORMAT +#define TARGET_FORMAT "coff-i386" +#endif +#endif + +#ifdef TC_M68K +#include "coff/m68k.h" +#ifndef TARGET_FORMAT +#define TARGET_FORMAT "coff-m68k" +#endif +#endif + +#ifdef TC_A29K +#include "coff/a29k.h" +#define TARGET_FORMAT "coff-a29k-big" +#endif + +#ifdef TC_I960 +#include "coff/i960.h" +#define TARGET_FORMAT "coff-Intel-little" +#endif + +#ifdef TC_Z8K +#include "coff/z8k.h" +#define TARGET_FORMAT "coff-z8k" +#endif + +#ifdef TC_H8300 +#include "coff/h8300.h" +#define TARGET_FORMAT "coff-h8300" +#endif + +#ifdef TC_H8500 +#include "coff/h8500.h" +#define TARGET_FORMAT "coff-h8500" +#endif + +#ifdef TC_SH +#include "coff/sh.h" +#define TARGET_FORMAT (shl ? "coff-shl" : "coff-sh") +#endif + +#ifdef TC_M88K +#include "coff/m88k.h" +#define TARGET_FORMAT "coff-m88kbcs" +#endif + +#ifdef TC_W65 +#include "coff/w65.h" +#define TARGET_FORMAT "coff-w65" +#endif + + +/* Targets may also set this. Also, if BFD_ASSEMBLER is defined, this + will already have been defined. */ +#undef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS 1 + +#ifndef OBJ_COFF_MAX_AUXENTRIES +#define OBJ_COFF_MAX_AUXENTRIES 1 +#endif /* OBJ_COFF_MAX_AUXENTRIES */ + +extern void coff_obj_symbol_new_hook PARAMS ((struct symbol *)); +#define obj_symbol_new_hook coff_obj_symbol_new_hook + +extern void coff_obj_read_begin_hook PARAMS ((void)); +#define obj_read_begin_hook coff_obj_read_begin_hook + +/* *********************************************************************** + + This file really contains two implementations of the COFF back end. + They are in the process of being merged, but this is only a + preliminary, mechanical merging. Many definitions that are + identical between the two are still found in both versions. + + The first version, with BFD_ASSEMBLER defined, uses high-level BFD + interfaces and data structures. The second version, with + BFD_ASSEMBLER not defined, also uses BFD, but mostly for swapping + data structures and for doing the actual I/O. The latter defines + the preprocessor symbols BFD and BFD_HEADERS. Try not to let this + confuse you. + + These two are in the process of being merged, and eventually the + BFD_ASSEMBLER version should take over completely. Release timing + issues and namespace problems convinced me to merge the two + together in this fashion, a little sooner than I would have liked. + The real merge should be much better done by the time the next + release comes out. + + For now, the structure of this file is: + <common> + #ifdef BFD_ASSEMBLER + <one version> + #else + <other version> + #endif + <common> + Unfortunately, the common portions are very small at the moment, + and many declarations or definitions are duplicated. The structure + of obj-coff.c is similar. + + See doc/internals.texi for a brief discussion of the history, if + you care. + + Ken Raeburn, 5 May 1994 + + *********************************************************************** */ + +#ifdef BFD_ASSEMBLER + +#include "bfd/libcoff.h" + +#define OUTPUT_FLAVOR bfd_target_coff_flavour + +/* SYMBOL TABLE */ + +/* Alter the field names, for now, until we've fixed up the other + references to use the new name. */ +#ifdef TC_I960 +#define TC_SYMFIELD_TYPE struct symbol * +#define sy_tc bal +#endif + +#define OBJ_SYMFIELD_TYPE unsigned long +#define sy_obj sy_flags + +#define SYM_AUXENT(S) (&coffsymbol ((S)->bsym)->native[1].u.auxent) + +#define DO_NOT_STRIP 0 + +extern void obj_coff_section PARAMS ((int)); + +/* The number of auxiliary entries */ +#define S_GET_NUMBER_AUXILIARY(s) (coffsymbol((s)->bsym)->native->u.syment.n_numaux) +/* The number of auxiliary entries */ +#define S_SET_NUMBER_AUXILIARY(s,v) (S_GET_NUMBER_AUXILIARY (s) = (v)) + +/* True if a symbol name is in the string table, i.e. its length is > 8. */ +#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) + +extern int S_SET_DATA_TYPE PARAMS ((struct symbol *, int)); +extern int S_SET_STORAGE_CLASS PARAMS ((struct symbol *, int)); +extern int S_GET_STORAGE_CLASS PARAMS ((struct symbol *)); +extern void SA_SET_SYM_ENDNDX PARAMS ((struct symbol *, struct symbol *)); + +/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ +/* Omit the tv related fields */ +/* Accessors */ + +#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l) +#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno) +#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size) +#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize) +#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx) +#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]) +#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname) +#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen) +#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc) +#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno) + +#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno=(v)) +#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size=(v)) +#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize=(v)) +#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) +#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) +#define SA_SET_FILE_FNAME(s,v) strncpy(SYM_AUXENT (s)->x_file.x_fname,(v),FILNMLEN) +#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen=(v)) +#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc=(v)) +#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno=(v)) + +/* + * Internal use only definitions. SF_ stands for symbol flags. + * + * These values can be assigned to sy_symbol.ost_flags field of a symbolS. + * + * You'll break i960 if you shift the SYSPROC bits anywhere else. for + * more on the balname/callname hack, see tc-i960.h. b.out is done + * differently. + */ + +#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ +#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ +#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ +#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ +#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ + +#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ + +#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ +#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ +#define SF_STRING (0x00004000) /* Symbol name length > 8 */ +#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ + +#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ + +#define SF_FUNCTION (0x00010000) /* The symbol is a function */ +#define SF_PROCESS (0x00020000) /* Process symbol before write */ +#define SF_TAGGED (0x00040000) /* Is associated with a tag */ +#define SF_TAG (0x00080000) /* Is a tag */ +#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ +#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ +/* All other bits are unused. */ + +/* Accessors */ +#define SF_GET(s) ((s)->sy_flags) +#define SF_GET_DEBUG(s) ((s)->bsym->flags & BSF_DEBUGGING) +#define SF_SET_DEBUG(s) ((s)->bsym->flags |= BSF_DEBUGGING) +#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK) +#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK) +#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE) +#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS) +#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED) +#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING) +#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL) +#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION) +#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS) +#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED) +#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG) +#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT) +#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* used by i960 */ +#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* used by i960 */ +#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* used by i960 */ +#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* used by i960 */ +#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* used by i960 */ + +/* Modifiers */ +#define SF_SET(s,v) (SF_GET (s) = (v)) +#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK)) +#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK)) +#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE) +#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS) +#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED) +#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING) +#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL) +#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL) +#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION) +#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS) +#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED) +#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG) +#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT) +#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* used by i960 */ +#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* used by i960 */ +#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* used by i960 */ +#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* used by i960 */ +#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* used by i960 */ + +/* -------------- Line number handling ------- */ +extern int text_lineno_number; +extern int coff_line_base; +extern int coff_n_line_nos; + +#define obj_emit_lineno(WHERE,LINE,FILE_START) abort () +extern void coff_add_linesym PARAMS ((struct symbol *)); + + +void c_dot_file_symbol PARAMS ((char *filename)); +#define obj_app_file c_dot_file_symbol + +extern void coff_frob_symbol PARAMS ((struct symbol *, int *)); +extern void coff_adjust_symtab PARAMS ((void)); +extern void coff_frob_section PARAMS ((segT)); +extern void coff_adjust_section_syms PARAMS ((bfd *, asection *, PTR)); +extern void coff_frob_file PARAMS ((void)); +#define obj_frob_symbol(S,P) coff_frob_symbol(S,&P) +#define obj_adjust_symtab() coff_adjust_symtab() +#define obj_frob_section(S) coff_frob_section (S) +#define obj_frob_file() coff_frob_file () + +extern struct symbol *coff_last_function; + +/* Forward the segment of a forwarded symbol, handle assignments that + just copy symbol values, etc. */ +#ifndef TE_I386AIX +#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ + (SF_GET_GET_SEGMENT (dest) \ + ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ + : 0) +#else +#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ + (SF_GET_GET_SEGMENT (dest) && S_GET_SEGMENT (dest) == SEG_UNKNOWN \ + ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ + : 0) +#endif + +/* sanity check */ + +#ifdef TC_I960 +#ifndef C_LEAFSTAT +hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it. +#endif /* no C_LEAFSTAT */ +#endif /* TC_I960 */ + +#else /* not BFD_ASSEMBLER */ + +#ifdef TC_A29K +/* Allow translate from aout relocs to coff relocs */ +#define NO_RELOC 20 +#define RELOC_32 1 +#define RELOC_8 2 +#define RELOC_CONST 3 +#define RELOC_CONSTH 4 +#define RELOC_JUMPTARG 5 +#define RELOC_BASE22 6 +#define RELOC_HI22 7 +#define RELOC_LO10 8 +#define RELOC_BASE13 9 +#define RELOC_WDISP22 10 +#define RELOC_WDISP30 11 +#endif + +extern const segT N_TYPE_seg[]; + +/* Magic number of paged executable. */ +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 0x8300 + + +/* SYMBOL TABLE */ + +/* Symbol table entry data type */ + +typedef struct +{ + /* Basic symbol */ + struct internal_syment ost_entry; + /* Auxiliary entry. */ + union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; + /* obj_coff internal use only flags */ + unsigned int ost_flags; +} obj_symbol_type; + +#ifndef DO_NOT_STRIP +#define DO_NOT_STRIP 0 +#endif +/* Symbol table macros and constants */ + +/* Possible and usefull section number in symbol table + * The values of TEXT, DATA and BSS may not be portable. + */ + +#define C_ABS_SECTION N_ABS +#define C_UNDEF_SECTION N_UNDEF +#define C_DEBUG_SECTION N_DEBUG +#define C_NTV_SECTION N_TV +#define C_PTV_SECTION P_TV +#define C_REGISTER_SECTION 50 + +/* + * Macros to extract information from a symbol table entry. + * This syntaxic indirection allows independence regarding a.out or coff. + * The argument (s) of all these macros is a pointer to a symbol table entry. + */ + +/* Predicates */ +/* True if the symbol is external */ +#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION) +/* True if symbol has been defined, ie : + section > 0 (DATA, TEXT or BSS) + section == 0 and value > 0 (external bss symbol) */ +#define S_IS_DEFINED(s) \ + ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION \ + || ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION \ + && S_GET_VALUE (s) > 0) \ + || ((s)->sy_symbol.ost_entry.n_scnum == C_ABS_SECTION)) +/* True if a debug special symbol entry */ +#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION) +/* True if a symbol is local symbol name */ +/* A symbol name whose name includes ^A is a gas internal pseudo symbol */ +#define S_IS_LOCAL(s) \ + ((s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION \ + || (S_LOCAL_NAME(s) && ! flag_keep_locals && ! S_IS_DEBUG (s)) \ + || strchr (S_GET_NAME (s), '\001') != NULL \ + || strchr (S_GET_NAME (s), '\002') != NULL) +/* True if a symbol is not defined in this file */ +#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 \ + && S_GET_VALUE (s) == 0) +/* + * True if a symbol can be multiply defined (bss symbols have this def + * though it is bad practice) + */ +#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 \ + && S_GET_VALUE (s) != 0) +/* True if a symbol name is in the string table, i.e. its length is > 8. */ +#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) + +/* Accessors */ +/* The name of the symbol */ +#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset) +/* The pointer to the string table */ +#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset) +/* The numeric value of the segment */ +#define S_GET_SEGMENT(s) s_get_segment(s) +/* The data type */ +#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type) +/* The storage class */ +#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass) +/* The number of auxiliary entries */ +#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux) + +/* Modifiers */ +/* Set the name of the symbol */ +#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v)) +/* Set the offset of the symbol */ +#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v)) +/* The numeric value of the segment */ +#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v)) +/* The data type */ +#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v)) +/* The storage class */ +#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v)) +/* The number of auxiliary entries */ +#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v)) + +/* Additional modifiers */ +/* The symbol is external (does not mean undefined) */ +#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); } + +/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ +/* Omit the tv related fields */ +/* Accessors */ +#define SYM_AUXENT(S) (&(S)->sy_symbol.ost_auxent[0]) + +#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l) +#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno) +#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size) +#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize) +#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx.l) +#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]) +#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname) +#define SA_GET_FILE_FNAME_OFFSET(s) (SYM_AUXENT (s)->x_file.x_n.x_offset) +#define SA_GET_FILE_FNAME_ZEROS(s) (SYM_AUXENT (s)->x_file.x_n.x_zeroes) +#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen) +#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc) +#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno) + +/* Modifiers */ +#define SA_SET_SYM_TAGNDX(s,v) (SYM_AUXENT (s)->x_sym.x_tagndx.l=(v)) +#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno=(v)) +#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size=(v)) +#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize=(v)) +#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) +#define SA_SET_SYM_ENDNDX(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx.l=(v)) +#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) +#define SA_SET_FILE_FNAME(s,v) strncpy(SYM_AUXENT (s)->x_file.x_fname,(v),FILNMLEN) +#define SA_SET_FILE_FNAME_OFFSET(s,v) (SYM_AUXENT (s)->x_file.x_n.x_offset=(v)) +#define SA_SET_FILE_FNAME_ZEROS(s,v) (SYM_AUXENT (s)->x_file.x_n.x_zeroes=(v)) +#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen=(v)) +#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc=(v)) +#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno=(v)) + +/* + * Internal use only definitions. SF_ stands for symbol flags. + * + * These values can be assigned to sy_symbol.ost_flags field of a symbolS. + * + * You'll break i960 if you shift the SYSPROC bits anywhere else. for + * more on the balname/callname hack, see tc-i960.h. b.out is done + * differently. + */ + +#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ +#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ +#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ +#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ +#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ + +#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ + +#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ +#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ +#define SF_STRING (0x00004000) /* Symbol name length > 8 */ +#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ + +#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ + +#define SF_FUNCTION (0x00010000) /* The symbol is a function */ +#define SF_PROCESS (0x00020000) /* Process symbol before write */ +#define SF_TAGGED (0x00040000) /* Is associated with a tag */ +#define SF_TAG (0x00080000) /* Is a tag */ +#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ +#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ +#define SF_ADJ_LNNOPTR (0x00400000) /* Has a lnnoptr */ +/* All other bits are unused. */ + +/* Accessors */ +#define SF_GET(s) ((s)->sy_symbol.ost_flags) +#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK) +#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK) +#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE) +#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS) +#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED) +#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING) +#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL) +#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION) +#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS) +#define SF_GET_DEBUG(s) (SF_GET (s) & SF_DEBUG) +#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED) +#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG) +#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT) +#define SF_GET_ADJ_LNNOPTR(s) (SF_GET (s) & SF_ADJ_LNNOPTR) +#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* used by i960 */ +#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* used by i960 */ +#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* used by i960 */ +#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* used by i960 */ +#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* used by i960 */ + +/* Modifiers */ +#define SF_SET(s,v) (SF_GET (s) = (v)) +#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK)) +#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK)) +#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE) +#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS) +#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED) +#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING) +#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL) +#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL) +#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION) +#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS) +#define SF_SET_DEBUG(s) (SF_GET (s) |= SF_DEBUG) +#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED) +#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG) +#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT) +#define SF_SET_ADJ_LNNOPTR(s) (SF_GET (s) |= SF_ADJ_LNNOPTR) +#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* used by i960 */ +#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* used by i960 */ +#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* used by i960 */ +#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* used by i960 */ +#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* used by i960 */ + +/* File header macro and type definition */ + +/* + * File position calculators. Beware to use them when all the + * appropriate fields are set in the header. + */ + +#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define OBJ_COFF_AOUTHDRSZ (0) +#else +#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_FILE_SIZE(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \ + H_GET_SYMBOL_TABLE_SIZE(h) + \ + (h)->string_table_size) +#define H_GET_TEXT_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ) +#define H_GET_DATA_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h)) +#define H_GET_BSS_FILE_OFFSET(h) 0 +#define H_GET_RELOCATION_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h)) +#define H_GET_LINENO_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h)) +#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \ + (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ + H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ + H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ + H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h)) + +/* Accessors */ +/* aouthdr */ +#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic) +#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp) +#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize) +#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize) +#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize) +#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry) +#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start) +#define H_GET_DATA_START(h) ((h)->aouthdr.data_start) +/* filehdr */ +#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic) +#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns) +#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat) +#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr) +#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms) +#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ) +#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr) +#define H_GET_FLAGS(h) ((h)->filehdr.f_flags) +/* Extra fields to achieve bsd a.out compatibility and for convenience */ +#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size) +#define H_GET_STRING_SIZE(h) ((h)->string_table_size) +#define H_GET_LINENO_SIZE(h) ((h)->lineno_size) + +#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + sizeof(AOUTHDR)\ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ +#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ + + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) +#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ + +#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ) +#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ) + +/* Modifiers */ +/* aouthdr */ +#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v)) +#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v)) +#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v)) +#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v)) +#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v)) +#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v)) +#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v)) +#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v)) +/* filehdr */ +#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v)) +#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v)) +#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v)) +#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v)) +#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v)) +#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v)) +#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v)) +/* Extra fields to achieve bsd a.out compatibility and for convinience */ +#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d)) +#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) +#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v)) + +/* Segment flipping */ + +typedef struct +{ + struct internal_aouthdr aouthdr; /* a.out header */ + struct internal_filehdr filehdr; /* File header, not machine dep. */ + long string_table_size; /* names + '\0' + sizeof(int) */ + long relocation_size; /* Cumulated size of relocation + information for all sections in + bytes. */ + long lineno_size; /* Size of the line number information + table in bytes */ +} object_headers; + + + +struct lineno_list +{ + struct bfd_internal_lineno line; + char *frag; /* Frag to which the line number is related */ + struct lineno_list *next; /* Forward chain pointer */ +}; + + + + +#define obj_segment_name(i) (segment_info[(int) (i)].scnhdr.s_name) + +#define obj_add_segment(s) obj_coff_add_segment (s) + +extern segT obj_coff_add_segment PARAMS ((const char *)); + +extern void obj_coff_section PARAMS ((int)); + +extern void c_dot_file_symbol PARAMS ((char *filename)); +#define obj_app_file c_dot_file_symbol +extern void obj_extra_stuff PARAMS ((object_headers * headers)); + +extern segT s_get_segment PARAMS ((struct symbol * ptr)); + +extern void c_section_header PARAMS ((struct internal_scnhdr * header, + char *name, + long core_address, + long size, + long data_ptr, + long reloc_ptr, + long lineno_ptr, + long reloc_number, + long lineno_number, + long alignment)); + +#ifndef tc_coff_symbol_emit_hook +void tc_coff_symbol_emit_hook PARAMS ((struct symbol *)); +#endif + +/* sanity check */ + +#ifdef TC_I960 +#ifndef C_LEAFSTAT +hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it. +#endif /* no C_LEAFSTAT */ +#endif /* TC_I960 */ +extern struct internal_scnhdr data_section_header; +extern struct internal_scnhdr text_section_header; + +/* Forward the segment of a forwarded symbol. */ +#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ + (SF_GET_GET_SEGMENT (dest) \ + ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ + : 0) + +#ifdef TE_PE +#define obj_handle_link_once(t) obj_coff_pe_handle_link_once (t) +extern void obj_coff_pe_handle_link_once (); +#endif + +#endif /* not BFD_ASSEMBLER */ + +/* Stabs in a coff file go into their own section. */ +#define SEPARATE_STAB_SECTIONS 1 + +/* We need 12 bytes at the start of the section to hold some initial + information. */ +extern void obj_coff_init_stab_section PARAMS ((segT)); +#define INIT_STAB_SECTION(seg) obj_coff_init_stab_section (seg) + +#endif /* OBJ_FORMAT_H */ diff --git a/contrib/binutils/gas/config/obj-ecoff.c b/contrib/binutils/gas/config/obj-ecoff.c new file mode 100644 index 0000000..27194a0 --- /dev/null +++ b/contrib/binutils/gas/config/obj-ecoff.c @@ -0,0 +1,305 @@ +/* ECOFF object file format. + Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + This file was put together by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define OBJ_HEADER "obj-ecoff.h" +#include "as.h" +#include "coff/internal.h" +#include "bfd/libcoff.h" +#include "bfd/libecoff.h" + +/* Almost all of the ECOFF support is actually in ecoff.c in the main + gas directory. This file mostly just arranges to call that one at + the right times. */ + +static int ecoff_sec_sym_ok_for_reloc PARAMS ((asection *)); +static void obj_ecoff_frob_symbol PARAMS ((symbolS *, int *)); +static void ecoff_pop_insert PARAMS ((void)); + +/* These are the pseudo-ops we support in this file. Only those + relating to debugging information are supported here. + + The following pseudo-ops from the Kane and Heinrich MIPS book + should be defined here, but are currently unsupported: .aent, + .bgnb, .endb, .verstamp, .vreg. + + The following pseudo-ops from the Kane and Heinrich MIPS book are + MIPS CPU specific, and should be defined by tc-mips.c: .alias, + .extern, .galive, .gjaldef, .gjrlive, .livereg, .noalias, .option, + .rdata, .sdata, .set. + + The following pseudo-ops from the Kane and Heinrich MIPS book are + not MIPS CPU specific, but are also not ECOFF specific. I have + only listed the ones which are not already in read.c. It's not + completely clear where these should be defined, but tc-mips.c is + probably the most reasonable place: .asciiz, .asm0, .endr, .err, + .half, .lab, .repeat, .struct, .weakext. */ + +const pseudo_typeS obj_pseudo_table[] = +{ + /* COFF style debugging information. .ln is not used; .loc is used + instead. */ + { "def", ecoff_directive_def, 0 }, + { "dim", ecoff_directive_dim, 0 }, + { "endef", ecoff_directive_endef, 0 }, + { "file", ecoff_directive_file, 0 }, + { "scl", ecoff_directive_scl, 0 }, + { "size", ecoff_directive_size, 0 }, + { "esize", ecoff_directive_size, 0 }, + { "tag", ecoff_directive_tag, 0 }, + { "type", ecoff_directive_type, 0 }, + { "etype", ecoff_directive_type, 0 }, + { "val", ecoff_directive_val, 0 }, + + /* ECOFF specific debugging information. */ + { "begin", ecoff_directive_begin, 0 }, + { "bend", ecoff_directive_bend, 0 }, + { "end", ecoff_directive_end, 0 }, + { "ent", ecoff_directive_ent, 0 }, + { "fmask", ecoff_directive_fmask, 0 }, + { "frame", ecoff_directive_frame, 0 }, + { "loc", ecoff_directive_loc, 0 }, + { "mask", ecoff_directive_mask, 0 }, + + /* Other ECOFF directives. */ + { "extern", ecoff_directive_extern, 0 }, + { "weakext", ecoff_directive_weakext, 0 }, + + /* These are used on Irix. I don't know how to implement them. */ + { "bgnb", s_ignore, 0 }, + { "endb", s_ignore, 0 }, + { "verstamp", s_ignore, 0 }, + + /* Sentinel. */ + { NULL } +}; + +/* Swap out the symbols and debugging information for BFD. */ + +void +ecoff_frob_file () +{ + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (stdoutput)->debug_swap; + bfd_vma addr; + asection *sec; + HDRR *hdr; + char *buf; + char *set; + + /* Set the section VMA values. We force the .sdata and .sbss + sections to the end to ensure that their VMA addresses are close + together so that the GP register can address both of them. We + put the .bss section after the .sbss section. + + Also, for the Alpha, we must sort the sections, to make sure they + appear in the output file in the correct order. (Actually, maybe + this is a job for BFD. But the VMAs computed would be out of + whack if we computed them given our initial, random ordering. + It's possible that that wouldn't break things; I could do some + experimenting sometime and find out. + + This output ordering of sections is magic, on the Alpha, at + least. The .lita section must come before .lit8 and .lit4, + otherwise the OSF/1 linker may silently trash the .lit{4,8} + section contents. Also, .text must preceed .rdata. These differ + from the order described in some parts of the DEC OSF/1 Assembly + Language Programmer's Guide, but that order doesn't seem to work + with their linker. + + I don't know if section ordering on the MIPS is important. */ + + static const char *const names[] = { + /* text segment */ + ".text", ".rdata", ".init", ".fini", + /* data segment */ + ".data", ".lita", ".lit8", ".lit4", ".sdata", ".got", + /* bss segment */ + ".sbss", ".bss", + }; +#define n_names (sizeof (names) / sizeof (names[0])) + + addr = 0; + { + /* Sections that match names, order to be straightened out later. */ + asection *secs[n_names]; + /* Linked list of sections with non-matching names. Random ordering. */ + asection *other_sections = 0; + /* Pointer to next section, since we're destroying the original + ordering. */ + asection *next; + + int i; + + for (i = 0; i < n_names; i++) + secs[i] = 0; + for (sec = stdoutput->sections; sec != (asection *) NULL; sec = next) + { + next = sec->next; + for (i = 0; i < n_names; i++) + if (!strcmp (sec->name, names[i])) + { + secs[i] = sec; + break; + } + if (i == n_names) + { + bfd_set_section_vma (stdoutput, sec, addr); + addr += bfd_section_size (stdoutput, sec); + sec->next = other_sections; + other_sections = sec; + } + } + for (i = 0; i < n_names; i++) + if (secs[i]) + { + sec = secs[i]; + bfd_set_section_vma (stdoutput, sec, addr); + addr += bfd_section_size (stdoutput, sec); + } + for (i = n_names - 1; i >= 0; i--) + if (secs[i]) + { + sec = secs[i]; + sec->next = other_sections; + other_sections = sec; + } + stdoutput->sections = other_sections; + } + + /* Build the ECOFF debugging information. */ + assert (ecoff_data (stdoutput) != 0); + hdr = &ecoff_data (stdoutput)->debug_info.symbolic_header; + ecoff_build_debug (hdr, &buf, debug_swap); + + /* Finish up the ecoff_tdata structure. */ + set = buf; +#define SET(ptr, count, type, size) \ + if (hdr->count == 0) \ + ecoff_data (stdoutput)->debug_info.ptr = (type) NULL; \ + else \ + { \ + ecoff_data (stdoutput)->debug_info.ptr = (type) set; \ + set += hdr->count * size; \ + } + + SET (line, cbLine, unsigned char *, sizeof (unsigned char)); + SET (external_dnr, idnMax, PTR, debug_swap->external_dnr_size); + SET (external_pdr, ipdMax, PTR, debug_swap->external_pdr_size); + SET (external_sym, isymMax, PTR, debug_swap->external_sym_size); + SET (external_opt, ioptMax, PTR, debug_swap->external_opt_size); + SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext)); + SET (ss, issMax, char *, sizeof (char)); + SET (ssext, issExtMax, char *, sizeof (char)); + SET (external_rfd, crfd, PTR, debug_swap->external_rfd_size); + SET (external_fdr, ifdMax, PTR, debug_swap->external_fdr_size); + SET (external_ext, iextMax, PTR, debug_swap->external_ext_size); + +#undef SET + + /* Fill in the register masks. */ + { + unsigned long gprmask = 0; + unsigned long fprmask = 0; + unsigned long *cprmask = NULL; + +#ifdef TC_MIPS + /* Fill in the MIPS register masks. It's probably not worth + setting up a generic interface for this. */ + gprmask = mips_gprmask; + cprmask = mips_cprmask; +#endif + +#ifdef TC_ALPHA + alpha_frob_ecoff_data (); + + if (! bfd_ecoff_set_gp_value (stdoutput, alpha_gp_value)) + as_fatal ("Can't set GP value"); + + gprmask = alpha_gprmask; + fprmask = alpha_fprmask; +#endif + + if (! bfd_ecoff_set_regmasks (stdoutput, gprmask, fprmask, cprmask)) + as_fatal ("Can't set register masks"); + } +} + +/* This is called by the ECOFF code to set the external information + for a symbol. We just pass it on to BFD, which expects the swapped + information to be stored in the native field of the symbol. */ + +void +obj_ecoff_set_ext (sym, ext) + symbolS *sym; + EXTR *ext; +{ + const struct ecoff_debug_swap * const debug_swap + = &ecoff_backend (stdoutput)->debug_swap; + ecoff_symbol_type *esym; + + know (bfd_asymbol_flavour (sym->bsym) == bfd_target_ecoff_flavour); + esym = ecoffsymbol (sym->bsym); + esym->local = false; + esym->native = xmalloc (debug_swap->external_ext_size); + (*debug_swap->swap_ext_out) (stdoutput, ext, esym->native); +} + +static int +ecoff_sec_sym_ok_for_reloc (sec) + asection *sec; +{ + return 1; +} + +static void +obj_ecoff_frob_symbol (sym, puntp) + symbolS *sym; + int *puntp; +{ + ecoff_frob_symbol (sym); +} + +static void +ecoff_pop_insert () +{ + pop_insert (obj_pseudo_table); +} + +const struct format_ops ecoff_format_ops = +{ + bfd_target_ecoff_flavour, + 0, + 1, + obj_ecoff_frob_symbol, + ecoff_frob_file, + 0, + 0, 0, + 0, 0, + 0, + ecoff_generate_asm_lineno, + ecoff_stab, + ecoff_sec_sym_ok_for_reloc, + ecoff_pop_insert, + ecoff_set_ext, + ecoff_read_begin_hook, + ecoff_symbol_new_hook, +}; diff --git a/contrib/binutils/gas/config/obj-ecoff.h b/contrib/binutils/gas/config/obj-ecoff.h new file mode 100644 index 0000000..0192afe --- /dev/null +++ b/contrib/binutils/gas/config/obj-ecoff.h @@ -0,0 +1,70 @@ +/* ECOFF object file format header file. + Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define OBJ_ECOFF 1 + +/* Use the generic ECOFF debugging code. */ +#define ECOFF_DEBUGGING 1 + +#define OUTPUT_FLAVOR bfd_target_ecoff_flavour + +#include "targ-cpu.h" + +#include "ecoff.h" + +/* For each gas symbol we keep track of which file it came from, of + whether we have generated an ECOFF symbol for it, and whether the + symbols is undefined (this last is needed to distinguish a .extern + symbols from a .comm symbol). */ + +#define TARGET_SYMBOL_FIELDS \ + struct efdr *ecoff_file; \ + struct localsym *ecoff_symbol; \ + valueT ecoff_extern_size; + +/* Modify the ECOFF symbol. */ +#define obj_frob_symbol(symp, punt) ecoff_frob_symbol (symp) + +/* This is used to write the symbolic data in the format that BFD + expects it. */ +extern void ecoff_frob_file PARAMS ((void)); +#define obj_frob_file() ecoff_frob_file () + +/* We use the ECOFF functions as our hooks. */ +#define obj_read_begin_hook ecoff_read_begin_hook +#define obj_symbol_new_hook ecoff_symbol_new_hook + +/* Record file switches in the ECOFF symbol table. */ +#define obj_app_file(name) ecoff_new_file (name) + +/* At the moment we don't want to do any stabs processing in read.c. */ +#define OBJ_PROCESS_STAB(seg, what, string, type, other, desc) \ + ecoff_stab ((seg), (what), (string), (type), (other), (desc)) + +#define OBJ_GENERATE_ASM_LINENO(filename, lineno) \ + ecoff_generate_asm_lineno ((filename), (lineno)) + +#define EMIT_SECTION_SYMBOLS 0 +#define obj_sec_sym_ok_for_reloc(SEC) 1 + +#define obj_ecoff_set_ext ecoff_set_ext +extern void obj_ecoff_set_ext PARAMS ((struct symbol *, EXTR *)); diff --git a/contrib/binutils/gas/config/obj-elf.c b/contrib/binutils/gas/config/obj-elf.c new file mode 100644 index 0000000..c861d54 --- /dev/null +++ b/contrib/binutils/gas/config/obj-elf.c @@ -0,0 +1,1600 @@ +/* ELF object file format + Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define OBJ_HEADER "obj-elf.h" +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +#ifndef ECOFF_DEBUGGING +#define ECOFF_DEBUGGING 0 +#else +#define NEED_ECOFF_DEBUG +#endif + +#ifdef NEED_ECOFF_DEBUG +#include "ecoff.h" +#endif + +#ifdef TC_MIPS +#include "elf/mips.h" +#endif + +#ifdef TC_PPC +#include "elf/ppc.h" +#endif + +static bfd_vma elf_s_get_size PARAMS ((symbolS *)); +static void elf_s_set_size PARAMS ((symbolS *, bfd_vma)); +static bfd_vma elf_s_get_align PARAMS ((symbolS *)); +static void elf_s_set_align PARAMS ((symbolS *, bfd_vma)); +static void elf_copy_symbol_attributes PARAMS ((symbolS *, symbolS *)); +static int elf_sec_sym_ok_for_reloc PARAMS ((asection *)); +static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR)); + +#ifdef NEED_ECOFF_DEBUG +static boolean elf_get_extr PARAMS ((asymbol *, EXTR *)); +static void elf_set_index PARAMS ((asymbol *, bfd_size_type)); +#endif + +static void obj_elf_line PARAMS ((int)); +void obj_elf_version PARAMS ((int)); +static void obj_elf_size PARAMS ((int)); +static void obj_elf_type PARAMS ((int)); +static void obj_elf_ident PARAMS ((int)); +static void obj_elf_weak PARAMS ((int)); +static void obj_elf_local PARAMS ((int)); +static void obj_elf_common PARAMS ((int)); +static void obj_elf_symver PARAMS ((int)); +static void obj_elf_data PARAMS ((int)); +static void obj_elf_text PARAMS ((int)); + +static const pseudo_typeS elf_pseudo_table[] = +{ + {"comm", obj_elf_common, 0}, + {"ident", obj_elf_ident, 0}, + {"local", obj_elf_local, 0}, + {"previous", obj_elf_previous, 0}, + {"section", obj_elf_section, 0}, + {"section.s", obj_elf_section, 0}, + {"sect", obj_elf_section, 0}, + {"sect.s", obj_elf_section, 0}, + {"size", obj_elf_size, 0}, + {"type", obj_elf_type, 0}, + {"version", obj_elf_version, 0}, + {"weak", obj_elf_weak, 0}, + + /* These are used for stabs-in-elf configurations. */ + {"line", obj_elf_line, 0}, + + /* This is a GNU extension to handle symbol versions. */ + {"symver", obj_elf_symver, 0}, + + /* These are used for dwarf. */ + {"2byte", cons, 2}, + {"4byte", cons, 4}, + {"8byte", cons, 8}, + + /* We need to trap the section changing calls to handle .previous. */ + {"data", obj_elf_data, 0}, + {"text", obj_elf_text, 0}, + + /* End sentinel. */ + {NULL}, +}; + +static const pseudo_typeS ecoff_debug_pseudo_table[] = +{ +#ifdef NEED_ECOFF_DEBUG + /* COFF style debugging information for ECOFF. .ln is not used; .loc + is used instead. */ + { "def", ecoff_directive_def, 0 }, + { "dim", ecoff_directive_dim, 0 }, + { "endef", ecoff_directive_endef, 0 }, + { "file", ecoff_directive_file, 0 }, + { "scl", ecoff_directive_scl, 0 }, + { "tag", ecoff_directive_tag, 0 }, + { "val", ecoff_directive_val, 0 }, + + /* COFF debugging requires pseudo-ops .size and .type, but ELF + already has meanings for those. We use .esize and .etype + instead. These are only generated by gcc anyhow. */ + { "esize", ecoff_directive_size, 0 }, + { "etype", ecoff_directive_type, 0 }, + + /* ECOFF specific debugging information. */ + { "begin", ecoff_directive_begin, 0 }, + { "bend", ecoff_directive_bend, 0 }, + { "end", ecoff_directive_end, 0 }, + { "ent", ecoff_directive_ent, 0 }, + { "fmask", ecoff_directive_fmask, 0 }, + { "frame", ecoff_directive_frame, 0 }, + { "loc", ecoff_directive_loc, 0 }, + { "mask", ecoff_directive_mask, 0 }, + + /* Other ECOFF directives. */ + { "extern", ecoff_directive_extern, 0 }, + + /* These are used on Irix. I don't know how to implement them. */ + { "alias", s_ignore, 0 }, + { "bgnb", s_ignore, 0 }, + { "endb", s_ignore, 0 }, + { "lab", s_ignore, 0 }, + { "noalias", s_ignore, 0 }, + { "verstamp", s_ignore, 0 }, + { "vreg", s_ignore, 0 }, +#endif + + {NULL} /* end sentinel */ +}; + +#undef NO_RELOC +#include "aout/aout64.h" + +/* This is called when the assembler starts. */ + +void +elf_begin () +{ + /* Add symbols for the known sections to the symbol table. */ + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + ".text"))); + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + ".data"))); + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + ".bss"))); +} + +void +elf_pop_insert () +{ + pop_insert (elf_pseudo_table); + if (ECOFF_DEBUGGING) + pop_insert (ecoff_debug_pseudo_table); +} + +static bfd_vma +elf_s_get_size (sym) + symbolS *sym; +{ + return S_GET_SIZE (sym); +} + +static void +elf_s_set_size (sym, sz) + symbolS *sym; + bfd_vma sz; +{ + S_SET_SIZE (sym, sz); +} + +static bfd_vma +elf_s_get_align (sym) + symbolS *sym; +{ + return S_GET_ALIGN (sym); +} + +static void +elf_s_set_align (sym, align) + symbolS *sym; + bfd_vma align; +{ + S_SET_ALIGN (sym, align); +} + +static void +elf_copy_symbol_attributes (dest, src) + symbolS *dest, *src; +{ + OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src); +} + +static int +elf_sec_sym_ok_for_reloc (sec) + asection *sec; +{ + return obj_sec_sym_ok_for_reloc (sec); +} + +void +elf_file_symbol (s) + char *s; +{ + symbolS *sym; + + sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0); + sym->sy_frag = &zero_address_frag; + sym->bsym->flags |= BSF_FILE; + + if (symbol_rootP != sym) + { + symbol_remove (sym, &symbol_rootP, &symbol_lastP); + symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); +#ifdef DEBUG + verify_symbol_chain (symbol_rootP, symbol_lastP); +#endif + } + +#ifdef NEED_ECOFF_DEBUG + ecoff_new_file (s); +#endif +} + +static void +obj_elf_common (ignore) + int ignore; +{ + char *name; + char c; + char *p; + int temp, size; + symbolS *symbolP; + int have_align; + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("Expected comma after symbol-name"); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) + { + as_bad (".COMMon length (%d.) <0! Ignored.", temp); + ignore_rest_of_line (); + return; + } + size = temp; + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + as_bad ("Ignoring attempt to re-define symbol"); + ignore_rest_of_line (); + return; + } + if (S_GET_VALUE (symbolP) != 0) + { + if (S_GET_VALUE (symbolP) != size) + { + as_warn ("Length of .comm \"%s\" is already %ld. Not changed to %d.", + S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); + } + } + know (symbolP->sy_frag == &zero_address_frag); + if (*input_line_pointer != ',') + have_align = 0; + else + { + have_align = 1; + input_line_pointer++; + SKIP_WHITESPACE (); + } + if (! have_align || *input_line_pointer != '"') + { + if (! have_align) + temp = 0; + else + { + temp = get_absolute_expression (); + if (temp < 0) + { + temp = 0; + as_warn ("Common alignment negative; 0 assumed"); + } + } + if (symbolP->local) + { + segT old_sec; + int old_subsec; + char *pfrag; + int align; + + /* allocate_bss: */ + old_sec = now_seg; + old_subsec = now_subseg; + if (temp) + { + /* convert to a power of 2 alignment */ + for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); + if (temp != 1) + { + as_bad ("Common alignment not a power of 2"); + ignore_rest_of_line (); + return; + } + } + else + align = 0; + record_alignment (bss_section, align); + subseg_set (bss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == bss_section) + symbolP->sy_frag->fr_symbol = 0; + symbolP->sy_frag = frag_now; + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, bss_section); + S_CLEAR_EXTERNAL (symbolP); + subseg_set (old_sec, old_subsec); + } + else + { + allocate_common: + S_SET_VALUE (symbolP, (valueT) size); + S_SET_ALIGN (symbolP, temp); + S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); + } + } + else + { + input_line_pointer++; + /* @@ Some use the dot, some don't. Can we get some consistency?? */ + if (*input_line_pointer == '.') + input_line_pointer++; + /* @@ Some say data, some say bss. */ + if (strncmp (input_line_pointer, "bss\"", 4) + && strncmp (input_line_pointer, "data\"", 5)) + { + while (*--input_line_pointer != '"') + ; + input_line_pointer--; + goto bad_common_segment; + } + while (*input_line_pointer++ != '"') + ; + goto allocate_common; + } + + symbolP->bsym->flags |= BSF_OBJECT; + + demand_empty_rest_of_line (); + return; + + { + bad_common_segment: + p = input_line_pointer; + while (*p && *p != '\n') + p++; + c = *p; + *p = '\0'; + as_bad ("bad .common segment %s", input_line_pointer + 1); + *p = c; + input_line_pointer = p; + ignore_rest_of_line (); + return; + } +} + +static void +obj_elf_local (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolP; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_CLEAR_EXTERNAL (symbolP); + symbolP->local = 1; + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +static void +obj_elf_weak (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolP; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_SET_WEAK (symbolP); + symbolP->local = 1; + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +static segT previous_section; +static int previous_subsection; + +/* Handle the .section pseudo-op. This code supports two different + syntaxes. + + The first is found on Solaris, and looks like + .section ".sec1",#alloc,#execinstr,#write + Here the names after '#' are the SHF_* flags to turn on for the + section. I'm not sure how it determines the SHT_* type (BFD + doesn't really give us control over the type, anyhow). + + The second format is found on UnixWare, and probably most SVR4 + machines, and looks like + .section .sec1,"a",@progbits + The quoted string may contain any combination of a, w, x, and + represents the SHF_* flags to turn on for the section. The string + beginning with '@' can be progbits or nobits. There should be + other possibilities, but I don't know what they are. In any case, + BFD doesn't really let us set the section type. */ + +/* Certain named sections have particular defined types, listed on p. + 4-19 of the ABI. */ +struct special_section +{ + const char *name; + int type; + int attributes; +}; + +static struct special_section special_sections[] = +{ + { ".bss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { ".comment", SHT_PROGBITS, 0 }, + { ".data", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".data1", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".debug", SHT_PROGBITS, 0 }, + { ".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".line", SHT_PROGBITS, 0 }, + { ".note", SHT_NOTE, 0 }, + { ".rodata", SHT_PROGBITS, SHF_ALLOC }, + { ".rodata1", SHT_PROGBITS, SHF_ALLOC }, + { ".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + +#ifdef ELF_TC_SPECIAL_SECTIONS + ELF_TC_SPECIAL_SECTIONS +#endif + +#if 0 + /* The following section names are special, but they can not + reasonably appear in assembler code. Some of the attributes are + processor dependent. */ + { ".dynamic", SHT_DYNAMIC, SHF_ALLOC /* + SHF_WRITE */ }, + { ".dynstr", SHT_STRTAB, SHF_ALLOC }, + { ".dynsym", SHT_DYNSYM, SHF_ALLOC }, + { ".got", SHT_PROGBITS, 0 }, + { ".hash", SHT_HASH, SHF_ALLOC }, + { ".interp", SHT_PROGBITS, /* SHF_ALLOC */ }, + { ".plt", SHT_PROGBITS, 0 }, + { ".shstrtab",SHT_STRTAB, 0 }, + { ".strtab", SHT_STRTAB, /* SHF_ALLOC */ }, + { ".symtab", SHT_SYMTAB, /* SHF_ALLOC */ }, +#endif + + { NULL, 0, 0 } +}; + +void +obj_elf_section (xxx) + int xxx; +{ + char *string; + int new_sec; + segT sec; + int type, attr; + int i; + flagword flags; + symbolS *secsym; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (flag_mri) + { + char mri_type; + + previous_section = now_seg; + previous_subsection = now_subseg; + + s_mri_sect (&mri_type); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif + + return; + } + + /* Get name of section. */ + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + string = demand_copy_C_string (&xxx); + if (string == NULL) + { + ignore_rest_of_line (); + return; + } + } + else + { + char *p = input_line_pointer; + char c; + while (0 == strchr ("\n\t,; ", *p)) + p++; + if (p == input_line_pointer) + { + as_warn ("Missing section name"); + ignore_rest_of_line (); + return; + } + c = *p; + *p = 0; + string = xmalloc ((unsigned long) (p - input_line_pointer + 1)); + strcpy (string, input_line_pointer); + *p = c; + input_line_pointer = p; + } + + /* Switch to the section, creating it if necessary. */ + previous_section = now_seg; + previous_subsection = now_subseg; + + new_sec = bfd_get_section_by_name (stdoutput, string) == NULL; + sec = subseg_new (string, 0); + + /* If this section already existed, we don't bother to change the + flag values. */ + if (! new_sec) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + ++input_line_pointer; + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif + + return; + } + + SKIP_WHITESPACE (); + + type = SHT_NULL; + attr = 0; + + if (*input_line_pointer == ',') + { + /* Skip the comma. */ + ++input_line_pointer; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + /* Pick up a string with a combination of a, w, x. */ + ++input_line_pointer; + while (*input_line_pointer != '"') + { + switch (*input_line_pointer) + { + case 'a': + attr |= SHF_ALLOC; + break; + case 'w': + attr |= SHF_WRITE; + break; + case 'x': + attr |= SHF_EXECINSTR; + break; + default: + { + char *bad_msg = "Bad .section directive: want a,w,x in string"; +#ifdef md_elf_section_letter + int md_attr = md_elf_section_letter (*input_line_pointer, &bad_msg); + if (md_attr) + attr |= md_attr; + else +#endif + { + as_warn (bad_msg); + ignore_rest_of_line (); + return; + } + } + } + ++input_line_pointer; + } + + /* Skip the closing quote. */ + ++input_line_pointer; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + if (*input_line_pointer == '@') + { + ++input_line_pointer; + if (strncmp (input_line_pointer, "progbits", + sizeof "progbits" - 1) == 0) + { + type = SHT_PROGBITS; + input_line_pointer += sizeof "progbits" - 1; + } + else if (strncmp (input_line_pointer, "nobits", + sizeof "nobits" - 1) == 0) + { + type = SHT_NOBITS; + input_line_pointer += sizeof "nobits" - 1; + } + else + { +#ifdef md_elf_section_type + int md_type = md_elf_section_type (&input_line_pointer); + if (md_type) + type = md_type; + else +#endif + { + as_warn ("Unrecognized section type"); + ignore_rest_of_line (); + } + } + } + } + } + else + { + do + { + SKIP_WHITESPACE (); + if (*input_line_pointer != '#') + { + as_warn ("Bad .section directive"); + ignore_rest_of_line (); + return; + } + ++input_line_pointer; + if (strncmp (input_line_pointer, "write", + sizeof "write" - 1) == 0) + { + attr |= SHF_WRITE; + input_line_pointer += sizeof "write" - 1; + } + else if (strncmp (input_line_pointer, "alloc", + sizeof "alloc" - 1) == 0) + { + attr |= SHF_ALLOC; + input_line_pointer += sizeof "alloc" - 1; + } + else if (strncmp (input_line_pointer, "execinstr", + sizeof "execinstr" - 1) == 0) + { + attr |= SHF_EXECINSTR; + input_line_pointer += sizeof "execinstr" - 1; + } + else + { +#ifdef md_elf_section_word + int md_attr = md_elf_section_word (&input_line_pointer); + if (md_attr) + attr |= md_attr; + else +#endif + { + as_warn ("Unrecognized section attribute"); + ignore_rest_of_line (); + return; + } + } + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + --input_line_pointer; + } + } + + /* See if this is one of the special sections. */ + for (i = 0; special_sections[i].name != NULL; i++) + { + if (string[1] == special_sections[i].name[1] + && strcmp (string, special_sections[i].name) == 0) + { + if (type == SHT_NULL) + type = special_sections[i].type; + else if (type != special_sections[i].type) + as_warn ("Setting incorrect section type for %s", string); + + if ((attr &~ special_sections[i].attributes) != 0) + { + /* As a GNU extension, we permit a .note section to be + allocatable. If the linker sees an allocateable + .note section, it will create a PT_NOTE segment in + the output file. */ + if (strcmp (string, ".note") != 0 + || attr != SHF_ALLOC) + as_warn ("Setting incorrect section attributes for %s", + string); + } + attr |= special_sections[i].attributes; + + break; + } + } + + flags = (SEC_RELOC + | ((attr & SHF_WRITE) ? 0 : SEC_READONLY) + | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0) + | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0) + | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)); + if (special_sections[i].name == NULL) + { + if (type == SHT_PROGBITS) + flags |= SEC_ALLOC | SEC_LOAD; + else if (type == SHT_NOBITS) + { + flags |= SEC_ALLOC; + flags &=~ SEC_LOAD; + } + +#ifdef md_elf_section_flags + flags = md_elf_section_flags (flags, attr, type); +#endif + } + + bfd_set_section_flags (stdoutput, sec, flags); + + /* Add a symbol for this section to the symbol table. */ + secsym = symbol_find (string); + if (secsym != NULL) + secsym->bsym = sec->symbol; + else + symbol_table_insert (section_symbol (sec)); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif + + demand_empty_rest_of_line (); +} + +/* Change to the .data section. */ + +static void +obj_elf_data (i) + int i; +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + s_data (i); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +/* Change to the .text section. */ + +static void +obj_elf_text (i) + int i; +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + s_text (i); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +/* This can be called from the processor backends if they change + sections. */ + +void +obj_elf_section_change_hook () +{ + previous_section = now_seg; + previous_subsection = now_subseg; +} + +void +obj_elf_previous (ignore) + int ignore; +{ + if (previous_section == 0) + { + as_bad (".previous without corresponding .section; ignored"); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + subseg_set (previous_section, previous_subsection); + previous_section = 0; + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static void +obj_elf_line (ignore) + int ignore; +{ + /* Assume delimiter is part of expression. BSD4.2 as fails with + delightful bug, so we are not being incompatible here. */ + new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); + demand_empty_rest_of_line (); +} + +/* This handle the .symver pseudo-op, which is used to specify a + symbol version. The syntax is ``.symver NAME,SYMVERNAME''. + SYMVERNAME may contain ELF_VER_CHR ('@') characters. This + pseudo-op causes the assembler to emit a symbol named SYMVERNAME + with the same value as the symbol NAME. */ + +static void +obj_elf_symver (ignore) + int ignore; +{ + char *name; + char c; + symbolS *sym; + + name = input_line_pointer; + c = get_symbol_end (); + + sym = symbol_find_or_make (name); + + *input_line_pointer = c; + + if (sym->sy_obj.versioned_name != NULL) + { + as_bad ("multiple .symver directives for symbol `%s'", + S_GET_NAME (sym)); + ignore_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("expected comma after name in .symver"); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + name = input_line_pointer; + while (1) + { + c = get_symbol_end (); + if (c != ELF_VER_CHR) + break; + *input_line_pointer++ = c; + } + + sym->sy_obj.versioned_name = xstrdup (name); + + *input_line_pointer = c; + + if (strchr (sym->sy_obj.versioned_name, ELF_VER_CHR) == NULL) + { + as_bad ("missing version name in `%s' for symbol `%s'", + sym->sy_obj.versioned_name, S_GET_NAME (sym)); + ignore_rest_of_line (); + return; + } + + demand_empty_rest_of_line (); +} + +void +obj_read_begin_hook () +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_read_begin_hook (); +#endif +} + +void +obj_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + symbolP->sy_obj.size = NULL; + symbolP->sy_obj.versioned_name = NULL; + +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_symbol_new_hook (symbolP); +#endif +} + +void +obj_elf_version (ignore) + int ignore; +{ + char *name; + unsigned int c; + char ch; + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp = (asection *) NULL; + int i, len; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '\"') + { + ++input_line_pointer; /* -> 1st char of string. */ + name = input_line_pointer; + + while (is_a_char (c = next_char_of_string ())) + ; + c = *input_line_pointer; + *input_line_pointer = '\0'; + *(input_line_pointer - 1) = '\0'; + *input_line_pointer = c; + + /* create the .note section */ + + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* process the version string */ + + len = strlen (name); + + i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */ + i_note.descsz = 0; /* no description */ + i_note.type = NT_VERSION; + p = frag_more (sizeof (e_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, 4); + p = frag_more (sizeof (e_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, 4); + p = frag_more (sizeof (e_note.type)); + md_number_to_chars (p, (valueT) i_note.type, 4); + + for (i = 0; i < len; i++) + { + ch = *(name + i); + { + FRAG_APPEND_1_CHAR (ch); + } + } + frag_align (2, 0, 0); + + subseg_set (seg, subseg); + } + else + { + as_bad ("Expected quoted string"); + } + demand_empty_rest_of_line (); +} + +static void +obj_elf_size (ignore) + int ignore; +{ + char *name = input_line_pointer; + char c = get_symbol_end (); + char *p; + expressionS exp; + symbolS *sym; + + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad ("expected comma after name `%s' in .size directive", name); + *p = c; + ignore_rest_of_line (); + return; + } + input_line_pointer++; + expression (&exp); + if (exp.X_op == O_absent) + { + as_bad ("missing expression in .size directive"); + exp.X_op = O_constant; + exp.X_add_number = 0; + } + *p = 0; + sym = symbol_find_or_make (name); + *p = c; + if (exp.X_op == O_constant) + S_SET_SIZE (sym, exp.X_add_number); + else + { + sym->sy_obj.size = (expressionS *) xmalloc (sizeof (expressionS)); + *sym->sy_obj.size = exp; + } + demand_empty_rest_of_line (); +} + +/* Handle the ELF .type pseudo-op. This sets the type of a symbol. + There are three syntaxes. The first (used on Solaris) is + .type SYM,#function + The second (used on UnixWare) is + .type SYM,@function + The third (reportedly to be used on Irix 6.0) is + .type SYM STT_FUNC + */ + +static void +obj_elf_type (ignore) + int ignore; +{ + char *name; + char c; + int type; + const char *typename; + symbolS *sym; + + name = input_line_pointer; + c = get_symbol_end (); + sym = symbol_find_or_make (name); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + ++input_line_pointer; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '#' || *input_line_pointer == '@') + ++input_line_pointer; + + typename = input_line_pointer; + c = get_symbol_end (); + + type = 0; + if (strcmp (typename, "function") == 0 + || strcmp (typename, "STT_FUNC") == 0) + type = BSF_FUNCTION; + else if (strcmp (typename, "object") == 0 + || strcmp (typename, "STT_OBJECT") == 0) + type = BSF_OBJECT; + else + as_bad ("ignoring unrecognized symbol type \"%s\"", typename); + + *input_line_pointer = c; + + sym->bsym->flags |= type; + + demand_empty_rest_of_line (); +} + +static void +obj_elf_ident (ignore) + int ignore; +{ + static segT comment_section; + segT old_section = now_seg; + int old_subsection = now_subseg; + + if (!comment_section) + { + char *p; + comment_section = subseg_new (".comment", 0); + bfd_set_section_flags (stdoutput, comment_section, + SEC_READONLY | SEC_HAS_CONTENTS); + p = frag_more (1); + *p = 0; + } + else + subseg_set (comment_section, 0); + stringer (1); + subseg_set (old_section, old_subsection); +} + +#ifdef INIT_STAB_SECTION + +/* The first entry in a .stabs section is special. */ + +void +obj_elf_init_stab_section (seg) + segT seg; +{ + char *file; + char *p; + char *stabstr_name; + unsigned int stroff; + + /* Force the section to align to a longword boundary. Without this, + UnixWare ar crashes. */ + bfd_set_section_alignment (stdoutput, seg, 2); + + /* Make space for this first symbol. */ + p = frag_more (12); + /* Zero it out. */ + memset (p, 0, 12); + as_where (&file, (unsigned int *) NULL); + stabstr_name = (char *) alloca (strlen (segment_name (seg)) + 4); + strcpy (stabstr_name, segment_name (seg)); + strcat (stabstr_name, "str"); + stroff = get_stab_string_offset (file, stabstr_name); + know (stroff == 1); + md_number_to_chars (p, stroff, 4); + seg_info (seg)->stabu.p = p; +} + +#endif + +/* Fill in the counts in the first entry in a .stabs section. */ + +static void +adjust_stab_sections (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + char *name; + asection *strsec; + char *p; + int strsz, nsyms; + + if (strncmp (".stab", sec->name, 5)) + return; + if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) + return; + + name = (char *) alloca (strlen (sec->name) + 4); + strcpy (name, sec->name); + strcat (name, "str"); + strsec = bfd_get_section_by_name (abfd, name); + if (strsec) + strsz = bfd_section_size (abfd, strsec); + else + strsz = 0; + nsyms = bfd_section_size (abfd, sec) / 12 - 1; + + p = seg_info (sec)->stabu.p; + assert (p != 0); + + bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); + bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); +} + +#ifdef NEED_ECOFF_DEBUG + +/* This function is called by the ECOFF code. It is supposed to + record the external symbol information so that the backend can + write it out correctly. The ELF backend doesn't actually handle + this at the moment, so we do it ourselves. We save the information + in the symbol. */ + +void +elf_ecoff_set_ext (sym, ext) + symbolS *sym; + struct ecoff_extr *ext; +{ + sym->bsym->udata.p = (PTR) ext; +} + +/* This function is called by bfd_ecoff_debug_externals. It is + supposed to *EXT to the external symbol information, and return + whether the symbol should be used at all. */ + +static boolean +elf_get_extr (sym, ext) + asymbol *sym; + EXTR *ext; +{ + if (sym->udata.p == NULL) + return false; + *ext = *(EXTR *) sym->udata.p; + return true; +} + +/* This function is called by bfd_ecoff_debug_externals. It has + nothing to do for ELF. */ + +/*ARGSUSED*/ +static void +elf_set_index (sym, indx) + asymbol *sym; + bfd_size_type indx; +{ +} + +#endif /* NEED_ECOFF_DEBUG */ + +void +elf_frob_symbol (symp, puntp) + symbolS *symp; + int *puntp; +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_frob_symbol (symp); +#endif + + if (symp->sy_obj.size != NULL) + { + switch (symp->sy_obj.size->X_op) + { + case O_subtract: + S_SET_SIZE (symp, + (S_GET_VALUE (symp->sy_obj.size->X_add_symbol) + + symp->sy_obj.size->X_add_number + - S_GET_VALUE (symp->sy_obj.size->X_op_symbol))); + break; + case O_constant: + S_SET_SIZE (symp, + (S_GET_VALUE (symp->sy_obj.size->X_add_symbol) + + symp->sy_obj.size->X_add_number)); + break; + default: + as_bad (".size expression too complicated to fix up"); + break; + } + free (symp->sy_obj.size); + symp->sy_obj.size = NULL; + } + + if (symp->sy_obj.versioned_name != NULL) + { + /* This symbol was given a new name with the .symver directive. + + If this is an external reference, just rename the symbol to + include the version string. This will make the relocs be + against the correct versioned symbol. + + If this is a definition, add an alias. FIXME: Using an alias + will permit the debugging information to refer to the right + symbol. However, it's not clear whether it is the best + approach. */ + + if (! S_IS_DEFINED (symp)) + { + char *p; + + /* Verify that the name isn't using the @@ syntax--this is + reserved for definitions of the default version to link + against. */ + p = strchr (symp->sy_obj.versioned_name, ELF_VER_CHR); + know (p != NULL); + if (p[1] == ELF_VER_CHR) + { + as_bad ("invalid attempt to declare external version name as default in symbol `%s'", + symp->sy_obj.versioned_name); + *puntp = true; + } + S_SET_NAME (symp, symp->sy_obj.versioned_name); + } + else + { + symbolS *symp2; + + /* FIXME: Creating a new symbol here is risky. We're in the + final loop over the symbol table. We can get away with + it only because the symbol goes to the end of the list, + where the loop will still see it. It would probably be + better to do this in obj_frob_file_before_adjust. */ + + symp2 = symbol_find_or_make (symp->sy_obj.versioned_name); + + /* Now we act as though we saw symp2 = sym. */ + + S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); + + /* Subtracting out the frag address here is a hack because + we are in the middle of the final loop. */ + S_SET_VALUE (symp2, S_GET_VALUE (symp) - symp->sy_frag->fr_address); + + symp2->sy_frag = symp->sy_frag; + + /* This will copy over the size information. */ + copy_symbol_attributes (symp2, symp); + + if (S_IS_WEAK (symp)) + S_SET_WEAK (symp2); + + if (S_IS_EXTERNAL (symp)) + S_SET_EXTERNAL (symp2); + } + } + + /* Double check weak symbols. */ + if (symp->bsym->flags & BSF_WEAK) + { + if (S_IS_COMMON (symp)) + as_bad ("Symbol `%s' can not be both weak and common", + S_GET_NAME (symp)); + } + +#ifdef TC_MIPS + /* The Irix 5 and 6 assemblers set the type of any common symbol and + any undefined non-function symbol to STT_OBJECT. We try to be compatible, + since newer Irix 5 and 6 linkers care. */ + if (S_IS_COMMON (symp) + || (! S_IS_DEFINED (symp) && ((symp->bsym->flags & BSF_FUNCTION) == 0))) + symp->bsym->flags |= BSF_OBJECT; +#endif + +#ifdef TC_PPC + /* Frob the PowerPC, so that the symbol always has object type + if it is not some other type. VxWorks needs this. */ + if ((symp->bsym->flags & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0 + && S_IS_DEFINED (symp)) + symp->bsym->flags |= BSF_OBJECT; +#endif +} + +void +elf_frob_file () +{ + bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0); + +#ifdef elf_tc_final_processing + elf_tc_final_processing (); +#endif +} + +/* It is required that we let write_relocs have the opportunity to + optimize away fixups before output has begun, since it is possible + to eliminate all fixups for a section and thus we never should + have generated the relocation section. */ + +void +elf_frob_file_after_relocs () +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + /* Generate the ECOFF debugging information. */ + { + const struct ecoff_debug_swap *debug_swap; + struct ecoff_debug_info debug; + char *buf; + asection *sec; + + debug_swap + = get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap; + know (debug_swap != (const struct ecoff_debug_swap *) NULL); + ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap); + + /* Set up the pointers in debug. */ +#define SET(ptr, offset, type) \ + debug.ptr = (type) (buf + debug.symbolic_header.offset) + + SET (line, cbLineOffset, unsigned char *); + SET (external_dnr, cbDnOffset, PTR); + SET (external_pdr, cbPdOffset, PTR); + SET (external_sym, cbSymOffset, PTR); + SET (external_opt, cbOptOffset, PTR); + SET (external_aux, cbAuxOffset, union aux_ext *); + SET (ss, cbSsOffset, char *); + SET (external_fdr, cbFdOffset, PTR); + SET (external_rfd, cbRfdOffset, PTR); + /* ssext and external_ext are set up just below. */ + +#undef SET + + /* Set up the external symbols. */ + debug.ssext = debug.ssext_end = NULL; + debug.external_ext = debug.external_ext_end = NULL; + if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true, + elf_get_extr, elf_set_index)) + as_fatal ("Failed to set up debugging information: %s", + bfd_errmsg (bfd_get_error ())); + + sec = bfd_get_section_by_name (stdoutput, ".mdebug"); + assert (sec != NULL); + + know (stdoutput->output_has_begun == false); + + /* We set the size of the section, call bfd_set_section_contents + to force the ELF backend to allocate a file position, and then + write out the data. FIXME: Is this really the best way to do + this? */ + sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap); + + if (! bfd_set_section_contents (stdoutput, sec, (PTR) NULL, + (file_ptr) 0, (bfd_size_type) 0)) + as_fatal ("Can't start writing .mdebug section: %s", + bfd_errmsg (bfd_get_error ())); + + know (stdoutput->output_has_begun == true); + know (sec->filepos != 0); + + if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap, + sec->filepos)) + as_fatal ("Could not write .mdebug section: %s", + bfd_errmsg (bfd_get_error ())); + } +#endif /* NEED_ECOFF_DEBUG */ +} + +#ifdef SCO_ELF + +/* Heavily plagarized from obj_elf_version. The idea is to emit the + SCO specific identifier in the .notes section to satisfy the SCO + linker. + + This looks more complicated than it really is. As opposed to the + "obvious" solution, this should handle the cross dev cases + correctly. (i.e, hosting on a 64 bit big endian processor, but + generating SCO Elf code) Efficiency isn't a concern, as there + should be exactly one of these sections per object module. + + SCO OpenServer 5 identifies it's ELF modules with a standard ELF + .note section. + + int_32 namesz = 4 ; Name size + int_32 descsz = 12 ; Descriptive information + int_32 type = 1 ; + char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL + int_32 version = (major ver # << 16) | version of tools ; + int_32 source = (tool_id << 16 ) | 1 ; + int_32 info = 0 ; These are set by the SCO tools, but we + don't know enough about the source + environment to set them. SCO ld currently + ignores them, and recommends we set them + to zero. */ + +#define SCO_MAJOR_VERSION 0x1 +#define SCO_MINOR_VERSION 0x1 + +void +sco_id () +{ + + char *name; + unsigned int c; + char ch; + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp = (asection *) NULL; + int i, len; + + /* create the .note section */ + + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* process the version string */ + + i_note.namesz = 4; + i_note.descsz = 12; /* 12 descriptive bytes */ + i_note.type = NT_VERSION; /* Contains a version string */ + + p = frag_more (sizeof (i_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, 4); + + p = frag_more (sizeof (i_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, 4); + + p = frag_more (sizeof (i_note.type)); + md_number_to_chars (p, (valueT) i_note.type, 4); + + p = frag_more (4); + strcpy (p, "SCO"); + + /* Note: this is the version number of the ELF we're representing */ + p = frag_more (4); + md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); + + /* Here, we pick a magic number for ourselves (yes, I "registered" + it with SCO. The bottom bit shows that we are compat with the + SCO ABI. */ + p = frag_more (4); + md_number_to_chars (p, 0x4c520000 | 0x0001, 4); + + /* If we knew (or cared) what the source language options were, we'd + fill them in here. SCO has given us permission to ignore these + and just set them to zero. */ + p = frag_more (4); + md_number_to_chars (p, 0x0000, 4); + + frag_align (2, 0, 0); + + /* We probably can't restore the current segment, for there likely + isn't one yet... */ + if (seg && subseg) + subseg_set (seg, subseg); + +} + +#endif /* SCO_ELF */ + +const struct format_ops elf_format_ops = +{ + bfd_target_elf_flavour, + 0, + 1, + elf_frob_symbol, + elf_frob_file, + elf_frob_file_after_relocs, + elf_s_get_size, elf_s_set_size, + elf_s_get_align, elf_s_set_align, + elf_copy_symbol_attributes, +#ifdef NEED_ECOFF_DEBUG + ecoff_generate_asm_lineno, + ecoff_stab, +#else + 0, + 0, /* process_stab */ +#endif + elf_sec_sym_ok_for_reloc, + elf_pop_insert, +#ifdef NEED_ECOFF_DEBUG + elf_ecoff_set_ext, +#else + 0, +#endif + obj_read_begin_hook, + obj_symbol_new_hook, +}; diff --git a/contrib/binutils/gas/config/obj-elf.h b/contrib/binutils/gas/config/obj-elf.h new file mode 100644 index 0000000..973f938 --- /dev/null +++ b/contrib/binutils/gas/config/obj-elf.h @@ -0,0 +1,173 @@ +/* ELF object file format. + Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +/* HP PA-RISC support was contributed by the Center for Software Science + at the University of Utah. */ + +#ifndef _OBJ_ELF_H +#define _OBJ_ELF_H + +#define OBJ_ELF 1 + +#define OUTPUT_FLAVOR bfd_target_elf_flavour + +#include <bfd.h> + +#define BYTES_IN_WORD 4 /* for now */ +#include "bfd/elf-bfd.h" + +/* Additional information we keep for each symbol. */ + +/* FIXME: For some reason, this structure is needed both here and in + obj-multi.h. */ +#ifndef OBJ_SYMFIELD_TYPE +struct elf_obj_sy +{ + /* Use this to keep track of .size expressions that involve + differences that we can't compute yet. */ + expressionS *size; + + /* The name specified by the .symver directive. */ + char *versioned_name; +}; +#endif + +#define OBJ_SYMFIELD_TYPE struct elf_obj_sy + +/* Symbol fields used by the ELF back end. */ +#define ELF_TARGET_SYMBOL_FIELDS int local:1; + +/* Don't change this; change ELF_TARGET_SYMBOL_FIELDS instead. */ +#define TARGET_SYMBOL_FIELDS ELF_TARGET_SYMBOL_FIELDS + +#include "targ-cpu.h" + +#ifndef FALSE +#define FALSE 0 +#define TRUE !FALSE +#endif + +#define obj_begin() elf_begin () +extern void elf_begin PARAMS ((void)); + +/* should be conditional on address size! */ +#define elf_symbol(asymbol) ((elf_symbol_type *)(&(asymbol)->the_bfd)) + +#define S_GET_SIZE(S) (elf_symbol ((S)->bsym)->internal_elf_sym.st_size) +#define S_SET_SIZE(S,V) \ + (elf_symbol((S)->bsym)->internal_elf_sym.st_size = (V)) + +#define S_GET_ALIGN(S) (elf_symbol ((S)->bsym)->internal_elf_sym.st_value) +#define S_SET_ALIGN(S,V) \ + (elf_symbol ((S)->bsym)->internal_elf_sym.st_value = (V)) + +#define S_GET_OTHER(S) (elf_symbol ((S)->bsym)->internal_elf_sym.st_other) +#define S_SET_OTHER(S,V) \ + (elf_symbol ((S)->bsym)->internal_elf_sym.st_other = (V)) + +extern asection *gdb_section; + +#define obj_frob_file elf_frob_file +extern void elf_frob_file PARAMS ((void)); + +#define obj_frob_file_after_relocs elf_frob_file_after_relocs +extern void elf_frob_file_after_relocs PARAMS ((void)); + +#define obj_app_file elf_file_symbol +extern void elf_file_symbol PARAMS ((char *)); + +extern void obj_elf_section_change_hook PARAMS ((void)); + +extern void obj_elf_section PARAMS ((int)); +extern void obj_elf_previous PARAMS ((int)); +extern void obj_elf_version PARAMS ((int)); + +/* BFD wants to write the udata field, which is a no-no for the + globally defined sections. */ +#define obj_sec_sym_ok_for_reloc(SEC) ((SEC)->owner != 0) + +/* When setting one symbol equal to another, by default we probably + want them to have the same "size", whatever it means in the current + context. */ +#define OBJ_COPY_SYMBOL_ATTRIBUTES(DEST,SRC) \ +do \ + { \ + S_SET_SIZE ((DEST), S_GET_SIZE (SRC)); \ + S_SET_OTHER ((DEST), S_GET_OTHER (SRC)); \ + } \ +while (0) + +/* Stabs go in a separate section. */ +#define SEPARATE_STAB_SECTIONS 1 + +/* We need 12 bytes at the start of the section to hold some initial + information. */ +extern void obj_elf_init_stab_section PARAMS ((segT)); +#define INIT_STAB_SECTION(seg) obj_elf_init_stab_section (seg) + +/* For now, always set ECOFF_DEBUGGING for an Alpha target. */ +#ifdef TC_ALPHA +#define ECOFF_DEBUGGING 1 +#endif + +/* For now, always set ECOFF_DEBUGGING for a MIPS target. */ +#ifdef TC_MIPS +#define ECOFF_DEBUGGING 1 +#endif + +#if ECOFF_DEBUGGING + +/* If we are generating ECOFF debugging information, we need some + additional fields for each symbol. */ +#undef TARGET_SYMBOL_FIELDS +#define TARGET_SYMBOL_FIELDS \ + ELF_TARGET_SYMBOL_FIELDS \ + struct efdr *ecoff_file; \ + struct localsym *ecoff_symbol; \ + valueT ecoff_extern_size; + +/* We smuggle stabs in ECOFF rather than using a separate section. + The Irix linker can not handle a separate stabs section. */ +#undef SEPARATE_STAB_SECTIONS +#undef INIT_STAB_SECTION +#define OBJ_PROCESS_STAB(seg, what, string, type, other, desc) \ + ecoff_stab ((seg), (what), (string), (type), (other), (desc)) + +#define OBJ_GENERATE_ASM_LINENO(filename, lineno) \ + ecoff_generate_asm_lineno ((filename), (lineno)) + +#endif /* ECOFF_DEBUGGING */ + +extern void elf_frob_symbol PARAMS ((struct symbol *, int *)); +#define obj_frob_symbol(symp, punt) elf_frob_symbol (symp, &punt) + +extern void elf_pop_insert PARAMS ((void)); +#define obj_pop_insert() elf_pop_insert() + +#ifndef OBJ_MAYBE_ELF +#define obj_ecoff_set_ext elf_ecoff_set_ext +#ifdef ANSI_PROTOTYPES +struct ecoff_extr; +#endif +extern void elf_ecoff_set_ext PARAMS ((struct symbol *, struct ecoff_extr *)); +#endif + +#endif /* _OBJ_ELF_H */ diff --git a/contrib/binutils/gas/config/obj-generic.c b/contrib/binutils/gas/config/obj-generic.c new file mode 100644 index 0000000..69fc3d1 --- /dev/null +++ b/contrib/binutils/gas/config/obj-generic.c @@ -0,0 +1,41 @@ +/* This file is obj-generic.c and is intended to be a template for + object format specific source files. + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Chars that can be used to separate mant from exp in floating point nums */ +char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* These chars start a comment anywhere in a source file (except inside + another comment */ +const char comment_chars[] = "#"; + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-generic.c */ diff --git a/contrib/binutils/gas/config/obj-generic.h b/contrib/binutils/gas/config/obj-generic.h new file mode 100644 index 0000000..dc18e43 --- /dev/null +++ b/contrib/binutils/gas/config/obj-generic.h @@ -0,0 +1,80 @@ +/* This file is obj-generic.h + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * This file is obj-generic.h and is intended to be a template for + * object format specific header files. + */ + +/* define an obj specific macro off which target cpu back ends may key. */ +#define OBJ_GENERIC 1 + +/* include whatever target cpu is appropriate. */ +#include "targ-cpu.h" + +/* + * SYMBOLS + */ + +/* + * If your object format needs to reorder symbols, define this. When + * defined, symbols are kept on a doubly linked list and functions are + * made available for push, insert, append, and delete. If not defined, + * symbols are kept on a singly linked list, only the append and clear + * facilities are available, and they are macros. + */ + +/* #define SYMBOLS_NEED_PACKPOINTERS */ + +/* */ +typedef struct + { + void *nothing; + } + +obj_symbol_type; /* should be the format's symbol structure */ + +typedef void *object_headers; + +/* symbols have names */ +#define S_GET_NAME(s) ("foo") /* get the name of a symbolP */ +#define S_SET_NAME(s,v) ; +/* symbols have segments */ +#define S_GET_SEGMENT(s) (SEG_UNKNOWN) +#define S_SET_SEGMENT(s,v) ; +/* symbols may be external */ +#define S_IS_EXTERNAL(s) (0) +#define S_SET_EXTERNAL(s) ; + +/* symbols may or may not be defined */ +#define S_IS_DEFINED(s) (0) + + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0) /* your magic number */ + +#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of obj-generic.h */ diff --git a/contrib/binutils/gas/config/obj-ieee.c b/contrib/binutils/gas/config/obj-ieee.c new file mode 100644 index 0000000..42e4b1f --- /dev/null +++ b/contrib/binutils/gas/config/obj-ieee.c @@ -0,0 +1,627 @@ +/* obj-format for ieee-695 records. + Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +/* + created by + + steve chamberlain steve@cygnus.com + */ + +/* + this will hopefully become the port through which bfd and gas talk, + for the moment, only ieee is known to work well. + */ + +#include "bfd.h" +#include "as.h" +#include "subsegs.h" +#include "output-file.h" +#include "frags.h" + +bfd *abfd; + +/* How many addresses does the .align take? */ +static relax_addressT +relax_align (address, alignment) + register relax_addressT address; /* Address now. */ + register long alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~((~0) << alignment); + new_address = (address + mask) & (~mask); + return (new_address - address); +} /* relax_align() */ + +/* calculate the size of the frag chain and create a bfd section + to contain all of it */ +static void +DEFUN (size_section, (abfd, idx), + bfd * abfd AND + unsigned int idx) +{ + asection *sec; + unsigned int size = 0; + fragS *frag = segment_info[idx].frag_root; + while (frag) + { + if (frag->fr_address != size) + { + printf ("Out of step\n"); + size = frag->fr_address; + } + size += frag->fr_fix; + switch (frag->fr_type) + { + case rs_fill: + case rs_org: + size += frag->fr_offset * frag->fr_var; + break; + case rs_align: + case rs_align_code: + { + addressT off; + + off = relax_align (size, frag->fr_offset); + if (frag->fr_subtype != 0 && off > frag->fr_subtype) + off = 0; + size += off; + } + } + frag = frag->fr_next; + } + if (size) + { + char *name = segment_info[idx].name; + if (name == (char *) NULL) + { + name = ".data"; + } + segment_info[idx].user_stuff = (char *) (sec = bfd_make_section (abfd, name)); + /* Make it output through itself */ + sec->output_section = sec; + sec->flags |= SEC_HAS_CONTENTS; + bfd_set_section_size (abfd, sec, size); + } +} + +/* run through a frag chain and write out the data to go with it */ +static void +DEFUN (fill_section, (abfd, idx), + bfd * abfd AND + unsigned int idx) +{ + asection *sec = segment_info[idx].user_stuff; + if (sec) + { + fragS *frag = segment_info[idx].frag_root; + unsigned int offset = 0; + while (frag) + { + unsigned int fill_size; + unsigned int count; + switch (frag->fr_type) + { + case rs_fill: + case rs_align: + case rs_org: + if (frag->fr_fix) + { + bfd_set_section_contents (abfd, + sec, + frag->fr_literal, + frag->fr_address, + frag->fr_fix); + } + offset += frag->fr_fix; + fill_size = frag->fr_var; + if (fill_size) + { + unsigned int off = frag->fr_fix; + for (count = frag->fr_offset; count; count--) + { + bfd_set_section_contents (abfd, sec, + frag->fr_literal + + frag->fr_fix, + frag->fr_address + off, + fill_size); + off += fill_size; + } + } + break; + default: + abort (); + } + frag = frag->fr_next; + } + } +} + +/* Count the relocations in a chain */ + +static unsigned int +DEFUN (count_entries_in_chain, (idx), + unsigned int idx) +{ + unsigned int nrelocs; + fixS *fixup_ptr; + + /* Count the relocations */ + fixup_ptr = segment_info[idx].fix_root; + nrelocs = 0; + while (fixup_ptr != (fixS *) NULL) + { + fixup_ptr = fixup_ptr->fx_next; + nrelocs++; + } + return nrelocs; +} + +/* output all the relocations for a section */ +void +DEFUN (do_relocs_for, (idx), + unsigned int idx) +{ + unsigned int nrelocs; + arelent **reloc_ptr_vector; + arelent *reloc_vector; + asymbol **ptrs; + asection *section = (asection *) (segment_info[idx].user_stuff); + unsigned int i; + fixS *from; + if (section) + { + nrelocs = count_entries_in_chain (idx); + + reloc_ptr_vector = (arelent **) malloc ((nrelocs + 1) * sizeof (arelent *)); + reloc_vector = (arelent *) malloc (nrelocs * sizeof (arelent)); + ptrs = (asymbol **) malloc (nrelocs * sizeof (asymbol *)); + from = segment_info[idx].fix_root; + for (i = 0; i < nrelocs; i++) + { + arelent *to = reloc_vector + i; + asymbol *s; + reloc_ptr_vector[i] = to; + to->howto = (reloc_howto_type *) (from->fx_r_type); + +#if 0 /* We can't represent complicated things in a reloc yet */ + if (from->fx_addsy == 0 || from->fx_subsy != 0) abort(); +#endif + + s = &(from->fx_addsy->sy_symbol.sy); + to->address = ((char *) (from->fx_frag->fr_address + + from->fx_where)) + - ((char *) (&(from->fx_frag->fr_literal))); + to->addend = from->fx_offset; + /* If we know the symbol which we want to relocate to, turn + this reloaction into a section relative. + + If this relocation is pcrelative, and we know the + destination, we still want to keep the relocation - since + the linker might relax some of the bytes, but it stops + being pc relative and turns into an absolute relocation. */ + if (s) + { + if ((s->flags & BSF_UNDEFINED) == 0) + { + to->section = s->section; + + /* We can refer directly to the value field here, + rather than using S_GET_VALUE, because this is + only called after do_symbols, which sets up the + value field. */ + to->addend += s->value; + + to->sym_ptr_ptr = 0; + if (to->howto->pcrel_offset) + { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address + 1; + } + } + else + { + to->section = 0; + *ptrs = &(from->fx_addsy->sy_symbol.sy); + to->sym_ptr_ptr = ptrs; + + if (to->howto->pcrel_offset) + { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address - 1; + } + } + + } + else + { + to->section = 0; + } + + ptrs++; + from = from->fx_next; + } + + /* attatch to the section */ + section->orelocation = reloc_ptr_vector; + section->reloc_count = nrelocs; + section->flags |= SEC_LOAD; + } +} + +/* do the symbols.. */ +static void +DEFUN (do_symbols, (abfd), + bfd * abfd) +{ + extern symbolS *symbol_rootP; + symbolS *ptr; + asymbol **symbol_ptr_vec; + asymbol *symbol_vec; + unsigned int count = 0; + unsigned int index; + + + for (ptr = symbol_rootP; + ptr != (symbolS *) NULL; + ptr = ptr->sy_next) + { + if (SEG_NORMAL (ptr->sy_symbol.seg)) + { + ptr->sy_symbol.sy.section = + (asection *) (segment_info[ptr->sy_symbol.seg].user_stuff); + S_SET_VALUE (ptr, S_GET_VALUE (ptr) + ptr->sy_frag->fr_address); + if (ptr->sy_symbol.sy.flags == 0) + { + ptr->sy_symbol.sy.flags = BSF_LOCAL; + } + } + else + { + switch (ptr->sy_symbol.seg) + { + case SEG_ABSOLUTE: + ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE; + ptr->sy_symbol.sy.section = 0; + break; + case SEG_UNKNOWN: + ptr->sy_symbol.sy.flags = BSF_UNDEFINED; + ptr->sy_symbol.sy.section = 0; + break; + default: + abort (); + } + } + ptr->sy_symbol.sy.value = S_GET_VALUE (ptr); + count++; + } + symbol_ptr_vec = (asymbol **) malloc ((count + 1) * sizeof (asymbol *)); + + index = 0; + for (ptr = symbol_rootP; + ptr != (symbolS *) NULL; + ptr = ptr->sy_next) + { + symbol_ptr_vec[index] = &(ptr->sy_symbol.sy); + index++; + } + symbol_ptr_vec[index] = 0; + abfd->outsymbols = symbol_ptr_vec; + abfd->symcount = count; +} + +/* The generic as->bfd converter. Other backends may have special case + code */ + +void +DEFUN_VOID (bfd_as_write_hook) +{ + int i; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + size_section (abfd, i); + } + + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + fill_section (abfd, i); + + do_symbols (abfd); + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + do_relocs_for (i); + +} + +S_SET_SEGMENT (x, y) + symbolS *x; + int y; +{ + x->sy_symbol.seg = y; +} + +S_IS_DEFINED (x) + symbolS *x; +{ + if (SEG_NORMAL (x->sy_symbol.seg)) + { + return 1; + } + switch (x->sy_symbol.seg) + { + case SEG_UNKNOWN: + return 0; + default: + abort (); + } +} + +S_IS_EXTERNAL (x) +{ + abort (); +} + +S_GET_DESC (x) +{ + abort (); +} + +S_GET_SEGMENT (x) + symbolS *x; +{ + return x->sy_symbol.seg; +} + +S_SET_EXTERNAL (x) + symbolS *x; +{ + x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT; +} + +S_SET_NAME (x, y) + symbolS *x; + char *y; +{ + x->sy_symbol.sy.name = y; +} + +S_GET_OTHER (x) +{ + abort (); +} + +S_IS_DEBUG (x) +{ + abort (); +} + +#ifndef segment_name +char * +segment_name () +{ + abort (); +} +#endif + +void +obj_read_begin_hook () +{ +} + +static void +obj_ieee_section (ignore) + int ignore; +{ + extern char *input_line_pointer; + extern char is_end_of_line[]; + char *p = input_line_pointer; + char *s = p; + int i; + /* Look up the name, if it doesn't exist, make it */ + while (*p && *p != ' ' && *p != ',' && !is_end_of_line[*p]) + { + p++; + } + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + if (segment_info[i].hadone) + { + if (strncmp (segment_info[i].name, s, p - s) == 0) + { + goto ok; + + } + } + else + break; + } + if (i == SEG_UNKNOWN) + { + as_bad ("too many sections"); + return; + } + + segment_info[i].hadone = 1; + segment_info[i].name = malloc (p - s + 1); + memcpy (segment_info[i].name, s, p - s); + segment_info[i].name[p - s] = 0; +ok: + subseg_set (i, 0); + while (!is_end_of_line[*p]) + p++; + input_line_pointer = p; + +} + + +void cons (); +void s_ignore (); + + +void s_globl (); +const pseudo_typeS obj_pseudo_table[] = +{ + {"section", obj_ieee_section, 0}, + {"data.b", cons, 1}, + {"data.w", cons, 2}, + {"data.l", cons, 4}, + {"export", s_globl, 0}, + {"option", s_ignore, 0}, + {"end", s_ignore, 0}, + {"import", s_ignore, 0}, + {"sdata", stringer, 0}, + 0, + +}; + + + +void +obj_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + symbolP->sy_symbol.sy.the_bfd = abfd; +} + + + + + +#if 1 +extern void +DEFUN_VOID (write_object_file) +{ + int i; + struct frchain *frchain_ptr; + struct frag *frag_ptr; + + abfd = bfd_openw (out_file_name, "ieee"); + + if (abfd == 0) + { + as_perror ("FATAL: Can't create %s", out_file_name); + exit (EXIT_FAILURE); + } + bfd_set_format (abfd, bfd_object); + bfd_set_arch_mach (abfd, bfd_arch_h8300, 0); + subseg_set (1, 0); + subseg_set (2, 0); + subseg_set (3, 0); + for (frchain_ptr = frchain_root; + frchain_ptr != (struct frchain *) NULL; + frchain_ptr = frchain_ptr->frch_next) + { + /* Run through all the sub-segments and align them up. Also close any + open frags. We tack a .fill onto the end of the frag chain so + that any .align's size can be worked by looking at the next + frag. */ + + subseg_set (frchain_ptr->frch_seg, frchain_ptr->frch_subseg); +#ifndef SUB_SEGMENT_ALIGN +#define SUB_SEGMENT_ALIGN(SEG) 2 +#endif + frag_align (SUB_SEGMENT_ALIGN (now_seg), 0, 0); + frag_wane (frag_now); + frag_now->fr_fix = 0; + know (frag_now->fr_next == NULL); + } + + /* Now build one big frag chain for each segment, linked through + fr_next. */ + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + + fragS **prev_frag_ptr_ptr; + struct frchain *next_frchain_ptr; + + /* struct frag **head_ptr = segment_info[i].frag_root;*/ + + segment_info[i].frag_root = segment_info[i].frchainP->frch_root; +#if 0 + /* Im not sure what this is for */ + for (frchain_ptr = segment_info[i].frchainP->frch_root; + frchain_ptr != (struct frchain *) NULL; + frchain_ptr = frchain_ptr->frch_next) + { + *head_ptr = frchain_ptr; + head_ptr = &frchain_ptr->next; + } + + +#endif + } + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + relax_segment (segment_info[i].frag_root, i); + } + + /* Now the addresses of the frags are correct within the segment */ + + bfd_as_write_hook (); + bfd_close (abfd); +} + +#endif + +H_SET_TEXT_SIZE (a, b) +{ + abort (); +} + +H_GET_TEXT_SIZE () +{ + abort (); +} + +H_SET_BSS_SIZE () +{ + abort (); +} + +H_SET_STRING_SIZE () +{ + abort (); +} + +H_SET_RELOCATION_SIZE () +{ + abort (); +} + +H_SET_MAGIC_NUMBER () +{ + abort (); +} + +H_GET_FILE_SIZE () +{ + abort (); +} + +H_GET_TEXT_RELOCATION_SIZE () +{ + abort (); +} + +/* end of obj-ieee.c */ diff --git a/contrib/binutils/gas/config/obj-ieee.h b/contrib/binutils/gas/config/obj-ieee.h new file mode 100644 index 0000000..4a0f126 --- /dev/null +++ b/contrib/binutils/gas/config/obj-ieee.h @@ -0,0 +1,50 @@ +/* This file is obj-ieee.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define BFD 1 + +#include <bfd.h> + +typedef struct +{ + asymbol sy; + int seg; +} + +obj_symbol_type; + +#define S_GET_NAME(s) (((s)->sy_symbol.sy.name)) + +typedef struct + { + int x; + } + +object_headers; + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1 + + +int lineno_rootP; + + +#define IEEE_STYLE + +/* end of obj-ieee.h */ diff --git a/contrib/binutils/gas/config/obj-multi.c b/contrib/binutils/gas/config/obj-multi.c new file mode 100644 index 0000000..d115093 --- /dev/null +++ b/contrib/binutils/gas/config/obj-multi.c @@ -0,0 +1,4 @@ +/* foo */ + +#include "as.h" + diff --git a/contrib/binutils/gas/config/obj-multi.h b/contrib/binutils/gas/config/obj-multi.h new file mode 100644 index 0000000..526b82e --- /dev/null +++ b/contrib/binutils/gas/config/obj-multi.h @@ -0,0 +1,50 @@ +/* hi */ + +#include "emul.h" +#include "targ-cpu.h" + +#define OUTPUT_FLAVOR (this_format->flavor) +#define obj_frob_symbol(S,P) (this_format->frob_symbol)(S,&(P)) +#define obj_frob_file (this_format->frob_file) +#define obj_frob_file_after_relocs (this_format->frob_file_after_relocs) +#define obj_ecoff_set_ext (this_format->ecoff_set_ext) +#define obj_pop_insert (this_format->pop_insert) +#define obj_read_begin_hook() (this_format->read_begin_hook?this_format->read_begin_hook():(void)0) +#define obj_symbol_new_hook (this_format->symbol_new_hook) +#define obj_sec_sym_ok_for_reloc (this_format->sec_sym_ok_for_reloc) +#define S_GET_SIZE (this_format->s_get_size) +#define S_SET_SIZE (this_format->s_set_size) +#define S_GET_ALIGN (this_format->s_get_align) +#define S_SET_ALIGN (this_format->s_set_align) +#define obj_copy_symbol_attributes (this_format->copy_symbol_attributes) +#define OBJ_PROCESS_STAB (this_format->process_stab) + +#if defined (OBJ_MAYBE_ECOFF) || (defined (OBJ_MAYBE_ELF) && defined (TC_MIPS)) +#define ECOFF_DEBUGGING 1 +#endif + +/* FIXME: What's the story here? Why do we have to define + OBJ_SYMFIELD_TYPE both here and in obj-elf.h? */ +#ifdef OBJ_MAYBE_ELF +struct elf_obj_sy +{ + expressionS *size; + char *versioned_name; +}; +#define OBJ_SYMFIELD_TYPE struct elf_obj_sy +#define ELF_TARGET_SYMBOL_FIELDS int local:1; +#else +#define ELF_TARGET_SYMBOL_FIELDS +#endif + +#ifdef ECOFF_DEBUGGING +struct efdr; +struct localsym; +#define ECOFF_DEBUG_TARGET_SYMBOL_FIELDS struct efdr *ecoff_file; struct localsym *ecoff_symbol; valueT ecoff_extern_size; +#else +#define ECOFF_DEBUG_TARGET_SYMBOL_FIELDS +#endif + +#define TARGET_SYMBOL_FIELDS \ + ELF_TARGET_SYMBOL_FIELDS \ + ECOFF_DEBUG_TARGET_SYMBOL_FIELDS diff --git a/contrib/binutils/gas/config/sco5.mt b/contrib/binutils/gas/config/sco5.mt new file mode 100644 index 0000000..8879320 --- /dev/null +++ b/contrib/binutils/gas/config/sco5.mt @@ -0,0 +1 @@ +TDEFINES=-DSCO_ELF diff --git a/contrib/binutils/gas/config/tc-alpha.c b/contrib/binutils/gas/config/tc-alpha.c new file mode 100644 index 0000000..a47191e --- /dev/null +++ b/contrib/binutils/gas/config/tc-alpha.c @@ -0,0 +1,4428 @@ +/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU. + Copyright (C) 1989, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + Contributed by Carnegie Mellon University, 1993. + Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. + Modified by Ken Raeburn for gas-2.x and ECOFF support. + Modified by Richard Henderson for ELF support. + Modified by Klaus K"ampf for EVAX (openVMS/Alpha) support. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include "as.h" +#include "subsegs.h" + +#include "opcode/alpha.h" + +#ifdef OBJ_ELF +#include "elf/alpha.h" +#endif + +#include <ctype.h> + + +/* Local types */ + +#define MAX_INSN_FIXUPS 2 +#define MAX_INSN_ARGS 5 + +struct alpha_fixup +{ + expressionS exp; + bfd_reloc_code_real_type reloc; +}; + +struct alpha_insn +{ + unsigned insn; + int nfixups; + struct alpha_fixup fixups[MAX_INSN_FIXUPS]; +}; + +enum alpha_macro_arg +{ + MACRO_EOA = 1, MACRO_IR, MACRO_PIR, MACRO_CPIR, MACRO_FPR, MACRO_EXP +}; + +struct alpha_macro +{ + const char *name; + void (*emit) PARAMS ((const expressionS *, int, const PTR)); + const PTR arg; + enum alpha_macro_arg argsets[16]; +}; + +/* Two extra symbols we want to see in our input. This is a blatent + misuse of the expressionS.X_op field. */ + +#define O_pregister (O_max+1) /* O_register, but in parentheses */ +#define O_cpregister (O_pregister+1) /* + a leading comma */ + +/* Macros for extracting the type and number of encoded register tokens */ + +#define is_ir_num(x) (((x) & 32) == 0) +#define is_fpr_num(x) (((x) & 32) != 0) +#define regno(x) ((x) & 31) + +/* Something odd inherited from the old assembler */ + +#define note_gpreg(R) (alpha_gprmask |= (1 << (R))) +#define note_fpreg(R) (alpha_fprmask |= (1 << (R))) + +/* Predicates for 16- and 32-bit ranges */ + +#define range_signed_16(x) ((offsetT)(x) >= -(offsetT)0x8000 && \ + (offsetT)(x) <= (offsetT)0x7FFF) +#define range_signed_32(x) ((offsetT)(x) >= -(offsetT)0x80000000 && \ + (offsetT)(x) <= (offsetT)0x7FFFFFFF) + +/* Macros for sign extending from 16- and 32-bits. */ +/* XXX: The cast macros will work on all the systems that I care about, + but really a predicate should be found to use the non-cast forms. */ + +#if 1 +#define sign_extend_16(x) ((short)(x)) +#define sign_extend_32(x) ((int)(x)) +#else +#define sign_extend_16(x) ((offsetT)(((x) & 0xFFFF) ^ 0x8000) - 0x8000) +#define sign_extend_32(x) ((offsetT)(((x) & 0xFFFFFFFF) \ + ^ 0x80000000) - 0x80000000) +#endif + +/* Macros to build tokens */ + +#define set_tok_reg(t, r) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_register, \ + (t).X_add_number = (r)) +#define set_tok_preg(t, r) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_pregister, \ + (t).X_add_number = (r)) +#define set_tok_cpreg(t, r) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_cpregister, \ + (t).X_add_number = (r)) +#define set_tok_freg(t, r) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_register, \ + (t).X_add_number = (r)+32) +#define set_tok_sym(t, s, a) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_symbol, \ + (t).X_add_symbol = (s), \ + (t).X_add_number = (a)) +#define set_tok_const(t, n) (memset(&(t), 0, sizeof(t)), \ + (t).X_op = O_constant, \ + (t).X_add_number = (n)) + + +/* Prototypes for all local functions */ + +static int tokenize_arguments PARAMS ((char *, expressionS *, int)); +static const struct alpha_opcode *find_opcode_match + PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *)); +static const struct alpha_macro *find_macro_match + PARAMS ((const struct alpha_macro *, const expressionS *, int *)); +static unsigned insert_operand + PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned)); +static void assemble_insn + PARAMS ((const struct alpha_opcode *, const expressionS *, int, + struct alpha_insn *)); +static void emit_insn PARAMS ((struct alpha_insn *)); +static void assemble_tokens_to_insn + PARAMS ((const char *, const expressionS *, int, struct alpha_insn *)); +static void assemble_tokens + PARAMS ((const char *, const expressionS *, int, int)); + +static int load_expression + PARAMS ((int, const expressionS *, int *, expressionS *)); + +static void emit_ldgp PARAMS ((const expressionS *, int, const PTR)); +static void emit_division PARAMS ((const expressionS *, int, const PTR)); +static void emit_lda PARAMS ((const expressionS *, int, const PTR)); +static void emit_ldah PARAMS ((const expressionS *, int, const PTR)); +static void emit_ir_load PARAMS ((const expressionS *, int, const PTR)); +static void emit_loadstore PARAMS ((const expressionS *, int, const PTR)); +static void emit_jsrjmp PARAMS ((const expressionS *, int, const PTR)); +static void emit_ldX PARAMS ((const expressionS *, int, const PTR)); +static void emit_ldXu PARAMS ((const expressionS *, int, const PTR)); +static void emit_uldX PARAMS ((const expressionS *, int, const PTR)); +static void emit_uldXu PARAMS ((const expressionS *, int, const PTR)); +static void emit_ldil PARAMS ((const expressionS *, int, const PTR)); +static void emit_stX PARAMS ((const expressionS *, int, const PTR)); +static void emit_ustX PARAMS ((const expressionS *, int, const PTR)); +static void emit_sextX PARAMS ((const expressionS *, int, const PTR)); +static void emit_retjcr PARAMS ((const expressionS *, int, const PTR)); + +static void s_alpha_text PARAMS ((int)); +static void s_alpha_data PARAMS ((int)); +#ifndef OBJ_ELF +static void s_alpha_comm PARAMS ((int)); +#endif +#if defined (OBJ_ECOFF) || defined (OBJ_EVAX) +static void s_alpha_rdata PARAMS ((int)); +#endif +#ifdef OBJ_ECOFF +static void s_alpha_sdata PARAMS ((int)); +#endif +#ifdef OBJ_ELF +static void s_alpha_section PARAMS ((int)); +#endif +#ifdef OBJ_EVAX +static void s_alpha_section PARAMS ((int)); +#endif +static void s_alpha_gprel32 PARAMS ((int)); +static void s_alpha_float_cons PARAMS ((int)); +static void s_alpha_proc PARAMS ((int)); +static void s_alpha_set PARAMS ((int)); +static void s_alpha_base PARAMS ((int)); +static void s_alpha_align PARAMS ((int)); +static void s_alpha_stringer PARAMS ((int)); +static void s_alpha_space PARAMS ((int)); + +static void create_literal_section PARAMS ((const char *, segT *, symbolS **)); +#ifndef OBJ_ELF +static void select_gp_value PARAMS ((void)); +#endif +static void alpha_align PARAMS ((int, char *, symbolS *)); + + +/* Generic assembler global variables which must be defined by all + targets. */ + +/* These are exported to relaxing code, even though we don't do any + relaxing on this processor currently. */ +int md_short_jump_size = 4; +int md_long_jump_size = 4; + +/* Characters which always start a comment. */ +const char comment_chars[] = "#"; + +/* Characters which start a comment at the beginning of a line. */ +const char line_comment_chars[] = "#"; + +/* Characters which may be used to separate multiple commands on a + single line. */ +const char line_separator_chars[] = ";"; + +/* Characters which are used to indicate an exponent in a floating + point number. */ +const char EXP_CHARS[] = "eE"; + +/* Characters which mean that a number is a floating point constant, + as in 0d1.0. */ +#if 0 +const char FLT_CHARS[] = "dD"; +#else +/* XXX: Do all of these really get used on the alpha?? */ +char FLT_CHARS[] = "rRsSfFdDxXpP"; +#endif + +#ifdef OBJ_EVAX +const char *md_shortopts = "Fm:g+1h:H"; +#else +const char *md_shortopts = "Fm:g"; +#endif + +struct option md_longopts[] = { +#define OPTION_32ADDR (OPTION_MD_BASE) + { "32addr", no_argument, NULL, OPTION_32ADDR }, + { NULL, no_argument, NULL, 0 } +}; + +size_t md_longopts_size = sizeof(md_longopts); + + +#ifdef OBJ_EVAX +#define AXP_REG_R0 0 +#define AXP_REG_R16 16 +#define AXP_REG_R17 17 +#undef AXP_REG_T9 +#define AXP_REG_T9 22 +#undef AXP_REG_T10 +#define AXP_REG_T10 23 +#undef AXP_REG_T11 +#define AXP_REG_T11 24 +#undef AXP_REG_T12 +#define AXP_REG_T12 25 +#define AXP_REG_AI 25 +#undef AXP_REG_FP +#define AXP_REG_FP 29 + +#undef AXP_REG_GP +#define AXP_REG_GP AXP_REG_PV +#endif /* OBJ_EVAX */ + +/* The cpu for which we are generating code */ +static unsigned alpha_target = AXP_OPCODE_BASE; +static const char *alpha_target_name = "<all>"; + +/* The hash table of instruction opcodes */ +static struct hash_control *alpha_opcode_hash; + +/* The hash table of macro opcodes */ +static struct hash_control *alpha_macro_hash; + +#ifdef OBJ_ECOFF +/* The $gp relocation symbol */ +static symbolS *alpha_gp_symbol; + +/* XXX: what is this, and why is it exported? */ +valueT alpha_gp_value; +#endif + +/* The current $gp register */ +static int alpha_gp_register = AXP_REG_GP; + +/* A table of the register symbols */ +static symbolS *alpha_register_table[64]; + +/* Constant sections, or sections of constants */ +#ifdef OBJ_ECOFF +static segT alpha_lita_section; +static segT alpha_lit4_section; +#endif +#ifdef OBJ_EVAX +static segT alpha_link_section; +static segT alpha_ctors_section; +static segT alpha_dtors_section; +#endif +static segT alpha_lit8_section; + +/* Symbols referring to said sections. */ +#ifdef OBJ_ECOFF +static symbolS *alpha_lita_symbol; +static symbolS *alpha_lit4_symbol; +#endif +#ifdef OBJ_EVAX +static symbolS *alpha_link_symbol; +static symbolS *alpha_ctors_symbol; +static symbolS *alpha_dtors_symbol; +#endif +static symbolS *alpha_lit8_symbol; + +/* Literal for .litX+0x8000 within .lita */ +#ifdef OBJ_ECOFF +static offsetT alpha_lit4_literal; +static offsetT alpha_lit8_literal; +#endif + +/* Is the assembler not allowed to use $at? */ +static int alpha_noat_on = 0; + +/* Are macros enabled? */ +static int alpha_macros_on = 1; + +/* Are floats disabled? */ +static int alpha_nofloats_on = 0; + +/* Are addresses 32 bit? */ +static int alpha_addr32_on = 0; + +/* Symbol labelling the current insn. When the Alpha gas sees + foo: + .quad 0 + and the section happens to not be on an eight byte boundary, it + will align both the symbol and the .quad to an eight byte boundary. */ +static symbolS *alpha_insn_label; + +/* Whether we should automatically align data generation pseudo-ops. + .align 0 will turn this off. */ +static int alpha_auto_align_on = 1; + +/* The known current alignment of the current section. */ +static int alpha_current_align; + +/* These are exported to ECOFF code. */ +unsigned long alpha_gprmask, alpha_fprmask; + +/* Whether the debugging option was seen. */ +static int alpha_debug; + +#ifdef OBJ_EVAX +/* Collect information about current procedure here. */ +static struct { + symbolS *symbol; /* proc pdesc symbol */ + int pdsckind; + int framereg; /* register for frame pointer */ + int framesize; /* size of frame */ + int rsa_offset; + int ra_save; + int fp_save; + long imask; + long fmask; + int type; + int prologue; +} alpha_evax_proc; + +static int alpha_flag_hash_long_names = 0; /* -+ */ +static int alpha_flag_show_after_trunc = 0; /* -H */ + +/* If the -+ switch is given, then a hash is appended to any name that is + * longer than 64 characters, else longer symbol names are truncated. + */ + +static int alpha_basereg_clobbered; +#endif + +/* The macro table */ + +static const struct alpha_macro alpha_macros[] = { +/* Load/Store macros */ + { "lda", emit_lda, NULL, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldah", emit_ldah, NULL, + { MACRO_IR, MACRO_EXP, MACRO_EOA } }, + + { "ldl", emit_ir_load, "ldl", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldl_l", emit_ir_load, "ldl_l", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldq", emit_ir_load, "ldq", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldq_l", emit_ir_load, "ldq_l", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldq_u", emit_ir_load, "ldq_u", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldf", emit_loadstore, "ldf", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldg", emit_loadstore, "ldg", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "lds", emit_loadstore, "lds", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldt", emit_loadstore, "ldt", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + + { "ldb", emit_ldX, (PTR)0, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldbu", emit_ldXu, (PTR)0, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldw", emit_ldX, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldwu", emit_ldXu, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + + { "uldw", emit_uldX, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "uldwu", emit_uldXu, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "uldl", emit_uldX, (PTR)2, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "uldlu", emit_uldXu, (PTR)2, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "uldq", emit_uldXu, (PTR)3, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + + { "ldgp", emit_ldgp, NULL, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } }, + + { "ldi", emit_lda, NULL, + { MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldil", emit_ldil, NULL, + { MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ldiq", emit_lda, NULL, + { MACRO_IR, MACRO_EXP, MACRO_EOA } }, +#if 0 + { "ldif" emit_ldiq, NULL, + { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldid" emit_ldiq, NULL, + { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldig" emit_ldiq, NULL, + { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldis" emit_ldiq, NULL, + { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "ldit" emit_ldiq, NULL, + { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, +#endif + + { "stl", emit_loadstore, "stl", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stl_c", emit_loadstore, "stl_c", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stq", emit_loadstore, "stq", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stq_c", emit_loadstore, "stq_c", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stq_u", emit_loadstore, "stq_u", + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stf", emit_loadstore, "stf", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "stg", emit_loadstore, "stg", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "sts", emit_loadstore, "sts", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + { "stt", emit_loadstore, "stt", + { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_FPR, MACRO_EXP, MACRO_EOA } }, + + { "stb", emit_stX, (PTR)0, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "stw", emit_stX, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ustw", emit_ustX, (PTR)1, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ustl", emit_ustX, (PTR)2, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + { "ustq", emit_ustX, (PTR)3, + { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA } }, + +/* Arithmetic macros */ +#if 0 + { "absl" emit_absl, 1, { IR } }, + { "absl" emit_absl, 2, { IR, IR } }, + { "absl" emit_absl, 2, { EXP, IR } }, + { "absq" emit_absq, 1, { IR } }, + { "absq" emit_absq, 2, { IR, IR } }, + { "absq" emit_absq, 2, { EXP, IR } }, +#endif + + { "sextb", emit_sextX, (PTR)0, + { MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EOA, + /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, + { "sextw", emit_sextX, (PTR)1, + { MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EOA, + /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, + + { "divl", emit_division, "__divl", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "divlu", emit_division, "__divlu", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "divq", emit_division, "__divq", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "divqu", emit_division, "__divqu", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "reml", emit_division, "__reml", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "remlu", emit_division, "__remlu", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "remq", emit_division, "__remq", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + { "remqu", emit_division, "__remqu", + { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_IR, MACRO_EOA, + /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, + + { "jsr", emit_jsrjmp, "jsr", + { MACRO_PIR, MACRO_EXP, MACRO_EOA, + MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA, + MACRO_EXP, MACRO_EOA } }, + { "jmp", emit_jsrjmp, "jmp", + { MACRO_PIR, MACRO_EXP, MACRO_EOA, + MACRO_PIR, MACRO_EOA, + MACRO_IR, MACRO_EXP, MACRO_EOA, + MACRO_EXP, MACRO_EOA } }, + { "ret", emit_retjcr, "ret", + { MACRO_IR, MACRO_EXP, MACRO_EOA, + MACRO_IR, MACRO_EOA, + MACRO_PIR, MACRO_EXP, MACRO_EOA, + MACRO_PIR, MACRO_EOA, + MACRO_EXP, MACRO_EOA, + MACRO_EOA } }, + { "jcr", emit_retjcr, "jcr", + { MACRO_IR, MACRO_EXP, MACRO_EOA, + MACRO_IR, MACRO_EOA, + MACRO_PIR, MACRO_EXP, MACRO_EOA, + MACRO_PIR, MACRO_EOA, + MACRO_EXP, MACRO_EOA, + MACRO_EOA } }, + { "jsr_coroutine", emit_retjcr, "jcr", + { MACRO_IR, MACRO_EXP, MACRO_EOA, + MACRO_IR, MACRO_EOA, + MACRO_PIR, MACRO_EXP, MACRO_EOA, + MACRO_PIR, MACRO_EOA, + MACRO_EXP, MACRO_EOA, + MACRO_EOA } }, +}; + +static const int alpha_num_macros + = sizeof(alpha_macros) / sizeof(*alpha_macros); + +/* Public interface functions */ + +/* This function is called once, at assembler startup time. It sets + up all the tables, etc. that the MD part of the assembler will + need, that can be determined before arguments are parsed. */ + +void +md_begin () +{ + unsigned int i = 0; + + /* Create the opcode hash table */ + + alpha_opcode_hash = hash_new (); + for (i = 0; i < alpha_num_opcodes; ) + { + const char *name, *retval; + + name = alpha_opcodes[i].name; + retval = hash_insert (alpha_opcode_hash, name, (PTR)&alpha_opcodes[i]); + if (retval) + as_fatal ("internal error: can't hash opcode `%s': %s", name, retval); + + while (++i < alpha_num_opcodes + && (alpha_opcodes[i].name == name + || !strcmp (alpha_opcodes[i].name, name))) + continue; + } + + /* Some opcodes include modifiers of various sorts with a "/mod" syntax, + like the architecture manual suggests. However, for use with gcc at + least, we also need access to those same opcodes without the "/". */ + for (i = 0; i < alpha_num_opcodes; ) + { + const char *name, *slash; + name = alpha_opcodes[i].name; + if ((slash = strchr(name, '/')) != NULL) + { + char *p = xmalloc (strlen (name)); + memcpy(p, name, slash-name); + strcpy(p+(slash-name), slash+1); + + (void)hash_insert(alpha_opcode_hash, p, (PTR)&alpha_opcodes[i]); + /* Ignore failures -- the opcode table does duplicate some + variants in different forms, like "hw_stq" and "hw_st/q". */ + } + + while (++i < alpha_num_opcodes + && (alpha_opcodes[i].name == name + || !strcmp (alpha_opcodes[i].name, name))) + continue; + } + + /* Create the macro hash table */ + + alpha_macro_hash = hash_new (); + for (i = 0; i < alpha_num_macros; ) + { + const char *name, *retval; + + name = alpha_macros[i].name; + retval = hash_insert (alpha_macro_hash, name, (PTR)&alpha_macros[i]); + if (retval) + as_fatal ("internal error: can't hash macro `%s': %s", name, retval); + + while (++i < alpha_num_macros + && (alpha_macros[i].name == name + || !strcmp (alpha_macros[i].name, name))) + continue; + } + + /* Construct symbols for each of the registers */ + + for (i = 0; i < 32; ++i) + { + char name[4]; + sprintf(name, "$%d", i); + alpha_register_table[i] = symbol_create(name, reg_section, i, + &zero_address_frag); + } + for (; i < 64; ++i) + { + char name[5]; + sprintf(name, "$f%d", i-32); + alpha_register_table[i] = symbol_create(name, reg_section, i, + &zero_address_frag); + } + + /* Create the special symbols and sections we'll be using */ + + /* So .sbss will get used for tiny objects. */ + bfd_set_gp_size (stdoutput, 8); + +#ifdef OBJ_ECOFF + create_literal_section (".lita", &alpha_lita_section, &alpha_lita_symbol); + + /* For handling the GP, create a symbol that won't be output in the + symbol table. We'll edit it out of relocs later. */ + alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000, + &zero_address_frag); +#endif + +#ifdef OBJ_EVAX + create_literal_section (".link", &alpha_link_section, &alpha_link_symbol); +#endif + +#ifdef OBJ_ELF + if (ECOFF_DEBUGGING) + { + segT sec; + + sec = subseg_new(".mdebug", (subsegT)0); + bfd_set_section_flags(stdoutput, sec, SEC_HAS_CONTENTS|SEC_READONLY); + bfd_set_section_alignment(stdoutput, sec, 3); + +#ifdef ERIC_neverdef + sec = subseg_new(".reginfo", (subsegT)0); + /* The ABI says this section should be loaded so that the running + program can access it. */ + bfd_set_section_flags(stdoutput, sec, + SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_DATA); + bfd_set_section_alignement(stdoutput, sec, 3); +#endif + } +#endif /* OBJ_ELF */ + + subseg_set(text_section, 0); +} + +/* The public interface to the instruction assembler. */ + +void +md_assemble (str) + char *str; +{ + char opname[32]; /* current maximum is 13 */ + expressionS tok[MAX_INSN_ARGS]; + int ntok, opnamelen, trunclen; + + /* split off the opcode */ + opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/48"); + trunclen = (opnamelen < sizeof (opname) - 1 + ? opnamelen + : sizeof (opname) - 1); + memcpy (opname, str, trunclen); + opname[trunclen] = '\0'; + + /* tokenize the rest of the line */ + if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0) + { + as_bad ("syntax error"); + return; + } + + /* finish it off */ + assemble_tokens (opname, tok, ntok, alpha_macros_on); +} + +/* Round up a section's size to the appropriate boundary. */ + +valueT +md_section_align (seg, size) + segT seg; + valueT size; +{ + int align = bfd_get_section_alignment(stdoutput, seg); + valueT mask = ((valueT)1 << align) - 1; + + return (size + mask) & ~mask; +} + +/* Turn a string in input_line_pointer into a floating point constant + of type type, and store the appropriate bytes in *litP. The number + of LITTLENUMS emitted is stored in *sizeP. An error message is + returned, or NULL on OK. */ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +extern char *vax_md_atof PARAMS ((int, char *, int *)); + +char * +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) + { + /* VAX floats */ + case 'G': + /* VAX md_atof doesn't like "G" for some reason. */ + type = 'g'; + case 'F': + case 'D': + return vax_md_atof (type, litP, sizeP); + + /* IEEE floats */ + case 'f': + prec = 2; + break; + + case 'd': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP = 0; + return "Bad call to MD_ATOF()"; + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + *sizeP = prec * sizeof (LITTLENUM_TYPE); + + for (wordP = words + prec - 1; prec--;) + { + md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + + return 0; +} + +/* Take care of the target-specific command-line options. */ + +int +md_parse_option (c, arg) + int c; + char *arg; +{ + switch (c) + { + case 'F': + alpha_nofloats_on = 1; + break; + + case OPTION_32ADDR: + alpha_addr32_on = 1; + break; + + case 'g': + alpha_debug = 1; + break; + + case 'm': + { + static const struct machine + { + const char *name; + unsigned flags; + } *p, m[] = + { + { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 }, + /* Do we have CIX extension here? */ + { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX }, + /* Still same PALcodes? */ + { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX + |AXP_OPCODE_CIX|AXP_OPCODE_MAX) }, + /* All new PALcodes? Extras? */ + { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_BWX + |AXP_OPCODE_CIX|AXP_OPCODE_MAX) }, + + { "ev4", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "ev45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "lca45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, + { "ev5", AXP_OPCODE_BASE|AXP_OPCODE_EV5 }, + { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX }, + { "pca56", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX + |AXP_OPCODE_CIX|AXP_OPCODE_MAX) }, + { "ev6", (AXP_OPCODE_BASE|AXP_OPCODE_BWX + |AXP_OPCODE_CIX|AXP_OPCODE_MAX) }, + + { "all", AXP_OPCODE_BASE }, + { 0 } + }; + + for (p = m; p->name; ++p) + if (strcmp(arg, p->name) == 0) + { + alpha_target_name = p->name, alpha_target = p->flags; + goto found; + } + as_warn("Unknown CPU identifier `%s'", arg); + found:; + } + break; + +#ifdef OBJ_EVAX + case '+': /* For g++. Hash any name > 63 chars long. */ + alpha_flag_hash_long_names = 1; + break; + + case 'H': /* Show new symbol after hash truncation */ + alpha_flag_show_after_trunc = 1; + break; + + case 'h': /* for gnu-c/vax compatibility. */ + break; +#endif + + default: + return 0; + } + + return 1; +} + +/* Print a description of the command-line options that we accept. */ + +void +md_show_usage (stream) + FILE *stream; +{ + fputs("\ +Alpha options:\n\ +-32addr treat addresses as 32-bit values\n\ +-F lack floating point instructions support\n\ +-m21064 | -m21066 | -m21164 | -m21164a\n\ +-mev4 | -mev45 | -mev5 | -mev56 | -mall\n\ + specify variant of Alpha architecture\n", + stream); +#ifdef OBJ_EVAX + fputs ("\ +VMS options:\n\ +-+ hash encode (don't truncate) names longer than 64 characters\n\ +-H show new symbol after hash truncation\n", + stream); +#endif +} + +/* Decide from what point a pc-relative relocation is relative to, + relative to the pc-relative fixup. Er, relatively speaking. */ + +long +md_pcrel_from (fixP) + fixS *fixP; +{ + valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; + switch (fixP->fx_r_type) + { + case BFD_RELOC_ALPHA_GPDISP: + case BFD_RELOC_ALPHA_GPDISP_HI16: + case BFD_RELOC_ALPHA_GPDISP_LO16: + return addr; + default: + return fixP->fx_size + addr; + } +} + +/* Attempt to simplify or even eliminate a fixup. The return value is + ignored; perhaps it was once meaningful, but now it is historical. + To indicate that a fixup has been eliminated, set fixP->fx_done. + + For ELF, here it is that we transform the GPDISP_HI16 reloc we used + internally into the GPDISP reloc used externally. We had to do + this so that we'd have the GPDISP_LO16 reloc as a tag to compute + the distance to the "lda" instruction for setting the addend to + GPDISP. */ + +int +md_apply_fix (fixP, valueP) + fixS *fixP; + valueT *valueP; +{ + char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; + valueT value = *valueP; + unsigned image, size; + + switch (fixP->fx_r_type) + { + /* The GPDISP relocations are processed internally with a symbol + referring to the current function; we need to drop in a value + which, when added to the address of the start of the function, + gives the desired GP. */ + case BFD_RELOC_ALPHA_GPDISP_HI16: + { + fixS *next = fixP->fx_next; + assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16); + + fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where + - fixP->fx_frag->fr_address - fixP->fx_where); + + value = (value - sign_extend_16 (value)) >> 16; + } +#ifdef OBJ_ELF + fixP->fx_r_type = BFD_RELOC_ALPHA_GPDISP; +#endif + goto do_reloc_gp; + + case BFD_RELOC_ALPHA_GPDISP_LO16: + value = sign_extend_16 (value); + fixP->fx_offset = 0; +#ifdef OBJ_ELF + fixP->fx_done = 1; +#endif + + do_reloc_gp: + fixP->fx_addsy = section_symbol (absolute_section); + md_number_to_chars (fixpos, value, 2); + break; + + case BFD_RELOC_16: + size = 2; + goto do_reloc_xx; + case BFD_RELOC_32: + size = 4; + goto do_reloc_xx; + case BFD_RELOC_64: + size = 8; + do_reloc_xx: + if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) + { + md_number_to_chars (fixpos, value, size); + goto done; + } + return 1; + +#ifdef OBJ_ECOFF + case BFD_RELOC_GPREL32: + assert (fixP->fx_subsy == alpha_gp_symbol); + fixP->fx_subsy = 0; + /* FIXME: inherited this obliviousness of `value' -- why? */ + md_number_to_chars (fixpos, -alpha_gp_value, 4); + break; +#endif +#ifdef OBJ_ELF + case BFD_RELOC_GPREL32: + return 1; +#endif + + case BFD_RELOC_23_PCREL_S2: + if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) + { + image = bfd_getl32(fixpos); + image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF); + goto write_done; + } + return 1; + + case BFD_RELOC_ALPHA_HINT: + if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) + { + image = bfd_getl32(fixpos); + image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); + goto write_done; + } + return 1; + +#ifdef OBJ_ECOFF + case BFD_RELOC_ALPHA_LITERAL: + md_number_to_chars (fixpos, value, 2); + return 1; + + case BFD_RELOC_ALPHA_LITUSE: + return 1; +#endif +#ifdef OBJ_ELF + case BFD_RELOC_ALPHA_ELF_LITERAL: + case BFD_RELOC_ALPHA_LITUSE: + return 1; +#endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_LINKAGE: + case BFD_RELOC_ALPHA_CODEADDR: + return 1; +#endif + + default: + { + const struct alpha_operand *operand; + + if ((int)fixP->fx_r_type >= 0) + as_fatal ("unhandled relocation type %s", + bfd_get_reloc_code_name (fixP->fx_r_type)); + + assert (-(int)fixP->fx_r_type < alpha_num_operands); + operand = &alpha_operands[-(int)fixP->fx_r_type]; + + /* The rest of these fixups only exist internally during symbol + resolution and have no representation in the object file. + Therefore they must be completely resolved as constants. */ + + if (fixP->fx_addsy != 0 + && fixP->fx_addsy->bsym->section != absolute_section) + as_bad_where (fixP->fx_file, fixP->fx_line, + "non-absolute expression in constant field"); + + image = bfd_getl32(fixpos); + image = insert_operand(image, operand, (offsetT)value, + fixP->fx_file, fixP->fx_line); + } + goto write_done; + } + + if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0) + return 1; + else + { + as_warn_where(fixP->fx_file, fixP->fx_line, + "type %d reloc done?\n", (int)fixP->fx_r_type); + goto done; + } + +write_done: + md_number_to_chars(fixpos, image, 4); + +done: + fixP->fx_done = 1; + return 0; +} + +/* + * Look for a register name in the given symbol. + */ + +symbolS * +md_undefined_symbol(name) + char *name; +{ + if (*name == '$') + { + int is_float = 0, num; + + switch (*++name) + { + case 'f': + if (name[1] == 'p' && name[2] == '\0') + return alpha_register_table[AXP_REG_FP]; + is_float = 32; + /* FALLTHRU */ + + case 'r': + if (!isdigit(*++name)) + break; + /* FALLTHRU */ + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (name[1] == '\0') + num = name[0] - '0'; + else if (name[0] != '0' && isdigit(name[1]) && name[2] == '\0') + { + num = (name[0] - '0') * 10 + name[1] - '0'; + if (num >= 32) + break; + } + else + break; + + if (!alpha_noat_on && num == AXP_REG_AT) + as_warn("Used $at without \".set noat\""); + return alpha_register_table[num + is_float]; + + case 'a': + if (name[1] == 't' && name[2] == '\0') + { + if (!alpha_noat_on) + as_warn("Used $at without \".set noat\""); + return alpha_register_table[AXP_REG_AT]; + } + break; + + case 'g': + if (name[1] == 'p' && name[2] == '\0') + return alpha_register_table[alpha_gp_register]; + break; + + case 's': + if (name[1] == 'p' && name[2] == '\0') + return alpha_register_table[AXP_REG_SP]; + break; + } + } + return NULL; +} + +#ifdef OBJ_ECOFF +/* @@@ Magic ECOFF bits. */ + +void +alpha_frob_ecoff_data () +{ + select_gp_value (); + /* $zero and $f31 are read-only */ + alpha_gprmask &= ~1; + alpha_fprmask &= ~1; +} +#endif + +/* Hook to remember a recently defined label so that the auto-align + code can adjust the symbol after we know what alignment will be + required. */ + +void +alpha_define_label (sym) + symbolS *sym; +{ + alpha_insn_label = sym; +} + +/* Return true if we must always emit a reloc for a type and false if + there is some hope of resolving it a assembly time. */ + +int +alpha_force_relocation (f) + fixS *f; +{ + switch (f->fx_r_type) + { + case BFD_RELOC_ALPHA_GPDISP_HI16: + case BFD_RELOC_ALPHA_GPDISP_LO16: + case BFD_RELOC_ALPHA_GPDISP: +#ifdef OBJ_ECOFF + case BFD_RELOC_ALPHA_LITERAL: +#endif +#ifdef OBJ_ELF + case BFD_RELOC_ALPHA_ELF_LITERAL: +#endif + case BFD_RELOC_ALPHA_LITUSE: + case BFD_RELOC_GPREL32: +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_LINKAGE: + case BFD_RELOC_ALPHA_CODEADDR: +#endif + return 1; + + case BFD_RELOC_23_PCREL_S2: + case BFD_RELOC_32: + case BFD_RELOC_64: + case BFD_RELOC_ALPHA_HINT: + return 0; + + default: + assert((int)f->fx_r_type < 0 && -(int)f->fx_r_type < alpha_num_operands); + return 0; + } +} + +/* Return true if we can partially resolve a relocation now. */ + +int +alpha_fix_adjustable (f) + fixS *f; +{ +#ifdef OBJ_ELF + /* Prevent all adjustments to global symbols */ + if (S_IS_EXTERN (f->fx_addsy)) + return 0; +#endif + + /* Are there any relocation types for which we must generate a reloc + but we can adjust the values contained within it? */ + switch (f->fx_r_type) + { + case BFD_RELOC_ALPHA_GPDISP_HI16: + case BFD_RELOC_ALPHA_GPDISP_LO16: + case BFD_RELOC_ALPHA_GPDISP: + return 0; + +#ifdef OBJ_ECOFF + case BFD_RELOC_ALPHA_LITERAL: +#endif +#ifdef OBJ_ELF + case BFD_RELOC_ALPHA_ELF_LITERAL: +#endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_LINKAGE: + case BFD_RELOC_ALPHA_CODEADDR: +#endif + return 1; + + case BFD_RELOC_ALPHA_LITUSE: + return 0; + + case BFD_RELOC_GPREL32: + case BFD_RELOC_23_PCREL_S2: + case BFD_RELOC_32: + case BFD_RELOC_64: + case BFD_RELOC_ALPHA_HINT: + return 1; + + default: + assert ((int)f->fx_r_type < 0 + && - (int)f->fx_r_type < alpha_num_operands); + return 1; + } + /*NOTREACHED*/ +} + +/* Generate the BFD reloc to be stuck in the object file from the + fixup used internally in the assembler. */ + +arelent * +tc_gen_reloc (sec, fixp) + asection *sec; + fixS *fixp; +{ + arelent *reloc; + + reloc = (arelent *) xmalloc (sizeof (arelent)); + reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + + /* Make sure none of our internal relocations make it this far. + They'd better have been fully resolved by this point. */ + assert ((int)fixp->fx_r_type > 0); + + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "cannot represent `%s' relocation in object file", + bfd_get_reloc_code_name (fixp->fx_r_type)); + return NULL; + } + + if (!fixp->fx_pcrel != !reloc->howto->pc_relative) + { + as_fatal ("internal error? cannot generate `%s' relocation", + bfd_get_reloc_code_name (fixp->fx_r_type)); + } + assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); + +#ifdef OBJ_ECOFF + if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) + { + /* fake out bfd_perform_relocation. sigh */ + reloc->addend = -alpha_gp_value; + } + else +#endif + { + reloc->addend = fixp->fx_offset; +#ifdef OBJ_ELF + /* + * Ohhh, this is ugly. The problem is that if this is a local global + * symbol, the relocation will entirely be performed at link time, not + * at assembly time. bfd_perform_reloc doesn't know about this sort + * of thing, and as a result we need to fake it out here. + */ + if (S_IS_EXTERN (fixp->fx_addsy) && !S_IS_COMMON(fixp->fx_addsy)) + reloc->addend -= fixp->fx_addsy->bsym->value; +#endif + } + + return reloc; +} + +/* Parse a register name off of the input_line and return a register + number. Gets md_undefined_symbol above to do the register name + matching for us. + + Only called as a part of processing the ECOFF .frame directive. */ + +int +tc_get_register (frame) + int frame; +{ + int framereg = AXP_REG_SP; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '$') + { + char *s = input_line_pointer; + char c = get_symbol_end (); + symbolS *sym = md_undefined_symbol (s); + + *strchr(s, '\0') = c; + if (sym && (framereg = S_GET_VALUE (sym)) <= 31) + goto found; + } + as_warn ("frame reg expected, using $%d.", framereg); + +found: + note_gpreg (framereg); + return framereg; +} + +/* This is called before the symbol table is processed. In order to + work with gcc when using mips-tfile, we must keep all local labels. + However, in other cases, we want to discard them. If we were + called with -g, but we didn't see any debugging information, it may + mean that gcc is smuggling debugging information through to + mips-tfile, in which case we must generate all local labels. */ + +#ifdef OBJ_ECOFF + +void +alpha_frob_file_before_adjust () +{ + if (alpha_debug != 0 + && ! ecoff_debugging_seen) + flag_keep_locals = 1; +} + +#endif /* OBJ_ECOFF */ + +/* Parse the arguments to an opcode. */ + +static int +tokenize_arguments (str, tok, ntok) + char *str; + expressionS tok[]; + int ntok; +{ + expressionS *end_tok = tok + ntok; + char *old_input_line_pointer; + int saw_comma = 0, saw_arg = 0; + + memset (tok, 0, sizeof (*tok) * ntok); + + /* Save and restore input_line_pointer around this function */ + old_input_line_pointer = input_line_pointer; + input_line_pointer = str; + + while (tok < end_tok && *input_line_pointer) + { + SKIP_WHITESPACE (); + switch (*input_line_pointer) + { + case '\0': + goto fini; + + case ',': + ++input_line_pointer; + if (saw_comma || !saw_arg) + goto err; + saw_comma = 1; + break; + + case '(': + { + char *hold = input_line_pointer++; + + /* First try for parenthesized register ... */ + expression (tok); + if (*input_line_pointer == ')' && tok->X_op == O_register) + { + tok->X_op = (saw_comma ? O_cpregister : O_pregister); + saw_comma = 0; + saw_arg = 1; + ++input_line_pointer; + ++tok; + break; + } + + /* ... then fall through to plain expression */ + input_line_pointer = hold; + } + + default: + if (saw_arg && !saw_comma) + goto err; + expression (tok); + if (tok->X_op == O_illegal || tok->X_op == O_absent) + goto err; + + saw_comma = 0; + saw_arg = 1; + ++tok; + break; + } + } + +fini: + if (saw_comma) + goto err; + input_line_pointer = old_input_line_pointer; + return ntok - (end_tok - tok); + +err: + input_line_pointer = old_input_line_pointer; + return -1; +} + +/* Search forward through all variants of an opcode looking for a + syntax match. */ + +static const struct alpha_opcode * +find_opcode_match(first_opcode, tok, pntok, pcpumatch) + const struct alpha_opcode *first_opcode; + const expressionS *tok; + int *pntok; + int *pcpumatch; +{ + const struct alpha_opcode *opcode = first_opcode; + int ntok = *pntok; + int got_cpu_match = 0; + + do + { + const unsigned char *opidx; + int tokidx = 0; + + /* Don't match opcodes that don't exist on this architecture */ + if (!(opcode->flags & alpha_target)) + goto match_failed; + + got_cpu_match = 1; + + for (opidx = opcode->operands; *opidx; ++opidx) + { + const struct alpha_operand *operand = &alpha_operands[*opidx]; + + /* only take input from real operands */ + if (operand->flags & AXP_OPERAND_FAKE) + continue; + + /* when we expect input, make sure we have it */ + if (tokidx >= ntok) + { + if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0) + goto match_failed; + continue; + } + + /* match operand type with expression type */ + switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK) + { + case AXP_OPERAND_IR: + if (tok[tokidx].X_op != O_register + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + break; + case AXP_OPERAND_FPR: + if (tok[tokidx].X_op != O_register + || !is_fpr_num(tok[tokidx].X_add_number)) + goto match_failed; + break; + case AXP_OPERAND_IR|AXP_OPERAND_PARENS: + if (tok[tokidx].X_op != O_pregister + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + break; + case AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA: + if (tok[tokidx].X_op != O_cpregister + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + break; + + case AXP_OPERAND_RELATIVE: + case AXP_OPERAND_SIGNED: + case AXP_OPERAND_UNSIGNED: + switch (tok[tokidx].X_op) + { + case O_illegal: + case O_absent: + case O_register: + case O_pregister: + case O_cpregister: + goto match_failed; + } + break; + + default: + /* everything else should have been fake */ + abort(); + } + ++tokidx; + } + + /* possible match -- did we use all of our input? */ + if (tokidx == ntok) + { + *pntok = ntok; + return opcode; + } + + match_failed:; + } + while (++opcode-alpha_opcodes < alpha_num_opcodes + && !strcmp(opcode->name, first_opcode->name)); + + if (*pcpumatch) + *pcpumatch = got_cpu_match; + + return NULL; +} + +/* Search forward through all variants of a macro looking for a syntax + match. */ + +static const struct alpha_macro * +find_macro_match(first_macro, tok, pntok) + const struct alpha_macro *first_macro; + const expressionS *tok; + int *pntok; +{ + const struct alpha_macro *macro = first_macro; + int ntok = *pntok; + + do + { + const enum alpha_macro_arg *arg = macro->argsets; + int tokidx = 0; + + while (*arg) + { + switch (*arg) + { + case MACRO_EOA: + if (tokidx == ntok) + return macro; + else + tokidx = 0; + break; + + case MACRO_IR: + if (tokidx >= ntok || tok[tokidx].X_op != O_register + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + ++tokidx; + break; + case MACRO_PIR: + if (tokidx >= ntok || tok[tokidx].X_op != O_pregister + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + ++tokidx; + break; + case MACRO_CPIR: + if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister + || !is_ir_num(tok[tokidx].X_add_number)) + goto match_failed; + ++tokidx; + break; + case MACRO_FPR: + if (tokidx >= ntok || tok[tokidx].X_op != O_register + || !is_fpr_num(tok[tokidx].X_add_number)) + goto match_failed; + ++tokidx; + break; + + case MACRO_EXP: + if (tokidx >= ntok) + goto match_failed; + switch (tok[tokidx].X_op) + { + case O_illegal: + case O_absent: + case O_register: + case O_pregister: + case O_cpregister: + goto match_failed; + } + ++tokidx; + break; + + match_failed: + while (*arg != MACRO_EOA) + ++arg; + tokidx = 0; + break; + } + ++arg; + } + } + while (++macro-alpha_macros < alpha_num_macros + && !strcmp(macro->name, first_macro->name)); + + return NULL; +} + +/* Insert an operand value into an instruction. */ + +static unsigned +insert_operand(insn, operand, val, file, line) + unsigned insn; + const struct alpha_operand *operand; + offsetT val; + char *file; + unsigned line; +{ + if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW)) + { + offsetT min, max; + + if (operand->flags & AXP_OPERAND_SIGNED) + { + max = (1 << (operand->bits - 1)) - 1; + min = -(1 << (operand->bits - 1)); + } + else + { + max = (1 << operand->bits) - 1; + min = 0; + } + + if (val < min || val > max) + { + const char *err = + "operand out of range (%s not between %d and %d)"; + char buf[sizeof (val) * 3 + 2]; + + sprint_value(buf, val); + if (file) + as_warn_where(file, line, err, buf, min, max); + else + as_warn(err, buf, min, max); + } + } + + if (operand->insert) + { + const char *errmsg = NULL; + + insn = (*operand->insert) (insn, val, &errmsg); + if (errmsg) + as_warn (errmsg); + } + else + insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift); + + return insn; +} + +/* + * Turn an opcode description and a set of arguments into + * an instruction and a fixup. + */ + +static void +assemble_insn(opcode, tok, ntok, insn) + const struct alpha_opcode *opcode; + const expressionS *tok; + int ntok; + struct alpha_insn *insn; +{ + const unsigned char *argidx; + unsigned image; + int tokidx = 0; + + memset (insn, 0, sizeof (*insn)); + image = opcode->opcode; + + for (argidx = opcode->operands; *argidx; ++argidx) + { + const struct alpha_operand *operand = &alpha_operands[*argidx]; + const expressionS *t; + + if (operand->flags & AXP_OPERAND_FAKE) + { + /* fake operands take no value and generate no fixup */ + image = insert_operand(image, operand, 0, NULL, 0); + continue; + } + + if (tokidx >= ntok) + { + switch (operand->flags & AXP_OPERAND_OPTIONAL_MASK) + { + case AXP_OPERAND_DEFAULT_FIRST: + t = &tok[0]; + break; + case AXP_OPERAND_DEFAULT_SECOND: + t = &tok[1]; + break; + case AXP_OPERAND_DEFAULT_ZERO: + { + static const expressionS zero_exp = { 0, 0, 0, O_constant, 1 }; + t = &zero_exp; + } + break; + default: + abort(); + } + } + else + t = &tok[tokidx++]; + + switch (t->X_op) + { + case O_register: + case O_pregister: + case O_cpregister: + image = insert_operand(image, operand, regno(t->X_add_number), + NULL, 0); + break; + + case O_constant: + image = insert_operand(image, operand, t->X_add_number, NULL, 0); + break; + + default: + { + struct alpha_fixup *fixup; + + if (insn->nfixups >= MAX_INSN_FIXUPS) + as_fatal("too many fixups"); + + fixup = &insn->fixups[insn->nfixups++]; + + fixup->exp = *t; + fixup->reloc = operand->default_reloc; + } + break; + } + } + + insn->insn = image; +} + +/* + * Actually output an instruction with its fixup. + */ + +static void +emit_insn (insn) + struct alpha_insn *insn; +{ + char *f; + int i; + + /* Take care of alignment duties */ + if (alpha_auto_align_on && alpha_current_align < 2) + alpha_align (2, (char *) NULL, alpha_insn_label); + if (alpha_current_align > 2) + alpha_current_align = 2; + alpha_insn_label = NULL; + + /* Write out the instruction. */ + f = frag_more (4); + md_number_to_chars (f, insn->insn, 4); + + /* Apply the fixups in order */ + for (i = 0; i < insn->nfixups; ++i) + { + struct alpha_fixup *fixup = &insn->fixups[i]; + int size, pcrel; + fixS *fixP; + + /* Some fixups are only used internally and so have no howto */ + if ((int)fixup->reloc < 0) + size = 4, pcrel = 0; +#ifdef OBJ_ELF + /* These relocation types are only used internally. */ + else if (fixup->reloc == BFD_RELOC_ALPHA_GPDISP_HI16 + || fixup->reloc == BFD_RELOC_ALPHA_GPDISP_LO16) + { + size = 2, pcrel = 0; + } +#endif + else + { + reloc_howto_type *reloc_howto + = bfd_reloc_type_lookup (stdoutput, fixup->reloc); + assert (reloc_howto); + + size = bfd_get_reloc_size (reloc_howto); + pcrel = reloc_howto->pc_relative; + } + assert (size >= 1 && size <= 4); + + fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size, + &fixup->exp, pcrel, fixup->reloc); + + /* Turn off complaints that the addend is too large for some fixups */ + switch (fixup->reloc) + { + case BFD_RELOC_ALPHA_GPDISP_LO16: +#ifdef OBJ_ECOFF + case BFD_RELOC_ALPHA_LITERAL: +#endif +#ifdef OBJ_ELF + case BFD_RELOC_ALPHA_ELF_LITERAL: +#endif + case BFD_RELOC_GPREL32: + fixP->fx_no_overflow = 1; + break; + default: + break; + } + } +} + +/* Given an opcode name and a pre-tokenized set of arguments, assemble + the insn, but do not emit it. + + Note that this implies no macros allowed, since we can't store more + than one insn in an insn structure. */ + +static void +assemble_tokens_to_insn(opname, tok, ntok, insn) + const char *opname; + const expressionS *tok; + int ntok; + struct alpha_insn *insn; +{ + const struct alpha_opcode *opcode; + + /* search opcodes */ + opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); + if (opcode) + { + int cpumatch; + opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); + if (opcode) + { + assemble_insn (opcode, tok, ntok, insn); + return; + } + else if (cpumatch) + as_bad ("inappropriate arguments for opcode `%s'", opname); + else + as_bad ("opcode `%s' not supported for target %s", opname, + alpha_target_name); + } + else + as_bad ("unknown opcode `%s'", opname); +} + +/* Given an opcode name and a pre-tokenized set of arguments, take the + opcode all the way through emission. */ + +static void +assemble_tokens (opname, tok, ntok, local_macros_on) + const char *opname; + const expressionS *tok; + int ntok; + int local_macros_on; +{ + int found_something = 0; + const struct alpha_opcode *opcode; + const struct alpha_macro *macro; + int cpumatch = 1; + + /* search macros */ + if (local_macros_on) + { + macro = ((const struct alpha_macro *) + hash_find (alpha_macro_hash, opname)); + if (macro) + { + found_something = 1; + macro = find_macro_match (macro, tok, &ntok); + if (macro) + { + (*macro->emit) (tok, ntok, macro->arg); + return; + } + } + } + + /* search opcodes */ + opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); + if (opcode) + { + found_something = 1; + opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); + if (opcode) + { + struct alpha_insn insn; + assemble_insn (opcode, tok, ntok, &insn); + emit_insn (&insn); + return; + } + } + + if (found_something) + if (cpumatch) + as_bad ("inappropriate arguments for opcode `%s'", opname); + else + as_bad ("opcode `%s' not supported for target %s", opname, + alpha_target_name); + else + as_bad ("unknown opcode `%s'", opname); +} + + +/* Some instruction sets indexed by lg(size) */ +static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL }; +static const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" }; +static const char * const insXh_op[] = { NULL, "inswh", "inslh", "insqh" }; +static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" }; +static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" }; +static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" }; +static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" }; +static const char * const stX_op[] = { "stb", "stw", "stl", "stq" }; +static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" }; +static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; + +/* Implement the ldgp macro. */ + +static void +emit_ldgp (tok, ntok, unused) + const expressionS *tok; + int ntok; + const PTR unused; +{ +#ifdef OBJ_AOUT +FIXME +#endif +#if defined(OBJ_ECOFF) || defined(OBJ_ELF) + /* from "ldgp r1,n(r2)", generate "ldah r1,X(R2); lda r1,Y(r1)" + with appropriate constants and relocations. */ + struct alpha_insn insn; + expressionS newtok[3]; + expressionS addend; + + /* We're going to need this symbol in md_apply_fix(). */ + (void) section_symbol (absolute_section); + +#ifdef OBJ_ECOFF + if (regno (tok[2].X_add_number) == AXP_REG_PV) + ecoff_set_gp_prolog_size (0); +#endif + + newtok[0] = tok[0]; + set_tok_const (newtok[1], 0); + newtok[2] = tok[2]; + + assemble_tokens_to_insn ("ldah", newtok, 3, &insn); + + addend = tok[1]; + +#ifdef OBJ_ECOFF + assert (addend.X_op == O_constant); + addend.X_op = O_symbol; + addend.X_add_symbol = alpha_gp_symbol; +#endif + + insn.nfixups = 1; + insn.fixups[0].exp = addend; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16; + + emit_insn (&insn); + + set_tok_preg (newtok[2], tok[0].X_add_number); + + assemble_tokens_to_insn ("lda", newtok, 3, &insn); + +#ifdef OBJ_ECOFF + addend.X_add_number += 4; +#endif + + insn.nfixups = 1; + insn.fixups[0].exp = addend; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16; + + emit_insn (&insn); +#endif /* OBJ_ECOFF || OBJ_ELF */ +} + +#ifdef OBJ_EVAX + +/* Add symbol+addend to link pool. + Return offset from basesym to entry in link pool. + + Add new fixup only if offset isn't 16bit. */ + +valueT +add_to_link_pool (basesym, sym, addend) + symbolS *basesym; + symbolS *sym; + offsetT addend; +{ + segT current_section = now_seg; + int current_subsec = now_subseg; + valueT offset; + bfd_reloc_code_real_type reloc_type; + char *p; + segment_info_type *seginfo = seg_info (alpha_link_section); + fixS *fixp; + + offset = -basesym->sy_obj; + + /* @@ This assumes all entries in a given section will be of the same + size... Probably correct, but unwise to rely on. */ + /* This must always be called with the same subsegment. */ + + if (seginfo->frchainP) + for (fixp = seginfo->frchainP->fix_root; + fixp != (fixS *) NULL; + fixp = fixp->fx_next, offset += 8) + { + if (fixp->fx_addsy == sym && fixp->fx_offset == addend) + { + if (range_signed_16 (offset)) + { + return offset; + } + } + } + + /* Not found in 16bit signed range. */ + + subseg_set (alpha_link_section, 0); + p = frag_more (8); + memset (p, 0, 8); + + fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, + BFD_RELOC_64); + + subseg_set (current_section, current_subsec); + seginfo->literal_pool_size += 8; + return offset; +} + +#endif /* OBJ_EVAX */ + +/* Load a (partial) expression into a target register. + + If poffset is not null, after the call it will either contain + O_constant 0, or a 16-bit offset appropriate for any MEM format + instruction. In addition, pbasereg will be modified to point to + the base register to use in that MEM format instruction. + + In any case, *pbasereg should contain a base register to add to the + expression. This will normally be either AXP_REG_ZERO or + alpha_gp_register. Symbol addresses will always be loaded via $gp, + so "foo($0)" is interpreted as adding the address of foo to $0; + i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ". Odd, perhaps, + but this is what OSF/1 does. + + Finally, the return value is true if the calling macro may emit a + LITUSE reloc if otherwise appropriate. */ + +static int +load_expression (targreg, exp, pbasereg, poffset) + int targreg; + const expressionS *exp; + int *pbasereg; + expressionS *poffset; +{ + int emit_lituse = 0; + offsetT addend = exp->X_add_number; + int basereg = *pbasereg; + struct alpha_insn insn; + expressionS newtok[3]; + + switch (exp->X_op) + { + case O_symbol: + { +#ifdef OBJ_ECOFF + offsetT lit; + + /* attempt to reduce .lit load by splitting the offset from + its symbol when possible, but don't create a situation in + which we'd fail. */ + if (!range_signed_32 (addend) && + (alpha_noat_on || targreg == AXP_REG_AT)) + { + lit = add_to_literal_pool (exp->X_add_symbol, addend, + alpha_lita_section, 8); + addend = 0; + } + else + { + lit = add_to_literal_pool (exp->X_add_symbol, 0, + alpha_lita_section, 8); + } + + if (lit >= 0x8000) + as_fatal ("overflow in literal (.lita) table"); + + /* emit "ldq r, lit(gp)" */ + + if (basereg != alpha_gp_register && targreg == basereg) + { + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + if (targreg == AXP_REG_AT) + as_bad ("macro requires $at while $at in use"); + + set_tok_reg (newtok[0], AXP_REG_AT); + } + else + set_tok_reg (newtok[0], targreg); + set_tok_sym (newtok[1], alpha_lita_symbol, lit); + set_tok_preg (newtok[2], alpha_gp_register); + + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + + assert (insn.nfixups == 1); + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; +#endif /* OBJ_ECOFF */ +#ifdef OBJ_ELF + /* emit "ldq r, gotoff(gp)" */ + + if (basereg != alpha_gp_register && targreg == basereg) + { + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + if (targreg == AXP_REG_AT) + as_bad ("macro requires $at while $at in use"); + + set_tok_reg (newtok[0], AXP_REG_AT); + } + else + set_tok_reg (newtok[0], targreg); + + if (!range_signed_32 (addend) + && (alpha_noat_on || targreg == AXP_REG_AT)) + { + newtok[1] = *exp; + addend = 0; + } + else + { + set_tok_sym (newtok[1], exp->X_add_symbol, 0); + } + + set_tok_preg (newtok[2], alpha_gp_register); + + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + + assert (insn.nfixups == 1); + insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; +#endif /* OBJ_ELF */ +#ifdef OBJ_EVAX + offsetT link; + + if (alpha_basereg_clobbered) + { + /* no basereg, reload basreg from 0(FP). */ + set_tok_reg (newtok[0], targreg); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_FP); + basereg = targreg; + assemble_tokens ("ldq", newtok, 3, 0); + } + + /* Find symbol or symbol pointer in link section. */ + + if (exp->X_add_symbol == alpha_evax_proc.symbol) + { + if (range_signed_16 (addend)) + { + set_tok_reg (newtok[0], targreg); + set_tok_const (newtok[1], addend); + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("lda", newtok, 3, &insn); + addend = 0; + } + else + { + set_tok_reg (newtok[0], targreg); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("lda", newtok, 3, &insn); + } + } + else + { + if (!range_signed_32 (addend)) + { + link = add_to_link_pool (alpha_evax_proc.symbol, + exp->X_add_symbol, addend); + addend = 0; + } + else + { + link = add_to_link_pool (alpha_evax_proc.symbol, + exp->X_add_symbol, 0); + } + set_tok_reg (newtok[0], targreg); + set_tok_const (newtok[1], link); + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + } +#endif /* OBJ_EVAX */ + + emit_insn(&insn); + +#ifndef OBJ_EVAX + emit_lituse = 1; + + if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO) + { + /* emit "addq r, base, r" */ + + set_tok_reg (newtok[1], basereg); + set_tok_reg (newtok[2], targreg); + assemble_tokens ("addq", newtok, 3, 0); + } +#endif + + basereg = targreg; + } + break; + + case O_constant: + break; + + case O_subtract: + /* Assume that this difference expression will be resolved to an + absolute value and that that value will fit in 16 bits. */ + + set_tok_reg (newtok[0], targreg); + newtok[1] = *exp; + set_tok_preg (newtok[2], basereg); + assemble_tokens ("lda", newtok, 3, 0); + + if (poffset) + set_tok_const (*poffset, 0); + return 0; + + default: + abort(); + } + + if (!range_signed_32 (addend)) + { + offsetT lit; + + /* for 64-bit addends, just put it in the literal pool */ + +#ifdef OBJ_EVAX + /* emit "ldq targreg, lit(basereg)" */ + lit = add_to_link_pool (alpha_evax_proc.symbol, + section_symbol (absolute_section), addend); + set_tok_reg (newtok[0], targreg); + set_tok_const (newtok[1], lit); + set_tok_preg (newtok[2], alpha_gp_register); + assemble_tokens ("ldq", newtok, 3, 0); +#else + + if (alpha_lit8_section == NULL) + { + create_literal_section (".lit8", + &alpha_lit8_section, + &alpha_lit8_symbol); + +#ifdef OBJ_ECOFF + alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000, + alpha_lita_section, 8); + if (alpha_lit8_literal >= 0x8000) + as_fatal ("overflow in literal (.lita) table"); +#endif + } + + lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000; + if (lit >= 0x8000) + as_fatal ("overflow in literal (.lit8) table"); + + /* emit "lda litreg, .lit8+0x8000" */ + + if (targreg == basereg) + { + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + if (targreg == AXP_REG_AT) + as_bad ("macro requires $at while $at in use"); + + set_tok_reg (newtok[0], AXP_REG_AT); + } + else + set_tok_reg (newtok[0], targreg); +#ifdef OBJ_ECOFF + set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal); +#endif +#ifdef OBJ_ELF + set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000); +#endif + set_tok_preg (newtok[2], alpha_gp_register); + + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + + assert (insn.nfixups == 1); +#ifdef OBJ_ECOFF + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; +#endif +#ifdef OBJ_ELF + insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; +#endif + + emit_insn (&insn); + + /* emit "ldq litreg, lit(litreg)" */ + + set_tok_const (newtok[1], lit); + set_tok_preg (newtok[2], newtok[0].X_add_number); + + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + + assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + insn.nfixups++; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; + insn.fixups[0].exp.X_op = O_constant; + insn.fixups[0].exp.X_add_number = 1; + emit_lituse = 0; + + emit_insn (&insn); + + /* emit "addq litreg, base, target" */ + + if (basereg != AXP_REG_ZERO) + { + set_tok_reg (newtok[1], basereg); + set_tok_reg (newtok[2], targreg); + assemble_tokens ("addq", newtok, 3, 0); + } +#endif /* !OBJ_EVAX */ + + if (poffset) + set_tok_const (*poffset, 0); + *pbasereg = targreg; + } + else + { + offsetT low, high, extra, tmp; + + /* for 32-bit operands, break up the addend */ + + low = sign_extend_16 (addend); + tmp = addend - low; + high = sign_extend_16 (tmp >> 16); + + if (tmp - (high << 16)) + { + extra = 0x4000; + tmp -= 0x40000000; + high = sign_extend_16 (tmp >> 16); + } + else + extra = 0; + + set_tok_reg (newtok[0], targreg); + set_tok_preg (newtok[2], basereg); + + if (extra) + { + /* emit "ldah r, extra(r) */ + set_tok_const (newtok[1], extra); + assemble_tokens ("ldah", newtok, 3, 0); + set_tok_preg (newtok[2], basereg = targreg); + } + + if (high) + { + /* emit "ldah r, high(r) */ + set_tok_const (newtok[1], high); + assemble_tokens ("ldah", newtok, 3, 0); + basereg = targreg; + set_tok_preg (newtok[2], basereg); + } + + if ((low && !poffset) || (!poffset && basereg != targreg)) + { + /* emit "lda r, low(base)" */ + set_tok_const (newtok[1], low); + assemble_tokens ("lda", newtok, 3, 0); + basereg = targreg; + low = 0; + } + + if (poffset) + set_tok_const (*poffset, low); + *pbasereg = basereg; + } + + return emit_lituse; +} + +/* The lda macro differs from the lda instruction in that it handles + most simple expressions, particualrly symbol address loads and + large constants. */ + +static void +emit_lda (tok, ntok, unused) + const expressionS *tok; + int ntok; + const PTR unused; +{ + int basereg; + + if (ntok == 2) + basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); + else + basereg = tok[2].X_add_number; + + (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL); +} + +/* The ldah macro differs from the ldah instruction in that it has $31 + as an implied base register. */ + +static void +emit_ldah (tok, ntok, unused) + const expressionS *tok; + int ntok; + const PTR unused; +{ + expressionS newtok[3]; + + newtok[0] = tok[0]; + newtok[1] = tok[1]; + set_tok_preg (newtok[2], AXP_REG_ZERO); + + assemble_tokens ("ldah", newtok, 3, 0); +} + +/* Handle all "simple" integer register loads -- ldq, ldq_l, ldq_u, + etc. They differ from the real instructions in that they do simple + expressions like the lda macro. */ + +static void +emit_ir_load (tok, ntok, opname) + const expressionS *tok; + int ntok; + const PTR opname; +{ + int basereg, lituse; + expressionS newtok[3]; + struct alpha_insn insn; + + if (ntok == 2) + basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); + else + basereg = tok[2].X_add_number; + + lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg, + &newtok[1]); + + newtok[0] = tok[0]; + set_tok_preg (newtok[2], basereg); + + assemble_tokens_to_insn ((const char *)opname, newtok, 3, &insn); + + if (lituse) + { + assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + insn.nfixups++; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; + insn.fixups[0].exp.X_op = O_constant; + insn.fixups[0].exp.X_add_number = 1; + } + + emit_insn (&insn); +#ifdef OBJ_EVAX + /* special hack. If the basereg is clobbered for a call + all lda's before the call don't have a basereg. */ + if ((tok[0].X_op == O_register) + && (tok[0].X_add_number == alpha_gp_register)) + { + alpha_basereg_clobbered = 1; + } +#endif +} + +/* Handle fp register loads, and both integer and fp register stores. + Again, we handle simple expressions. */ + +static void +emit_loadstore (tok, ntok, opname) + const expressionS *tok; + int ntok; + const PTR opname; +{ + int basereg, lituse; + expressionS newtok[3]; + struct alpha_insn insn; + + if (ntok == 2) + basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); + else + basereg = tok[2].X_add_number; + + if (tok[1].X_op != O_constant || !range_signed_16(tok[1].X_add_number)) + { + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]); + } + else + { + newtok[1] = tok[1]; + lituse = 0; + } + + newtok[0] = tok[0]; + set_tok_preg (newtok[2], basereg); + + assemble_tokens_to_insn ((const char *)opname, newtok, 3, &insn); + + if (lituse) + { + assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + insn.nfixups++; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; + insn.fixups[0].exp.X_op = O_constant; + insn.fixups[0].exp.X_add_number = 1; + } + + emit_insn (&insn); +} + +/* Load a half-word or byte as an unsigned value. */ + +static void +emit_ldXu (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + if (alpha_target & AXP_OPCODE_BWX) + emit_ir_load (tok, ntok, ldXu_op[(long)vlgsize]); + else + { + expressionS newtok[3]; + + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + + /* emit "lda $at, exp" */ + + memcpy (newtok, tok, sizeof (expressionS) * ntok); + newtok[0].X_add_number = AXP_REG_AT; + assemble_tokens ("lda", newtok, ntok, 1); + + /* emit "ldq_u targ, 0($at)" */ + + newtok[0] = tok[0]; + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "extXl targ, $at, targ" */ + + set_tok_reg (newtok[1], AXP_REG_AT); + newtok[2] = newtok[0]; + assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1); + } +} + +/* Load a half-word or byte as a signed value. */ + +static void +emit_ldX (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + emit_ldXu (tok, ntok, vlgsize); + assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1); +} + +/* Load an integral value from an unaligned address as an unsigned + value. */ + +static void +emit_uldXu (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + long lgsize = (long)vlgsize; + expressionS newtok[3]; + + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + + /* emit "lda $at, exp" */ + + memcpy (newtok, tok, sizeof (expressionS) * ntok); + newtok[0].X_add_number = AXP_REG_AT; + assemble_tokens ("lda", newtok, ntok, 1); + + /* emit "ldq_u $t9, 0($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "ldq_u $t10, size-1($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_const (newtok[1], (1<<lgsize)-1); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "extXl $t9, $at, $t9" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_reg (newtok[1], AXP_REG_AT); + set_tok_reg (newtok[2], AXP_REG_T9); + assemble_tokens (extXl_op[lgsize], newtok, 3, 1); + + /* emit "extXh $t10, $at, $t10" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_reg (newtok[2], AXP_REG_T10); + assemble_tokens (extXh_op[lgsize], newtok, 3, 1); + + /* emit "or $t9, $t10, targ" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_reg (newtok[1], AXP_REG_T10); + newtok[2] = tok[0]; + assemble_tokens ("or", newtok, 3, 1); +} + +/* Load an integral value from an unaligned address as a signed value. + Note that quads should get funneled to the unsigned load since we + don't have to do the sign extension. */ + +static void +emit_uldX (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + emit_uldXu (tok, ntok, vlgsize); + assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1); +} + +/* Implement the ldil macro. */ + +static void +emit_ldil (tok, ntok, unused) + const expressionS *tok; + int ntok; + const PTR unused; +{ + expressionS newtok[2]; + + memcpy (newtok, tok, sizeof(newtok)); + newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number); + + assemble_tokens ("lda", newtok, ntok, 1); +} + +/* Store a half-word or byte. */ + +static void +emit_stX (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + int lgsize = (int)(long)vlgsize; + + if (alpha_target & AXP_OPCODE_BWX) + emit_loadstore (tok, ntok, stX_op[lgsize]); + else + { + expressionS newtok[3]; + + if (alpha_noat_on) + as_bad("macro requires $at register while noat in effect"); + + /* emit "lda $at, exp" */ + + memcpy (newtok, tok, sizeof (expressionS) * ntok); + newtok[0].X_add_number = AXP_REG_AT; + assemble_tokens ("lda", newtok, ntok, 1); + + /* emit "ldq_u $t9, 0($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "insXl src, $at, $t10" */ + + newtok[0] = tok[0]; + set_tok_reg (newtok[1], AXP_REG_AT); + set_tok_reg (newtok[2], AXP_REG_T10); + assemble_tokens (insXl_op[lgsize], newtok, 3, 1); + + /* emit "mskXl $t9, $at, $t9" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + newtok[2] = newtok[0]; + assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); + + /* emit "or $t9, $t10, $t9" */ + + set_tok_reg (newtok[1], AXP_REG_T10); + assemble_tokens ("or", newtok, 3, 1); + + /* emit "stq_u $t9, 0($at) */ + + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("stq_u", newtok, 3, 1); + } +} + +/* Store an integer to an unaligned address. */ + +static void +emit_ustX (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + int lgsize = (int)(long)vlgsize; + expressionS newtok[3]; + + /* emit "lda $at, exp" */ + + memcpy (newtok, tok, sizeof (expressionS) * ntok); + newtok[0].X_add_number = AXP_REG_AT; + assemble_tokens ("lda", newtok, ntok, 1); + + /* emit "ldq_u $9, 0($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "ldq_u $10, size-1($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_const (newtok[1], (1 << lgsize)-1); + assemble_tokens ("ldq_u", newtok, 3, 1); + + /* emit "insXl src, $at, $t11" */ + + newtok[0] = tok[0]; + set_tok_reg (newtok[1], AXP_REG_AT); + set_tok_reg (newtok[2], AXP_REG_T11); + assemble_tokens (insXl_op[lgsize], newtok, 3, 1); + + /* emit "insXh src, $at, $t12" */ + + set_tok_reg (newtok[2], AXP_REG_T12); + assemble_tokens (insXh_op[lgsize], newtok, 3, 1); + + /* emit "mskXl $t9, $at, $t9" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + newtok[2] = newtok[0]; + assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); + + /* emit "mskXh $t10, $at, $t10" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + newtok[2] = newtok[0]; + assemble_tokens (mskXh_op[lgsize], newtok, 3, 1); + + /* emit "or $t9, $t11, $t9" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_reg (newtok[1], AXP_REG_T11); + newtok[2] = newtok[0]; + assemble_tokens ("or", newtok, 3, 1); + + /* emit "or $t10, $t12, $t10" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_reg (newtok[1], AXP_REG_T12); + newtok[2] = newtok[0]; + assemble_tokens ("or", newtok, 3, 1); + + /* emit "stq_u $t9, 0($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_AT); + assemble_tokens ("stq_u", newtok, 3, 1); + + /* emit "stq_u $t10, size-1($at)" */ + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_const (newtok[1], (1 << lgsize)-1); + assemble_tokens ("stq_u", newtok, 3, 1); +} + +/* Sign extend a half-word or byte. The 32-bit sign extend is + implemented as "addl $31, $r, $t" in the opcode table. */ + +static void +emit_sextX (tok, ntok, vlgsize) + const expressionS *tok; + int ntok; + const PTR vlgsize; +{ + long lgsize = (long)vlgsize; + + if (alpha_target & AXP_OPCODE_BWX) + assemble_tokens (sextX_op[lgsize], tok, ntok, 0); + else + { + int bitshift = 64 - 8 * (1 << lgsize); + expressionS newtok[3]; + + /* emit "sll src,bits,dst" */ + + newtok[0] = tok[0]; + set_tok_const (newtok[1], bitshift); + newtok[2] = tok[ntok - 1]; + assemble_tokens ("sll", newtok, 3, 1); + + /* emit "sra dst,bits,dst" */ + + newtok[0] = newtok[2]; + assemble_tokens ("sra", newtok, 3, 1); + } +} + +/* Implement the division and modulus macros. */ + +#ifdef OBJ_EVAX + +/* Make register usage like in normal procedure call. + Don't clobber PV and RA. */ + +static void +emit_division (tok, ntok, symname) + const expressionS *tok; + int ntok; + const PTR symname; +{ + /* DIVISION and MODULUS. Yech. + * + * Convert + * OP x,y,result + * to + * mov x,R16 # if x != R16 + * mov y,R17 # if y != R17 + * lda AT,__OP + * jsr AT,(AT),0 + * mov R0,result + * + * with appropriate optimizations if R0,R16,R17 are the registers + * specified by the compiler. + */ + + int xr, yr, rr; + symbolS *sym; + expressionS newtok[3]; + + xr = regno (tok[0].X_add_number); + yr = regno (tok[1].X_add_number); + + if (ntok < 3) + rr = xr; + else + rr = regno (tok[2].X_add_number); + + /* Move the operands into the right place */ + if (yr == AXP_REG_R16 && xr == AXP_REG_R17) + { + /* They are in exactly the wrong order -- swap through AT */ + + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + + set_tok_reg (newtok[0], AXP_REG_R16); + set_tok_reg (newtok[1], AXP_REG_AT); + assemble_tokens ("mov", newtok, 2, 1); + + set_tok_reg (newtok[0], AXP_REG_R17); + set_tok_reg (newtok[1], AXP_REG_R16); + assemble_tokens ("mov", newtok, 2, 1); + + set_tok_reg (newtok[0], AXP_REG_AT); + set_tok_reg (newtok[1], AXP_REG_R17); + assemble_tokens ("mov", newtok, 2, 1); + } + else + { + if (yr == AXP_REG_R16) + { + set_tok_reg (newtok[0], AXP_REG_R16); + set_tok_reg (newtok[1], AXP_REG_R17); + assemble_tokens ("mov", newtok, 2, 1); + } + + if (xr != AXP_REG_R16) + { + set_tok_reg (newtok[0], xr); + set_tok_reg (newtok[1], AXP_REG_R16); + assemble_tokens ("mov", newtok, 2, 1); + } + + if (yr != AXP_REG_R16 && yr != AXP_REG_R17) + { + set_tok_reg (newtok[0], yr); + set_tok_reg (newtok[1], AXP_REG_R17); + assemble_tokens ("mov", newtok, 2, 1); + } + } + + sym = symbol_find_or_make ((const char *)symname); + + set_tok_reg (newtok[0], AXP_REG_AT); + set_tok_sym (newtok[1], sym, 0); + assemble_tokens ("lda", newtok, 2, 1); + + /* Call the division routine */ + set_tok_reg (newtok[0], AXP_REG_AT); + set_tok_cpreg (newtok[1], AXP_REG_AT); + set_tok_const (newtok[2], 0); + assemble_tokens ("jsr", newtok, 3, 1); + + /* Move the result to the right place */ + if (rr != AXP_REG_R0) + { + set_tok_reg (newtok[0], AXP_REG_R0); + set_tok_reg (newtok[1], rr); + assemble_tokens ("mov", newtok, 2, 1); + } +} + +#else /* !OBJ_EVAX */ + +static void +emit_division (tok, ntok, symname) + const expressionS *tok; + int ntok; + const PTR symname; +{ + /* DIVISION and MODULUS. Yech. + * Convert + * OP x,y,result + * to + * lda pv,__OP + * mov x,t10 + * mov y,t11 + * jsr t9,(pv),__OP + * mov t12,result + * + * with appropriate optimizations if t10,t11,t12 are the registers + * specified by the compiler. + */ + + int xr, yr, rr; + symbolS *sym; + expressionS newtok[3]; + + xr = regno (tok[0].X_add_number); + yr = regno (tok[1].X_add_number); + + if (ntok < 3) + rr = xr; + else + rr = regno (tok[2].X_add_number); + + sym = symbol_find_or_make ((const char *)symname); + + /* Move the operands into the right place */ + if (yr == AXP_REG_T10 && xr == AXP_REG_T11) + { + /* They are in exactly the wrong order -- swap through AT */ + + if (alpha_noat_on) + as_bad ("macro requires $at register while noat in effect"); + + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_reg (newtok[1], AXP_REG_AT); + assemble_tokens ("mov", newtok, 2, 1); + + set_tok_reg (newtok[0], AXP_REG_T11); + set_tok_reg (newtok[1], AXP_REG_T10); + assemble_tokens ("mov", newtok, 2, 1); + + set_tok_reg (newtok[0], AXP_REG_AT); + set_tok_reg (newtok[1], AXP_REG_T11); + assemble_tokens ("mov", newtok, 2, 1); + } + else + { + if (yr == AXP_REG_T10) + { + set_tok_reg (newtok[0], AXP_REG_T10); + set_tok_reg (newtok[1], AXP_REG_T11); + assemble_tokens ("mov", newtok, 2, 1); + } + + if (xr != AXP_REG_T10) + { + set_tok_reg (newtok[0], xr); + set_tok_reg (newtok[1], AXP_REG_T10); + assemble_tokens ("mov", newtok, 2, 1); + } + + if (yr != AXP_REG_T10 && yr != AXP_REG_T11) + { + set_tok_reg (newtok[0], yr); + set_tok_reg (newtok[1], AXP_REG_T11); + assemble_tokens ("mov", newtok, 2, 1); + } + } + + /* Call the division routine */ + set_tok_reg (newtok[0], AXP_REG_T9); + set_tok_sym (newtok[1], sym, 0); + assemble_tokens ("jsr", newtok, 2, 1); + + /* Reload the GP register */ +#ifdef OBJ_AOUT +FIXME +#endif +#if defined(OBJ_ECOFF) || defined(OBJ_ELF) + set_tok_reg (newtok[0], alpha_gp_register); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_T9); + assemble_tokens ("ldgp", newtok, 3, 1); +#endif + + /* Move the result to the right place */ + if (rr != AXP_REG_T12) + { + set_tok_reg (newtok[0], AXP_REG_T12); + set_tok_reg (newtok[1], rr); + assemble_tokens ("mov", newtok, 2, 1); + } +} + +#endif /* !OBJ_EVAX */ + +/* The jsr and jmp macros differ from their instruction counterparts + in that they can load the target address and default most + everything. */ + +static void +emit_jsrjmp (tok, ntok, vopname) + const expressionS *tok; + int ntok; + const PTR vopname; +{ + const char *opname = (const char *) vopname; + struct alpha_insn insn; + expressionS newtok[3]; + int r, tokidx = 0, lituse = 0; + + if (tokidx < ntok && tok[tokidx].X_op == O_register) + r = regno (tok[tokidx++].X_add_number); + else + r = strcmp (opname, "jmp") == 0 ? AXP_REG_ZERO : AXP_REG_RA; + + set_tok_reg (newtok[0], r); + + if (tokidx < ntok && + (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) + r = regno (tok[tokidx++].X_add_number); +#ifdef OBJ_EVAX + /* keep register if jsr $n.<sym> */ +#else + else + { + int basereg = alpha_gp_register; + lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL); + } +#endif + + set_tok_cpreg (newtok[1], r); + +#ifdef OBJ_EVAX + /* FIXME: Add hint relocs to BFD for evax. */ +#else + if (tokidx < ntok) + newtok[2] = tok[tokidx]; + else +#endif + set_tok_const (newtok[2], 0); + + assemble_tokens_to_insn (opname, newtok, 3, &insn); + + /* add the LITUSE fixup */ + if (lituse) + { + assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + insn.nfixups++; + insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; + insn.fixups[0].exp.X_op = O_constant; + insn.fixups[0].exp.X_add_number = 3; + } + + emit_insn (&insn); + +#ifdef OBJ_EVAX + alpha_basereg_clobbered = 0; + + /* reload PV from 0(FP) if it is our current base register. */ + if (alpha_gp_register == AXP_REG_PV) + { + set_tok_reg (newtok[0], AXP_REG_PV); + set_tok_const (newtok[1], 0); + set_tok_preg (newtok[2], AXP_REG_FP); + assemble_tokens ("ldq", newtok, 3, 0); + } +#endif +} + +/* The ret and jcr instructions differ from their instruction + counterparts in that everything can be defaulted. */ + +static void +emit_retjcr (tok, ntok, vopname) + const expressionS *tok; + int ntok; + const PTR vopname; +{ + const char *opname = (const char *)vopname; + expressionS newtok[3]; + int r, tokidx = 0; + + if (tokidx < ntok && tok[tokidx].X_op == O_register) + r = regno (tok[tokidx++].X_add_number); + else + r = AXP_REG_ZERO; + + set_tok_reg (newtok[0], r); + + if (tokidx < ntok && + (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) + r = regno (tok[tokidx++].X_add_number); + else + r = AXP_REG_RA; + + set_tok_cpreg (newtok[1], r); + + if (tokidx < ntok) + newtok[2] = tok[tokidx]; + else + set_tok_const (newtok[2], strcmp(opname, "ret") == 0); + + assemble_tokens (opname, newtok, 3, 0); +} + +/* Assembler directives */ + +/* Handle the .text pseudo-op. This is like the usual one, but it + clears alpha_insn_label and restores auto alignment. */ + +static void +s_alpha_text (i) + int i; + +{ + s_text (i); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +/* Handle the .data pseudo-op. This is like the usual one, but it + clears alpha_insn_label and restores auto alignment. */ + +static void +s_alpha_data (i) + int i; +{ + s_data (i); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +#ifdef OBJ_ECOFF + +/* Handle the OSF/1 .comm pseudo quirks. */ + +static void +s_alpha_comm (ignore) + int ignore; +{ + register char *name; + register char c; + register char *p; + offsetT temp; + register symbolS *symbolP; + + name = input_line_pointer; + c = get_symbol_end (); + + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + + SKIP_WHITESPACE (); + + /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ + if (*input_line_pointer == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + } + if ((temp = get_absolute_expression ()) < 0) + { + as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); + ignore_rest_of_line (); + return; + } + + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + as_bad ("Ignoring attempt to re-define symbol"); + ignore_rest_of_line (); + return; + } + + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) temp) + as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) temp); + } + else + { + S_SET_VALUE (symbolP, (valueT) temp); + S_SET_EXTERNAL (symbolP); + } + + know (symbolP->sy_frag == &zero_address_frag); + + demand_empty_rest_of_line (); +} + +#endif /* ! OBJ_ELF */ + +#ifdef OBJ_ECOFF + +/* Handle the .rdata pseudo-op. This is like the usual one, but it + clears alpha_insn_label and restores auto alignment. */ + +static void +s_alpha_rdata (ignore) + int ignore; +{ + int temp; + + temp = get_absolute_expression (); + subseg_new (".rdata", 0); + demand_empty_rest_of_line (); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +#endif + +#ifdef OBJ_ECOFF + +/* Handle the .sdata pseudo-op. This is like the usual one, but it + clears alpha_insn_label and restores auto alignment. */ + +static void +s_alpha_sdata (ignore) + int ignore; +{ + int temp; + + temp = get_absolute_expression (); + subseg_new (".sdata", 0); + demand_empty_rest_of_line (); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} +#endif + +#ifdef OBJ_ELF + +/* Handle the .section pseudo-op. This is like the usual one, but it + clears alpha_insn_label and restores auto alignment. */ + +static void +s_alpha_section (ignore) + int ignore; +{ + obj_elf_section (ignore); + + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +#endif + +#ifdef OBJ_EVAX + +/* Handle the section specific pseudo-op. */ + +static void +s_alpha_section (secid) + int secid; +{ + int temp; +#define EVAX_SECTION_COUNT 6 + static char *section_name[EVAX_SECTION_COUNT+1] = + { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors", ".lcomm" }; + + if ((secid <= 0) || (secid > EVAX_SECTION_COUNT)) + { + as_fatal ("Unknown section directive"); + demand_empty_rest_of_line (); + return; + } + temp = get_absolute_expression (); + subseg_new (section_name[secid], 0); + demand_empty_rest_of_line (); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + + +/* .prologue */ + +static void +s_alpha_prologue (ignore) + int ignore; +{ + alpha_basereg_clobbered = 0; + demand_empty_rest_of_line (); + + return; +} + + +/* Parse .ent directives. */ + +static void +s_alpha_ent (ignore) + int ignore; +{ + symbolS *symbol; + expressionS symexpr; + + alpha_evax_proc.pdsckind = 0; + alpha_evax_proc.framereg = -1; + alpha_evax_proc.framesize = 0; + alpha_evax_proc.rsa_offset = 0; + alpha_evax_proc.ra_save = AXP_REG_RA; + alpha_evax_proc.fp_save = -1; + alpha_evax_proc.imask = 0; + alpha_evax_proc.fmask = 0; + alpha_evax_proc.prologue = 0; + alpha_evax_proc.type = 0; + + expression (&symexpr); + + if (symexpr.X_op != O_symbol) + { + as_fatal (".ent directive has no symbol"); + demand_empty_rest_of_line (); + return; + } + + symbol = make_expr_symbol (&symexpr); + symbol->bsym->flags |= BSF_FUNCTION; + alpha_evax_proc.symbol = symbol; + + demand_empty_rest_of_line (); + return; +} + + +/* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives. */ + +static void +s_alpha_frame (ignore) + int ignore; +{ + long val; + + alpha_evax_proc.framereg = tc_get_register (1); + + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',' + || get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .frame directive 1./2. param"); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + alpha_evax_proc.framesize = val; + + (void) tc_get_register (1); + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',') + { + as_warn ("Bad .frame directive 3./4. param"); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + alpha_evax_proc.rsa_offset = get_absolute_expression (); + + return; +} + +static void +s_alpha_pdesc (ignore) + int ignore; +{ + char *name; + char name_end; + long val; + register char *p; + expressionS exp; + symbolS *entry_sym; + fixS *fixp; + segment_info_type *seginfo = seg_info (alpha_link_section); + + if (now_seg != alpha_link_section) + { + as_bad (".pdesc directive not in link (.link) section"); + demand_empty_rest_of_line (); + return; + } + + if ((alpha_evax_proc.symbol == 0) + || (!S_IS_DEFINED (alpha_evax_proc.symbol))) + { + as_fatal (".pdesc has no matching .ent"); + demand_empty_rest_of_line (); + return; + } + + alpha_evax_proc.symbol->sy_obj = (valueT)seginfo->literal_pool_size; + + expression (&exp); + if (exp.X_op != O_symbol) + { + as_warn (".pdesc directive has no entry symbol"); + demand_empty_rest_of_line (); + return; + } + + entry_sym = make_expr_symbol (&exp); + /* Save bfd symbol of proc desc in function symbol. */ + alpha_evax_proc.symbol->bsym->udata.p = (PTR)entry_sym->bsym; + + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',') + { + as_warn ("No comma after .pdesc <entryname>"); + demand_empty_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + name = input_line_pointer; + name_end = get_symbol_end (); + + if (strncmp(name, "stack", 5) == 0) + { + alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK; + } + else if (strncmp(name, "reg", 3) == 0) + { + alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER; + } + else if (strncmp(name, "null", 4) == 0) + { + alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL; + } + else + { + as_fatal ("unknown procedure kind"); + demand_empty_rest_of_line (); + return; + } + + *input_line_pointer = name_end; + demand_empty_rest_of_line (); + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + frag_align (3, 0, 0); + p = frag_more (16); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); + fixp->fx_done = 1; + seginfo->literal_pool_size += 16; + + *p = alpha_evax_proc.pdsckind + | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0); + *(p+1) = PDSC_S_M_NATIVE + | PDSC_S_M_NO_JACKET; + + switch (alpha_evax_proc.pdsckind) + { + case PDSC_S_K_KIND_NULL: + *(p+2) = 0; + *(p+3) = 0; + break; + case PDSC_S_K_KIND_FP_REGISTER: + *(p+2) = alpha_evax_proc.fp_save; + *(p+3) = alpha_evax_proc.ra_save; + break; + case PDSC_S_K_KIND_FP_STACK: + md_number_to_chars (p+2, (valueT)alpha_evax_proc.rsa_offset, 2); + break; + default: /* impossible */ + break; + } + + *(p+4) = 0; + *(p+5) = alpha_evax_proc.type & 0x0f; + + /* Signature offset. */ + md_number_to_chars (p+6, (valueT)0, 2); + + fix_new_exp (frag_now, p-frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64); + + if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL) + return; + + /* Add dummy fix to make add_to_link_pool work. */ + p = frag_more (8); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); + fixp->fx_done = 1; + seginfo->literal_pool_size += 8; + + /* pdesc+16: Size. */ + md_number_to_chars (p, (valueT)alpha_evax_proc.framesize, 4); + + md_number_to_chars (p+4, (valueT)0, 2); + + /* Entry length. */ + md_number_to_chars (p+6, alpha_evax_proc.prologue, 2); + + if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER) + return; + + /* Add dummy fix to make add_to_link_pool work. */ + p = frag_more (8); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); + fixp->fx_done = 1; + seginfo->literal_pool_size += 8; + + /* pdesc+24: register masks. */ + + md_number_to_chars (p, alpha_evax_proc.imask, 4); + md_number_to_chars (p+4, alpha_evax_proc.fmask, 4); + + return; +} + + +/* Support for crash debug on vms. */ + +static void +s_alpha_name (ignore) + int ignore; +{ + register char *p; + expressionS exp; + segment_info_type *seginfo = seg_info (alpha_link_section); + + if (now_seg != alpha_link_section) + { + as_bad (".name directive not in link (.link) section"); + demand_empty_rest_of_line (); + return; + } + + expression (&exp); + if (exp.X_op != O_symbol) + { + as_warn (".name directive has no symbol"); + demand_empty_rest_of_line (); + return; + } + + demand_empty_rest_of_line (); + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + frag_align (3, 0, 0); + p = frag_more (8); + seginfo->literal_pool_size += 8; + + fix_new_exp (frag_now, p-frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64); + + return; +} + + +static void +s_alpha_linkage (ignore) + int ignore; +{ + expressionS exp; + char *p; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + expression (&exp); + if (exp.X_op != O_symbol) + { + as_fatal ("No symbol after .linkage"); + } + else + { + p = frag_more (LKP_S_K_SIZE); + memset (p, 0, LKP_S_K_SIZE); + fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\ + BFD_RELOC_ALPHA_LINKAGE); + } + demand_empty_rest_of_line (); + + return; +} + + +static void +s_alpha_code_address (ignore) + int ignore; +{ + expressionS exp; + char *p; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + expression (&exp); + if (exp.X_op != O_symbol) + { + as_fatal ("No symbol after .code_address"); + } + else + { + p = frag_more (8); + memset (p, 0, 8); + fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\ + BFD_RELOC_ALPHA_CODEADDR); + } + demand_empty_rest_of_line (); + + return; +} + + +static void +s_alpha_fp_save (ignore) + int ignore; +{ + + alpha_evax_proc.fp_save = tc_get_register (1); + + demand_empty_rest_of_line (); + return; +} + + +static void +s_alpha_mask (ignore) + int ignore; +{ + long val; + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .mask directive"); + --input_line_pointer; + } + else + { + alpha_evax_proc.imask = val; + (void)get_absolute_expression (); + } + demand_empty_rest_of_line (); + + return; +} + + +static void +s_alpha_fmask (ignore) + int ignore; +{ + long val; + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .fmask directive"); + --input_line_pointer; + } + else + { + alpha_evax_proc.fmask = val; + (void) get_absolute_expression (); + } + demand_empty_rest_of_line (); + + return; +} + +static void +s_alpha_end (ignore) + int ignore; +{ + char c; + + c = get_symbol_end (); + *input_line_pointer = c; + demand_empty_rest_of_line (); + alpha_evax_proc.symbol = 0; + alpha_basereg_clobbered = 0; + + return; +} + + +static void +s_alpha_file (ignore) + int ignore; +{ + symbolS *s; + int length; + static char case_hack[32]; + + extern char *demand_copy_string PARAMS ((int *lenP)); + + sprintf (case_hack, "<CASE:%01d%01d>", + alpha_flag_hash_long_names, alpha_flag_show_after_trunc); + + s = symbol_find_or_make (case_hack); + s->bsym->flags |= BSF_FILE; + + get_absolute_expression (); + s = symbol_find_or_make (demand_copy_string (&length)); + s->bsym->flags |= BSF_FILE; + demand_empty_rest_of_line (); + + return; +} +#endif /* OBJ_EVAX */ + +/* Handle the .gprel32 pseudo op. */ + +static void +s_alpha_gprel32 (ignore) + int ignore; +{ + expressionS e; + char *p; + + SKIP_WHITESPACE (); + expression (&e); + +#ifdef OBJ_ELF + switch (e.X_op) + { + case O_constant: + e.X_add_symbol = section_symbol(absolute_section); + e.X_op = O_symbol; + /* FALLTHRU */ + case O_symbol: + break; + default: + abort(); + } +#else +#ifdef OBJ_ECOFF + switch (e.X_op) + { + case O_constant: + e.X_add_symbol = section_symbol (absolute_section); + /* fall through */ + case O_symbol: + e.X_op = O_subtract; + e.X_op_symbol = alpha_gp_symbol; + break; + default: + abort (); + } +#endif +#endif + + if (alpha_auto_align_on && alpha_current_align < 2) + alpha_align (2, (char *) NULL, alpha_insn_label); + if (alpha_current_align > 2) + alpha_current_align = 2; + alpha_insn_label = NULL; + + p = frag_more (4); + memset (p, 0, 4); + fix_new_exp (frag_now, p-frag_now->fr_literal, 4, + &e, 0, BFD_RELOC_GPREL32); +} + +/* Handle floating point allocation pseudo-ops. This is like the + generic vresion, but it makes sure the current label, if any, is + correctly aligned. */ + +static void +s_alpha_float_cons (type) + int type; +{ + int log_size; + + switch (type) + { + default: + case 'f': + case 'F': + log_size = 2; + break; + + case 'd': + case 'D': + case 'G': + log_size = 3; + break; + + case 'x': + case 'X': + case 'p': + case 'P': + log_size = 4; + break; + } + + if (alpha_auto_align_on && alpha_current_align < log_size) + alpha_align (log_size, (char *) NULL, alpha_insn_label); + if (alpha_current_align > log_size) + alpha_current_align = log_size; + alpha_insn_label = NULL; + + float_cons (type); +} + +/* Handle the .proc pseudo op. We don't really do much with it except + parse it. */ + +static void +s_alpha_proc (is_static) + int is_static; +{ + char *name; + char c; + char *p; + symbolS *symbolP; + int temp; + + /* Takes ".proc name,nargs" */ + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + symbolP = symbol_find_or_make (name); + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_warn ("Expected comma after name \"%s\"", name); + *p = c; + temp = 0; + ignore_rest_of_line (); + } + else + { + input_line_pointer++; + temp = get_absolute_expression (); + } + /* symbolP->sy_other = (signed char) temp; */ + as_warn ("unhandled: .proc %s,%d", name, temp); + demand_empty_rest_of_line (); +} + +/* Handle the .set pseudo op. This is used to turn on and off most of + the assembler features. */ + +static void +s_alpha_set (x) + int x; +{ + char *name = input_line_pointer, ch, *s; + int yesno = 1; + + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + input_line_pointer++; + ch = *input_line_pointer; + *input_line_pointer = '\0'; + + s = name; + if (s[0] == 'n' && s[1] == 'o') + { + yesno = 0; + s += 2; + } + if (!strcmp ("reorder", s)) + /* ignore */ ; + else if (!strcmp ("at", s)) + alpha_noat_on = !yesno; + else if (!strcmp ("macro", s)) + alpha_macros_on = yesno; + else if (!strcmp ("move", s)) + /* ignore */ ; + else if (!strcmp ("volatile", s)) + /* ignore */ ; + else + as_warn ("Tried to .set unrecognized mode `%s'", name); + + *input_line_pointer = ch; + demand_empty_rest_of_line (); +} + +/* Handle the .base pseudo op. This changes the assembler's notion of + the $gp register. */ + +static void +s_alpha_base (ignore) + int ignore; +{ +#if 0 + if (first_32bit_quadrant) + { + /* not fatal, but it might not work in the end */ + as_warn ("File overrides no-base-register option."); + first_32bit_quadrant = 0; + } +#endif + + SKIP_WHITESPACE (); + if (*input_line_pointer == '$') + { /* $rNN form */ + input_line_pointer++; + if (*input_line_pointer == 'r') + input_line_pointer++; + } + + alpha_gp_register = get_absolute_expression (); + if (alpha_gp_register < 0 || alpha_gp_register > 31) + { + alpha_gp_register = AXP_REG_GP; + as_warn ("Bad base register, using $%d.", alpha_gp_register); + } + + demand_empty_rest_of_line (); +} + +/* Handle the .align pseudo-op. This aligns to a power of two. It + also adjusts any current instruction label. We treat this the same + way the MIPS port does: .align 0 turns off auto alignment. */ + +static void +s_alpha_align (ignore) + int ignore; +{ + int align; + char fill, *pfill; + long max_alignment = 15; + + align = get_absolute_expression (); + if (align > max_alignment) + { + align = max_alignment; + as_bad ("Alignment too large: %d. assumed", align); + } + else if (align < 0) + { + as_warn ("Alignment negative: 0 assumed"); + align = 0; + } + + if (*input_line_pointer == ',') + { + input_line_pointer++; + fill = get_absolute_expression (); + pfill = &fill; + } + else + pfill = NULL; + + if (align != 0) + { + alpha_auto_align_on = 1; + alpha_align (align, pfill, alpha_insn_label); + } + else + { + alpha_auto_align_on = 0; + } + + demand_empty_rest_of_line (); +} + +/* Hook the normal string processor to reset known alignment. */ + +static void +s_alpha_stringer (terminate) + int terminate; +{ + alpha_current_align = 0; + alpha_insn_label = NULL; + stringer (terminate); +} + +/* Hook the normal space processing to reset known alignment. */ + +static void +s_alpha_space (ignore) + int ignore; +{ + alpha_current_align = 0; + alpha_insn_label = NULL; + s_space (ignore); +} + +/* Hook into cons for auto-alignment. */ + +void +alpha_cons_align (size) + int size; +{ + int log_size; + + log_size = 0; + while ((size >>= 1) != 0) + ++log_size; + + if (alpha_auto_align_on && alpha_current_align < log_size) + alpha_align (log_size, (char *) NULL, alpha_insn_label); + if (alpha_current_align > log_size) + alpha_current_align = log_size; + alpha_insn_label = NULL; +} + + +#ifdef DEBUG1 +/* print token expression with alpha specific extension. */ + +static void +alpha_print_token(f, exp) + FILE *f; + const expressionS *exp; +{ + switch (exp->X_op) + { + case O_cpregister: + putc (',', f); + /* FALLTHRU */ + case O_pregister: + putc ('(', f); + { + expressionS nexp = *exp; + nexp.X_op = O_register; + print_expr (f, &nexp); + } + putc (')', f); + break; + default: + print_expr (f, exp); + break; + } + return; +} +#endif + +/* The target specific pseudo-ops which we support. */ + +const pseudo_typeS md_pseudo_table[] = +{ + {"common", s_comm, 0}, /* is this used? */ +#ifdef OBJ_ECOFF + {"comm", s_alpha_comm, 0}, /* osf1 compiler does this */ + {"rdata", s_alpha_rdata, 0}, +#endif + {"text", s_alpha_text, 0}, + {"data", s_alpha_data, 0}, +#ifdef OBJ_ECOFF + {"sdata", s_alpha_sdata, 0}, +#endif +#ifdef OBJ_ELF + {"section", s_alpha_section, 0}, + {"section.s", s_alpha_section, 0}, + {"sect", s_alpha_section, 0}, + {"sect.s", s_alpha_section, 0}, +#endif +#ifdef OBJ_EVAX + { "pdesc", s_alpha_pdesc, 0}, + { "name", s_alpha_name, 0}, + { "linkage", s_alpha_linkage, 0}, + { "code_address", s_alpha_code_address, 0}, + { "ent", s_alpha_ent, 0}, + { "frame", s_alpha_frame, 0}, + { "fp_save", s_alpha_fp_save, 0}, + { "mask", s_alpha_mask, 0}, + { "fmask", s_alpha_fmask, 0}, + { "end", s_alpha_end, 0}, + { "file", s_alpha_file, 0}, + { "rdata", s_alpha_section, 1}, + { "comm", s_alpha_section, 2}, + { "link", s_alpha_section, 3}, + { "ctors", s_alpha_section, 4}, + { "dtors", s_alpha_section, 5}, + { "lcomm", s_alpha_section, 6}, +#endif + {"gprel32", s_alpha_gprel32, 0}, + {"t_floating", s_alpha_float_cons, 'd'}, + {"s_floating", s_alpha_float_cons, 'f'}, + {"f_floating", s_alpha_float_cons, 'F'}, + {"g_floating", s_alpha_float_cons, 'G'}, + {"d_floating", s_alpha_float_cons, 'D'}, + + {"proc", s_alpha_proc, 0}, + {"aproc", s_alpha_proc, 1}, + {"set", s_alpha_set, 0}, + {"reguse", s_ignore, 0}, + {"livereg", s_ignore, 0}, + {"base", s_alpha_base, 0}, /*??*/ + {"option", s_ignore, 0}, + {"prologue", s_ignore, 0}, + {"aent", s_ignore, 0}, + {"ugen", s_ignore, 0}, + {"eflag", s_ignore, 0}, + + {"align", s_alpha_align, 0}, + {"double", s_alpha_float_cons, 'd'}, + {"float", s_alpha_float_cons, 'f'}, + {"single", s_alpha_float_cons, 'f'}, + {"ascii", s_alpha_stringer, 0}, + {"asciz", s_alpha_stringer, 1}, + {"string", s_alpha_stringer, 1}, + {"space", s_alpha_space, 0}, + {"skip", s_alpha_space, 0}, + {"zero", s_alpha_space, 0}, + +/* We don't do any optimizing, so we can safely ignore these. */ + {"noalias", s_ignore, 0}, + {"alias", s_ignore, 0}, + + {NULL, 0, 0}, +}; + + +/* Build a BFD section with its flags set appropriately for the .lita, + .lit8, or .lit4 sections. */ + +static void +create_literal_section (name, secp, symp) + const char *name; + segT *secp; + symbolS **symp; +{ + segT current_section = now_seg; + int current_subsec = now_subseg; + segT new_sec; + + *secp = new_sec = subseg_new (name, 0); + subseg_set (current_section, current_subsec); + bfd_set_section_alignment (stdoutput, new_sec, 4); + bfd_set_section_flags (stdoutput, new_sec, + SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_DATA); + + S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec)); +} + +#ifdef OBJ_ECOFF + +/* @@@ GP selection voodoo. All of this seems overly complicated and + unnecessary; which is the primary reason it's for ECOFF only. */ + +static inline void +maybe_set_gp (sec) + asection *sec; +{ + bfd_vma vma; + if (!sec) + return; + vma = bfd_get_section_vma (foo, sec); + if (vma && vma < alpha_gp_value) + alpha_gp_value = vma; +} + +static void +select_gp_value () +{ + assert (alpha_gp_value == 0); + + /* Get minus-one in whatever width... */ + alpha_gp_value = 0; alpha_gp_value--; + + /* Select the smallest VMA of these existing sections. */ + maybe_set_gp (alpha_lita_section); +#if 0 + /* These were disabled before -- should we use them? */ + maybe_set_gp (sdata); + maybe_set_gp (lit8_sec); + maybe_set_gp (lit4_sec); +#endif + +/* @@ Will a simple 0x8000 work here? If not, why not? */ +#define GP_ADJUSTMENT (0x8000 - 0x10) + + alpha_gp_value += GP_ADJUSTMENT; + + S_SET_VALUE (alpha_gp_symbol, alpha_gp_value); + +#ifdef DEBUG1 + printf ("Chose GP value of %lx\n", alpha_gp_value); +#endif +} +#endif /* OBJ_ECOFF */ + +/* Called internally to handle all alignment needs. This takes care + of eliding calls to frag_align if'n the cached current alignment + says we've already got it, as well as taking care of the auto-align + feature wrt labels. */ + +static void +alpha_align (n, pfill, label) + int n; + char *pfill; + symbolS *label; +{ + if (alpha_current_align >= n) + return; + + if (pfill == NULL) + { + if (n > 2 + && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) + { + static char const nop[4] = { 0x1f, 0x04, 0xff, 0x47 }; + + /* First, make sure we're on a four-byte boundary, in case + someone has been putting .byte values into the text + section. The DEC assembler silently fills with unaligned + no-op instructions. This will zero-fill, then nop-fill + with proper alignment. */ + if (alpha_current_align < 2) + frag_align (2, 0, 0); + frag_align_pattern (n, nop, sizeof nop, 0); + } + else + frag_align (n, 0, 0); + } + else + frag_align (n, *pfill, 0); + + alpha_current_align = n; + + if (label != NULL) + { + assert (S_GET_SEGMENT (label) == now_seg); + label->sy_frag = frag_now; + S_SET_VALUE (label, (valueT) frag_now_fix ()); + } + + record_alignment(now_seg, n); +} + +/* The Alpha has support for some VAX floating point types, as well as for + IEEE floating point. We consider IEEE to be the primary floating point + format, and sneak in the VAX floating point support here. */ +#define md_atof vax_md_atof +#include "config/atof-vax.c" diff --git a/contrib/binutils/gas/config/tc-alpha.h b/contrib/binutils/gas/config/tc-alpha.h new file mode 100644 index 0000000..af2ded6 --- /dev/null +++ b/contrib/binutils/gas/config/tc-alpha.h @@ -0,0 +1,84 @@ +/* This file is tc-alpha.h + Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + Written by Ken Raeburn <raeburn@cygnus.com>. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define TC_ALPHA + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#define TARGET_ARCH bfd_arch_alpha + +#define TARGET_FORMAT (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \ + ? "ecoff-littlealpha" \ + : OUTPUT_FLAVOR == bfd_target_elf_flavour \ + ? "elf64-alpha" \ + : OUTPUT_FLAVOR == bfd_target_evax_flavour \ + ? "evax-alpha" \ + : "unknown-format") + +#define NEED_LITERAL_POOL +#define TC_HANDLES_FX_DONE +#define REPEAT_CONS_EXPRESSIONS + +extern int alpha_force_relocation PARAMS ((struct fix *)); +extern int alpha_fix_adjustable PARAMS ((struct fix *)); + +extern unsigned long alpha_gprmask, alpha_fprmask; +extern valueT alpha_gp_value; + +#define TC_FORCE_RELOCATION(FIXP) alpha_force_relocation (FIXP) +#define tc_fix_adjustable(FIXP) alpha_fix_adjustable (FIXP) +#define RELOC_REQUIRES_SYMBOL + +#define md_convert_frag(b,s,f) as_fatal ("alpha convert_frag\n") +#define md_create_long_jump(p,f,t,fr,s) as_fatal("alpha_create_long_jump") +#define md_create_short_jump(p,f,t,fr,s) as_fatal("alpha_create_short_jump") +#define md_estimate_size_before_relax(f,s) \ + (as_fatal("estimate_size_before_relax called"),1) +#define md_operand(x) + +#ifdef OBJ_EVAX + +/* This field keeps the symbols position in the link section. */ +#define OBJ_SYMFIELD_TYPE valueT + +#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) \ + fix_new_exp (FRAG, OFF, (int)LEN, EXP, 0, \ + LEN == 2 ? BFD_RELOC_16 \ + : LEN == 4 ? BFD_RELOC_32 \ + : LEN == 8 ? BFD_RELOC_64 \ + : BFD_RELOC_ALPHA_LINKAGE); +#endif + +#define md_number_to_chars number_to_chars_littleendian + +extern int tc_get_register PARAMS ((int frame)); +extern void alpha_frob_ecoff_data PARAMS ((void)); + +#define tc_frob_label(sym) alpha_define_label (sym) +extern void alpha_define_label PARAMS ((struct symbol *)); + +#define md_cons_align(nbytes) alpha_cons_align (nbytes) +extern void alpha_cons_align PARAMS ((int)); + +#ifdef OBJ_ECOFF +#define tc_frob_file_before_adjust() alpha_frob_file_before_adjust () +extern void alpha_frob_file_before_adjust PARAMS ((void)); +#endif diff --git a/contrib/binutils/gas/config/tc-generic.c b/contrib/binutils/gas/config/tc-generic.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/binutils/gas/config/tc-generic.c diff --git a/contrib/binutils/gas/config/tc-generic.h b/contrib/binutils/gas/config/tc-generic.h new file mode 100644 index 0000000..72df020 --- /dev/null +++ b/contrib/binutils/gas/config/tc-generic.h @@ -0,0 +1,39 @@ +/* This file is tc-generic.h + + Copyright (C) 1987, 91, 92, 95, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * This file is tc-generic.h and is intended to be a template for target cpu + * specific header files. It is my intent that this file compile. It is also + * my intent that this file grow into something that can be used as both a + * template for porting, and a stub for testing. xoxorich. + */ + +#define TC_GENERIC 1 + +#define TARGET_BYTES_BIG_ENDIAN 0 + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of tc-generic.h */ diff --git a/contrib/binutils/gas/config/tc-i386.c b/contrib/binutils/gas/config/tc-i386.c new file mode 100644 index 0000000..3981a2d --- /dev/null +++ b/contrib/binutils/gas/config/tc-i386.c @@ -0,0 +1,3174 @@ +/* i386.c -- Assemble code for the Intel 80386 + Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + Bugs & suggestions are completely welcome. This is free software. + Please help us make it better. + */ + +#include <ctype.h> + +#include "as.h" +#include "subsegs.h" + +#include "obstack.h" +#include "opcode/i386.h" + +#ifndef TC_RELOC +#define TC_RELOC(X,Y) (Y) +#endif + +static unsigned long mode_from_disp_size PARAMS ((unsigned long)); +static int fits_in_signed_byte PARAMS ((long)); +static int fits_in_unsigned_byte PARAMS ((long)); +static int fits_in_unsigned_word PARAMS ((long)); +static int fits_in_signed_word PARAMS ((long)); +static int smallest_imm_type PARAMS ((long)); +static void set_16bit_code_flag PARAMS ((int)); +#ifdef BFD_ASSEMBLER +static bfd_reloc_code_real_type reloc + PARAMS ((int, int, bfd_reloc_code_real_type)); +#endif + +/* 'md_assemble ()' gathers together information and puts it into a + i386_insn. */ + +struct _i386_insn + { + /* TM holds the template for the insn were currently assembling. */ + template tm; + /* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */ + char suffix; + /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */ + + /* OPERANDS gives the number of given operands. */ + unsigned int operands; + + /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number + of given register, displacement, memory operands and immediate + operands. */ + unsigned int reg_operands, disp_operands, mem_operands, imm_operands; + + /* TYPES [i] is the type (see above #defines) which tells us how to + search through DISPS [i] & IMMS [i] & REGS [i] for the required + operand. */ + unsigned int types[MAX_OPERANDS]; + + /* Displacements (if given) for each operand. */ + expressionS *disps[MAX_OPERANDS]; + + /* Relocation type for operand */ +#ifdef BFD_ASSEMBLER + enum bfd_reloc_code_real disp_reloc[MAX_OPERANDS]; +#else + int disp_reloc[MAX_OPERANDS]; +#endif + + /* Immediate operands (if given) for each operand. */ + expressionS *imms[MAX_OPERANDS]; + + /* Register operands (if given) for each operand. */ + reg_entry *regs[MAX_OPERANDS]; + + /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode + the base index byte below. */ + reg_entry *base_reg; + reg_entry *index_reg; + unsigned int log2_scale_factor; + + /* SEG gives the seg_entry of this insn. It is equal to zero unless + an explicit segment override is given. */ + const seg_entry *seg; /* segment for memory operands (if given) */ + + /* PREFIX holds all the given prefix opcodes (usually null). + PREFIXES is the size of PREFIX. */ + /* richfix: really unsigned? */ + unsigned char prefix[MAX_PREFIXES]; + unsigned int prefixes; + + /* RM and IB are the modrm byte and the base index byte where the + addressing modes of this insn are encoded. */ + + modrm_byte rm; + base_index_byte bi; + }; + +typedef struct _i386_insn i386_insn; + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +const char comment_chars[] = "#/"; +#else +const char comment_chars[] = "#"; +#endif + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that comments started like this one will always work if + '/' isn't otherwise defined. */ +#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +const char line_comment_chars[] = ""; +#else +const char line_comment_chars[] = "/"; +#endif +const char line_separator_chars[] = ""; + +/* Chars that can be used to separate mant from exp in floating point nums */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "fFdDxX"; + +/* tables for lexical analysis */ +static char opcode_chars[256]; +static char register_chars[256]; +static char operand_chars[256]; +static char space_chars[256]; +static char identifier_chars[256]; +static char digit_chars[256]; + +/* lexical macros */ +#define is_opcode_char(x) (opcode_chars[(unsigned char) x]) +#define is_operand_char(x) (operand_chars[(unsigned char) x]) +#define is_register_char(x) (register_chars[(unsigned char) x]) +#define is_space_char(x) (space_chars[(unsigned char) x]) +#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) +#define is_digit_char(x) (digit_chars[(unsigned char) x]) + +/* put here all non-digit non-letter charcters that may occur in an operand */ +static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]"; + +static char *ordinal_names[] = {"first", "second", "third"}; /* for printfs */ + +/* md_assemble() always leaves the strings it's passed unaltered. To + effect this we maintain a stack of saved characters that we've smashed + with '\0's (indicating end of strings for various sub-fields of the + assembler instruction). */ +static char save_stack[32]; +static char *save_stack_p; /* stack pointer */ +#define END_STRING_AND_SAVE(s) *save_stack_p++ = *s; *s = '\0' +#define RESTORE_END_STRING(s) *s = *--save_stack_p + +/* The instruction we're assembling. */ +static i386_insn i; + +/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ +static expressionS disp_expressions[2], im_expressions[2]; + +/* pointers to ebp & esp entries in reg_hash hash table */ +static reg_entry *ebp, *esp; + +static int this_operand; /* current operand we are working on */ + +static int flag_do_long_jump; /* FIXME what does this do? */ + +static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */ + +/* Interface to relax_segment. + There are 2 relax states for 386 jump insns: one for conditional & + one for unconditional jumps. This is because the these two types + of jumps add different sizes to frags when we're figuring out what + sort of jump to choose to reach a given label. */ + +/* types */ +#define COND_JUMP 1 /* conditional jump */ +#define UNCOND_JUMP 2 /* unconditional jump */ +/* sizes */ +#define BYTE 0 +#define WORD 1 +#define DWORD 2 +#define UNKNOWN_SIZE 3 + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +#define ENCODE_RELAX_STATE(type,size) \ + ((relax_substateT)((type<<2) | (size))) +#define SIZE_FROM_RELAX_STATE(s) \ + ( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) ) + +const relax_typeS md_relax_table[] = +{ +/* The fields are: + 1) most positive reach of this state, + 2) most negative reach of this state, + 3) how many bytes this mode will add to the size of the current frag + 4) which index into the table to try if we can't fit into this one. + */ + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0}, + + /* For now we don't use word displacement jumps; they may be + untrustworthy. */ + {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, DWORD)}, + /* word conditionals add 3 bytes to frag: + 2 opcode prefix; 1 displacement bytes */ + {32767 + 2, -32768 + 2, 3, ENCODE_RELAX_STATE (COND_JUMP, DWORD)}, + /* dword conditionals adds 4 bytes to frag: + 1 opcode prefix; 3 displacement bytes */ + {0, 0, 4, 0}, + {1, 1, 0, 0}, + + {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD)}, + /* word jmp adds 2 bytes to frag: + 1 opcode prefix; 1 displacement bytes */ + {32767 + 2, -32768 + 2, 2, ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD)}, + /* dword jmp adds 3 bytes to frag: + 0 opcode prefix; 3 displacement bytes */ + {0, 0, 3, 0}, + {1, 1, 0, 0}, + +}; + + +void +i386_align_code (fragP, count) + fragS *fragP; + int count; +{ + /* Various efficient no-op patterns for aligning code labels. */ + /* Note: Don't try to assemble the instructions in the comments. */ + /* 0L and 0w are not legal */ + static const char f32_1[] = + {0x90}; /* nop */ + static const char f32_2[] = + {0x89,0xf6}; /* movl %esi,%esi */ + static const char f32_3[] = + {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ + static const char f32_4[] = + {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_5[] = + {0x90, /* nop */ + 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_6[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ + static const char f32_7[] = + {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const char f32_8[] = + {0x90, /* nop */ + 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const char f32_9[] = + {0x89,0xf6, /* movl %esi,%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_10[] = + {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_11[] = + {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_12[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ + 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ + static const char f32_13[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_14[] = + {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_15[] = + {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; + static const char f16_4[] = + {0x8d,0xb6,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_5[] = + {0x90, /* nop */ + 0x8d,0xb6,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_6[] = + {0x89,0xf6, /* mov %si,%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_7[] = + {0x8d,0x76,0x00, /* lea 0(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_8[] = + {0x8d,0xb6,0x00,0x00, /* lea 0w(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char *const f32_patt[] = { + f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, + f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 + }; + static const char *const f16_patt[] = { + f32_1, f32_2, f32_3, f16_4, f16_5, f16_6, f16_7, f16_8, + f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15 + }; + + if (count > 0 && count <= 15) + { + if (flag_16bit_code) + { + memcpy(fragP->fr_literal + fragP->fr_fix, + f16_patt[count - 1], count); + if (count > 8) /* adjust jump offset */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; + } + else + memcpy(fragP->fr_literal + fragP->fr_fix, + f32_patt[count - 1], count); + fragP->fr_var = count; + } +} + +static char *output_invalid PARAMS ((int c)); +static int i386_operand PARAMS ((char *operand_string)); +static reg_entry *parse_register PARAMS ((char *reg_string)); +#ifndef I386COFF +static void s_bss PARAMS ((int)); +#endif + +symbolS *GOT_symbol; /* Pre-defined "__GLOBAL_OFFSET_TABLE" */ + +static INLINE unsigned long +mode_from_disp_size (t) + unsigned long t; +{ + return (t & Disp8) ? 1 : (t & Disp32) ? 2 : 0; +} + +#if 0 +/* Not used. */ +/* convert opcode suffix ('b' 'w' 'l' typically) into type specifier */ + +static INLINE unsigned long +opcode_suffix_to_type (s) + unsigned long s; +{ + return (s == BYTE_OPCODE_SUFFIX + ? Byte : (s == WORD_OPCODE_SUFFIX + ? Word : DWord)); +} /* opcode_suffix_to_type() */ +#endif + +static INLINE int +fits_in_signed_byte (num) + long num; +{ + return (num >= -128) && (num <= 127); +} /* fits_in_signed_byte() */ + +static INLINE int +fits_in_unsigned_byte (num) + long num; +{ + return (num & 0xff) == num; +} /* fits_in_unsigned_byte() */ + +static INLINE int +fits_in_unsigned_word (num) + long num; +{ + return (num & 0xffff) == num; +} /* fits_in_unsigned_word() */ + +static INLINE int +fits_in_signed_word (num) + long num; +{ + return (-32768 <= num) && (num <= 32767); +} /* fits_in_signed_word() */ + +static int +smallest_imm_type (num) + long num; +{ +#if 0 + /* This code is disabled because all the Imm1 forms in the opcode table + are slower on the i486, and they're the versions with the implicitly + specified single-position displacement, which has another syntax if + you really want to use that form. If you really prefer to have the + one-byte-shorter Imm1 form despite these problems, re-enable this + code. */ + if (num == 1) + return Imm1 | Imm8 | Imm8S | Imm16 | Imm32; +#endif + return (fits_in_signed_byte (num) + ? (Imm8S | Imm8 | Imm16 | Imm32) + : fits_in_unsigned_byte (num) + ? (Imm8 | Imm16 | Imm32) + : (fits_in_signed_word (num) || fits_in_unsigned_word (num)) + ? (Imm16 | Imm32) + : (Imm32)); +} /* smallest_imm_type() */ + +static void +set_16bit_code_flag (new_16bit_code_flag) + int new_16bit_code_flag; +{ + flag_16bit_code = new_16bit_code_flag; +} + +const pseudo_typeS md_pseudo_table[] = +{ +#ifndef I386COFF + {"bss", s_bss, 0}, +#endif +#ifndef OBJ_AOUT + {"align", s_align_bytes, 0}, +#else + {"align", s_align_ptwo, 0}, +#endif + {"ffloat", float_cons, 'f'}, + {"dfloat", float_cons, 'd'}, + {"tfloat", float_cons, 'x'}, + {"value", cons, 2}, + {"noopt", s_ignore, 0}, + {"optim", s_ignore, 0}, + {"code16", set_16bit_code_flag, 1}, + {"code32", set_16bit_code_flag, 0}, + {0, 0, 0} +}; + +/* for interface with expression () */ +extern char *input_line_pointer; + +/* obstack for constructing various things in md_begin */ +struct obstack o; + +/* hash table for opcode lookup */ +static struct hash_control *op_hash; +/* hash table for register lookup */ +static struct hash_control *reg_hash; +/* hash table for prefix lookup */ +static struct hash_control *prefix_hash; + + +void +md_begin () +{ + const char *hash_err; + + obstack_begin (&o, 4096); + + /* initialize op_hash hash table */ + op_hash = hash_new (); + + { + register const template *optab; + register templates *core_optab; + char *prev_name; + + optab = i386_optab; /* setup for loop */ + prev_name = optab->name; + obstack_grow (&o, optab, sizeof (template)); + core_optab = (templates *) xmalloc (sizeof (templates)); + + for (optab++; optab < i386_optab_end; optab++) + { + if (!strcmp (optab->name, prev_name)) + { + /* same name as before --> append to current template list */ + obstack_grow (&o, optab, sizeof (template)); + } + else + { + /* different name --> ship out current template list; + add to hash table; & begin anew */ + /* Note: end must be set before start! since obstack_next_free + changes upon opstack_finish */ + core_optab->end = (template *) obstack_next_free (&o); + core_optab->start = (template *) obstack_finish (&o); + hash_err = hash_insert (op_hash, prev_name, (char *) core_optab); + if (hash_err) + { + hash_error: + as_fatal ("Internal Error: Can't hash %s: %s", prev_name, + hash_err); + } + prev_name = optab->name; + core_optab = (templates *) xmalloc (sizeof (templates)); + obstack_grow (&o, optab, sizeof (template)); + } + } + } + + /* initialize reg_hash hash table */ + reg_hash = hash_new (); + { + register const reg_entry *regtab; + + for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) + { + hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); + if (hash_err) + goto hash_error; + } + } + + esp = (reg_entry *) hash_find (reg_hash, "esp"); + ebp = (reg_entry *) hash_find (reg_hash, "ebp"); + + /* initialize reg_hash hash table */ + prefix_hash = hash_new (); + { + register const prefix_entry *prefixtab; + + for (prefixtab = i386_prefixtab; + prefixtab < i386_prefixtab_end; prefixtab++) + { + hash_err = hash_insert (prefix_hash, prefixtab->prefix_name, + (PTR) prefixtab); + if (hash_err) + goto hash_error; + } + } + + /* fill in lexical tables: opcode_chars, operand_chars, space_chars */ + { + register int c; + register char *p; + + for (c = 0; c < 256; c++) + { + if (islower (c) || isdigit (c)) + { + opcode_chars[c] = c; + register_chars[c] = c; + } + else if (isupper (c)) + { + opcode_chars[c] = tolower (c); + register_chars[c] = opcode_chars[c]; + } + else if (c == PREFIX_SEPERATOR) + { + opcode_chars[c] = c; + } + else if (c == ')' || c == '(') + { + register_chars[c] = c; + } + + if (isupper (c) || islower (c) || isdigit (c)) + operand_chars[c] = c; + + if (isdigit (c) || c == '-') + digit_chars[c] = c; + + if (isalpha (c) || c == '_' || c == '.' || isdigit (c)) + identifier_chars[c] = c; + +#ifdef LEX_AT + identifier_chars['@'] = '@'; +#endif + + if (c == ' ' || c == '\t') + space_chars[c] = c; + } + + for (p = operand_special_chars; *p != '\0'; p++) + operand_chars[(unsigned char) *p] = *p; + } + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + record_alignment (text_section, 2); + record_alignment (data_section, 2); + record_alignment (bss_section, 2); + } +#endif +} + +void +i386_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "i386 opcode", op_hash); + hash_print_statistics (file, "i386 register", reg_hash); + hash_print_statistics (file, "i386 prefix", prefix_hash); +} + + +#ifdef DEBUG386 + +/* debugging routines for md_assemble */ +static void pi PARAMS ((char *, i386_insn *)); +static void pte PARAMS ((template *)); +static void pt PARAMS ((unsigned int)); +static void pe PARAMS ((expressionS *)); +static void ps PARAMS ((symbolS *)); + +static void +pi (line, x) + char *line; + i386_insn *x; +{ + register template *p; + int i; + + fprintf (stdout, "%s: template ", line); + pte (&x->tm); + fprintf (stdout, " modrm: mode %x reg %x reg/mem %x", + x->rm.mode, x->rm.reg, x->rm.regmem); + fprintf (stdout, " base %x index %x scale %x\n", + x->bi.base, x->bi.index, x->bi.scale); + for (i = 0; i < x->operands; i++) + { + fprintf (stdout, " #%d: ", i + 1); + pt (x->types[i]); + fprintf (stdout, "\n"); + if (x->types[i] + & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX)) + fprintf (stdout, "%s\n", x->regs[i]->reg_name); + if (x->types[i] & Imm) + pe (x->imms[i]); + if (x->types[i] & (Disp | Abs)) + pe (x->disps[i]); + } +} + +static void +pte (t) + template *t; +{ + int i; + fprintf (stdout, " %d operands ", t->operands); + fprintf (stdout, "opcode %x ", + t->base_opcode); + if (t->extension_opcode != None) + fprintf (stdout, "ext %x ", t->extension_opcode); + if (t->opcode_modifier & D) + fprintf (stdout, "D"); + if (t->opcode_modifier & W) + fprintf (stdout, "W"); + fprintf (stdout, "\n"); + for (i = 0; i < t->operands; i++) + { + fprintf (stdout, " #%d type ", i + 1); + pt (t->operand_types[i]); + fprintf (stdout, "\n"); + } +} + +static void +pe (e) + expressionS *e; +{ + fprintf (stdout, " operation %d\n", e->X_op); + fprintf (stdout, " add_number %d (%x)\n", + e->X_add_number, e->X_add_number); + if (e->X_add_symbol) + { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_op_symbol) + { + fprintf (stdout, " op_symbol "); + ps (e->X_op_symbol); + fprintf (stdout, "\n"); + } +} + +static void +ps (s) + symbolS *s; +{ + fprintf (stdout, "%s type %s%s", + S_GET_NAME (s), + S_IS_EXTERNAL (s) ? "EXTERNAL " : "", + segment_name (S_GET_SEGMENT (s))); +} + +struct type_name + { + unsigned int mask; + char *tname; + } + +type_names[] = +{ + { Reg8, "r8" }, + { Reg16, "r16" }, + { Reg32, "r32" }, + { Imm8, "i8" }, + { Imm8S, "i8s" }, + { Imm16, "i16" }, + { Imm32, "i32" }, + { Mem8, "Mem8" }, + { Mem16, "Mem16" }, + { Mem32, "Mem32" }, + { BaseIndex, "BaseIndex" }, + { Abs8, "Abs8" }, + { Abs16, "Abs16" }, + { Abs32, "Abs32" }, + { Disp8, "d8" }, + { Disp16, "d16" }, + { Disp32, "d32" }, + { SReg2, "SReg2" }, + { SReg3, "SReg3" }, + { Acc, "Acc" }, + { InOutPortReg, "InOutPortReg" }, + { ShiftCount, "ShiftCount" }, + { Imm1, "i1" }, + { Control, "control reg" }, + { Test, "test reg" }, + { FloatReg, "FReg" }, + { FloatAcc, "FAcc" }, + { JumpAbsolute, "Jump Absolute" }, + { RegMMX, "rMMX" }, + { 0, "" } +}; + +static void +pt (t) + unsigned int t; +{ + register struct type_name *ty; + + if (t == Unknown) + { + fprintf (stdout, "Unknown"); + } + else + { + for (ty = type_names; ty->mask; ty++) + if (t & ty->mask) + fprintf (stdout, "%s, ", ty->tname); + } + fflush (stdout); +} + +#endif /* DEBUG386 */ + +#ifdef BFD_ASSEMBLER +static bfd_reloc_code_real_type +reloc (size, pcrel, other) + int size; + int pcrel; + bfd_reloc_code_real_type other; +{ + if (other != NO_RELOC) return other; + + if (pcrel) + switch (size) + { + case 1: return BFD_RELOC_8_PCREL; + case 2: return BFD_RELOC_16_PCREL; + case 4: return BFD_RELOC_32_PCREL; + } + else + switch (size) + { + case 1: return BFD_RELOC_8; + case 2: return BFD_RELOC_16; + case 4: return BFD_RELOC_32; + } + + as_bad ("Can not do %d byte %srelocation", size, + pcrel ? "pc-relative " : ""); + return BFD_RELOC_NONE; +} + +/* + * Here we decide which fixups can be adjusted to make them relative to + * the beginning of the section instead of the symbol. Basically we need + * to make sure that the dynamic relocations are done correctly, so in + * some cases we force the original symbol to be used. + */ +int +tc_i386_fix_adjustable(fixP) + fixS * fixP; +{ +#ifndef OBJ_AOUT + /* Prevent all adjustments to global symbols. */ + if (S_IS_EXTERN (fixP->fx_addsy)) + return 0; + if (S_IS_WEAK (fixP->fx_addsy)) + return 0; +#endif /* ! defined (OBJ_AOUT) */ + /* adjust_reloc_syms doesn't know about the GOT */ + if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF + || fixP->fx_r_type == BFD_RELOC_386_PLT32 + || fixP->fx_r_type == BFD_RELOC_386_GOT32) + return 0; + return 1; +} +#else +#define reloc(SIZE,PCREL,OTHER) 0 +#define BFD_RELOC_32 0 +#define BFD_RELOC_32_PCREL 0 +#define BFD_RELOC_386_PLT32 0 +#define BFD_RELOC_386_GOT32 0 +#define BFD_RELOC_386_GOTOFF 0 +#endif + +/* This is the guts of the machine-dependent assembler. LINE points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. */ + +void +md_assemble (line) + char *line; +{ + /* Holds template once we've found it. */ + template *t; + + /* Count the size of the instruction generated. */ + int insn_size = 0; + + /* Possible templates for current insn */ + templates *current_templates = (templates *) 0; + + int j; + + /* Initialize globals. */ + memset (&i, '\0', sizeof (i)); + for (j = 0; j < MAX_OPERANDS; j++) + i.disp_reloc[j] = NO_RELOC; + memset (disp_expressions, '\0', sizeof (disp_expressions)); + memset (im_expressions, '\0', sizeof (im_expressions)); + save_stack_p = save_stack; /* reset stack pointer */ + + /* Fist parse an opcode & call i386_operand for the operands. + We assume that the scrubber has arranged it so that line[0] is the valid + start of a (possibly prefixed) opcode. */ + { + char *l = line; + + /* 1 if operand is pending after ','. */ + unsigned int expecting_operand = 0; + /* 1 if we found a prefix only acceptable with string insns. */ + unsigned int expecting_string_instruction = 0; + /* Non-zero if operand parens not balanced. */ + unsigned int paren_not_balanced; + char *token_start = l; + + while (!is_space_char (*l) && *l != END_OF_INSN) + { + if (!is_opcode_char (*l)) + { + as_bad ("invalid character %s in opcode", output_invalid (*l)); + return; + } + else if (*l != PREFIX_SEPERATOR) + { + *l = opcode_chars[(unsigned char) *l]; /* fold case of opcodes */ + l++; + } + else + { + /* This opcode's got a prefix. */ + unsigned int q; + prefix_entry *prefix; + + if (l == token_start) + { + as_bad ("expecting prefix; got nothing"); + return; + } + END_STRING_AND_SAVE (l); + prefix = (prefix_entry *) hash_find (prefix_hash, token_start); + if (!prefix) + { + as_bad ("no such opcode prefix ('%s')", token_start); + return; + } + RESTORE_END_STRING (l); + /* check for repeated prefix */ + for (q = 0; q < i.prefixes; q++) + if (i.prefix[q] == prefix->prefix_code) + { + as_bad ("same prefix used twice; you don't really want this!"); + return; + } + if (i.prefixes == MAX_PREFIXES) + { + as_bad ("too many opcode prefixes"); + return; + } + i.prefix[i.prefixes++] = prefix->prefix_code; + if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE) + expecting_string_instruction = 1; + /* skip past PREFIX_SEPERATOR and reset token_start */ + token_start = ++l; + } + } + END_STRING_AND_SAVE (l); + if (token_start == l) + { + as_bad ("expecting opcode; got nothing"); + return; + } + + /* Lookup insn in hash; try intel & att naming conventions if appropriate; + that is: we only use the opcode suffix 'b' 'w' or 'l' if we need to. */ + current_templates = (templates *) hash_find (op_hash, token_start); + if (!current_templates) + { + int last_index = strlen (token_start) - 1; + char last_char = token_start[last_index]; + switch (last_char) + { + case DWORD_OPCODE_SUFFIX: + case WORD_OPCODE_SUFFIX: + case BYTE_OPCODE_SUFFIX: + token_start[last_index] = '\0'; + current_templates = (templates *) hash_find (op_hash, token_start); + token_start[last_index] = last_char; + i.suffix = last_char; + } + if (!current_templates) + { + as_bad ("no such 386 instruction: `%s'", token_start); + return; + } + } + RESTORE_END_STRING (l); + + /* check for rep/repne without a string instruction */ + if (expecting_string_instruction && + !IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) + { + as_bad ("expecting string instruction after rep/repne"); + return; + } + + /* There may be operands to parse. */ + if (*l != END_OF_INSN && + /* For string instructions, we ignore any operands if given. This + kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where + the operands are always going to be the same, and are not really + encoded in machine code. */ + !IS_STRING_INSTRUCTION (current_templates-> + start->base_opcode)) + { + /* parse operands */ + do + { + /* skip optional white space before operand */ + while (!is_operand_char (*l) && *l != END_OF_INSN) + { + if (!is_space_char (*l)) + { + as_bad ("invalid character %s before %s operand", + output_invalid (*l), + ordinal_names[i.operands]); + return; + } + l++; + } + token_start = l; /* after white space */ + paren_not_balanced = 0; + while (paren_not_balanced || *l != ',') + { + if (*l == END_OF_INSN) + { + if (paren_not_balanced) + { + as_bad ("unbalanced parenthesis in %s operand.", + ordinal_names[i.operands]); + return; + } + else + break; /* we are done */ + } + else if (!is_operand_char (*l) && !is_space_char (*l)) + { + as_bad ("invalid character %s in %s operand", + output_invalid (*l), + ordinal_names[i.operands]); + return; + } + if (*l == '(') + ++paren_not_balanced; + if (*l == ')') + --paren_not_balanced; + l++; + } + if (l != token_start) + { /* yes, we've read in another operand */ + unsigned int operand_ok; + this_operand = i.operands++; + if (i.operands > MAX_OPERANDS) + { + as_bad ("spurious operands; (%d operands/instruction max)", + MAX_OPERANDS); + return; + } + /* now parse operand adding info to 'i' as we go along */ + END_STRING_AND_SAVE (l); + operand_ok = i386_operand (token_start); + RESTORE_END_STRING (l); /* restore old contents */ + if (!operand_ok) + return; + } + else + { + if (expecting_operand) + { + expecting_operand_after_comma: + as_bad ("expecting operand after ','; got nothing"); + return; + } + if (*l == ',') + { + as_bad ("expecting operand before ','; got nothing"); + return; + } + } + + /* now *l must be either ',' or END_OF_INSN */ + if (*l == ',') + { + if (*++l == END_OF_INSN) + { /* just skip it, if it's \n complain */ + goto expecting_operand_after_comma; + } + expecting_operand = 1; + } + } + while (*l != END_OF_INSN); /* until we get end of insn */ + } + } + + /* Now we've parsed the opcode into a set of templates, and have the + operands at hand. + + Next, we find a template that matches the given insn, + making sure the overlap of the given operands types is consistent + with the template operand types. */ + +#define MATCH(overlap,given_type) \ + (overlap && \ + (((overlap & (JumpAbsolute|BaseIndex|Mem8)) \ + == (given_type & (JumpAbsolute|BaseIndex|Mem8))) \ + || (overlap == InOutPortReg))) + + + /* If m0 and m1 are register matches they must be consistent + with the expected operand types t0 and t1. + That is, if both m0 & m1 are register matches + i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ? + then, either 1. or 2. must be true: + 1. the expected operand type register overlap is null: + (t0 & t1 & Reg) == 0 + AND + the given register overlap is null: + (m0 & m1 & Reg) == 0 + 2. the expected operand type register overlap == the given + operand type overlap: (t0 & t1 & m0 & m1 & Reg). + */ +#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \ + ( ((m0 & (Reg)) && (m1 & (Reg))) ? \ + ( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \ + ((t0 & t1) & (m0 & m1) & (Reg)) \ + ) : 1) + { + register unsigned int overlap0, overlap1; + expressionS *exp; + unsigned int overlap2; + unsigned int found_reverse_match; + + overlap0 = overlap1 = overlap2 = found_reverse_match = 0; + for (t = current_templates->start; + t < current_templates->end; + t++) + { + /* must have right number of operands */ + if (i.operands != t->operands) + continue; + else if (!t->operands) + break; /* 0 operands always matches */ + + overlap0 = i.types[0] & t->operand_types[0]; + switch (t->operands) + { + case 1: + if (!MATCH (overlap0, i.types[0])) + continue; + break; + case 2: + case 3: + overlap1 = i.types[1] & t->operand_types[1]; + if (!MATCH (overlap0, i.types[0]) || + !MATCH (overlap1, i.types[1]) || + !CONSISTENT_REGISTER_MATCH (overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) + { + + /* check if other direction is valid ... */ + if (!(t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS)) + continue; + + /* try reversing direction of operands */ + overlap0 = i.types[0] & t->operand_types[1]; + overlap1 = i.types[1] & t->operand_types[0]; + if (!MATCH (overlap0, i.types[0]) || + !MATCH (overlap1, i.types[1]) || + !CONSISTENT_REGISTER_MATCH (overlap0, overlap1, + t->operand_types[0], + t->operand_types[1])) + { + /* does not match either direction */ + continue; + } + /* found a reverse match here -- slip through */ + /* found_reverse_match holds which of D or FloatD we've found */ + found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS; + } /* endif: not forward match */ + /* found either forward/reverse 2 operand match here */ + if (t->operands == 3) + { + overlap2 = i.types[2] & t->operand_types[2]; + if (!MATCH (overlap2, i.types[2]) || + !CONSISTENT_REGISTER_MATCH (overlap0, overlap2, + t->operand_types[0], + t->operand_types[2]) || + !CONSISTENT_REGISTER_MATCH (overlap1, overlap2, + t->operand_types[1], + t->operand_types[2])) + continue; + } + /* found either forward/reverse 2 or 3 operand match here: + slip through to break */ + } + break; /* we've found a match; break out of loop */ + } /* for (t = ... */ + if (t == current_templates->end) + { /* we found no match */ + as_bad ("operands given don't match any known 386 instruction"); + return; + } + + /* Copy the template we found (we may change it!). */ + i.tm = *t; + t = &i.tm; /* alter new copy of template */ + + /* If the matched instruction specifies an explicit opcode suffix, + use it - and make sure none has already been specified. */ + if (t->opcode_modifier & (Data16|Data32)) + { + if (i.suffix) + { + as_bad ("extraneous opcode suffix given"); + return; + } + if (t->opcode_modifier & Data16) + i.suffix = WORD_OPCODE_SUFFIX; + else + i.suffix = DWORD_OPCODE_SUFFIX; + } + + /* If there's no opcode suffix we try to invent one based on register + operands. */ + if (!i.suffix && i.reg_operands) + { + /* We take i.suffix from the LAST register operand specified. This + assumes that the last register operands is the destination register + operand. */ + int op; + for (op = 0; op < MAX_OPERANDS; op++) + if (i.types[op] & Reg) + { + i.suffix = ((i.types[op] & Reg8) ? BYTE_OPCODE_SUFFIX : + (i.types[op] & Reg16) ? WORD_OPCODE_SUFFIX : + DWORD_OPCODE_SUFFIX); + } + } + else if (i.suffix != 0 + && i.reg_operands != 0 + && (i.types[i.operands - 1] & Reg) != 0) + { + int bad; + + /* If the last operand is a register, make sure it is + compatible with the suffix. */ + + bad = 0; + switch (i.suffix) + { + default: + abort (); + case BYTE_OPCODE_SUFFIX: + /* If this is an eight bit register, it's OK. If it's the + 16 or 32 bit version of an eight bit register, we will + just use the low portion, and that's OK too. */ + if ((i.types[i.operands - 1] & Reg8) == 0 + && i.regs[i.operands - 1]->reg_num >= 4) + bad = 1; + break; + case WORD_OPCODE_SUFFIX: + case DWORD_OPCODE_SUFFIX: + /* We don't insist on the presence or absence of the e + prefix on the register, but we reject eight bit + registers. */ + if ((i.types[i.operands - 1] & Reg8) != 0) + bad = 1; + } + if (bad) + as_bad ("register does not match opcode suffix"); + } + + /* Make still unresolved immediate matches conform to size of immediate + given in i.suffix. Note: overlap2 cannot be an immediate! + We assume this. */ + if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32)) + && overlap0 != Imm8 && overlap0 != Imm8S + && overlap0 != Imm16 && overlap0 != Imm32) + { + if (!i.suffix) + { + as_bad ("no opcode suffix given; can't determine immediate size"); + return; + } + overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32)) + && overlap1 != Imm8 && overlap1 != Imm8S + && overlap1 != Imm16 && overlap1 != Imm32) + { + if (!i.suffix) + { + as_bad ("no opcode suffix given; can't determine immediate size"); + return; + } + overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) : + (i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32)); + } + + i.types[0] = overlap0; + i.types[1] = overlap1; + i.types[2] = overlap2; + + if (overlap0 & ImplicitRegister) + i.reg_operands--; + if (overlap1 & ImplicitRegister) + i.reg_operands--; + if (overlap2 & ImplicitRegister) + i.reg_operands--; + if (overlap0 & Imm1) + i.imm_operands = 0; /* kludge for shift insns */ + + if (found_reverse_match) + { + unsigned int save; + save = t->operand_types[0]; + t->operand_types[0] = t->operand_types[1]; + t->operand_types[1] = save; + } + + /* Finalize opcode. First, we change the opcode based on the operand + size given by i.suffix: we never have to change things for byte insns, + or when no opcode suffix is need to size the operands. */ + + if (!i.suffix && (t->opcode_modifier & W)) + { + as_bad ("no opcode suffix given and no register operands; can't size instruction"); + return; + } + + if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) + { + /* Select between byte and word/dword operations. */ + if (t->opcode_modifier & W) + t->base_opcode |= W; + /* Now select between word & dword operations via the + operand size prefix. */ + if ((i.suffix == WORD_OPCODE_SUFFIX) ^ flag_16bit_code) + { + if (i.prefixes == MAX_PREFIXES) + { + as_bad ("%d prefixes given and 'w' opcode suffix gives too many prefixes", + MAX_PREFIXES); + return; + } + i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE; + } + } + + /* For insns with operands there are more diddles to do to the opcode. */ + if (i.operands) + { + /* Default segment register this instruction will use + for memory accesses. 0 means unknown. + This is only for optimizing out unnecessary segment overrides. */ + const seg_entry *default_seg = 0; + + /* True if this instruction uses a memory addressing mode, + and therefore may need an address-size prefix. */ + int uses_mem_addrmode = 0; + + + /* If we found a reverse match we must alter the opcode direction bit + found_reverse_match holds bit to set (different for int & + float insns). */ + + if (found_reverse_match) + { + t->base_opcode |= found_reverse_match; + } + + /* The imul $imm, %reg instruction is converted into + imul $imm, %reg, %reg. */ + if (t->opcode_modifier & imulKludge) + { + /* Pretend we saw the 3 operand case. */ + i.regs[2] = i.regs[1]; + i.reg_operands = 2; + } + + /* The clr %reg instruction is converted into xor %reg, %reg. */ + if (t->opcode_modifier & iclrKludge) + { + i.regs[1] = i.regs[0]; + i.reg_operands = 2; + } + + /* Certain instructions expect the destination to be in the i.rm.reg + field. This is by far the exceptional case. For these + instructions, if the source operand is a register, we must reverse + the i.rm.reg and i.rm.regmem fields. We accomplish this by faking + that the two register operands were given in the reverse order. */ + if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) + { + unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1; + unsigned int second_reg_operand = first_reg_operand + 1; + reg_entry *tmp = i.regs[first_reg_operand]; + i.regs[first_reg_operand] = i.regs[second_reg_operand]; + i.regs[second_reg_operand] = tmp; + } + + if (t->opcode_modifier & ShortForm) + { + /* The register or float register operand is in operand 0 or 1. */ + unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; + /* Register goes in low 3 bits of opcode. */ + t->base_opcode |= i.regs[op]->reg_num; + } + else if (t->opcode_modifier & ShortFormW) + { + /* Short form with 0x8 width bit. Register is always dest. operand */ + t->base_opcode |= i.regs[1]->reg_num; + if (i.suffix == WORD_OPCODE_SUFFIX || + i.suffix == DWORD_OPCODE_SUFFIX) + t->base_opcode |= 0x8; + } + else if (t->opcode_modifier & Seg2ShortForm) + { + if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) + { + as_bad ("you can't 'pop cs' on the 386."); + return; + } + t->base_opcode |= (i.regs[0]->reg_num << 3); + } + else if (t->opcode_modifier & Seg3ShortForm) + { + /* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1. + 'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9. + So, only if i.regs[0]->reg_num == 5 (%gs) do we need + to change the opcode. */ + if (i.regs[0]->reg_num == 5) + t->base_opcode |= 0x08; + } + else if ((t->base_opcode & ~DW) == MOV_AX_DISP32) + { + /* This is a special non-modrm instruction + that addresses memory with a 32-bit displacement mode anyway, + and thus requires an address-size prefix if in 16-bit mode. */ + uses_mem_addrmode = 1; + default_seg = &ds; + } + else if (t->opcode_modifier & Modrm) + { + /* The opcode is completed (modulo t->extension_opcode which must + be put into the modrm byte. + Now, we make the modrm & index base bytes based on all the info + we've collected. */ + + /* i.reg_operands MUST be the number of real register operands; + implicit registers do not count. */ + if (i.reg_operands == 2) + { + unsigned int source, dest; + source = ((i.types[0] + & (Reg + | SReg2 + | SReg3 + | Control + | Debug + | Test + | RegMMX)) + ? 0 : 1); + dest = source + 1; + i.rm.mode = 3; + /* We must be careful to make sure that all + segment/control/test/debug/MMX registers go into + the i.rm.reg field (despite the whether they are + source or destination operands). */ + if (i.regs[dest]->reg_type + & (SReg2 | SReg3 | Control | Debug | Test | RegMMX)) + { + i.rm.reg = i.regs[dest]->reg_num; + i.rm.regmem = i.regs[source]->reg_num; + } + else + { + i.rm.reg = i.regs[source]->reg_num; + i.rm.regmem = i.regs[dest]->reg_num; + } + } + else + { /* if it's not 2 reg operands... */ + if (i.mem_operands) + { + unsigned int fake_zero_displacement = 0; + unsigned int op = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2); + + /* Encode memory operand into modrm byte and base index + byte. */ + + if (i.base_reg == esp && !i.index_reg) + { + /* <disp>(%esp) becomes two byte modrm with no index + register. */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = mode_from_disp_size (i.types[op]); + i.bi.base = ESP_REG_NUM; + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; /* Must be zero! */ + } + else if (i.base_reg == ebp && !i.index_reg) + { + if (!(i.types[op] & Disp)) + { + /* Must fake a zero byte displacement. There is + no direct way to code '(%ebp)' directly. */ + fake_zero_displacement = 1; + /* fake_zero_displacement code does not set this. */ + i.types[op] |= Disp8; + } + i.rm.mode = mode_from_disp_size (i.types[op]); + i.rm.regmem = EBP_REG_NUM; + } + else if (!i.base_reg && (i.types[op] & BaseIndex)) + { + /* There are three cases here. + Case 1: '<32bit disp>(,1)' -- indirect absolute. + (Same as cases 2 & 3 with NO index register) + Case 2: <32bit disp> (,<index>) -- no base register with disp + Case 3: (, <index>) --- no base register; + no disp (must add 32bit 0 disp). */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.rm.mode = 0; /* 32bit mode */ + i.bi.base = NO_BASE_REGISTER; + i.types[op] &= ~Disp; + i.types[op] |= Disp32; /* Must be 32bit! */ + if (i.index_reg) + { /* case 2 or case 3 */ + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.disp_operands == 0) + fake_zero_displacement = 1; /* case 3 */ + } + else + { + i.bi.index = NO_INDEX_REGISTER; + i.bi.scale = 0; + } + } + else if (i.disp_operands && !i.base_reg && !i.index_reg) + { + /* Operand is just <32bit disp> */ + i.rm.regmem = EBP_REG_NUM; + i.rm.mode = 0; + i.types[op] &= ~Disp; + i.types[op] |= Disp32; + } + else + { + /* It's not a special case; rev'em up. */ + i.rm.regmem = i.base_reg->reg_num; + i.rm.mode = mode_from_disp_size (i.types[op]); + if (i.index_reg) + { + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.bi.base = i.base_reg->reg_num; + i.bi.index = i.index_reg->reg_num; + i.bi.scale = i.log2_scale_factor; + if (i.base_reg == ebp && i.disp_operands == 0) + { /* pace */ + fake_zero_displacement = 1; + i.types[op] |= Disp8; + i.rm.mode = mode_from_disp_size (i.types[op]); + } + } + } + if (fake_zero_displacement) + { + /* Fakes a zero displacement assuming that i.types[op] + holds the correct displacement size. */ + exp = &disp_expressions[i.disp_operands++]; + i.disps[op] = exp; + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + + /* Find the default segment for the memory operand. + Used to optimize out explicit segment specifications. */ + if (i.seg) + { + unsigned int seg_index; + + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) + { + seg_index = (i.rm.mode << 3) | i.bi.base; + default_seg = two_byte_segment_defaults[seg_index]; + } + else + { + seg_index = (i.rm.mode << 3) | i.rm.regmem; + default_seg = one_byte_segment_defaults[seg_index]; + } + } + } + + /* Fill in i.rm.reg or i.rm.regmem field with register + operand (if any) based on + t->extension_opcode. Again, we must be careful to + make sure that segment/control/debug/test/MMX + registers are coded into the i.rm.reg field. */ + if (i.reg_operands) + { + unsigned int op = + ((i.types[0] + & (Reg | SReg2 | SReg3 | Control | Debug + | Test | RegMMX)) + ? 0 + : ((i.types[1] + & (Reg | SReg2 | SReg3 | Control | Debug + | Test | RegMMX)) + ? 1 + : 2)); + /* If there is an extension opcode to put here, the + register number must be put into the regmem field. */ + if (t->extension_opcode != None) + i.rm.regmem = i.regs[op]->reg_num; + else + i.rm.reg = i.regs[op]->reg_num; + + /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 + we must set it to 3 to indicate this is a register + operand int the regmem field */ + if (!i.mem_operands) + i.rm.mode = 3; + } + + /* Fill in i.rm.reg field with extension opcode (if any). */ + if (t->extension_opcode != None) + i.rm.reg = t->extension_opcode; + } + + if (i.rm.mode != 3) + uses_mem_addrmode = 1; + } + + /* GAS currently doesn't support 16-bit memory addressing modes at all, + so if we're writing 16-bit code and using a memory addressing mode, + always spew out an address size prefix. */ + if (uses_mem_addrmode && flag_16bit_code) + { + if (i.prefixes == MAX_PREFIXES) + { + as_bad ("%d prefixes given and address size override gives too many prefixes", + MAX_PREFIXES); + return; + } + i.prefix[i.prefixes++] = ADDR_PREFIX_OPCODE; + } + + /* If a segment was explicitly specified, + and the specified segment is not the default, + use an opcode prefix to select it. + If we never figured out what the default segment is, + then default_seg will be zero at this point, + and the specified segment prefix will always be used. */ + if ((i.seg) && (i.seg != default_seg)) + { + if (i.prefixes == MAX_PREFIXES) + { + as_bad ("%d prefixes given and %s segment override gives too many prefixes", + MAX_PREFIXES, i.seg->seg_name); + return; + } + i.prefix[i.prefixes++] = i.seg->seg_prefix; + } + } + } + + /* Handle conversion of 'int $3' --> special int3 insn. */ + if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) + { + t->base_opcode = INT3_OPCODE; + i.imm_operands = 0; + } + + /* We are ready to output the insn. */ + { + register char *p; + + /* Output jumps. */ + if (t->opcode_modifier & Jump) + { + unsigned long n = i.disps[0]->X_add_number; + + if (i.disps[0]->X_op == O_constant) + { + if (fits_in_signed_byte (n)) + { + p = frag_more (2); + insn_size += 2; + p[0] = t->base_opcode; + p[1] = n; + } + else + { /* It's an absolute word/dword displacement. */ + + /* Use only 16-bit jumps for 16-bit code, + because text segments are limited to 64K anyway; + use only 32-bit jumps for 32-bit code, + because they're faster. */ + int jmp_size = flag_16bit_code ? 2 : 4; + if (flag_16bit_code && !fits_in_signed_word (n)) + { + as_bad ("16-bit jump out of range"); + return; + } + + if (t->base_opcode == JUMP_PC_RELATIVE) + { /* pace */ + /* unconditional jump */ + p = frag_more (1 + jmp_size); + insn_size += 1 + jmp_size; + p[0] = (char) 0xe9; + md_number_to_chars (&p[1], (valueT) n, jmp_size); + } + else + { + /* conditional jump */ + p = frag_more (2 + jmp_size); + insn_size += 2 + jmp_size; + p[0] = TWO_BYTE_OPCODE_ESCAPE; + p[1] = t->base_opcode + 0x10; + md_number_to_chars (&p[2], (valueT) n, jmp_size); + } + } + } + else + { + if (flag_16bit_code) + { + FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); + insn_size += 1; + } + + /* It's a symbol; end frag & setup for relax. + Make sure there are more than 6 chars left in the current frag; + if not we'll have to start a new one. */ + frag_grow (7); + p = frag_more (1); + insn_size += 1; + p[0] = t->base_opcode; + frag_var (rs_machine_dependent, + 6, /* 2 opcode/prefix + 4 displacement */ + 1, + ((unsigned char) *p == JUMP_PC_RELATIVE + ? ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE) + : ENCODE_RELAX_STATE (COND_JUMP, BYTE)), + i.disps[0]->X_add_symbol, + (offsetT) n, p); + } + } + else if (t->opcode_modifier & (JumpByte | JumpDword)) + { + int size = (t->opcode_modifier & JumpByte) ? 1 : 4; + unsigned long n = i.disps[0]->X_add_number; + unsigned char *q; + + /* The jcx/jecx instruction might need a data size prefix. */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) + { + if (*q == WORD_PREFIX_OPCODE) + { + FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); + insn_size += 1; + break; + } + } + + if ((size == 4) && (flag_16bit_code)) + { + FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); + insn_size += 1; + } + + if (fits_in_unsigned_byte (t->base_opcode)) + { + FRAG_APPEND_1_CHAR (t->base_opcode); + insn_size += 1; + } + else + { + p = frag_more (2); /* opcode can be at most two bytes */ + insn_size += 2; + /* put out high byte first: can't use md_number_to_chars! */ + *p++ = (t->base_opcode >> 8) & 0xff; + *p = t->base_opcode & 0xff; + } + + p = frag_more (size); + insn_size += size; + if (i.disps[0]->X_op == O_constant) + { + md_number_to_chars (p, (valueT) n, size); + if (size == 1 && !fits_in_signed_byte (n)) + { + as_bad ("loop/jecx only takes byte displacement; %lu shortened to %d", + n, *p); + } + } + else + { + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.disps[0], 1, reloc (size, 1, i.disp_reloc[0])); + + } + } + else if (t->opcode_modifier & JumpInterSegment) + { + if (flag_16bit_code) + { + FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); + insn_size += 1; + } + + p = frag_more (1 + 2 + 4); /* 1 opcode; 2 segment; 4 offset */ + insn_size += 1 + 2 + 4; + p[0] = t->base_opcode; + if (i.imms[1]->X_op == O_constant) + md_number_to_chars (p + 1, (valueT) i.imms[1]->X_add_number, 4); + else + fix_new_exp (frag_now, p + 1 - frag_now->fr_literal, 4, + i.imms[1], 0, BFD_RELOC_32); + if (i.imms[0]->X_op != O_constant) + as_bad ("can't handle non absolute segment in long call/jmp"); + md_number_to_chars (p + 5, (valueT) i.imms[0]->X_add_number, 2); + } + else + { + /* Output normal instructions here. */ + unsigned char *q; + + /* First the prefix bytes. */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) + { + p = frag_more (1); + insn_size += 1; + md_number_to_chars (p, (valueT) *q, 1); + } + + /* Now the opcode; be careful about word order here! */ + if (fits_in_unsigned_byte (t->base_opcode)) + { + FRAG_APPEND_1_CHAR (t->base_opcode); + insn_size += 1; + } + else if (fits_in_unsigned_word (t->base_opcode)) + { + p = frag_more (2); + insn_size += 2; + /* put out high byte first: can't use md_number_to_chars! */ + *p++ = (t->base_opcode >> 8) & 0xff; + *p = t->base_opcode & 0xff; + } + else + { /* opcode is either 3 or 4 bytes */ + if (t->base_opcode & 0xff000000) + { + p = frag_more (4); + insn_size += 4; + *p++ = (t->base_opcode >> 24) & 0xff; + } + else + { + p = frag_more (3); + insn_size += 3; + } + *p++ = (t->base_opcode >> 16) & 0xff; + *p++ = (t->base_opcode >> 8) & 0xff; + *p = (t->base_opcode) & 0xff; + } + + /* Now the modrm byte and base index byte (if present). */ + if (t->opcode_modifier & Modrm) + { + p = frag_more (1); + insn_size += 1; + /* md_number_to_chars (p, i.rm, 1); */ + md_number_to_chars (p, + (valueT) (i.rm.regmem << 0 + | i.rm.reg << 3 + | i.rm.mode << 6), + 1); + /* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) + ==> need second modrm byte. */ + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) + { + p = frag_more (1); + insn_size += 1; + /* md_number_to_chars (p, i.bi, 1); */ + md_number_to_chars (p, (valueT) (i.bi.base << 0 + | i.bi.index << 3 + | i.bi.scale << 6), + 1); + } + } + + if (i.disp_operands) + { + register unsigned int n; + + for (n = 0; n < i.operands; n++) + { + if (i.disps[n]) + { + if (i.disps[n]->X_op == O_constant) + { + if (i.types[n] & (Disp8 | Abs8)) + { + p = frag_more (1); + insn_size += 1; + md_number_to_chars (p, + (valueT) i.disps[n]->X_add_number, + 1); + } + else if (i.types[n] & (Disp16 | Abs16)) + { + p = frag_more (2); + insn_size += 2; + md_number_to_chars (p, + (valueT) i.disps[n]->X_add_number, + 2); + } + else + { /* Disp32|Abs32 */ + p = frag_more (4); + insn_size += 4; + md_number_to_chars (p, + (valueT) i.disps[n]->X_add_number, + 4); + } + } + else + { /* not absolute_section */ + /* need a 32-bit fixup (don't support 8bit non-absolute disps) */ + p = frag_more (4); + insn_size += 4; + fix_new_exp (frag_now, p - frag_now->fr_literal, 4, + i.disps[n], 0, + TC_RELOC(i.disp_reloc[n], BFD_RELOC_32)); + } + } + } + } /* end displacement output */ + + /* output immediate */ + if (i.imm_operands) + { + register unsigned int n; + + for (n = 0; n < i.operands; n++) + { + if (i.imms[n]) + { + if (i.imms[n]->X_op == O_constant) + { + if (i.types[n] & (Imm8 | Imm8S)) + { + p = frag_more (1); + insn_size += 1; + md_number_to_chars (p, + (valueT) i.imms[n]->X_add_number, + 1); + } + else if (i.types[n] & Imm16) + { + p = frag_more (2); + insn_size += 2; + md_number_to_chars (p, + (valueT) i.imms[n]->X_add_number, + 2); + } + else + { + p = frag_more (4); + insn_size += 4; + md_number_to_chars (p, + (valueT) i.imms[n]->X_add_number, + 4); + } + } + else + { /* not absolute_section */ + /* Need a 32-bit fixup (don't support 8bit + non-absolute ims). Try to support other + sizes ... */ + int r_type; + int size; + int pcrel = 0; + + if (i.types[n] & (Imm8 | Imm8S)) + size = 1; + else if (i.types[n] & Imm16) + size = 2; + else + size = 4; + r_type = reloc (size, 0, i.disp_reloc[0]); + p = frag_more (size); + insn_size += size; +#ifdef BFD_ASSEMBLER + if (r_type == BFD_RELOC_32 + && GOT_symbol + && GOT_symbol == i.imms[n]->X_add_symbol + && (i.imms[n]->X_op == O_symbol + || (i.imms[n]->X_op == O_add + && (i.imms[n]->X_op_symbol->sy_value.X_op + == O_subtract)))) + { + r_type = BFD_RELOC_386_GOTPC; + i.imms[n]->X_add_number += 3; + } +#endif + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.imms[n], pcrel, r_type); + } + } + } + } /* end immediate output */ + } + +#ifdef DEBUG386 + if (flag_debug) + { + pi (line, &i); + } +#endif /* DEBUG386 */ + } +} + +/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero + on error. */ + +static int +i386_operand (operand_string) + char *operand_string; +{ + register char *op_string = operand_string; + + /* Address of '\0' at end of operand_string. */ + char *end_of_operand_string = operand_string + strlen (operand_string); + + /* Start and end of displacement string expression (if found). */ + char *displacement_string_start = NULL; + char *displacement_string_end = NULL; + + /* We check for an absolute prefix (differentiating, + for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ + if (*op_string == ABSOLUTE_PREFIX) + { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + + /* Check if operand is a register. */ + if (*op_string == REGISTER_PREFIX) + { + register reg_entry *r; + if (!(r = parse_register (op_string))) + { + as_bad ("bad register name ('%s')", op_string); + return 0; + } + /* Check for segment override, rather than segment register by + searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */ + if ((r->reg_type & (SReg2 | SReg3)) && op_string[3] == ':') + { + switch (r->reg_num) + { + case 0: + i.seg = (seg_entry *) & es; + break; + case 1: + i.seg = (seg_entry *) & cs; + break; + case 2: + i.seg = (seg_entry *) & ss; + break; + case 3: + i.seg = (seg_entry *) & ds; + break; + case 4: + i.seg = (seg_entry *) & fs; + break; + case 5: + i.seg = (seg_entry *) & gs; + break; + } + op_string += 4; /* skip % <x> s : */ + operand_string = op_string; /* Pretend given string starts here. */ + if (!is_digit_char (*op_string) && !is_identifier_char (*op_string) + && *op_string != '(' && *op_string != ABSOLUTE_PREFIX) + { + as_bad ("bad memory operand after segment override"); + return 0; + } + /* Handle case of %es:*foo. */ + if (*op_string == ABSOLUTE_PREFIX) + { + op_string++; + i.types[this_operand] |= JumpAbsolute; + } + goto do_memory_reference; + } + i.types[this_operand] |= r->reg_type; + i.regs[this_operand] = r; + i.reg_operands++; + } + else if (*op_string == IMMEDIATE_PREFIX) + { /* ... or an immediate */ + char *save_input_line_pointer; + segT exp_seg = 0; + expressionS *exp; + + if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) + { + as_bad ("only 1 or 2 immediate operands are allowed"); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.imms[this_operand] = exp; + save_input_line_pointer = input_line_pointer; + input_line_pointer = ++op_string; /* must advance op_string! */ + SKIP_WHITESPACE (); + exp_seg = expression (exp); + input_line_pointer = save_input_line_pointer; + + if (exp->X_op == O_absent) + { + /* missing or bad expr becomes absolute 0 */ + as_bad ("missing or invalid immediate expression '%s' taken as 0", + operand_string); + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + i.types[this_operand] |= Imm; + } + else if (exp->X_op == O_constant) + { + i.types[this_operand] |= + smallest_imm_type ((unsigned long) exp->X_add_number); + } +#ifdef OBJ_AOUT + else if (exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section +#ifdef BFD_ASSEMBLER + && ! bfd_is_com_section (exp_seg) +#endif + ) + { + seg_unimplemented: + as_bad ("Unimplemented segment type %d in parse_operand", exp_seg); + return 0; + } +#endif + else + { + /* this is an address ==> 32bit */ + i.types[this_operand] |= Imm32; + } + /* shorten this type of this operand if the instruction wants + * fewer bits than are present in the immediate. The bit field + * code can put out 'andb $0xffffff, %al', for example. pace + * also 'movw $foo,(%eax)' + */ + switch (i.suffix) + { + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16; + break; + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Imm16 | Imm8 | Imm8S; + break; + } + } + else if (is_digit_char (*op_string) || is_identifier_char (*op_string) + || *op_string == '(') + { + /* This is a memory reference of some sort. */ + register char *base_string; + unsigned int found_base_index_form; + + do_memory_reference: + if (i.mem_operands == MAX_MEMORY_OPERANDS) + { + as_bad ("more than 1 memory reference in instruction"); + return 0; + } + i.mem_operands++; + + /* Determine type of memory operand from opcode_suffix; + no opcode suffix implies general memory references. */ + switch (i.suffix) + { + case BYTE_OPCODE_SUFFIX: + i.types[this_operand] |= Mem8; + break; + case WORD_OPCODE_SUFFIX: + i.types[this_operand] |= Mem16; + break; + case DWORD_OPCODE_SUFFIX: + default: + i.types[this_operand] |= Mem32; + } + + /* Check for base index form. We detect the base index form by + looking for an ')' at the end of the operand, searching + for the '(' matching it, and finding a REGISTER_PREFIX or ',' + after it. */ + base_string = end_of_operand_string - 1; + found_base_index_form = 0; + if (*base_string == ')') + { + unsigned int parens_balanced = 1; + /* We've already checked that the number of left & right ()'s are + equal, so this loop will not be infinite. */ + do + { + base_string--; + if (*base_string == ')') + parens_balanced++; + if (*base_string == '(') + parens_balanced--; + } + while (parens_balanced); + base_string++; /* Skip past '('. */ + if (*base_string == REGISTER_PREFIX || *base_string == ',') + found_base_index_form = 1; + } + + /* If we can't parse a base index register expression, we've found + a pure displacement expression. We set up displacement_string_start + and displacement_string_end for the code below. */ + if (!found_base_index_form) + { + displacement_string_start = op_string; + displacement_string_end = end_of_operand_string; + } + else + { + char *base_reg_name, *index_reg_name, *num_string; + int num; + + i.types[this_operand] |= BaseIndex; + + /* If there is a displacement set-up for it to be parsed later. */ + if (base_string != op_string + 1) + { + displacement_string_start = op_string; + displacement_string_end = base_string - 1; + } + + /* Find base register (if any). */ + if (*base_string != ',') + { + base_reg_name = base_string++; + /* skip past register name & parse it */ + while (isalpha (*base_string)) + base_string++; + if (base_string == base_reg_name + 1) + { + as_bad ("can't find base register name after '(%c'", + REGISTER_PREFIX); + return 0; + } + END_STRING_AND_SAVE (base_string); + if (!(i.base_reg = parse_register (base_reg_name))) + { + as_bad ("bad base register name ('%s')", base_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Now check seperator; must be ',' ==> index reg + OR num ==> no index reg. just scale factor + OR ')' ==> end. (scale factor = 1) */ + if (*base_string != ',' && *base_string != ')') + { + as_bad ("expecting ',' or ')' after base register in `%s'", + operand_string); + return 0; + } + + /* There may index reg here; and there may be a scale factor. */ + if (*base_string == ',' && *(base_string + 1) == REGISTER_PREFIX) + { + index_reg_name = ++base_string; + while (isalpha (*++base_string)); + END_STRING_AND_SAVE (base_string); + if (!(i.index_reg = parse_register (index_reg_name))) + { + as_bad ("bad index register name ('%s')", index_reg_name); + return 0; + } + RESTORE_END_STRING (base_string); + } + + /* Check for scale factor. */ + if (*base_string == ',' && isdigit (*(base_string + 1))) + { + num_string = ++base_string; + while (is_digit_char (*base_string)) + base_string++; + if (base_string == num_string) + { + as_bad ("can't find a scale factor after ','"); + return 0; + } + END_STRING_AND_SAVE (base_string); + /* We've got a scale factor. */ + if (!sscanf (num_string, "%d", &num)) + { + as_bad ("can't parse scale factor from '%s'", num_string); + return 0; + } + RESTORE_END_STRING (base_string); + switch (num) + { /* must be 1 digit scale */ + case 1: + i.log2_scale_factor = 0; + break; + case 2: + i.log2_scale_factor = 1; + break; + case 4: + i.log2_scale_factor = 2; + break; + case 8: + i.log2_scale_factor = 3; + break; + default: + as_bad ("expecting scale factor of 1, 2, 4, 8; got %d", num); + return 0; + } + } + else + { + if (!i.index_reg && *base_string == ',') + { + as_bad ("expecting index register or scale factor after ','; got '%c'", + *(base_string + 1)); + return 0; + } + } + } + + /* If there's an expression begining the operand, parse it, + assuming displacement_string_start and displacement_string_end + are meaningful. */ + if (displacement_string_start) + { + register expressionS *exp; + segT exp_seg = 0; + char *save_input_line_pointer; + exp = &disp_expressions[i.disp_operands]; + i.disps[this_operand] = exp; + i.disp_reloc[this_operand] = NO_RELOC; + i.disp_operands++; + save_input_line_pointer = input_line_pointer; + input_line_pointer = displacement_string_start; + END_STRING_AND_SAVE (displacement_string_end); +#ifndef LEX_AT + { + /* + * We can have operands of the form + * <symbol>@GOTOFF+<nnn> + * Take the easy way out here and copy everything + * into a temporary buffer... + */ + register char *cp; + if ((cp = strchr (input_line_pointer,'@')) != NULL) { + char tmpbuf[BUFSIZ]; + + if(!GOT_symbol) + GOT_symbol = symbol_find_or_make(GLOBAL_OFFSET_TABLE_NAME); + + if (strncmp(cp+1, "PLT", 3) == 0) { + i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+3); + *cp = '@'; + } else if (strncmp(cp+1, "GOTOFF", 6) == 0) { + i.disp_reloc[this_operand] = BFD_RELOC_386_GOTOFF; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+6); + *cp = '@'; + } else if (strncmp(cp+1, "GOT", 3) == 0) { + i.disp_reloc[this_operand] = BFD_RELOC_386_GOT32; + *cp = '\0'; + strcpy(tmpbuf, input_line_pointer); + strcat(tmpbuf, cp+1+3); + *cp = '@'; + } else + as_bad("Bad reloc specifier '%s' in expression", cp+1); + input_line_pointer = tmpbuf; + } + } +#endif + exp_seg = expression (exp); + +#ifdef BFD_ASSEMBLER + /* We do this to make sure that the section symbol is in + the symbol table. We will ultimately change the relocation + to be relative to the beginning of the section */ + if (i.disp_reloc[this_operand] == BFD_RELOC_386_GOTOFF) + { + if (S_IS_LOCAL(exp->X_add_symbol) + && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section) + section_symbol(exp->X_add_symbol->bsym->section); + assert (exp->X_op == O_symbol); + exp->X_op = O_subtract; + exp->X_op_symbol = GOT_symbol; + i.disp_reloc[this_operand] = BFD_RELOC_32; + } +#endif + + if (*input_line_pointer) + as_bad ("Ignoring junk '%s' after expression", input_line_pointer); + RESTORE_END_STRING (displacement_string_end); + input_line_pointer = save_input_line_pointer; + if (exp->X_op == O_absent) + { + /* missing expr becomes absolute 0 */ + as_bad ("missing or invalid displacement '%s' taken as 0", + operand_string); + i.types[this_operand] |= (Disp | Abs); + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + else if (exp->X_op == O_constant) + { + i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number); + } + else if (exp_seg == text_section + || exp_seg == data_section + || exp_seg == bss_section + || exp_seg == undefined_section) + { + i.types[this_operand] |= Disp32; + } + else + { +#ifndef OBJ_AOUT + i.types[this_operand] |= Disp32; +#else + goto seg_unimplemented; +#endif + } + } + + /* Make sure the memory operand we've been dealt is valid. */ + if (i.base_reg && i.index_reg && + !(i.base_reg->reg_type & i.index_reg->reg_type & Reg)) + { + as_bad ("register size mismatch in (base,index,scale) expression"); + return 0; + } + /* + * special case for (%dx) while doing input/output op + */ + if ((i.base_reg && + (i.base_reg->reg_type == (Reg16 | InOutPortReg)) && + (i.index_reg == 0))) + { + i.types[this_operand] |= InOutPortReg; + return 1; + } + if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) || + (i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) + { + as_bad ("base/index register must be 32 bit register"); + return 0; + } + if (i.index_reg && i.index_reg == esp) + { + as_bad ("%s may not be used as an index register", esp->reg_name); + return 0; + } + } + else + { /* it's not a memory operand; argh! */ + as_bad ("invalid char %s begining %s operand '%s'", + output_invalid (*op_string), ordinal_names[this_operand], + op_string); + return 0; + } + return 1; /* normal return */ +} + +/* + * md_estimate_size_before_relax() + * + * Called just before relax(). + * Any symbol that is now undefined will not become defined. + * Return the correct fr_subtype in the frag. + * Return the initial "guess for fr_var" to caller. + * The guess for fr_var is ACTUALLY the growth beyond fr_fix. + * Whatever we do to grow fr_fix or fr_var contributes to our returned value. + * Although it may not be explicit in the frag, pretend fr_var starts with a + * 0 value. + */ +int +md_estimate_size_before_relax (fragP, segment) + register fragS *fragP; + register segT segment; +{ + register unsigned char *opcode; + register int old_fr_fix; + + old_fr_fix = fragP->fr_fix; + opcode = (unsigned char *) fragP->fr_opcode; + /* We've already got fragP->fr_subtype right; all we have to do is check + for un-relaxable symbols. */ + if (S_GET_SEGMENT (fragP->fr_symbol) != segment) + { + /* symbol is undefined in this segment */ + switch (opcode[0]) + { + case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */ + opcode[0] = 0xe9; /* dword disp jmp */ + fragP->fr_fix += 4; + fix_new (fragP, old_fr_fix, 4, + fragP->fr_symbol, + fragP->fr_offset, 1, + (GOT_symbol && /* Not quite right - we should switch on + presence of @PLT, but I cannot see how + to get to that from here. We should have + done this in md_assemble to really + get it right all of the time, but I + think it does not matter that much, as + this will be right most of the time. ERY*/ + S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)? + BFD_RELOC_386_PLT32 : BFD_RELOC_32_PCREL); + break; + + default: + /* This changes the byte-displacement jump 0x7N --> + the dword-displacement jump 0x0f8N */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */ + fragP->fr_fix += 1 + 4; /* we've added an opcode byte */ + fix_new (fragP, old_fr_fix + 1, 4, + fragP->fr_symbol, + fragP->fr_offset, 1, + (GOT_symbol && /* Not quite right - we should switch on + presence of @PLT, but I cannot see how + to get to that from here. ERY */ + S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)? + BFD_RELOC_386_PLT32 : BFD_RELOC_32_PCREL); + break; + } + frag_wane (fragP); + } + return (fragP->fr_var + fragP->fr_fix - old_fr_fix); +} /* md_estimate_size_before_relax() */ + +/* + * md_convert_frag(); + * + * Called after relax() is finished. + * In: Address of frag. + * fr_type == rs_machine_dependent. + * fr_subtype is what the address relaxed to. + * + * Out: Any fixSs and constants are set up. + * Caller will turn frag into a ".space 0". + */ +#ifndef BFD_ASSEMBLER +void +md_convert_frag (headers, sec, fragP) + object_headers *headers; + segT sec; + register fragS *fragP; +#else +void +md_convert_frag (abfd, sec, fragP) + bfd *abfd; + segT sec; + register fragS *fragP; +#endif +{ + register unsigned char *opcode; + unsigned char *where_to_put_displacement = NULL; + unsigned int target_address; + unsigned int opcode_address; + unsigned int extension = 0; + int displacement_from_opcode_start; + + opcode = (unsigned char *) fragP->fr_opcode; + + /* Address we want to reach in file space. */ + target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; +#ifdef BFD_ASSEMBLER /* not needed otherwise? */ + target_address += fragP->fr_symbol->sy_frag->fr_address; +#endif + + /* Address opcode resides at in file space. */ + opcode_address = fragP->fr_address + fragP->fr_fix; + + /* Displacement from opcode start to fill into instruction. */ + displacement_from_opcode_start = target_address - opcode_address; + + switch (fragP->fr_subtype) + { + case ENCODE_RELAX_STATE (COND_JUMP, BYTE): + case ENCODE_RELAX_STATE (UNCOND_JUMP, BYTE): + /* don't have to change opcode */ + extension = 1; /* 1 opcode + 1 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, WORD): + opcode[1] = TWO_BYTE_OPCODE_ESCAPE; + opcode[2] = opcode[0] + 0x10; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 4; /* 3 opcode + 2 displacement */ + where_to_put_displacement = &opcode[3]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD): + opcode[1] = 0xe9; + opcode[0] = WORD_PREFIX_OPCODE; + extension = 3; /* 2 opcode + 2 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, DWORD): + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + extension = 5; /* 2 opcode + 4 displacement */ + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, DWORD): + opcode[0] = 0xe9; + extension = 4; /* 1 opcode + 4 displacement */ + where_to_put_displacement = &opcode[1]; + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + /* now put displacement after opcode */ + md_number_to_chars ((char *) where_to_put_displacement, + (valueT) (displacement_from_opcode_start - extension), + SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); + fragP->fr_fix += extension; +} + + +int md_short_jump_size = 2; /* size of byte displacement jmp */ +int md_long_jump_size = 5; /* size of dword displacement jmp */ +const int md_reloc_size = 8; /* Size of relocation record */ + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + long offset; + + offset = to_addr - (from_addr + 2); + md_number_to_chars (ptr, (valueT) 0xeb, 1); /* opcode for byte-disp jump */ + md_number_to_chars (ptr + 1, (valueT) offset, 1); +} + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + long offset; + + if (flag_do_long_jump) + { + offset = to_addr - S_GET_VALUE (to_symbol); + md_number_to_chars (ptr, (valueT) 0xe9, 1);/* opcode for long jmp */ + md_number_to_chars (ptr + 1, (valueT) offset, 4); + fix_new (frag, (ptr + 1) - frag->fr_literal, 4, + to_symbol, (offsetT) 0, 0, BFD_RELOC_32); + } + else + { + offset = to_addr - (from_addr + 5); + md_number_to_chars (ptr, (valueT) 0xe9, 1); + md_number_to_chars (ptr + 1, (valueT) offset, 4); + } +} + +/* Apply a fixup (fixS) to segment data, once it has been determined + by our caller that we have all the info we need to fix it up. + + On the 386, immediates, displacements, and data pointers are all in + the same (little-endian) format, so we don't need to care about which + we are handling. */ + +int +md_apply_fix3 (fixP, valp, seg) + fixS *fixP; /* The fix we're to put in. */ + valueT *valp; /* Pointer to the value of the bits. */ + segT seg; /* Segment fix is from. */ +{ + register char *p = fixP->fx_where + fixP->fx_frag->fr_literal; + valueT value = *valp; + +#if defined (BFD_ASSEMBLER) && !defined (TE_Mach) + /* + * This is a hack. There should be a better way to + * handle this. + */ + if (fixP->fx_r_type == BFD_RELOC_32_PCREL && fixP->fx_addsy) + { +#ifndef OBJ_AOUT + if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + value += fixP->fx_where + fixP->fx_frag->fr_address; +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && (S_GET_SEGMENT (fixP->fx_addsy) == seg + || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)) + { + /* Yes, we add the values in twice. This is because + bfd_perform_relocation subtracts them out again. I think + bfd_perform_relocation is broken, but I don't dare change + it. FIXME. */ + value += fixP->fx_where + fixP->fx_frag->fr_address; + } +#endif + } + + /* Fix a few things - the dynamic linker expects certain values here, + and we must not dissappoint it. */ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && fixP->fx_addsy) + switch(fixP->fx_r_type) { + case BFD_RELOC_386_PLT32: + /* Make the jump instruction point to the address of the operand. At + runtime we merely add the offset to the actual PLT entry. */ + value = 0xfffffffc; + break; + case BFD_RELOC_386_GOTPC: +/* + * This is tough to explain. We end up with this one if we have + * operands that look like "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal + * here is to obtain the absolute address of the GOT, and it is strongly + * preferable from a performance point of view to avoid using a runtime + * relocation for this. The actual sequence of instructions often look + * something like: + * + * call .L66 + * .L66: + * popl %ebx + * addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx + * + * The call and pop essentially return the absolute address of + * the label .L66 and store it in %ebx. The linker itself will + * ultimately change the first operand of the addl so that %ebx points to + * the GOT, but to keep things simple, the .o file must have this operand + * set so that it generates not the absolute address of .L66, but the + * absolute address of itself. This allows the linker itself simply + * treat a GOTPC relocation as asking for a pcrel offset to the GOT to be + * added in, and the addend of the relocation is stored in the operand + * field for the instruction itself. + * + * Our job here is to fix the operand so that it would add the correct + * offset so that %ebx would point to itself. The thing that is tricky is + * that .-.L66 will point to the beginning of the instruction, so we need + * to further modify the operand so that it will point to itself. + * There are other cases where you have something like: + * + * .long $_GLOBAL_OFFSET_TABLE_+[.-.L66] + * + * and here no correction would be required. Internally in the assembler + * we treat operands of this form as not being pcrel since the '.' is + * explicitly mentioned, and I wonder whether it would simplify matters + * to do it this way. Who knows. In earlier versions of the PIC patches, + * the pcrel_adjust field was used to store the correction, but since the + * expression is not pcrel, I felt it would be confusing to do it this way. + */ + value -= 1; + break; + case BFD_RELOC_386_GOT32: + value = 0; /* Fully resolved at runtime. No addend. */ + break; + case BFD_RELOC_386_GOTOFF: + break; + + default: + break; + } +#endif + +#endif + md_number_to_chars (p, value, fixP->fx_size); + + return 1; +} + +#if 0 +/* This is never used. */ +long /* Knows about the byte order in a word. */ +md_chars_to_number (con, nbytes) + unsigned char con[]; /* Low order byte 1st. */ + int nbytes; /* Number of bytes in the input. */ +{ + long retval; + for (retval = 0, con += nbytes - 1; nbytes--; con--) + { + retval <<= BITS_PER_CHAR; + retval |= *con; + } + return retval; +} +#endif /* 0 */ + + +#define MAX_LITTLENUMS 6 + +/* Turn the string pointed to by litP into a floating point constant of type + type, and emit the appropriate bytes. The number of LITTLENUMS emitted + is stored in *sizeP . An error message is returned, or NULL on OK. */ +char * +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) + { + case 'f': + case 'F': + prec = 2; + break; + + case 'd': + case 'D': + prec = 4; + break; + + case 'x': + case 'X': + prec = 5; + break; + + default: + *sizeP = 0; + return "Bad call to md_atof ()"; + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * sizeof (LITTLENUM_TYPE); + /* This loops outputs the LITTLENUMs in REVERSE order; in accord with + the bigendian 386. */ + for (wordP = words + prec - 1; prec--;) + { + md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + return 0; +} + +char output_invalid_buf[8]; + +static char * +output_invalid (c) + char c; +{ + if (isprint (c)) + sprintf (output_invalid_buf, "'%c'", c); + else + sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); + return output_invalid_buf; +} + +/* reg_string starts *before* REGISTER_PREFIX */ +static reg_entry * +parse_register (reg_string) + char *reg_string; +{ + register char *s = reg_string; + register char *p; + char reg_name_given[MAX_REG_NAME_SIZE]; + + s++; /* skip REGISTER_PREFIX */ + for (p = reg_name_given; is_register_char (*s); p++, s++) + { + *p = register_chars[(unsigned char) *s]; + if (p >= reg_name_given + MAX_REG_NAME_SIZE) + return (reg_entry *) 0; + } + *p = '\0'; + return (reg_entry *) hash_find (reg_hash, reg_name_given); +} + +#ifdef OBJ_ELF +CONST char *md_shortopts = "kmVQ:"; +#else +CONST char *md_shortopts = "m"; +#endif +struct option md_longopts[] = { + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); + +int +md_parse_option (c, arg) + int c; + char *arg; +{ + switch (c) + { + case 'm': + flag_do_long_jump = 1; + break; + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + /* -k: Ignore for FreeBSD compatibility. */ + case 'k': + break; + + /* -V: SVR4 argument to print version ID. */ + case 'V': + print_version_id (); + break; + + /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section + should be emitted or not. FIXME: Not implemented. */ + case 'Q': + break; +#endif + + default: + return 0; + } + return 1; +} + +void +md_show_usage (stream) + FILE *stream; +{ + fprintf (stream, "\ +-m do long jump\n"); +} + +#ifdef BFD_ASSEMBLER +#ifdef OBJ_MAYBE_ELF +#ifdef OBJ_MAYBE_COFF + +/* Pick the target format to use. */ + +const char * +i386_target_format () +{ + switch (OUTPUT_FLAVOR) + { + case bfd_target_coff_flavour: + return "coff-i386"; + case bfd_target_elf_flavour: + return "elf32-i386"; + default: + abort (); + return NULL; + } +} + +#endif /* OBJ_MAYBE_COFF */ +#endif /* OBJ_MAYBE_ELF */ +#endif /* BFD_ASSEMBLER */ + +/* ARGSUSED */ +symbolS * +md_undefined_symbol (name) + char *name; +{ + if (*name == '_' && *(name+1) == 'G' + && strcmp(name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if(!GOT_symbol) + { + if(symbol_find(name)) + as_bad("GOT already in symbol table"); + GOT_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + }; + return GOT_symbol; + } + return 0; +} + +/* Round up a section size to the appropriate boundary. */ +valueT +md_section_align (segment, size) + segT segment; + valueT size; +{ +#ifdef OBJ_AOUT +#ifdef BFD_ASSEMBLER + /* For a.out, force the section size to be aligned. If we don't do + this, BFD will align it for us, but it will not write out the + final bytes of the section. This may be a bug in BFD, but it is + easier to fix it here since that is how the other a.out targets + work. */ + int align; + + align = bfd_get_section_alignment (stdoutput, segment); + size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); +#endif +#endif + + return size; +} + +/* Exactly what point is a PC-relative offset relative TO? On the + i386, they're relative to the address of the offset, plus its + size. (??? Is this right? FIXME-SOON!) */ +long +md_pcrel_from (fixP) + fixS *fixP; +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +#ifndef I386COFF + +static void +s_bss (ignore) + int ignore; +{ + register int temp; + + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); +} + +#endif + + +#ifdef BFD_ASSEMBLER + +void +i386_validate_fix (fixp) + fixS *fixp; +{ + if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + { + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + fixp->fx_subsy = 0; + } +} + +#define F(SZ,PCREL) (((SZ) << 1) + (PCREL)) +#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break + +arelent * +tc_gen_reloc (section, fixp) + asection *section; + fixS *fixp; +{ + arelent *rel; + bfd_reloc_code_real_type code; + + switch(fixp->fx_r_type) + { + case BFD_RELOC_386_PLT32: + case BFD_RELOC_386_GOT32: + case BFD_RELOC_386_GOTOFF: + case BFD_RELOC_386_GOTPC: + code = fixp->fx_r_type; + break; + default: + switch (F (fixp->fx_size, fixp->fx_pcrel)) + { + MAP (1, 0, BFD_RELOC_8); + MAP (2, 0, BFD_RELOC_16); + MAP (4, 0, BFD_RELOC_32); + MAP (1, 1, BFD_RELOC_8_PCREL); + MAP (2, 1, BFD_RELOC_16_PCREL); + MAP (4, 1, BFD_RELOC_32_PCREL); + default: + as_bad ("Can not do %d byte %srelocation", fixp->fx_size, + fixp->fx_pcrel ? "pc-relative " : ""); + } + } +#undef MAP +#undef F + + if (code == BFD_RELOC_32 + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + code = BFD_RELOC_386_GOTPC; + + rel = (arelent *) xmalloc (sizeof (arelent)); + rel->sym_ptr_ptr = &fixp->fx_addsy->bsym; + rel->address = fixp->fx_frag->fr_address + fixp->fx_where; + if (fixp->fx_pcrel) + rel->addend = fixp->fx_addnumber; + else + rel->addend = 0; + + rel->howto = bfd_reloc_type_lookup (stdoutput, code); + if (rel->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "Cannot represent relocation type %s", + bfd_get_reloc_code_name (code)); + /* Set howto to a garbage value so that we can keep going. */ + rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + assert (rel->howto != NULL); + } + + return rel; +} + +#else /* ! BFD_ASSEMBLER */ + +#if (defined(OBJ_AOUT) | defined(OBJ_BOUT)) +void +tc_aout_fix_to_chars (where, fixP, segment_address_in_file) + char *where; + fixS *fixP; + relax_addressT segment_address_in_file; +{ + /* + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ + + static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2}; + long r_symbolnum; + + know (fixP->fx_addsy != NULL); + + md_number_to_chars (where, + (valueT) (fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file), + 4); + + r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) + ? S_GET_TYPE (fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + where[6] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[4] = r_symbolnum & 0x0ff; + where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 3) & 0x08) + | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) + | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f)); +} + +#endif /* OBJ_AOUT or OBJ_BOUT */ + +#if defined (I386COFF) + +short +tc_coff_fix2rtype (fixP) + fixS *fixP; +{ + if (fixP->fx_r_type == R_IMAGEBASE) + return R_IMAGEBASE; + + return (fixP->fx_pcrel ? + (fixP->fx_size == 1 ? R_PCRBYTE : + fixP->fx_size == 2 ? R_PCRWORD : + R_PCRLONG) : + (fixP->fx_size == 1 ? R_RELBYTE : + fixP->fx_size == 2 ? R_RELWORD : + R_DIR32)); +} + +int +tc_coff_sizemachdep (frag) + fragS *frag; +{ + if (frag->fr_next) + return (frag->fr_next->fr_address - frag->fr_address); + else + return 0; +} + +#endif /* I386COFF */ + +#endif /* BFD_ASSEMBLER? */ + +/* end of tc-i386.c */ diff --git a/contrib/binutils/gas/config/tc-i386.h b/contrib/binutils/gas/config/tc-i386.h new file mode 100644 index 0000000..8205f53 --- /dev/null +++ b/contrib/binutils/gas/config/tc-i386.h @@ -0,0 +1,434 @@ +/* tc-i386.h -- Header file for tc-i386.c + Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef TC_I386 +#define TC_I386 1 + +#ifdef ANSI_PROTOTYPES +struct fix; +#endif + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#ifdef TE_LYNX +#define TARGET_FORMAT "coff-i386-lynx" +#endif + +#ifdef BFD_ASSEMBLER +/* This is used to determine relocation types in tc-i386.c. The first + parameter is the current relocation type, the second one is the desired + type. The idea is that if the original type is already some kind of PIC + relocation, we leave it alone, otherwise we give it the desired type */ + +#define TC_RELOC(X,Y) (((X) != BFD_RELOC_386_PLT32 && \ + (X) != BFD_RELOC_386_GOTOFF && \ + (X) != BFD_RELOC_386_GOT32 && \ + (X) != BFD_RELOC_386_GOTPC) ? Y : X) + +#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X) +extern int tc_i386_fix_adjustable PARAMS ((struct fix *)); + +/* This is the relocation type for direct references to GLOBAL_OFFSET_TABLE. + * It comes up in complicated expressions such as + * _GLOBAL_OFFSET_TABLE_+[.-.L284], which cannot be expressed normally with + * the regular expressions. The fixup specified here when used at runtime + * implies that we should add the address of the GOT to the specified location, + * and as a result we have simplified the expression into something we can use. + */ +#define TC_RELOC_GLOBAL_OFFSET_TABLE BFD_RELOC_386_GOTPC + +/* This expression evaluates to false if the relocation is for a local object + for which we still want to do the relocation at runtime. True if we + are willing to perform this relocation while building the .o file. + This is only used for pcrel relocations, so GOTOFF does not need to be + checked here. I am not sure if some of the others are ever used with + pcrel, but it is easier to be safe than sorry. */ + +#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ + ((FIX)->fx_r_type != BFD_RELOC_386_PLT32 \ + && (FIX)->fx_r_type != BFD_RELOC_386_GOT32 \ + && (FIX)->fx_r_type != BFD_RELOC_386_GOTPC) + +#define TARGET_ARCH bfd_arch_i386 + +#ifdef OBJ_AOUT +#ifdef TE_NetBSD +#define TARGET_FORMAT "a.out-i386-netbsd" +#endif +#ifdef TE_386BSD +#define TARGET_FORMAT "a.out-i386-bsd" +#endif +#ifdef TE_LINUX +#define TARGET_FORMAT "a.out-i386-linux" +#endif +#ifdef TE_Mach +#define TARGET_FORMAT "a.out-mach3" +#endif +#ifdef TE_DYNIX +#define TARGET_FORMAT "a.out-i386-dynix" +#endif +#ifndef TARGET_FORMAT +#define TARGET_FORMAT "a.out-i386" +#endif +#endif /* OBJ_AOUT */ + +#ifdef OBJ_ELF +#define TARGET_FORMAT "elf32-i386" +#endif + +#ifdef OBJ_MAYBE_ELF +#ifdef OBJ_MAYBE_COFF +extern const char *i386_target_format PARAMS ((void)); +#define TARGET_FORMAT i386_target_format () +#endif +#endif + +#else /* ! BFD_ASSEMBLER */ + +/* COFF STUFF */ + +#define COFF_MAGIC I386MAGIC +#define BFD_ARCH bfd_arch_i386 +#define COFF_FLAGS F_AR32WR +#define TC_COUNT_RELOC(x) ((x)->fx_addsy || (x)->fx_r_type==7) +#define TC_FORCE_RELOCATION(x) ((x)->fx_r_type==7) +#define TC_COFF_FIX2RTYPE(fixP) tc_coff_fix2rtype(fixP) +extern short tc_coff_fix2rtype PARAMS ((struct fix *)); +#define TC_COFF_SIZEMACHDEP(frag) tc_coff_sizemachdep(frag) +extern int tc_coff_sizemachdep PARAMS ((fragS *frag)); +#define SUB_SEGMENT_ALIGN(SEG) 2 +#define TC_RVA_RELOC 7 +/* Need this for PIC relocations */ +#define NEED_FX_R_TYPE + + +#ifdef TE_386BSD +/* The BSDI linker apparently rejects objects with a machine type of + M_386 (100). */ +#define AOUT_MACHTYPE 0 +#else +#define AOUT_MACHTYPE 100 +#endif + +#undef REVERSE_SORT_RELOCS + +#endif /* ! BFD_ASSEMBLER */ + +#ifdef BFD_ASSEMBLER +#define NO_RELOC BFD_RELOC_NONE +#else +#define NO_RELOC 0 +#endif +#define tc_coff_symbol_emit_hook(a) ; /* not used */ + +#ifndef BFD_ASSEMBLER +#ifndef OBJ_AOUT +#ifndef TE_PE +/* Local labels starts with .L */ +#define LOCAL_LABEL(name) (name[0] == '.' \ + && (name[1] == 'L' || name[1] == 'X' || name[1] == '.')) +#endif +#endif +#endif + +#define LOCAL_LABELS_FB 1 + +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ + +#define MAX_OPERANDS 3 /* max operands per insn */ +#define MAX_PREFIXES 5 /* max prefixes per opcode */ +#define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn */ +#define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn (lcall uses 2) */ + +/* we define the syntax here (modulo base,index,scale syntax) */ +#define REGISTER_PREFIX '%' +#define IMMEDIATE_PREFIX '$' +#define ABSOLUTE_PREFIX '*' +#define PREFIX_SEPERATOR '/' + +#define TWO_BYTE_OPCODE_ESCAPE 0x0f +#define NOP_OPCODE (char) 0x90 + +/* register numbers */ +#define EBP_REG_NUM 5 +#define ESP_REG_NUM 4 + +/* modrm_byte.regmem for twobyte escape */ +#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM +/* index_base_byte.index for no index register addressing */ +#define NO_INDEX_REGISTER ESP_REG_NUM +/* index_base_byte.base for no base register addressing */ +#define NO_BASE_REGISTER EBP_REG_NUM + +/* these are the att as opcode suffixes, making movl --> mov, for example */ +#define DWORD_OPCODE_SUFFIX 'l' +#define WORD_OPCODE_SUFFIX 'w' +#define BYTE_OPCODE_SUFFIX 'b' + +/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ +#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ +#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) + +#define END_OF_INSN '\0' + +/* + When an operand is read in it is classified by its type. This type includes + all the possible ways an operand can be used. Thus, '%eax' is both 'register + # 0' and 'The Accumulator'. In our language this is expressed by OR'ing + 'Reg32' (any 32 bit register) and 'Acc' (the accumulator). + Operands are classified so that we can match given operand types with + the opcode table in i386-opcode.h. + */ +#define Unknown 0x0 +/* register */ +#define Reg8 0x1 /* 8 bit reg */ +#define Reg16 0x2 /* 16 bit reg */ +#define Reg32 0x4 /* 32 bit reg */ +#define Reg (Reg8|Reg16|Reg32) /* gen'l register */ +#define WordReg (Reg16|Reg32) /* for push/pop operands */ +/* immediate */ +#define Imm8 0x8 /* 8 bit immediate */ +#define Imm8S 0x10 /* 8 bit immediate sign extended */ +#define Imm16 0x20 /* 16 bit immediate */ +#define Imm32 0x40 /* 32 bit immediate */ +#define Imm1 0x80 /* 1 bit immediate */ +#define ImmUnknown Imm32 /* for unknown expressions */ +#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */ +/* memory */ +#define Disp8 0x200 /* 8 bit displacement (for jumps) */ +#define Disp16 0x400 /* 16 bit displacement */ +#define Disp32 0x800 /* 32 bit displacement */ +#define Disp (Disp8|Disp16|Disp32) /* General displacement */ +#define DispUnknown Disp32 /* for unknown size displacements */ +#define Mem8 0x1000 +#define Mem16 0x2000 +#define Mem32 0x4000 +#define BaseIndex 0x8000 +#define Mem (Disp|Mem8|Mem16|Mem32|BaseIndex) /* General memory */ +#define WordMem (Mem16|Mem32|Disp|BaseIndex) +#define ByteMem (Mem8|Disp|BaseIndex) +/* specials */ +#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */ +#define ShiftCount 0x20000 /* register to hold shift cound = cl */ +#define Control 0x40000 /* Control register */ +#define Debug 0x80000 /* Debug register */ +#define Test 0x100000 /* Test register */ +#define FloatReg 0x200000 /* Float register */ +#define FloatAcc 0x400000 /* Float stack top %st(0) */ +#define SReg2 0x800000 /* 2 bit segment register */ +#define SReg3 0x1000000 /* 3 bit segment register */ +#define Acc 0x2000000 /* Accumulator %al or %ax or %eax */ +#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc) +#define JumpAbsolute 0x4000000 +#define Abs8 0x08000000 +#define Abs16 0x10000000 +#define Abs32 0x20000000 +#define Abs (Abs8|Abs16|Abs32) +#define RegMMX 0x40000000 /* MMX register */ + +#define Byte (Reg8|Imm8|Imm8S) +#define Word (Reg16|Imm16) +#define DWord (Reg32|Imm32) + +#define SMALLEST_DISP_TYPE(num) \ + fits_in_signed_byte(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32) + +typedef struct +{ + /* instruction name sans width suffix ("mov" for movl insns) */ + char *name; + + /* how many operands */ + unsigned int operands; + + /* base_opcode is the fundamental opcode byte with a optional prefix(es). */ + unsigned int base_opcode; + + /* extension_opcode is the 3 bit extension for group <n> insns. + If this template has no extension opcode (the usual case) use None */ + unsigned char extension_opcode; +#define None 0xff /* If no extension_opcode is possible. */ + + /* the bits in opcode_modifier are used to generate the final opcode from + the base_opcode. These bits also are used to detect alternate forms of + the same instruction */ + unsigned int opcode_modifier; + + /* opcode_modifier bits: */ +#define W 0x1 /* set if operands are words or dwords */ +#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */ + /* direction flag for floating insns: MUST BE 0x400 */ +#define FloatD 0x400 + /* shorthand */ +#define DW (D|W) +#define ShortForm 0x10 /* register is in low 3 bits of opcode */ +#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */ +#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */ +#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */ +#define Jump 0x100 /* special case for jump insns. */ +#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ + /* 0x400 CANNOT BE USED since it's already used by FloatD above */ +#define DONT_USE 0x400 +#define NoModrm 0x800 +#define Modrm 0x1000 +#define imulKludge 0x2000 +#define JumpByte 0x4000 +#define JumpDword 0x8000 +#define ReverseRegRegmem 0x10000 +#define Data16 0x20000 /* needs data prefix if in 32-bit mode */ +#define Data32 0x40000 /* needs data prefix if in 16-bit mode */ +#define iclrKludge 0x80000 /* used to convert clr to xor */ + + /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the + instuction comes in byte, word, and dword sizes and is encoded into + machine code in the canonical way. */ +#define COMES_IN_ALL_SIZES (W) + + /* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the + source and destination operands can be reversed by setting either + the D (for integer insns) or the FloatD (for floating insns) bit + in base_opcode. */ +#define COMES_IN_BOTH_DIRECTIONS (D|FloatD) + + /* operand_types[i] describes the type of operand i. This is made + by OR'ing together all of the possible type masks. (e.g. + 'operand_types[i] = Reg|Imm' specifies that operand i can be + either a register or an immediate operand */ + unsigned int operand_types[3]; +} +template; + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. + */ +typedef struct + { + template *start; + template *end; + } templates; + +/* these are for register name --> number & type hash lookup */ +typedef struct + { + char *reg_name; + unsigned int reg_type; + unsigned int reg_num; + } + +reg_entry; + +typedef struct + { + char *seg_name; + unsigned int seg_prefix; + } + +seg_entry; + +/* these are for prefix name --> prefix code hash lookup */ +typedef struct + { + char *prefix_name; + unsigned char prefix_code; + } + +prefix_entry; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct + { + unsigned regmem:3; /* codes register or memory operand */ + unsigned reg:3; /* codes register operand (or extended opcode) */ + unsigned mode:2; /* how to interpret regmem & reg */ + } + +modrm_byte; + +/* 386 opcode byte to code indirect addressing. */ +typedef struct + { + unsigned base:3; + unsigned index:3; + unsigned scale:2; + } + +base_index_byte; + +/* The name of the global offset table generated by the compiler. Allow + this to be overridden if need be. */ +#ifndef GLOBAL_OFFSET_TABLE_NAME +#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" +#endif + +#ifdef BFD_ASSEMBLER +void i386_validate_fix PARAMS ((struct fix *)); +#define TC_VALIDATE_FIX(FIXP,SEGTYPE,SKIP) i386_validate_fix(FIXP) +#endif + +#endif /* TC_I386 */ + +#define md_operand(x) + +extern const struct relax_type md_relax_table[]; +#define TC_GENERIC_RELAX_TABLE md_relax_table + + +extern int flag_16bit_code; + +#define md_do_align(n, fill, len, max, around) \ +if ((n) && !need_pass_2 \ + && (!(fill) || ((char)*(fill) == (char)0x90 && (len) == 1)) \ + && now_seg != data_section && now_seg != bss_section) \ + { \ + char *p; \ + p = frag_var (rs_align_code, 15, 1, (relax_substateT) max, \ + (symbolS *) 0, (offsetT) (n), (char *) 0); \ + *p = 0x90; \ + goto around; \ + } + +extern void i386_align_code PARAMS ((fragS *, int)); + +#define HANDLE_ALIGN(fragP) \ +if (fragP->fr_type == rs_align_code) \ + i386_align_code (fragP, (fragP->fr_next->fr_address \ + - fragP->fr_address \ + - fragP->fr_fix)); + +/* call md_apply_fix3 with segment instead of md_apply_fix */ +#define MD_APPLY_FIX3 + +void i386_print_statistics PARAMS ((FILE *)); +#define tc_print_statistics i386_print_statistics + +#define md_number_to_chars number_to_chars_littleendian + +#ifdef SCO_ELF +#define tc_init_after_args() sco_id () +extern void sco_id PARAMS ((void)); +#endif + +/* end of tc-i386.h */ diff --git a/contrib/binutils/gas/config/tc-m68851.h b/contrib/binutils/gas/config/tc-m68851.h new file mode 100644 index 0000000..0f6d741 --- /dev/null +++ b/contrib/binutils/gas/config/tc-m68851.h @@ -0,0 +1,304 @@ +/* This file is tc-m68851.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * pmmu.h + */ + +/* I suppose we have to copyright this file. Someone on the net sent it + to us as part of the changes for the m68851 Memory Management Unit */ + +/* Copyright (C) 1987 Free Software Foundation, Inc. + + This file is part of Gas, the GNU Assembler. + + The GNU assembler is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the GNU Assembler General + Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + the GNU Assembler, but only under the conditions described in the + GNU Assembler General Public License. A copy of this license is + supposed to have been given to you along with the GNU Assembler + so you can know your rights and responsibilities. It should be + in a file named COPYING. Among other things, the copyright + notice and this notice must be preserved on all copies. */ + +#ifdef m68851 + +/* + I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + P pmmu register + Possible values: + 000 TC Translation Control reg + 100 CAL Current Access Level + 101 VAL Validate Access Level + 110 SCC Stack Change Control + 111 AC Access Control + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer + 010 SRP Supervisor Root Pointer + 011 CRP Cpu Root Pointer + + f function code register + 0 SFC + 1 DFC + + V VAL register only + + X BADx, BACx + 100 BAD Breakpoint Acknowledge Data + 101 BAC Breakpoint Acknowledge Control + + Y PSR + Z PCSR + + | memory (modes 2-6, 7.*) + + */ + +/* + * these defines should be in m68k.c but + * i put them here to keep all the m68851 stuff + * together -rab + * JF--Make sure these #s don't clash with the ones in m68k.c + * That would be BAD. + */ +#define TC (FPS+1) /* 48 */ +#define DRP (TC+1) /* 49 */ +#define SRP (DRP+1) /* 50 */ +#define CRP (SRP+1) /* 51 */ +#define CAL (CRP+1) /* 52 */ +#define VAL (CAL+1) /* 53 */ +#define SCC (VAL+1) /* 54 */ +#define AC (SCC+1) /* 55 */ +#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */ +#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */ +#define PSR (BAC+8) /* 72 */ +#define PCSR (PSR+1) /* 73 */ + +/* name */ /* opcode */ /* match */ /* args */ + +{"pbac", one(0xf0c7), one(0xffbf), "Bc"}, +{"pbacw", one(0xf087), one(0xffbf), "Bc"}, +{"pbas", one(0xf0c6), one(0xffbf), "Bc"}, +{"pbasw", one(0xf086), one(0xffbf), "Bc"}, +{"pbbc", one(0xf0c1), one(0xffbf), "Bc"}, +{"pbbcw", one(0xf081), one(0xffbf), "Bc"}, +{"pbbs", one(0xf0c0), one(0xffbf), "Bc"}, +{"pbbsw", one(0xf080), one(0xffbf), "Bc"}, +{"pbcc", one(0xf0cf), one(0xffbf), "Bc"}, +{"pbccw", one(0xf08f), one(0xffbf), "Bc"}, +{"pbcs", one(0xf0ce), one(0xffbf), "Bc"}, +{"pbcsw", one(0xf08e), one(0xffbf), "Bc"}, +{"pbgc", one(0xf0cd), one(0xffbf), "Bc"}, +{"pbgcw", one(0xf08d), one(0xffbf), "Bc"}, +{"pbgs", one(0xf0cc), one(0xffbf), "Bc"}, +{"pbgsw", one(0xf08c), one(0xffbf), "Bc"}, +{"pbic", one(0xf0cb), one(0xffbf), "Bc"}, +{"pbicw", one(0xf08b), one(0xffbf), "Bc"}, +{"pbis", one(0xf0ca), one(0xffbf), "Bc"}, +{"pbisw", one(0xf08a), one(0xffbf), "Bc"}, +{"pblc", one(0xf0c3), one(0xffbf), "Bc"}, +{"pblcw", one(0xf083), one(0xffbf), "Bc"}, +{"pbls", one(0xf0c2), one(0xffbf), "Bc"}, +{"pblsw", one(0xf082), one(0xffbf), "Bc"}, +{"pbsc", one(0xf0c5), one(0xffbf), "Bc"}, +{"pbscw", one(0xf085), one(0xffbf), "Bc"}, +{"pbss", one(0xf0c4), one(0xffbf), "Bc"}, +{"pbssw", one(0xf084), one(0xffbf), "Bc"}, +{"pbwc", one(0xf0c9), one(0xffbf), "Bc"}, +{"pbwcw", one(0xf089), one(0xffbf), "Bc"}, +{"pbws", one(0xf0c8), one(0xffbf), "Bc"}, +{"pbwsw", one(0xf088), one(0xffbf), "Bc"}, + + +{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"}, +{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"}, +{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"}, +{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"}, +{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"}, +{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"}, +{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"}, +{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"}, +{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"}, +{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"}, +{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"}, +{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"}, +{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"}, + +{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" }, + +{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" }, +{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" }, +{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" }, +{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" }, +{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" }, +{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" }, + +{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" }, +{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" }, +{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" }, +{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" }, +{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"}, + +{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" }, + +{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" }, +{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" }, +{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" }, +{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" }, + + /* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */ +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" }, +{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" }, +{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" }, + + /* BADx, BACx */ +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" }, +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" }, + + /* PSR, PCSR */ + /* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */ +{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" }, +{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" }, +{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" }, + +{"prestore", one(0xf140), one(0xffc0), "&s"}, +{"prestore", one(0xf158), one(0xfff8), "+s"}, +{"psave", one(0xf100), one(0xffc0), "&s"}, +{"psave", one(0xf100), one(0xffc0), "+s"}, + +{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"}, +{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"}, +{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"}, +{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"}, +{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"}, +{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"}, +{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"}, +{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"}, +{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"}, +{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"}, +{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"}, +{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"}, +{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"}, +{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"}, +{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"}, +{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"}, + +{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" }, +{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" }, +{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" }, +{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" }, +{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" }, + +{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"}, +{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"}, +{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""}, + +{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"}, +{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"}, +{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""}, + +{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"}, +{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"}, +{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""}, + +{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"}, +{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"}, +{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""}, + +{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"}, +{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"}, +{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""}, + +{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"}, +{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"}, +{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""}, + +{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"}, +{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"}, +{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""}, + +{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"}, +{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"}, +{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""}, + +{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"}, +{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"}, +{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""}, + +{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"}, +{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"}, +{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""}, + +{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"}, +{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"}, +{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""}, + +{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"}, +{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"}, +{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""}, + +{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"}, +{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"}, +{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""}, + +{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"}, +{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"}, +{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""}, + +{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"}, +{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"}, +{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""}, + +{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"}, +{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"}, +{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""}, + +{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"}, +{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" }, + +#endif /* m68851 */ + +/* end of tc-m68851.h */ diff --git a/contrib/binutils/gas/config/tc-sh.c b/contrib/binutils/gas/config/tc-sh.c new file mode 100644 index 0000000..0c0bf4b --- /dev/null +++ b/contrib/binutils/gas/config/tc-sh.c @@ -0,0 +1,2110 @@ +/* tc-sh.c -- Assemble code for the Hitachi Super-H + Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* + Written By Steve Chamberlain + sac@cygnus.com + */ + +#include <stdio.h> +#include "as.h" +#include "bfd.h" +#include "subsegs.h" +#define DEFINE_TABLE +#include "opcodes/sh-opc.h" +#include <ctype.h> +const char comment_chars[] = "!"; +const char line_separator_chars[] = ";"; +const char line_comment_chars[] = "!#"; + +static void s_uses PARAMS ((int)); + +static void sh_count_relocs PARAMS ((bfd *, segT, PTR)); +static void sh_frob_section PARAMS ((bfd *, segT, PTR)); + +/* This table describes all the machine specific pseudo-ops the assembler + has to support. The fields are: + pseudo-op name without dot + function to call to execute this pseudo-op + Integer arg to pass to the function + */ + +void cons (); +void s_align_bytes (); + +int shl = 0; + +static void +little (ignore) + int ignore; +{ + shl = 1; + target_big_endian = 0; +} + +const pseudo_typeS md_pseudo_table[] = +{ + {"int", cons, 4}, + {"word", cons, 2}, + {"form", listing_psize, 0}, + {"little", little, 0}, + {"heading", listing_title, 0}, + {"import", s_ignore, 0}, + {"page", listing_eject, 0}, + {"program", s_ignore, 0}, + {"uses", s_uses, 0}, + {0, 0, 0} +}; + +/*int md_reloc_size; */ + +int sh_relax; /* set if -relax seen */ + +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +#define C(a,b) ENCODE_RELAX(a,b) + +#define JREG 14 /* Register used as a temp when relaxing */ +#define ENCODE_RELAX(what,length) (((what) << 4) + (length)) +#define GET_WHAT(x) ((x>>4)) + +/* These are the two types of relaxable instrction */ +#define COND_JUMP 1 +#define UNCOND_JUMP 2 + +#define UNDEF_DISP 0 +#define COND8 1 +#define COND12 2 +#define COND32 3 +#define UNCOND12 1 +#define UNCOND32 2 +#define UNDEF_WORD_DISP 4 +#define END 5 + +#define UNCOND12 1 +#define UNCOND32 2 + +/* Branch displacements are from the address of the branch plus + four, thus all minimum and maximum values have 4 added to them. */ +#define COND8_F 258 +#define COND8_M -252 +#define COND8_LENGTH 2 + +/* There is one extra instruction before the branch, so we must add + two more bytes to account for it. */ +#define COND12_F 4100 +#define COND12_M -4090 +#define COND12_LENGTH 6 + +/* ??? The minimum and maximum values are wrong, but this does not matter + since this relocation type is not supported yet. */ +#define COND32_F (1<<30) +#define COND32_M -(1<<30) +#define COND32_LENGTH 14 + +#define UNCOND12_F 4098 +#define UNCOND12_M -4092 +#define UNCOND12_LENGTH 2 + +/* ??? The minimum and maximum values are wrong, but this does not matter + since this relocation type is not supported yet. */ +#define UNCOND32_F (1<<30) +#define UNCOND32_M -(1<<30) +#define UNCOND32_LENGTH 14 + +const relax_typeS md_relax_table[C (END, 0)] = { + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, + /* C (COND_JUMP, COND8) */ + { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP, COND12) }, + /* C (COND_JUMP, COND12) */ + { COND12_F, COND12_M, COND12_LENGTH, C (COND_JUMP, COND32), }, + /* C (COND_JUMP, COND32) */ + { COND32_F, COND32_M, COND32_LENGTH, 0, }, + { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, + /* C (UNCOND_JUMP, UNCOND12) */ + { UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), }, + /* C (UNCOND_JUMP, UNCOND32) */ + { UNCOND32_F, UNCOND32_M, UNCOND32_LENGTH, 0, }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, +}; + +static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ + +/* + This function is called once, at assembler startup time. This should + set up all the tables, etc that the MD part of the assembler needs + */ + +void +md_begin () +{ + sh_opcode_info *opcode; + char *prev_name = ""; + + if (! shl) + target_big_endian = 1; + + opcode_hash_control = hash_new (); + + /* Insert unique names into hash table */ + for (opcode = sh_table; opcode->name; opcode++) + { + if (strcmp (prev_name, opcode->name)) + { + prev_name = opcode->name; + hash_insert (opcode_hash_control, opcode->name, (char *) opcode); + } + else + { + /* Make all the opcodes with the same name point to the same + string */ + opcode->name = prev_name; + } + } +} + +static int reg_m; +static int reg_n; +static int reg_b; + +static expressionS immediate; /* absolute expression */ + +typedef struct + { + sh_arg_type type; + int reg; + } + +sh_operand_info; + +/* try and parse a reg name, returns number of chars consumed */ +static int +parse_reg (src, mode, reg) + char *src; + int *mode; + int *reg; +{ + /* We use !isalnum for the next character after the register name, to + make sure that we won't accidentally recognize a symbol name such as + 'sram' as being a reference to the register 'sr'. */ + + if (src[0] == 'r') + { + if (src[1] >= '0' && src[1] <= '7' && strncmp(&src[2], "_bank", 5) == 0 + && ! isalnum (src[7])) + { + *mode = A_REG_B; + *reg = (src[1] - '0'); + return 7; + } + } + + if (src[0] == 'r') + { + if (src[1] == '1') + { + if (src[2] >= '0' && src[2] <= '5' && ! isalnum (src[3])) + { + *mode = A_REG_N; + *reg = 10 + src[2] - '0'; + return 3; + } + } + if (src[1] >= '0' && src[1] <= '9' && ! isalnum (src[2])) + { + *mode = A_REG_N; + *reg = (src[1] - '0'); + return 2; + } + } + + if (src[0] == 's' && src[1] == 's' && src[2] == 'r' && ! isalnum (src[3])) + { + *mode = A_SSR; + return 3; + } + + if (src[0] == 's' && src[1] == 'p' && src[2] == 'c' && ! isalnum (src[3])) + { + *mode = A_SPC; + return 3; + } + + if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2])) + { + *mode = A_SR; + return 2; + } + + if (src[0] == 's' && src[1] == 'p' && ! isalnum (src[2])) + { + *mode = A_REG_N; + *reg = 15; + return 2; + } + + if (src[0] == 'p' && src[1] == 'r' && ! isalnum (src[2])) + { + *mode = A_PR; + return 2; + } + if (src[0] == 'p' && src[1] == 'c' && ! isalnum (src[2])) + { + *mode = A_DISP_PC; + return 2; + } + if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) + { + *mode = A_GBR; + return 3; + } + if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) + { + *mode = A_VBR; + return 3; + } + + if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' && ! isalnum (src[4])) + { + if (src[3] == 'l') + { + *mode = A_MACL; + return 4; + } + if (src[3] == 'h') + { + *mode = A_MACH; + return 4; + } + } + if (src[0] == 'f' && src[1] == 'r') + { + if (src[2] == '1') + { + if (src[3] >= '0' && src[3] <= '5' && ! isalnum (src[4])) + { + *mode = F_REG_N; + *reg = 10 + src[3] - '0'; + return 4; + } + } + if (src[2] >= '0' && src[2] <= '9' && ! isalnum (src[3])) + { + *mode = F_REG_N; + *reg = (src[2] - '0'); + return 3; + } + } + if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l' + && ! isalnum (src[4])) + { + *mode = FPUL_N; + return 4; + } + + if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c' + && src[4] == 'r' && ! isalnum (src[5])) + { + *mode = FPSCR_N; + return 5; + } + + return 0; +} + +static symbolS *dot() +{ + const char *fake; + + /* JF: '.' is pseudo symbol with value of current location + in current segment. */ + fake = FAKE_LABEL_NAME; + return symbol_new (fake, + now_seg, + (valueT) frag_now_fix (), + frag_now); + +} + + +static +char * +parse_exp (s) + char *s; +{ + char *save; + char *new; + + save = input_line_pointer; + input_line_pointer = s; + expression (&immediate); + if (immediate.X_op == O_absent) + as_bad ("missing operand"); + new = input_line_pointer; + input_line_pointer = save; + return new; +} + + +/* The many forms of operand: + + Rn Register direct + @Rn Register indirect + @Rn+ Autoincrement + @-Rn Autodecrement + @(disp:4,Rn) + @(disp:8,GBR) + @(disp:8,PC) + + @(R0,Rn) + @(R0,GBR) + + disp:8 + disp:12 + #imm8 + pr, gbr, vbr, macl, mach + + */ + +static +char * +parse_at (src, op) + char *src; + sh_operand_info *op; +{ + int len; + int mode; + src++; + if (src[0] == '-') + { + /* Must be predecrement */ + src++; + + len = parse_reg (src, &mode, &(op->reg)); + if (mode != A_REG_N) + as_bad ("illegal register after @-"); + + op->type = A_DEC_N; + src += len; + } + else if (src[0] == '(') + { + /* Could be @(disp, rn), @(disp, gbr), @(disp, pc), @(r0, gbr) or + @(r0, rn) */ + src++; + len = parse_reg (src, &mode, &(op->reg)); + if (len && mode == A_REG_N) + { + src += len; + if (op->reg != 0) + { + as_bad ("must be @(r0,...)"); + } + if (src[0] == ',') + src++; + /* Now can be rn or gbr */ + len = parse_reg (src, &mode, &(op->reg)); + if (mode == A_GBR) + { + op->type = A_R0_GBR; + } + else if (mode == A_REG_N) + { + op->type = A_IND_R0_REG_N; + } + else + { + as_bad ("syntax error in @(r0,...)"); + } + } + else + { + /* Must be an @(disp,.. thing) */ + src = parse_exp (src); + if (src[0] == ',') + src++; + /* Now can be rn, gbr or pc */ + len = parse_reg (src, &mode, &op->reg); + if (len) + { + if (mode == A_REG_N) + { + op->type = A_DISP_REG_N; + } + else if (mode == A_GBR) + { + op->type = A_DISP_GBR; + } + else if (mode == A_DISP_PC) + { + /* Turn a plain @(4,pc) into @(.+4,pc) */ + if (immediate.X_op == O_constant) { + immediate.X_add_symbol = dot(); + immediate.X_op = O_symbol; + } + op->type = A_DISP_PC; + } + else + { + as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); + } + } + else + { + as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); + } + } + src += len; + if (src[0] != ')') + as_bad ("expecting )"); + else + src++; + } + else + { + src += parse_reg (src, &mode, &(op->reg)); + if (mode != A_REG_N) + { + as_bad ("illegal register after @"); + } + if (src[0] == '+') + { + op->type = A_INC_N; + src++; + } + else + { + op->type = A_IND_N; + } + } + return src; +} + +static void +get_operand (ptr, op) + char **ptr; + sh_operand_info *op; +{ + char *src = *ptr; + int mode = -1; + unsigned int len; + + if (src[0] == '#') + { + src++; + *ptr = parse_exp (src); + op->type = A_IMM; + return; + } + + else if (src[0] == '@') + { + *ptr = parse_at (src, op); + return; + } + len = parse_reg (src, &mode, &(op->reg)); + if (len) + { + *ptr = src + len; + op->type = mode; + return; + } + else + { + /* Not a reg, the only thing left is a displacement */ + *ptr = parse_exp (src); + op->type = A_DISP_PC; + return; + } +} + +static +char * +get_operands (info, args, operand) + sh_opcode_info *info; + char *args; + sh_operand_info *operand; + +{ + char *ptr = args; + if (info->arg[0]) + { + ptr++; + + get_operand (&ptr, operand + 0); + if (info->arg[1]) + { + if (*ptr == ',') + { + ptr++; + } + get_operand (&ptr, operand + 1); + if (info->arg[2]) + { + if (*ptr == ',') + { + ptr++; + } + get_operand (&ptr, operand + 2); + } + else + { + operand[2].type = 0; + } + } + else + { + operand[1].type = 0; + operand[2].type = 0; + } + } + else + { + operand[0].type = 0; + operand[1].type = 0; + operand[2].type = 0; + } + return ptr; +} + +/* Passed a pointer to a list of opcodes which use different + addressing modes, return the opcode which matches the opcodes + provided + */ + +static +sh_opcode_info * +get_specific (opcode, operands) + sh_opcode_info *opcode; + sh_operand_info *operands; +{ + sh_opcode_info *this_try = opcode; + char *name = opcode->name; + int n = 0; + while (opcode->name) + { + this_try = opcode++; + if (this_try->name != name) + { + /* We've looked so far down the table that we've run out of + opcodes with the same name */ + return 0; + } + /* look at both operands needed by the opcodes and provided by + the user - since an arg test will often fail on the same arg + again and again, we'll try and test the last failing arg the + first on each opcode try */ + + for (n = 0; this_try->arg[n]; n++) + { + sh_operand_info *user = operands + n; + sh_arg_type arg = this_try->arg[n]; + switch (arg) + { + case A_IMM: + case A_BDISP12: + case A_BDISP8: + case A_DISP_GBR: + case A_DISP_PC: + case A_MACH: + case A_PR: + case A_MACL: + if (user->type != arg) + goto fail; + break; + case A_R0: + /* opcode needs r0 */ + if (user->type != A_REG_N || user->reg != 0) + goto fail; + break; + case A_R0_GBR: + if (user->type != A_R0_GBR || user->reg != 0) + goto fail; + break; + case F_FR0: + if (user->type != F_REG_N || user->reg != 0) + goto fail; + break; + + case A_REG_N: + case A_INC_N: + case A_DEC_N: + case A_IND_N: + case A_IND_R0_REG_N: + case A_DISP_REG_N: + case F_REG_N: + case FPUL_N: + case FPSCR_N: + /* Opcode needs rn */ + if (user->type != arg) + goto fail; + reg_n = user->reg; + break; + case A_GBR: + case A_SR: + case A_VBR: + case A_SSR: + case A_SPC: + if (user->type != arg) + goto fail; + break; + + case A_REG_B: + if (user->type != arg) + goto fail; + reg_b = user->reg; + break; + + case A_REG_M: + case A_INC_M: + case A_DEC_M: + case A_IND_M: + case A_IND_R0_REG_M: + case A_DISP_REG_M: + /* Opcode needs rn */ + if (user->type != arg - A_REG_M + A_REG_N) + goto fail; + reg_m = user->reg; + break; + + case F_REG_M: + case FPUL_M: + case FPSCR_M: + /* Opcode needs rn */ + if (user->type != arg - F_REG_M + F_REG_N) + goto fail; + reg_m = user->reg; + break; + + default: + printf ("unhandled %d\n", arg); + goto fail; + } + } + return this_try; + fail:; + } + + return 0; +} + +int +check (operand, low, high) + expressionS *operand; + int low; + int high; +{ + if (operand->X_op != O_constant + || operand->X_add_number < low + || operand->X_add_number > high) + { + as_bad ("operand must be absolute in range %d..%d", low, high); + } + return operand->X_add_number; +} + + +static void +insert (where, how, pcrel) + char *where; + int how; + int pcrel; +{ + fix_new_exp (frag_now, + where - frag_now->fr_literal, + 2, + &immediate, + pcrel, + how); +} + +static void +build_relax (opcode) + sh_opcode_info *opcode; +{ + int high_byte = target_big_endian ? 0 : 1; + char *p; + + if (opcode->arg[0] == A_BDISP8) + { + p = frag_var (rs_machine_dependent, + md_relax_table[C (COND_JUMP, COND32)].rlx_length, + md_relax_table[C (COND_JUMP, COND8)].rlx_length, + C (COND_JUMP, 0), + immediate.X_add_symbol, + immediate.X_add_number, + 0); + p[high_byte] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]); + } + else if (opcode->arg[0] == A_BDISP12) + { + p = frag_var (rs_machine_dependent, + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length, + md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length, + C (UNCOND_JUMP, 0), + immediate.X_add_symbol, + immediate.X_add_number, + 0); + p[high_byte] = (opcode->nibbles[0] << 4); + } + +} + +/* Now we know what sort of opcodes it is, lets build the bytes - + */ +static void +build_Mytes (opcode, operand) + sh_opcode_info *opcode; + sh_operand_info *operand; + +{ + int index; + char nbuf[4]; + char *output = frag_more (2); + int low_byte = target_big_endian ? 1 : 0; + nbuf[0] = 0; + nbuf[1] = 0; + nbuf[2] = 0; + nbuf[3] = 0; + + for (index = 0; index < 4; index++) + { + sh_nibble_type i = opcode->nibbles[index]; + if (i < 16) + { + nbuf[index] = i; + } + else + { + switch (i) + { + case REG_N: + nbuf[index] = reg_n; + break; + case REG_M: + nbuf[index] = reg_m; + break; + case REG_B: + nbuf[index] = reg_b | 0x08; + break; + case DISP_4: + insert (output + low_byte, BFD_RELOC_SH_IMM4, 0); + break; + case IMM_4BY4: + insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0); + break; + case IMM_4BY2: + insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0); + break; + case IMM_4: + insert (output + low_byte, BFD_RELOC_SH_IMM4, 0); + break; + case IMM_8BY4: + insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0); + break; + case IMM_8BY2: + insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0); + break; + case IMM_8: + insert (output + low_byte, BFD_RELOC_SH_IMM8, 0); + break; + case PCRELIMM_8BY4: + insert (output, BFD_RELOC_SH_PCRELIMM8BY4, 1); + break; + case PCRELIMM_8BY2: + insert (output, BFD_RELOC_SH_PCRELIMM8BY2, 1); + break; + default: + printf ("failed for %d\n", i); + } + } + } + if (! target_big_endian) { + output[1] = (nbuf[0] << 4) | (nbuf[1]); + output[0] = (nbuf[2] << 4) | (nbuf[3]); + } + else { + output[0] = (nbuf[0] << 4) | (nbuf[1]); + output[1] = (nbuf[2] << 4) | (nbuf[3]); + } +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. + */ + +void +md_assemble (str) + char *str; +{ + unsigned char *op_start; + unsigned char *op_end; + sh_operand_info operand[3]; + sh_opcode_info *opcode; + char name[20]; + int nlen = 0; + /* Drop leading whitespace */ + while (*str == ' ') + str++; + + /* find the op code end */ + for (op_start = op_end = (unsigned char *) (str); + *op_end + && nlen < 20 + && !is_end_of_line[*op_end] && *op_end != ' '; + op_end++) + { + name[nlen] = op_start[nlen]; + nlen++; + } + name[nlen] = 0; + + if (nlen == 0) + { + as_bad ("can't find opcode "); + } + + opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name); + + if (opcode == NULL) + { + as_bad ("unknown opcode"); + return; + } + + if (sh_relax + && ! seg_info (now_seg)->tc_segment_info_data.in_code) + { + /* Output a CODE reloc to tell the linker that the following + bytes are instructions, not data. */ + fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, + BFD_RELOC_SH_CODE); + seg_info (now_seg)->tc_segment_info_data.in_code = 1; + } + + if (opcode->arg[0] == A_BDISP12 + || opcode->arg[0] == A_BDISP8) + { + parse_exp (op_end + 1); + build_relax (opcode); + } + else + { + if (opcode->arg[0] != A_END) + { + get_operands (opcode, op_end, operand); + } + opcode = get_specific (opcode, operand); + + if (opcode == 0) + { + /* Couldn't find an opcode which matched the operands */ + char *where = frag_more (2); + + where[0] = 0x0; + where[1] = 0x0; + as_bad ("invalid operands for opcode"); + return; + } + + build_Mytes (opcode, operand); + } + +} + +/* This routine is called each time a label definition is seen. It + emits a BFD_RELOC_SH_LABEL reloc if necessary. */ + +void +sh_frob_label () +{ + static fragS *last_label_frag; + static int last_label_offset; + + if (sh_relax + && seg_info (now_seg)->tc_segment_info_data.in_code) + { + int offset; + + offset = frag_now_fix (); + if (frag_now != last_label_frag + || offset != last_label_offset) + { + fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL); + last_label_frag = frag_now; + last_label_offset = offset; + } + } +} + +/* This routine is called when the assembler is about to output some + data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */ + +void +sh_flush_pending_output () +{ + if (sh_relax + && seg_info (now_seg)->tc_segment_info_data.in_code) + { + fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, + BFD_RELOC_SH_DATA); + seg_info (now_seg)->tc_segment_info_data.in_code = 0; + } +} + +symbolS * +DEFUN (md_undefined_symbol, (name), + char *name) +{ + return 0; +} + +#ifdef OBJ_COFF + +void +DEFUN (tc_crawl_symbol_chain, (headers), + object_headers * headers) +{ + printf ("call to tc_crawl_symbol_chain \n"); +} + +void +DEFUN (tc_headers_hook, (headers), + object_headers * headers) +{ + printf ("call to tc_headers_hook \n"); +} + +#endif + +/* Various routines to kill one day */ +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP . An error message is returned, or NULL on OK. + */ +char * +md_atof (type, litP, sizeP) + int type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[4]; + char *t; + int i; + + switch (type) + { + case 'f': + prec = 2; + break; + + case 'd': + prec = 4; + break; + + default: + *sizeP = 0; + return "bad call to md_atof"; + } + + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * 2; + + if (! target_big_endian) + { + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litP, (valueT) words[i], 2); + litP += 2; + } + } + else + { + for (i = 0; i < prec; i++) + { + md_number_to_chars (litP, (valueT) words[i], 2); + litP += 2; + } + } + + return NULL; +} + +/* Handle the .uses pseudo-op. This pseudo-op is used just before a + call instruction. It refers to a label of the instruction which + loads the register which the call uses. We use it to generate a + special reloc for the linker. */ + +static void +s_uses (ignore) + int ignore; +{ + expressionS ex; + + if (! sh_relax) + as_warn (".uses pseudo-op seen when not relaxing"); + + expression (&ex); + + if (ex.X_op != O_symbol || ex.X_add_number != 0) + { + as_bad ("bad .uses format"); + ignore_rest_of_line (); + return; + } + + fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES); + + demand_empty_rest_of_line (); +} + +CONST char *md_shortopts = ""; +struct option md_longopts[] = { + +#define OPTION_RELAX (OPTION_MD_BASE) +#define OPTION_LITTLE (OPTION_MD_BASE+1) + + {"relax", no_argument, NULL, OPTION_RELAX}, + {"little", no_argument, NULL, OPTION_LITTLE}, + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); + +int +md_parse_option (c, arg) + int c; + char *arg; +{ + switch (c) + { + case OPTION_RELAX: + sh_relax = 1; + break; + case OPTION_LITTLE: + shl = 1; + target_big_endian = 0; + break; + + default: + return 0; + } + + return 1; +} + +void +md_show_usage (stream) + FILE *stream; +{ + fprintf(stream, "\ +SH options:\n\ +-little generate little endian code\n\ +-relax alter jump instructions for long displacements\n"); +} + +int md_short_jump_size; + +void +tc_Nout_fix_to_chars () +{ + printf ("call to tc_Nout_fix_to_chars \n"); + abort (); +} + +void +md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) + char *ptr; + addressT from_Nddr; + addressT to_Nddr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) + char *ptr; + addressT from_Nddr, to_Nddr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +/* This struct is used to pass arguments to sh_count_relocs through + bfd_map_over_sections. */ + +struct sh_count_relocs +{ + /* Symbol we are looking for. */ + symbolS *sym; + /* Count of relocs found. */ + int count; +}; + +/* Count the number of fixups in a section which refer to a particular + symbol. When using BFD_ASSEMBLER, this is called via + bfd_map_over_sections. */ + +/*ARGSUSED*/ +static void +sh_count_relocs (abfd, sec, data) + bfd *abfd; + segT sec; + PTR data; +{ + struct sh_count_relocs *info = (struct sh_count_relocs *) data; + segment_info_type *seginfo; + symbolS *sym; + fixS *fix; + + seginfo = seg_info (sec); + if (seginfo == NULL) + return; + + sym = info->sym; + for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next) + { + if (fix->fx_addsy == sym) + { + ++info->count; + fix->fx_tcbit = 1; + } + } +} + +/* Handle the count relocs for a particular section. When using + BFD_ASSEMBLER, this is called via bfd_map_over_sections. */ + +/*ARGSUSED*/ +static void +sh_frob_section (abfd, sec, ignore) + bfd *abfd; + segT sec; + PTR ignore; +{ + segment_info_type *seginfo; + fixS *fix; + + seginfo = seg_info (sec); + if (seginfo == NULL) + return; + + for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next) + { + symbolS *sym; + bfd_vma val; + fixS *fscan; + struct sh_count_relocs info; + + if (fix->fx_r_type != BFD_RELOC_SH_USES) + continue; + + /* The BFD_RELOC_SH_USES reloc should refer to a defined local + symbol in the same section. */ + sym = fix->fx_addsy; + if (sym == NULL + || fix->fx_subsy != NULL + || fix->fx_addnumber != 0 + || S_GET_SEGMENT (sym) != sec +#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) + || S_GET_STORAGE_CLASS (sym) == C_EXT +#endif + || S_IS_EXTERNAL (sym)) + { + as_warn_where (fix->fx_file, fix->fx_line, + ".uses does not refer to a local symbol in the same section"); + continue; + } + + /* Look through the fixups again, this time looking for one + at the same location as sym. */ + val = S_GET_VALUE (sym); + for (fscan = seginfo->fix_root; + fscan != NULL; + fscan = fscan->fx_next) + if (val == fscan->fx_frag->fr_address + fscan->fx_where + && fscan->fx_r_type != BFD_RELOC_SH_ALIGN + && fscan->fx_r_type != BFD_RELOC_SH_CODE + && fscan->fx_r_type != BFD_RELOC_SH_DATA + && fscan->fx_r_type != BFD_RELOC_SH_LABEL) + break; + if (fscan == NULL) + { + as_warn_where (fix->fx_file, fix->fx_line, + "can't find fixup pointed to by .uses"); + continue; + } + + if (fscan->fx_tcbit) + { + /* We've already done this one. */ + continue; + } + + /* fscan should also be a fixup to a local symbol in the same + section. */ + sym = fscan->fx_addsy; + if (sym == NULL + || fscan->fx_subsy != NULL + || fscan->fx_addnumber != 0 + || S_GET_SEGMENT (sym) != sec +#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) + || S_GET_STORAGE_CLASS (sym) == C_EXT +#endif + || S_IS_EXTERNAL (sym)) + { + as_warn_where (fix->fx_file, fix->fx_line, + ".uses target does not refer to a local symbol in the same section"); + continue; + } + + /* Now we look through all the fixups of all the sections, + counting the number of times we find a reference to sym. */ + info.sym = sym; + info.count = 0; +#ifdef BFD_ASSEMBLER + bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info); +#else + { + int iscan; + + for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++) + sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info); + } +#endif + + if (info.count < 1) + abort (); + + /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym. + We have already adjusted the value of sym to include the + fragment address, so we undo that adjustment here. */ + subseg_change (sec, 0); + fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address, + 4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT); + } +} + +/* This function is called after the symbol table has been completed, + but before the relocs or section contents have been written out. + If we have seen any .uses pseudo-ops, they point to an instruction + which loads a register with the address of a function. We look + through the fixups to find where the function address is being + loaded from. We then generate a COUNT reloc giving the number of + times that function address is referred to. The linker uses this + information when doing relaxing, to decide when it can eliminate + the stored function address entirely. */ + +void +sh_frob_file () +{ + if (! sh_relax) + return; + +#ifdef BFD_ASSEMBLER + bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL); +#else + { + int iseg; + + for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++) + sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL); + } +#endif +} + +/* Called after relaxing. Set the correct sizes of the fragments, and + create relocs so that md_apply_fix will fill in the correct values. */ + +void +md_convert_frag (headers, seg, fragP) +#ifdef BFD_ASSEMBLER + bfd *headers; +#else + object_headers *headers; +#endif + segT seg; + fragS *fragP; +{ + int donerelax = 0; + + switch (fragP->fr_subtype) + { + case C (COND_JUMP, COND8): + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, + 1, BFD_RELOC_SH_PCDISP8BY2); + fragP->fr_fix += 2; + fragP->fr_var = 0; + break; + + case C (UNCOND_JUMP, UNCOND12): + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, + 1, BFD_RELOC_SH_PCDISP12BY2); + fragP->fr_fix += 2; + fragP->fr_var = 0; + break; + + case C (UNCOND_JUMP, UNCOND32): + case C (UNCOND_JUMP, UNDEF_WORD_DISP): + if (fragP->fr_symbol == NULL) + as_bad ("at 0x%lx, displacement overflows 12-bit field", + (unsigned long) fragP->fr_address); + else + as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 12-bit field", + (unsigned long) fragP->fr_address, + S_IS_DEFINED (fragP->fr_symbol) ? "" : "un", + S_GET_NAME (fragP->fr_symbol)); + +#if 0 /* This code works, but generates poor code and the compiler + should never produce a sequence that requires it to be used. */ + + /* A jump wont fit in 12 bits, make code which looks like + bra foo + mov.w @(0, PC), r14 + .long disp + foo: bra @r14 + */ + int t = buffer[0] & 0x10; + + buffer[highbyte] = 0xa0; /* branch over move and disp */ + buffer[lowbyte] = 3; + buffer[highbyte+2] = 0xd0 | JREG; /* Build mov insn */ + buffer[lowbyte+2] = 0x00; + + buffer[highbyte+4] = 0; /* space for 32 bit jump disp */ + buffer[lowbyte+4] = 0; + buffer[highbyte+6] = 0; + buffer[lowbyte+6] = 0; + + buffer[highbyte+8] = 0x40 | JREG; /* Build jmp @JREG */ + buffer[lowbyte+8] = t ? 0xb : 0x2b; + + buffer[highbyte+10] = 0x20; /* build nop */ + buffer[lowbyte+10] = 0x0b; + + /* Make reloc for the long disp */ + fix_new (fragP, + fragP->fr_fix + 4, + 4, + fragP->fr_symbol, + fragP->fr_offset, + 0, + BFD_RELOC_32); + fragP->fr_fix += UNCOND32_LENGTH; + fragP->fr_var = 0; + donerelax = 1; +#endif + + break; + + case C (COND_JUMP, COND12): + /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */ + { + unsigned char *buffer = + (unsigned char *) (fragP->fr_fix + fragP->fr_literal); + int highbyte = target_big_endian ? 0 : 1; + int lowbyte = target_big_endian ? 1 : 0; + + /* Toggle the true/false bit of the bcond. */ + buffer[highbyte] ^= 0x2; + + /* Build a relocation to six bytes farther on. */ + subseg_change (seg, 0); + fix_new (fragP, fragP->fr_fix, 2, +#ifdef BFD_ASSEMBLER + section_symbol (seg), +#else + seg_info (seg)->dot, +#endif + fragP->fr_address + fragP->fr_fix + 6, + 1, BFD_RELOC_SH_PCDISP8BY2); + + /* Set up a jump instruction. */ + buffer[highbyte + 2] = 0xa0; + buffer[lowbyte + 2] = 0; + fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol, + fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2); + + /* Fill in a NOP instruction. */ + buffer[highbyte + 4] = 0x0; + buffer[lowbyte + 4] = 0x9; + + fragP->fr_fix += 6; + fragP->fr_var = 0; + donerelax = 1; + } + break; + + case C (COND_JUMP, COND32): + case C (COND_JUMP, UNDEF_WORD_DISP): + if (fragP->fr_symbol == NULL) + as_bad ("at 0x%lx, displacement overflows 8-bit field", + (unsigned long) fragP->fr_address); + else + as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 8-bit field ", + (unsigned long) fragP->fr_address, + S_IS_DEFINED (fragP->fr_symbol) ? "" : "un", + S_GET_NAME (fragP->fr_symbol)); + +#if 0 /* This code works, but generates poor code, and the compiler + should never produce a sequence that requires it to be used. */ + + /* A bcond won't fit and it won't go into a 12 bit + displacement either, the code sequence looks like: + b!cond foop + mov.w @(n, PC), r14 + jmp @r14 + nop + .long where + foop: + */ + + buffer[0] ^= 0x2; /* Toggle T/F bit */ +#define JREG 14 + buffer[1] = 5; /* branch over mov, jump, nop and ptr */ + buffer[2] = 0xd0 | JREG; /* Build mov insn */ + buffer[3] = 0x2; + buffer[4] = 0x40 | JREG; /* Build jmp @JREG */ + buffer[5] = 0x0b; + buffer[6] = 0x20; /* build nop */ + buffer[7] = 0x0b; + buffer[8] = 0; /* space for 32 bit jump disp */ + buffer[9] = 0; + buffer[10] = 0; + buffer[11] = 0; + buffer[12] = 0; + buffer[13] = 0; + /* Make reloc for the long disp */ + fix_new (fragP, + fragP->fr_fix + 8, + 4, + fragP->fr_symbol, + fragP->fr_offset, + 0, + BFD_RELOC_32); + fragP->fr_fix += COND32_LENGTH; + fragP->fr_var = 0; + donerelax = 1; +#endif + + break; + + default: + abort (); + } + + if (donerelax && !sh_relax) + as_warn_where (fragP->fr_file, fragP->fr_line, + "overflow in branch to %s; converted into longer instruction sequence", + (fragP->fr_symbol != NULL + ? S_GET_NAME (fragP->fr_symbol) + : "")); +} + +valueT +DEFUN (md_section_align, (seg, size), + segT seg AND + valueT size) +{ +#ifdef BFD_ASSEMBLER +#ifdef OBJ_ELF + return size; +#else /* ! OBJ_ELF */ + return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1) + & (-1 << bfd_get_section_alignment (stdoutput, seg))); +#endif /* ! OBJ_ELF */ +#else /* ! BFD_ASSEMBLER */ + return ((size + (1 << section_alignment[(int) seg]) - 1) + & (-1 << section_alignment[(int) seg])); +#endif /* ! BFD_ASSEMBLER */ +} + +/* When relaxing, we need to output a reloc for any .align directive + that requests alignment to a four byte boundary or larger. */ + +void +sh_handle_align (frag) + fragS *frag; +{ + if (sh_relax + && frag->fr_type == rs_align + && frag->fr_address + frag->fr_fix > 0 + && frag->fr_offset > 1 + && now_seg != bss_section) + fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0, + BFD_RELOC_SH_ALIGN); +} + +/* This macro decides whether a particular reloc is an entry in a + switch table. It is used when relaxing, because the linker needs + to know about all such entries so that it can adjust them if + necessary. */ + +#ifdef BFD_ASSEMBLER +#define SWITCH_TABLE_CONS(fix) (0) +#else +#define SWITCH_TABLE_CONS(fix) \ + ((fix)->fx_r_type == 0 \ + && ((fix)->fx_size == 2 \ + || (fix)->fx_size == 4)) +#endif + +#define SWITCH_TABLE(fix) \ + ((fix)->fx_addsy != NULL \ + && (fix)->fx_subsy != NULL \ + && S_GET_SEGMENT ((fix)->fx_addsy) == text_section \ + && S_GET_SEGMENT ((fix)->fx_subsy) == text_section \ + && ((fix)->fx_r_type == BFD_RELOC_32 \ + || (fix)->fx_r_type == BFD_RELOC_16 \ + || SWITCH_TABLE_CONS (fix))) + +/* See whether we need to force a relocation into the output file. + This is used to force out switch and PC relative relocations when + relaxing. */ + +int +sh_force_relocation (fix) + fixS *fix; +{ + if (! sh_relax) + return 0; + + return (fix->fx_pcrel + || SWITCH_TABLE (fix) + || fix->fx_r_type == BFD_RELOC_SH_COUNT + || fix->fx_r_type == BFD_RELOC_SH_ALIGN + || fix->fx_r_type == BFD_RELOC_SH_CODE + || fix->fx_r_type == BFD_RELOC_SH_DATA + || fix->fx_r_type == BFD_RELOC_SH_LABEL); +} + +/* Apply a fixup to the object file. */ + +#ifdef BFD_ASSEMBLER +int +md_apply_fix (fixP, valp) + fixS *fixP; + valueT *valp; +#else +void +md_apply_fix (fixP, val) + fixS *fixP; + long val; +#endif +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + int lowbyte = target_big_endian ? 1 : 0; + int highbyte = target_big_endian ? 0 : 1; +#ifdef BFD_ASSEMBLER + long val = *valp; +#endif + +#ifndef BFD_ASSEMBLER + if (fixP->fx_r_type == 0) + { + if (fixP->fx_size == 2) + fixP->fx_r_type = BFD_RELOC_16; + else if (fixP->fx_size == 4) + fixP->fx_r_type = BFD_RELOC_32; + else if (fixP->fx_size == 1) + fixP->fx_r_type = BFD_RELOC_SH_IMM8; + else + abort (); + } +#endif + + switch (fixP->fx_r_type) + { + case BFD_RELOC_SH_IMM4: + *buf = (*buf & 0xf0) | (val & 0xf); + break; + + case BFD_RELOC_SH_IMM4BY2: + *buf = (*buf & 0xf0) | ((val >> 1) & 0xf); + break; + + case BFD_RELOC_SH_IMM4BY4: + *buf = (*buf & 0xf0) | ((val >> 2) & 0xf); + break; + + case BFD_RELOC_SH_IMM8BY2: + *buf = val >> 1; + break; + + case BFD_RELOC_SH_IMM8BY4: + *buf = val >> 2; + break; + + case BFD_RELOC_8: + case BFD_RELOC_SH_IMM8: + *buf++ = val; + break; + + case BFD_RELOC_SH_PCRELIMM8BY4: + /* The lower two bits of the PC are cleared before the + displacement is added in. We can assume that the destination + is on a 4 byte bounday. If this instruction is also on a 4 + byte boundary, then we want + (target - here) / 4 + and target - here is a multiple of 4. + Otherwise, we are on a 2 byte boundary, and we want + (target - (here - 2)) / 4 + and target - here is not a multiple of 4. Computing + (target - (here - 2)) / 4 == (target - here + 2) / 4 + works for both cases, since in the first case the addition of + 2 will be removed by the division. target - here is in the + variable val. */ + val = (val + 2) / 4; + if (val & ~0xff) + as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); + buf[lowbyte] = val; + break; + + case BFD_RELOC_SH_PCRELIMM8BY2: + val /= 2; + if (val & ~0xff) + as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); + buf[lowbyte] = val; + break; + + case BFD_RELOC_SH_PCDISP8BY2: + val /= 2; + if (val < -0x80 || val > 0x7f) + as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); + buf[lowbyte] = val; + break; + + case BFD_RELOC_SH_PCDISP12BY2: + val /= 2; + if (val < -0x800 || val >= 0x7ff) + as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); + buf[lowbyte] = val & 0xff; + buf[highbyte] |= (val >> 8) & 0xf; + break; + + case BFD_RELOC_32: + if (! target_big_endian) + { + *buf++ = val >> 0; + *buf++ = val >> 8; + *buf++ = val >> 16; + *buf++ = val >> 24; + } + else + { + *buf++ = val >> 24; + *buf++ = val >> 16; + *buf++ = val >> 8; + *buf++ = val >> 0; + } + break; + + case BFD_RELOC_16: + if (! target_big_endian) + { + *buf++ = val >> 0; + *buf++ = val >> 8; + } + else + { + *buf++ = val >> 8; + *buf++ = val >> 0; + } + break; + + case BFD_RELOC_SH_USES: + /* Pass the value into sh_coff_reloc_mangle. */ + fixP->fx_addnumber = val; + break; + + case BFD_RELOC_SH_COUNT: + case BFD_RELOC_SH_ALIGN: + case BFD_RELOC_SH_CODE: + case BFD_RELOC_SH_DATA: + case BFD_RELOC_SH_LABEL: + /* Nothing to do here. */ + break; + + default: + abort (); + } + +#ifdef BFD_ASSEMBLER + return 0; +#endif +} + +int md_long_jump_size; + +/* Called just before address relaxation. Return the length + by which a fragment must grow to reach it's destination. */ + +int +md_estimate_size_before_relax (fragP, segment_type) + register fragS *fragP; + register segT segment_type; +{ + switch (fragP->fr_subtype) + { + case C (UNCOND_JUMP, UNDEF_DISP): + /* used to be a branch to somewhere which was unknown */ + if (!fragP->fr_symbol) + { + fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; + } + else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type) + { + fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; + } + else + { + fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; + return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; + } + break; + + default: + abort (); + case C (COND_JUMP, UNDEF_DISP): + /* used to be a branch to somewhere which was unknown */ + if (fragP->fr_symbol + && S_GET_SEGMENT (fragP->fr_symbol) == segment_type) + { + /* Got a symbol and it's defined in this segment, become byte + sized - maybe it will fix up */ + fragP->fr_subtype = C (COND_JUMP, COND8); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; + } + else if (fragP->fr_symbol) + { + /* Its got a segment, but its not ours, so it will always be long */ + fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length; + return md_relax_table[C (COND_JUMP, COND32)].rlx_length; + } + else + { + /* We know the abs value */ + fragP->fr_subtype = C (COND_JUMP, COND8); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; + } + + break; + } + return fragP->fr_var; +} + +/* Put number into target byte order */ + +void +md_number_to_chars (ptr, use, nbytes) + char *ptr; + valueT use; + int nbytes; +{ + if (! target_big_endian) + number_to_chars_littleendian (ptr, use, nbytes); + else + number_to_chars_bigendian (ptr, use, nbytes); +} + +long +md_pcrel_from (fixP) + fixS *fixP; +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2; +} + +#ifdef OBJ_COFF + +int +tc_coff_sizemachdep (frag) + fragS *frag; +{ + return md_relax_table[frag->fr_subtype].rlx_length; +} + +#endif /* OBJ_COFF */ + +/* When we align the .text section, insert the correct NOP pattern. */ + +int +sh_do_align (n, fill, len, max) + int n; + const char *fill; + int len; + int max; +{ + if (fill == NULL +#ifdef BFD_ASSEMBLER + && (now_seg->flags & SEC_CODE) != 0 +#else + && now_seg != data_section + && now_seg != bss_section +#endif + && n > 1) + { + static const unsigned char big_nop_pattern[] = { 0x00, 0x09 }; + static const unsigned char little_nop_pattern[] = { 0x09, 0x00 }; + + /* First align to a 2 byte boundary, in case there is an odd + .byte. */ + frag_align (1, 0, 0); + if (target_big_endian) + frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max); + else + frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern, + max); + return 1; + } + + return 0; +} + +#ifndef BFD_ASSEMBLER +#ifdef OBJ_COFF + +/* Map BFD relocs to SH COFF relocs. */ + +struct reloc_map +{ + bfd_reloc_code_real_type bfd_reloc; + int sh_reloc; +}; + +static const struct reloc_map coff_reloc_map[] = +{ + { BFD_RELOC_32, R_SH_IMM32 }, + { BFD_RELOC_16, R_SH_IMM16 }, + { BFD_RELOC_8, R_SH_IMM8 }, + { BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 }, + { BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP }, + { BFD_RELOC_SH_IMM4, R_SH_IMM4 }, + { BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 }, + { BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 }, + { BFD_RELOC_SH_IMM8, R_SH_IMM8 }, + { BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 }, + { BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 }, + { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 }, + { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 }, + { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, + { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, + { BFD_RELOC_SH_USES, R_SH_USES }, + { BFD_RELOC_SH_COUNT, R_SH_COUNT }, + { BFD_RELOC_SH_ALIGN, R_SH_ALIGN }, + { BFD_RELOC_SH_CODE, R_SH_CODE }, + { BFD_RELOC_SH_DATA, R_SH_DATA }, + { BFD_RELOC_SH_LABEL, R_SH_LABEL }, + { BFD_RELOC_UNUSED, 0 } +}; + +/* Adjust a reloc for the SH. This is similar to the generic code, + but does some minor tweaking. */ + +void +sh_coff_reloc_mangle (seg, fix, intr, paddr) + segment_info_type *seg; + fixS *fix; + struct internal_reloc *intr; + unsigned int paddr; +{ + symbolS *symbol_ptr = fix->fx_addsy; + symbolS *dot; + + intr->r_vaddr = paddr + fix->fx_frag->fr_address + fix->fx_where; + + if (! SWITCH_TABLE (fix)) + { + const struct reloc_map *rm; + + for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++) + if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type) + break; + if (rm->bfd_reloc == BFD_RELOC_UNUSED) + as_bad_where (fix->fx_file, fix->fx_line, + "Can not represent %s relocation in this object file format", + bfd_get_reloc_code_name (fix->fx_r_type)); + intr->r_type = rm->sh_reloc; + intr->r_offset = 0; + } + else + { + know (sh_relax); + + if (fix->fx_r_type == BFD_RELOC_16) + intr->r_type = R_SH_SWITCH16; + else if (fix->fx_r_type == BFD_RELOC_32) + intr->r_type = R_SH_SWITCH32; + else + abort (); + + /* For a switch reloc, we set r_offset to the difference between + the reloc address and the subtrahend. When the linker is + doing relaxing, it can use the determine the starting and + ending points of the switch difference expression. */ + intr->r_offset = intr->r_vaddr - S_GET_VALUE (fix->fx_subsy); + } + + /* PC relative relocs are always against the current section. */ + if (symbol_ptr == NULL) + { + switch (fix->fx_r_type) + { + case BFD_RELOC_SH_PCRELIMM8BY2: + case BFD_RELOC_SH_PCRELIMM8BY4: + case BFD_RELOC_SH_PCDISP8BY2: + case BFD_RELOC_SH_PCDISP12BY2: + case BFD_RELOC_SH_USES: + symbol_ptr = seg->dot; + break; + default: + break; + } + } + + if (fix->fx_r_type == BFD_RELOC_SH_USES) + { + /* We can't store the offset in the object file, since this + reloc does not take up any space, so we store it in r_offset. + The fx_addnumber field was set in md_apply_fix. */ + intr->r_offset = fix->fx_addnumber; + } + else if (fix->fx_r_type == BFD_RELOC_SH_COUNT) + { + /* We can't store the count in the object file, since this reloc + does not take up any space, so we store it in r_offset. The + fx_offset field was set when the fixup was created in + sh_coff_frob_file. */ + intr->r_offset = fix->fx_offset; + /* This reloc is always absolute. */ + symbol_ptr = NULL; + } + else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN) + { + /* Store the alignment in the r_offset field. */ + intr->r_offset = fix->fx_offset; + /* This reloc is always absolute. */ + symbol_ptr = NULL; + } + else if (fix->fx_r_type == BFD_RELOC_SH_CODE + || fix->fx_r_type == BFD_RELOC_SH_DATA + || fix->fx_r_type == BFD_RELOC_SH_LABEL) + { + /* These relocs are always absolute. */ + symbol_ptr = NULL; + } + + /* Turn the segment of the symbol into an offset. */ + if (symbol_ptr != NULL) + { + dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; + if (dot != NULL) + intr->r_symndx = dot->sy_number; + else + intr->r_symndx = symbol_ptr->sy_number; + } + else + intr->r_symndx = -1; +} + +#endif /* OBJ_COFF */ +#endif /* ! BFD_ASSEMBLER */ + +#ifdef BFD_ASSEMBLER + +/* Create a reloc. */ + +arelent * +tc_gen_reloc (section, fixp) + asection *section; + fixS *fixp; +{ + arelent *rel; + bfd_reloc_code_real_type r_type; + + rel = (arelent *) xmalloc (sizeof (arelent)); + rel->sym_ptr_ptr = &fixp->fx_addsy->bsym; + rel->address = fixp->fx_frag->fr_address + fixp->fx_where; + + r_type = fixp->fx_r_type; + + if (SWITCH_TABLE (fixp)) + { + rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy); + if (r_type == BFD_RELOC_16) + r_type = BFD_RELOC_SH_SWITCH16; + else if (r_type == BFD_RELOC_32) + r_type = BFD_RELOC_SH_SWITCH32; + else + abort (); + } + else if (r_type == BFD_RELOC_SH_USES) + rel->addend = fixp->fx_addnumber; + else if (r_type == BFD_RELOC_SH_COUNT) + rel->addend = fixp->fx_offset; + else if (r_type == BFD_RELOC_SH_ALIGN) + rel->addend = fixp->fx_offset; + else if (fixp->fx_pcrel) + rel->addend = fixp->fx_addnumber; + else + rel->addend = 0; + + rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); + if (rel->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "Cannot represent relocation type %s", + bfd_get_reloc_code_name (r_type)); + /* Set howto to a garbage value so that we can keep going. */ + rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + assert (rel->howto != NULL); + } + + return rel; +} + +#endif /* BFD_ASSEMBLER */ diff --git a/contrib/binutils/gas/config/tc-sh.h b/contrib/binutils/gas/config/tc-sh.h new file mode 100644 index 0000000..fb5c9ef --- /dev/null +++ b/contrib/binutils/gas/config/tc-sh.h @@ -0,0 +1,134 @@ +/* This file is tc-sh.h + Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define TC_SH + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#define TARGET_ARCH bfd_arch_sh + +/* Whether in little endian mode. */ +extern int shl; + +/* Whether -relax was used. */ +extern int sh_relax; + +/* Don't try to break words. */ +#define WORKING_DOT_WORD + +/* When relaxing, we need to generate relocations for alignment + directives. */ +#define HANDLE_ALIGN(frag) sh_handle_align (frag) +extern void sh_handle_align PARAMS ((fragS *)); + +/* We need to force out some relocations when relaxing. */ +#define TC_FORCE_RELOCATION(fix) sh_force_relocation (fix) +extern int sh_force_relocation (); + +#define IGNORE_NONSTANDARD_ESCAPES + +#define LISTING_HEADER (shl ? "Hitachi Super-H GAS Little Endian" : "Hitachi Super-H GAS Big Endian") + +#define md_operand(x) + +extern const struct relax_type md_relax_table[]; +#define TC_GENERIC_RELAX_TABLE md_relax_table + +/* We use a special alignment function to insert the correct nop + pattern. */ +extern int sh_do_align PARAMS ((int, const char *, int, int)); +#define md_do_align(n,fill,len,max,l) if (sh_do_align (n,fill,len,max)) goto l + +/* We record, for each section, whether we have most recently output a + CODE reloc or a DATA reloc. */ +struct sh_segment_info_type +{ + int in_code : 1; +}; +#define TC_SEGMENT_INFO_TYPE struct sh_segment_info_type + +/* We call a routine to emit a reloc for a label, so that the linker + can align loads and stores without crossing a label. */ +extern void sh_frob_label PARAMS ((void)); +#define tc_frob_label(sym) sh_frob_label () + +/* We call a routine to flush pending output in order to output a DATA + reloc when required. */ +extern void sh_flush_pending_output PARAMS ((void)); +#define md_flush_pending_output() sh_flush_pending_output () + +#ifdef BFD_ASSEMBLER +#define tc_frob_file_before_adjust sh_frob_file +#else +#define tc_frob_file sh_frob_file +#endif +extern void sh_frob_file PARAMS ((void)); + +#ifdef OBJ_COFF +/* COFF specific definitions. */ + +#define DO_NOT_STRIP 0 + +/* This macro translates between an internal fix and an coff reloc type */ +#define TC_COFF_FIX2RTYPE(fix) ((fix)->fx_r_type) + +#define BFD_ARCH TARGET_ARCH + +#define COFF_MAGIC (shl ? SH_ARCH_MAGIC_LITTLE : SH_ARCH_MAGIC_BIG) + +/* We need to write out relocs which have not been completed. */ +#define TC_COUNT_RELOC(fix) ((fix)->fx_addsy != NULL) + +#define TC_RELOC_MANGLE(seg, fix, int, paddr) \ + sh_coff_reloc_mangle ((seg), (fix), (int), (paddr)) +extern void sh_coff_reloc_mangle (); + +#define tc_coff_symbol_emit_hook(a) ; /* not used */ + +#define NEED_FX_R_TYPE 1 + +#define TC_KEEP_FX_OFFSET 1 + +#define TC_COFF_SIZEMACHDEP(frag) tc_coff_sizemachdep(frag) +extern int tc_coff_sizemachdep PARAMS ((fragS *)); + +/* We align most sections to a 16 byte boundary. */ +#define SUB_SEGMENT_ALIGN(SEG) \ + (strncmp (obj_segment_name (SEG), ".stabstr", 8) == 0 \ + ? 0 \ + : ((strncmp (obj_segment_name (SEG), ".stab", 5) == 0 \ + || strcmp (obj_segment_name (SEG), ".ctors") == 0 \ + || strcmp (obj_segment_name (SEG), ".dtors") == 0) \ + ? 2 \ + : 4)) + +#endif /* OBJ_COFF */ + +#ifdef OBJ_ELF +/* ELF specific definitions. */ + +/* Whether or not the target is big endian */ +extern int target_big_endian; + +#define TARGET_FORMAT (shl ? "elf32-shl" : "elf32-sh") + +#endif /* OBJ_ELF */ + +/* end of tc-sh.h */ diff --git a/contrib/binutils/gas/config/tc-z8k.c b/contrib/binutils/gas/config/tc-z8k.c new file mode 100644 index 0000000..909dd92 --- /dev/null +++ b/contrib/binutils/gas/config/tc-z8k.c @@ -0,0 +1,1613 @@ +/* tc-z8k.c -- Assemble code for the Zilog Z800n + Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + Written By Steve Chamberlain + sac@cygnus.com + */ +#define DEFINE_TABLE +#include <stdio.h> + +#include "opcodes/z8k-opc.h" + +#include "as.h" +#include "bfd.h" +#include <ctype.h> + +const char comment_chars[] = +{'!', 0}; +const char line_separator_chars[] = +{';', 0}; +const char line_comment_chars[] = +{'#', 0}; + +extern int machine; +extern int coff_flags; +int segmented_mode; +const int md_reloc_size; + +/* This table describes all the machine specific pseudo-ops the assembler + has to support. The fields are: + pseudo-op name without dot + function to call to execute this pseudo-op + Integer arg to pass to the function + */ + +void cons (); + +void +s_segm () +{ + segmented_mode = 1; + machine = bfd_mach_z8001; + coff_flags = F_Z8001; +} + +void +s_unseg () +{ + segmented_mode = 0; + machine = bfd_mach_z8002; + coff_flags = F_Z8002; +} + +static +void +even () +{ + frag_align (1, 0, 0); + record_alignment (now_seg, 1); +} + +void obj_coff_section (); + +int +tohex (c) + int c; +{ + if (isdigit (c)) + return c - '0'; + if (islower (c)) + return c - 'a' + 10; + return c - 'A' + 10; +} + +void +sval () +{ + + SKIP_WHITESPACE (); + if (*input_line_pointer == '\'') + { + int c; + input_line_pointer++; + c = *input_line_pointer++; + while (c != '\'') + { + if (c == '%') + { + c = (tohex (input_line_pointer[0]) << 4) + | tohex (input_line_pointer[1]); + input_line_pointer += 2; + } + FRAG_APPEND_1_CHAR (c); + c = *input_line_pointer++; + } + demand_empty_rest_of_line (); + } + +} +const pseudo_typeS md_pseudo_table[] = +{ + {"int", cons, 2}, + {"data.b", cons, 1}, + {"data.w", cons, 2}, + {"data.l", cons, 4}, + {"form", listing_psize, 0}, + {"heading", listing_title, 0}, + {"import", s_ignore, 0}, + {"page", listing_eject, 0}, + {"program", s_ignore, 0}, + {"z8001", s_segm, 0}, + {"z8002", s_unseg, 0}, + + + {"segm", s_segm, 0}, + {"unsegm", s_unseg, 0}, + {"unseg", s_unseg, 0}, + {"name", s_app_file, 0}, + {"global", s_globl, 0}, + {"wval", cons, 2}, + {"lval", cons, 4}, + {"bval", cons, 1}, + {"sval", sval, 0}, + {"rsect", obj_coff_section, 0}, + {"sect", obj_coff_section, 0}, + {"block", s_space, 0}, + {"even", even, 0}, + {0, 0, 0} +}; + +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ + +void +md_begin () +{ + opcode_entry_type *opcode; + char *prev_name = ""; + int idx = 0; + + opcode_hash_control = hash_new (); + + for (opcode = z8k_table; opcode->name; opcode++) + { + /* Only enter unique codes into the table */ + char *src = opcode->name; + + if (strcmp (opcode->name, prev_name)) + { + hash_insert (opcode_hash_control, opcode->name, (char *) opcode); + idx++; + } + opcode->idx = idx; + prev_name = opcode->name; + } + + /* default to z8002 */ + s_unseg (); + + /* insert the pseudo ops too */ + for (idx = 0; md_pseudo_table[idx].poc_name; idx++) + { + opcode_entry_type *fake_opcode; + fake_opcode = (opcode_entry_type *) malloc (sizeof (opcode_entry_type)); + fake_opcode->name = md_pseudo_table[idx].poc_name, + fake_opcode->func = (void *) (md_pseudo_table + idx); + fake_opcode->opcode = 250; + hash_insert (opcode_hash_control, fake_opcode->name, fake_opcode); + } + + linkrelax = 1; +} + +struct z8k_exp +{ + char *e_beg; + char *e_end; + expressionS e_exp; +}; +typedef struct z8k_op +{ + char regsize; /* 'b','w','r','q' */ + unsigned int reg; /* 0..15 */ + + int mode; + + unsigned int x_reg; /* any other register associated with the mode */ + expressionS exp; /* any expression */ +} + +op_type; + +static expressionS *da_operand; +static expressionS *imm_operand; + +int reg[16]; +int the_cc; +int the_ctrl; +int the_flags; +int the_interrupt; + +char * +DEFUN (whatreg, (reg, src), + int *reg AND + char *src) +{ + if (isdigit (src[1])) + { + *reg = (src[0] - '0') * 10 + src[1] - '0'; + return src + 2; + } + else + { + *reg = (src[0] - '0'); + return src + 1; + } +} + +/* + parse operands + + rh0-rh7, rl0-rl7 + r0-r15 + rr0-rr14 + rq0--rq12 + WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp + r0l,r0h,..r7l,r7h + @WREG + @WREG+ + @-WREG + #const + + */ + +/* try and parse a reg name, returns number of chars consumed */ +char * +DEFUN (parse_reg, (src, mode, reg), + char *src AND + int *mode AND + unsigned int *reg) +{ + char *res = 0; + char regno; + + if (src[0] == 's' && src[1] == 'p') + { + if (segmented_mode) + { + *mode = CLASS_REG_LONG; + *reg = 14; + } + else + { + *mode = CLASS_REG_WORD; + *reg = 15; + } + return src + 2; + } + if (src[0] == 'r') + { + if (src[1] == 'r') + { + *mode = CLASS_REG_LONG; + res = whatreg (reg, src + 2); + regno = *reg; + if (regno > 14) + as_warn ("register rr%d, out of range.",regno); + } + else if (src[1] == 'h') + { + *mode = CLASS_REG_BYTE; + res = whatreg (reg, src + 2); + regno = *reg; + if (regno > 7) + as_warn ("register rh%d, out of range.",regno); + } + else if (src[1] == 'l') + { + *mode = CLASS_REG_BYTE; + res = whatreg (reg, src + 2); + regno = *reg; + if (regno > 7) + as_warn ("register rl%d, out of range.",regno); + *reg += 8; + } + else if (src[1] == 'q') + { + *mode = CLASS_REG_QUAD; + res = whatreg (reg, src + 2); + regno = *reg; + if (regno > 12) + as_warn ("register rq%d, out of range.",regno); + } + else + { + *mode = CLASS_REG_WORD; + res = whatreg (reg, src + 1); + regno = *reg; + if (regno > 15) + as_warn ("register r%d, out of range.",regno); + } + } + return res; + +} + +char * +DEFUN (parse_exp, (s, op), + char *s AND + expressionS * op) +{ + char *save = input_line_pointer; + char *new; + + input_line_pointer = s; + expression (op); + if (op->X_op == O_absent) + as_bad ("missing operand"); + new = input_line_pointer; + input_line_pointer = save; + return new; +} + +/* The many forms of operand: + + <rb> + <r> + <rr> + <rq> + @r + #exp + exp + exp(r) + r(#exp) + r(r) + + + + */ + +static +char * +DEFUN (checkfor, (ptr, what), + char *ptr AND + char what) +{ + if (*ptr == what) + ptr++; + else + { + as_bad ("expected %c", what); + } + return ptr; +} + +/* Make sure the mode supplied is the size of a word */ +static void +DEFUN (regword, (mode, string), + int mode AND + char *string) +{ + int ok; + + ok = CLASS_REG_WORD; + if (ok != mode) + { + as_bad ("register is wrong size for a word %s", string); + } +} + +/* Make sure the mode supplied is the size of an address */ +static void +DEFUN (regaddr, (mode, string), + int mode AND + char *string) +{ + int ok; + + ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD; + if (ok != mode) + { + as_bad ("register is wrong size for address %s", string); + } +} + +struct ctrl_names +{ + int value; + char *name; +}; + +struct ctrl_names ctrl_table[] = +{ + 0x2, "fcw", + 0X3, "refresh", + 0x4, "psapseg", + 0x5, "psapoff", + 0x5, "psap", + 0x6, "nspseg", + 0x7, "nspoff", + 0x7, "nsp", + 0, 0 +}; + +static void +DEFUN (get_ctrl_operand, (ptr, mode, dst), + char **ptr AND + struct z8k_op *mode AND + unsigned int dst) +{ + char *src = *ptr; + int r; + int i; + + while (*src == ' ') + src++; + + mode->mode = CLASS_CTRL; + for (i = 0; ctrl_table[i].name; i++) + { + int j; + + for (j = 0; ctrl_table[i].name[j]; j++) + { + if (ctrl_table[i].name[j] != src[j]) + goto fail; + } + the_ctrl = ctrl_table[i].value; + *ptr = src + j; + return; + fail:; + } + the_ctrl = 0; + return; +} + +struct flag_names +{ + int value; + char *name; + +}; + +struct flag_names flag_table[] = +{ + 0x1, "p", + 0x1, "v", + 0x2, "s", + 0x4, "z", + 0x8, "c", + 0x0, "+", + 0, 0 +}; + +static void +DEFUN (get_flags_operand, (ptr, mode, dst), + char **ptr AND + struct z8k_op *mode AND + unsigned int dst) +{ + char *src = *ptr; + int r; + int i; + int j; + + while (*src == ' ') + src++; + + mode->mode = CLASS_FLAGS; + the_flags = 0; + for (j = 0; j <= 9; j++) + { + if (!src[j]) + goto done; + for (i = 0; flag_table[i].name; i++) + { + if (flag_table[i].name[0] == src[j]) + { + the_flags = the_flags | flag_table[i].value; + goto match; + } + } + goto done; + match: + ; + } + done: + *ptr = src + j; + return; +} + + +struct interrupt_names +{ + int value; + char *name; + +}; + +struct interrupt_names intr_table[] = +{ + 0x1, "nvi", + 0x2, "vi", + 0x3, "both", + 0x3, "all", + 0, 0 +}; + +static void +DEFUN (get_interrupt_operand, (ptr, mode, dst), + char **ptr AND + struct z8k_op *mode AND + unsigned int dst) +{ + char *src = *ptr; + int r; + int i; + + while (*src == ' ') + src++; + + mode->mode = CLASS_IMM; + for (i = 0; intr_table[i].name; i++) + { + int j; + + for (j = 0; intr_table[i].name[j]; j++) + { + if (intr_table[i].name[j] != src[j]) + goto fail; + } + the_interrupt = intr_table[i].value; + *ptr = src + j; + return; + fail:; + } + the_interrupt = 0x0; + return; +} + +struct cc_names +{ + int value; + char *name; + +}; + +struct cc_names table[] = +{ + 0x0, "f", + 0x1, "lt", + 0x2, "le", + 0x3, "ule", + 0x4, "ov", + 0x4, "pe", + 0x5, "mi", + 0x6, "eq", + 0x6, "z", + 0x7, "c", + 0x7, "ult", + 0x8, "t", + 0x9, "ge", + 0xa, "gt", + 0xb, "ugt", + 0xc, "nov", + 0xc, "po", + 0xd, "pl", + 0xe, "ne", + 0xe, "nz", + 0xf, "nc", + 0xf, "uge", + 0, 0 +}; + +static void +DEFUN (get_cc_operand, (ptr, mode, dst), + char **ptr AND + struct z8k_op *mode AND + unsigned int dst) +{ + char *src = *ptr; + int r; + int i; + + while (*src == ' ') + src++; + + mode->mode = CLASS_CC; + for (i = 0; table[i].name; i++) + { + int j; + + for (j = 0; table[i].name[j]; j++) + { + if (table[i].name[j] != src[j]) + goto fail; + } + the_cc = table[i].value; + *ptr = src + j; + return; + fail:; + } + the_cc = 0x8; +} + +static void +get_operand (ptr, mode, dst) + char **ptr; + struct z8k_op *mode; + unsigned int dst; +{ + char *src = *ptr; + char *end; + unsigned int num; + unsigned int len; + unsigned int size; + + mode->mode = 0; + + while (*src == ' ') + src++; + if (*src == '#') + { + mode->mode = CLASS_IMM; + imm_operand = &(mode->exp); + src = parse_exp (src + 1, &(mode->exp)); + } + else if (*src == '@') + { + int d; + + mode->mode = CLASS_IR; + src = parse_reg (src + 1, &d, &mode->reg); + } + else + { + int regn; + + end = parse_reg (src, &mode->mode, ®n); + + if (end) + { + int nw, nr; + + src = end; + if (*src == '(') + { + src++; + end = parse_reg (src, &nw, &nr); + if (end) + { + /* Got Ra(Rb) */ + src = end; + + if (*src != ')') + { + as_bad ("Missing ) in ra(rb)"); + } + else + { + src++; + } + + regaddr (mode->mode, "ra(rb) ra"); +/* regword (mode->mode, "ra(rb) rb");*/ + mode->mode = CLASS_BX; + mode->reg = regn; + mode->x_reg = nr; + reg[ARG_RX] = nr; + } + else + { + /* Got Ra(disp) */ + if (*src == '#') + src++; + src = parse_exp (src, &(mode->exp)); + src = checkfor (src, ')'); + mode->mode = CLASS_BA; + mode->reg = regn; + mode->x_reg = 0; + imm_operand = &(mode->exp); + } + } + else + { + mode->reg = regn; + mode->x_reg = 0; + } + } + else + { + /* No initial reg */ + src = parse_exp (src, &(mode->exp)); + if (*src == '(') + { + src++; + end = parse_reg (src, &(mode->mode), ®n); + regword (mode->mode, "addr(Ra) ra"); + mode->mode = CLASS_X; + mode->reg = regn; + mode->x_reg = 0; + da_operand = &(mode->exp); + src = checkfor (end, ')'); + } + else + { + /* Just an address */ + mode->mode = CLASS_DA; + mode->reg = 0; + mode->x_reg = 0; + da_operand = &(mode->exp); + } + } + } + *ptr = src; +} + +static +char * +get_operands (opcode, op_end, operand) + opcode_entry_type *opcode; + char *op_end; + op_type *operand; +{ + char *ptr = op_end; +char *savptr; + switch (opcode->noperands) + { + case 0: + operand[0].mode = 0; + operand[1].mode = 0; + break; + + case 1: + ptr++; + if (opcode->arg_info[0] == CLASS_CC) + { + get_cc_operand (&ptr, operand + 0, 0); + } + else if (opcode->arg_info[0] == CLASS_FLAGS) + { + get_flags_operand (&ptr, operand + 0, 0); + } + else if (opcode->arg_info[0] == (CLASS_IMM +(ARG_IMM2))) + { + get_interrupt_operand (&ptr, operand + 0, 0); + } + else + { + get_operand (&ptr, operand + 0, 0); + } + operand[1].mode = 0; + break; + + case 2: + ptr++; + savptr = ptr; + if (opcode->arg_info[0] == CLASS_CC) + { + get_cc_operand (&ptr, operand + 0, 0); + } + else if (opcode->arg_info[0] == CLASS_CTRL) + { + get_ctrl_operand (&ptr, operand + 0, 0); + if (the_ctrl == 0) + { + ptr = savptr; + get_operand (&ptr, operand + 0, 0); + if (ptr == 0) + return; + if (*ptr == ',') + ptr++; + get_ctrl_operand (&ptr, operand + 1, 1); + return ptr; + } + } + else + { + get_operand (&ptr, operand + 0, 0); + } + if (ptr == 0) + return; + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 1, 1); + break; + + case 3: + ptr++; + get_operand (&ptr, operand + 0, 0); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 1, 1); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 2, 2); + break; + + case 4: + ptr++; + get_operand (&ptr, operand + 0, 0); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 1, 1); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 2, 2); + if (*ptr == ',') + ptr++; + get_cc_operand (&ptr, operand + 3, 3); + break; + default: + abort (); + } + + return ptr; +} + +/* Passed a pointer to a list of opcodes which use different + addressing modes, return the opcode which matches the opcodes + provided + */ + +static +opcode_entry_type * +DEFUN (get_specific, (opcode, operands), + opcode_entry_type * opcode AND + op_type * operands) + +{ + opcode_entry_type *this_try = opcode; + int found = 0; + unsigned int noperands = opcode->noperands; + + unsigned int dispreg; + unsigned int this_index = opcode->idx; + + while (this_index == opcode->idx && !found) + { + unsigned int i; + + this_try = opcode++; + for (i = 0; i < noperands; i++) + { + int mode = operands[i].mode; + + if ((mode & CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK)) + { + /* it could be an pc rel operand, if this is a da mode and + we like disps, then insert it */ + + if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP) + { + /* This is the case */ + operands[i].mode = CLASS_DISP; + } + else if (mode == CLASS_BA && this_try->arg_info[i]) + { + /* Can't think of a way to turn what we've been given into + something that's ok */ + goto fail; + } + else if (this_try->arg_info[i] & CLASS_PR) + { + if (mode == CLASS_REG_LONG && segmented_mode) + { + /* ok */ + } + else if (mode == CLASS_REG_WORD && !segmented_mode) + { + /* ok */ + } + else + goto fail; + } + else + goto fail; + } + switch (mode & CLASS_MASK) + { + default: + break; + case CLASS_X: + case CLASS_IR: + case CLASS_BA: + case CLASS_BX: + case CLASS_DISP: + case CLASS_REG: + case CLASS_REG_WORD: + case CLASS_REG_BYTE: + case CLASS_REG_QUAD: + case CLASS_REG_LONG: + case CLASS_REGN0: + reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg; + break; + } + } + + found = 1; + fail:; + } + if (found) + return this_try; + else + return 0; +} + +static void +DEFUN (check_operand, (operand, width, string), + struct z8k_op *operand AND + unsigned int width AND + char *string) +{ + if (operand->exp.X_add_symbol == 0 + && operand->exp.X_op_symbol == 0) + { + + /* No symbol involved, let's look at offset, it's dangerous if any of + the high bits are not 0 or ff's, find out by oring or anding with + the width and seeing if the answer is 0 or all fs*/ + if ((operand->exp.X_add_number & ~width) != 0 && + (operand->exp.X_add_number | width) != (~0)) + { + as_warn ("operand %s0x%x out of range.", string, operand->exp.X_add_number); + } + } + +} + +static char buffer[20]; + +static void +DEFUN (newfix, (ptr, type, operand), + int ptr AND + int type AND + expressionS * operand) +{ + if (operand->X_add_symbol + || operand->X_op_symbol + || operand->X_add_number) + { + fix_new_exp (frag_now, + ptr, + 1, + operand, + 0, + type); + } +} + +static char * +DEFUN (apply_fix, (ptr, type, operand, size), + char *ptr AND + int type AND + expressionS * operand AND + int size) +{ + int n = operand->X_add_number; + + operand->X_add_number = n; + newfix ((ptr - buffer) / 2, type, operand); +#if 1 + switch (size) + { + case 8: /* 8 nibbles == 32 bits */ + *ptr++ = n >> 28; + *ptr++ = n >> 24; + *ptr++ = n >> 20; + *ptr++ = n >> 16; + case 4: /* 4 niblles == 16 bits */ + *ptr++ = n >> 12; + *ptr++ = n >> 8; + case 2: + *ptr++ = n >> 4; + case 1: + *ptr++ = n >> 0; + break; + } +#endif + return ptr; + +} + +/* Now we know what sort of opcodes it is, lets build the bytes - + */ +#define INSERT(x,y) *x++ = y>>24; *x++ = y>> 16; *x++=y>>8; *x++ =y; +static void +build_bytes (this_try, operand) + opcode_entry_type * this_try; + struct z8k_op *operand; +{ + unsigned int i; + + int length; + char *output; + char *output_ptr = buffer; + char part; + int c; + char high; + int nib; + int nibble; + unsigned int *class_ptr; + + frag_wane (frag_now); + frag_new (0); + + memset (buffer, 20, 0); + class_ptr = this_try->byte_info; +top:; + + for (nibble = 0; c = *class_ptr++; nibble++) + { + + switch (c & CLASS_MASK) + { + default: + + abort (); + case CLASS_ADDRESS: + /* Direct address, we don't cope with the SS mode right now */ + if (segmented_mode) + { + da_operand->X_add_number |= 0x80000000; + output_ptr = apply_fix (output_ptr, R_IMM32, da_operand, 8); + } + else + { + output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); + } + da_operand = 0; + break; + case CLASS_DISP8: + /* pc rel 8 bit */ + output_ptr = apply_fix (output_ptr, R_JR, da_operand, 2); + da_operand = 0; + break; + + case CLASS_0DISP7: + /* pc rel 7 bit */ + *output_ptr = 0; + output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); + da_operand = 0; + break; + + case CLASS_1DISP7: + /* pc rel 7 bit */ + *output_ptr = 0x80; + output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); + output_ptr[-2] = 0x8; + da_operand = 0; + break; + + case CLASS_BIT_1OR2: + *output_ptr = c & 0xf; + if (imm_operand) + { + if (imm_operand->X_add_number == 2) + { + *output_ptr |= 2; + } + else if (imm_operand->X_add_number != 1) + { + as_bad ("immediate must be 1 or 2"); + } + } + else + { + as_bad ("immediate 1 or 2 expected"); + } + output_ptr++; + break; + case CLASS_CC: + *output_ptr++ = the_cc; + break; + case CLASS_0CCC: + *output_ptr++ = the_ctrl; + break; + case CLASS_1CCC: + *output_ptr++ = the_ctrl | 0x8; + break; + case CLASS_00II: + *output_ptr++ = (~the_interrupt & 0x3); + break; + case CLASS_01II: + *output_ptr++ = (~the_interrupt & 0x3) | 0x4; + break; + case CLASS_FLAGS: + *output_ptr++ = the_flags; + break; + case CLASS_BIT: + *output_ptr++ = c & 0xf; + break; + case CLASS_REGN0: + if (reg[c & 0xf] == 0) + { + as_bad ("can't use R0 here"); + } + case CLASS_REG: + case CLASS_REG_BYTE: + case CLASS_REG_WORD: + case CLASS_REG_LONG: + case CLASS_REG_QUAD: + /* Insert bit mattern of + right reg */ + *output_ptr++ = reg[c & 0xf]; + break; + case CLASS_DISP: + output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); + da_operand = 0; + break; + + case CLASS_IMM: + { + nib = 0; + switch (c & ARG_MASK) + { + case ARG_IMM4: + output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); + break; + case ARG_IMM4M1: + imm_operand->X_add_number--; + output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); + break; + case ARG_IMMNMINUS1: + imm_operand->X_add_number--; + output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); + break; + case ARG_NIM8: + imm_operand->X_add_number = -imm_operand->X_add_number; + case ARG_IMM8: + output_ptr = apply_fix (output_ptr, R_IMM8, imm_operand, 2); + break; + case ARG_IMM16: + output_ptr = apply_fix (output_ptr, R_IMM16, imm_operand, 4); + break; + + case ARG_IMM32: + output_ptr = apply_fix (output_ptr, R_IMM32, imm_operand, 8); + break; + + default: + abort (); + } + } + } + } + + /* Copy from the nibble buffer into the frag */ + + { + int length = (output_ptr - buffer) / 2; + char *src = buffer; + char *fragp = frag_more (length); + + while (src < output_ptr) + { + *fragp = (src[0] << 4) | src[1]; + src += 2; + fragp++; + } + + } + +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This funciton is supposed to emit + the frags/bytes it assembles to. + */ + +void +DEFUN (md_assemble, (str), + char *str) +{ + char *op_start; + char *op_end; + unsigned int i; + struct z8k_op operand[3]; + opcode_entry_type *opcode; + opcode_entry_type *prev_opcode; + + char *dot = 0; + char c; + + /* Drop leading whitespace */ + while (*str == ' ') + str++; + + /* find the op code end */ + for (op_start = op_end = str; + *op_end != 0 && *op_end != ' '; + op_end++) + { + } + + ; + + if (op_end == op_start) + { + as_bad ("can't find opcode "); + } + c = *op_end; + + *op_end = 0; + + opcode = (opcode_entry_type *) hash_find (opcode_hash_control, + op_start); + + + if (opcode == NULL) + { + as_bad ("unknown opcode"); + return; + } + + if (opcode->opcode == 250) + { + /* was really a pseudo op */ + + pseudo_typeS *p; + char oc; + + char *old = input_line_pointer; + *op_end = c; + + + input_line_pointer = op_end; + + oc = *old; + *old = '\n'; + while (*input_line_pointer == ' ') + input_line_pointer++; + p = (pseudo_typeS *) (opcode->func); + + (p->poc_handler) (p->poc_val); + input_line_pointer = old; + *old = oc; + } + else + { + input_line_pointer = get_operands (opcode, op_end, + operand); + prev_opcode = opcode; + + opcode = get_specific (opcode, operand); + + if (opcode == 0) + { + /* Couldn't find an opcode which matched the operands */ + char *where = frag_more (2); + + where[0] = 0x0; + where[1] = 0x0; + + as_bad ("Can't find opcode to match operands"); + return; + } + + build_bytes (opcode, operand); + } +} + +void +DEFUN (tc_crawl_symbol_chain, (headers), + object_headers * headers) +{ + printf ("call to tc_crawl_symbol_chain \n"); +} + +symbolS * +DEFUN (md_undefined_symbol, (name), + char *name) +{ + return 0; +} + +void +DEFUN (tc_headers_hook, (headers), + object_headers * headers) +{ + printf ("call to tc_headers_hook \n"); +} + +/* Various routines to kill one day */ +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP . An error message is returned, or NULL on OK. + */ +char * +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee (); + + switch (type) + { + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP = 0; + return "Bad call to MD_ATOF()"; + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * sizeof (LITTLENUM_TYPE); + for (wordP = words; prec--;) + { + md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + return 0; +} + +CONST char *md_shortopts = "z:"; +struct option md_longopts[] = { + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); + +int +md_parse_option (c, arg) + int c; + char *arg; +{ + switch (c) + { + case 'z': + if (!strcmp (arg, "8001")) + s_segm (); + else if (!strcmp (arg, "8002")) + s_unseg (); + else + { + as_bad ("invalid architecture -z%s", arg); + return 0; + } + break; + + default: + return 0; + } + + return 1; +} + +void +md_show_usage (stream) + FILE *stream; +{ + fprintf(stream, "\ +Z8K options:\n\ +-z8001 generate segmented code\n\ +-z8002 generate unsegmented code\n"); +} + +int md_short_jump_size; + +void +tc_aout_fix_to_chars () +{ + printf ("call to tc_aout_fix_to_chars \n"); + abort (); +} + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr; + addressT to_addr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_convert_frag (headers, seg, fragP) + object_headers *headers; + segT seg; + fragS *fragP; +{ + printf ("call to md_convert_frag \n"); + abort (); +} + +valueT +DEFUN (md_section_align, (seg, size), + segT seg AND + valueT size) +{ + return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); + +} + +void +md_apply_fix (fixP, val) + fixS *fixP; + long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + switch (fixP->fx_r_type) + { + case R_IMM4L: + buf[0] = (buf[0] & 0xf0) | ((buf[0] + val) & 0xf); + break; + + case R_JR: + + *buf++ = val; + /* if (val != 0) abort();*/ + break; + + case R_DISP7: + + *buf++ += val; + /* if (val != 0) abort();*/ + break; + + case R_IMM8: + buf[0] += val; + break; + case R_IMM16: + *buf++ = (val >> 8); + *buf++ = val; + break; + case R_IMM32: + *buf++ = (val >> 24); + *buf++ = (val >> 16); + *buf++ = (val >> 8); + *buf++ = val; + break; +#if 0 + case R_DA | R_SEG: + *buf++ = (val >> 16); + *buf++ = 0x00; + *buf++ = (val >> 8); + *buf++ = val; + break; +#endif + + case 0: + md_number_to_chars (buf, val, fixP->fx_size); + break; + + default: + abort (); + + } +} + +int md_long_jump_size; +int +md_estimate_size_before_relax (fragP, segment_type) + register fragS *fragP; + register segT segment_type; +{ + printf ("call tomd_estimate_size_before_relax \n"); + abort (); +} + +/* Put number into target byte order */ + +void +DEFUN (md_number_to_chars, (ptr, use, nbytes), + char *ptr AND + valueT use AND + int nbytes) +{ + number_to_chars_bigendian (ptr, use, nbytes); +} +long +md_pcrel_from (fixP) + fixS *fixP; +{ + abort (); +} + +void +tc_coff_symbol_emit_hook (s) + struct symbol *s; +{ +} + +void +tc_reloc_mangle (fix_ptr, intr, base) + fixS *fix_ptr; + struct internal_reloc *intr; + bfd_vma base; + +{ + symbolS *symbol_ptr; + + if (fix_ptr->fx_addsy && + fix_ptr->fx_subsy) + { + symbolS *add = fix_ptr->fx_addsy; + symbolS *sub = fix_ptr->fx_subsy; + if (S_GET_SEGMENT(add) != S_GET_SEGMENT(sub)) + { + as_bad("Can't subtract symbols in different sections %s %s", + S_GET_NAME(add), S_GET_NAME(sub)); + } + else { + int diff = S_GET_VALUE(add) - S_GET_VALUE(sub); + fix_ptr->fx_addsy = 0; + fix_ptr->fx_subsy = 0; + fix_ptr->fx_offset += diff; + } + } + symbol_ptr = fix_ptr->fx_addsy; + + /* If this relocation is attached to a symbol then it's ok + to output it */ + if (fix_ptr->fx_r_type == 0) + { + /* cons likes to create reloc32's whatever the size of the reloc.. */ + switch (fix_ptr->fx_size) + { + case 2: + intr->r_type = R_IMM16; + break; + case 1: + intr->r_type = R_IMM8; + break; + case 4: + intr->r_type = R_IMM32; + break; + default: + abort (); + } + + } + else + { + intr->r_type = fix_ptr->fx_r_type; + } + + intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base; + intr->r_offset = fix_ptr->fx_offset; + + if (symbol_ptr) + intr->r_symndx = symbol_ptr->sy_number; + else + intr->r_symndx = -1; +} + diff --git a/contrib/binutils/gas/config/tc-z8k.h b/contrib/binutils/gas/config/tc-z8k.h new file mode 100644 index 0000000..1a58502 --- /dev/null +++ b/contrib/binutils/gas/config/tc-z8k.h @@ -0,0 +1,46 @@ +/* This file is tc-z8k.h + Copyright (C) 1987-1992, 93, 95, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#define TC_Z8K +#define TARGET_BYTES_BIG_ENDIAN 1 + +#ifndef BFD_ASSEMBLER +#define LOCAL_LABEL(x) 0 +#endif + +/* This macro translates between an internal fix and an coff reloc type */ +#define TC_COFF_FIX2RTYPE(fixP) abort(); + +#define BFD_ARCH bfd_arch_z8k +#define COFF_MAGIC 0x8000 +#define TC_COUNT_RELOC(x) (1) +#define IGNORE_NONSTANDARD_ESCAPES + +#define TC_RELOC_MANGLE(s,a,b,c) tc_reloc_mangle(a,b,c) + +#define DO_NOT_STRIP 0 +#define LISTING_HEADER "Zilog Z8000 GAS " +#define NEED_FX_R_TYPE 1 +#define RELOC_32 1234 + +#define md_operand(x) + +/* end of tc-z8k.h */ diff --git a/contrib/binutils/gas/config/te-386bsd.h b/contrib/binutils/gas/config/te-386bsd.h new file mode 100644 index 0000000..dbff990 --- /dev/null +++ b/contrib/binutils/gas/config/te-386bsd.h @@ -0,0 +1,31 @@ +/* te-386bsd.h -- 386BSD target environment declarations. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TE_386BSD 1 + +#include "obj-format.h" + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of te-sun3.h */ diff --git a/contrib/binutils/gas/config/te-aux.h b/contrib/binutils/gas/config/te-aux.h new file mode 100644 index 0000000..da6fa01 --- /dev/null +++ b/contrib/binutils/gas/config/te-aux.h @@ -0,0 +1,17 @@ +#define TE_AUX + +/* From obj-coff.h: + This internal_lineno crap is to stop namespace pollution from the + bfd internal coff headerfile. */ +#define internal_lineno bfd_internal_lineno +#include "coff/aux-coff.h" /* override bits in coff/internal.h */ +#undef internal_lineno + +#define COFF_NOLOAD_PROBLEM +#define KEEP_RELOC_INFO + +#include "obj-format.h" + +#ifndef LOCAL_LABELS_FB +#define LOCAL_LABELS_FB 1 +#endif diff --git a/contrib/binutils/gas/config/te-generic.h b/contrib/binutils/gas/config/te-generic.h new file mode 100644 index 0000000..b8eda45 --- /dev/null +++ b/contrib/binutils/gas/config/te-generic.h @@ -0,0 +1,22 @@ +/* + * This file is te-generic.h and is intended to be a template for + * target environment specific header files. + * + * It is my intent that this file will evolve into a file suitable for config, + * compile, and copying as an aid for testing and porting. xoxorich. + */ + +/* Added these, because if we don't know what we're targetting we may + need an assembler version of libgcc, and that will use local + labels. */ +#define LOCAL_LABELS_DOLLAR 1 +#define LOCAL_LABELS_FB 1 + +/* these define interfaces */ +#ifdef OBJ_HEADER +#include OBJ_HEADER +#else +#include "obj-format.h" +#endif + +/* end of te-generic.h */ diff --git a/contrib/binutils/gas/config/te-linux.h b/contrib/binutils/gas/config/te-linux.h new file mode 100644 index 0000000..c235a7a --- /dev/null +++ b/contrib/binutils/gas/config/te-linux.h @@ -0,0 +1,4 @@ +#define TE_LINUX +#define LOCAL_LABELS_FB 1 + +#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-multi.h b/contrib/binutils/gas/config/te-multi.h new file mode 100644 index 0000000..b8eda45 --- /dev/null +++ b/contrib/binutils/gas/config/te-multi.h @@ -0,0 +1,22 @@ +/* + * This file is te-generic.h and is intended to be a template for + * target environment specific header files. + * + * It is my intent that this file will evolve into a file suitable for config, + * compile, and copying as an aid for testing and porting. xoxorich. + */ + +/* Added these, because if we don't know what we're targetting we may + need an assembler version of libgcc, and that will use local + labels. */ +#define LOCAL_LABELS_DOLLAR 1 +#define LOCAL_LABELS_FB 1 + +/* these define interfaces */ +#ifdef OBJ_HEADER +#include OBJ_HEADER +#else +#include "obj-format.h" +#endif + +/* end of te-generic.h */ diff --git a/contrib/binutils/gas/config/te-nbsd.h b/contrib/binutils/gas/config/te-nbsd.h new file mode 100644 index 0000000..2291ba5 --- /dev/null +++ b/contrib/binutils/gas/config/te-nbsd.h @@ -0,0 +1,21 @@ +/* te-nbsd.h -- NetBSD target environment declarations. + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TE_NetBSD 1 +#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-pe.h b/contrib/binutils/gas/config/te-pe.h new file mode 100644 index 0000000..1c1f0b2 --- /dev/null +++ b/contrib/binutils/gas/config/te-pe.h @@ -0,0 +1,7 @@ +#define TE_PE +#define LEX_AT 1 /* can have @'s inside labels */ + +/* The PE format supports long section names. */ +#define COFF_LONG_SECTION_NAMES + +#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-svr4.h b/contrib/binutils/gas/config/te-svr4.h new file mode 100644 index 0000000..7217ee1 --- /dev/null +++ b/contrib/binutils/gas/config/te-svr4.h @@ -0,0 +1,4 @@ +#define TE_SVR4 +#define LOCAL_LABELS_FB 1 + +#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-sysv32.h b/contrib/binutils/gas/config/te-sysv32.h new file mode 100644 index 0000000..923e6e5 --- /dev/null +++ b/contrib/binutils/gas/config/te-sysv32.h @@ -0,0 +1,6 @@ +/* Remove leading underscore from the gcc generated symbol names */ +#define STRIP_UNDERSCORE + +#include "obj-format.h" + +/* end of te-sysv32.h */ diff --git a/contrib/binutils/gas/configure b/contrib/binutils/gas/configure new file mode 100755 index 0000000..b188f4f --- /dev/null +++ b/contrib/binutils/gas/configure @@ -0,0 +1,2881 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-bfd-assembler use BFD back end for writing object files" +ac_help="$ac_help + targets alternative target configurations besides the primary" +ac_help="$ac_help + --enable-shared build shared BFD library" +ac_help="$ac_help + --enable-commonbfdlib build shared BFD/opcodes/libiberty library" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=as.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +user_bfd_gas= +# Check whether --enable-bfd-assembler or --disable-bfd-assembler was given. +if test "${enable_bfd_assembler+set}" = set; then + enableval="$enable_bfd_assembler" + case "${enableval}" in + yes) need_bfd=yes user_bfd_gas=yes ;; + no) user_bfd_gas=no ;; + *) { echo "configure: error: bad value ${enableval} given for bfd-assembler option" 1>&2; exit 1; } ;; +esac +fi +# Check whether --enable-targets or --disable-targets was given. +if test "${enable_targets+set}" = set; then + enableval="$enable_targets" + case "${enableval}" in + yes | "") { echo "configure: error: enable-targets option must specify target names or 'all'" 1>&2; exit 1; } + ;; + no) enable_targets= ;; + *) enable_targets=$enableval ;; +esac +fi +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + case "${enableval}" in + yes) shared=true shared_bfd=true shared_opcodes=true ;; + no) shared=false ;; + *bfd*opcodes*) shared=true shared_bfd=true shared_opcodes=true ;; + *opcodes*bfd*) shared=true shared_bfd=true shared_opcodes=true ;; + *bfd*) shared=true shared_bfd=true ;; + *opcodes*) shared=true shared_opcodes=true ;; + *) shared=false ;; +esac +fi +# Check whether --enable-commonbfdlib or --disable-commonbfdlib was given. +if test "${enable_commonbfdlib+set}" = set; then + enableval="$enable_commonbfdlib" + case "${enableval}" in + yes) commonbfdlib=true ;; + no) commonbfdlib=false ;; + *) { echo "configure: error: bad value ${enableval} for BFD commonbfdlib option" 1>&2; exit 1; } ;; +esac +fi + +# Generate a header file -- gets more post-processing by Makefile later. + + +ac_aux_dir= +for ac_dir in `cd $srcdir;pwd`/.. $srcdir/`cd $srcdir;pwd`/..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir;pwd`/.. $srcdir/`cd $srcdir;pwd`/.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:622: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:643: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`$ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:661: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`$ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +te_file=generic + +canon_targets="" +if test -n "$enable_targets" ; then + for t in `echo $enable_targets | sed 's/,/ /g'`; do + result=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $t 2>/dev/null` + if test -n "$result" ; then + canon_targets="$canon_targets $result" +# else +# # Permit "all", etc. We don't support it yet though. +# canon_targets="$canon_targets $t" + fi + done + _gas_uniq_list="$canon_targets" +_gas_uniq_newlist="" +for _gas_uniq_i in _gas_uniq_dummy $_gas_uniq_list ; do + case $_gas_uniq_i in + _gas_uniq_dummy) ;; + *) case " $_gas_uniq_newlist " in + *" $_gas_uniq_i "*) ;; + *) _gas_uniq_newlist="$_gas_uniq_newlist $_gas_uniq_i" ;; + esac ;; + esac +done +canon_targets=$_gas_uniq_newlist + +fi + +emulations="" + +for this_target in $target $canon_targets ; do + + eval `echo $this_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/cpu=\1 vendor=\2 os=\3/'` + + # check for architecture variants + case ${cpu} in + armeb) cpu_type=arm endian=big ;; + arm*) cpu_type=arm endian=little ;; + hppa*) cpu_type=hppa ;; + i[456]86) cpu_type=i386 ;; + m680[012346]0) cpu_type=m68k ;; + m68008) cpu_type=m68k ;; + m683??) cpu_type=m68k ;; + m8*) cpu_type=m88k ;; + mips*el) cpu_type=mips endian=little ;; + mips*) cpu_type=mips endian=big ;; + powerpcle*) cpu_type=ppc endian=little ;; + powerpc*) cpu_type=ppc endian=big ;; + rs6000*) cpu_type=ppc ;; + sparc64) cpu_type=sparc want_sparc_v9=true ;; + sparc*) cpu_type=sparc ;; + *) cpu_type=${cpu} ;; + esac + + if test ${this_target} = $target ; then + target_cpu_type=${cpu_type} + elif test ${target_cpu_type} != ${cpu_type} ; then + continue + fi + + targ=${cpu_type} + generic_target=${cpu_type}-$vendor-$os + dev=no + bfd_gas=no + em=generic + + # assign object format + case ${generic_target} in + a29k-*-coff) fmt=coff targ=ebmon29k ;; + a29k-amd-udi) fmt=coff targ=ebmon29k ;; + a29k-amd-ebmon) fmt=coff targ=ebmon29k ;; + a29k-nyu-sym1) fmt=coff targ=ebmon29k ;; + a29k-*-vxworks*) fmt=coff ;; + + alpha-*-*vms*) fmt=evax ;; + alpha-*-netware*) fmt=ecoff ;; + alpha-*-openbsd*) fmt=ecoff ;; + alpha-*-osf*) fmt=ecoff ;; + alpha-*-linuxecoff*) fmt=ecoff ;; + alpha-*-linux*) fmt=elf em=linux ;; + + + arm-*-riscix*) fmt=aout targ=arm-lit em=riscix ;; + arm-*-aout) fmt=aout + case "$endian" in + big) targ=arm-big ;; + *) targ=arm-lit ;; + esac + ;; + arm-*-coff) fmt=coff ;; + arm-*-riscix*) fmt=aout ;; + arm-*-pe) fmt=coff targ=armcoff em=pe ;; + + d10v-*-*) fmt=elf bfd_gas=yes ;; + + hppa-*-*elf*) fmt=elf em=hppa ;; + hppa-*-lites*) fmt=elf em=hppa ;; + hppa-*-osf*) fmt=som em=hppa ;; + hppa-*-rtems*) fmt=elf em=hppa ;; + hppa-*-hpux*) fmt=som em=hppa ;; + hppa-*-bsd*) fmt=som em=hppa ;; + hppa-*-hiux*) fmt=som em=hppa ;; + + h8300-*-coff) fmt=coff ;; + + i386-ibm-aix*) fmt=coff targ=i386coff + em=i386aix ;; + i386-sequent-bsd*) fmt=aout em=dynix bfd_gas=yes ;; + i386-*-bsd*) fmt=aout em=386bsd ;; + i386-*-netbsd0.8) fmt=aout em=386bsd ;; + i386-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes;; + i386-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes;; + i386-*-linux*aout* | i386-*-linuxoldld) fmt=aout em=linux ;; + i386-*-linux*coff*) fmt=coff em=linux + targ=i386coff ;; + i386-*-linux*) fmt=elf em=linux ;; + i386-*-lynxos*) fmt=coff targ=i386coff + em=lynx ;; + i386-*-sysv4* | i386-*-solaris* | i386-*-elf | i386-*-freebsdelf*) + fmt=elf ;; + i386-*-sco*elf*) fmt=elf targ=sco5 ;; + i386-*-coff | i386-*-sysv* | i386-*-sco* | i386-*-isc*) + fmt=coff targ=i386coff ;; + i386-*-vsta) fmt=aout ;; + i386-*-go32) fmt=coff targ=i386coff ;; + i386-*-rtems*) fmt=coff targ=i386coff ;; + i386-*-gnu*) fmt=elf ;; + i386-*-mach*) + fmt=aout em=mach bfd_gas=yes ;; + i386-*-msdos*) fmt=aout ;; + i386-*-moss*) fmt=elf ;; + i386-*-pe) fmt=coff targ=i386coff em=pe ;; + i386-*-cygwin32) fmt=coff targ=i386coff em=pe ;; + i386-*-*nt) fmt=coff targ=i386coff em=pe ;; + i960-*-bout) fmt=bout ;; + i960-*-coff) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-rtems*) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-nindy*) fmt=bout ;; + i960-*-vxworks4*) fmt=bout ;; + i960-*-vxworks5.0) fmt=bout ;; + i960-*-vxworks5.*) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-vxworks*) fmt=bout ;; + + m32r-*-*) fmt=elf bfd_gas=yes ;; + + m68k-*-vxworks* | m68k-ericsson-ose | m68k-*-sunos*) + fmt=aout em=sun3 ;; + m68k-motorola-sysv*) fmt=coff targ=m68kcoff em=delta ;; + m68k-bull-sysv3*) fmt=coff targ=m68kcoff em=dpx2 ;; + m68k-apollo-*) fmt=coff targ=apollo em=apollo ;; + m68k-*-sysv4*) # must be before -sysv* + fmt=elf em=svr4 ;; + m68k-*-elf*) fmt=elf ;; + m68k-*-coff | m68k-*-sysv* | m68k-*-rtems*) + fmt=coff targ=m68kcoff ;; + m68k-*-hpux*) fmt=hp300 em=hp300 ;; + m68k-*-linux*aout*) fmt=aout em=linux ;; + m68k-*-linux*) fmt=elf em=linux ;; + m68k-*-lynxos*) fmt=coff targ=m68kcoff + em=lynx ;; + m68k-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + m68k-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + m68k-apple-aux*) fmt=coff targ=m68kcoff em=aux ;; + m68k-*-psos*) fmt=elf em=psos;; + + m88k-motorola-sysv3*) fmt=coff targ=m88kcoff em=delt88 ;; + m88k-*-coff*) fmt=coff targ=m88kcoff ;; + + # don't change em like *-*-bsd does + mips-dec-netbsd*) fmt=elf targ=mips-lit endian=little ;; + mips-dec-openbsd*) fmt=elf targ=mips-lit endian=little ;; + mips-dec-bsd*) fmt=aout targ=mips-lit ;; + mips-sony-bsd*) fmt=ecoff targ=mips-big ;; + mips-*-bsd*) { echo "configure: error: Unknown vendor for mips-bsd configuration." 1>&2; exit 1; } ;; + mips-*-ultrix*) fmt=ecoff targ=mips-lit endian=little ;; + mips-*-osf*) fmt=ecoff targ=mips-lit endian=little ;; + mips-*-ecoff*) fmt=ecoff + case "$endian" in + big) targ=mips-big ;; + *) targ=mips-lit ;; + esac + ;; + mips-*-ecoff*) fmt=ecoff targ=mips-big ;; + mips-*-irix6*) fmt=elf targ=mips-big ;; + mips-*-irix5*) fmt=elf targ=mips-big ;; + mips-*-irix*) fmt=ecoff targ=mips-big ;; + mips-*-lnews*) fmt=ecoff targ=mips-lit em=lnews ;; + mips-*-riscos*) fmt=ecoff targ=mips-big ;; + mips-*-sysv*) fmt=ecoff targ=mips-big ;; + mips-*-elf* | mips-*-rtems* | mips-*-linux* | mips-*-gnu* | mips-*-openbsd*) + fmt=elf + case "$endian" in + big) targ=mips-big ;; + *) targ=mips-lit ;; + esac + ;; + mn10200-*-*) fmt=elf bfd_gas=yes ;; + mn10300-*-*) fmt=elf bfd_gas=yes ;; + ppc-*-pe | ppc-*-cygwin32 | ppc-*-winnt*) + fmt=coff em=pe + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-aix*) fmt=coff ;; + ppc-*-beos*) fmt=coff ;; + ppc-*-*bsd* | ppc-*-elf* | ppc-*-eabi* | ppc-*-sysv4*) + fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-linux*) fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) { echo "configure: error: Linux must be configured big endian" 1>&2; exit 1; } ;; + esac + ;; + ppc-*-solaris*) fmt=elf + case "$endian" in + big) { echo "configure: error: Solaris must be configured little endian" 1>&2; exit 1; } ;; + *) targ=ppc-sol ;; + esac + ;; + ppc-*-rtems*) + fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-macos* | ppc-*-mpw*) + fmt=coff em=macos ;; + ppc-*-netware*) fmt=elf em=ppcnw ;; + + sh-*-elf*) fmt=elf ;; + sh-*-coff*) fmt=coff ;; + + ns32k-pc532-mach* | ns32k-pc532-ux*) fmt=aout em=pc532mach ;; + ns32k-pc532-netbsd* | ns32k-pc532-lites*) fmt=aout em=nbsd532 ;; + ns32k-pc532-openbsd*) fmt=aout em=nbsd532 ;; + + sparc-*-rtems*) fmt=aout ;; + sparc-*-sunos4*) fmt=aout em=sun3 ;; + sparc-*-aout | sparc*-*-vxworks*) + fmt=aout em=sparcaout ;; + sparc-*-coff) fmt=coff ;; + sparc-*-linux*aout*) fmt=aout em=linux ;; + sparc-*-linux*) fmt=elf em=linux ;; + sparc-*-lynxos*) fmt=coff em=lynx ;; + sparc-fujitsu-none) fmt=aout ;; + sparc-*-elf | sparc-*-sysv4* | sparc-*-solaris*) + fmt=elf ;; + sparc-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + sparc-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + + vax-*-bsd* | vax-*-ultrix*) + fmt=aout ;; + vax-*-vms) fmt=vms ;; + + z8k-*-coff | z8k-*-sim) + fmt=coff ;; + + w65-*-*) fmt=coff ;; + + *-*-aout | *-*-scout) + fmt=aout ;; + *-*-nindy*) + fmt=bout ;; + *-*-bsd*) + fmt=aout em=sun3 ;; + *-*-generic) fmt=generic ;; + *-*-xray | *-*-hms) fmt=coff ;; + *-*-sim) fmt=coff ;; + *-*-elf | *-*-sysv4* | *-*-solaris*) + echo "configure: warning: GAS support for ${generic_target} is incomplete." 1>&2 + fmt=elf dev=yes ;; + *-*-vxworks) fmt=aout ;; + *-*-netware) fmt=elf ;; + esac + + case ${cpu_type}-${fmt} in + alpha-*) bfd_gas=yes ;; + arm-*) bfd_gas=yes ;; + # not yet + # i386-aout) bfd_gas=preferred ;; + mips-*) bfd_gas=yes ;; + ns32k-*) bfd_gas=yes ;; + ppc-*) bfd_gas=yes ;; + sparc-*) bfd_gas=yes ;; + *-elf) bfd_gas=yes ;; + *-ecoff) bfd_gas=yes ;; + *-som) bfd_gas=yes ;; + *) ;; + esac + +# Other random stuff. + + # do we need the opcodes library? + case ${cpu_type} in + vax | i386) + ;; + *) + need_opcodes=yes + if test "${shared_opcodes}" = "true"; then + # A shared libopcodes must be linked against libbfd. + need_bfd=yes + fi + ;; + esac + + test -n "$want_sparc_v9" && cat >> confdefs.h <<\EOF +#define SPARC_V9 1 +EOF + + + case ${cpu}-${vendor}-${os} in + sparc64-*-elf*) cat >> confdefs.h <<\EOF +#define SPARC_ARCH64 1 +EOF + ;; + esac + + case ${cpu_type} in + m32r) + case ${extra_objects} in + *cgen.o*) ;; + *) extra_objects="$extra_objects cgen.o" + cat >> confdefs.h <<\EOF +#define USING_CGEN 1 +EOF + + ;; + esac + ;; + + m68k) + case ${extra_objects} in + *m68k-parse.o*) ;; + *) extra_objects="$extra_objects m68k-parse.o" ;; + esac + ;; + + mips) + echo ${extra_objects} | grep -s "itbl-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-parse.o" + fi + + echo ${extra_objects} | grep -s "itbl-lex.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-lex.o" + fi + + echo ${extra_objects} | grep -s "itbl-ops.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-ops.o" + fi + ;; + + *) + ;; + esac + +# See if we really can support this configuration with the emulation code. + + if test $this_target = $target ; then + primary_bfd_gas=$bfd_gas + obj_format=$fmt + gas_target=$targ + te_file=$em + + if test $bfd_gas = no ; then + # Can't support other configurations this way. + break + fi + elif test $bfd_gas = no ; then + # Can't support this configuration. + break + fi + +# From target name and format, produce a list of supported emulations. + + case ${generic_target}-${fmt} in + mips-*-irix5*-*) emulation="mipsbelf mipslelf mipself mipsbecoff mipslecoff mipsecoff" ;; + mips-*-linux*-*) case "$endian" in + big) emulation="mipsbelf mipslelf mipself mipsbecoff mipslecoff mipsecoff" ;; + *) emulation="mipslelf mipsbelf mipself mipslecoff mipsbecoff mipsecoff" ;; + esac ;; + mips-*-lnews*-ecoff) ;; + mips-*-*-ecoff) case "$endian" in + big) emulation="mipsbecoff mipslecoff mipsecoff" ;; + *) emulation="mipslecoff mipsbecoff mipsecoff" ;; + esac ;; + mips-*-*-elf) case "$endian" in + big) emulation="mipsbelf mipslelf mipself" ;; + *) emulation="mipslelf mipsbelf mipself" ;; + # Uncommenting the next line will turn on support for i386 COFF + # in any i386 ELF configuration. This probably doesn't work + # correctly. + # i386-*-*-elf) emulation="i386coff i386elf" ;; + esac ;; + esac + + emulations="$emulations $emulation" + +done + +# Assign floating point type. Most processors with FP support +# IEEE FP. On those that don't support FP at all, usually IEEE +# is emulated. +case ${target_cpu} in + vax | tahoe ) atof=${target_cpu} ;; + *) atof=ieee ;; +esac + +case "${obj_format}" in + "") { echo "configure: error: GAS does not know what format to use for target ${target}" 1>&2; exit 1; } ;; +esac + + +if test ! -r ${srcdir}/config/tc-${target_cpu_type}.c; then + { echo "configure: error: GAS does not support target CPU ${target_cpu_type}" 1>&2; exit 1; } +fi + +if test ! -r ${srcdir}/config/obj-${obj_format}.c; then + { echo "configure: error: GAS does not have support for object file format ${obj_format}" 1>&2; exit 1; } +fi + +# and target makefile frag + +target_frag=${srcdir}/config/${gas_target}.mt +if test ! -r ${target_frag}; then + target_frag=/dev/null # ick! but subst_file can't be conditionalized +fi + + +case ${user_bfd_gas}-${primary_bfd_gas} in + yes-yes | no-no) + # We didn't override user's choice. + ;; + no-yes) + echo "configure: warning: Use of BFD is required for ${target}; overriding config options." 1>&2 + ;; + no-preferred) + primary_bfd_gas=no + ;; + *-preferred) + primary_bfd_gas=yes + ;; + yes-*) + primary_bfd_gas=yes + ;; + -*) + # User specified nothing. + ;; +esac + +# Some COFF configurations want these random other flags set. +case ${obj_format} in + coff) + case ${target_cpu_type} in + i386) cat >> confdefs.h <<\EOF +#define I386COFF 1 +EOF + ;; + m68k) cat >> confdefs.h <<\EOF +#define M68KCOFF 1 +EOF + ;; + m88k) cat >> confdefs.h <<\EOF +#define M88KCOFF 1 +EOF + ;; + esac + ;; +esac + +# Getting this done right is going to be a bitch. Each configuration specified +# with --enable-targets=... should be checked for environment, format, cpu, and +# bfd_gas setting. +# +# For each configuration, the necessary object file support code must be linked +# in. This might be only one, it might be up to four. The necessary emulation +# code needs to be provided, too. +# +# And then there's "--enable-targets=all".... +# +# For now, just always do it for MIPS ELF or ECOFF configurations. Sigh. + +formats="${obj_format}" +emfiles="" +EMULATIONS="" +_gas_uniq_list="$emulations" +_gas_uniq_newlist="" +for _gas_uniq_i in _gas_uniq_dummy $_gas_uniq_list ; do + case $_gas_uniq_i in + _gas_uniq_dummy) ;; + *) case " $_gas_uniq_newlist " in + *" $_gas_uniq_i "*) ;; + *) _gas_uniq_newlist="$_gas_uniq_newlist $_gas_uniq_i" ;; + esac ;; + esac +done +emulations=$_gas_uniq_newlist + +for em in . $emulations ; do + case $em in + .) continue ;; + mipsbelf | mipslelf) + fmt=elf file=mipself ;; + mipsbecoff | mipslecoff) + fmt=ecoff file=mipsecoff ;; + i386coff) + fmt=coff file=i386coff ;; + i386elf) + fmt=elf file=i386elf ;; + esac + formats="$formats $fmt" + emfiles="$emfiles e-$file.o" + EMULATIONS="$EMULATIONS &$em," +done +_gas_uniq_list="$formats" +_gas_uniq_newlist="" +for _gas_uniq_i in _gas_uniq_dummy $_gas_uniq_list ; do + case $_gas_uniq_i in + _gas_uniq_dummy) ;; + *) case " $_gas_uniq_newlist " in + *" $_gas_uniq_i "*) ;; + *) _gas_uniq_newlist="$_gas_uniq_newlist $_gas_uniq_i" ;; + esac ;; + esac +done +formats=$_gas_uniq_newlist + +_gas_uniq_list="$emfiles" +_gas_uniq_newlist="" +for _gas_uniq_i in _gas_uniq_dummy $_gas_uniq_list ; do + case $_gas_uniq_i in + _gas_uniq_dummy) ;; + *) case " $_gas_uniq_newlist " in + *" $_gas_uniq_i "*) ;; + *) _gas_uniq_newlist="$_gas_uniq_newlist $_gas_uniq_i" ;; + esac ;; + esac +done +emfiles=$_gas_uniq_newlist + +if test `set . $formats ; shift ; echo $#` -gt 1 ; then + for fmt in $formats ; do + case $fmt in + aout) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_AOUT 1 +EOF + ;; + bout) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_BOUT 1 +EOF + ;; + coff) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_COFF 1 +EOF + ;; + ecoff) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_ECOFF 1 +EOF + ;; + elf) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_ELF 1 +EOF + ;; + generic) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_GENERIC 1 +EOF + ;; + hp300) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_HP300 1 +EOF + ;; + ieee) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_IEEE 1 +EOF + ;; + som) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_SOM 1 +EOF + ;; + vms) cat >> confdefs.h <<\EOF +#define OBJ_MAYBE_VMS 1 +EOF + ;; + esac + extra_objects="$extra_objects obj-$fmt.o" + done + obj_format=multi +fi +if test `set . $emfiles ; shift ; echo $#` -gt 0 ; then + te_file=multi + extra_objects="$extra_objects $emfiles" + DEFAULT_EMULATION=`set . $emulations ; echo $2` + cat >> confdefs.h <<\EOF +#define USE_EMULATIONS 1 +EOF + +fi + +cat >> confdefs.h <<EOF +#define EMULATIONS $EMULATIONS +EOF + +cat >> confdefs.h <<EOF +#define DEFAULT_EMULATION "$DEFAULT_EMULATION" +EOF + + +case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in + yes-*-coff) need_bfd=yes ;; + no-*-coff) need_bfd=yes + cat >> confdefs.h <<\EOF +#define MANY_SEGMENTS 1 +EOF + ;; +esac + +reject_dev_configs=yes + +case ${reject_dev_configs}-${dev} in + yes-yes) # Oops. + { echo "configure: error: GAS does not support the ${generic_target} configuration." 1>&2; exit 1; } + ;; +esac + + + + + + +case "${primary_bfd_gas}" in + yes) cat >> confdefs.h <<\EOF +#define BFD_ASSEMBLER 1 +EOF + + need_bfd=yes ;; +esac + +# do we need the opcodes library? +case "${need_opcodes}" in +yes) + OPCODES_DEP=../opcodes/libopcodes.a + OPCODES_LIB='-L../opcodes -lopcodes' + + # We need to handle some special cases for shared libraries. + case "${host}" in + *-*-sunos*) + # On SunOS, we must link against the name we are going to install, + # not -lbfd, since SunOS does not support SONAME. + if test "${shared_opcodes}" = "true"; then + OPCODES_LIB='-L../opcodes -l`echo opcodes | sed '"'"'$(program_transform_name)'"'"'`' + fi + ;; + alpha*-*-osf*) + # On Alpha OSF/1, the native linker searches all the -L + # directories for any LIB.so files, and only then searches for any + # LIB.a files. That means that if there is an installed + # libbfd.so, but this build is not done with --enable-shared, the + # link will wind up being against the install libbfd.so rather + # than the newly built libbfd. To avoid this, we must explicitly + # link against libbfd.a when --enable-shared is not used. + if test "${shared_opcodes}" != "true"; then + OPCODES_LIB='../opcodes/libopcodes.a' + fi + ;; + esac + ;; +esac + +case "${need_bfd}" in +yes) + BFDDEP=../bfd/libbfd.a + BFDLIB='-L../bfd -lbfd' + ALL_OBJ_DEPS="$ALL_OBJ_DEPS ../bfd/bfd.h" + + # We need to handle some special cases for shared libraries + case "${host}" in + *-*-sunos*) + # On SunOS, we must link against the name we are going to install, + # not -lbfd, since SunOS does not support SONAME. + if test "${shared_bfd}" = "true"; then + BFDLIB='-L../bfd -l`echo bfd | sed '"'"'$(program_transform_name)'"'"'`' + fi + ;; + alpha*-*-osf*) + # On Alpha OSF/1, the native linker searches all the -L + # directories for any LIB.so files, and only then searches for any + # LIB.a files. That means that if there is an installed + # libbfd.so, but this build is not done with --enable-shared, the + # link will wind up being against the install libbfd.so rather + # than the newly built libbfd. To avoid this, we must explicitly + # link against libbfd.a when --enable-shared is not used. + if test "${shared_bfd}" != "true"; then + BFDLIB='../bfd/libbfd.a' + fi + ;; + esac + + if test "${commonbfdlib}" = "true"; then + # when a shared libbfd is built with --enable-commonbfdlib, + # all of libopcodes is available in libbfd.so + OPCODES_LIB= + fi + ;; +esac + + + + + + + + +cat >> confdefs.h <<EOF +#define TARGET_ALIAS "${target_alias}" +EOF + +cat >> confdefs.h <<EOF +#define TARGET_CANONICAL "${target}" +EOF + +cat >> confdefs.h <<EOF +#define TARGET_CPU "${target_cpu}" +EOF + +cat >> confdefs.h <<EOF +#define TARGET_VENDOR "${target_vendor}" +EOF + +cat >> confdefs.h <<EOF +#define TARGET_OS "${target_os}" +EOF + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1449: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1478: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1526: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 1536 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:1540: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1560: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1565: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1574: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1589: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1627: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1678: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 1693 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1699: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 1710 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1716: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in string.h stdlib.h memory.h strings.h unistd.h stdarg.h varargs.h errno.h sys/types.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1742: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1747 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1752: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Put this here so that autoconf's "cross-compiling" message doesn't confuse +# people who are not cross-compiling but are compiling cross-assemblers. +echo $ac_n "checking whether compiling a cross-assembler""... $ac_c" 1>&6 +echo "configure:1782: checking whether compiling a cross-assembler" >&5 +if test "${host}" = "${target}"; then + cross_gas=no +else + cross_gas=yes + cat >> confdefs.h <<\EOF +#define CROSS_COMPILE 1 +EOF + +fi +echo "$ac_t""$cross_gas" 1>&6 + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1797: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1802 "configure" +#include "confdefs.h" +#include <alloca.h> +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1809: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1830: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1835 "configure" +#include "confdefs.h" + +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1858: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.o + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1890: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1895 "configure" +#include "confdefs.h" +#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1920: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1925 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1948: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<EOF +#define CRAY_STACKSEG_END $ac_func +EOF + + break +else + echo "$ac_t""no" 1>&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1975: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext <<EOF +#line 1983 "configure" +#include "confdefs.h" +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:2002: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <<EOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:2024: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 2031 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:2038: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + + +# VMS doesn't have unlink. +for ac_func in unlink remove +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2068: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2073 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2096: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + break +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Some systems don't have sbrk(). +for ac_func in sbrk +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2125: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2130 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2153: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Some non-ANSI preprocessors botch requoting inside strings. That's bad +# enough, but on some of those systems, the assert macro relies on requoting +# working properly! +echo $ac_n "checking for working assert macro""... $ac_c" 1>&6 +echo "configure:2182: checking for working assert macro" >&5 +if eval "test \"`echo '$''{'gas_cv_assert_ok'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2187 "configure" +#include "confdefs.h" +#include <assert.h> +#include <stdio.h> +int main() { + +/* check for requoting problems */ +static int a, b, c, d; +static char *s; +assert (!strcmp(s, "foo bar baz quux")); +/* check for newline handling */ +assert (a == b + || c == d); + +; return 0; } +EOF +if { (eval echo configure:2203: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_assert_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_assert_ok=no +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_assert_ok" 1>&6 +test $gas_cv_assert_ok = yes || cat >> confdefs.h <<\EOF +#define BROKEN_ASSERT 1 +EOF + + + +# On some systems, the system header files may not declare malloc, realloc, +# and free. There are places where gas needs these functions to have been +# declared -- such as when taking their addresses. +gas_test_headers=" +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +" + +echo $ac_n "checking whether declaration is required for strstr""... $ac_c" 1>&6 +echo "configure:2244: checking whether declaration is required for strstr" >&5 +if eval "test \"`echo '$''{'gas_cv_decl_needed_strstr'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2249 "configure" +#include "confdefs.h" +$gas_test_headers +int main() { + +typedef char *(*f)(); +f x; +x = (f) strstr; + +; return 0; } +EOF +if { (eval echo configure:2260: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_decl_needed_strstr=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_decl_needed_strstr=yes +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_decl_needed_strstr" 1>&6 +test $gas_cv_decl_needed_strstr = no || { + cat >> confdefs.h <<\EOF +#define NEED_DECLARATION_STRSTR 1 +EOF + +} + + +echo $ac_n "checking whether declaration is required for malloc""... $ac_c" 1>&6 +echo "configure:2281: checking whether declaration is required for malloc" >&5 +if eval "test \"`echo '$''{'gas_cv_decl_needed_malloc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2286 "configure" +#include "confdefs.h" +$gas_test_headers +int main() { + +typedef char *(*f)(); +f x; +x = (f) malloc; + +; return 0; } +EOF +if { (eval echo configure:2297: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_decl_needed_malloc=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_decl_needed_malloc=yes +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_decl_needed_malloc" 1>&6 +test $gas_cv_decl_needed_malloc = no || { + cat >> confdefs.h <<\EOF +#define NEED_DECLARATION_MALLOC 1 +EOF + +} + + +echo $ac_n "checking whether declaration is required for free""... $ac_c" 1>&6 +echo "configure:2318: checking whether declaration is required for free" >&5 +if eval "test \"`echo '$''{'gas_cv_decl_needed_free'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2323 "configure" +#include "confdefs.h" +$gas_test_headers +int main() { + +typedef void (*f)(); +f x; +x = (f) free; + +; return 0; } +EOF +if { (eval echo configure:2334: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_decl_needed_free=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_decl_needed_free=yes +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_decl_needed_free" 1>&6 +test $gas_cv_decl_needed_free = no || { + cat >> confdefs.h <<\EOF +#define NEED_DECLARATION_FREE 1 +EOF + +} + + +echo $ac_n "checking whether declaration is required for sbrk""... $ac_c" 1>&6 +echo "configure:2355: checking whether declaration is required for sbrk" >&5 +if eval "test \"`echo '$''{'gas_cv_decl_needed_sbrk'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2360 "configure" +#include "confdefs.h" +$gas_test_headers +int main() { + +typedef char *(*f)(); +f x; +x = (f) sbrk; + +; return 0; } +EOF +if { (eval echo configure:2371: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_decl_needed_sbrk=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_decl_needed_sbrk=yes +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_decl_needed_sbrk" 1>&6 +test $gas_cv_decl_needed_sbrk = no || { + cat >> confdefs.h <<\EOF +#define NEED_DECLARATION_SBRK 1 +EOF + +} + + +# Does errno.h declare errno, or do we have to add a separate declaration +# for it? + +echo $ac_n "checking whether declaration is required for errno""... $ac_c" 1>&6 +echo "configure:2395: checking whether declaration is required for errno" >&5 +if eval "test \"`echo '$''{'gas_cv_decl_needed_errno'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2400 "configure" +#include "confdefs.h" + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +int main() { + +typedef int f; +f x; +x = (f) errno; + +; return 0; } +EOF +if { (eval echo configure:2415: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + gas_cv_decl_needed_errno=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gas_cv_decl_needed_errno=yes +fi +rm -f conftest* +fi +echo "$ac_t""$gas_cv_decl_needed_errno" 1>&6 +test $gas_cv_decl_needed_errno = no || { + cat >> confdefs.h <<\EOF +#define NEED_DECLARATION_ERRNO 1 +EOF + +} + + +HLDFLAGS= +HLDENV= +RPATH_ENVVAR=LD_LIBRARY_PATH +# If we have shared libraries, try to set rpath reasonably. +if test "${shared}" = "true"; then + case "${host}" in + *-*-hpux*) + HLDFLAGS='-Wl,+s,+b,$(libdir)' + RPATH_ENVVAR=SHLIB_PATH + ;; + *-*-irix5* | *-*-irix6*) + HLDFLAGS='-Wl,-rpath,$(libdir)' + ;; + *-*-linux*aout*) + ;; + *-*-linux*) + HLDFLAGS='-Wl,-rpath,$(libdir)' + ;; + *-*-solaris*) + HLDFLAGS='-R $(libdir)' + ;; + *-*-sysv4*) + HLDENV='if test -z "$${LD_RUN_PATH}"; then LD_RUN_PATH=$(libdir); else LD_RUN_PATH=$${LD_RUN_PATH}:$(libdir); fi; export LD_RUN_PATH;' + ;; + esac +fi + +# On SunOS, if the linker supports the -rpath option, use it to +# prevent ../bfd and ../opcodes from being included in the run time +# search path. +case "${host}" in + *-*-sunos*) + echo 'main () { }' > conftest.c + ${CC} -o conftest -Wl,-rpath= conftest.c >/dev/null 2>conftest.t + if grep 'unrecognized' conftest.t >/dev/null 2>&1; then + : + elif grep 'No such file' conftest.t >/dev/null 2>&1; then + : + elif grep 'do not mix' conftest.t >/dev/null 2>&1; then + : + elif test "${shared}" = "true"; then + HLDFLAGS='-Wl,-rpath=$(libdir)' + else + HLDFLAGS='-Wl,-rpath=' + fi + rm -f conftest.t conftest.c conftest + ;; +esac + + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile doc/Makefile .gdbinit:gdbinit.in conf" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +/@target_frag@/r $target_frag +s%@target_frag@%%g +s%@extra_objects@%$extra_objects%g +s%@target_cpu_type@%$target_cpu_type%g +s%@obj_format@%$obj_format%g +s%@te_file@%$te_file%g +s%@atof@%$atof%g +s%@BFDDEP@%$BFDDEP%g +s%@BFDLIB@%$BFDLIB%g +s%@OPCODES_DEP@%$OPCODES_DEP%g +s%@OPCODES_LIB@%$OPCODES_LIB%g +s%@ALL_OBJ_DEPS@%$ALL_OBJ_DEPS%g +s%@CC@%$CC%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g +s%@HLDFLAGS@%$HLDFLAGS%g +s%@HLDENV@%$HLDENV%g +s%@RPATH_ENVVAR@%$RPATH_ENVVAR%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile doc/Makefile .gdbinit:gdbinit.in"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="conf" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF +target_cpu_type=${target_cpu_type} + obj_format=${obj_format} + te_file=${te_file} +EOF +cat >> $CONFIG_STATUS <<\EOF +rm -f targ-cpu.c targ-cpu.h obj-format.h obj-format.c targ-env.h atof-targ.c itbl-cpu.h + echo '#include "tc-'"${target_cpu_type}"'.h"' > targ-cpu.h + echo '#include "obj-'"${obj_format}"'.h"' > obj-format.h + echo '#include "te-'"${te_file}"'.h"' > targ-env.h + echo '#include "itbl-'"${target_cpu_type}"'.h"' > itbl-cpu.h + case ${target_cpu_type} in + m32r) echo '#include "opcodes/'"${target_cpu_type}"'-opc.h"' > cgen-opc.h ;; + esac +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/contrib/binutils/gas/configure.in b/contrib/binutils/gas/configure.in new file mode 100644 index 0000000..81e1209 --- /dev/null +++ b/contrib/binutils/gas/configure.in @@ -0,0 +1,815 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl And be careful when changing it! If you must add tests with square +dnl brackets, be sure changequote invocations surround it. +dnl +dnl +AC_PREREQ(2.5)dnl v2.5 needed for --bindir et al +AC_INIT(as.h)dnl +dnl +user_bfd_gas= +AC_ARG_ENABLE(bfd-assembler, +[ --enable-bfd-assembler use BFD back end for writing object files], +[case "${enableval}" in + yes) need_bfd=yes user_bfd_gas=yes ;; + no) user_bfd_gas=no ;; + *) AC_MSG_ERROR(bad value ${enableval} given for bfd-assembler option) ;; +esac])dnl +AC_ARG_ENABLE(targets, +[ targets alternative target configurations besides the primary], +[case "${enableval}" in + yes | "") AC_ERROR(enable-targets option must specify target names or 'all') + ;; + no) enable_targets= ;; + *) enable_targets=$enableval ;; +esac])dnl +AC_ARG_ENABLE(shared, +[ --enable-shared build shared BFD library], +[case "${enableval}" in + yes) shared=true shared_bfd=true shared_opcodes=true ;; + no) shared=false ;; + *bfd*opcodes*) shared=true shared_bfd=true shared_opcodes=true ;; + *opcodes*bfd*) shared=true shared_bfd=true shared_opcodes=true ;; + *bfd*) shared=true shared_bfd=true ;; + *opcodes*) shared=true shared_opcodes=true ;; + *) shared=false ;; +esac])dnl +AC_ARG_ENABLE(commonbfdlib, +[ --enable-commonbfdlib build shared BFD/opcodes/libiberty library], +[case "${enableval}" in + yes) commonbfdlib=true ;; + no) commonbfdlib=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for BFD commonbfdlib option]) ;; +esac])dnl + +# Generate a header file -- gets more post-processing by Makefile later. +AC_CONFIG_HEADER(conf) + +dnl For recursion to work right, this must be an absolute pathname. +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +te_file=generic + +canon_targets="" +if test -n "$enable_targets" ; then + for t in `echo $enable_targets | sed 's/,/ /g'`; do + result=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $t 2>/dev/null` + if test -n "$result" ; then + canon_targets="$canon_targets $result" +# else +# # Permit "all", etc. We don't support it yet though. +# canon_targets="$canon_targets $t" + fi + done + GAS_UNIQ(canon_targets) +fi + +emulations="" + +for this_target in $target $canon_targets ; do + +changequote(,)dnl + eval `echo $this_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/cpu=\1 vendor=\2 os=\3/'` +changequote([,])dnl + + # check for architecture variants + case ${cpu} in + armeb) cpu_type=arm endian=big ;; + arm*) cpu_type=arm endian=little ;; + hppa*) cpu_type=hppa ;; +changequote(,)dnl + i[456]86) cpu_type=i386 ;; + m680[012346]0) cpu_type=m68k ;; + m68008) cpu_type=m68k ;; + m683??) cpu_type=m68k ;; +changequote([,])dnl + m8*) cpu_type=m88k ;; + mips*el) cpu_type=mips endian=little ;; + mips*) cpu_type=mips endian=big ;; + powerpcle*) cpu_type=ppc endian=little ;; + powerpc*) cpu_type=ppc endian=big ;; + rs6000*) cpu_type=ppc ;; + sparc64) cpu_type=sparc want_sparc_v9=true ;; + sparc*) cpu_type=sparc ;; + *) cpu_type=${cpu} ;; + esac + + if test ${this_target} = $target ; then + target_cpu_type=${cpu_type} + elif test ${target_cpu_type} != ${cpu_type} ; then + continue + fi + + targ=${cpu_type} + generic_target=${cpu_type}-$vendor-$os + dev=no + bfd_gas=no + em=generic + + # assign object format + case ${generic_target} in + a29k-*-coff) fmt=coff targ=ebmon29k ;; + a29k-amd-udi) fmt=coff targ=ebmon29k ;; + a29k-amd-ebmon) fmt=coff targ=ebmon29k ;; + a29k-nyu-sym1) fmt=coff targ=ebmon29k ;; + a29k-*-vxworks*) fmt=coff ;; + + alpha-*-*vms*) fmt=evax ;; + alpha-*-netware*) fmt=ecoff ;; + alpha-*-openbsd*) fmt=ecoff ;; + alpha-*-osf*) fmt=ecoff ;; + alpha-*-linuxecoff*) fmt=ecoff ;; + alpha-*-linux*) fmt=elf em=linux ;; + + + arm-*-riscix*) fmt=aout targ=arm-lit em=riscix ;; + arm-*-aout) fmt=aout + case "$endian" in + big) targ=arm-big ;; + *) targ=arm-lit ;; + esac + ;; + arm-*-coff) fmt=coff ;; + arm-*-riscix*) fmt=aout ;; + arm-*-pe) fmt=coff targ=armcoff em=pe ;; + + d10v-*-*) fmt=elf bfd_gas=yes ;; + + hppa-*-*elf*) fmt=elf em=hppa ;; + hppa-*-lites*) fmt=elf em=hppa ;; + hppa-*-osf*) fmt=som em=hppa ;; + hppa-*-rtems*) fmt=elf em=hppa ;; + hppa-*-hpux*) fmt=som em=hppa ;; + hppa-*-bsd*) fmt=som em=hppa ;; + hppa-*-hiux*) fmt=som em=hppa ;; + + h8300-*-coff) fmt=coff ;; + + i386-ibm-aix*) fmt=coff targ=i386coff + em=i386aix ;; + i386-sequent-bsd*) fmt=aout em=dynix bfd_gas=yes ;; + i386-*-bsd*) fmt=aout em=386bsd ;; + i386-*-netbsd0.8) fmt=aout em=386bsd ;; + i386-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes;; + i386-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes;; + i386-*-linux*aout* | i386-*-linuxoldld) fmt=aout em=linux ;; + i386-*-linux*coff*) fmt=coff em=linux + targ=i386coff ;; + i386-*-linux*) fmt=elf em=linux ;; + i386-*-lynxos*) fmt=coff targ=i386coff + em=lynx ;; + i386-*-sysv4* | i386-*-solaris* | i386-*-elf | i386-*-freebsdelf*) + fmt=elf ;; + i386-*-sco*elf*) fmt=elf targ=sco5 ;; + i386-*-coff | i386-*-sysv* | i386-*-sco* | i386-*-isc*) + fmt=coff targ=i386coff ;; + i386-*-vsta) fmt=aout ;; + i386-*-go32) fmt=coff targ=i386coff ;; + i386-*-rtems*) fmt=coff targ=i386coff ;; + i386-*-gnu*) fmt=elf ;; + i386-*-mach*) + fmt=aout em=mach bfd_gas=yes ;; + i386-*-msdos*) fmt=aout ;; + i386-*-moss*) fmt=elf ;; + i386-*-pe) fmt=coff targ=i386coff em=pe ;; + i386-*-cygwin32) fmt=coff targ=i386coff em=pe ;; + i386-*-*nt) fmt=coff targ=i386coff em=pe ;; + i960-*-bout) fmt=bout ;; + i960-*-coff) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-rtems*) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-nindy*) fmt=bout ;; + i960-*-vxworks4*) fmt=bout ;; + i960-*-vxworks5.0) fmt=bout ;; + i960-*-vxworks5.*) fmt=coff em=ic960 targ=ic960coff ;; + i960-*-vxworks*) fmt=bout ;; + + m32r-*-*) fmt=elf bfd_gas=yes ;; + + m68k-*-vxworks* | m68k-ericsson-ose | m68k-*-sunos*) + fmt=aout em=sun3 ;; + m68k-motorola-sysv*) fmt=coff targ=m68kcoff em=delta ;; + m68k-bull-sysv3*) fmt=coff targ=m68kcoff em=dpx2 ;; + m68k-apollo-*) fmt=coff targ=apollo em=apollo ;; + m68k-*-sysv4*) # must be before -sysv* + fmt=elf em=svr4 ;; + m68k-*-elf*) fmt=elf ;; + m68k-*-coff | m68k-*-sysv* | m68k-*-rtems*) + fmt=coff targ=m68kcoff ;; + m68k-*-hpux*) fmt=hp300 em=hp300 ;; + m68k-*-linux*aout*) fmt=aout em=linux ;; + m68k-*-linux*) fmt=elf em=linux ;; + m68k-*-lynxos*) fmt=coff targ=m68kcoff + em=lynx ;; + m68k-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + m68k-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + m68k-apple-aux*) fmt=coff targ=m68kcoff em=aux ;; + m68k-*-psos*) fmt=elf em=psos;; + + m88k-motorola-sysv3*) fmt=coff targ=m88kcoff em=delt88 ;; + m88k-*-coff*) fmt=coff targ=m88kcoff ;; + + # don't change em like *-*-bsd does + mips-dec-netbsd*) fmt=elf targ=mips-lit endian=little ;; + mips-dec-openbsd*) fmt=elf targ=mips-lit endian=little ;; + mips-dec-bsd*) fmt=aout targ=mips-lit ;; + mips-sony-bsd*) fmt=ecoff targ=mips-big ;; + mips-*-bsd*) AC_MSG_ERROR(Unknown vendor for mips-bsd configuration.) ;; + mips-*-ultrix*) fmt=ecoff targ=mips-lit endian=little ;; + mips-*-osf*) fmt=ecoff targ=mips-lit endian=little ;; + mips-*-ecoff*) fmt=ecoff + case "$endian" in + big) targ=mips-big ;; + *) targ=mips-lit ;; + esac + ;; + mips-*-ecoff*) fmt=ecoff targ=mips-big ;; + mips-*-irix6*) fmt=elf targ=mips-big ;; + mips-*-irix5*) fmt=elf targ=mips-big ;; + mips-*-irix*) fmt=ecoff targ=mips-big ;; + mips-*-lnews*) fmt=ecoff targ=mips-lit em=lnews ;; + mips-*-riscos*) fmt=ecoff targ=mips-big ;; + mips-*-sysv*) fmt=ecoff targ=mips-big ;; + mips-*-elf* | mips-*-rtems* | mips-*-linux* | mips-*-gnu* | mips-*-openbsd*) + fmt=elf + case "$endian" in + big) targ=mips-big ;; + *) targ=mips-lit ;; + esac + ;; + mn10200-*-*) fmt=elf bfd_gas=yes ;; + mn10300-*-*) fmt=elf bfd_gas=yes ;; + ppc-*-pe | ppc-*-cygwin32 | ppc-*-winnt*) + fmt=coff em=pe + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-aix*) fmt=coff ;; + ppc-*-beos*) fmt=coff ;; + ppc-*-*bsd* | ppc-*-elf* | ppc-*-eabi* | ppc-*-sysv4*) + fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-linux*) fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) AC_MSG_ERROR(Linux must be configured big endian) ;; + esac + ;; + ppc-*-solaris*) fmt=elf + case "$endian" in + big) AC_MSG_ERROR(Solaris must be configured little endian) ;; + *) targ=ppc-sol ;; + esac + ;; + ppc-*-rtems*) + fmt=elf + case "$endian" in + big) targ=ppc-big ;; + *) targ=ppc-lit ;; + esac + ;; + ppc-*-macos* | ppc-*-mpw*) + fmt=coff em=macos ;; + ppc-*-netware*) fmt=elf em=ppcnw ;; + + sh-*-elf*) fmt=elf ;; + sh-*-coff*) fmt=coff ;; + + ns32k-pc532-mach* | ns32k-pc532-ux*) fmt=aout em=pc532mach ;; + ns32k-pc532-netbsd* | ns32k-pc532-lites*) fmt=aout em=nbsd532 ;; + ns32k-pc532-openbsd*) fmt=aout em=nbsd532 ;; + + sparc-*-rtems*) fmt=aout ;; + sparc-*-sunos4*) fmt=aout em=sun3 ;; + sparc-*-aout | sparc*-*-vxworks*) + fmt=aout em=sparcaout ;; + sparc-*-coff) fmt=coff ;; + sparc-*-linux*aout*) fmt=aout em=linux ;; + sparc-*-linux*) fmt=elf em=linux ;; + sparc-*-lynxos*) fmt=coff em=lynx ;; + sparc-fujitsu-none) fmt=aout ;; + sparc-*-elf | sparc-*-sysv4* | sparc-*-solaris*) + fmt=elf ;; + sparc-*-netbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + sparc-*-openbsd*) fmt=aout em=nbsd bfd_gas=yes ;; + + vax-*-bsd* | vax-*-ultrix*) + fmt=aout ;; + vax-*-vms) fmt=vms ;; + + z8k-*-coff | z8k-*-sim) + fmt=coff ;; + + w65-*-*) fmt=coff ;; + + *-*-aout | *-*-scout) + fmt=aout ;; + *-*-nindy*) + fmt=bout ;; + *-*-bsd*) + fmt=aout em=sun3 ;; + *-*-generic) fmt=generic ;; + *-*-xray | *-*-hms) fmt=coff ;; + *-*-sim) fmt=coff ;; + *-*-elf | *-*-sysv4* | *-*-solaris*) + AC_MSG_WARN(GAS support for ${generic_target} is incomplete.) + fmt=elf dev=yes ;; + *-*-vxworks) fmt=aout ;; + *-*-netware) fmt=elf ;; + esac + + case ${cpu_type}-${fmt} in + alpha-*) bfd_gas=yes ;; + arm-*) bfd_gas=yes ;; + # not yet + # i386-aout) bfd_gas=preferred ;; + mips-*) bfd_gas=yes ;; + ns32k-*) bfd_gas=yes ;; + ppc-*) bfd_gas=yes ;; + sparc-*) bfd_gas=yes ;; + *-elf) bfd_gas=yes ;; + *-ecoff) bfd_gas=yes ;; + *-som) bfd_gas=yes ;; + *) ;; + esac + +# Other random stuff. + + # do we need the opcodes library? + case ${cpu_type} in + vax | i386) + ;; + *) + need_opcodes=yes + if test "${shared_opcodes}" = "true"; then + # A shared libopcodes must be linked against libbfd. + need_bfd=yes + fi + ;; + esac + + test -n "$want_sparc_v9" && AC_DEFINE(SPARC_V9) + + case ${cpu}-${vendor}-${os} in + sparc64-*-elf*) AC_DEFINE(SPARC_ARCH64) ;; + esac + + case ${cpu_type} in + m32r) + case ${extra_objects} in + *cgen.o*) ;; + *) extra_objects="$extra_objects cgen.o" + AC_DEFINE(USING_CGEN) + ;; + esac + ;; + + m68k) + case ${extra_objects} in + *m68k-parse.o*) ;; + *) extra_objects="$extra_objects m68k-parse.o" ;; + esac + ;; + + mips) + echo ${extra_objects} | grep -s "itbl-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-parse.o" + fi + + echo ${extra_objects} | grep -s "itbl-lex.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-lex.o" + fi + + echo ${extra_objects} | grep -s "itbl-ops.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects itbl-ops.o" + fi + ;; + + *) + ;; + esac + +# See if we really can support this configuration with the emulation code. + + if test $this_target = $target ; then + primary_bfd_gas=$bfd_gas + obj_format=$fmt + gas_target=$targ + te_file=$em + + if test $bfd_gas = no ; then + # Can't support other configurations this way. + break + fi + elif test $bfd_gas = no ; then + # Can't support this configuration. + break + fi + +# From target name and format, produce a list of supported emulations. + + case ${generic_target}-${fmt} in + mips-*-irix5*-*) emulation="mipsbelf mipslelf mipself mipsbecoff mipslecoff mipsecoff" ;; + mips-*-linux*-*) case "$endian" in + big) emulation="mipsbelf mipslelf mipself mipsbecoff mipslecoff mipsecoff" ;; + *) emulation="mipslelf mipsbelf mipself mipslecoff mipsbecoff mipsecoff" ;; + esac ;; + mips-*-lnews*-ecoff) ;; + mips-*-*-ecoff) case "$endian" in + big) emulation="mipsbecoff mipslecoff mipsecoff" ;; + *) emulation="mipslecoff mipsbecoff mipsecoff" ;; + esac ;; + mips-*-*-elf) case "$endian" in + big) emulation="mipsbelf mipslelf mipself" ;; + *) emulation="mipslelf mipsbelf mipself" ;; + # Uncommenting the next line will turn on support for i386 COFF + # in any i386 ELF configuration. This probably doesn't work + # correctly. + # i386-*-*-elf) emulation="i386coff i386elf" ;; + esac ;; + esac + + emulations="$emulations $emulation" + +done + +# Assign floating point type. Most processors with FP support +# IEEE FP. On those that don't support FP at all, usually IEEE +# is emulated. +case ${target_cpu} in + vax | tahoe ) atof=${target_cpu} ;; + *) atof=ieee ;; +esac + +case "${obj_format}" in + "") AC_MSG_ERROR(GAS does not know what format to use for target ${target}) ;; +esac + +dnl +dnl Make sure the desired support files exist. +dnl + +if test ! -r ${srcdir}/config/tc-${target_cpu_type}.c; then + AC_MSG_ERROR(GAS does not support target CPU ${target_cpu_type}) +fi + +if test ! -r ${srcdir}/config/obj-${obj_format}.c; then + AC_MSG_ERROR(GAS does not have support for object file format ${obj_format}) +fi + +# and target makefile frag + +target_frag=${srcdir}/config/${gas_target}.mt +if test ! -r ${target_frag}; then + target_frag=/dev/null # ick! but subst_file can't be conditionalized +fi +AC_SUBST_FILE(target_frag) + +case ${user_bfd_gas}-${primary_bfd_gas} in + yes-yes | no-no) + # We didn't override user's choice. + ;; + no-yes) + AC_MSG_WARN(Use of BFD is required for ${target}; overriding config options.) + ;; + no-preferred) + primary_bfd_gas=no + ;; + *-preferred) + primary_bfd_gas=yes + ;; + yes-*) + primary_bfd_gas=yes + ;; + -*) + # User specified nothing. + ;; +esac + +# Some COFF configurations want these random other flags set. +case ${obj_format} in + coff) + case ${target_cpu_type} in + i386) AC_DEFINE(I386COFF) ;; + m68k) AC_DEFINE(M68KCOFF) ;; + m88k) AC_DEFINE(M88KCOFF) ;; + esac + ;; +esac + +# Getting this done right is going to be a bitch. Each configuration specified +# with --enable-targets=... should be checked for environment, format, cpu, and +# bfd_gas setting. +# +# For each configuration, the necessary object file support code must be linked +# in. This might be only one, it might be up to four. The necessary emulation +# code needs to be provided, too. +# +# And then there's "--enable-targets=all".... +# +# For now, just always do it for MIPS ELF or ECOFF configurations. Sigh. + +formats="${obj_format}" +emfiles="" +EMULATIONS="" +GAS_UNIQ(emulations) +for em in . $emulations ; do + case $em in + .) continue ;; + mipsbelf | mipslelf) + fmt=elf file=mipself ;; + mipsbecoff | mipslecoff) + fmt=ecoff file=mipsecoff ;; + i386coff) + fmt=coff file=i386coff ;; + i386elf) + fmt=elf file=i386elf ;; + esac + formats="$formats $fmt" + emfiles="$emfiles e-$file.o" + EMULATIONS="$EMULATIONS &$em," +done +GAS_UNIQ(formats) +GAS_UNIQ(emfiles) +if test `set . $formats ; shift ; echo $#` -gt 1 ; then + for fmt in $formats ; do + case $fmt in + aout) AC_DEFINE(OBJ_MAYBE_AOUT) ;; + bout) AC_DEFINE(OBJ_MAYBE_BOUT) ;; + coff) AC_DEFINE(OBJ_MAYBE_COFF) ;; + ecoff) AC_DEFINE(OBJ_MAYBE_ECOFF) ;; + elf) AC_DEFINE(OBJ_MAYBE_ELF) ;; + generic) AC_DEFINE(OBJ_MAYBE_GENERIC) ;; + hp300) AC_DEFINE(OBJ_MAYBE_HP300) ;; + ieee) AC_DEFINE(OBJ_MAYBE_IEEE) ;; + som) AC_DEFINE(OBJ_MAYBE_SOM) ;; + vms) AC_DEFINE(OBJ_MAYBE_VMS) ;; + esac + extra_objects="$extra_objects obj-$fmt.o" + done + obj_format=multi +fi +if test `set . $emfiles ; shift ; echo $#` -gt 0 ; then + te_file=multi + extra_objects="$extra_objects $emfiles" + DEFAULT_EMULATION=`set . $emulations ; echo $2` + AC_DEFINE(USE_EMULATIONS) +fi +AC_SUBST(extra_objects) +AC_DEFINE_UNQUOTED(EMULATIONS, $EMULATIONS) +AC_DEFINE_UNQUOTED(DEFAULT_EMULATION, "$DEFAULT_EMULATION") + +case ${primary_bfd_gas}-${target_cpu_type}-${obj_format} in + yes-*-coff) need_bfd=yes ;; + no-*-coff) need_bfd=yes + AC_DEFINE(MANY_SEGMENTS) ;; +esac + +reject_dev_configs=yes + +case ${reject_dev_configs}-${dev} in + yes-yes) # Oops. + AC_MSG_ERROR(GAS does not support the ${generic_target} configuration.) + ;; +esac + +AC_SUBST(target_cpu_type) +AC_SUBST(obj_format) +AC_SUBST(te_file) +AC_SUBST(atof) +dnl AC_SUBST(emulation) + +case "${primary_bfd_gas}" in + yes) AC_DEFINE(BFD_ASSEMBLER) + need_bfd=yes ;; +esac + +# do we need the opcodes library? +case "${need_opcodes}" in +yes) + OPCODES_DEP=../opcodes/libopcodes.a + OPCODES_LIB='-L../opcodes -lopcodes' + + # We need to handle some special cases for shared libraries. + case "${host}" in + *-*-sunos*) + # On SunOS, we must link against the name we are going to install, + # not -lbfd, since SunOS does not support SONAME. + if test "${shared_opcodes}" = "true"; then + OPCODES_LIB='-L../opcodes -l`echo opcodes | sed '"'"'$(program_transform_name)'"'"'`' + fi + ;; + alpha*-*-osf*) + # On Alpha OSF/1, the native linker searches all the -L + # directories for any LIB.so files, and only then searches for any + # LIB.a files. That means that if there is an installed + # libbfd.so, but this build is not done with --enable-shared, the + # link will wind up being against the install libbfd.so rather + # than the newly built libbfd. To avoid this, we must explicitly + # link against libbfd.a when --enable-shared is not used. + if test "${shared_opcodes}" != "true"; then + OPCODES_LIB='../opcodes/libopcodes.a' + fi + ;; + esac + ;; +esac + +case "${need_bfd}" in +yes) + BFDDEP=../bfd/libbfd.a + BFDLIB='-L../bfd -lbfd' + ALL_OBJ_DEPS="$ALL_OBJ_DEPS ../bfd/bfd.h" + + # We need to handle some special cases for shared libraries + case "${host}" in + *-*-sunos*) + # On SunOS, we must link against the name we are going to install, + # not -lbfd, since SunOS does not support SONAME. + if test "${shared_bfd}" = "true"; then + BFDLIB='-L../bfd -l`echo bfd | sed '"'"'$(program_transform_name)'"'"'`' + fi + ;; + alpha*-*-osf*) + # On Alpha OSF/1, the native linker searches all the -L + # directories for any LIB.so files, and only then searches for any + # LIB.a files. That means that if there is an installed + # libbfd.so, but this build is not done with --enable-shared, the + # link will wind up being against the install libbfd.so rather + # than the newly built libbfd. To avoid this, we must explicitly + # link against libbfd.a when --enable-shared is not used. + if test "${shared_bfd}" != "true"; then + BFDLIB='../bfd/libbfd.a' + fi + ;; + esac + + if test "${commonbfdlib}" = "true"; then + # when a shared libbfd is built with --enable-commonbfdlib, + # all of libopcodes is available in libbfd.so + OPCODES_LIB= + fi + ;; +esac + +AC_SUBST(BFDDEP) +AC_SUBST(BFDLIB) +AC_SUBST(OPCODES_DEP) +AC_SUBST(OPCODES_LIB) + +AC_SUBST(ALL_OBJ_DEPS) + +AC_DEFINE_UNQUOTED(TARGET_ALIAS, "${target_alias}") +AC_DEFINE_UNQUOTED(TARGET_CANONICAL, "${target}") +AC_DEFINE_UNQUOTED(TARGET_CPU, "${target_cpu}") +AC_DEFINE_UNQUOTED(TARGET_VENDOR, "${target_vendor}") +AC_DEFINE_UNQUOTED(TARGET_OS, "${target_os}") + +AC_PROG_CC +AC_PROG_INSTALL + +AC_CHECK_HEADERS(string.h stdlib.h memory.h strings.h unistd.h stdarg.h varargs.h errno.h sys/types.h) + +# Put this here so that autoconf's "cross-compiling" message doesn't confuse +# people who are not cross-compiling but are compiling cross-assemblers. +AC_MSG_CHECKING(whether compiling a cross-assembler) +if test "${host}" = "${target}"; then + cross_gas=no +else + cross_gas=yes + AC_DEFINE(CROSS_COMPILE) +fi +AC_MSG_RESULT($cross_gas) + +dnl ansidecl.h will deal with const +dnl AC_CONST +AC_FUNC_ALLOCA +AC_C_INLINE + +# VMS doesn't have unlink. +AC_CHECK_FUNCS(unlink remove, break) + +# Some systems don't have sbrk(). +AC_CHECK_FUNCS(sbrk) + +# Some non-ANSI preprocessors botch requoting inside strings. That's bad +# enough, but on some of those systems, the assert macro relies on requoting +# working properly! +GAS_WORKING_ASSERT + +# On some systems, the system header files may not declare malloc, realloc, +# and free. There are places where gas needs these functions to have been +# declared -- such as when taking their addresses. +gas_test_headers=" +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +" +GAS_CHECK_DECL_NEEDED(strstr, f, char *(*f)(), $gas_test_headers) +GAS_CHECK_DECL_NEEDED(malloc, f, char *(*f)(), $gas_test_headers) +GAS_CHECK_DECL_NEEDED(free, f, void (*f)(), $gas_test_headers) +GAS_CHECK_DECL_NEEDED(sbrk, f, char *(*f)(), $gas_test_headers) + +# Does errno.h declare errno, or do we have to add a separate declaration +# for it? +GAS_CHECK_DECL_NEEDED(errno, f, int f, [ +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +]) + +HLDFLAGS= +HLDENV= +RPATH_ENVVAR=LD_LIBRARY_PATH +# If we have shared libraries, try to set rpath reasonably. +if test "${shared}" = "true"; then + case "${host}" in + *-*-hpux*) + HLDFLAGS='-Wl,+s,+b,$(libdir)' + RPATH_ENVVAR=SHLIB_PATH + ;; + *-*-irix5* | *-*-irix6*) + HLDFLAGS='-Wl,-rpath,$(libdir)' + ;; + *-*-linux*aout*) + ;; + *-*-linux*) + HLDFLAGS='-Wl,-rpath,$(libdir)' + ;; + *-*-solaris*) + HLDFLAGS='-R $(libdir)' + ;; + *-*-sysv4*) + HLDENV='if test -z "$${LD_RUN_PATH}"; then LD_RUN_PATH=$(libdir); else LD_RUN_PATH=$${LD_RUN_PATH}:$(libdir); fi; export LD_RUN_PATH;' + ;; + esac +fi + +# On SunOS, if the linker supports the -rpath option, use it to +# prevent ../bfd and ../opcodes from being included in the run time +# search path. +case "${host}" in + *-*-sunos*) + echo 'main () { }' > conftest.c + ${CC} -o conftest -Wl,-rpath= conftest.c >/dev/null 2>conftest.t + if grep 'unrecognized' conftest.t >/dev/null 2>&1; then + : + elif grep 'No such file' conftest.t >/dev/null 2>&1; then + : + elif grep 'do not mix' conftest.t >/dev/null 2>&1; then + : + elif test "${shared}" = "true"; then + HLDFLAGS='-Wl,-rpath=$(libdir)' + else + HLDFLAGS='-Wl,-rpath=' + fi + rm -f conftest.t conftest.c conftest + ;; +esac +AC_SUBST(HLDFLAGS) +AC_SUBST(HLDENV) +AC_SUBST(RPATH_ENVVAR) + +dnl This must come last. + +dnl We used to make symlinks to files in the source directory, but now +dnl we just use the right name for .c files, and create .h files in +dnl the build directory which include the right .h file. Make sure +dnl the old symlinks don't exist, so that a reconfigure in an existing +dnl directory behaves reasonably. + +AC_OUTPUT(Makefile doc/Makefile .gdbinit:gdbinit.in, +[rm -f targ-cpu.c targ-cpu.h obj-format.h obj-format.c targ-env.h atof-targ.c itbl-cpu.h + echo '#include "tc-'"${target_cpu_type}"'.h"' > targ-cpu.h + echo '#include "obj-'"${obj_format}"'.h"' > obj-format.h + echo '#include "te-'"${te_file}"'.h"' > targ-env.h + echo '#include "itbl-'"${target_cpu_type}"'.h"' > itbl-cpu.h + case ${target_cpu_type} in + m32r) echo '#include "opcodes/'"${target_cpu_type}"'-opc.h"' > cgen-opc.h ;; + esac], +[target_cpu_type=${target_cpu_type} + obj_format=${obj_format} + te_file=${te_file}]) diff --git a/contrib/binutils/gas/debug.c b/contrib/binutils/gas/debug.c new file mode 100644 index 0000000..e99f23f --- /dev/null +++ b/contrib/binutils/gas/debug.c @@ -0,0 +1,104 @@ +/* This file is debug.c + Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Routines for debug use only. */ + +#include "as.h" +#include "subsegs.h" + +dmp_frags () +{ + frchainS *chp; + char *p; + + for (chp = frchain_root; chp; chp = chp->frch_next) + { + switch (chp->frch_seg) + { + case SEG_DATA: + p = "Data"; + break; + case SEG_TEXT: + p = "Text"; + break; + default: + p = "???"; + break; + } + printf ("\nSEGMENT %s %d\n", p, chp->frch_subseg); + dmp_frag (chp->frch_root, "\t"); + } +} + +dmp_frag (fp, indent) + struct frag *fp; + char *indent; +{ + for (; fp; fp = fp->fr_next) + { + printf ("%sFRAGMENT @ 0x%x\n", indent, fp); + switch (fp->fr_type) + { + case rs_align: + printf ("%srs_align(%d)\n", indent, fp->fr_offset); + break; + case rs_fill: + printf ("%srs_fill(%d)\n", indent, fp->fr_offset); + printf ("%s", indent); + var_chars (fp, fp->fr_var + fp->fr_fix); + printf ("%s\t repeated %d times,", + indent, fp->fr_offset); + printf (" fixed length if # chars == 0)\n"); + break; + case rs_org: + printf ("%srs_org(%d+sym @0x%x)\n", indent, + fp->fr_offset, fp->fr_symbol); + printf ("%sfill with ", indent); + var_chars (fp, 1); + printf ("\n"); + break; + case rs_machine_dependent: + printf ("%smachine_dep\n", indent); + break; + default: + printf ("%sunknown type\n", indent); + break; + } + printf ("%saddr=%d(0x%x)\n", indent, fp->fr_address, fp->fr_address); + printf ("%sfr_fix=%d\n", indent, fp->fr_fix); + printf ("%sfr_var=%d\n", indent, fp->fr_var); + printf ("%sfr_offset=%d\n", indent, fp->fr_offset); + printf ("%schars @ 0x%x\n", indent, fp->fr_literal); + printf ("\n"); + } +} + +var_chars (fp, n) + struct frag *fp; + int n; +{ + unsigned char *p; + + for (p = (unsigned char *) fp->fr_literal; n; n--, p++) + { + printf ("%02x ", *p); + } +} + +/* end of debug.c */ diff --git a/contrib/binutils/gas/dep-in.sed b/contrib/binutils/gas/dep-in.sed new file mode 100644 index 0000000..e4ac32b --- /dev/null +++ b/contrib/binutils/gas/dep-in.sed @@ -0,0 +1,44 @@ +:loop +/\\$/N +/\\$/b loop + +s! ../config.h!!g +s! ../../bfd/bfd.h!!g +s! ../itbl-parse.h!!g +s!@INCDIR@!$(INCDIR)!g +s!@BFDDIR@!$(BFDDIR)!g +s!@SRCDIR@/config!$(srcdir)/config!g +s!@SRCDIR@/../opcodes!$(srcdir)/../opcodes!g +s!@SRCDIR@/!!g +s! config.h!!g +s! as.h!!g +s! targ-env.h!!g +s! obj-format.h!!g +s! targ-cpu.h!!g +s! flonum.h!!g +s! expr.h!!g +s! struc-symbol.h!!g +s! write.h!!g +s! frags.h!!g +s! hash.h!!g +s! read.h!!g +s! symbols.h!!g +s! tc.h!!g +s! obj.h!!g +s! listing.h!!g +s! bignum.h!!g +s! bit_fix.h!!g +s! itbl-cpu.h!!g +s! \$(srcdir)/config/te-generic.h!!g +s! \$(INCDIR)/libiberty.h!!g +s! \$(INCDIR)/ansidecl.h!!g +s! \$(INCDIR)/fopen-same.h!!g + +s/\\\n */ /g + +s/ *$// +s/ */ /g +/:$/d + +s/\(.\{50\}[^ ]*\) /\1 \\\ + /g diff --git a/contrib/binutils/gas/doc/Makefile.in b/contrib/binutils/gas/doc/Makefile.in new file mode 100644 index 0000000..3749cbc --- /dev/null +++ b/contrib/binutils/gas/doc/Makefile.in @@ -0,0 +1,193 @@ +# Makefile for GNU Assembler documentation +# Copyright (C) 1987-1993 Free Software Foundation, Inc. + +#This file is part of GNU GAS. + +#GNU GAS is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#GNU GAS is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with GNU GAS; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# The targets for external use include: +# all, doc, proto, install, uninstall, includes, TAGS, +# clean, cleanconfig, realclean, stage1, stage2, stage3, stage4. + +# Variables that exist for you to override. + +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ + +program_transform_name = @program_transform_name@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = @infodir@ +includedir = @includedir@ + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_XFORM1 = $(INSTALL) -b $(program_transform_name) .1 + +AR = ar +AR_FLAGS = qv +BISON = bison +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +DVIPS = dvips +RANLIB = ranlib + +# What version of the manual you want; "all" includes everything +CONFIG=all + +# Where to find texinfo.tex to format docn with TeX +TEXIDIR = $(srcdir)/../../texinfo + +## + +all: +install: + $(INSTALL_XFORM1) $(srcdir)/as.1 $(man1dir)/as.1 + +info: as.info gasp.info +dvi: as.dvi gasp.dvi +ps: as.ps gasp.ps + +asconfig.texi: $(CONFIG).texi + rm -f asconfig.texi + ln -s $(srcdir)/$(CONFIG).texi ./asconfig.texi || \ + ln $(srcdir)/$(CONFIG).texi ./asconfig.texi || \ + cp $(srcdir)/$(CONFIG).texi ./asconfig.texi + +as.info: $(srcdir)/as.texinfo asconfig.texi + $(MAKEINFO) -I$(TEXIDIR) -I$(srcdir) -o as.info $(srcdir)/as.texinfo + +gasp.info: $(srcdir)/gasp.texi + $(MAKEINFO) -o gasp.info $(srcdir)/gasp.texi + +install-info: install-info-as install-info-gasp +install-info-as: as.info + if [ -r as.info ]; then \ + dir=. ; \ + else \ + dir=$(srcdir) ; \ + fi ; \ + for i in `cd $$dir ; echo as.info*` ; do \ + $(INSTALL_DATA) $$dir/$$i $(infodir)/$$i ; \ + done +install-info-gasp: gasp.info + if [ -r gasp.info ]; then \ + dir=. ; \ + else \ + dir=$(srcdir) ; \ + fi ; \ + for i in `cd $$dir ; echo gasp.info*` ; do \ + $(INSTALL_DATA) $$dir/$$i $(infodir)/$$i ; \ + done + +as.dvi: $(srcdir)/as.texinfo asconfig.texi + TEXINPUTS=$(srcdir):$(TEXIDIR):$$TEXINPUTS MAKEINFO='$(MAKEINFO) -I$(srcdir)' \ + $(TEXI2DVI) $(srcdir)/as.texinfo + +as.ps: as.dvi + $(DVIPS) -o $@ $? + +gasp.dvi: $(srcdir)/gasp.texi + TEXINPUTS=$(srcdir):$(TEXIDIR):$$TEXINPUTS MAKEINFO='$(MAKEINFO) -I$(srcdir)' \ + $(TEXI2DVI) $(srcdir)/gasp.texi + +gasp.ps: gasp.dvi + $(DVIPS) -o $@ $? + +# This one isn't ready for prime time yet. Not even a little bit. + +internals.info: $(srcdir)/internals.texi + $(MAKEINFO) -o $@ $? + +internals.dvi: $(srcdir)/internals.texi + TEXINPUTS=$(srcdir):$(TEXIDIR):$$TEXINPUTS MAKEINFO='$(MAKEINFO) -I$(srcdir)' \ + $(TEXI2DVI) $(srcdir)/internals.texi + +internals.ps: internals.dvi + $(DVIPS) -o $@ $? + +internals.ps4: internals.ps + psnup -4 <$? >$@ + +# ROFF doc targets as.ms, as.mm, as.me +# (we don't use a variable because we don't trust all makes to handle +# a var in the target name right). +# roff output (-ms) +# THESE ARE PROBABLY BROKEN until texi2roff extended for Texinfo conditionals +as.ms: $(srcdir)/as.texinfo asconfig.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + $(srcdir)/as.texinfo | \ + texi2roff -ms >as.ms + +# roff output (-mm) +as.mm: $(srcdir)/as.texinfo asconfig.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + -e '/@noindent/d' \ + $(srcdir)/as.texinfo | \ + texi2roff -mm | \ + sed -e 's/---/\\(em/g' \ + >as.mm + +# roff output (-me) +as.me: $(srcdir)/as.texinfo asconfig.texi + sed -e '/\\input texinfo/d' \ + -e '/@c TEXI2ROFF-KILL/,/@c END TEXI2ROFF-KILL/d' \ + -e 's/{.*,,/{/' \ + $(srcdir)/as.texinfo | \ + texi2roff -me >as.me + +clean mostlyclean: clean-dvi clean-info + rm -f asconfig.texi core *~ + +distclean: + rm -f Makefile config.status asconfig.texi \ + as.?? as.??s as.aux as.log as.toc \ + internals.?? internals.??s internals.aux internals.log internals.toc \ + gasp.?? gasp.??s gasp.aux gasp.log gasp.toc + +clean-dvi: + rm -f as.?? as.??? gasp.?? gasp.??? internals.?? internals.??? + +clean-info: + rm -f as.info* gasp.info* + +maintainer-clean realclean: clean-info distclean + +force: + +Makefile: $(srcdir)/Makefile.in $(host_makefile_frag) $(target_makefile_frag) + (cd .. ; $(SHELL) ./config.status) diff --git a/contrib/binutils/gas/doc/all.texi b/contrib/binutils/gas/doc/all.texi new file mode 100644 index 0000000..8476921 --- /dev/null +++ b/contrib/binutils/gas/doc/all.texi @@ -0,0 +1,66 @@ +@c Copyright 1992, 1993 Free Software Foundation, Inc. +@c This file is part of the documentation for the GAS manual + +@c Configuration settings for all-inclusive version of manual + +@c switches:------------------------------------------------------------ +@c Properties of the manual +@c ======================== +@c Discuss all architectures? +@set ALL-ARCH +@c A generic form of manual (not tailored to specific target)? +@set GENERIC +@c Include text on assembler internals? +@clear INTERNALS +@c Many object formats supported in this config? +@set MULTI-OBJ + +@c Object formats of interest +@c ========================== +@set AOUT +@set BOUT +@set COFF +@set ELF +@set SOM + +@c CPUs of interest +@c ================ +@set A29K +@set D10V +@set H8/300 +@set H8/500 +@set SH +@set I80386 +@set I960 +@set MIPS +@set M680X0 +@set Z8000 +@set SPARC +@set VAX +@set VXWORKS +@set HPPA + +@c Does this version of the assembler use the difference-table kluge? +@set DIFF-TBL-KLUGE + +@c Do all machines described use IEEE floating point? +@clear IEEEFLOAT + +@c Is a word 32 bits, or 16? +@clear W32 +@set W16 + +@c Do symbols have different characters than usual? +@clear SPECIAL-SYMS + +@c strings:------------------------------------------------------------ +@c Name of the assembler: +@set AS as +@c Name of C compiler: +@set GCC gcc +@c Name of linker: +@set LD ld +@c Text for target machine (best not used in generic case; but just in case...) +@set TARGET machine specific +@c Name of object format NOT SET in generic version +@clear OBJ-NAME diff --git a/contrib/binutils/gas/doc/as.1 b/contrib/binutils/gas/doc/as.1 new file mode 100644 index 0000000..1ff0d0b --- /dev/null +++ b/contrib/binutils/gas/doc/as.1 @@ -0,0 +1,293 @@ +.\" Copyright (c) 1991, 1992, 1996 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.TH as 1 "29 March 1996" "cygnus support" "GNU Development Tools" + +.SH NAME +GNU as \- the portable GNU assembler. + +.SH SYNOPSIS +.na +.B as +.RB "[\|" \-a "[\|" dhlns "\|]" \c +\&\[\|\=\c +.I file\c +\&\|]\|] +.RB "[\|" \-D "\|]" +.RB "[\|" \-\-defsym\ SYM=VAL "\|]" +.RB "[\|" \-f "\|]" +.RB "[\|" \-I +.I path\c +\&\|] +.RB "[\|" \-K "\|]" +.RB "[\|" \-L "\|]" +.RB "[\|" \-M\ |\ \-\-mri "\|]" +.RB "[\|" \-o +.I objfile\c +\&\|] +.RB "[\|" \-R "\|]" +.RB "[\|" \-v "\|]" +.RB "[\|" \-w "\|]" +.RB "[\|" \-\^\- "\ |\ " \c +.I files\c +\&\|.\|.\|.\|] + +.I i960-only options: +.br +.RB "[\|" \-ACA "\||\|" \-ACA_A "\||\|" \-ACB\c +.RB "\||\|" \-ACC "\||\|" \-AKA "\||\|" \-AKB\c +.RB "\||\|" \-AKC "\||\|" \-AMC "\|]" +.RB "[\|" \-b "\|]" +.RB "[\|" \-no-relax "\|]" + +.I m680x0-only options: +.br +.RB "[\|" \-l "\|]" +.RB "[\|" \-mc68000 "\||\|" \-mc68010 "\||\|" \-mc68020 "\|]" +.ad b + +.SH DESCRIPTION +GNU \c +.B as\c +\& is really a family of assemblers. +If you use (or have used) the GNU assembler on one architecture, you +should find a fairly similar environment when you use it on another +architecture. Each version has much in common with the others, +including object file formats, most assembler directives (often called +\c +.I pseudo-ops)\c +\& and assembler syntax. + +For information on the syntax and pseudo-ops used by GNU \c +.B as\c +\&, see `\|\c +.B as\c +\|' entry in \c +.B info \c +(or the manual \c +.I +.I +Using as: The GNU Assembler\c +\&). + +\c +.B as\c +\& is primarily intended to assemble the output of the GNU C +compiler \c +.B gcc\c +\& for use by the linker \c +.B ld\c +\&. Nevertheless, +we've tried to make \c +.B as\c +\& assemble correctly everything that the native +assembler would. +This doesn't mean \c +.B as\c +\& always uses the same syntax as another +assembler for the same architecture; for example, we know of several +incompatible versions of 680x0 assembly language syntax. + +Each time you run \c +.B as\c +\& it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) + +If \c +.B as\c +\& is given no file names it attempts to read one input file +from the \c +.B as\c +\& standard input, which is normally your terminal. You +may have to type \c +.B ctl-D\c +\& to tell \c +.B as\c +\& there is no more program +to assemble. Use `\|\c +.B \-\^\-\c +\|' if you need to explicitly name the standard input file +in your command line. + +.B as\c +\& may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when \c +.B as\c +\& is +run automatically by a compiler. Warnings report an assumption made so +that \c +.B as\c +\& could keep assembling a flawed program; errors report a +grave problem that stops the assembly. + +.SH OPTIONS +.TP +.BR \-a +Turn on assembly listings. There are various suboptions. +.B d +omits debugging directives. +.B h +includes the high level source code; this is only available if the +source file can be found, and the code was compiled with +.B \-g. +.B l +includes an assembly listing. +.B n +omits forms processing. +.B s +includes a symbol listing. +.B = +.I file +sets the listing file name; this must be the last suboption. +The default suboptions are +.B hls. +.TP +.B \-D +This option is accepted only for script compatibility with calls to +other assemblers; it has no effect on \c +.B as\c +\&. +.TP +.B \-\-defsym SYM=VALUE +Define the symbol SYM to be VALUE before assembling the input file. +VALUE must be an integer constant. As in C, a leading 0x indicates a +hexadecimal value, and a leading 0 indicates an octal value. +.TP +.B \-f +``fast''--skip preprocessing (assume source is compiler output). +.TP +.BI "\-I\ " path +Add +.I path +to the search list for +.B .include +directives. +.TP +.B \-K +Issue warnings when difference tables altered for long displacements. +.TP +.B \-L +Keep (in symbol table) local symbols, starting with `\|\c +.B L\c +\|' +.TP +.B \-M, \-\-mri +Assemble in MRI compatibility mode. +.TP +.BI "\-o\ " objfile +Name the object-file output from \c +.B as +.TP +.B \-R +Fold data section into text section +.TP +.B \-v +Announce \c +.B as\c +\& version +.TP +.B \-W +Suppress warning messages +.TP +.IR "\-\^\-" "\ |\ " "files\|.\|.\|." +Source files to assemble, or standard input (\c +.BR "\-\^\-" ")" +.TP +.BI \-A var +.I +(When configured for Intel 960.) +Specify which variant of the 960 architecture is the target. +.TP +.B \-b +.I +(When configured for Intel 960.) +Add code to collect statistics about branches taken. +.TP +.B \-no-relax +.I +(When configured for Intel 960.) +Do not alter compare-and-branch instructions for long displacements; +error if necessary. +.TP +.B \-l +.I +(When configured for Motorola 68000). +.br +Shorten references to undefined symbols, to one word instead of two. +.TP +.BR "\-mc68000" "\||\|" "\-mc68010" "\||\|" "\-mc68020" +.I +(When configured for Motorola 68000). +.br +Specify what processor in the 68000 family is the target (default 68020) + +.PP +Options may be in any order, and may be +before, after, or between file names. The order of file names is +significant. + +`\|\c +.B \-\^\-\c +\|' (two hyphens) by itself names the standard input file +explicitly, as one of the files for \c +.B as\c +\& to assemble. + +Except for `\|\c +.B \-\^\-\c +\|' any command line argument that begins with a +hyphen (`\|\c +.B \-\c +\|') is an option. Each option changes the behavior of +\c +.B as\c +\&. No option changes the way another option works. An +option is a `\|\c +.B \-\c +\|' followed by one or more letters; the case of +the letter is important. All options are optional. + +The `\|\c +.B \-o\c +\|' option expects exactly one file name to follow. The file +name may either immediately follow the option's letter (compatible +with older assemblers) or it may be the next command argument (GNU +standard). + +These two command lines are equivalent: +.br +.B +as\ \ \-o\ \ my\-object\-file.o\ \ mumble.s +.br +.B +as\ \ \-omy\-object\-file.o\ \ mumble.s + +.SH "SEE ALSO" +.RB "`\|" as "\|'" +entry in +.B +info\c +\&; +.I +Using as: The GNU Assembler\c +\&; +.BR gcc "(" 1 ")," +.BR ld "(" 1 ")." + +.SH COPYING +Copyright (c) 1991, 1992 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/contrib/binutils/gas/doc/as.texinfo b/contrib/binutils/gas/doc/as.texinfo new file mode 100644 index 0000000..c6ad48f --- /dev/null +++ b/contrib/binutils/gas/doc/as.texinfo @@ -0,0 +1,4970 @@ +\input texinfo @c -*-Texinfo-*- +@c Copyright (c) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +@c UPDATE!! On future updates-- +@c (1) check for new machine-dep cmdline options in +@c md_parse_option definitions in config/tc-*.c +@c (2) for platform-specific directives, examine md_pseudo_op +@c in config/tc-*.c +@c (3) for object-format specific directives, examine obj_pseudo_op +@c in config/obj-*.c +@c (4) portable directives in potable[] in read.c +@c %**start of header +@setfilename as.info +@c ---config--- +@c defaults, config file may override: +@set have-stabs +@c --- +@include asconfig.texi +@c --- +@c common OR combinations of conditions +@ifset AOUT +@set aout-bout +@end ifset +@ifset BOUT +@set aout-bout +@end ifset +@ifset H8/300 +@set H8 +@end ifset +@ifset H8/500 +@set H8 +@end ifset +@ifset SH +@set H8 +@end ifset +@ifset HPPA +@set abnormal-separator +@end ifset +@c ------------ +@ifset GENERIC +@settitle Using @value{AS} +@end ifset +@ifclear GENERIC +@settitle Using @value{AS} (@value{TARGET}) +@end ifclear +@setchapternewpage odd +@c %**end of header + +@c @smallbook +@c @set SMALL +@c WARE! Some of the machine-dependent sections contain tables of machine +@c instructions. Except in multi-column format, these tables look silly. +@c Unfortunately, Texinfo doesn't have a general-purpose multi-col format, so +@c the multi-col format is faked within @example sections. +@c +@c Again unfortunately, the natural size that fits on a page, for these tables, +@c is different depending on whether or not smallbook is turned on. +@c This matters, because of order: text flow switches columns at each page +@c break. +@c +@c The format faked in this source works reasonably well for smallbook, +@c not well for the default large-page format. This manual expects that if you +@c turn on @smallbook, you will also uncomment the "@set SMALL" to enable the +@c tables in question. You can turn on one without the other at your +@c discretion, of course. +@ifinfo +@set SMALL +@c the insn tables look just as silly in info files regardless of smallbook, +@c might as well show 'em anyways. +@end ifinfo + +@ifinfo +@format +START-INFO-DIR-ENTRY +* As: (as). The GNU assembler. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@finalout +@syncodeindex ky cp + +@ifinfo +This file documents the GNU Assembler "@value{AS}". + +Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this manual +under the conditions for verbatim copying, provided that the entire resulting +derived work is distributed under the terms of a permission notice identical to +this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end ifinfo + +@titlepage +@title Using @value{AS} +@subtitle The @sc{gnu} Assembler +@ifclear GENERIC +@subtitle for the @value{TARGET} family +@end ifclear +@sp 1 +@subtitle January 1994 +@sp 1 +@sp 13 +The Free Software Foundation Inc. thanks The Nice Computer +Company of Australia for loaning Dean Elsner to write the +first (Vax) version of @code{as} for Project @sc{gnu}. +The proprietors, management and staff of TNCCA thank FSF for +distracting the boss while they got some work +done. +@sp 3 +@author Dean Elsner, Jay Fenlason & friends +@page +@tex +{\parskip=0pt +\hfill {\it Using {\tt @value{AS}}}\par +\hfill Edited by Cygnus Support\par +} +%"boxit" macro for figures: +%Modified from Knuth's ``boxit'' macro from TeXbook (answer to exercise 21.3) +\gdef\boxit#1#2{\vbox{\hrule\hbox{\vrule\kern3pt + \vbox{\parindent=0pt\parskip=0pt\hsize=#1\kern3pt\strut\hfil +#2\hfil\strut\kern3pt}\kern3pt\vrule}\hrule}}%box with visible outline +\gdef\ibox#1#2{\hbox to #1{#2\hfil}\kern8pt}% invisible box +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this manual +under the conditions for verbatim copying, provided that the entire resulting +derived work is distributed under the terms of a permission notice identical to +this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage + +@ifinfo +@node Top +@top Using @value{AS} + +This file is a user guide to the @sc{gnu} assembler @code{@value{AS}}. +@ifclear GENERIC +This version of the file describes @code{@value{AS}} configured to generate +code for @value{TARGET} architectures. +@end ifclear +@menu +* Overview:: Overview +* Invoking:: Command-Line Options +* Syntax:: Syntax +* Sections:: Sections and Relocation +* Symbols:: Symbols +* Expressions:: Expressions +* Pseudo Ops:: Assembler Directives +* Machine Dependencies:: Machine Dependent Features +* Reporting Bugs:: Reporting Bugs +* Acknowledgements:: Who Did What +* Index:: Index +@end menu +@end ifinfo + +@node Overview +@chapter Overview +@iftex +This manual is a user guide to the @sc{gnu} assembler @code{@value{AS}}. +@ifclear GENERIC +This version of the manual describes @code{@value{AS}} configured to generate +code for @value{TARGET} architectures. +@end ifclear +@end iftex + +@cindex invocation summary +@cindex option summary +@cindex summary of options +Here is a brief summary of how to invoke @code{@value{AS}}. For details, +@pxref{Invoking,,Comand-Line Options}. + +@c We don't use deffn and friends for the following because they seem +@c to be limited to one line for the header. +@smallexample +@value{AS} [ -a[cdhlns][=file] ] [ -D ] [ --defsym @var{sym}=@var{val} ] + [ -f ] [ --help ] [ -I @var{dir} ] [ -J ] [ -K ] [ -L ] + [ -o @var{objfile} ] [ -R ] [ --statistics ] [ -v ] [ -version ] + [ --version ] [ -W ] [ -w ] [ -x ] [ -Z ] +@ifset A29K +@c am29k has no machine-dependent assembler options +@end ifset +@ifset D10V + [ -O ] +@end ifset + +@ifset H8 +@c Hitachi family chips have no machine-dependent assembler options +@end ifset +@ifset HPPA +@c HPPA has no machine-dependent assembler options (yet). +@end ifset +@ifset SPARC +@c The order here is important. See c-sparc.texi. + [ -Av6 | -Av7 | -Av8 | -Asparclet | -Asparclite | -Av9 | -Av9a ] + [ -xarch=v8plus | -xarch=v8plusa ] [ -bump ] +@end ifset +@ifset Z8000 +@c Z8000 has no machine-dependent assembler options +@end ifset +@ifset I960 +@c see md_parse_option in tc-i960.c + [ -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC ] + [ -b ] [ -no-relax ] +@end ifset +@ifset M680X0 + [ -l ] [ -m68000 | -m68010 | -m68020 | ... ] +@end ifset +@ifset MIPS + [ -nocpp ] [ -EL ] [ -EB ] [ -G @var{num} ] [ -mcpu=@var{CPU} ] + [ -mips1 ] [ -mips2 ] [ -mips3 ] [ -m4650 ] [ -no-m4650 ] + [ --trap ] [ --break ] + [ --emulation=@var{name} ] +@end ifset + [ -- | @var{files} @dots{} ] +@end smallexample + +@table @code +@item -a[dhlns] +Turn on listings, in any of a variety of ways: + +@table @code +@item -ad +omit debugging directives + +@item -ah +include high-level source + +@item -al +include assembly + +@item -an +omit forms processing + +@item -as +include symbols + +@item =file +set the name of the listing file +@end table + +You may combine these options; for example, use @samp{-aln} for assembly +listing without forms processing. The @samp{=file} option, if used, must be +the last one. By itself, @samp{-a} defaults to @samp{-ahls}---that is, all +listings turned on. + +@item -D +Ignored. This option is accepted for script compatibility with calls to +other assemblers. + +@item --defsym @var{sym}=@var{value} +Define the symbol @var{sym} to be @var{value} before assembling the input file. +@var{value} must be an integer constant. As in C, a leading @samp{0x} +indicates a hexadecimal value, and a leading @samp{0} indicates an octal value. + +@item -f +``fast''---skip whitespace and comment preprocessing (assume source is +compiler output). + +@item --help +Print a summary of the command line options and exit. + +@item -I @var{dir} +Add directory @var{dir} to the search list for @code{.include} directives. + +@item -J +Don't warn about signed overflow. + +@item -K +@ifclear DIFF-TBL-KLUGE +This option is accepted but has no effect on the @value{TARGET} family. +@end ifclear +@ifset DIFF-TBL-KLUGE +Issue warnings when difference tables altered for long displacements. +@end ifset + +@item -L +Keep (in the symbol table) local symbols, starting with @samp{L}. + +@item -o @var{objfile} +Name the object-file output from @code{@value{AS}} @var{objfile}. + +@item -R +Fold the data section into the text section. + +@item --statistics +Print the maximum space (in bytes) and total time (in seconds) used by +assembly. + +@item -v +@itemx -version +Print the @code{as} version. + +@item --version +Print the @code{as} version and exit. + +@item -W +Suppress warning messages. + +@item -w +Ignored. + +@item -x +Ignored. + +@item -Z +Generate an object file even after errors. + +@item -- | @var{files} @dots{} +Standard input, or source files to assemble. + +@end table + +@ifset ARC +The following options are available when @value{AS} is configured for +an ARC processor. + +@table @code + +@cindex ARC endianness +@cindex endianness, ARC +@cindex big endian output, ARC +@item -mbig-endian +Generate ``big endian'' format output. + +@cindex little endian output, ARC +@item -mlittle-endian +Generate ``little endian'' format output. + +@end table +@end ifset + +@ifset D10V +The following options are available when @value{AS} is configured for +a D10V processor. +@table @code +@cindex D10V optimization +@cindex optimization, D10V +@item -O +Optimize output by parallelizing instructions. +@end table +@end ifset + +@ifset I960 +The following options are available when @value{AS} is configured for the +Intel 80960 processor. + +@table @code +@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC +Specify which variant of the 960 architecture is the target. + +@item -b +Add code to collect statistics about branches taken. + +@item -no-relax +Do not alter compare-and-branch instructions for long displacements; +error if necessary. + +@end table +@end ifset + +@ifset M680X0 +The following options are available when @value{AS} is configured for the +Motorola 68000 series. + +@table @code + +@item -l +Shorten references to undefined symbols, to one word instead of two. + +@item -m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060 +@itemx | -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -mcpu32 | -m5200 +Specify what processor in the 68000 family is the target. The default +is normally the 68020, but this can be changed at configuration time. + +@item -m68881 | -m68882 | -mno-68881 | -mno-68882 +The target machine does (or does not) have a floating-point coprocessor. +The default is to assume a coprocessor for 68020, 68030, and cpu32. Although +the basic 68000 is not compatible with the 68881, a combination of the +two can be specified, since it's possible to do emulation of the +coprocessor instructions with the main processor. + +@item -m68851 | -mno-68851 +The target machine does (or does not) have a memory-management +unit coprocessor. The default is to assume an MMU for 68020 and up. + +@end table +@end ifset + +@ifset SPARC +The following options are available when @code{@value{AS}} is configured +for the SPARC architecture: + +@table @code +@item -Av6 | -Av7 | -Av8 | -Asparclet | -Asparclite | -Av9 | -Av9a +Explicitly select a variant of the SPARC architecture. + +@item -xarch=v8plus | -xarch=v8plusa +For compatibility with the Solaris v9 assembler. These options are +equivalent to -Av9 and -Av9a, respectively. + +@item -bump +Warn when the assembler switches to another architecture. +@end table +@end ifset + +@ifset MIPS +The following options are available when @value{AS} is configured for +a MIPS processor. + +@table @code +@item -G @var{num} +This option sets the largest size of an object that can be referenced +implicitly with the @code{gp} register. It is only accepted for targets that +use ECOFF format, such as a DECstation running Ultrix. The default value is 8. + +@cindex MIPS endianness +@cindex endianness, MIPS +@cindex big endian output, MIPS +@item -EB +Generate ``big endian'' format output. + +@cindex little endian output, MIPS +@item -EL +Generate ``little endian'' format output. + +@cindex MIPS ISA +@item -mips1 +@itemx -mips2 +@itemx -mips3 +Generate code for a particular MIPS Instruction Set Architecture level. +@samp{-mips1} corresponds to the @sc{r2000} and @sc{r3000} processors, +@samp{-mips2} to the @sc{r6000} processor, and @samp{-mips3} to the @sc{r4000} +processor. + +@item -m4650 +@item -no-m4650 +Generate code for the MIPS @sc{r4650} chip. This tells the assembler to accept +the @samp{mad} and @samp{madu} instruction, and to not schedule @samp{nop} +instructions around accesses to the @samp{HI} and @samp{LO} registers. +@samp{-no-m4650} turns off this option. + +@item -mcpu=@var{CPU} +Generate code for a particular MIPS cpu. This has little effect on the +assembler, but it is passed by @code{@value{GCC}}. + +@cindex emulation +@item --emulation=@var{name} +This option causes @code{@value{AS}} to emulated @code{@value{AS}} configured +for some other target, in all respects, including output format (choosing +between ELF and ECOFF only), handling of pseudo-opcodes which may generate +debugging information or store symbol table information, and default +endianness. The available configuration names are: @samp{mipsecoff}, +@samp{mipself}, @samp{mipslecoff}, @samp{mipsbecoff}, @samp{mipslelf}, +@samp{mipsbelf}. The first two do not alter the default endianness from that +of the primary target for which the assembler was configured; the others change +the default to little- or big-endian as indicated by the @samp{b} or @samp{l} +in the name. Using @samp{-EB} or @samp{-EL} will override the endianness +selection in any case. + +This option is currently supported only when the primary target +@code{@value{AS}} is configured for is a MIPS ELF or ECOFF target. +Furthermore, the primary target or others specified with +@samp{--enable-targets=@dots{}} at configuration time must include support for +the other format, if both are to be available. For example, the Irix 5 +configuration includes support for both. + +Eventually, this option will support more configurations, with more +fine-grained control over the assembler's behavior, and will be supported for +more processors. + +@item -nocpp +@code{@value{AS}} ignores this option. It is accepted for compatibility with +the native tools. + +@need 900 +@item --trap +@itemx --no-trap +@itemx --break +@itemx --no-break +Control how to deal with multiplication overflow and division by zero. +@samp{--trap} or @samp{--no-break} (which are synonyms) take a trap exception +(and only work for Instruction Set Architecture level 2 and higher); +@samp{--break} or @samp{--no-trap} (also synonyms, and the default) take a +break exception. +@end table +@end ifset + +@menu +* Manual:: Structure of this Manual +* GNU Assembler:: The GNU Assembler +* Object Formats:: Object File Formats +* Command Line:: Command Line +* Input Files:: Input Files +* Object:: Output (Object) File +* Errors:: Error and Warning Messages +@end menu + +@node Manual +@section Structure of this Manual + +@cindex manual, structure and purpose +This manual is intended to describe what you need to know to use +@sc{gnu} @code{@value{AS}}. We cover the syntax expected in source files, including +notation for symbols, constants, and expressions; the directives that +@code{@value{AS}} understands; and of course how to invoke @code{@value{AS}}. + +@ifclear GENERIC +We also cover special features in the @value{TARGET} +configuration of @code{@value{AS}}, including assembler directives. +@end ifclear +@ifset GENERIC +This manual also describes some of the machine-dependent features of +various flavors of the assembler. +@end ifset + +@cindex machine instructions (not covered) +On the other hand, this manual is @emph{not} intended as an introduction +to programming in assembly language---let alone programming in general! +In a similar vein, we make no attempt to introduce the machine +architecture; we do @emph{not} describe the instruction set, standard +mnemonics, registers or addressing modes that are standard to a +particular architecture. +@ifset GENERIC +You may want to consult the manufacturer's +machine architecture manual for this information. +@end ifset +@ifclear GENERIC +@ifset H8/300 +For information on the H8/300 machine instruction set, see @cite{H8/300 +Series Programming Manual} (Hitachi ADE--602--025). For the H8/300H, +see @cite{H8/300H Series Programming Manual} (Hitachi). +@end ifset +@ifset H8/500 +For information on the H8/500 machine instruction set, see @cite{H8/500 +Series Programming Manual} (Hitachi M21T001). +@end ifset +@ifset SH +For information on the Hitachi SH machine instruction set, see +@cite{SH-Microcomputer User's Manual} (Hitachi Micro Systems, Inc.). +@end ifset +@ifset Z8000 +For information on the Z8000 machine instruction set, see @cite{Z8000 CPU Technical Manual} +@end ifset +@end ifclear + +@c I think this is premature---doc@cygnus.com, 17jan1991 +@ignore +Throughout this manual, we assume that you are running @dfn{GNU}, +the portable operating system from the @dfn{Free Software +Foundation, Inc.}. This restricts our attention to certain kinds of +computer (in particular, the kinds of computers that @sc{gnu} can run on); +once this assumption is granted examples and definitions need less +qualification. + +@code{@value{AS}} is part of a team of programs that turn a high-level +human-readable series of instructions into a low-level +computer-readable series of instructions. Different versions of +@code{@value{AS}} are used for different kinds of computer. +@end ignore + +@c There used to be a section "Terminology" here, which defined +@c "contents", "byte", "word", and "long". Defining "word" to any +@c particular size is confusing when the .word directive may generate 16 +@c bits on one machine and 32 bits on another; in general, for the user +@c version of this manual, none of these terms seem essential to define. +@c They were used very little even in the former draft of the manual; +@c this draft makes an effort to avoid them (except in names of +@c directives). + +@node GNU Assembler +@section The GNU Assembler + +@sc{gnu} @code{as} is really a family of assemblers. +@ifclear GENERIC +This manual describes @code{@value{AS}}, a member of that family which is +configured for the @value{TARGET} architectures. +@end ifclear +If you use (or have used) the @sc{gnu} assembler on one architecture, you +should find a fairly similar environment when you use it on another +architecture. Each version has much in common with the others, +including object file formats, most assembler directives (often called +@dfn{pseudo-ops}) and assembler syntax.@refill + +@cindex purpose of @sc{gnu} assembler +@code{@value{AS}} is primarily intended to assemble the output of the +@sc{gnu} C compiler @code{@value{GCC}} for use by the linker +@code{@value{LD}}. Nevertheless, we've tried to make @code{@value{AS}} +assemble correctly everything that other assemblers for the same +machine would assemble. +@ifset VAX +Any exceptions are documented explicitly (@pxref{Machine Dependencies}). +@end ifset +@ifset M680X0 +@c This remark should appear in generic version of manual; assumption +@c here is that generic version sets M680x0. +This doesn't mean @code{@value{AS}} always uses the same syntax as another +assembler for the same architecture; for example, we know of several +incompatible versions of 680x0 assembly language syntax. +@end ifset + +Unlike older assemblers, @code{@value{AS}} is designed to assemble a source +program in one pass of the source file. This has a subtle impact on the +@kbd{.org} directive (@pxref{Org,,@code{.org}}). + +@node Object Formats +@section Object File Formats + +@cindex object file format +The @sc{gnu} assembler can be configured to produce several alternative +object file formats. For the most part, this does not affect how you +write assembly language programs; but directives for debugging symbols +are typically different in different file formats. @xref{Symbol +Attributes,,Symbol Attributes}. +@ifclear GENERIC +@ifclear MULTI-OBJ +On the @value{TARGET}, @code{@value{AS}} is configured to produce +@value{OBJ-NAME} format object files. +@end ifclear +@c The following should exhaust all configs that set MULTI-OBJ, ideally +@ifset A29K +On the @value{TARGET}, @code{@value{AS}} can be configured to produce either +@code{a.out} or COFF format object files. +@end ifset +@ifset I960 +On the @value{TARGET}, @code{@value{AS}} can be configured to produce either +@code{b.out} or COFF format object files. +@end ifset +@ifset HPPA +On the @value{TARGET}, @code{@value{AS}} can be configured to produce either +SOM or ELF format object files. +@end ifset +@end ifclear + +@node Command Line +@section Command Line + +@cindex command line conventions +After the program name @code{@value{AS}}, the command line may contain +options and file names. Options may appear in any order, and may be +before, after, or between file names. The order of file names is +significant. + +@cindex standard input, as input file +@kindex -- +@file{--} (two hyphens) by itself names the standard input file +explicitly, as one of the files for @code{@value{AS}} to assemble. + +@cindex options, command line +Except for @samp{--} any command line argument that begins with a +hyphen (@samp{-}) is an option. Each option changes the behavior of +@code{@value{AS}}. No option changes the way another option works. An +option is a @samp{-} followed by one or more letters; the case of +the letter is important. All options are optional. + +Some options expect exactly one file name to follow them. The file +name may either immediately follow the option's letter (compatible +with older assemblers) or it may be the next command argument (@sc{gnu} +standard). These two command lines are equivalent: + +@smallexample +@value{AS} -o my-object-file.o mumble.s +@value{AS} -omy-object-file.o mumble.s +@end smallexample + +@node Input Files +@section Input Files + +@cindex input +@cindex source program +@cindex files, input +We use the phrase @dfn{source program}, abbreviated @dfn{source}, to +describe the program input to one run of @code{@value{AS}}. The program may +be in one or more files; how the source is partitioned into files +doesn't change the meaning of the source. + +@c I added "con" prefix to "catenation" just to prove I can overcome my +@c APL training... doc@cygnus.com +The source program is a concatenation of the text in all the files, in the +order specified. + +Each time you run @code{@value{AS}} it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) + +You give @code{@value{AS}} a command line that has zero or more input file +names. The input files are read (from left file name to right). A +command line argument (in any position) that has no special meaning +is taken to be an input file name. + +If you give @code{@value{AS}} no file names it attempts to read one input file +from the @code{@value{AS}} standard input, which is normally your terminal. You +may have to type @key{ctl-D} to tell @code{@value{AS}} there is no more program +to assemble. + +Use @samp{--} if you need to explicitly name the standard input file +in your command line. + +If the source is empty, @code{@value{AS}} produces a small, empty object +file. + +@subheading Filenames and Line-numbers + +@cindex input file linenumbers +@cindex line numbers, in input files +There are two ways of locating a line in the input file (or files) and +either may be used in reporting error messages. One way refers to a line +number in a physical file; the other refers to a line number in a +``logical'' file. @xref{Errors, ,Error and Warning Messages}. + +@dfn{Physical files} are those files named in the command line given +to @code{@value{AS}}. + +@dfn{Logical files} are simply names declared explicitly by assembler +directives; they bear no relation to physical files. Logical file names +help error messages reflect the original source file, when @code{@value{AS}} +source is itself synthesized from other files. +@xref{App-File,,@code{.app-file}}. + +@node Object +@section Output (Object) File + +@cindex object file +@cindex output file +@kindex a.out +@kindex .o +Every time you run @code{@value{AS}} it produces an output file, which is +your assembly language program translated into numbers. This file +is the object file. Its default name is +@ifclear BOUT +@code{a.out}. +@end ifclear +@ifset BOUT +@ifset GENERIC +@code{a.out}, or +@end ifset +@code{b.out} when @code{@value{AS}} is configured for the Intel 80960. +@end ifset +You can give it another name by using the @code{-o} option. Conventionally, +object file names end with @file{.o}. The default name is used for historical +reasons: older assemblers were capable of assembling self-contained programs +directly into a runnable program. (For some formats, this isn't currently +possible, but it can be done for the @code{a.out} format.) + +@cindex linker +@kindex ld +The object file is meant for input to the linker @code{@value{LD}}. It contains +assembled program code, information to help @code{@value{LD}} integrate +the assembled program into a runnable file, and (optionally) symbolic +information for the debugger. + +@c link above to some info file(s) like the description of a.out. +@c don't forget to describe @sc{gnu} info as well as Unix lossage. + +@node Errors +@section Error and Warning Messages + +@cindex error messsages +@cindex warning messages +@cindex messages from assembler +@code{@value{AS}} may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when a compiler +runs @code{@value{AS}} automatically. Warnings report an assumption made so +that @code{@value{AS}} could keep assembling a flawed program; errors report a +grave problem that stops the assembly. + +@cindex format of warning messages +Warning messages have the format + +@smallexample +file_name:@b{NNN}:Warning Message Text +@end smallexample + +@noindent +@cindex line numbers, in warnings/errors +(where @b{NNN} is a line number). If a logical file name has been given +(@pxref{App-File,,@code{.app-file}}) it is used for the filename, +otherwise the name of the current input file is used. If a logical line +number was given +@ifset GENERIC +(@pxref{Line,,@code{.line}}) +@end ifset +@ifclear GENERIC +@ifclear A29K +(@pxref{Line,,@code{.line}}) +@end ifclear +@ifset A29K +(@pxref{Ln,,@code{.ln}}) +@end ifset +@end ifclear +then it is used to calculate the number printed, +otherwise the actual line in the current source file is printed. The +message text is intended to be self explanatory (in the grand Unix +tradition). + +@cindex format of error messages +Error messages have the format +@smallexample +file_name:@b{NNN}:FATAL:Error Message Text +@end smallexample +The file name and line number are derived as for warning +messages. The actual message text may be rather less explanatory +because many of them aren't supposed to happen. + +@node Invoking +@chapter Command-Line Options + +@cindex options, all versions of assembler +This chapter describes command-line options available in @emph{all} +versions of the @sc{gnu} assembler; @pxref{Machine Dependencies}, for options specific +@ifclear GENERIC +to the @value{TARGET}. +@end ifclear +@ifset GENERIC +to particular machine architectures. +@end ifset + +If you are invoking @code{@value{AS}} via the @sc{gnu} C compiler (version 2), you +can use the @samp{-Wa} option to pass arguments through to the +assembler. The assembler arguments must be separated from each other +(and the @samp{-Wa}) by commas. For example: + +@smallexample +gcc -c -g -O -Wa,-alh,-L file.c +@end smallexample + +@noindent +emits a listing to standard output with high-level +and assembly source. + +Usually you do not need to use this @samp{-Wa} mechanism, since many compiler +command-line options are automatically passed to the assembler by the compiler. +(You can call the @sc{gnu} compiler driver with the @samp{-v} option to see +precisely what options it passes to each compilation pass, including the +assembler.) + +@menu +* a:: -a[cdhlns] enable listings +* D:: -D for compatibility +* f:: -f to work faster +* I:: -I for .include search path +@ifclear DIFF-TBL-KLUGE +* K:: -K for compatibility +@end ifclear +@ifset DIFF-TBL-KLUGE +* K:: -K for difference tables +@end ifset + +* L:: -L to retain local labels +* M:: -M or --mri to assemble in MRI compatibility mode +* o:: -o to name the object file +* R:: -R to join data and text sections +* statistics:: --statistics to see statistics about assembly +* v:: -v to announce version +* W:: -W to suppress warnings +* Z:: -Z to make object file even after errors +@end menu + +@node a +@section Enable Listings: @code{-a[cdhlns]} + +@kindex -a +@kindex -ac +@kindex -ad +@kindex -ah +@kindex -al +@kindex -an +@kindex -as +@cindex listings, enabling +@cindex assembly listings, enabling + +These options enable listing output from the assembler. By itself, +@samp{-a} requests high-level, assembly, and symbols listing. +You can use other letters to select specific options for the list: +@samp{-ah} requests a high-level language listing, +@samp{-al} requests an output-program assembly listing, and +@samp{-as} requests a symbol table listing. +High-level listings require that a compiler debugging option like +@samp{-g} be used, and that assembly listings (@samp{-al}) be requested +also. + +Use the @samp{-ac} option to omit false conditionals from a listing. Any lines +which are not assembled because of a false @code{.if} (or @code{.ifdef}, or any +other conditional), or a true @code{.if} followed by an @code{.else}, will be +omitted from the listing. + +Use the @samp{-ad} option to omit debugging directives from the +listing. + +Once you have specified one of these options, you can further control +listing output and its appearance using the directives @code{.list}, +@code{.nolist}, @code{.psize}, @code{.eject}, @code{.title}, and +@code{.sbttl}. +The @samp{-an} option turns off all forms processing. +If you do not request listing output with one of the @samp{-a} options, the +listing-control directives have no effect. + +The letters after @samp{-a} may be combined into one option, +@emph{e.g.}, @samp{-aln}. + +@node D +@section @code{-D} + +@kindex -D +This option has no effect whatsoever, but it is accepted to make it more +likely that scripts written for other assemblers also work with +@code{@value{AS}}. + +@node f +@section Work Faster: @code{-f} + +@kindex -f +@cindex trusted compiler +@cindex faster processing (@code{-f}) +@samp{-f} should only be used when assembling programs written by a +(trusted) compiler. @samp{-f} stops the assembler from doing whitespace +and comment preprocessing on +the input file(s) before assembling them. @xref{Preprocessing, +,Preprocessing}. + +@quotation +@emph{Warning:} if you use @samp{-f} when the files actually need to be +preprocessed (if they contain comments, for example), @code{@value{AS}} does +not work correctly. +@end quotation + +@node I +@section @code{.include} search path: @code{-I} @var{path} + +@kindex -I @var{path} +@cindex paths for @code{.include} +@cindex search path for @code{.include} +@cindex @code{include} directive search path +Use this option to add a @var{path} to the list of directories +@code{@value{AS}} searches for files specified in @code{.include} +directives (@pxref{Include,,@code{.include}}). You may use @code{-I} as +many times as necessary to include a variety of paths. The current +working directory is always searched first; after that, @code{@value{AS}} +searches any @samp{-I} directories in the same order as they were +specified (left to right) on the command line. + +@node K +@section Difference Tables: @code{-K} + +@kindex -K +@ifclear DIFF-TBL-KLUGE +On the @value{TARGET} family, this option is allowed, but has no effect. It is +permitted for compatibility with the @sc{gnu} assembler on other platforms, +where it can be used to warn when the assembler alters the machine code +generated for @samp{.word} directives in difference tables. The @value{TARGET} +family does not have the addressing limitations that sometimes lead to this +alteration on other platforms. +@end ifclear + +@ifset DIFF-TBL-KLUGE +@cindex difference tables, warning +@cindex warning for altered difference tables +@code{@value{AS}} sometimes alters the code emitted for directives of the form +@samp{.word @var{sym1}-@var{sym2}}; @pxref{Word,,@code{.word}}. +You can use the @samp{-K} option if you want a warning issued when this +is done. +@end ifset + +@node L +@section Include Local Labels: @code{-L} + +@kindex -L +@cindex local labels, retaining in output +Labels beginning with @samp{L} (upper case only) are called @dfn{local +labels}. @xref{Symbol Names}. Normally you do not see such labels when +debugging, because they are intended for the use of programs (like +compilers) that compose assembler programs, not for your notice. +Normally both @code{@value{AS}} and @code{@value{LD}} discard such labels, so you do not +normally debug with them. + +This option tells @code{@value{AS}} to retain those @samp{L@dots{}} symbols +in the object file. Usually if you do this you also tell the linker +@code{@value{LD}} to preserve symbols whose names begin with @samp{L}. + +By default, a local label is any label beginning with @samp{L}, but each +target is allowed to redefine the local label prefix. +@ifset HPPA +On the HPPA local labels begin with @samp{L$}. +@end ifset + +@node M +@section Assemble in MRI Compatibility Mode: @code{-M} + +@kindex -M +@cindex MRI compatibility mode +The @code{-M} or @code{--mri} option selects MRI compatibility mode. This +changes the syntax and pseudo-op handling of @code{@value{AS}} to make it +compatible with the @code{ASM68K} or the @code{ASM960} (depending upon the +configured target) assembler from Microtec Research. The exact nature of the +MRI syntax will not be documented here; see the MRI manuals for more +information. Note in particular that the handling of macros and macro +arguments is somewhat different. The purpose of this option is to permit +assembling existing MRI assembler code using @code{@value{AS}}. + +The MRI compatibility is not complete. Certain operations of the MRI assembler +depend upon its object file format, and can not be supported using other object +file formats. Supporting these would require enhancing each object file format +individually. These are: + +@itemize @bullet +@item global symbols in common section + +The m68k MRI assembler supports common sections which are merged by the linker. +Other object file formats do not support this. @code{@value{AS}} handles +common sections by treating them as a single common symbol. It permits local +symbols to be defined within a common section, but it can not support global +symbols, since it has no way to describe them. + +@item complex relocations + +The MRI assemblers support relocations against a negated section address, and +relocations which combine the start addresses of two or more sections. These +are not support by other object file formats. + +@item @code{END} pseudo-op specifying start address + +The MRI @code{END} pseudo-op permits the specification of a start address. +This is not supported by other object file formats. The start address may +instead be specified using the @code{-e} option to the linker, or in a linker +script. + +@item @code{IDNT}, @code{.ident} and @code{NAME} pseudo-ops + +The MRI @code{IDNT}, @code{.ident} and @code{NAME} pseudo-ops assign a module +name to the output file. This is not supported by other object file formats. + +@item @code{ORG} pseudo-op + +The m68k MRI @code{ORG} pseudo-op begins an absolute section at a given +address. This differs from the usual @code{@value{AS}} @code{.org} pseudo-op, +which changes the location within the current section. Absolute sections are +not supported by other object file formats. The address of a section may be +assigned within a linker script. +@end itemize + +There are some other features of the MRI assembler which are not supported by +@code{@value{AS}}, typically either because they are difficult or because they +seem of little consequence. Some of these may be supported in future releases. + +@itemize @bullet + +@item EBCDIC strings + +EBCDIC strings are not supported. + +@item packed binary coded decimal + +Packed binary coded decimal is not supported. This means that the @code{DC.P} +and @code{DCB.P} pseudo-ops are not supported. + +@item @code{FEQU} pseudo-op + +The m68k @code{FEQU} pseudo-op is not supported. + +@item @code{NOOBJ} pseudo-op + +The m68k @code{NOOBJ} pseudo-op is not supported. + +@item @code{OPT} branch control options + +The m68k @code{OPT} branch control options---@code{B}, @code{BRS}, @code{BRB}, +@code{BRL}, and @code{BRW}---are ignored. @code{@value{AS}} automatically +relaxes all branches, whether forward or backward, to an appropriate size, so +these options serve no purpose. + +@item @code{OPT} list control options + +The following m68k @code{OPT} list control options are ignored: @code{C}, +@code{CEX}, @code{CL}, @code{CRE}, @code{E}, @code{G}, @code{I}, @code{M}, +@code{MEX}, @code{MC}, @code{MD}, @code{X}. + +@item other @code{OPT} options + +The following m68k @code{OPT} options are ignored: @code{NEST}, @code{O}, +@code{OLD}, @code{OP}, @code{P}, @code{PCO}, @code{PCR}, @code{PCS}, @code{R}. + +@item @code{OPT} @code{D} option is default + +The m68k @code{OPT} @code{D} option is the default, unlike the MRI assembler. +@code{OPT NOD} may be used to turn it off. + +@item @code{XREF} pseudo-op. + +The m68k @code{XREF} pseudo-op is ignored. + +@item @code{.debug} pseudo-op + +The i960 @code{.debug} pseudo-op is not supported. + +@item @code{.extended} pseudo-op + +The i960 @code{.extended} pseudo-op is not supported. + +@item @code{.list} pseudo-op. + +The various options of the i960 @code{.list} pseudo-op are not supported. + +@item @code{.optimize} pseudo-op + +The i960 @code{.optimize} pseudo-op is not supported. + +@item @code{.output} pseudo-op + +The i960 @code{.output} pseudo-op is not supported. + +@item @code{.setreal} pseudo-op + +The i960 @code{.setreal} pseudo-op is not supported. + +@end itemize + +@node o +@section Name the Object File: @code{-o} + +@kindex -o +@cindex naming object file +@cindex object file name +There is always one object file output when you run @code{@value{AS}}. By +default it has the name +@ifset GENERIC +@ifset I960 +@file{a.out} (or @file{b.out}, for Intel 960 targets only). +@end ifset +@ifclear I960 +@file{a.out}. +@end ifclear +@end ifset +@ifclear GENERIC +@ifset I960 +@file{b.out}. +@end ifset +@ifclear I960 +@file{a.out}. +@end ifclear +@end ifclear +You use this option (which takes exactly one filename) to give the +object file a different name. + +Whatever the object file is called, @code{@value{AS}} overwrites any +existing file of the same name. + +@node R +@section Join Data and Text Sections: @code{-R} + +@kindex -R +@cindex data and text sections, joining +@cindex text and data sections, joining +@cindex joining text and data sections +@cindex merging text and data sections +@code{-R} tells @code{@value{AS}} to write the object file as if all +data-section data lives in the text section. This is only done at +the very last moment: your binary data are the same, but data +section parts are relocated differently. The data section part of +your object file is zero bytes long because all its bytes are +appended to the text section. (@xref{Sections,,Sections and Relocation}.) + +When you specify @code{-R} it would be possible to generate shorter +address displacements (because we do not have to cross between text and +data section). We refrain from doing this simply for compatibility with +older versions of @code{@value{AS}}. In future, @code{-R} may work this way. + +@ifset COFF +When @code{@value{AS}} is configured for COFF output, +this option is only useful if you use sections named @samp{.text} and +@samp{.data}. +@end ifset + +@ifset HPPA +@code{-R} is not supported for any of the HPPA targets. Using +@code{-R} generates a warning from @code{@value{AS}}. +@end ifset + +@node statistics +@section Display Assembly Statistics: @code{--statistics} + +@kindex --statistics +@cindex statistics, about assembly +@cindex time, total for assembly +@cindex space used, maximum for assembly +Use @samp{--statistics} to display two statistics about the resources used by +@code{@value{AS}}: the maximum amount of space allocated during the assembly +(in bytes), and the total execution time taken for the assembly (in @sc{cpu} +seconds). + +@node v +@section Announce Version: @code{-v} + +@kindex -v +@kindex -version +@cindex assembler version +@cindex version of assembler +You can find out what version of as is running by including the +option @samp{-v} (which you can also spell as @samp{-version}) on the +command line. + +@node W +@section Suppress Warnings: @code{-W} + +@kindex -W +@cindex suppressing warnings +@cindex warnings, suppressing +@code{@value{AS}} should never give a warning or error message when +assembling compiler output. But programs written by people often +cause @code{@value{AS}} to give a warning that a particular assumption was +made. All such warnings are directed to the standard error file. +If you use this option, no warnings are issued. This option only +affects the warning messages: it does not change any particular of how +@code{@value{AS}} assembles your file. Errors, which stop the assembly, are +still reported. + +@node Z +@section Generate Object File in Spite of Errors: @code{-Z} +@cindex object file, after errors +@cindex errors, continuing after +After an error message, @code{@value{AS}} normally produces no output. If for +some reason you are interested in object file output even after +@code{@value{AS}} gives an error message on your program, use the @samp{-Z} +option. If there are any errors, @code{@value{AS}} continues anyways, and +writes an object file after a final warning message of the form @samp{@var{n} +errors, @var{m} warnings, generating bad object file.} + +@node Syntax +@chapter Syntax + +@cindex machine-independent syntax +@cindex syntax, machine-independent +This chapter describes the machine-independent syntax allowed in a +source file. @code{@value{AS}} syntax is similar to what many other +assemblers use; it is inspired by the BSD 4.2 +@ifclear VAX +assembler. +@end ifclear +@ifset VAX +assembler, except that @code{@value{AS}} does not assemble Vax bit-fields. +@end ifset + +@menu +* Preprocessing:: Preprocessing +* Whitespace:: Whitespace +* Comments:: Comments +* Symbol Intro:: Symbols +* Statements:: Statements +* Constants:: Constants +@end menu + +@node Preprocessing +@section Preprocessing + +@cindex preprocessing +The @code{@value{AS}} internal preprocessor: +@itemize @bullet +@cindex whitespace, removed by preprocessor +@item +adjusts and removes extra whitespace. It leaves one space or tab before +the keywords on a line, and turns any other whitespace on the line into +a single space. + +@cindex comments, removed by preprocessor +@item +removes all comments, replacing them with a single space, or an +appropriate number of newlines. + +@cindex constants, converted by preprocessor +@item +converts character constants into the appropriate numeric values. +@end itemize + +It does not do macro processing, include file handling, or +anything else you may get from your C compiler's preprocessor. You can +do include file processing with the @code{.include} directive +(@pxref{Include,,@code{.include}}). You can use the @sc{gnu} C compiler driver +to get other ``CPP'' style preprocessing, by giving the input file a +@samp{.S} suffix. @xref{Overall Options,, Options Controlling the Kind of +Output, gcc.info, Using GNU CC}. + +Excess whitespace, comments, and character constants +cannot be used in the portions of the input text that are not +preprocessed. + +@cindex turning preprocessing on and off +@cindex preprocessing, turning on and off +@kindex #NO_APP +@kindex #APP +If the first line of an input file is @code{#NO_APP} or if you use the +@samp{-f} option, whitespace and comments are not removed from the input file. +Within an input file, you can ask for whitespace and comment removal in +specific portions of the by putting a line that says @code{#APP} before the +text that may contain whitespace or comments, and putting a line that says +@code{#NO_APP} after this text. This feature is mainly intend to support +@code{asm} statements in compilers whose output is otherwise free of comments +and whitespace. + +@node Whitespace +@section Whitespace + +@cindex whitespace +@dfn{Whitespace} is one or more blanks or tabs, in any order. +Whitespace is used to separate symbols, and to make programs neater for +people to read. Unless within character constants +(@pxref{Characters,,Character Constants}), any whitespace means the same +as exactly one space. + +@node Comments +@section Comments + +@cindex comments +There are two ways of rendering comments to @code{@value{AS}}. In both +cases the comment is equivalent to one space. + +Anything from @samp{/*} through the next @samp{*/} is a comment. +This means you may not nest these comments. + +@smallexample +/* + The only way to include a newline ('\n') in a comment + is to use this sort of comment. +*/ + +/* This sort of comment does not nest. */ +@end smallexample + +@cindex line comment character +Anything from the @dfn{line comment} character to the next newline +is considered a comment and is ignored. The line comment character is +@ifset A29K +@samp{;} for the AMD 29K family; +@end ifset +@ifset H8/300 +@samp{;} for the H8/300 family; +@end ifset +@ifset H8/500 +@samp{!} for the H8/500 family; +@end ifset +@ifset HPPA +@samp{;} for the HPPA; +@end ifset +@ifset I960 +@samp{#} on the i960; +@end ifset +@ifset SH +@samp{!} for the Hitachi SH; +@end ifset +@ifset SPARC +@samp{!} on the SPARC; +@end ifset +@ifset M680X0 +@samp{|} on the 680x0; +@end ifset +@ifset VAX +@samp{#} on the Vax; +@end ifset +@ifset Z8000 +@samp{!} for the Z8000; +@end ifset +see @ref{Machine Dependencies}. @refill +@c FIXME What about i386, m88k, i860? + +@ifset GENERIC +On some machines there are two different line comment characters. One +character only begins a comment if it is the first non-whitespace character on +a line, while the other always begins a comment. +@end ifset + +@kindex # +@cindex lines starting with @code{#} +@cindex logical line numbers +To be compatible with past assemblers, lines that begin with @samp{#} have a +special interpretation. Following the @samp{#} should be an absolute +expression (@pxref{Expressions}): the logical line number of the @emph{next} +line. Then a string (@pxref{Strings,, Strings}) is allowed: if present it is a +new logical file name. The rest of the line, if any, should be whitespace. + +If the first non-whitespace characters on the line are not numeric, +the line is ignored. (Just like a comment.) + +@smallexample + # This is an ordinary comment. +# 42-6 "new_file_name" # New logical file name + # This is logical line # 36. +@end smallexample +This feature is deprecated, and may disappear from future versions +of @code{@value{AS}}. + +@node Symbol Intro +@section Symbols + +@cindex characters used in symbols +@ifclear SPECIAL-SYMS +A @dfn{symbol} is one or more characters chosen from the set of all +letters (both upper and lower case), digits and the three characters +@samp{_.$}. +@end ifclear +@ifset SPECIAL-SYMS +@ifclear GENERIC +@ifset H8 +A @dfn{symbol} is one or more characters chosen from the set of all +letters (both upper and lower case), digits and the three characters +@samp{._$}. (Save that, on the H8/300 only, you may not use @samp{$} in +symbol names.) +@end ifset +@end ifclear +@end ifset +@ifset GENERIC +On most machines, you can also use @code{$} in symbol names; exceptions +are noted in @ref{Machine Dependencies}. +@end ifset +No symbol may begin with a digit. Case is significant. +There is no length limit: all characters are significant. Symbols are +delimited by characters not in that set, or by the beginning of a file +(since the source program must end with a newline, the end of a file is +not a possible symbol delimiter). @xref{Symbols}. +@cindex length of symbols + +@node Statements +@section Statements + +@cindex statements, structure of +@cindex line separator character +@cindex statement separator character +@ifclear GENERIC +@ifclear abnormal-separator +A @dfn{statement} ends at a newline character (@samp{\n}) or at a +semicolon (@samp{;}). The newline or semicolon is considered part of +the preceding statement. Newlines and semicolons within character +constants are an exception: they do not end statements. +@end ifclear +@ifset abnormal-separator +@ifset A29K +A @dfn{statement} ends at a newline character (@samp{\n}) or an ``at'' +sign (@samp{@@}). The newline or at sign is considered part of the +preceding statement. Newlines and at signs within character constants +are an exception: they do not end statements. +@end ifset +@ifset HPPA +A @dfn{statement} ends at a newline character (@samp{\n}) or an exclamation +point (@samp{!}). The newline or exclamation point is considered part of the +preceding statement. Newlines and exclamation points within character +constants are an exception: they do not end statements. +@end ifset +@ifset H8 +A @dfn{statement} ends at a newline character (@samp{\n}); or (for the +H8/300) a dollar sign (@samp{$}); or (for the +Hitachi-SH or the +H8/500) a semicolon +(@samp{;}). The newline or separator character is considered part of +the preceding statement. Newlines and separators within character +constants are an exception: they do not end statements. +@end ifset +@end ifset +@end ifclear +@ifset GENERIC +A @dfn{statement} ends at a newline character (@samp{\n}) or line +separator character. (The line separator is usually @samp{;}, unless +this conflicts with the comment character; @pxref{Machine Dependencies}.) The +newline or separator character is considered part of the preceding +statement. Newlines and separators within character constants are an +exception: they do not end statements. +@end ifset + +@cindex newline, required at file end +@cindex EOF, newline must precede +It is an error to end any statement with end-of-file: the last +character of any input file should be a newline.@refill + +@cindex continuing statements +@cindex multi-line statements +@cindex statement on multiple lines +You may write a statement on more than one line if you put a +backslash (@kbd{\}) immediately in front of any newlines within the +statement. When @code{@value{AS}} reads a backslashed newline both +characters are ignored. You can even put backslashed newlines in +the middle of symbol names without changing the meaning of your +source program. + +An empty statement is allowed, and may include whitespace. It is ignored. + +@cindex instructions and directives +@cindex directives and instructions +@c "key symbol" is not used elsewhere in the document; seems pedantic to +@c @defn{} it in that case, as was done previously... doc@cygnus.com, +@c 13feb91. +A statement begins with zero or more labels, optionally followed by a +key symbol which determines what kind of statement it is. The key +symbol determines the syntax of the rest of the statement. If the +symbol begins with a dot @samp{.} then the statement is an assembler +directive: typically valid for any computer. If the symbol begins with +a letter the statement is an assembly language @dfn{instruction}: it +assembles into a machine language instruction. +@ifset GENERIC +Different versions of @code{@value{AS}} for different computers +recognize different instructions. In fact, the same symbol may +represent a different instruction in a different computer's assembly +language.@refill +@end ifset + +@cindex @code{:} (label) +@cindex label (@code{:}) +A label is a symbol immediately followed by a colon (@code{:}). +Whitespace before a label or after a colon is permitted, but you may not +have whitespace between a label's symbol and its colon. @xref{Labels}. + +@ifset HPPA +For HPPA targets, labels need not be immediately followed by a colon, but +the definition of a label must begin in column zero. This also implies that +only one label may be defined on each line. +@end ifset + +@smallexample +label: .directive followed by something +another_label: # This is an empty statement. + instruction operand_1, operand_2, @dots{} +@end smallexample + +@node Constants +@section Constants + +@cindex constants +A constant is a number, written so that its value is known by +inspection, without knowing any context. Like this: +@smallexample +@group +.byte 74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value. +.ascii "Ring the bell\7" # A string constant. +.octa 0x123456789abcdef0123456789ABCDEF0 # A bignum. +.float 0f-314159265358979323846264338327\ +95028841971.693993751E-40 # - pi, a flonum. +@end group +@end smallexample + +@menu +* Characters:: Character Constants +* Numbers:: Number Constants +@end menu + +@node Characters +@subsection Character Constants + +@cindex character constants +@cindex constants, character +There are two kinds of character constants. A @dfn{character} stands +for one character in one byte and its value may be used in +numeric expressions. String constants (properly called string +@emph{literals}) are potentially many bytes and their values may not be +used in arithmetic expressions. + +@menu +* Strings:: Strings +* Chars:: Characters +@end menu + +@node Strings +@subsubsection Strings + +@cindex string constants +@cindex constants, string +A @dfn{string} is written between double-quotes. It may contain +double-quotes or null characters. The way to get special characters +into a string is to @dfn{escape} these characters: precede them with +a backslash @samp{\} character. For example @samp{\\} represents +one backslash: the first @code{\} is an escape which tells +@code{@value{AS}} to interpret the second character literally as a backslash +(which prevents @code{@value{AS}} from recognizing the second @code{\} as an +escape character). The complete list of escapes follows. + +@cindex escape codes, character +@cindex character escape codes +@table @kbd +@c @item \a +@c Mnemonic for ACKnowledge; for ASCII this is octal code 007. +@c +@cindex @code{\b} (backspace character) +@cindex backspace (@code{\b}) +@item \b +Mnemonic for backspace; for ASCII this is octal code 010. + +@c @item \e +@c Mnemonic for EOText; for ASCII this is octal code 004. +@c +@cindex @code{\f} (formfeed character) +@cindex formfeed (@code{\f}) +@item \f +Mnemonic for FormFeed; for ASCII this is octal code 014. + +@cindex @code{\n} (newline character) +@cindex newline (@code{\n}) +@item \n +Mnemonic for newline; for ASCII this is octal code 012. + +@c @item \p +@c Mnemonic for prefix; for ASCII this is octal code 033, usually known as @code{escape}. +@c +@cindex @code{\r} (carriage return character) +@cindex carriage return (@code{\r}) +@item \r +Mnemonic for carriage-Return; for ASCII this is octal code 015. + +@c @item \s +@c Mnemonic for space; for ASCII this is octal code 040. Included for compliance with +@c other assemblers. +@c +@cindex @code{\t} (tab) +@cindex tab (@code{\t}) +@item \t +Mnemonic for horizontal Tab; for ASCII this is octal code 011. + +@c @item \v +@c Mnemonic for Vertical tab; for ASCII this is octal code 013. +@c @item \x @var{digit} @var{digit} @var{digit} +@c A hexadecimal character code. The numeric code is 3 hexadecimal digits. +@c +@cindex @code{\@var{ddd}} (octal character code) +@cindex octal character code (@code{\@var{ddd}}) +@item \ @var{digit} @var{digit} @var{digit} +An octal character code. The numeric code is 3 octal digits. +For compatibility with other Unix systems, 8 and 9 are accepted as digits: +for example, @code{\008} has the value 010, and @code{\009} the value 011. + +@cindex @code{\@var{xd...}} (hex character code) +@cindex hex character code (@code{\@var{xd...}}) +@item \@code{x} @var{hex-digits...} +A hex character code. All trailing hex digits are combined. Either upper or +lower case @code{x} works. + +@cindex @code{\\} (@samp{\} character) +@cindex backslash (@code{\\}) +@item \\ +Represents one @samp{\} character. + +@c @item \' +@c Represents one @samp{'} (accent acute) character. +@c This is needed in single character literals +@c (@xref{Characters,,Character Constants}.) to represent +@c a @samp{'}. +@c +@cindex @code{\"} (doublequote character) +@cindex doublequote (@code{\"}) +@item \" +Represents one @samp{"} character. Needed in strings to represent +this character, because an unescaped @samp{"} would end the string. + +@item \ @var{anything-else} +Any other character when escaped by @kbd{\} gives a warning, but +assembles as if the @samp{\} was not present. The idea is that if +you used an escape sequence you clearly didn't want the literal +interpretation of the following character. However @code{@value{AS}} has no +other interpretation, so @code{@value{AS}} knows it is giving you the wrong +code and warns you of the fact. +@end table + +Which characters are escapable, and what those escapes represent, +varies widely among assemblers. The current set is what we think +the BSD 4.2 assembler recognizes, and is a subset of what most C +compilers recognize. If you are in doubt, do not use an escape +sequence. + +@node Chars +@subsubsection Characters + +@cindex single character constant +@cindex character, single +@cindex constant, single character +A single character may be written as a single quote immediately +followed by that character. The same escapes apply to characters as +to strings. So if you want to write the character backslash, you +must write @kbd{'\\} where the first @code{\} escapes the second +@code{\}. As you can see, the quote is an acute accent, not a +grave accent. A newline +@ifclear GENERIC +@ifclear abnormal-separator +(or semicolon @samp{;}) +@end ifclear +@ifset abnormal-separator +@ifset A29K +(or at sign @samp{@@}) +@end ifset +@ifset H8 +(or dollar sign @samp{$}, for the H8/300; or semicolon @samp{;} for the +Hitachi SH or +H8/500) +@end ifset +@end ifset +@end ifclear +immediately following an acute accent is taken as a literal character +and does not count as the end of a statement. The value of a character +constant in a numeric expression is the machine's byte-wide code for +that character. @code{@value{AS}} assumes your character code is ASCII: +@kbd{'A} means 65, @kbd{'B} means 66, and so on. @refill + +@node Numbers +@subsection Number Constants + +@cindex constants, number +@cindex number constants +@code{@value{AS}} distinguishes three kinds of numbers according to how they +are stored in the target machine. @emph{Integers} are numbers that +would fit into an @code{int} in the C language. @emph{Bignums} are +integers, but they are stored in more than 32 bits. @emph{Flonums} +are floating point numbers, described below. + +@menu +* Integers:: Integers +* Bignums:: Bignums +* Flonums:: Flonums +@ifclear GENERIC +@ifset I960 +* Bit Fields:: Bit Fields +@end ifset +@end ifclear +@end menu + +@node Integers +@subsubsection Integers +@cindex integers +@cindex constants, integer + +@cindex binary integers +@cindex integers, binary +A binary integer is @samp{0b} or @samp{0B} followed by zero or more of +the binary digits @samp{01}. + +@cindex octal integers +@cindex integers, octal +An octal integer is @samp{0} followed by zero or more of the octal +digits (@samp{01234567}). + +@cindex decimal integers +@cindex integers, decimal +A decimal integer starts with a non-zero digit followed by zero or +more digits (@samp{0123456789}). + +@cindex hexadecimal integers +@cindex integers, hexadecimal +A hexadecimal integer is @samp{0x} or @samp{0X} followed by one or +more hexadecimal digits chosen from @samp{0123456789abcdefABCDEF}. + +Integers have the usual values. To denote a negative integer, use +the prefix operator @samp{-} discussed under expressions +(@pxref{Prefix Ops,,Prefix Operators}). + +@node Bignums +@subsubsection Bignums + +@cindex bignums +@cindex constants, bignum +A @dfn{bignum} has the same syntax and semantics as an integer +except that the number (or its negative) takes more than 32 bits to +represent in binary. The distinction is made because in some places +integers are permitted while bignums are not. + +@node Flonums +@subsubsection Flonums +@cindex flonums +@cindex floating point numbers +@cindex constants, floating point + +@cindex precision, floating point +A @dfn{flonum} represents a floating point number. The translation is +indirect: a decimal floating point number from the text is converted by +@code{@value{AS}} to a generic binary floating point number of more than +sufficient precision. This generic floating point number is converted +to a particular computer's floating point format (or formats) by a +portion of @code{@value{AS}} specialized to that computer. + +A flonum is written by writing (in order) +@itemize @bullet +@item +The digit @samp{0}. +@ifset HPPA +(@samp{0} is optional on the HPPA.) +@end ifset + +@item +A letter, to tell @code{@value{AS}} the rest of the number is a flonum. +@ifset GENERIC +@kbd{e} is recommended. Case is not important. +@ignore +@c FIXME: verify if flonum syntax really this vague for most cases +(Any otherwise illegal letter works here, but that might be changed. Vax BSD +4.2 assembler seems to allow any of @samp{defghDEFGH}.) +@end ignore + +On the H8/300, H8/500, +Hitachi SH, +and AMD 29K architectures, the letter must be +one of the letters @samp{DFPRSX} (in upper or lower case). + + +On the Intel 960 architecture, the letter must be +one of the letters @samp{DFT} (in upper or lower case). + +On the HPPA architecture, the letter must be @samp{E} (upper case only). +@end ifset +@ifclear GENERIC +@ifset A29K +One of the letters @samp{DFPRSX} (in upper or lower case). +@end ifset +@ifset H8 +One of the letters @samp{DFPRSX} (in upper or lower case). +@end ifset +@ifset HPPA +The letter @samp{E} (upper case only). +@end ifset +@ifset I960 +One of the letters @samp{DFT} (in upper or lower case). +@end ifset +@end ifclear + +@item +An optional sign: either @samp{+} or @samp{-}. + +@item +An optional @dfn{integer part}: zero or more decimal digits. + +@item +An optional @dfn{fractional part}: @samp{.} followed by zero +or more decimal digits. + +@item +An optional exponent, consisting of: + +@itemize @bullet +@item +An @samp{E} or @samp{e}. +@c I can't find a config where "EXP_CHARS" is other than 'eE', but in +@c principle this can perfectly well be different on different targets. +@item +Optional sign: either @samp{+} or @samp{-}. +@item +One or more decimal digits. +@end itemize + +@end itemize + +At least one of the integer part or the fractional part must be +present. The floating point number has the usual base-10 value. + +@code{@value{AS}} does all processing using integers. Flonums are computed +independently of any floating point hardware in the computer running +@code{@value{AS}}. + +@ifclear GENERIC +@ifset I960 +@c Bit fields are written as a general facility but are also controlled +@c by a conditional-compilation flag---which is as of now (21mar91) +@c turned on only by the i960 config of GAS. +@node Bit Fields +@subsubsection Bit Fields + +@cindex bit fields +@cindex constants, bit field +You can also define numeric constants as @dfn{bit fields}. +specify two numbers separated by a colon--- +@example +@var{mask}:@var{value} +@end example +@noindent +@code{@value{AS}} applies a bitwise @sc{and} between @var{mask} and +@var{value}. + +The resulting number is then packed +@ifset GENERIC +@c this conditional paren in case bit fields turned on elsewhere than 960 +(in host-dependent byte order) +@end ifset +into a field whose width depends on which assembler directive has the +bit-field as its argument. Overflow (a result from the bitwise and +requiring more binary digits to represent) is not an error; instead, +more constants are generated, of the specified width, beginning with the +least significant digits.@refill + +The directives @code{.byte}, @code{.hword}, @code{.int}, @code{.long}, +@code{.short}, and @code{.word} accept bit-field arguments. +@end ifset +@end ifclear + +@node Sections +@chapter Sections and Relocation +@cindex sections +@cindex relocation + +@menu +* Secs Background:: Background +* Ld Sections:: Linker Sections +* As Sections:: Assembler Internal Sections +* Sub-Sections:: Sub-Sections +* bss:: bss Section +@end menu + +@node Secs Background +@section Background + +Roughly, a section is a range of addresses, with no gaps; all data +``in'' those addresses is treated the same for some particular purpose. +For example there may be a ``read only'' section. + +@cindex linker, and assembler +@cindex assembler, and linker +The linker @code{@value{LD}} reads many object files (partial programs) and +combines their contents to form a runnable program. When @code{@value{AS}} +emits an object file, the partial program is assumed to start at address 0. +@code{@value{LD}} assigns the final addresses for the partial program, so that +different partial programs do not overlap. This is actually an +oversimplification, but it suffices to explain how @code{@value{AS}} uses +sections. + +@code{@value{LD}} moves blocks of bytes of your program to their run-time +addresses. These blocks slide to their run-time addresses as rigid +units; their length does not change and neither does the order of bytes +within them. Such a rigid unit is called a @emph{section}. Assigning +run-time addresses to sections is called @dfn{relocation}. It includes +the task of adjusting mentions of object-file addresses so they refer to +the proper run-time addresses. +@ifset H8 +For the H8/300 and H8/500, +and for the Hitachi SH, +@code{@value{AS}} pads sections if needed to +ensure they end on a word (sixteen bit) boundary. +@end ifset + +@cindex standard assembler sections +An object file written by @code{@value{AS}} has at least three sections, any +of which may be empty. These are named @dfn{text}, @dfn{data} and +@dfn{bss} sections. + +@ifset COFF +@ifset GENERIC +When it generates COFF output, +@end ifset +@code{@value{AS}} can also generate whatever other named sections you specify +using the @samp{.section} directive (@pxref{Section,,@code{.section}}). +If you do not use any directives that place output in the @samp{.text} +or @samp{.data} sections, these sections still exist, but are empty. +@end ifset + +@ifset HPPA +@ifset GENERIC +When @code{@value{AS}} generates SOM or ELF output for the HPPA, +@end ifset +@code{@value{AS}} can also generate whatever other named sections you +specify using the @samp{.space} and @samp{.subspace} directives. See +@cite{HP9000 Series 800 Assembly Language Reference Manual} +(HP 92432-90001) for details on the @samp{.space} and @samp{.subspace} +assembler directives. + +@ifset SOM +Additionally, @code{@value{AS}} uses different names for the standard +text, data, and bss sections when generating SOM output. Program text +is placed into the @samp{$CODE$} section, data into @samp{$DATA$}, and +BSS into @samp{$BSS$}. +@end ifset +@end ifset + +Within the object file, the text section starts at address @code{0}, the +data section follows, and the bss section follows the data section. + +@ifset HPPA +When generating either SOM or ELF output files on the HPPA, the text +section starts at address @code{0}, the data section at address +@code{0x4000000}, and the bss section follows the data section. +@end ifset + +To let @code{@value{LD}} know which data changes when the sections are +relocated, and how to change that data, @code{@value{AS}} also writes to the +object file details of the relocation needed. To perform relocation +@code{@value{LD}} must know, each time an address in the object +file is mentioned: +@itemize @bullet +@item +Where in the object file is the beginning of this reference to +an address? +@item +How long (in bytes) is this reference? +@item +Which section does the address refer to? What is the numeric value of +@display +(@var{address}) @minus{} (@var{start-address of section})? +@end display +@item +Is the reference to an address ``Program-Counter relative''? +@end itemize + +@cindex addresses, format of +@cindex section-relative addressing +In fact, every address @code{@value{AS}} ever uses is expressed as +@display +(@var{section}) + (@var{offset into section}) +@end display +@noindent +Further, most expressions @code{@value{AS}} computes have this section-relative +nature. +@ifset SOM +(For some object formats, such as SOM for the HPPA, some expressions are +symbol-relative instead.) +@end ifset + +In this manual we use the notation @{@var{secname} @var{N}@} to mean ``offset +@var{N} into section @var{secname}.'' + +Apart from text, data and bss sections you need to know about the +@dfn{absolute} section. When @code{@value{LD}} mixes partial programs, +addresses in the absolute section remain unchanged. For example, address +@code{@{absolute 0@}} is ``relocated'' to run-time address 0 by +@code{@value{LD}}. Although the linker never arranges two partial programs' +data sections with overlapping addresses after linking, @emph{by definition} +their absolute sections must overlap. Address @code{@{absolute@ 239@}} in one +part of a program is always the same address when the program is running as +address @code{@{absolute@ 239@}} in any other part of the program. + +The idea of sections is extended to the @dfn{undefined} section. Any +address whose section is unknown at assembly time is by definition +rendered @{undefined @var{U}@}---where @var{U} is filled in later. +Since numbers are always defined, the only way to generate an undefined +address is to mention an undefined symbol. A reference to a named +common block would be such a symbol: its value is unknown at assembly +time so it has section @emph{undefined}. + +By analogy the word @emph{section} is used to describe groups of sections in +the linked program. @code{@value{LD}} puts all partial programs' text +sections in contiguous addresses in the linked program. It is +customary to refer to the @emph{text section} of a program, meaning all +the addresses of all partial programs' text sections. Likewise for +data and bss sections. + +Some sections are manipulated by @code{@value{LD}}; others are invented for +use of @code{@value{AS}} and have no meaning except during assembly. + +@node Ld Sections +@section Linker Sections +@code{@value{LD}} deals with just four kinds of sections, summarized below. + +@table @strong + +@ifset COFF +@cindex named sections +@cindex sections, named +@item named sections +@end ifset +@ifset aout-bout +@cindex text section +@cindex data section +@itemx text section +@itemx data section +@end ifset +These sections hold your program. @code{@value{AS}} and @code{@value{LD}} treat them as +separate but equal sections. Anything you can say of one section is +true another. +@ifset aout-bout +When the program is running, however, it is +customary for the text section to be unalterable. The +text section is often shared among processes: it contains +instructions, constants and the like. The data section of a running +program is usually alterable: for example, C variables would be stored +in the data section. +@end ifset + +@cindex bss section +@item bss section +This section contains zeroed bytes when your program begins running. It +is used to hold unitialized variables or common storage. The length of +each partial program's bss section is important, but because it starts +out containing zeroed bytes there is no need to store explicit zero +bytes in the object file. The bss section was invented to eliminate +those explicit zeros from object files. + +@cindex absolute section +@item absolute section +Address 0 of this section is always ``relocated'' to runtime address 0. +This is useful if you want to refer to an address that @code{@value{LD}} must +not change when relocating. In this sense we speak of absolute +addresses being ``unrelocatable'': they do not change during relocation. + +@cindex undefined section +@item undefined section +This ``section'' is a catch-all for address references to objects not in +the preceding sections. +@c FIXME: ref to some other doc on obj-file formats could go here. +@end table + +@cindex relocation example +An idealized example of three relocatable sections follows. +@ifset COFF +The example uses the traditional section names @samp{.text} and @samp{.data}. +@end ifset +Memory addresses are on the horizontal axis. + +@c TEXI2ROFF-KILL +@ifinfo +@c END TEXI2ROFF-KILL +@smallexample + +-----+----+--+ +partial program # 1: |ttttt|dddd|00| + +-----+----+--+ + + text data bss + seg. seg. seg. + + +---+---+---+ +partial program # 2: |TTT|DDD|000| + +---+---+---+ + + +--+---+-----+--+----+---+-----+~~ +linked program: | |TTT|ttttt| |dddd|DDD|00000| + +--+---+-----+--+----+---+-----+~~ + + addresses: 0 @dots{} +@end smallexample +@c TEXI2ROFF-KILL +@end ifinfo +@need 5000 +@tex + +\line{\it Partial program \#1: \hfil} +\line{\ibox{2.5cm}{\tt text}\ibox{2cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{2.5cm}{\tt ttttt}\boxit{2cm}{\tt dddd}\boxit{1cm}{\tt 00}\hfil} + +\line{\it Partial program \#2: \hfil} +\line{\ibox{1cm}{\tt text}\ibox{1.5cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{1cm}{\tt TTT}\boxit{1.5cm}{\tt DDDD}\boxit{1cm}{\tt 000}\hfil} + +\line{\it linked program: \hfil} +\line{\ibox{.5cm}{}\ibox{1cm}{\tt text}\ibox{2.5cm}{}\ibox{.75cm}{}\ibox{2cm}{\tt data}\ibox{1.5cm}{}\ibox{2cm}{\tt bss}\hfil} +\line{\boxit{.5cm}{}\boxit{1cm}{\tt TTT}\boxit{2.5cm}{\tt +ttttt}\boxit{.75cm}{}\boxit{2cm}{\tt dddd}\boxit{1.5cm}{\tt +DDDD}\boxit{2cm}{\tt 00000}\ \dots\hfil} + +\line{\it addresses: \hfil} +\line{0\dots\hfil} + +@end tex +@c END TEXI2ROFF-KILL + +@node As Sections +@section Assembler Internal Sections + +@cindex internal assembler sections +@cindex sections in messages, internal +These sections are meant only for the internal use of @code{@value{AS}}. They +have no meaning at run-time. You do not really need to know about these +sections for most purposes; but they can be mentioned in @code{@value{AS}} +warning messages, so it might be helpful to have an idea of their +meanings to @code{@value{AS}}. These sections are used to permit the +value of every expression in your assembly language program to be a +section-relative address. + +@table @b +@cindex assembler internal logic error +@item ASSEMBLER-INTERNAL-LOGIC-ERROR! +An internal assembler logic error has been found. This means there is a +bug in the assembler. + +@cindex expr (internal section) +@item expr section +The assembler stores complex expression internally as combinations of +symbols. When it needs to represent an expression as a symbol, it puts +it in the expr section. +@c FIXME item debug +@c FIXME item transfer[t] vector preload +@c FIXME item transfer[t] vector postload +@c FIXME item register +@end table + +@node Sub-Sections +@section Sub-Sections + +@cindex numbered subsections +@cindex grouping data +@ifset aout-bout +Assembled bytes +@ifset COFF +conventionally +@end ifset +fall into two sections: text and data. +@end ifset +You may have separate groups of +@ifset GENERIC +data in named sections +@end ifset +@ifclear GENERIC +@ifclear aout-bout +data in named sections +@end ifclear +@ifset aout-bout +text or data +@end ifset +@end ifclear +that you want to end up near to each other in the object file, even though they +are not contiguous in the assembler source. @code{@value{AS}} allows you to +use @dfn{subsections} for this purpose. Within each section, there can be +numbered subsections with values from 0 to 8192. Objects assembled into the +same subsection go into the object file together with other objects in the same +subsection. For example, a compiler might want to store constants in the text +section, but might not want to have them interspersed with the program being +assembled. In this case, the compiler could issue a @samp{.text 0} before each +section of code being output, and a @samp{.text 1} before each group of +constants being output. + +Subsections are optional. If you do not use subsections, everything +goes in subsection number zero. + +@ifset GENERIC +Each subsection is zero-padded up to a multiple of four bytes. +(Subsections may be padded a different amount on different flavors +of @code{@value{AS}}.) +@end ifset +@ifclear GENERIC +@ifset H8 +On the H8/300 and H8/500 platforms, each subsection is zero-padded to a word +boundary (two bytes). +The same is true on the Hitachi SH. +@end ifset +@ifset I960 +@c FIXME section padding (alignment)? +@c Rich Pixley says padding here depends on target obj code format; that +@c doesn't seem particularly useful to say without further elaboration, +@c so for now I say nothing about it. If this is a generic BFD issue, +@c these paragraphs might need to vanish from this manual, and be +@c discussed in BFD chapter of binutils (or some such). +@end ifset +@ifset A29K +On the AMD 29K family, no particular padding is added to section or +subsection sizes; @value{AS} forces no alignment on this platform. +@end ifset +@end ifclear + +Subsections appear in your object file in numeric order, lowest numbered +to highest. (All this to be compatible with other people's assemblers.) +The object file contains no representation of subsections; @code{@value{LD}} and +other programs that manipulate object files see no trace of them. +They just see all your text subsections as a text section, and all your +data subsections as a data section. + +To specify which subsection you want subsequent statements assembled +into, use a numeric argument to specify it, in a @samp{.text +@var{expression}} or a @samp{.data @var{expression}} statement. +@ifset COFF +@ifset GENERIC +When generating COFF output, you +@end ifset +@ifclear GENERIC +You +@end ifclear +can also use an extra subsection +argument with arbitrary named sections: @samp{.section @var{name}, +@var{expression}}. +@end ifset +@var{Expression} should be an absolute expression. +(@xref{Expressions}.) If you just say @samp{.text} then @samp{.text 0} +is assumed. Likewise @samp{.data} means @samp{.data 0}. Assembly +begins in @code{text 0}. For instance: +@smallexample +.text 0 # The default subsection is text 0 anyway. +.ascii "This lives in the first text subsection. *" +.text 1 +.ascii "But this lives in the second text subsection." +.data 0 +.ascii "This lives in the data section," +.ascii "in the first data subsection." +.text 0 +.ascii "This lives in the first text section," +.ascii "immediately following the asterisk (*)." +@end smallexample + +Each section has a @dfn{location counter} incremented by one for every byte +assembled into that section. Because subsections are merely a convenience +restricted to @code{@value{AS}} there is no concept of a subsection location +counter. There is no way to directly manipulate a location counter---but the +@code{.align} directive changes it, and any label definition captures its +current value. The location counter of the section where statements are being +assembled is said to be the @dfn{active} location counter. + +@node bss +@section bss Section + +@cindex bss section +@cindex common variable storage +The bss section is used for local common variable storage. +You may allocate address space in the bss section, but you may +not dictate data to load into it before your program executes. When +your program starts running, all the contents of the bss +section are zeroed bytes. + +The @code{.lcomm} pseudo-op defines a symbol in the bss section; see +@ref{Lcomm,,@code{.lcomm}}. + +The @code{.comm} pseudo-op may be used to declare a common symbol, which is +another form of uninitialized symbol; see @xref{Comm,,@code{.comm}}. + +@ifset GENERIC +When assembling for a target which supports multiple sections, such as ELF or +COFF, you may switch into the @code{.bss} section and define symbols as usual; +see @ref{Section,,@code{.section}}. You may only assemble zero values into the +section. Typically the section will only contain symbol definitions and +@code{.skip} directives (@pxref{Skip,,@code{.skip}}). +@end ifset + +@node Symbols +@chapter Symbols + +@cindex symbols +Symbols are a central concept: the programmer uses symbols to name +things, the linker uses symbols to link, and the debugger uses symbols +to debug. + +@quotation +@cindex debuggers, and symbol order +@emph{Warning:} @code{@value{AS}} does not place symbols in the object file in +the same order they were declared. This may break some debuggers. +@end quotation + +@menu +* Labels:: Labels +* Setting Symbols:: Giving Symbols Other Values +* Symbol Names:: Symbol Names +* Dot:: The Special Dot Symbol +* Symbol Attributes:: Symbol Attributes +@end menu + +@node Labels +@section Labels + +@cindex labels +A @dfn{label} is written as a symbol immediately followed by a colon +@samp{:}. The symbol then represents the current value of the +active location counter, and is, for example, a suitable instruction +operand. You are warned if you use the same symbol to represent two +different locations: the first definition overrides any other +definitions. + +@ifset HPPA +On the HPPA, the usual form for a label need not be immediately followed by a +colon, but instead must start in column zero. Only one label may be defined on +a single line. To work around this, the HPPA version of @code{@value{AS}} also +provides a special directive @code{.label} for defining labels more flexibly. +@end ifset + +@node Setting Symbols +@section Giving Symbols Other Values + +@cindex assigning values to symbols +@cindex symbol values, assigning +A symbol can be given an arbitrary value by writing a symbol, followed +by an equals sign @samp{=}, followed by an expression +(@pxref{Expressions}). This is equivalent to using the @code{.set} +directive. @xref{Set,,@code{.set}}. + +@node Symbol Names +@section Symbol Names + +@cindex symbol names +@cindex names, symbol +@ifclear SPECIAL-SYMS +Symbol names begin with a letter or with one of @samp{._}. On most +machines, you can also use @code{$} in symbol names; exceptions are +noted in @ref{Machine Dependencies}. That character may be followed by any +string of digits, letters, dollar signs (unless otherwise noted in +@ref{Machine Dependencies}), and underscores. +@end ifclear +@ifset A29K +For the AMD 29K family, @samp{?} is also allowed in the +body of a symbol name, though not at its beginning. +@end ifset + +@ifset SPECIAL-SYMS +@ifset H8 +Symbol names begin with a letter or with one of @samp{._}. On the +Hitachi SH or the +H8/500, you can also use @code{$} in symbol names. That character may +be followed by any string of digits, letters, dollar signs (save on the +H8/300), and underscores. +@end ifset +@end ifset + +Case of letters is significant: @code{foo} is a different symbol name +than @code{Foo}. + +Each symbol has exactly one name. Each name in an assembly language program +refers to exactly one symbol. You may use that symbol name any number of times +in a program. + +@subheading Local Symbol Names + +@cindex local symbol names +@cindex symbol names, local +@cindex temporary symbol names +@cindex symbol names, temporary +Local symbols help compilers and programmers use names temporarily. +There are ten local symbol names, which are re-used throughout the +program. You may refer to them using the names @samp{0} @samp{1} +@dots{} @samp{9}. To define a local symbol, write a label of the form +@samp{@b{N}:} (where @b{N} represents any digit). To refer to the most +recent previous definition of that symbol write @samp{@b{N}b}, using the +same digit as when you defined the label. To refer to the next +definition of a local label, write @samp{@b{N}f}---where @b{N} gives you +a choice of 10 forward references. The @samp{b} stands for +``backwards'' and the @samp{f} stands for ``forwards''. + +Local symbols are not emitted by the current @sc{gnu} C compiler. + +There is no restriction on how you can use these labels, but +remember that at any point in the assembly you can refer to at most +10 prior local labels and to at most 10 forward local labels. + +Local symbol names are only a notation device. They are immediately +transformed into more conventional symbol names before the assembler +uses them. The symbol names stored in the symbol table, appearing in +error messages and optionally emitted to the object file have these +parts: + +@table @code +@item L +All local labels begin with @samp{L}. Normally both @code{@value{AS}} and +@code{@value{LD}} forget symbols that start with @samp{L}. These labels are +used for symbols you are never intended to see. If you use the +@samp{-L} option then @code{@value{AS}} retains these symbols in the +object file. If you also instruct @code{@value{LD}} to retain these symbols, +you may use them in debugging. + +@item @var{digit} +If the label is written @samp{0:} then the digit is @samp{0}. +If the label is written @samp{1:} then the digit is @samp{1}. +And so on up through @samp{9:}. + +@item @kbd{C-A} +This unusual character is included so you do not accidentally invent +a symbol of the same name. The character has ASCII value +@samp{\001}. + +@item @emph{ordinal number} +This is a serial number to keep the labels distinct. The first +@samp{0:} gets the number @samp{1}; The 15th @samp{0:} gets the +number @samp{15}; @emph{etc.}. Likewise for the other labels @samp{1:} +through @samp{9:}. +@end table + +For instance, the first @code{1:} is named @code{L1@kbd{C-A}1}, the 44th +@code{3:} is named @code{L3@kbd{C-A}44}. + +@node Dot +@section The Special Dot Symbol + +@cindex dot (symbol) +@cindex @code{.} (symbol) +@cindex current address +@cindex location counter +The special symbol @samp{.} refers to the current address that +@code{@value{AS}} is assembling into. Thus, the expression @samp{melvin: +.long .} defines @code{melvin} to contain its own address. +Assigning a value to @code{.} is treated the same as a @code{.org} +directive. Thus, the expression @samp{.=.+4} is the same as saying +@ifclear no-space-dir +@samp{.space 4}. +@end ifclear +@ifset no-space-dir +@ifset A29K +@samp{.block 4}. +@end ifset +@end ifset + +@node Symbol Attributes +@section Symbol Attributes + +@cindex symbol attributes +@cindex attributes, symbol +Every symbol has, as well as its name, the attributes ``Value'' and +``Type''. Depending on output format, symbols can also have auxiliary +attributes. +@ifset INTERNALS +The detailed definitions are in @file{a.out.h}. +@end ifset + +If you use a symbol without defining it, @code{@value{AS}} assumes zero for +all these attributes, and probably won't warn you. This makes the +symbol an externally defined symbol, which is generally what you +would want. + +@menu +* Symbol Value:: Value +* Symbol Type:: Type +@ifset aout-bout +@ifset GENERIC +* a.out Symbols:: Symbol Attributes: @code{a.out} +@end ifset +@ifclear GENERIC +@ifclear BOUT +* a.out Symbols:: Symbol Attributes: @code{a.out} +@end ifclear +@ifset BOUT +* a.out Symbols:: Symbol Attributes: @code{a.out}, @code{b.out} +@end ifset +@end ifclear +@end ifset +@ifset COFF +* COFF Symbols:: Symbol Attributes for COFF +@end ifset +@ifset SOM +* SOM Symbols:: Symbol Attributes for SOM +@end ifset +@end menu + +@node Symbol Value +@subsection Value + +@cindex value of a symbol +@cindex symbol value +The value of a symbol is (usually) 32 bits. For a symbol which labels a +location in the text, data, bss or absolute sections the value is the +number of addresses from the start of that section to the label. +Naturally for text, data and bss sections the value of a symbol changes +as @code{@value{LD}} changes section base addresses during linking. Absolute +symbols' values do not change during linking: that is why they are +called absolute. + +The value of an undefined symbol is treated in a special way. If it is +0 then the symbol is not defined in this assembler source file, and +@code{@value{LD}} tries to determine its value from other files linked into the +same program. You make this kind of symbol simply by mentioning a symbol +name without defining it. A non-zero value represents a @code{.comm} +common declaration. The value is how much common storage to reserve, in +bytes (addresses). The symbol refers to the first address of the +allocated storage. + +@node Symbol Type +@subsection Type + +@cindex type of a symbol +@cindex symbol type +The type attribute of a symbol contains relocation (section) +information, any flag settings indicating that a symbol is external, and +(optionally), other information for linkers and debuggers. The exact +format depends on the object-code output format in use. + +@ifset aout-bout +@ifclear GENERIC +@ifset BOUT +@c The following avoids a "widow" subsection title. @group would be +@c better if it were available outside examples. +@need 1000 +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out}, @code{b.out} + +@cindex @code{b.out} symbol attributes +@cindex symbol attributes, @code{b.out} +These symbol attributes appear only when @code{@value{AS}} is configured for +one of the Berkeley-descended object output formats---@code{a.out} or +@code{b.out}. + +@end ifset +@ifclear BOUT +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out} + +@cindex @code{a.out} symbol attributes +@cindex symbol attributes, @code{a.out} + +@end ifclear +@end ifclear +@ifset GENERIC +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out} + +@cindex @code{a.out} symbol attributes +@cindex symbol attributes, @code{a.out} + +@end ifset +@menu +* Symbol Desc:: Descriptor +* Symbol Other:: Other +@end menu + +@node Symbol Desc +@subsubsection Descriptor + +@cindex descriptor, of @code{a.out} symbol +This is an arbitrary 16-bit value. You may establish a symbol's +descriptor value by using a @code{.desc} statement +(@pxref{Desc,,@code{.desc}}). A descriptor value means nothing to +@code{@value{AS}}. + +@node Symbol Other +@subsubsection Other + +@cindex other attribute, of @code{a.out} symbol +This is an arbitrary 8-bit value. It means nothing to @code{@value{AS}}. +@end ifset + +@ifset COFF +@node COFF Symbols +@subsection Symbol Attributes for COFF + +@cindex COFF symbol attributes +@cindex symbol attributes, COFF + +The COFF format supports a multitude of auxiliary symbol attributes; +like the primary symbol attributes, they are set between @code{.def} and +@code{.endef} directives. + +@subsubsection Primary Attributes + +@cindex primary attributes, COFF symbols +The symbol name is set with @code{.def}; the value and type, +respectively, with @code{.val} and @code{.type}. + +@subsubsection Auxiliary Attributes + +@cindex auxiliary attributes, COFF symbols +The @code{@value{AS}} directives @code{.dim}, @code{.line}, @code{.scl}, +@code{.size}, and @code{.tag} can generate auxiliary symbol table +information for COFF. +@end ifset + +@ifset SOM +@node SOM Symbols +@subsection Symbol Attributes for SOM + +@cindex SOM symbol attributes +@cindex symbol attributes, SOM + +The SOM format for the HPPA supports a multitude of symbol attributes set with +the @code{.EXPORT} and @code{.IMPORT} directives. + +The attributes are described in @cite{HP9000 Series 800 Assembly +Language Reference Manual} (HP 92432-90001) under the @code{IMPORT} and +@code{EXPORT} assembler directive documentation. +@end ifset + +@node Expressions +@chapter Expressions + +@cindex expressions +@cindex addresses +@cindex numeric values +An @dfn{expression} specifies an address or numeric value. +Whitespace may precede and/or follow an expression. + +The result of an expression must be an absolute number, or else an offset into +a particular section. If an expression is not absolute, and there is not +enough information when @code{@value{AS}} sees the expression to know its +section, a second pass over the source program might be necessary to interpret +the expression---but the second pass is currently not implemented. +@code{@value{AS}} aborts with an error message in this situation. + +@menu +* Empty Exprs:: Empty Expressions +* Integer Exprs:: Integer Expressions +@end menu + +@node Empty Exprs +@section Empty Expressions + +@cindex empty expressions +@cindex expressions, empty +An empty expression has no value: it is just whitespace or null. +Wherever an absolute expression is required, you may omit the +expression, and @code{@value{AS}} assumes a value of (absolute) 0. This +is compatible with other assemblers. + +@node Integer Exprs +@section Integer Expressions + +@cindex integer expressions +@cindex expressions, integer +An @dfn{integer expression} is one or more @emph{arguments} delimited +by @emph{operators}. + +@menu +* Arguments:: Arguments +* Operators:: Operators +* Prefix Ops:: Prefix Operators +* Infix Ops:: Infix Operators +@end menu + +@node Arguments +@subsection Arguments + +@cindex expression arguments +@cindex arguments in expressions +@cindex operands in expressions +@cindex arithmetic operands +@dfn{Arguments} are symbols, numbers or subexpressions. In other +contexts arguments are sometimes called ``arithmetic operands''. In +this manual, to avoid confusing them with the ``instruction operands'' of +the machine language, we use the term ``argument'' to refer to parts of +expressions only, reserving the word ``operand'' to refer only to machine +instruction operands. + +Symbols are evaluated to yield @{@var{section} @var{NNN}@} where +@var{section} is one of text, data, bss, absolute, +or undefined. @var{NNN} is a signed, 2's complement 32 bit +integer. + +Numbers are usually integers. + +A number can be a flonum or bignum. In this case, you are warned +that only the low order 32 bits are used, and @code{@value{AS}} pretends +these 32 bits are an integer. You may write integer-manipulating +instructions that act on exotic constants, compatible with other +assemblers. + +@cindex subexpressions +Subexpressions are a left parenthesis @samp{(} followed by an integer +expression, followed by a right parenthesis @samp{)}; or a prefix +operator followed by an argument. + +@node Operators +@subsection Operators + +@cindex operators, in expressions +@cindex arithmetic functions +@cindex functions, in expressions +@dfn{Operators} are arithmetic functions, like @code{+} or @code{%}. Prefix +operators are followed by an argument. Infix operators appear +between their arguments. Operators may be preceded and/or followed by +whitespace. + +@node Prefix Ops +@subsection Prefix Operator + +@cindex prefix operators +@code{@value{AS}} has the following @dfn{prefix operators}. They each take +one argument, which must be absolute. + +@c the tex/end tex stuff surrounding this small table is meant to make +@c it align, on the printed page, with the similar table in the next +@c section (which is inside an enumerate). +@tex +\global\advance\leftskip by \itemindent +@end tex + +@table @code +@item - +@dfn{Negation}. Two's complement negation. +@item ~ +@dfn{Complementation}. Bitwise not. +@end table + +@tex +\global\advance\leftskip by -\itemindent +@end tex + +@node Infix Ops +@subsection Infix Operators + +@cindex infix operators +@cindex operators, permitted arguments +@dfn{Infix operators} take two arguments, one on either side. Operators +have precedence, but operations with equal precedence are performed left +to right. Apart from @code{+} or @code{-}, both arguments must be +absolute, and the result is absolute. + +@enumerate +@cindex operator precedence +@cindex precedence of operators + +@item +Highest Precedence + +@table @code +@item * +@dfn{Multiplication}. + +@item / +@dfn{Division}. Truncation is the same as the C operator @samp{/} + +@item % +@dfn{Remainder}. + +@item < +@itemx << +@dfn{Shift Left}. Same as the C operator @samp{<<}. + +@item > +@itemx >> +@dfn{Shift Right}. Same as the C operator @samp{>>}. +@end table + +@item +Intermediate precedence + +@table @code +@item | + +@dfn{Bitwise Inclusive Or}. + +@item & +@dfn{Bitwise And}. + +@item ^ +@dfn{Bitwise Exclusive Or}. + +@item ! +@dfn{Bitwise Or Not}. +@end table + +@item +Lowest Precedence + +@table @code +@cindex addition, permitted arguments +@cindex plus, permitted arguments +@cindex arguments for addition +@item + +@dfn{Addition}. If either argument is absolute, the result has the section of +the other argument. You may not add together arguments from different +sections. + +@cindex subtraction, permitted arguments +@cindex minus, permitted arguments +@cindex arguments for subtraction +@item - +@dfn{Subtraction}. If the right argument is absolute, the +result has the section of the left argument. +If both arguments are in the same section, the result is absolute. +You may not subtract arguments from different sections. +@c FIXME is there still something useful to say about undefined - undefined ? +@end table +@end enumerate + +In short, it's only meaningful to add or subtract the @emph{offsets} in an +address; you can only have a defined section in one of the two arguments. + +@node Pseudo Ops +@chapter Assembler Directives + +@cindex directives, machine independent +@cindex pseudo-ops, machine independent +@cindex machine independent directives +All assembler directives have names that begin with a period (@samp{.}). +The rest of the name is letters, usually in lower case. + +This chapter discusses directives that are available regardless of the +target machine configuration for the @sc{gnu} assembler. +@ifset GENERIC +Some machine configurations provide additional directives. +@xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset machine-directives +@xref{Machine Dependencies} for additional directives. +@end ifset +@end ifclear + +@menu +* Abort:: @code{.abort} +@ifset COFF +* ABORT:: @code{.ABORT} +@end ifset + +* Align:: @code{.align @var{abs-expr} , @var{abs-expr}} +* App-File:: @code{.app-file @var{string}} +* Ascii:: @code{.ascii "@var{string}"}@dots{} +* Asciz:: @code{.asciz "@var{string}"}@dots{} +* Balign:: @code{.balign @var{abs-expr} , @var{abs-expr}} +* Byte:: @code{.byte @var{expressions}} +* Comm:: @code{.comm @var{symbol} , @var{length} } +* Data:: @code{.data @var{subsection}} +@ifset COFF +* Def:: @code{.def @var{name}} +@end ifset +@ifset aout-bout +* Desc:: @code{.desc @var{symbol}, @var{abs-expression}} +@end ifset +@ifset COFF +* Dim:: @code{.dim} +@end ifset + +* Double:: @code{.double @var{flonums}} +* Eject:: @code{.eject} +* Else:: @code{.else} +@ifset COFF +* Endef:: @code{.endef} +@end ifset + +* Endif:: @code{.endif} +* Equ:: @code{.equ @var{symbol}, @var{expression}} +* Equiv:: @code{.equiv @var{symbol}, @var{expression}} +* Err:: @code{.err} +* Extern:: @code{.extern} +@ifclear no-file-dir +* File:: @code{.file @var{string}} +@end ifclear + +* Fill:: @code{.fill @var{repeat} , @var{size} , @var{value}} +* Float:: @code{.float @var{flonums}} +* Global:: @code{.global @var{symbol}}, @code{.globl @var{symbol}} +* hword:: @code{.hword @var{expressions}} +* Ident:: @code{.ident} +* If:: @code{.if @var{absolute expression}} +* Include:: @code{.include "@var{file}"} +* Int:: @code{.int @var{expressions}} +* Irp:: @code{.irp @var{symbol},@var{values}}@dots{} +* Irpc:: @code{.irpc @var{symbol},@var{values}}@dots{} +* Lcomm:: @code{.lcomm @var{symbol} , @var{length}} +* Lflags:: @code{.lflags} +@ifclear no-line-dir +* Line:: @code{.line @var{line-number}} +@end ifclear + +* Ln:: @code{.ln @var{line-number}} +* Linkonce:: @code{.linkonce [@var{type}]} +* List:: @code{.list} +* Long:: @code{.long @var{expressions}} +@ignore +* Lsym:: @code{.lsym @var{symbol}, @var{expression}} +@end ignore + +* Macro:: @code{.macro @var{name} @var{args}}@dots{} +* MRI:: @code{.mri @var{val}} + +* Nolist:: @code{.nolist} +* Octa:: @code{.octa @var{bignums}} +* Org:: @code{.org @var{new-lc} , @var{fill}} +* P2align:: @code{.p2align @var{abs-expr} , @var{abs-expr}} +* Psize:: @code{.psize @var{lines}, @var{columns}} +* Quad:: @code{.quad @var{bignums}} +* Rept:: @code{.rept @var{count}} +* Sbttl:: @code{.sbttl "@var{subheading}"} +@ifset COFF +* Scl:: @code{.scl @var{class}} +@end ifset +@ifset COFF +* Section:: @code{.section @var{name}, @var{subsection}} +@end ifset + +* Set:: @code{.set @var{symbol}, @var{expression}} +* Short:: @code{.short @var{expressions}} +* Single:: @code{.single @var{flonums}} +@ifset COFF +* Size:: @code{.size} +@end ifset + +* Skip:: @code{.skip @var{size} , @var{fill}} +* Space:: @code{.space @var{size} , @var{fill}} +@ifset have-stabs +* Stab:: @code{.stabd, .stabn, .stabs} +@end ifset + +* String:: @code{.string "@var{str}"} +@ifset ELF +* Symver:: @code{.symver @var{name},@var{name2@@nodename}} +@end ifset +@ifset COFF +* Tag:: @code{.tag @var{structname}} +@end ifset + +* Text:: @code{.text @var{subsection}} +* Title:: @code{.title "@var{heading}"} +@ifset COFF +* Type:: @code{.type @var{int}} +* Val:: @code{.val @var{addr}} +@end ifset + +* Word:: @code{.word @var{expressions}} +* Deprecated:: Deprecated Directives +@end menu + +@node Abort +@section @code{.abort} + +@cindex @code{abort} directive +@cindex stopping the assembly +This directive stops the assembly immediately. It is for +compatibility with other assemblers. The original idea was that the +assembly language source would be piped into the assembler. If the sender +of the source quit, it could use this directive tells @code{@value{AS}} to +quit also. One day @code{.abort} will not be supported. + +@ifset COFF +@node ABORT +@section @code{.ABORT} + +@cindex @code{ABORT} directive +When producing COFF output, @code{@value{AS}} accepts this directive as a +synonym for @samp{.abort}. + +@ifset BOUT +When producing @code{b.out} output, @code{@value{AS}} accepts this directive, +but ignores it. +@end ifset +@end ifset + +@node Align +@section @code{.align @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter +@cindex @code{align} directive +Pad the location counter (in the current subsection) to a particular storage +boundary. The first expression (which must be absolute) is the alignment +required, as described below. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +The way the required alignment is specified varies from system to system. +For the a29k, hppa, m68k, m88k, w65, sparc, and Hitachi SH, and i386 using ELF +format, +the first expression is the +alignment request in bytes. For example @samp{.align 8} advances +the location counter until it is a multiple of 8. If the location counter +is already a multiple of 8, no change is needed. + +For other systems, including the i386 using a.out format, it is the +number of low-order zero bits the location counter must have after +advancement. For example @samp{.align 3} advances the location +counter until it a multiple of 8. If the location counter is already a +multiple of 8, no change is needed. + +This inconsistency is due to the different behaviors of the various +native assemblers for these systems which GAS must emulate. +GAS also provides @code{.balign} and @code{.p2align} directives, +described later, which have a consistent behavior across all +architectures (but are specific to GAS). + +@node App-File +@section @code{.app-file @var{string}} + +@cindex logical file name +@cindex file name, logical +@cindex @code{app-file} directive +@code{.app-file} +@ifclear no-file-dir +(which may also be spelled @samp{.file}) +@end ifclear +tells @code{@value{AS}} that we are about to start a new +logical file. @var{string} is the new file name. In general, the +filename is recognized whether or not it is surrounded by quotes @samp{"}; +but if you wish to specify an empty file name is permitted, +you must give the quotes--@code{""}. This statement may go away in +future: it is only recognized to be compatible with old @code{@value{AS}} +programs.@refill + +@node Ascii +@section @code{.ascii "@var{string}"}@dots{} + +@cindex @code{ascii} directive +@cindex string literals +@code{.ascii} expects zero or more string literals (@pxref{Strings}) +separated by commas. It assembles each string (with no automatic +trailing zero byte) into consecutive addresses. + +@node Asciz +@section @code{.asciz "@var{string}"}@dots{} + +@cindex @code{asciz} directive +@cindex zero-terminated strings +@cindex null-terminated strings +@code{.asciz} is just like @code{.ascii}, but each string is followed by +a zero byte. The ``z'' in @samp{.asciz} stands for ``zero''. + +@node Balign +@section @code{.balign[wl] @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter given number of bytes +@cindex @code{balign} directive +Pad the location counter (in the current subsection) to a particular +storage boundary. The first expression (which must be absolute) is the +alignment request in bytes. For example @samp{.balign 8} advances +the location counter until it is a multiple of 8. If the location counter +is already a multiple of 8, no change is needed. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +@cindex @code{balignw} directive +@cindex @code{balignl} directive +The @code{.balignw} and @code{.balignl} directives are variants of the +@code{.balign} directive. The @code{.balignw} directive treats the fill +pattern as a two byte word value. The @code{.balignl} directives treats the +fill pattern as a four byte longword value. For example, @code{.balignw +4,0x368d} will align to a multiple of 4. If it skips two bytes, they will be +filled in with the value 0x368d (the exact placement of the bytes depends upon +the endianness of the processor). If it skips 1 or 3 bytes, the fill value is +undefined. + +@node Byte +@section @code{.byte @var{expressions}} + +@cindex @code{byte} directive +@cindex integers, one byte +@code{.byte} expects zero or more expressions, separated by commas. +Each expression is assembled into the next byte. + +@node Comm +@section @code{.comm @var{symbol} , @var{length} } + +@cindex @code{comm} directive +@cindex symbol, common +@code{.comm} declares a common symbol named @var{symbol}. When linking, a +common symbol in one object file may be merged with a defined or common symbol +of the same name in another object file. If @code{@value{LD}} does not see a +definition for the symbol--just one or more common symbols--then it will +allocate @var{length} bytes of uninitialized memory. @var{length} must be an +absolute expression. If @code{@value{LD}} sees multiple common symbols with +the same name, and they do not all have the same size, it will allocate space +using the largest size. + +@ifset ELF +When using ELF, the @code{.comm} directive takes an optional third argument. +This is the desired alignment of the symbol, specified as a byte boundary (for +example, an alignment of 16 means that the least significant 4 bits of the +address should be zero). The alignment must be an absolute expression, and it +must be a power of two. If @code{@value{LD}} allocates uninitialized memory +for the common symbol, it will use the alignment when placing the symbol. If +no alignment is specified, @code{@value{AS}} will set the alignment to the +largest power of two less than or equal to the size of the symbol, up to a +maximum of 16. +@end ifset + +@ifset HPPA +The syntax for @code{.comm} differs slightly on the HPPA. The syntax is +@samp{@var{symbol} .comm, @var{length}}; @var{symbol} is optional. +@end ifset + +@node Data +@section @code{.data @var{subsection}} + +@cindex @code{data} directive +@code{.data} tells @code{@value{AS}} to assemble the following statements onto the +end of the data subsection numbered @var{subsection} (which is an +absolute expression). If @var{subsection} is omitted, it defaults +to zero. + +@ifset COFF +@node Def +@section @code{.def @var{name}} + +@cindex @code{def} directive +@cindex COFF symbols, debugging +@cindex debugging COFF symbols +Begin defining debugging information for a symbol @var{name}; the +definition extends until the @code{.endef} directive is encountered. +@ifset BOUT + +This directive is only observed when @code{@value{AS}} is configured for COFF +format output; when producing @code{b.out}, @samp{.def} is recognized, +but ignored. +@end ifset +@end ifset + +@ifset aout-bout +@node Desc +@section @code{.desc @var{symbol}, @var{abs-expression}} + +@cindex @code{desc} directive +@cindex COFF symbol descriptor +@cindex symbol descriptor, COFF +This directive sets the descriptor of the symbol (@pxref{Symbol Attributes}) +to the low 16 bits of an absolute expression. + +@ifset COFF +The @samp{.desc} directive is not available when @code{@value{AS}} is +configured for COFF output; it is only for @code{a.out} or @code{b.out} +object format. For the sake of compatibility, @code{@value{AS}} accepts +it, but produces no output, when configured for COFF. +@end ifset +@end ifset + +@ifset COFF +@node Dim +@section @code{.dim} + +@cindex @code{dim} directive +@cindex COFF auxiliary symbol information +@cindex auxiliary symbol information, COFF +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. +@ifset BOUT + +@samp{.dim} is only meaningful when generating COFF format output; when +@code{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@node Double +@section @code{.double @var{flonums}} + +@cindex @code{double} directive +@cindex floating point numbers (double) +@code{.double} expects zero or more flonums, separated by commas. It +assembles floating point numbers. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@code{@value{AS}} is configured. @xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family @samp{.double} emits 64-bit floating-point numbers +in @sc{ieee} format. +@end ifset +@end ifclear + +@node Eject +@section @code{.eject} + +@cindex @code{eject} directive +@cindex new page, in listings +@cindex page, in listings +@cindex listing control: new page +Force a page break at this point, when generating assembly listings. + +@node Else +@section @code{.else} + +@cindex @code{else} directive +@code{.else} is part of the @code{@value{AS}} support for conditional +assembly; @pxref{If,,@code{.if}}. It marks the beginning of a section +of code to be assembled if the condition for the preceding @code{.if} +was false. + +@ignore +@node End, Endef, Else, Pseudo Ops +@section @code{.end} + +@cindex @code{end} directive +This doesn't do anything---but isn't an s_ignore, so I suspect it's +meant to do something eventually (which is why it isn't documented here +as "for compatibility with blah"). +@end ignore + +@ifset COFF +@node Endef +@section @code{.endef} + +@cindex @code{endef} directive +This directive flags the end of a symbol definition begun with +@code{.def}. +@ifset BOUT + +@samp{.endef} is only meaningful when generating COFF format output; if +@code{@value{AS}} is configured to generate @code{b.out}, it accepts this +directive but ignores it. +@end ifset +@end ifset + +@node Endif +@section @code{.endif} + +@cindex @code{endif} directive +@code{.endif} is part of the @code{@value{AS}} support for conditional assembly; +it marks the end of a block of code that is only assembled +conditionally. @xref{If,,@code{.if}}. + +@node Equ +@section @code{.equ @var{symbol}, @var{expression}} + +@cindex @code{equ} directive +@cindex assigning values to symbols +@cindex symbols, assigning values to +This directive sets the value of @var{symbol} to @var{expression}. +It is synonymous with @samp{.set}; @pxref{Set,,@code{.set}}. + +@ifset HPPA +The syntax for @code{equ} on the HPPA is +@samp{@var{symbol} .equ @var{expression}}. +@end ifset + +@node Equiv +@section @code{.equiv @var{symbol}, @var{expression}} +@cindex @code{equiv} directive +The @code{.equiv} directive is like @code{.equ} and @code{.set}, except that +the assembler will signal an error if @var{symbol} is already defined. + +Except for the contents of the error message, this is roughly equivalent to +@smallexample +.ifdef SYM +.err +.endif +.equ SYM,VAL +@end smallexample + +@node Err +@section @code{.err} +@cindex @code{err} directive +If @code{@value{AS}} assembles a @code{.err} directive, it will print an error +message and, unless the @code{-Z} option was used, it will not generate an +object file. This can be used to signal error an conditionally compiled code. + +@node Extern +@section @code{.extern} + +@cindex @code{extern} directive +@code{.extern} is accepted in the source program---for compatibility +with other assemblers---but it is ignored. @code{@value{AS}} treats +all undefined symbols as external. + +@ifclear no-file-dir +@node File +@section @code{.file @var{string}} + +@cindex @code{file} directive +@cindex logical file name +@cindex file name, logical +@code{.file} (which may also be spelled @samp{.app-file}) tells +@code{@value{AS}} that we are about to start a new logical file. +@var{string} is the new file name. In general, the filename is +recognized whether or not it is surrounded by quotes @samp{"}; but if +you wish to specify an empty file name, you must give the +quotes--@code{""}. This statement may go away in future: it is only +recognized to be compatible with old @code{@value{AS}} programs. +@ifset A29K +In some configurations of @code{@value{AS}}, @code{.file} has already been +removed to avoid conflicts with other assemblers. @xref{Machine Dependencies}. +@end ifset +@end ifclear + +@node Fill +@section @code{.fill @var{repeat} , @var{size} , @var{value}} + +@cindex @code{fill} directive +@cindex writing patterns in memory +@cindex patterns, writing in memory +@var{result}, @var{size} and @var{value} are absolute expressions. +This emits @var{repeat} copies of @var{size} bytes. @var{Repeat} +may be zero or more. @var{Size} may be zero or more, but if it is +more than 8, then it is deemed to have the value 8, compatible with +other people's assemblers. The contents of each @var{repeat} bytes +is taken from an 8-byte number. The highest order 4 bytes are +zero. The lowest order 4 bytes are @var{value} rendered in the +byte-order of an integer on the computer @code{@value{AS}} is assembling for. +Each @var{size} bytes in a repetition is taken from the lowest order +@var{size} bytes of this number. Again, this bizarre behavior is +compatible with other people's assemblers. + +@var{size} and @var{value} are optional. +If the second comma and @var{value} are absent, @var{value} is +assumed zero. If the first comma and following tokens are absent, +@var{size} is assumed to be 1. + +@node Float +@section @code{.float @var{flonums}} + +@cindex floating point numbers (single) +@cindex @code{float} directive +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.single}. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@code{@value{AS}} is configured. +@xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family, @code{.float} emits 32-bit floating point numbers +in @sc{ieee} format. +@end ifset +@end ifclear + +@node Global +@section @code{.global @var{symbol}}, @code{.globl @var{symbol}} + +@cindex @code{global} directive +@cindex symbol, making visible to linker +@code{.global} makes the symbol visible to @code{@value{LD}}. If you define +@var{symbol} in your partial program, its value is made available to +other partial programs that are linked with it. Otherwise, +@var{symbol} takes its attributes from a symbol of the same name +from another file linked into the same program. + +Both spellings (@samp{.globl} and @samp{.global}) are accepted, for +compatibility with other assemblers. + +@ifset HPPA +On the HPPA, @code{.global} is not always enough to make it accessible to other +partial programs. You may need the HPPA-only @code{.EXPORT} directive as well. +@xref{HPPA Directives,, HPPA Assembler Directives}. +@end ifset + +@node hword +@section @code{.hword @var{expressions}} + +@cindex @code{hword} directive +@cindex integers, 16-bit +@cindex numbers, 16-bit +@cindex sixteen bit integers +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. + +@ifset GENERIC +This directive is a synonym for @samp{.short}; depending on the target +architecture, it may also be a synonym for @samp{.word}. +@end ifset +@ifclear GENERIC +@ifset W32 +This directive is a synonym for @samp{.short}. +@end ifset +@ifset W16 +This directive is a synonym for both @samp{.short} and @samp{.word}. +@end ifset +@end ifclear + +@node Ident +@section @code{.ident} + +@cindex @code{ident} directive +This directive is used by some assemblers to place tags in object files. +@code{@value{AS}} simply accepts the directive for source-file +compatibility with such assemblers, but does not actually emit anything +for it. + +@node If +@section @code{.if @var{absolute expression}} + +@cindex conditional assembly +@cindex @code{if} directive +@code{.if} marks the beginning of a section of code which is only +considered part of the source program being assembled if the argument +(which must be an @var{absolute expression}) is non-zero. The end of +the conditional section of code must be marked by @code{.endif} +(@pxref{Endif,,@code{.endif}}); optionally, you may include code for the +alternative condition, flagged by @code{.else} (@pxref{Else,,@code{.else}}). + +The following variants of @code{.if} are also supported: +@table @code +@cindex @code{ifdef} directive +@item .ifdef @var{symbol} +Assembles the following section of code if the specified @var{symbol} +has been defined. + +@ignore +@cindex @code{ifeqs} directive +@item .ifeqs +Not yet implemented. +@end ignore + +@cindex @code{ifndef} directive +@cindex @code{ifnotdef} directive +@item .ifndef @var{symbol} +@itemx .ifnotdef @var{symbol} +Assembles the following section of code if the specified @var{symbol} +has not been defined. Both spelling variants are equivalent. + +@ignore +@item ifnes +Not yet implemented. +@end ignore +@end table + +@node Include +@section @code{.include "@var{file}"} + +@cindex @code{include} directive +@cindex supporting files, including +@cindex files, including +This directive provides a way to include supporting files at specified +points in your source program. The code from @var{file} is assembled as +if it followed the point of the @code{.include}; when the end of the +included file is reached, assembly of the original file continues. You +can control the search paths used with the @samp{-I} command-line option +(@pxref{Invoking,,Command-Line Options}). Quotation marks are required +around @var{file}. + +@node Int +@section @code{.int @var{expressions}} + +@cindex @code{int} directive +@cindex integers, 32-bit +Expect zero or more @var{expressions}, of any section, separated by commas. +For each expression, emit a number that, at run time, is the value of that +expression. The byte order and bit size of the number depends on what kind +of target the assembly is for. + +@ifclear GENERIC +@ifset H8 +On the H8/500 and most forms of the H8/300, @code{.int} emits 16-bit +integers. On the H8/300H and the Hitachi SH, however, @code{.int} emits +32-bit integers. +@end ifset +@end ifclear + +@node Irp +@section @code{.irp @var{symbol},@var{values}}@dots{} + +@cindex @code{irp} directive +Evaluate a sequence of statements assigning different values to @var{symbol}. +The sequence of statements starts at the @code{.irp} directive, and is +terminated by an @code{.endr} directive. For each @var{value}, @var{symbol} is +set to @var{value}, and the sequence of statements is assembled. If no +@var{value} is listed, the sequence of statements is assembled once, with +@var{symbol} set to the null string. To refer to @var{symbol} within the +sequence of statements, use @var{\symbol}. + +For example, assembling + +@example + .irp param,1,2,3 + move d\param,sp@@- + .endr +@end example + +is equivalent to assembling + +@example + move d1,sp@@- + move d2,sp@@- + move d3,sp@@- +@end example + +@node Irpc +@section @code{.irpc @var{symbol},@var{values}}@dots{} + +@cindex @code{irpc} directive +Evaluate a sequence of statements assigning different values to @var{symbol}. +The sequence of statements starts at the @code{.irpc} directive, and is +terminated by an @code{.endr} directive. For each character in @var{value}, +@var{symbol} is set to the character, and the sequence of statements is +assembled. If no @var{value} is listed, the sequence of statements is +assembled once, with @var{symbol} set to the null string. To refer to +@var{symbol} within the sequence of statements, use @var{\symbol}. + +For example, assembling + +@example + .irpc param,123 + move d\param,sp@@- + .endr +@end example + +is equivalent to assembling + +@example + move d1,sp@@- + move d2,sp@@- + move d3,sp@@- +@end example + +@node Lcomm +@section @code{.lcomm @var{symbol} , @var{length}} + +@cindex @code{lcomm} directive +@cindex local common symbols +@cindex symbols, local common +Reserve @var{length} (an absolute expression) bytes for a local common +denoted by @var{symbol}. The section and value of @var{symbol} are +those of the new local common. The addresses are allocated in the bss +section, so that at run-time the bytes start off zeroed. @var{Symbol} +is not declared global (@pxref{Global,,@code{.global}}), so is normally +not visible to @code{@value{LD}}. + +@ifset GENERIC +Some targets permit a third argument to be used with @code{.lcomm}. This +argument specifies the desired alignment of the symbol in the bss section. +@end ifset + +@ifset HPPA +The syntax for @code{.lcomm} differs slightly on the HPPA. The syntax is +@samp{@var{symbol} .lcomm, @var{length}}; @var{symbol} is optional. +@end ifset + +@node Lflags +@section @code{.lflags} + +@cindex @code{lflags} directive (ignored) +@code{@value{AS}} accepts this directive, for compatibility with other +assemblers, but ignores it. + +@ifclear no-line-dir +@node Line +@section @code{.line @var{line-number}} + +@cindex @code{line} directive +@end ifclear +@ifset no-line-dir +@node Ln +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +@end ifset +@cindex logical line number +@ifset aout-bout +Change the logical line number. @var{line-number} must be an absolute +expression. The next line has that logical line number. Therefore any other +statements on the current line (after a statement separator character) are +reported as on logical line number @var{line-number} @minus{} 1. One day +@code{@value{AS}} will no longer support this directive: it is recognized only +for compatibility with existing assembler programs. + +@ifset GENERIC +@ifset A29K +@emph{Warning:} In the AMD29K configuration of @value{AS}, this command is +not available; use the synonym @code{.ln} in that context. +@end ifset +@end ifset +@end ifset + +@ifclear no-line-dir +Even though this is a directive associated with the @code{a.out} or +@code{b.out} object-code formats, @code{@value{AS}} still recognizes it +when producing COFF output, and treats @samp{.line} as though it +were the COFF @samp{.ln} @emph{if} it is found outside a +@code{.def}/@code{.endef} pair. + +Inside a @code{.def}, @samp{.line} is, instead, one of the directives +used by compilers to generate auxiliary symbol information for +debugging. +@end ifclear + +@node Linkonce +@section @code{.linkonce [@var{type}]} +@cindex COMDAT +@cindex @code{linkonce} directive +@cindex common sections +Mark the current section so that the linker only includes a single copy of it. +This may be used to include the same section in several different object files, +but ensure that the linker will only include it once in the final output file. +The @code{.linkonce} pseudo-op must be used for each instance of the section. +Duplicate sections are detected based on the section name, so it should be +unique. + +This directive is only supported by a few object file formats; as of this +writing, the only object file format which supports it is the Portable +Executable format used on Windows NT. + +The @var{type} argument is optional. If specified, it must be one of the +following strings. For example: +@smallexample +.linkonce same_size +@end smallexample +Not all types may be supported on all object file formats. + +@table @code +@item discard +Silently discard duplicate sections. This is the default. + +@item one_only +Warn if there are duplicate sections, but still keep only one copy. + +@item same_size +Warn if any of the duplicates have different sizes. + +@item same_contents +Warn if any of the duplicates do not have exactly the same contents. +@end table + +@node Ln +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +@ifclear no-line-dir +@samp{.ln} is a synonym for @samp{.line}. +@end ifclear +@ifset no-line-dir +Tell @code{@value{AS}} to change the logical line number. @var{line-number} +must be an absolute expression. The next line has that logical +line number, so any other statements on the current line (after a +statement separator character @code{;}) are reported as on logical +line number @var{line-number} @minus{} 1. +@ifset BOUT + +This directive is accepted, but ignored, when @code{@value{AS}} is +configured for @code{b.out}; its effect is only associated with COFF +output format. +@end ifset +@end ifset + +@node MRI +@section @code{.mri @var{val}} + +@cindex @code{mri} directive +@cindex MRI mode, temporarily +If @var{val} is non-zero, this tells @code{@value{AS}} to enter MRI mode. If +@var{val} is zero, this tells @code{@value{AS}} to exit MRI mode. This change +affects code assembled until the next @code{.mri} directive, or until the end +of the file. @xref{M, MRI mode, MRI mode}. + +@node List +@section @code{.list} + +@cindex @code{list} directive +@cindex listing control, turning on +Control (in conjunction with the @code{.nolist} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +By default, listings are disabled. When you enable them (with the +@samp{-a} command line option; @pxref{Invoking,,Command-Line Options}), +the initial value of the listing counter is one. + +@node Long +@section @code{.long @var{expressions}} + +@cindex @code{long} directive +@code{.long} is the same as @samp{.int}, @pxref{Int,,@code{.int}}. + +@ignore +@c no one seems to know what this is for or whether this description is +@c what it really ought to do +@node Lsym +@section @code{.lsym @var{symbol}, @var{expression}} + +@cindex @code{lsym} directive +@cindex symbol, not referenced in assembly +@code{.lsym} creates a new symbol named @var{symbol}, but does not put it in +the hash table, ensuring it cannot be referenced by name during the +rest of the assembly. This sets the attributes of the symbol to be +the same as the expression value: +@smallexample +@var{other} = @var{descriptor} = 0 +@var{type} = @r{(section of @var{expression})} +@var{value} = @var{expression} +@end smallexample +@noindent +The new symbol is not flagged as external. +@end ignore + +@node Macro +@section @code{.macro} + +@cindex macros +The commands @code{.macro} and @code{.endm} allow you to define macros that +generate assembly output. For example, this definition specifies a macro +@code{sum} that puts a sequence of numbers into memory: + +@example + .macro sum from=0, to=5 + .long \from + .if \to-\from + sum "(\from+1)",\to + .endif + .endm +@end example + +@noindent +With that definition, @samp{SUM 0,5} is equivalent to this assembly input: + +@example + .long 0 + .long 1 + .long 2 + .long 3 + .long 4 + .long 5 +@end example + +@ftable @code +@item .macro @var{macname} +@itemx .macro @var{macname} @var{macargs} @dots{} +@cindex @code{macro} directive +Begin the definition of a macro called @var{macname}. If your macro +definition requires arguments, specify their names after the macro name, +separated by commas or spaces. You can supply a default value for any +macro argument by following the name with @samp{=@var{deflt}}. For +example, these are all valid @code{.macro} statements: + +@table @code +@item .macro comm +Begin the definition of a macro called @code{comm}, which takes no +arguments. + +@item .macro plus1 p, p1 +@itemx .macro plus1 p p1 +Either statement begins the definition of a macro called @code{plus1}, +which takes two arguments; within the macro definition, write +@samp{\p} or @samp{\p1} to evaluate the arguments. + +@item .macro reserve_str p1=0 p2 +Begin the definition of a macro called @code{reserve_str}, with two +arguments. The first argument has a default value, but not the second. +After the definition is complete, you can call the macro either as +@samp{reserve_str @var{a},@var{b}} (with @samp{\p1} evaluating to +@var{a} and @samp{\p2} evaluating to @var{b}), or as @samp{reserve_str +,@var{b}} (with @samp{\p1} evaluating as the default, in this case +@samp{0}, and @samp{\p2} evaluating to @var{b}). +@end table + +When you call a macro, you can specify the argument values either by +position, or by keyword. For example, @samp{sum 9,17} is equivalent to +@samp{sum to=17, from=9}. + +@item .endm +@cindex @code{endm} directive +Mark the end of a macro definition. + +@item .exitm +@cindex @code{exitm} directive +Exit early from the current macro definition. + +@cindex number of macros executed +@cindex macros, count executed +@item \@@ +@code{@value{AS}} maintains a counter of how many macros it has +executed in this pseudo-variable; you can copy that number to your +output with @samp{\@@}, but @emph{only within a macro definition}. + +@ignore +@item LOCAL @var{name} [ , @dots{} ] +@emph{Warning: @code{LOCAL} is only available if you select ``alternate +macro syntax'' with @samp{-a} or @samp{--alternate}.} @xref{Alternate,, +Alternate macro syntax}. + +Generate a string replacement for each of the @var{name} arguments, and +replace any instances of @var{name} in each macro expansion. The +replacement string is unique in the assembly, and different for each +separate macro expansion. @code{LOCAL} allows you to write macros that +define symbols, without fear of conflict between separate macro expansions. +@end ignore +@end ftable + +@node Nolist +@section @code{.nolist} + +@cindex @code{nolist} directive +@cindex listing control, turning off +Control (in conjunction with the @code{.list} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +@node Octa +@section @code{.octa @var{bignums}} + +@c FIXME: double size emitted for "octa" on i960, others? Or warn? +@cindex @code{octa} directive +@cindex integer, 16-byte +@cindex sixteen byte integer +This directive expects zero or more bignums, separated by commas. For each +bignum, it emits a 16-byte integer. + +The term ``octa'' comes from contexts in which a ``word'' is two bytes; +hence @emph{octa}-word for 16 bytes. + +@node Org +@section @code{.org @var{new-lc} , @var{fill}} + +@cindex @code{org} directive +@cindex location counter, advancing +@cindex advancing location counter +@cindex current address, advancing +Advance the location counter of the current section to +@var{new-lc}. @var{new-lc} is either an absolute expression or an +expression with the same section as the current subsection. That is, +you can't use @code{.org} to cross sections: if @var{new-lc} has the +wrong section, the @code{.org} directive is ignored. To be compatible +with former assemblers, if the section of @var{new-lc} is absolute, +@code{@value{AS}} issues a warning, then pretends the section of @var{new-lc} +is the same as the current subsection. + +@code{.org} may only increase the location counter, or leave it +unchanged; you cannot use @code{.org} to move the location counter +backwards. + +@c double negative used below "not undefined" because this is a specific +@c reference to "undefined" (as SEG_UNKNOWN is called in this manual) +@c section. doc@cygnus.com 18feb91 +Because @code{@value{AS}} tries to assemble programs in one pass, @var{new-lc} +may not be undefined. If you really detest this restriction we eagerly await +a chance to share your improved assembler. + +Beware that the origin is relative to the start of the section, not +to the start of the subsection. This is compatible with other +people's assemblers. + +When the location counter (of the current subsection) is advanced, the +intervening bytes are filled with @var{fill} which should be an +absolute expression. If the comma and @var{fill} are omitted, +@var{fill} defaults to zero. + +@node P2align +@section @code{.p2align[wl] @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter given a power of two +@cindex @code{p2align} directive +Pad the location counter (in the current subsection) to a particular +storage boundary. The first expression (which must be absolute) is the +number of low-order zero bits the location counter must have after +advancement. For example @samp{.p2align 3} advances the location +counter until it a multiple of 8. If the location counter is already a +multiple of 8, no change is needed. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +@cindex @code{p2alignw} directive +@cindex @code{p2alignl} directive +The @code{.p2alignw} and @code{.p2alignl} directives are variants of the +@code{.p2align} directive. The @code{.p2alignw} directive treats the fill +pattern as a two byte word value. The @code{.p2alignl} directives treats the +fill pattern as a four byte longword value. For example, @code{.p2alignw +2,0x368d} will align to a multiple of 4. If it skips two bytes, they will be +filled in with the value 0x368d (the exact placement of the bytes depends upon +the endianness of the processor). If it skips 1 or 3 bytes, the fill value is +undefined. + +@node Psize +@section @code{.psize @var{lines} , @var{columns}} + +@cindex @code{psize} directive +@cindex listing control: paper size +@cindex paper size, for listings +Use this directive to declare the number of lines---and, optionally, the +number of columns---to use for each page, when generating listings. + +If you do not use @code{.psize}, listings use a default line-count +of 60. You may omit the comma and @var{columns} specification; the +default width is 200 columns. + +@code{@value{AS}} generates formfeeds whenever the specified number of +lines is exceeded (or whenever you explicitly request one, using +@code{.eject}). + +If you specify @var{lines} as @code{0}, no formfeeds are generated save +those explicitly specified with @code{.eject}. + +@node Quad +@section @code{.quad @var{bignums}} + +@cindex @code{quad} directive +@code{.quad} expects zero or more bignums, separated by commas. For +each bignum, it emits +@ifclear bignum-16 +an 8-byte integer. If the bignum won't fit in 8 bytes, it prints a +warning message; and just takes the lowest order 8 bytes of the bignum. +@cindex eight-byte integer +@cindex integer, 8-byte + +The term ``quad'' comes from contexts in which a ``word'' is two bytes; +hence @emph{quad}-word for 8 bytes. +@end ifclear +@ifset bignum-16 +a 16-byte integer. If the bignum won't fit in 16 bytes, it prints a +warning message; and just takes the lowest order 16 bytes of the bignum. +@cindex sixteen-byte integer +@cindex integer, 16-byte +@end ifset + +@node Rept +@section @code{.rept @var{count}} + +@cindex @code{rept} directive +Repeat the sequence of lines between the @code{.rept} directive and the next +@code{.endr} directive @var{count} times. + +For example, assembling + +@example + .rept 3 + .long 0 + .endr +@end example + +is equivalent to assembling + +@example + .long 0 + .long 0 + .long 0 +@end example + +@node Sbttl +@section @code{.sbttl "@var{subheading}"} + +@cindex @code{sbttl} directive +@cindex subtitles for listings +@cindex listing control: subtitle +Use @var{subheading} as the title (third line, immediately after the +title line) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +@ifset COFF +@node Scl +@section @code{.scl @var{class}} + +@cindex @code{scl} directive +@cindex symbol storage class (COFF) +@cindex COFF symbol storage class +Set the storage-class value for a symbol. This directive may only be +used inside a @code{.def}/@code{.endef} pair. Storage class may flag +whether a symbol is static or external, or it may record further +symbolic debugging information. +@ifset BOUT + +The @samp{.scl} directive is primarily associated with COFF output; when +configured to generate @code{b.out} output format, @code{@value{AS}} +accepts this directive but ignores it. +@end ifset +@end ifset + +@node Section +@section @code{.section @var{name}} + +@cindex @code{section} directive +@cindex named section +Use the @code{.section} directive to assemble the following code into a section +named @var{name}. + +This directive is only supported for targets that actually support arbitrarily +named sections; on @code{a.out} targets, for example, it is not accepted, even +with a standard @code{a.out} section name. + +@ifset COFF +For COFF targets, the @code{.section} directive is used in one of the following +ways: +@smallexample +.section @var{name}[, "@var{flags}"] +.section @var{name}[, @var{subsegment}] +@end smallexample + +If the optional argument is quoted, it is taken as flags to use for the +section. Each flag is a single character. The following flags are recognized: +@table @code +@item b +bss section (uninitialized data) +@item n +section is not loaded +@item w +writable section +@item d +data section +@item r +read-only section +@item x +executable section +@end table + +If no flags are specified, the default flags depend upon the section name. If +the section name is not recognized, the default will be for the section to be +loaded and writable. + +If the optional argument to the @code{.section} directive is not quoted, it is +taken as a subsegment number (@pxref{Sub-Sections}). +@end ifset + +@ifset ELF +For ELF targets, the @code{.section} directive is used like this: +@smallexample +.section @var{name}[, "@var{flags}"[, @@@var{type}]] +@end smallexample +The optional @var{flags} argument is a quoted string which may contain any +combintion of the following characters: +@table @code +@item a +section is allocatable +@item w +section is writable +@item x +section is executable +@end table + +The optional @var{type} argument may contain one of the following constants: +@table @code +@item @@progbits +section contains data +@item @@nobits +section does not contain data (i.e., section only occupies space) +@end table + +If no flags are specified, the default flags depend upon the section name. If +the section name is not recognized, the default will be for the section to have +none of the above flags: it will not be allocated in memory, nor writable, nor +executable. The section will contain data. + +For ELF targets, the assembler supports another type of @code{.section} +directive for compatibility with the Solaris assembler: +@smallexample +.section "@var{name}"[, @var{flags}...] +@end smallexample +Note that the section name is quoted. There may be a sequence of comma +separated flags: +@table @code +@item #alloc +section is allocatable +@item #write +section is writable +@item #execinstr +section is executable +@end table +@end ifset + +@node Set +@section @code{.set @var{symbol}, @var{expression}} + +@cindex @code{set} directive +@cindex symbol value, setting +Set the value of @var{symbol} to @var{expression}. This +changes @var{symbol}'s value and type to conform to +@var{expression}. If @var{symbol} was flagged as external, it remains +flagged (@pxref{Symbol Attributes}). + +You may @code{.set} a symbol many times in the same assembly. + +If you @code{.set} a global symbol, the value stored in the object +file is the last value stored into it. + +@ifset HPPA +The syntax for @code{set} on the HPPA is +@samp{@var{symbol} .set @var{expression}}. +@end ifset + +@node Short +@section @code{.short @var{expressions}} + +@cindex @code{short} directive +@ifset GENERIC +@code{.short} is normally the same as @samp{.word}. +@xref{Word,,@code{.word}}. + +In some configurations, however, @code{.short} and @code{.word} generate +numbers of different lengths; @pxref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset W16 +@code{.short} is the same as @samp{.word}. @xref{Word,,@code{.word}}. +@end ifset +@ifset W32 +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. +@end ifset +@end ifclear + +@node Single +@section @code{.single @var{flonums}} + +@cindex @code{single} directive +@cindex floating point numbers (single) +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.float}. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@code{@value{AS}} is configured. @xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family, @code{.single} emits 32-bit floating point +numbers in @sc{ieee} format. +@end ifset +@end ifclear + +@ifset COFF +@node Size +@section @code{.size} + +@cindex @code{size} directive +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. +@ifset BOUT + +@samp{.size} is only meaningful when generating COFF format output; when +@code{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@ifclear no-space-dir +@node Skip +@section @code{.skip @var{size} , @var{fill}} + +@cindex @code{skip} directive +@cindex filling memory +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma and +@var{fill} are omitted, @var{fill} is assumed to be zero. This is the same as +@samp{.space}. + +@node Space +@section @code{.space @var{size} , @var{fill}} + +@cindex @code{space} directive +@cindex filling memory +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma +and @var{fill} are omitted, @var{fill} is assumed to be zero. This is the same +as @samp{.skip}. + +@ifset HPPA +@quotation +@emph{Warning:} @code{.space} has a completely different meaning for HPPA +targets; use @code{.block} as a substitute. See @cite{HP9000 Series 800 +Assembly Language Reference Manual} (HP 92432-90001) for the meaning of the +@code{.space} directive. @xref{HPPA Directives,,HPPA Assembler Directives}, +for a summary. +@end quotation +@end ifset +@end ifclear + +@ifset A29K +@ifclear GENERIC +@node Space +@section @code{.space} +@cindex @code{space} directive +@end ifclear +On the AMD 29K, this directive is ignored; it is accepted for +compatibility with other AMD 29K assemblers. + +@quotation +@emph{Warning:} In most versions of the @sc{gnu} assembler, the directive +@code{.space} has the effect of @code{.block} @xref{Machine Dependencies}. +@end quotation +@end ifset + +@ifset have-stabs +@node Stab +@section @code{.stabd, .stabn, .stabs} + +@cindex symbolic debuggers, information for +@cindex @code{stab@var{x}} directives +There are three directives that begin @samp{.stab}. +All emit symbols (@pxref{Symbols}), for use by symbolic debuggers. +The symbols are not entered in the @code{@value{AS}} hash table: they +cannot be referenced elsewhere in the source file. +Up to five fields are required: + +@table @var +@item string +This is the symbol's name. It may contain any character except +@samp{\000}, so is more general than ordinary symbol names. Some +debuggers used to code arbitrarily complex structures into symbol names +using this field. + +@item type +An absolute expression. The symbol's type is set to the low 8 bits of +this expression. Any bit pattern is permitted, but @code{@value{LD}} +and debuggers choke on silly bit patterns. + +@item other +An absolute expression. The symbol's ``other'' attribute is set to the +low 8 bits of this expression. + +@item desc +An absolute expression. The symbol's descriptor is set to the low 16 +bits of this expression. + +@item value +An absolute expression which becomes the symbol's value. +@end table + +If a warning is detected while reading a @code{.stabd}, @code{.stabn}, +or @code{.stabs} statement, the symbol has probably already been created; +you get a half-formed symbol in your object file. This is +compatible with earlier assemblers! + +@table @code +@cindex @code{stabd} directive +@item .stabd @var{type} , @var{other} , @var{desc} + +The ``name'' of the symbol generated is not even an empty string. +It is a null pointer, for compatibility. Older assemblers used a +null pointer so they didn't waste space in object files with empty +strings. + +The symbol's value is set to the location counter, +relocatably. When your program is linked, the value of this symbol +is the address of the location counter when the @code{.stabd} was +assembled. + +@cindex @code{stabn} directive +@item .stabn @var{type} , @var{other} , @var{desc} , @var{value} +The name of the symbol is set to the empty string @code{""}. + +@cindex @code{stabs} directive +@item .stabs @var{string} , @var{type} , @var{other} , @var{desc} , @var{value} +All five fields are specified. +@end table +@end ifset +@c end have-stabs + +@node String +@section @code{.string} "@var{str}" + +@cindex string, copying to object file +@cindex @code{string} directive + +Copy the characters in @var{str} to the object file. You may specify more than +one string to copy, separated by commas. Unless otherwise specified for a +particular machine, the assembler marks the end of each string with a 0 byte. +You can use any of the escape sequences described in @ref{Strings,,Strings}. + +@ifset ELF +@node Symver +@section @code{.symver} +@cindex @code{symver} directive +@cindex symbol versioning +@cindex versions of symbols +Use the @code{.symver} directive to bind symbols to specific version nodes +within a source file. This is only supported on ELF platforms, and is +typically used when assembling files to be linked into a shared library. +There are cases where it may make sense to use this in objects to be bound +into an application itself so as to override a versioned symbol from a +shared library. + +For ELF targets, the @code{.symver} directive is used like this: +@smallexample +.symver @var{name}, @var{name2@@nodename} +@end smallexample +In this case, the symbol @var{name} must exist and be defined within the file +being assembled. The @code{.versym} directive effectively creates a symbol +alias with the name @var{name2@@nodename}, and in fact the main reason that we +just don't try and create a regular alias is that the @var{@@} character isn't +permitted in symbol names. The @var{name2} part of the name is the actual name +of the symbol by which it will be externally referenced. The name @var{name} +itself is merely a name of convenience that is used so that it is possible to +have definitions for multiple versions of a function within a single source +file, and so that the compiler can unambiguously know which version of a +function is being mentioned. The @var{nodename} portion of the alias should be +the name of a node specified in the version script supplied to the linker when +building a shared library. If you are attempting to override a versioned +symbol from a shared library, then @var{nodename} should correspond to the +nodename of the symbol you are trying to override. +@end ifset + +@ifset COFF +@node Tag +@section @code{.tag @var{structname}} + +@cindex COFF structure debugging +@cindex structure debugging, COFF +@cindex @code{tag} directive +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. Tags are used to link structure +definitions in the symbol table with instances of those structures. +@ifset BOUT + +@samp{.tag} is only used when generating COFF format output; when +@code{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@node Text +@section @code{.text @var{subsection}} + +@cindex @code{text} directive +Tells @code{@value{AS}} to assemble the following statements onto the end of +the text subsection numbered @var{subsection}, which is an absolute +expression. If @var{subsection} is omitted, subsection number zero +is used. + +@node Title +@section @code{.title "@var{heading}"} + +@cindex @code{title} directive +@cindex listing control: title line +Use @var{heading} as the title (second line, immediately after the +source file name and pagenumber) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +@ifset COFF +@node Type +@section @code{.type @var{int}} + +@cindex COFF symbol type +@cindex symbol type, COFF +@cindex @code{type} directive +This directive, permitted only within @code{.def}/@code{.endef} pairs, +records the integer @var{int} as the type attribute of a symbol table entry. +@ifset BOUT + +@samp{.type} is associated only with COFF format output; when +@code{@value{AS}} is configured for @code{b.out} output, it accepts this +directive but ignores it. +@end ifset +@end ifset + +@ifset COFF +@node Val +@section @code{.val @var{addr}} + +@cindex @code{val} directive +@cindex COFF value attribute +@cindex value attribute, COFF +This directive, permitted only within @code{.def}/@code{.endef} pairs, +records the address @var{addr} as the value attribute of a symbol table +entry. +@ifset BOUT + +@samp{.val} is used only for COFF output; when @code{@value{AS}} is +configured for @code{b.out}, it accepts this directive but ignores it. +@end ifset +@end ifset + +@node Word +@section @code{.word @var{expressions}} + +@cindex @code{word} directive +This directive expects zero or more @var{expressions}, of any section, +separated by commas. +@ifclear GENERIC +@ifset W32 +For each expression, @code{@value{AS}} emits a 32-bit number. +@end ifset +@ifset W16 +For each expression, @code{@value{AS}} emits a 16-bit number. +@end ifset +@end ifclear +@ifset GENERIC + +The size of the number emitted, and its byte order, +depend on what target computer the assembly is for. +@end ifset + +@c on amd29k, i960, sparc the "special treatment to support compilers" doesn't +@c happen---32-bit addressability, period; no long/short jumps. +@ifset DIFF-TBL-KLUGE +@cindex difference tables altered +@cindex altered difference tables +@quotation +@emph{Warning: Special Treatment to support Compilers} +@end quotation + +@ifset GENERIC +Machines with a 32-bit address space, but that do less than 32-bit +addressing, require the following special treatment. If the machine of +interest to you does 32-bit addressing (or doesn't require it; +@pxref{Machine Dependencies}), you can ignore this issue. + +@end ifset +In order to assemble compiler output into something that works, +@code{@value{AS}} occasionlly does strange things to @samp{.word} directives. +Directives of the form @samp{.word sym1-sym2} are often emitted by +compilers as part of jump tables. Therefore, when @code{@value{AS}} assembles a +directive of the form @samp{.word sym1-sym2}, and the difference between +@code{sym1} and @code{sym2} does not fit in 16 bits, @code{@value{AS}} +creates a @dfn{secondary jump table}, immediately before the next label. +This secondary jump table is preceded by a short-jump to the +first byte after the secondary table. This short-jump prevents the flow +of control from accidentally falling into the new table. Inside the +table is a long-jump to @code{sym2}. The original @samp{.word} +contains @code{sym1} minus the address of the long-jump to +@code{sym2}. + +If there were several occurrences of @samp{.word sym1-sym2} before the +secondary jump table, all of them are adjusted. If there was a +@samp{.word sym3-sym4}, that also did not fit in sixteen bits, a +long-jump to @code{sym4} is included in the secondary jump table, +and the @code{.word} directives are adjusted to contain @code{sym3} +minus the address of the long-jump to @code{sym4}; and so on, for as many +entries in the original jump table as necessary. + +@ifset INTERNALS +@emph{This feature may be disabled by compiling @code{@value{AS}} with the +@samp{-DWORKING_DOT_WORD} option.} This feature is likely to confuse +assembly language programmers. +@end ifset +@end ifset +@c end DIFF-TBL-KLUGE + +@node Deprecated +@section Deprecated Directives + +@cindex deprecated directives +@cindex obsolescent directives +One day these directives won't work. +They are included for compatibility with older assemblers. +@table @t +@item .abort +@item .app-file +@item .line +@end table + +@ifset GENERIC +@node Machine Dependencies +@chapter Machine Dependent Features + +@cindex machine dependencies +The machine instruction sets are (almost by definition) different on +each machine where @code{@value{AS}} runs. Floating point representations +vary as well, and @code{@value{AS}} often supports a few additional +directives or command-line options for compatibility with other +assemblers on a particular platform. Finally, some versions of +@code{@value{AS}} support special pseudo-instructions for branch +optimization. + +This chapter discusses most of these differences, though it does not +include details on any machine's instruction set. For details on that +subject, see the hardware manufacturer's manual. + +@menu +@ifset A29K +* AMD29K-Dependent:: AMD 29K Dependent Features +@end ifset +@ifset D10V +* D10V-Dependent:: D10V Dependent Features +@end ifset +@ifset H8/300 +* H8/300-Dependent:: Hitachi H8/300 Dependent Features +@end ifset +@ifset H8/500 +* H8/500-Dependent:: Hitachi H8/500 Dependent Features +@end ifset +@ifset HPPA +* HPPA-Dependent:: HPPA Dependent Features +@end ifset +@ifset I80386 +* i386-Dependent:: Intel 80386 Dependent Features +@end ifset +@ifset I960 +* i960-Dependent:: Intel 80960 Dependent Features +@end ifset +@ifset M680X0 +* M68K-Dependent:: M680x0 Dependent Features +@end ifset +@ifset MIPS +* MIPS-Dependent:: MIPS Dependent Features +@end ifset +@ifset SH +* SH-Dependent:: Hitachi SH Dependent Features +@end ifset +@ifset SPARC +* Sparc-Dependent:: SPARC Dependent Features +@end ifset +@ifset Z8000 +* Z8000-Dependent:: Z8000 Dependent Features +@end ifset +@ifset VAX +* Vax-Dependent:: VAX Dependent Features +@end ifset +@end menu + +@lowersections +@end ifset + +@c The following major nodes are *sections* in the GENERIC version, *chapters* +@c in single-cpu versions. This is mainly achieved by @lowersections. There is a +@c peculiarity: to preserve cross-references, there must be a node called +@c "Machine Dependencies". Hence the conditional nodenames in each +@c major node below. Node defaulting in makeinfo requires adjacency of +@c node and sectioning commands; hence the repetition of @chapter BLAH +@c in both conditional blocks. + + +@ifset A29K +@include c-a29k.texi +@end ifset + +@ifset Hitachi-all +@ifclear GENERIC +@node Machine Dependencies +@chapter Machine Dependent Features + +The machine instruction sets are different on each Hitachi chip family, +and there are also some syntax differences among the families. This +chapter describes the specific @code{@value{AS}} features for each +family. + +@menu +* H8/300-Dependent:: Hitachi H8/300 Dependent Features +* H8/500-Dependent:: Hitachi H8/500 Dependent Features +* SH-Dependent:: Hitachi SH Dependent Features +@end menu +@lowersections +@end ifclear +@end ifset + +@ifset D10V +@include c-d10v.texi +@end ifset + +@ifset H8/300 +@include c-h8300.texi +@end ifset + +@ifset H8/500 +@include c-h8500.texi +@end ifset + +@ifset HPPA +@include c-hppa.texi +@end ifset + +@ifset I80386 +@include c-i386.texi +@end ifset + +@ifset I960 +@include c-i960.texi +@end ifset + +@ifset M680X0 +@include c-m68k.texi +@end ifset + +@ifset MIPS +@include c-mips.texi +@end ifset + +@ifset NS32K +@include c-ns32k.texi +@end ifset + +@ifset SH +@include c-sh.texi +@end ifset + +@ifset SPARC +@include c-sparc.texi +@end ifset + +@ifset Z8000 +@include c-z8k.texi +@end ifset + +@ifset VAX +@include c-vax.texi +@end ifset + +@ifset GENERIC +@c reverse effect of @down at top of generic Machine-Dep chapter +@raisesections +@end ifset + +@node Reporting Bugs +@chapter Reporting Bugs +@cindex bugs in assembler +@cindex reporting bugs in assembler + +Your bug reports play an essential role in making @code{@value{AS}} reliable. + +Reporting a bug may help you by bringing a solution to your problem, or it may +not. But in any case the principal function of a bug report is to help the +entire community by making the next version of @code{@value{AS}} work better. +Bug reports are your contribution to the maintenance of @code{@value{AS}}. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have you found a bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@cindex fatal signal +@cindex assembler crash +@cindex crash of assembler +@item +If the assembler gets a fatal signal, for any input whatever, that is a +@code{@value{AS}} bug. Reliable assemblers never crash. + +@cindex error on valid input +@item +If @code{@value{AS}} produces an error message for valid input, that is a bug. + +@cindex invalid input +@item +If @code{@value{AS}} does not produce an error message for invalid input, that +is a bug. However, you should note that your idea of ``invalid input'' might +be our idea of ``an extension'' or ``support for traditional practice''. + +@item +If you are an experienced user of assemblers, your suggestions for improvement +of @code{@value{AS}} are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to report bugs +@cindex bug reports +@cindex assembler bugs, reporting + +A number of companies and individuals offer support for @sc{gnu} products. If +you obtained @code{@value{AS}} from a support organization, we recommend you +contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs +distribution. + +In any event, we also recommend that you send bug reports for @code{@value{AS}} +to @samp{bug-gnu-utils@@prep.ai.mit.edu}. + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the problem +and assume that some details do not matter. Thus, you might assume that the +name of a symbol you use in an example does not matter. Well, probably it does +not, but one cannot be sure. Perhaps the bug is a stray memory reference which +happens to fetch from the location where that name is stored in memory; +perhaps, if the name were different, the contents of that location would fool +the assembler into doing the right thing despite the bug. Play it safe and +give a specific, complete example. That is the easiest thing for you to do, +and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix the bug if +it is new to us. Therefore, always write your bug reports on the assumption +that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' Those bug reports are useless, and we urge everyone to +@emph{refuse to respond to them} except to chide the sender to report +bugs properly. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of @code{@value{AS}}. @code{@value{AS}} announces it if you start +it with the @samp{--version} argument. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of @code{@value{AS}}. + +@item +Any patches you may have applied to the @code{@value{AS}} source. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile @code{@value{AS}}---e.g. +``@code{gcc-2.7}''. + +@item +The command arguments you gave the assembler to assemble your example and +observe the bug. To guarantee you will not omit something important, list them +all. A copy of the Makefile (or the output from make) is sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input file that will reproduce the bug. If the bug is observed when +the assembler is invoked via a compiler, send the assembler source, not the +high level language source. Most compilers will produce the assembler source +when run with the @samp{-S} option. If you are using @code{@value{GCC}}, use +the options @samp{-v --save-temps}; this will save the assembler source in a +file with an extension of @file{.s}, and also show you exactly how +@code{@value{AS}} is being run. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that @code{@value{AS}} gets a fatal signal, then we +will certainly notice it. But if the bug is incorrect output, we might not +notice unless it is glaringly wrong. You might as well not give us a chance to +make a mistake. + +Even if the problem you experience is a fatal signal, you should still say so +explicitly. Suppose something strange is going on, such as, your copy of +@code{@value{AS}} is out of synch, or you have encountered a bug in the C +library on your system. (This has happened!) Your copy might crash and ours +would not. If you told us to expect a crash, then when ours fails to crash, we +would know that the bug was not happening for us. If you had not told us to +expect a crash, then we would not be able to draw any conclusion from our +observations. + +@item +If you wish to suggest changes to the @code{@value{AS}} source, send us context +diffs, as generated by @code{diff} with the @samp{-u}, @samp{-c}, or @samp{-p} +option. Always send diffs from the old file to the new file. If you even +discuss something in the @code{@value{AS}} source, refer to it by context, not +by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, and so on. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with a program as complicated as @code{@value{AS}} it is very hard to +construct an example that will make the program follow a certain path through +the code. If you do not send us the example, we will not be able to construct +one, so we will not be able to verify that the bug is fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@node Acknowledgements +@chapter Acknowledgements + +If you have contributed to @code{@value{AS}} and your name isn't listed here, +it is not meant as a slight. We just don't know about it. Send mail to the +maintainer, and we'll correct the situation. Currently +@c (January 1994), +the maintainer is Ken Raeburn (email address @code{raeburn@@cygnus.com}). + +Dean Elsner wrote the original @sc{gnu} assembler for the VAX.@footnote{Any +more details?} + +Jay Fenlason maintained GAS for a while, adding support for GDB-specific debug +information and the 68k series machines, most of the preprocessing pass, and +extensive changes in @file{messages.c}, @file{input-file.c}, @file{write.c}. + +K. Richard Pixley maintained GAS for a while, adding various enhancements and +many bug fixes, including merging support for several processors, breaking GAS +up to handle multiple object file format back ends (including heavy rewrite, +testing, an integration of the coff and b.out back ends), adding configuration +including heavy testing and verification of cross assemblers and file splits +and renaming, converted GAS to strictly ANSI C including full prototypes, added +support for m680[34]0 and cpu32, did considerable work on i960 including a COFF +port (including considerable amounts of reverse engineering), a SPARC opcode +file rewrite, DECstation, rs6000, and hp300hpux host ports, updated ``know'' +assertions and made them work, much other reorganization, cleanup, and lint. + +Ken Raeburn wrote the high-level BFD interface code to replace most of the code +in format-specific I/O modules. + +The original VMS support was contributed by David L. Kashtan. Eric Youngdale +has done much work with it since. + +The Intel 80386 machine description was written by Eliot Dresselhaus. + +Minh Tran-Le at IntelliCorp contributed some AIX 386 support. + +The Motorola 88k machine description was contributed by Devon Bowen of Buffalo +University and Torbjorn Granlund of the Swedish Institute of Computer Science. + +Keith Knowles at the Open Software Foundation wrote the original MIPS back end +(@file{tc-mips.c}, @file{tc-mips.h}), and contributed Rose format support +(which hasn't been merged in yet). Ralph Campbell worked with the MIPS code to +support a.out format. + +Support for the Zilog Z8k and Hitachi H8/300 and H8/500 processors (tc-z8k, +tc-h8300, tc-h8500), and IEEE 695 object file format (obj-ieee), was written by +Steve Chamberlain of Cygnus Support. Steve also modified the COFF back end to +use BFD for some low-level operations, for use with the H8/300 and AMD 29k +targets. + +John Gilmore built the AMD 29000 support, added @code{.include} support, and +simplified the configuration of which versions accept which directives. He +updated the 68k machine description so that Motorola's opcodes always produced +fixed-size instructions (e.g. @code{jsr}), while synthetic instructions +remained shrinkable (@code{jbsr}). John fixed many bugs, including true tested +cross-compilation support, and one bug in relaxation that took a week and +required the proverbial one-bit fix. + +Ian Lance Taylor of Cygnus Support merged the Motorola and MIT syntax for the +68k, completed support for some COFF targets (68k, i386 SVR3, and SCO Unix), +added support for MIPS ECOFF and ELF targets, wrote the initial RS/6000 and +PowerPC assembler, and made a few other minor patches. + +Steve Chamberlain made @code{@value{AS}} able to generate listings. + +Hewlett-Packard contributed support for the HP9000/300. + +Jeff Law wrote GAS and BFD support for the native HPPA object format (SOM) +along with a fairly extensive HPPA testsuite (for both SOM and ELF object +formats). This work was supported by both the Center for Software Science at +the University of Utah and Cygnus Support. + +Support for ELF format files has been worked on by Mark Eichin of Cygnus +Support (original, incomplete implementation for SPARC), Pete Hoogenboom and +Jeff Law at the University of Utah (HPPA mainly), Michael Meissner of the Open +Software Foundation (i386 mainly), and Ken Raeburn of Cygnus Support (sparc, +and some initial 64-bit support). + +Richard Henderson rewrote the Alpha assembler. Klaus Kaempf wrote GAS and BFD +support for openVMS/Alpha. + +Several engineers at Cygnus Support have also provided many small bug fixes and +configuration enhancements. + +Many others have contributed large or small bugfixes and enhancements. If +you have contributed significant work and are not mentioned on this list, and +want to be, let us know. Some of the history has been lost; we are not +intentionally leaving anyone out. + +@node Index +@unnumbered Index + +@printindex cp + +@contents +@bye +@c Local Variables: +@c fill-column: 79 +@c End: diff --git a/contrib/binutils/gas/doc/c-i386.texi b/contrib/binutils/gas/doc/c-i386.texi new file mode 100644 index 0000000..9cd3d4c --- /dev/null +++ b/contrib/binutils/gas/doc/c-i386.texi @@ -0,0 +1,467 @@ +@c Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node i386-Dependent +@chapter 80386 Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter 80386 Dependent Features +@end ifclear + +@cindex i386 support +@cindex i80306 support +@menu +* i386-Options:: Options +* i386-Syntax:: AT&T Syntax versus Intel Syntax +* i386-Opcodes:: Opcode Naming +* i386-Regs:: Register Naming +* i386-prefixes:: Opcode Prefixes +* i386-Memory:: Memory References +* i386-jumps:: Handling of Jump Instructions +* i386-Float:: Floating Point +* i386-16bit:: Writing 16-bit Code +* i386-Notes:: Notes +@end menu + +@node i386-Options +@section Options + +@cindex options for i386 (none) +@cindex i386 options (none) +The 80386 has no machine dependent options. + +@node i386-Syntax +@section AT&T Syntax versus Intel Syntax + +@cindex i386 syntax compatibility +@cindex syntax compatibility, i386 +In order to maintain compatibility with the output of @code{@value{GCC}}, +@code{@value{AS}} supports AT&T System V/386 assembler syntax. This is quite +different from Intel syntax. We mention these differences because +almost all 80386 documents used only Intel syntax. Notable differences +between the two syntaxes are: + +@cindex immediate operands, i386 +@cindex i386 immediate operands +@cindex register operands, i386 +@cindex i386 register operands +@cindex jump/call operands, i386 +@cindex i386 jump/call operands +@cindex operand delimiters, i386 +@itemize @bullet +@item +AT&T immediate operands are preceded by @samp{$}; Intel immediate +operands are undelimited (Intel @samp{push 4} is AT&T @samp{pushl $4}). +AT&T register operands are preceded by @samp{%}; Intel register operands +are undelimited. AT&T absolute (as opposed to PC relative) jump/call +operands are prefixed by @samp{*}; they are undelimited in Intel syntax. + +@cindex i386 source, destination operands +@cindex source, destination operands; i386 +@item +AT&T and Intel syntax use the opposite order for source and destination +operands. Intel @samp{add eax, 4} is @samp{addl $4, %eax}. The +@samp{source, dest} convention is maintained for compatibility with +previous Unix assemblers. + +@cindex opcode suffixes, i386 +@cindex sizes operands, i386 +@cindex i386 size suffixes +@item +In AT&T syntax the size of memory operands is determined from the last +character of the opcode name. Opcode suffixes of @samp{b}, @samp{w}, +and @samp{l} specify byte (8-bit), word (16-bit), and long (32-bit) +memory references. Intel syntax accomplishes this by prefixes memory +operands (@emph{not} the opcodes themselves) with @samp{byte ptr}, +@samp{word ptr}, and @samp{dword ptr}. Thus, Intel @samp{mov al, byte +ptr @var{foo}} is @samp{movb @var{foo}, %al} in AT&T syntax. + +@cindex return instructions, i386 +@cindex i386 jump, call, return +@item +Immediate form long jumps and calls are +@samp{lcall/ljmp $@var{section}, $@var{offset}} in AT&T syntax; the +Intel syntax is +@samp{call/jmp far @var{section}:@var{offset}}. Also, the far return +instruction +is @samp{lret $@var{stack-adjust}} in AT&T syntax; Intel syntax is +@samp{ret far @var{stack-adjust}}. + +@cindex sections, i386 +@cindex i386 sections +@item +The AT&T assembler does not provide support for multiple section +programs. Unix style systems expect all programs to be single sections. +@end itemize + +@node i386-Opcodes +@section Opcode Naming + +@cindex i386 opcode naming +@cindex opcode naming, i386 +Opcode names are suffixed with one character modifiers which specify the +size of operands. The letters @samp{b}, @samp{w}, and @samp{l} specify +byte, word, and long operands. If no suffix is specified by an +instruction and it contains no memory operands then @code{@value{AS}} tries to +fill in the missing suffix based on the destination register operand +(the last one by convention). Thus, @samp{mov %ax, %bx} is equivalent +to @samp{movw %ax, %bx}; also, @samp{mov $1, %bx} is equivalent to +@samp{movw $1, %bx}. Note that this is incompatible with the AT&T Unix +assembler which assumes that a missing opcode suffix implies long +operand size. (This incompatibility does not affect compiler output +since compilers always explicitly specify the opcode suffix.) + +Almost all opcodes have the same names in AT&T and Intel format. There +are a few exceptions. The sign extend and zero extend instructions need +two sizes to specify them. They need a size to sign/zero extend +@emph{from} and a size to zero extend @emph{to}. This is accomplished +by using two opcode suffixes in AT&T syntax. Base names for sign extend +and zero extend are @samp{movs@dots{}} and @samp{movz@dots{}} in AT&T +syntax (@samp{movsx} and @samp{movzx} in Intel syntax). The opcode +suffixes are tacked on to this base name, the @emph{from} suffix before +the @emph{to} suffix. Thus, @samp{movsbl %al, %edx} is AT&T syntax for +``move sign extend @emph{from} %al @emph{to} %edx.'' Possible suffixes, +thus, are @samp{bl} (from byte to long), @samp{bw} (from byte to word), +and @samp{wl} (from word to long). + +@cindex conversion instructions, i386 +@cindex i386 conversion instructions +The Intel-syntax conversion instructions + +@itemize @bullet +@item +@samp{cbw} --- sign-extend byte in @samp{%al} to word in @samp{%ax}, + +@item +@samp{cwde} --- sign-extend word in @samp{%ax} to long in @samp{%eax}, + +@item +@samp{cwd} --- sign-extend word in @samp{%ax} to long in @samp{%dx:%ax}, + +@item +@samp{cdq} --- sign-extend dword in @samp{%eax} to quad in @samp{%edx:%eax}, +@end itemize + +@noindent +are called @samp{cbtw}, @samp{cwtl}, @samp{cwtd}, and @samp{cltd} in +AT&T naming. @code{@value{AS}} accepts either naming for these instructions. + +@cindex jump instructions, i386 +@cindex call instructions, i386 +Far call/jump instructions are @samp{lcall} and @samp{ljmp} in +AT&T syntax, but are @samp{call far} and @samp{jump far} in Intel +convention. + +@node i386-Regs +@section Register Naming + +@cindex i386 registers +@cindex registers, i386 +Register operands are always prefixes with @samp{%}. The 80386 registers +consist of + +@itemize @bullet +@item +the 8 32-bit registers @samp{%eax} (the accumulator), @samp{%ebx}, +@samp{%ecx}, @samp{%edx}, @samp{%edi}, @samp{%esi}, @samp{%ebp} (the +frame pointer), and @samp{%esp} (the stack pointer). + +@item +the 8 16-bit low-ends of these: @samp{%ax}, @samp{%bx}, @samp{%cx}, +@samp{%dx}, @samp{%di}, @samp{%si}, @samp{%bp}, and @samp{%sp}. + +@item +the 8 8-bit registers: @samp{%ah}, @samp{%al}, @samp{%bh}, +@samp{%bl}, @samp{%ch}, @samp{%cl}, @samp{%dh}, and @samp{%dl} (These +are the high-bytes and low-bytes of @samp{%ax}, @samp{%bx}, +@samp{%cx}, and @samp{%dx}) + +@item +the 6 section registers @samp{%cs} (code section), @samp{%ds} +(data section), @samp{%ss} (stack section), @samp{%es}, @samp{%fs}, +and @samp{%gs}. + +@item +the 3 processor control registers @samp{%cr0}, @samp{%cr2}, and +@samp{%cr3}. + +@item +the 6 debug registers @samp{%db0}, @samp{%db1}, @samp{%db2}, +@samp{%db3}, @samp{%db6}, and @samp{%db7}. + +@item +the 2 test registers @samp{%tr6} and @samp{%tr7}. + +@item +the 8 floating point register stack @samp{%st} or equivalently +@samp{%st(0)}, @samp{%st(1)}, @samp{%st(2)}, @samp{%st(3)}, +@samp{%st(4)}, @samp{%st(5)}, @samp{%st(6)}, and @samp{%st(7)}. +@end itemize + +@node i386-prefixes +@section Opcode Prefixes + +@cindex i386 opcode prefixes +@cindex opcode prefixes, i386 +@cindex prefixes, i386 +Opcode prefixes are used to modify the following opcode. They are used +to repeat string instructions, to provide section overrides, to perform +bus lock operations, and to give operand and address size (16-bit +operands are specified in an instruction by prefixing what would +normally be 32-bit operands with a ``operand size'' opcode prefix). +Opcode prefixes are usually given as single-line instructions with no +operands, and must directly precede the instruction they act upon. For +example, the @samp{scas} (scan string) instruction is repeated with: +@smallexample + repne + scas +@end smallexample + +Here is a list of opcode prefixes: + +@cindex section override prefixes, i386 +@itemize @bullet +@item +Section override prefixes @samp{cs}, @samp{ds}, @samp{ss}, @samp{es}, +@samp{fs}, @samp{gs}. These are automatically added by specifying +using the @var{section}:@var{memory-operand} form for memory references. + +@cindex size prefixes, i386 +@item +Operand/Address size prefixes @samp{data16} and @samp{addr16} +change 32-bit operands/addresses into 16-bit operands/addresses. Note +that 16-bit addressing modes (i.e. 8086 and 80286 addressing modes) +are not supported (yet). + +@cindex bus lock prefixes, i386 +@cindex inhibiting interrupts, i386 +@item +The bus lock prefix @samp{lock} inhibits interrupts during +execution of the instruction it precedes. (This is only valid with +certain instructions; see a 80386 manual for details). + +@cindex coprocessor wait, i386 +@item +The wait for coprocessor prefix @samp{wait} waits for the +coprocessor to complete the current instruction. This should never be +needed for the 80386/80387 combination. + +@cindex repeat prefixes, i386 +@item +The @samp{rep}, @samp{repe}, and @samp{repne} prefixes are added +to string instructions to make them repeat @samp{%ecx} times. +@end itemize + +@node i386-Memory +@section Memory References + +@cindex i386 memory references +@cindex memory references, i386 +An Intel syntax indirect memory reference of the form + +@smallexample +@var{section}:[@var{base} + @var{index}*@var{scale} + @var{disp}] +@end smallexample + +@noindent +is translated into the AT&T syntax + +@smallexample +@var{section}:@var{disp}(@var{base}, @var{index}, @var{scale}) +@end smallexample + +@noindent +where @var{base} and @var{index} are the optional 32-bit base and +index registers, @var{disp} is the optional displacement, and +@var{scale}, taking the values 1, 2, 4, and 8, multiplies @var{index} +to calculate the address of the operand. If no @var{scale} is +specified, @var{scale} is taken to be 1. @var{section} specifies the +optional section register for the memory operand, and may override the +default section register (see a 80386 manual for section register +defaults). Note that section overrides in AT&T syntax @emph{must} have +be preceded by a @samp{%}. If you specify a section override which +coincides with the default section register, @code{@value{AS}} does @emph{not} +output any section register override prefixes to assemble the given +instruction. Thus, section overrides can be specified to emphasize which +section register is used for a given memory operand. + +Here are some examples of Intel and AT&T style memory references: + +@table @asis +@item AT&T: @samp{-4(%ebp)}, Intel: @samp{[ebp - 4]} +@var{base} is @samp{%ebp}; @var{disp} is @samp{-4}. @var{section} is +missing, and the default section is used (@samp{%ss} for addressing with +@samp{%ebp} as the base register). @var{index}, @var{scale} are both missing. + +@item AT&T: @samp{foo(,%eax,4)}, Intel: @samp{[foo + eax*4]} +@var{index} is @samp{%eax} (scaled by a @var{scale} 4); @var{disp} is +@samp{foo}. All other fields are missing. The section register here +defaults to @samp{%ds}. + +@item AT&T: @samp{foo(,1)}; Intel @samp{[foo]} +This uses the value pointed to by @samp{foo} as a memory operand. +Note that @var{base} and @var{index} are both missing, but there is only +@emph{one} @samp{,}. This is a syntactic exception. + +@item AT&T: @samp{%gs:foo}; Intel @samp{gs:foo} +This selects the contents of the variable @samp{foo} with section +register @var{section} being @samp{%gs}. +@end table + +Absolute (as opposed to PC relative) call and jump operands must be +prefixed with @samp{*}. If no @samp{*} is specified, @code{@value{AS}} +always chooses PC relative addressing for jump/call labels. + +Any instruction that has a memory operand @emph{must} specify its size (byte, +word, or long) with an opcode suffix (@samp{b}, @samp{w}, or @samp{l}, +respectively). + +@node i386-jumps +@section Handling of Jump Instructions + +@cindex jump optimization, i386 +@cindex i386 jump optimization +Jump instructions are always optimized to use the smallest possible +displacements. This is accomplished by using byte (8-bit) displacement +jumps whenever the target is sufficiently close. If a byte displacement +is insufficient a long (32-bit) displacement is used. We do not support +word (16-bit) displacement jumps (i.e. prefixing the jump instruction +with the @samp{addr16} opcode prefix), since the 80386 insists upon masking +@samp{%eip} to 16 bits after the word displacement is added. + +Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz}, +@samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in byte +displacements, so that if you use these instructions (@code{@value{GCC}} does +not use them) you may get an error message (and incorrect code). The AT&T +80386 assembler tries to get around this problem by expanding @samp{jcxz foo} +to + +@smallexample + jcxz cx_zero + jmp cx_nonzero +cx_zero: jmp foo +cx_nonzero: +@end smallexample + +@node i386-Float +@section Floating Point + +@cindex i386 floating point +@cindex floating point, i386 +All 80387 floating point types except packed BCD are supported. +(BCD support may be added without much difficulty). These data +types are 16-, 32-, and 64- bit integers, and single (32-bit), +double (64-bit), and extended (80-bit) precision floating point. +Each supported type has an opcode suffix and a constructor +associated with it. Opcode suffixes specify operand's data +types. Constructors build these data types into memory. + +@cindex @code{float} directive, i386 +@cindex @code{single} directive, i386 +@cindex @code{double} directive, i386 +@cindex @code{tfloat} directive, i386 +@itemize @bullet +@item +Floating point constructors are @samp{.float} or @samp{.single}, +@samp{.double}, and @samp{.tfloat} for 32-, 64-, and 80-bit formats. +These correspond to opcode suffixes @samp{s}, @samp{l}, and @samp{t}. +@samp{t} stands for temporary real, and that the 80387 only supports +this format via the @samp{fldt} (load temporary real to stack top) and +@samp{fstpt} (store temporary real and pop stack) instructions. + +@cindex @code{word} directive, i386 +@cindex @code{long} directive, i386 +@cindex @code{int} directive, i386 +@cindex @code{quad} directive, i386 +@item +Integer constructors are @samp{.word}, @samp{.long} or @samp{.int}, and +@samp{.quad} for the 16-, 32-, and 64-bit integer formats. The corresponding +opcode suffixes are @samp{s} (single), @samp{l} (long), and @samp{q} +(quad). As with the temporary real format the 64-bit @samp{q} format is +only present in the @samp{fildq} (load quad integer to stack top) and +@samp{fistpq} (store quad integer and pop stack) instructions. +@end itemize + +Register to register operations do not require opcode suffixes, +so that @samp{fst %st, %st(1)} is equivalent to @samp{fstl %st, %st(1)}. + +@cindex i386 @code{fwait} instruction +@cindex @code{fwait instruction}, i386 +Since the 80387 automatically synchronizes with the 80386 @samp{fwait} +instructions are almost never needed (this is not the case for the +80286/80287 and 8086/8087 combinations). Therefore, @code{@value{AS}} suppresses +the @samp{fwait} instruction whenever it is implicitly selected by one +of the @samp{fn@dots{}} instructions. For example, @samp{fsave} and +@samp{fnsave} are treated identically. In general, all the @samp{fn@dots{}} +instructions are made equivalent to @samp{f@dots{}} instructions. If +@samp{fwait} is desired it must be explicitly coded. + +@node i386-16bit +@section Writing 16-bit Code + +@cindex i386 16-bit code +@cindex 16-bit code, i386 +@cindex real-mode code, i386 +@cindex @code{code16} directive, i386 +@cindex @code{code32} directive, i386 +While GAS normally writes only ``pure'' 32-bit i386 code, it has limited +support for writing code to run in real mode or in 16-bit protected mode +code segments. To do this, insert a @samp{.code16} directive before the +assembly language instructions to be run in 16-bit mode. You can switch +GAS back to writing normal 32-bit code with the @samp{.code32} directive. + +GAS understands exactly the same assembly language syntax in 16-bit mode as +in 32-bit mode. The function of any given instruction is exactly the same +regardless of mode, as long as the resulting object code is executed in the +mode for which GAS wrote it. So, for example, the @samp{ret} mnemonic +produces a 32-bit return instruction regardless of whether it is to be run +in 16-bit or 32-bit mode. (If GAS is in 16-bit mode, it will add an +operand size prefix to the instruction to force it to be a 32-bit return.) + +This means, for one thing, that you can use @sc{gnu} @sc{cc} to write code to be run +in real mode or 16-bit protected mode. Just insert the statement +@samp{asm(".code16");} at the beginning of your C source file, and while +@sc{gnu} @sc{cc} will still be generating 32-bit code, GAS will automatically add +all the necessary size prefixes to make that code run in 16-bit mode. Of +course, since @sc{gnu} @sc{cc} only writes small-model code (it doesn't know how to +attach segment selectors to pointers like native x86 compilers do), any +16-bit code you write with @sc{gnu} @sc{cc} will essentially be limited to a 64K +address space. Also, there will be a code size and performance penalty +due to all the extra address and operand size prefixes GAS has to add to +the instructions. + +Note that placing GAS in 16-bit mode does not mean that the resulting +code will necessarily run on a 16-bit pre-80386 processor. To write code +that runs on such a processor, you would have to refrain from using +@emph{any} 32-bit constructs which require GAS to output address or +operand size prefixes. At the moment this would be rather difficult, +because GAS currently supports @emph{only} 32-bit addressing modes: when +writing 16-bit code, it @emph{always} outputs address size prefixes for any +instruction that uses a non-register addressing mode. So you can write +code that runs on 16-bit processors, but only if that code never references +memory. + +@node i386-Notes +@section Notes + +@cindex i386 @code{mul}, @code{imul} instructions +@cindex @code{mul} instruction, i386 +@cindex @code{imul} instruction, i386 +There is some trickery concerning the @samp{mul} and @samp{imul} +instructions that deserves mention. The 16-, 32-, and 64-bit expanding +multiplies (base opcode @samp{0xf6}; extension 4 for @samp{mul} and 5 +for @samp{imul}) can be output only in the one operand form. Thus, +@samp{imul %ebx, %eax} does @emph{not} select the expanding multiply; +the expanding multiply would clobber the @samp{%edx} register, and this +would confuse @code{@value{GCC}} output. Use @samp{imul %ebx} to get the +64-bit product in @samp{%edx:%eax}. + +We have added a two operand form of @samp{imul} when the first operand +is an immediate mode expression and the second operand is a register. +This is just a shorthand, so that, multiplying @samp{%eax} by 69, for +example, can be done with @samp{imul $69, %eax} rather than @samp{imul +$69, %eax, %eax}. + diff --git a/contrib/binutils/gas/doc/c-sh.texi b/contrib/binutils/gas/doc/c-sh.texi new file mode 100644 index 0000000..d7b410b --- /dev/null +++ b/contrib/binutils/gas/doc/c-sh.texi @@ -0,0 +1,265 @@ +@c Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@page +@node SH-Dependent +@chapter Hitachi SH Dependent Features + +@cindex SH support +@menu +* SH Options:: Options +* SH Syntax:: Syntax +* SH Floating Point:: Floating Point +* SH Directives:: SH Machine Directives +* SH Opcodes:: Opcodes +@end menu + +@node SH Options +@section Options + +@cindex SH options (none) +@cindex options, SH (none) +@code{@value{AS}} has no additional command-line options for the Hitachi +SH family. + +@node SH Syntax +@section Syntax + +@menu +* SH-Chars:: Special Characters +* SH-Regs:: Register Names +* SH-Addressing:: Addressing Modes +@end menu + +@node SH-Chars +@subsection Special Characters + +@cindex line comment character, SH +@cindex SH line comment character +@samp{!} is the line comment character. + +@cindex line separator, SH +@cindex statement separator, SH +@cindex SH line separator +You can use @samp{;} instead of a newline to separate statements. + +@cindex symbol names, @samp{$} in +@cindex @code{$} in symbol names +Since @samp{$} has no special meaning, you may use it in symbol names. + +@node SH-Regs +@subsection Register Names + +@cindex SH registers +@cindex registers, SH +You can use the predefined symbols @samp{r0}, @samp{r1}, @samp{r2}, +@samp{r3}, @samp{r4}, @samp{r5}, @samp{r6}, @samp{r7}, @samp{r8}, +@samp{r9}, @samp{r10}, @samp{r11}, @samp{r12}, @samp{r13}, @samp{r14}, +and @samp{r15} to refer to the SH registers. + +The SH also has these control registers: + +@table @code +@item pr +procedure register (holds return address) + +@item pc +program counter + +@item mach +@itemx macl +high and low multiply accumulator registers + +@item sr +status register + +@item gbr +global base register + +@item vbr +vector base register (for interrupt vectors) +@end table + +@node SH-Addressing +@subsection Addressing Modes + +@cindex addressing modes, SH +@cindex SH addressing modes +@code{@value{AS}} understands the following addressing modes for the SH. +@code{R@var{n}} in the following refers to any of the numbered +registers, but @emph{not} the control registers. + +@table @code +@item R@var{n} +Register direct + +@item @@R@var{n} +Register indirect + +@item @@-R@var{n} +Register indirect with pre-decrement + +@item @@R@var{n}+ +Register indirect with post-increment + +@item @@(@var{disp}, R@var{n}) +Register indirect with displacement + +@item @@(R0, R@var{n}) +Register indexed + +@item @@(@var{disp}, GBR) +@code{GBR} offset + +@item @@(R0, GBR) +GBR indexed + +@item @var{addr} +@itemx @@(@var{disp}, PC) +PC relative address (for branch or for addressing memory). The +@code{@value{AS}} implementation allows you to use the simpler form +@var{addr} anywhere a PC relative address is called for; the alternate +form is supported for compatibility with other assemblers. + +@item #@var{imm} +Immediate data +@end table + +@node SH Floating Point +@section Floating Point + +@cindex floating point, SH (@sc{ieee}) +@cindex SH floating point (@sc{ieee}) +The SH family has no hardware floating point, but the @code{.float} +directive generates @sc{ieee} floating-point numbers for compatibility +with other development tools. + +@node SH Directives +@section SH Machine Directives + +@cindex SH machine directives (none) +@cindex machine directives, SH (none) +@cindex @code{word} directive, SH +@cindex @code{int} directive, SH +@code{@value{AS}} has no machine-dependent directives for the SH. + +@node SH Opcodes +@section Opcodes + +@cindex SH opcode summary +@cindex opcode summary, SH +@cindex mnemonics, SH +@cindex instruction summary, SH +For detailed information on the SH machine instruction set, see +@cite{SH-Microcomputer User's Manual} (Hitachi Micro Systems, Inc.). + +@code{@value{AS}} implements all the standard SH opcodes. No additional +pseudo-instructions are needed on this family. Note, however, that +because @code{@value{AS}} supports a simpler form of PC-relative +addressing, you may simply write (for example) + +@example +mov.l bar,r0 +@end example + +@noindent +where other assemblers might require an explicit displacement to +@code{bar} from the program counter: + +@example +mov.l @@(@var{disp}, PC) +@end example + +@ifset SMALL +@c this table, due to the multi-col faking and hardcoded order, looks silly +@c except in smallbook. See comments below "@set SMALL" near top of this file. + +Here is a summary of SH opcodes: + +@page +@smallexample +@i{Legend:} +Rn @r{a numbered register} +Rm @r{another numbered register} +#imm @r{immediate data} +disp @r{displacement} +disp8 @r{8-bit displacement} +disp12 @r{12-bit displacement} + +add #imm,Rn lds.l @@Rn+,PR +add Rm,Rn mac.w @@Rm+,@@Rn+ +addc Rm,Rn mov #imm,Rn +addv Rm,Rn mov Rm,Rn +and #imm,R0 mov.b Rm,@@(R0,Rn) +and Rm,Rn mov.b Rm,@@-Rn +and.b #imm,@@(R0,GBR) mov.b Rm,@@Rn +bf disp8 mov.b @@(disp,Rm),R0 +bra disp12 mov.b @@(disp,GBR),R0 +bsr disp12 mov.b @@(R0,Rm),Rn +bt disp8 mov.b @@Rm+,Rn +clrmac mov.b @@Rm,Rn +clrt mov.b R0,@@(disp,Rm) +cmp/eq #imm,R0 mov.b R0,@@(disp,GBR) +cmp/eq Rm,Rn mov.l Rm,@@(disp,Rn) +cmp/ge Rm,Rn mov.l Rm,@@(R0,Rn) +cmp/gt Rm,Rn mov.l Rm,@@-Rn +cmp/hi Rm,Rn mov.l Rm,@@Rn +cmp/hs Rm,Rn mov.l @@(disp,Rn),Rm +cmp/pl Rn mov.l @@(disp,GBR),R0 +cmp/pz Rn mov.l @@(disp,PC),Rn +cmp/str Rm,Rn mov.l @@(R0,Rm),Rn +div0s Rm,Rn mov.l @@Rm+,Rn +div0u mov.l @@Rm,Rn +div1 Rm,Rn mov.l R0,@@(disp,GBR) +exts.b Rm,Rn mov.w Rm,@@(R0,Rn) +exts.w Rm,Rn mov.w Rm,@@-Rn +extu.b Rm,Rn mov.w Rm,@@Rn +extu.w Rm,Rn mov.w @@(disp,Rm),R0 +jmp @@Rn mov.w @@(disp,GBR),R0 +jsr @@Rn mov.w @@(disp,PC),Rn +ldc Rn,GBR mov.w @@(R0,Rm),Rn +ldc Rn,SR mov.w @@Rm+,Rn +ldc Rn,VBR mov.w @@Rm,Rn +ldc.l @@Rn+,GBR mov.w R0,@@(disp,Rm) +ldc.l @@Rn+,SR mov.w R0,@@(disp,GBR) +ldc.l @@Rn+,VBR mova @@(disp,PC),R0 +lds Rn,MACH movt Rn +lds Rn,MACL muls Rm,Rn +lds Rn,PR mulu Rm,Rn +lds.l @@Rn+,MACH neg Rm,Rn +lds.l @@Rn+,MACL negc Rm,Rn +@page +nop stc VBR,Rn +not Rm,Rn stc.l GBR,@@-Rn +or #imm,R0 stc.l SR,@@-Rn +or Rm,Rn stc.l VBR,@@-Rn +or.b #imm,@@(R0,GBR) sts MACH,Rn +rotcl Rn sts MACL,Rn +rotcr Rn sts PR,Rn +rotl Rn sts.l MACH,@@-Rn +rotr Rn sts.l MACL,@@-Rn +rte sts.l PR,@@-Rn +rts sub Rm,Rn +sett subc Rm,Rn +shal Rn subv Rm,Rn +shar Rn swap.b Rm,Rn +shll Rn swap.w Rm,Rn +shll16 Rn tas.b @@Rn +shll2 Rn trapa #imm +shll8 Rn tst #imm,R0 +shlr Rn tst Rm,Rn +shlr16 Rn tst.b #imm,@@(R0,GBR) +shlr2 Rn xor #imm,R0 +shlr8 Rn xor Rm,Rn +sleep xor.b #imm,@@(R0,GBR) +stc GBR,Rn xtrct Rm,Rn +stc SR,Rn +@end smallexample +@end ifset + +@ifset Hitachi-all +@ifclear GENERIC +@raisesections +@end ifclear +@end ifset + diff --git a/contrib/binutils/gas/doc/c-z8k.texi b/contrib/binutils/gas/doc/c-z8k.texi new file mode 100644 index 0000000..1fb10e3 --- /dev/null +++ b/contrib/binutils/gas/doc/c-z8k.texi @@ -0,0 +1,380 @@ +@c Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node Z8000-Dependent +@chapter Z8000 Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter Z8000 Dependent Features +@end ifclear + +@cindex Z8000 support +The Z8000 @value{AS} supports both members of the Z8000 family: the +unsegmented Z8002, with 16 bit addresses, and the segmented Z8001 with +24 bit addresses. + +When the assembler is in unsegmented mode (specified with the +@code{unsegm} directive), an address takes up one word (16 bit) +sized register. When the assembler is in segmented mode (specified with +the @code{segm} directive), a 24-bit address takes up a long (32 bit) +register. @xref{Z8000 Directives,,Assembler Directives for the Z8000}, +for a list of other Z8000 specific assembler directives. + +@menu +* Z8000 Options:: No special command-line options for Z8000 +* Z8000 Syntax:: Assembler syntax for the Z8000 +* Z8000 Directives:: Special directives for the Z8000 +* Z8000 Opcodes:: Opcodes +@end menu + +@node Z8000 Options +@section Options + +@cindex Z8000 options +@cindex options, Z8000 +@code{@value{AS}} has no additional command-line options for the Zilog +Z8000 family. + +@node Z8000 Syntax +@section Syntax +@menu +* Z8000-Chars:: Special Characters +* Z8000-Regs:: Register Names +* Z8000-Addressing:: Addressing Modes +@end menu + +@node Z8000-Chars +@subsection Special Characters + +@cindex line comment character, Z8000 +@cindex Z8000 line comment character +@samp{!} is the line comment character. + +@cindex line separator, Z8000 +@cindex statement separator, Z8000 +@cindex Z8000 line separator +You can use @samp{;} instead of a newline to separate statements. + +@node Z8000-Regs +@subsection Register Names + +@cindex Z8000 registers +@cindex registers, Z8000 +The Z8000 has sixteen 16 bit registers, numbered 0 to 15. You can refer +to different sized groups of registers by register number, with the +prefix @samp{r} for 16 bit registers, @samp{rr} for 32 bit registers and +@samp{rq} for 64 bit registers. You can also refer to the contents of +the first eight (of the sixteen 16 bit registers) by bytes. They are +named @samp{r@var{n}h} and @samp{r@var{n}l}. + +@smallexample +@exdent @emph{byte registers} +r0l r0h r1h r1l r2h r2l r3h r3l +r4h r4l r5h r5l r6h r6l r7h r7l + +@exdent @emph{word registers} +r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 + +@exdent @emph{long word registers} +rr0 rr2 rr4 rr6 rr8 rr10 rr12 rr14 + +@exdent @emph{quad word registers} +rq0 rq4 rq8 rq12 +@end smallexample + +@node Z8000-Addressing +@subsection Addressing Modes + +@cindex addressing modes, Z8000 +@cindex Z800 addressing modes +@value{AS} understands the following addressing modes for the Z8000: + +@table @code +@item r@var{n} +Register direct + +@item @@r@var{n} +Indirect register + +@item @var{addr} +Direct: the 16 bit or 24 bit address (depending on whether the assembler +is in segmented or unsegmented mode) of the operand is in the instruction. + +@item address(r@var{n}) +Indexed: the 16 or 24 bit address is added to the 16 bit register to produce +the final address in memory of the operand. + +@item r@var{n}(#@var{imm}) +Base Address: the 16 or 24 bit register is added to the 16 bit sign +extended immediate displacement to produce the final address in memory +of the operand. + +@item r@var{n}(r@var{m}) +Base Index: the 16 or 24 bit register r@var{n} is added to the sign +extended 16 bit index register r@var{m} to produce the final address in +memory of the operand. + +@item #@var{xx} +Immediate data @var{xx}. +@end table + +@node Z8000 Directives +@section Assembler Directives for the Z8000 + +@cindex Z8000 directives +@cindex directives, Z8000 +The Z8000 port of @value{AS} includes these additional assembler directives, +for compatibility with other Z8000 assemblers. As shown, these do not +begin with @samp{.} (unlike the ordinary @value{AS} directives). + +@table @code +@kindex segm +@item segm +Generates code for the segmented Z8001. + +@kindex unsegm +@item unsegm +Generates code for the unsegmented Z8002. + +@kindex name +@item name +Synonym for @code{.file} + +@kindex global +@item global +Synonym for @code{.global} + +@kindex wval +@item wval +Synonym for @code{.word} + +@kindex lval +@item lval +Synonym for @code{.long} + +@kindex bval +@item bval +Synonym for @code{.byte} + +@kindex sval +@item sval +Assemble a string. @code{sval} expects one string literal, delimited by +single quotes. It assembles each byte of the string into consecutive +addresses. You can use the escape sequence @samp{%@var{xx}} (where +@var{xx} represents a two-digit hexadecimal number) to represent the +character whose @sc{ascii} value is @var{xx}. Use this feature to +describe single quote and other characters that may not appear in string +literals as themselves. For example, the C statement @w{@samp{char *a = +"he said \"it's 50% off\"";}} is represented in Z8000 assembly language +(shown with the assembler output in hex at the left) as + +@iftex +@begingroup +@let@nonarrowing=@comment +@end iftex +@smallexample +68652073 sval 'he said %22it%27s 50%25 off%22%00' +61696420 +22697427 +73203530 +25206F66 +662200 +@end smallexample +@iftex +@endgroup +@end iftex + +@kindex rsect +@item rsect +synonym for @code{.section} + +@kindex block +@item block +synonym for @code{.space} + +@kindex even +@item even +special case of @code{.align}; aligns output to even byte boundary. +@end table + +@node Z8000 Opcodes +@section Opcodes + +@cindex Z8000 opcode summary +@cindex opcode summary, Z8000 +@cindex mnemonics, Z8000 +@cindex instruction summary, Z8000 +For detailed information on the Z8000 machine instruction set, see +@cite{Z8000 Technical Manual}. + +@ifset SMALL +@c this table, due to the multi-col faking and hardcoded order, looks silly +@c except in smallbook. See comments below "@set SMALL" near top of this file. + +The following table summarizes the opcodes and their arguments: +@iftex +@begingroup +@let@nonarrowing=@comment +@end iftex +@smallexample + + rs @r{16 bit source register} + rd @r{16 bit destination register} + rbs @r{8 bit source register} + rbd @r{8 bit destination register} + rrs @r{32 bit source register} + rrd @r{32 bit destination register} + rqs @r{64 bit source register} + rqd @r{64 bit destination register} + addr @r{16/24 bit address} + imm @r{immediate data} + +adc rd,rs clrb addr cpsir @@rd,@@rs,rr,cc +adcb rbd,rbs clrb addr(rd) cpsirb @@rd,@@rs,rr,cc +add rd,@@rs clrb rbd dab rbd +add rd,addr com @@rd dbjnz rbd,disp7 +add rd,addr(rs) com addr dec @@rd,imm4m1 +add rd,imm16 com addr(rd) dec addr(rd),imm4m1 +add rd,rs com rd dec addr,imm4m1 +addb rbd,@@rs comb @@rd dec rd,imm4m1 +addb rbd,addr comb addr decb @@rd,imm4m1 +addb rbd,addr(rs) comb addr(rd) decb addr(rd),imm4m1 +addb rbd,imm8 comb rbd decb addr,imm4m1 +addb rbd,rbs comflg flags decb rbd,imm4m1 +addl rrd,@@rs cp @@rd,imm16 di i2 +addl rrd,addr cp addr(rd),imm16 div rrd,@@rs +addl rrd,addr(rs) cp addr,imm16 div rrd,addr +addl rrd,imm32 cp rd,@@rs div rrd,addr(rs) +addl rrd,rrs cp rd,addr div rrd,imm16 +and rd,@@rs cp rd,addr(rs) div rrd,rs +and rd,addr cp rd,imm16 divl rqd,@@rs +and rd,addr(rs) cp rd,rs divl rqd,addr +and rd,imm16 cpb @@rd,imm8 divl rqd,addr(rs) +and rd,rs cpb addr(rd),imm8 divl rqd,imm32 +andb rbd,@@rs cpb addr,imm8 divl rqd,rrs +andb rbd,addr cpb rbd,@@rs djnz rd,disp7 +andb rbd,addr(rs) cpb rbd,addr ei i2 +andb rbd,imm8 cpb rbd,addr(rs) ex rd,@@rs +andb rbd,rbs cpb rbd,imm8 ex rd,addr +bit @@rd,imm4 cpb rbd,rbs ex rd,addr(rs) +bit addr(rd),imm4 cpd rd,@@rs,rr,cc ex rd,rs +bit addr,imm4 cpdb rbd,@@rs,rr,cc exb rbd,@@rs +bit rd,imm4 cpdr rd,@@rs,rr,cc exb rbd,addr +bit rd,rs cpdrb rbd,@@rs,rr,cc exb rbd,addr(rs) +bitb @@rd,imm4 cpi rd,@@rs,rr,cc exb rbd,rbs +bitb addr(rd),imm4 cpib rbd,@@rs,rr,cc ext0e imm8 +bitb addr,imm4 cpir rd,@@rs,rr,cc ext0f imm8 +bitb rbd,imm4 cpirb rbd,@@rs,rr,cc ext8e imm8 +bitb rbd,rs cpl rrd,@@rs ext8f imm8 +bpt cpl rrd,addr exts rrd +call @@rd cpl rrd,addr(rs) extsb rd +call addr cpl rrd,imm32 extsl rqd +call addr(rd) cpl rrd,rrs halt +calr disp12 cpsd @@rd,@@rs,rr,cc in rd,@@rs +clr @@rd cpsdb @@rd,@@rs,rr,cc in rd,imm16 +clr addr cpsdr @@rd,@@rs,rr,cc inb rbd,@@rs +clr addr(rd) cpsdrb @@rd,@@rs,rr,cc inb rbd,imm16 +clr rd cpsi @@rd,@@rs,rr,cc inc @@rd,imm4m1 +clrb @@rd cpsib @@rd,@@rs,rr,cc inc addr(rd),imm4m1 +inc addr,imm4m1 ldb rbd,rs(rx) mult rrd,addr(rs) +inc rd,imm4m1 ldb rd(imm16),rbs mult rrd,imm16 +incb @@rd,imm4m1 ldb rd(rx),rbs mult rrd,rs +incb addr(rd),imm4m1 ldctl ctrl,rs multl rqd,@@rs +incb addr,imm4m1 ldctl rd,ctrl multl rqd,addr +incb rbd,imm4m1 ldd @@rs,@@rd,rr multl rqd,addr(rs) +ind @@rd,@@rs,ra lddb @@rs,@@rd,rr multl rqd,imm32 +indb @@rd,@@rs,rba lddr @@rs,@@rd,rr multl rqd,rrs +inib @@rd,@@rs,ra lddrb @@rs,@@rd,rr neg @@rd +inibr @@rd,@@rs,ra ldi @@rd,@@rs,rr neg addr +iret ldib @@rd,@@rs,rr neg addr(rd) +jp cc,@@rd ldir @@rd,@@rs,rr neg rd +jp cc,addr ldirb @@rd,@@rs,rr negb @@rd +jp cc,addr(rd) ldk rd,imm4 negb addr +jr cc,disp8 ldl @@rd,rrs negb addr(rd) +ld @@rd,imm16 ldl addr(rd),rrs negb rbd +ld @@rd,rs ldl addr,rrs nop +ld addr(rd),imm16 ldl rd(imm16),rrs or rd,@@rs +ld addr(rd),rs ldl rd(rx),rrs or rd,addr +ld addr,imm16 ldl rrd,@@rs or rd,addr(rs) +ld addr,rs ldl rrd,addr or rd,imm16 +ld rd(imm16),rs ldl rrd,addr(rs) or rd,rs +ld rd(rx),rs ldl rrd,imm32 orb rbd,@@rs +ld rd,@@rs ldl rrd,rrs orb rbd,addr +ld rd,addr ldl rrd,rs(imm16) orb rbd,addr(rs) +ld rd,addr(rs) ldl rrd,rs(rx) orb rbd,imm8 +ld rd,imm16 ldm @@rd,rs,n orb rbd,rbs +ld rd,rs ldm addr(rd),rs,n out @@rd,rs +ld rd,rs(imm16) ldm addr,rs,n out imm16,rs +ld rd,rs(rx) ldm rd,@@rs,n outb @@rd,rbs +lda rd,addr ldm rd,addr(rs),n outb imm16,rbs +lda rd,addr(rs) ldm rd,addr,n outd @@rd,@@rs,ra +lda rd,rs(imm16) ldps @@rs outdb @@rd,@@rs,rba +lda rd,rs(rx) ldps addr outib @@rd,@@rs,ra +ldar rd,disp16 ldps addr(rs) outibr @@rd,@@rs,ra +ldb @@rd,imm8 ldr disp16,rs pop @@rd,@@rs +ldb @@rd,rbs ldr rd,disp16 pop addr(rd),@@rs +ldb addr(rd),imm8 ldrb disp16,rbs pop addr,@@rs +ldb addr(rd),rbs ldrb rbd,disp16 pop rd,@@rs +ldb addr,imm8 ldrl disp16,rrs popl @@rd,@@rs +ldb addr,rbs ldrl rrd,disp16 popl addr(rd),@@rs +ldb rbd,@@rs mbit popl addr,@@rs +ldb rbd,addr mreq rd popl rrd,@@rs +ldb rbd,addr(rs) mres push @@rd,@@rs +ldb rbd,imm8 mset push @@rd,addr +ldb rbd,rbs mult rrd,@@rs push @@rd,addr(rs) +ldb rbd,rs(imm16) mult rrd,addr push @@rd,imm16 +push @@rd,rs set addr,imm4 subl rrd,imm32 +pushl @@rd,@@rs set rd,imm4 subl rrd,rrs +pushl @@rd,addr set rd,rs tcc cc,rd +pushl @@rd,addr(rs) setb @@rd,imm4 tccb cc,rbd +pushl @@rd,rrs setb addr(rd),imm4 test @@rd +res @@rd,imm4 setb addr,imm4 test addr +res addr(rd),imm4 setb rbd,imm4 test addr(rd) +res addr,imm4 setb rbd,rs test rd +res rd,imm4 setflg imm4 testb @@rd +res rd,rs sinb rbd,imm16 testb addr +resb @@rd,imm4 sinb rd,imm16 testb addr(rd) +resb addr(rd),imm4 sind @@rd,@@rs,ra testb rbd +resb addr,imm4 sindb @@rd,@@rs,rba testl @@rd +resb rbd,imm4 sinib @@rd,@@rs,ra testl addr +resb rbd,rs sinibr @@rd,@@rs,ra testl addr(rd) +resflg imm4 sla rd,imm8 testl rrd +ret cc slab rbd,imm8 trdb @@rd,@@rs,rba +rl rd,imm1or2 slal rrd,imm8 trdrb @@rd,@@rs,rba +rlb rbd,imm1or2 sll rd,imm8 trib @@rd,@@rs,rbr +rlc rd,imm1or2 sllb rbd,imm8 trirb @@rd,@@rs,rbr +rlcb rbd,imm1or2 slll rrd,imm8 trtdrb @@ra,@@rb,rbr +rldb rbb,rba sout imm16,rs trtib @@ra,@@rb,rr +rr rd,imm1or2 soutb imm16,rbs trtirb @@ra,@@rb,rbr +rrb rbd,imm1or2 soutd @@rd,@@rs,ra trtrb @@ra,@@rb,rbr +rrc rd,imm1or2 soutdb @@rd,@@rs,rba tset @@rd +rrcb rbd,imm1or2 soutib @@rd,@@rs,ra tset addr +rrdb rbb,rba soutibr @@rd,@@rs,ra tset addr(rd) +rsvd36 sra rd,imm8 tset rd +rsvd38 srab rbd,imm8 tsetb @@rd +rsvd78 sral rrd,imm8 tsetb addr +rsvd7e srl rd,imm8 tsetb addr(rd) +rsvd9d srlb rbd,imm8 tsetb rbd +rsvd9f srll rrd,imm8 xor rd,@@rs +rsvdb9 sub rd,@@rs xor rd,addr +rsvdbf sub rd,addr xor rd,addr(rs) +sbc rd,rs sub rd,addr(rs) xor rd,imm16 +sbcb rbd,rbs sub rd,imm16 xor rd,rs +sc imm8 sub rd,rs xorb rbd,@@rs +sda rd,rs subb rbd,@@rs xorb rbd,addr +sdab rbd,rs subb rbd,addr xorb rbd,addr(rs) +sdal rrd,rs subb rbd,addr(rs) xorb rbd,imm8 +sdl rd,rs subb rbd,imm8 xorb rbd,rbs +sdlb rbd,rs subb rbd,rbs xorb rbd,rbs +sdll rrd,rs subl rrd,@@rs +set @@rd,imm4 subl rrd,addr +set addr(rd),imm4 subl rrd,addr(rs) +@end smallexample +@iftex +@endgroup +@end iftex +@end ifset + diff --git a/contrib/binutils/gas/doc/gasp.texi b/contrib/binutils/gas/doc/gasp.texi new file mode 100644 index 0000000..64cd6f4 --- /dev/null +++ b/contrib/binutils/gas/doc/gasp.texi @@ -0,0 +1,1086 @@ +\input texinfo @c -*- Texinfo -*- +@setfilename gasp.info +@c +@c This file documents the assembly preprocessor "GASP" +@c +@c Copyright (c) 1994 Free Software Foundation, Inc. +@c +@c This text may be freely distributed under the terms of the GNU +@c General Public License. + +@ifinfo +@format +START-INFO-DIR-ENTRY +* gasp: (gasp). The GNU Assembler Preprocessor +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@syncodeindex ky cp +@syncodeindex fn cp + +@finalout +@setchapternewpage odd +@settitle GASP +@titlepage +@c FIXME boring title +@title GASP, an assembly preprocessor +@subtitle for GASP version 1 +@sp 1 +@subtitle March 1994 +@author Roland Pesch +@page + +@tex +{\parskip=0pt \hfill Cygnus Support\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1994, 1995 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@end titlepage + +@ifinfo +Copyright @copyright{} 1994, 1995 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. + +@node Top +@top GASP + +GASP is a preprocessor for assembly programs. + +This file describes version 1 of GASP. + +Steve Chamberlain wrote GASP; Roland Pesch wrote this manual. + +@menu +* Overview:: What is GASP? +* Invoking GASP:: Command line options. +* Commands:: Preprocessor commands. +* Index:: Index. +@end menu +@end ifinfo + +@node Overview +@chapter What is GASP? + +The primary purpose of the @sc{gnu} assembler is to assemble the output of +other programs---notably compilers. When you have to hand-code +specialized routines in assembly, that means the @sc{gnu} assembler is +an unfriendly processor: it has no directives for macros, conditionals, +or many other conveniences that you might expect. + +In some cases you can simply use the C preprocessor, or a generalized +preprocessor like @sc{m4}; but this can be awkward, since none of these +things are designed with assembly in mind. + +@sc{gasp} fills this need. It is expressly designed to provide the +facilities you need with hand-coded assembly code. Implementing it as a +preprocessor, rather than part of the assembler, allows the maximum +flexibility: you can use it with hand-coded assembly, without paying a +penalty of added complexity in the assembler you use for compiler +output. + +Here is a small example to give the flavor of @sc{gasp}. This input to +@sc{gasp} + +@cartouche +@example + .MACRO saveregs from=8 to=14 +count .ASSIGNA \from + ! save r\from..r\to + .AWHILE \&count LE \to + mov r\&count,@@-sp +count .ASSIGNA \&count + 1 + .AENDW + .ENDM + + saveregs from=12 + +bar: mov #H'dead+10,r0 +foo .SDATAC "hello"<10> + .END +@end example +@end cartouche + +@noindent +generates this assembly program: + +@cartouche +@example + ! save r12..r14 + mov r12,@@-sp + mov r13,@@-sp + mov r14,@@-sp + +bar: mov #57005+10,r0 +foo: .byte 6,104,101,108,108,111,10 +@end example +@end cartouche + +@node Invoking GASP +@chapter Command Line Options + +@c FIXME! Or is there a simpler way, calling from GAS option? +The simplest way to use @sc{gasp} is to run it as a filter and assemble +its output. In Unix and its ilk, you can do this, for example: + +@c FIXME! GASP filename suffix convention? +@example +$ gasp prog.asm | as -o prog.o +@end example + +Naturally, there are also a few command-line options to allow you to +request variations on this basic theme. Here is the full set of +possibilities for the @sc{gasp} command line. + +@example +gasp [ -a | --alternate ] + [ -c @var{char} | --commentchar @var{char} ] + [ -d | --debug ] [ -h | --help ] [ -M | --mri ] + [ -o @var{outfile} | --output @var{outfile} ] + [ -p | --print ] [ -s | --copysource ] + [ -u | --unreasonable ] [ -v | --version ] + @var{infile} @dots{} +@end example + +@ftable @code +@item @var{infile} @dots{} +@c FIXME! Why not stdin as default infile? +The input file names. You must specify at least one input file; if you +specify more, @sc{gasp} preprocesses them all, concatenating the output +in the order you list the @var{infile} arguments. + +Mark the end of each input file with the preprocessor command +@code{.END}. @xref{Other Commands,, Miscellaneous commands}. + +@item -a +@itemx --alternate +Use alternative macro syntax. @xref{Alternate,, Alternate macro +syntax}, for a discussion of how this syntax differs from the default +@sc{gasp} syntax. + +@cindex comment character, changing +@cindex semicolon, as comment +@cindex exclamation mark, as comment +@cindex shriek, as comment +@cindex bang, as comment +@cindex @code{!} default comment char +@cindex @code{;} as comment char +@item -c '@var{char}' +@itemx --commentchar '@var{char}' +Use @var{char} as the comment character. The default comment character +is @samp{!}. For example, to use a semicolon as the comment character, +specify @w{@samp{-c ';'}} on the @sc{gasp} command line. Since +assembler command characters often have special significance to command +shells, it is a good idea to quote or escape @var{char} when you specify +a comment character. + +For the sake of simplicity, all examples in this manual use the default +comment character @samp{!}. + +@item -d +@itemx --debug +Show debugging statistics. In this version of @sc{gasp}, this option +produces statistics about the string buffers that @sc{gasp} allocates +internally. For each defined buffersize @var{s}, @sc{gasp} shows the +number of strings @var{n} that it allocated, with a line like this: + +@example +strings size @var{s} : @var{n} +@end example + +@noindent +@sc{gasp} displays these statistics on the standard error stream, when +done preprocessing. + +@item -h +@itemx --help +Display a summary of the @sc{gasp} command line options. + +@item -M +@itemx --mri +Use MRI compatibility mode. Using this option causes @sc{gasp} to +accept the syntax and pseudo-ops used by the Microtec Research +@code{ASM68K} assembler. + +@item -o @var{outfile} +@itemx --output @var{outfile} +Write the output in a file called @var{outfile}. If you do not use the +@samp{-o} option, @sc{gasp} writes its output on the standard output +stream. + +@item -p +@itemx --print +Print line numbers. @sc{gasp} obeys this option @emph{only} if you also +specify @samp{-s} to copy source lines to its output. With @samp{-s +-p}, @sc{gasp} displays the line number of each source line copied +(immediately after the comment character at the beginning of the line). + +@item -s +@itemx --copysource +Copy the source lines to the output file. Use this option +to see the effect of each preprocessor line on the @sc{gasp} output. +@sc{gasp} places a comment character (@samp{!} by default) at +the beginning of each source line it copies, so that you can use this +option and still assemble the result. + +@item -u +@itemx --unreasonable +Bypass ``unreasonable expansion'' limit. Since you can define @sc{gasp} +macros inside other macro definitions, the preprocessor normally +includes a sanity check. If your program requires more than 1,000 +nested expansions, @sc{gasp} normally exits with an error message. Use +this option to turn off this check, allowing unlimited nested +expansions. + +@item -v +@itemx --version +Display the @sc{gasp} version number. +@end ftable + +@node Commands +@chapter Preprocessor Commands + +@sc{gasp} commands have a straightforward syntax that fits in well with +assembly conventions. In general, a command extends for a line, and may +have up to three fields: an optional label, the command itself, and +optional arguments to the command. You can write commands in upper or +lower case, though this manual shows them in upper case. @xref{Syntax +Details,, Details of the GASP syntax}, for more information. + +@menu +* Conditionals:: +* Loops:: +* Variables:: +* Macros:: +* Data:: +* Listings:: +* Other Commands:: +* Syntax Details:: +* Alternate:: +@end menu + +@node Conditionals +@section Conditional assembly + +The conditional-assembly directives allow you to include or exclude +portions of an assembly depending on how a pair of expressions, or a +pair of strings, compare. + +The overall structure of conditionals is familiar from many other +contexts. @code{.AIF} marks the start of a conditional, and precedes +assembly for the case when the condition is true. An optional +@code{.AELSE} precedes assembly for the converse case, and an +@code{.AENDI} marks the end of the condition. + +@c FIXME! Why doesn't -u turn off this check? +You may nest conditionals up to a depth of 100; @sc{gasp} rejects +nesting beyond that, because it may indicate a bug in your macro +structure. + +@c FIXME! Why isn't there something like cpp's -D option? Conditionals +@c would be much more useful if there were. +Conditionals are primarily useful inside macro definitions, where you +often need different effects depending on argument values. +@xref{Macros,, Defining your own directives}, for details about defining +macros. + +@ftable @code +@item .AIF @var{expra} @var{cmp} @var{exprb} +@itemx .AIF "@var{stra}" @var{cmp} "@var{strb}" + +The governing condition goes on the same line as the @code{.AIF} +preprocessor command. You may compare either two strings, or two +expressions. + +When you compare strings, only two conditional @var{cmp} comparison +operators are available: @samp{EQ} (true if @var{stra} and @var{strb} +are identical), and @samp{NE} (the opposite). + +When you compare two expressions, @emph{both expressions must be +absolute} (@pxref{Expressions,, Arithmetic expressions in GASP}). You +can use these @var{cmp} comparison operators with expressions: + +@ftable @code +@item EQ +Are @var{expra} and @var{exprb} equal? (For strings, are @var{stra} and +@var{strb} identical?) + +@item NE +Are @var{expra} and @var{exprb} different? (For strings, are @var{stra} +and @var{strb} different? + +@item LT +Is @var{expra} less than @var{exprb}? (Not allowed for strings.) + +@item LE +Is @var{expra} less than or equal to @var{exprb}? (Not allowed for strings.) + +@item GT +Is @var{expra} greater than @var{exprb}? (Not allowed for strings.) + +@item GE +Is @var{expra} greater than or equal to @var{exprb}? (Not allowed for +strings.) +@end ftable + +@item .AELSE +Marks the start of assembly code to be included if the condition fails. +Optional, and only allowed within a conditional (between @code{.AIF} and +@code{.AENDI}). + +@item .AENDI +Marks the end of a conditional assembly. +@end ftable + +@node Loops +@section Repetitive sections of assembly + +Two preprocessor directives allow you to repeatedly issue copies of the +same block of assembly code. + +@ftable @code +@item .AREPEAT @var{aexp} +@itemx .AENDR +If you simply need to repeat the same block of assembly over and over a +fixed number of times, sandwich one instance of the repeated block +between @code{.AREPEAT} and @code{.AENDR}. Specify the number of +copies as @var{aexp} (which must be an absolute expression). For +example, this repeats two assembly statements three times in succession: + +@cartouche +@example + .AREPEAT 3 + rotcl r2 + div1 r0,r1 + .AENDR +@end example +@end cartouche + +@item .AWHILE @var{expra} @var{cmp} @var{exprb} +@itemx .AENDW +@itemx .AWHILE @var{stra} @var{cmp} @var{strb} +@itemx .AENDW +To repeat a block of assembly depending on a conditional test, rather +than repeating it for a specific number of times, use @code{.AWHILE}. +@code{.AENDW} marks the end of the repeated block. The conditional +comparison works exactly the same way as for @code{.AIF}, with the same +comparison operators (@pxref{Conditionals,, Conditional assembly}). + +Since the terms of the comparison must be absolute expression, +@code{.AWHILE} is primarily useful within macros. @xref{Macros,, +Defining your own directives}. +@end ftable + +@cindex loops, breaking out of +@cindex breaking out of loops +You can use the @code{.EXITM} preprocessor directive to break out of +loops early (as well as to break out of macros). @xref{Macros,, +Defining your own directives}. + +@node Variables +@section Preprocessor variables + +You can use variables in @sc{gasp} to represent strings, registers, or +the results of expressions. + +You must distinguish two kinds of variables: +@enumerate +@item +Variables defined with @code{.EQU} or @code{.ASSIGN}. To evaluate this +kind of variable in your assembly output, simply mention its name. For +example, these two lines define and use a variable @samp{eg}: + +@cartouche +@example +eg .EQU FLIP-64 + @dots{} + mov.l eg,r0 +@end example +@end cartouche + +@emph{Do not use} this kind of variable in conditional expressions or +while loops; @sc{gasp} only evaluates these variables when writing +assembly output. + +@item +Variables for use during preprocessing. You can define these +with @code{.ASSIGNC} or @code{.ASSIGNA}. To evaluate this +kind of variable, write @samp{\&} before the variable name; for example, + +@cartouche +@example +opcit .ASSIGNA 47 + @dots{} + .AWHILE \&opcit GT 0 + @dots{} + .AENDW +@end example +@end cartouche + +@sc{gasp} treats macro arguments almost the same way, but to evaluate +them you use the prefix @samp{\} rather than @samp{\&}. +@xref{Macros,, Defining your own directives}. +@end enumerate + +@ftable @code +@item @var{pvar} .EQU @var{expr} +@c FIXME! Anything to beware of re GAS directive of same name? +Assign preprocessor variable @var{pvar} the value of the expression +@var{expr}. There are no restrictions on redefinition; use @samp{.EQU} +with the same @var{pvar} as often as you find it convenient. + +@item @var{pvar} .ASSIGN @var{expr} +Almost the same as @code{.EQU}, save that you may not redefine +@var{pvar} using @code{.ASSIGN} once it has a value. +@c FIXME!! Supposed to work this way, apparently, but on 9feb94 works +@c just like .EQU + +@item @var{pvar} .ASSIGNA @var{aexpr} +Define a variable with a numeric value, for use during preprocessing. +@var{aexpr} must be an absolute expression. You can redefine variables +with @code{.ASSIGNA} at any time. + +@item @var{pvar} .ASSIGNC "@var{str}" +Define a variable with a string value, for use during preprocessing. +You can redefine variables with @code{.ASSIGNC} at any time. + +@item @var{pvar} .REG (@var{register}) +Use @code{.REG} to define a variable that represents a register. In +particular, @var{register} is @emph{not evaluated} as an expression. +You may use @code{.REG} at will to redefine register variables. +@end ftable + +All these directives accept the variable name in the ``label'' position, +that is at the left margin. You may specify a colon after the variable +name if you wish; the first example above could have started @samp{eg:} +with the same effect. + +@c pagebreak makes for better aesthetics---ensures macro and expansion together +@page +@node Macros +@section Defining your own directives + +The commands @code{.MACRO} and @code{.ENDM} allow you to define macros +that generate assembly output. You can use these macros with a syntax +similar to built-in @sc{gasp} or assembler directives. For example, +this definition specifies a macro @code{SUM} that adds together a range of +consecutive registers: + +@cartouche +@example + .MACRO SUM FROM=0, TO=9 + ! \FROM \TO + mov r\FROM,r10 +COUNT .ASSIGNA \FROM+1 + .AWHILE \&COUNT LE \TO + add r\&COUNT,r10 +COUNT .ASSIGNA \&COUNT+1 + .AENDW + .ENDM +@end example +@end cartouche + +@noindent +With that definition, @samp{SUM 0,5} generates this assembly output: + +@cartouche +@example + ! 0 5 + mov r0,r10 + add r1,r10 + add r2,r10 + add r3,r10 + add r4,r10 + add r5,r10 +@end example +@end cartouche + +@ftable @code +@item .MACRO @var{macname} +@itemx .MACRO @var{macname} @var{macargs} @dots{} +Begin the definition of a macro called @var{macname}. If your macro +definition requires arguments, specify their names after the macro name, +separated by commas or spaces. You can supply a default value for any +macro argument by following the name with @samp{=@var{deflt}}. For +example, these are all valid @code{.MACRO} statements: + +@table @code +@item .MACRO COMM +Begin the definition of a macro called @code{COMM}, which takes no +arguments. + +@item .MACRO PLUS1 P, P1 +@itemx .MACRO PLUS1 P P1 +Either statement begins the definition of a macro called @code{PLUS1}, +which takes two arguments; within the macro definition, write +@samp{\P} or @samp{\P1} to evaluate the arguments. + +@item .MACRO RESERVE_STR P1=0 P2 +Begin the definition of a macro called @code{RESERVE_STR}, with two +arguments. The first argument has a default value, but not the second. +After the definition is complete, you can call the macro either as +@samp{RESERVE_STR @var{a},@var{b}} (with @samp{\P1} evaluating to +@var{a} and @samp{\P2} evaluating to @var{b}), or as @samp{RESERVE_STR +,@var{b}} (with @samp{\P1} evaluating as the default, in this case +@samp{0}, and @samp{\P2} evaluating to @var{b}). +@end table + +When you call a macro, you can specify the argument values either by +position, or by keyword. For example, @samp{SUM 9,17} is equivalent to +@samp{SUM TO=17, FROM=9}. Macro arguments are preprocessor variables +similar to the variables you define with @samp{.ASSIGNA} or +@samp{.ASSIGNC}; in particular, you can use them in conditionals or for +loop control. (The only difference is the prefix you write to evaluate +the variable: for a macro argument, write @samp{\@var{argname}}, but for +a preprocessor variable, write @samp{\&@var{varname}}.) + +@item @var{name} .MACRO +@itemx @var{name} .MACRO ( @var{macargs} @dots{} ) +@c FIXME check: I think no error _and_ no args recognized if I use form +@c NAME .MACRO ARG ARG +An alternative form of introducing a macro definition: specify the macro +name in the label position, and the arguments (if any) between +parentheses after the name. Defaulting rules and usage work the same +way as for the other macro definition syntax. + +@item .ENDM +Mark the end of a macro definition. + +@item .EXITM +Exit early from the current macro definition, @code{.AREPEAT} loop, or +@code{.AWHILE} loop. + +@cindex number of macros executed +@cindex macros, count executed +@item \@@ +@sc{gasp} maintains a counter of how many macros it has +executed in this pseudo-variable; you can copy that number to your +output with @samp{\@@}, but @emph{only within a macro definition}. + +@item LOCAL @var{name} [ , @dots{} ] +@emph{Warning: @code{LOCAL} is only available if you select ``alternate +macro syntax'' with @samp{-a} or @samp{--alternate}.} @xref{Alternate,, +Alternate macro syntax}. + +Generate a string replacement for each of the @var{name} arguments, and +replace any instances of @var{name} in each macro expansion. The +replacement string is unique in the assembly, and different for each +separate macro expansion. @code{LOCAL} allows you to write macros that +define symbols, without fear of conflict between separate macro expansions. +@end ftable + +@node Data +@section Data output + +In assembly code, you often need to specify working areas of memory; +depending on the application, you may want to initialize such memory or +not. @sc{gasp} provides preprocessor directives to help you avoid +repetitive coding for both purposes. + +You can use labels as usual to mark the data areas. + +@menu +* Initialized:: +* Uninitialized:: +@end menu + +@node Initialized +@subsection Initialized data + +These are the @sc{gasp} directives for initialized data, and the standard +@sc{gnu} assembler directives they expand to: + +@ftable @code +@item .DATA @var{expr}, @var{expr}, @dots{} +@itemx .DATA.B @var{expr}, @var{expr}, @dots{} +@itemx .DATA.W @var{expr}, @var{expr}, @dots{} +@itemx .DATA.L @var{expr}, @var{expr}, @dots{} +Evaluate arithmetic expressions @var{expr}, and emit the corresponding +@code{as} directive (labelled with @var{lab}). The unqualified +@code{.DATA} emits @samp{.long}; @code{.DATA.B} emits @samp{.byte}; +@code{.DATA.W} emits @samp{.short}; and @code{.DATA.L} emits +@samp{.long}. + +For example, @samp{foo .DATA 1,2,3} emits @samp{foo: .long 1,2,3}. + +@item .DATAB @var{repeat}, @var{expr} +@itemx .DATAB.B @var{repeat}, @var{expr} +@itemx .DATAB.W @var{repeat}, @var{expr} +@itemx .DATAB.L @var{repeat}, @var{expr} +@c FIXME! Looks like gasp accepts and ignores args after 2nd. +Make @code{as} emit @var{repeat} copies of the value of the expression +@var{expr} (using the @code{as} directive @code{.fill}). +@samp{.DATAB.B} repeats one-byte values; @samp{.DATAB.W} repeats +two-byte values; and @samp{.DATAB.L} repeats four-byte values. +@samp{.DATAB} without a suffix repeats four-byte values, just like +@samp{.DATAB.L}. + +@c FIXME! Allowing zero might be useful for edge conditions in macros. +@var{repeat} must be an absolute expression with a positive value. + +@item .SDATA "@var{str}" @dots{} +String data. Emits a concatenation of bytes, precisely as you specify +them (in particular, @emph{nothing is added to mark the end} of the +string). @xref{Constants,, String and numeric constants}, for details +about how to write strings. @code{.SDATA} concatenates multiple +arguments, making it easy to switch between string representations. You +can use commas to separate the individual arguments for clarity, if you +choose. + +@item .SDATAB @var{repeat}, "@var{str}" @dots{} +Repeated string data. The first argument specifies how many copies of +the string to emit; the remaining arguments specify the string, in the +same way as the arguments to @code{.SDATA}. + +@item .SDATAZ "@var{str}" @dots{} +Zero-terminated string data. Just like @code{.SDATA}, except that +@code{.SDATAZ} writes a zero byte at the end of the string. + +@item .SDATAC "@var{str}" @dots{} +Count-prefixed string data. Just like @code{.SDATA}, except that +@sc{gasp} precedes the string with a leading one-byte count. For +example, @samp{.SDATAC "HI"} generates @samp{.byte 2,72,73}. Since the +count field is only one byte, you can only use @code{.SDATAC} for +strings less than 256 bytes in length. +@end ftable + +@node Uninitialized +@subsection Uninitialized data + +@c FIXME! .space different on some platforms, notably HPPA. Config? +Use the @code{.RES}, @code{.SRES}, @code{.SRESC}, and @code{.SRESZ} +directives to reserve memory and leave it uninitialized. @sc{gasp} +resolves these directives to appropriate calls of the @sc{gnu} +@code{as} @code{.space} directive. + +@ftable @code +@item .RES @var{count} +@itemx .RES.B @var{count} +@itemx .RES.W @var{count} +@itemx .RES.L @var{count} +Reserve room for @var{count} uninitialized elements of data. The +suffix specifies the size of each element: @code{.RES.B} reserves +@var{count} bytes, @code{.RES.W} reserves @var{count} pairs of bytes, +and @code{.RES.L} reserves @var{count} quartets. @code{.RES} without a +suffix is equivalent to @code{.RES.L}. + +@item .SRES @var{count} +@itemx .SRES.B @var{count} +@itemx .SRES.W @var{count} +@itemx .SRES.L @var{count} +@c FIXME! This is boring. Shouldn't it at least have a different +@c default size? (e.g. the "S" suggests "string", for which .B +@c would be more appropriate) +@code{.SRES} is a synonym for @samp{.RES}. + +@item .SRESC @var{count} +@itemx .SRESC.B @var{count} +@itemx .SRESC.W @var{count} +@itemx .SRESC.L @var{count} +Like @code{.SRES}, but reserves space for @code{@var{count}+1} elements. + +@item .SRESZ @var{count} +@itemx .SRESZ.B @var{count} +@itemx .SRESZ.W @var{count} +@itemx .SRESZ.L @var{count} +Like @code{.SRES}, but reserves space for @code{@var{count}+1} elements. +@end ftable + +@node Listings +@section Assembly listing control + +The @sc{gasp} listing-control directives correspond to +related @sc{gnu} @code{as} directives. + +@ftable @code +@item .PRINT LIST +@itemx .PRINT NOLIST +Print control. This directive emits the @sc{gnu} @code{as} directive +@code{.list} or @code{.nolist}, according to its argument. @xref{List,, +@code{.list}, as.info, Using as}, for details on how these directives +interact. + +@item .FORM LIN=@var{ln} +@itemx .FORM COL=@var{cols} +@itemx .FORM LIN=@var{ln} COL=@var{cols} +Specify the page size for assembly listings: @var{ln} represents the +number of lines, and @var{cols} the number of columns. You may specify +either page dimension independently, or both together. If you do not +specify the number of lines, @sc{gasp} assumes 60 lines; if you do not +specify the number of columns, @sc{gasp} assumes 132 columns. +(Any values you may have specified in previous instances of @code{.FORM} +do @emph{not} carry over as defaults.) Emits the @code{.psize} +assembler directive. + +@item .HEADING @var{string} +Specify @var{string} as the title of your assembly listings. Emits +@samp{.title "@var{string}"}. + +@item .PAGE +Force a new page in assembly listings. Emits @samp{.eject}. +@end ftable + +@node Other Commands +@section Miscellaneous commands + +@ftable @code +@item .ALTERNATE +Use the alternate macro syntax henceforth in the assembly. +@xref{Alternate,, Alternate macro syntax}. + +@item .ORG +@c FIXME! This is very strange, since _GAS_ understands .org +This command is recognized, but not yet implemented. @sc{gasp} +generates an error message for programs that use @code{.ORG}. + +@item .RADIX @var{s} +@c FIXME no test cases in testsuite/gasp +@sc{gasp} understands numbers in any of base two, eight, ten, or +sixteen. You can encode the base explicitly in any numeric constant +(@pxref{Constants,, String and numeric constants}). If you write +numbers without an explicit indication of the base, the most recent +@samp{.RADIX @var{s}} command determines how they are interpreted. +@var{s} is a single letter, one of the following: + +@table @code +@item .RADIX B +Base 2. + +@item .RADIX Q +Base 8. + +@item .RADIX D +Base 10. This is the original default radix. + +@item .RADIX H +Base 16. +@end table + +You may specify the argument @var{s} in lower case (any of @samp{bqdh}) +with the same effects. + +@item .EXPORT @var{name} +@itemx .GLOBAL @var{name} +@c FIXME! No test cases in testsuite/gasp +Declare @var{name} global (emits @samp{.global @var{name}}). The two +directives are synonymous. + +@item .PROGRAM +No effect: @sc{gasp} accepts this directive, and silently ignores it. + +@item .END +Mark end of each preprocessor file. @sc{gasp} issues a warning if it +reaches end of file without seeing this command. + +@item .INCLUDE "@var{str}" +Preprocess the file named by @var{str}, as if its contents appeared +where the @code{.INCLUDE} directive does. @sc{gasp} imposes a maximum +limit of 30 stacked include files, as a sanity check. +@c FIXME! Why is include depth not affected by -u? + +@item .ALIGN @var{size} +@c FIXME! Why is this not utterly pointless? +Evaluate the absolute expression @var{size}, and emit the assembly +instruction @samp{.align @var{size}} using the result. +@end ftable + +@node Syntax Details +@section Details of the GASP syntax + +Since @sc{gasp} is meant to work with assembly code, its statement +syntax has no surprises for the assembly programmer. + +@cindex whitespace +@emph{Whitespace} (blanks or tabs; @emph{not} newline) is partially +significant, in that it delimits up to three fields in a line. The +amount of whitespace does not matter; you may line up fields in separate +lines if you wish, but @sc{gasp} does not require that. + +@cindex fields of @sc{gasp} source line +@cindex label field +The @emph{first field}, an optional @dfn{label}, must be flush left in a +line (with no leading whitespace) if it appears at all. You may use a +colon after the label if you wish; @sc{gasp} neither requires the colon +nor objects to it (but will not include it as part of the label name). + +@cindex directive field +The @emph{second field}, which must appear after some whitespace, +contains a @sc{gasp} or assembly @dfn{directive}. + +@cindex argument fields +Any @emph{further fields} on a line are @dfn{arguments} to the +directive; you can separate them from one another using either commas or +whitespace. + +@menu +* Markers:: +* Constants:: +* Symbols:: +* Expressions:: +* String Builtins:: +@end menu + +@node Markers +@subsection Special syntactic markers + +@sc{gasp} recognizes a few special markers: to delimit comments, to +continue a statement on the next line, to separate symbols from other +characters, and to copy text to the output literally. (One other +special marker, @samp{\@@}, works only within macro definitions; +@pxref{Macros,, Defining your own directives}.) + +@cindex comments +The trailing part of any @sc{gasp} source line may be a @dfn{comment}. +A comment begins with the first unquoted comment character (@samp{!} by +default), or an escaped or doubled comment character (@samp{\!} or +@samp{!!} by default), and extends to the end of a line. You can +specify what comment character to use with the @samp{-c} option +(@pxref{Invoking GASP,, Command Line Options}). The two kinds of +comment markers lead to slightly different treatment: + +@table @code +@item ! +A single, un-escaped comment character generates an assembly comment in +the @sc{gasp} output. @sc{gasp} evaluates any preprocessor variables +(macro arguments, or variables defined with @code{.ASSIGNA} or +@code{.ASSIGNC}) present. For example, a macro that begins like this + +@example + .MACRO SUM FROM=0, TO=9 + ! \FROM \TO +@end example + +@noindent +issues as the first line of output a comment that records the +values you used to call the macro. + +@c comments, preprocessor-only +@c preprocessor-only comments +@c GASP-only comments +@item \! +@itemx !! +Either an escaped comment character, or a double comment character, +marks a @sc{gasp} source comment. @sc{gasp} does not copy such comments +to the assembly output. +@end table + +@cindex continuation character +@kindex + +To @emph{continue a statement} on the next line of the file, begin the +second line with the character @samp{+}. + +@cindex literal copy to output +@cindex copying literally to output +@cindex preprocessing, avoiding +@cindex avoiding preprocessing +Occasionally you may want to prevent @sc{gasp} from preprocessing some +particular bit of text. To @emph{copy literally} from the @sc{gasp} +source to its output, place @samp{\(} before the string to copy, and +@samp{)} at the end. For example, write @samp{\(\!)} if you need the +characters @samp{\!} in your assembly output. + +@cindex symbol separator +@cindex text, separating from symbols +@cindex symbols, separating from text +To @emph{separate a preprocessor variable} from text to appear +immediately after its value, write a single quote (@code{'}). For +example, @samp{.SDATA "\P'1"} writes a string built by concatenating the +value of @code{P} and the digit @samp{1}. (You cannot achieve this by +writing just @samp{\P1}, since @samp{P1} is itself a valid name for a +preprocessor variable.) + +@node Constants +@subsection String and numeric constants + +There are two ways of writing @dfn{string constants} in @sc{gasp}: as +literal text, and by numeric byte value. Specify a string literal +between double quotes (@code{"@var{str}"}). Specify an individual +numeric byte value as an absolute expression between angle brackets +(@code{<@var{expr}>}. Directives that output strings allow you to +specify any number of either kind of value, in whatever order is +convenient, and concatenate the result. (Alternate syntax mode +introduces a number of alternative string notations; @pxref{Alternate,, +Alternate macro syntax}.) + +@c Details of numeric notation, e.g. base prefixes +You can write @dfn{numeric constants} either in a specific base, or in +whatever base is currently selected (either 10, or selected by the most +recent @code{.RADIX}). + +To write a number in a @emph{specific base}, use the pattern +@code{@var{s}'@var{ddd}}: a base specifier character @var{s}, followed +by a single quote followed by digits @var{ddd}. The base specifier +character matches those you can specify with @code{.RADIX}: @samp{B} for +base 2, @samp{Q} for base 8, @samp{D} for base 10, and @samp{H} for base +16. (You can write this character in lower case if you prefer.) + +@c FIXME! What are rules for recognizing number in deflt base? Whatever +@c is left over after parsing other things?? + +@node Symbols +@subsection Symbols + +@sc{gasp} recognizes symbol names that start with any alphabetic character, +@samp{_}, or @samp{$}, and continue with any of the same characters or +with digits. Label names follow the same rules. + +@node Expressions +@subsection Arithmetic expressions in GASP + +@cindex absolute expressions +@cindex relocatable expressions +There are two kinds of expressions, depending on their result: +@dfn{absolute} expressions, which resolve to a constant (that is, they +do not involve any values unknown to @sc{gasp}), and @dfn{relocatable} +expressions, which must reduce to the form + +@example +@var{addsym}+@var{const}-@var{subsym} +@end example + +@noindent +where @var{addsym} and @var{subsym} are assembly symbols of unknown +value, and @var{const} is a constant. + +Arithmetic for @sc{gasp} expressions follows very similar rules to C. +You can use parentheses to change precedence; otherwise, arithmetic +primitives have decreasing precedence in the order of the following +list. + +@enumerate +@item +Single-argument @code{+} (identity), @code{-} (arithmetic opposite), or +@code{~} (bitwise negation). @emph{The argument must be an absolute +expression.} + +@item +@code{*} (multiplication) and @code{/} (division). @emph{Both arguments +must be absolute expressions.} + +@item +@code{+} (addition) and @code{-} (subtraction). @emph{At least one argument +must be absolute.} +@c FIXME! Actually, subtraction doesn't check for this. + +@item +@code{&} (bitwise and). @emph{Both arguments must be absolute.} + +@item +@c FIXME! I agree ~ is a better notation than ^ for xor, but is the +@c improvement worth differing from C? +@code{|} (bitwise or) and @code{~} (bitwise exclusive or; @code{^} in +C). @emph{Both arguments must be absolute.} +@end enumerate + +@node String Builtins +@subsection String primitives + +You can use these primitives to manipulate strings (in the argument +field of @sc{gasp} statements): + +@ftable @code +@item .LEN("@var{str}") +Calculate the length of string @code{"@var{str}"}, as an absolute +expression. For example, @samp{.RES.B .LEN("sample")} reserves six +bytes of memory. + +@item .INSTR("@var{string}", "@var{seg}", @var{ix}) +Search for the first occurrence of @var{seg} after position @var{ix} of +@var{string}. For example, @samp{.INSTR("ABCDEFG", "CDE", 0)} evaluates +to the absolute result @code{2}. + +The result is @code{-1} if @var{seg} does not occur in @var{string} +after position @var{ix}. + +@item .SUBSTR("@var{string}",@var{start},@var{len}) +The substring of @var{string} beginning at byte number @var{start} and +extending for @var{len} bytes. +@end ftable + +@node Alternate +@section Alternate macro syntax + +If you specify @samp{-a} or @samp{--alternate} on the @sc{gasp} command +line, the preprocessor uses somewhat different syntax. This syntax is +reminiscent of the syntax of Phar Lap macro assembler, but it +is @emph{not} meant to be a full emulation of Phar Lap or similar +assemblers. In particular, @sc{gasp} does not support directives such +as @code{DB} and @code{IRP}, even in alternate syntax mode. + +In particular, @samp{-a} (or @samp{--alternate}) elicits these +differences: + +@table @emph +@item Preprocessor directives +You can use @sc{gasp} preprocessor directives without a leading @samp{.} +dot. For example, you can write @samp{SDATA} with the same effect as +@samp{.SDATA}. + +@item LOCAL +One additional directive, @code{LOCAL}, is available. @xref{Macros,, +Defining your own directives}, for an explanation of how to use +@code{LOCAL}. + +@need 2000 +@item String delimiters +You can write strings delimited in these other ways besides +@code{"@var{string}"}: + +@table @code +@item '@var{string}' +You can delimit strings with single-quote charaters. + +@item <@var{string}> +You can delimit strings with matching angle brackets. +@end table + +@item single-character string escape +To include any single character literally in a string (even if the +character would otherwise have some special meaning), you can prefix the +character with @samp{!} (an exclamation mark). For example, you can +write @samp{<4.3 !> 5.4!!>} to get the literal text @samp{4.3 > 5.4!}. + +@item Expression results as strings +You can write @samp{%@var{expr}} to evaluate the expression @var{expr} +and use the result as a string. +@end table + +@node Index +@unnumbered Index + +@printindex cp + +@contents +@bye diff --git a/contrib/binutils/gas/doc/h8.texi b/contrib/binutils/gas/doc/h8.texi new file mode 100644 index 0000000..0df1714 --- /dev/null +++ b/contrib/binutils/gas/doc/h8.texi @@ -0,0 +1,26 @@ +@clear ALL-ARCH +@clear GENERIC +@clear INTERNALS +@clear MULTI-OBJ +@clear AOUT +@clear BOUT +@set COFF +@clear ELF +@set Hitachi-all +@set H8/300 +@set H8/500 +@set SH +@clear DIFF-TBL-KLUGE +@set IEEEFLOAT +@clear W32 +@set W16 +@set SPECIAL-SYMS +@set AS as +@set GCC gcc +@set LD ld +@set TARGET H8/300 and H8/500 +@set TARGET H8/300, H8/500, and Hitachi SH +@set OBJ-NAME COFF +@c +@clear have-stabs +@set abnormal-separator diff --git a/contrib/binutils/gas/doc/internals.texi b/contrib/binutils/gas/doc/internals.texi new file mode 100644 index 0000000..ad57afd --- /dev/null +++ b/contrib/binutils/gas/doc/internals.texi @@ -0,0 +1,1519 @@ +\input texinfo +@setfilename internals.info +@node Top +@top Assembler Internals +@raisesections +@cindex internals + +This chapter describes the internals of the assembler. It is incomplete, but +it may help a bit. + +This chapter was last modified on $Date: 1997/04/25 18:20:48 $. It is not updated regularly, and it +may be out of date. + +@menu +* GAS versions:: GAS versions +* Data types:: Data types +* GAS processing:: What GAS does when it runs +* Porting GAS:: Porting GAS +* Relaxation:: Relaxation +* Broken words:: Broken words +* Internal functions:: Internal functions +* Test suite:: Test suite +@end menu + +@node GAS versions +@section GAS versions + +GAS has acquired layers of code over time. The original GAS only supported the +a.out object file format, with three sections. Support for multiple sections +has been added in two different ways. + +The preferred approach is to use the version of GAS created when the symbol +@code{BFD_ASSEMBLER} is defined. The other versions of GAS are documented for +historical purposes, and to help anybody who has to debug code written for +them. + +The type @code{segT} is used to represent a section in code which must work +with all versions of GAS. + +@menu +* Original GAS:: Original GAS version +* MANY_SEGMENTS:: MANY_SEGMENTS gas version +* BFD_ASSEMBLER:: BFD_ASSEMBLER gas version +@end menu + +@node Original GAS +@subsection Original GAS + +The original GAS only supported the a.out object file format with three +sections: @samp{.text}, @samp{.data}, and @samp{.bss}. This is the version of +GAS that is compiled if neither @code{BFD_ASSEMBLER} nor @code{MANY_SEGMENTS} +is defined. This version of GAS is still used for the m68k-aout target, and +perhaps others. + +This version of GAS should not be used for any new development. + +There is still code that is specific to this version of GAS, notably in +@file{write.c}. There is no way for this code to loop through all the +sections; it simply looks at global variables like @code{text_frag_root} and +@code{data_frag_root}. + +The type @code{segT} is an enum. + +@node MANY_SEGMENTS +@subsection MANY_SEGMENTS gas version +@cindex MANY_SEGMENTS + +The @code{MANY_SEGMENTS} version of gas is only used for COFF. It uses the BFD +library, but it writes out all the data itself using @code{bfd_write}. This +version of gas supports up to 40 normal sections. The section names are stored +in the @code{seg_name} array. Other information is stored in the +@code{segment_info} array. + +The type @code{segT} is an enum. Code that wants to examine all the sections +can use a @code{segT} variable as loop index from @code{SEG_E0} up to but not +including @code{SEG_UNKNOWN}. + +Most of the code specific to this version of GAS is in the file +@file{config/obj-coff.c}, in the portion of that file that is compiled when +@code{BFD_ASSEMBLER} is not defined. + +This version of GAS is still used for several COFF targets. + +@node BFD_ASSEMBLER +@subsection BFD_ASSEMBLER gas version +@cindex BFD_ASSEMBLER + +The preferred version of GAS is the @code{BFD_ASSEMBLER} version. In this +version of GAS, the output file is a normal BFD, and the BFD routines are used +to generate the output. + +@code{BFD_ASSEMBLER} will automatically be used for certain targets, including +those that use the ELF, ECOFF, and SOM object file formats, and also all Alpha, +MIPS, PowerPC, and SPARC targets. You can force the use of +@code{BFD_ASSEMBLER} for other targets with the configure option +@samp{--enable-bfd-assembler}; however, it has not been tested for many +targets, and can not be assumed to work. + +@node Data types +@section Data types +@cindex internals, data types + +This section describes some fundamental GAS data types. + +@menu +* Symbols:: The symbolS structure +* Expressions:: The expressionS structure +* Fixups:: The fixS structure +* Frags:: The fragS structure +@end menu + +@node Symbols +@subsection Symbols +@cindex internals, symbols +@cindex symbols, internal +@cindex symbolS structure + +The definition for @code{struct symbol}, also known as @code{symbolS}, is +located in @file{struc-symbol.h}. Symbol structures contain the following +fields: + +@table @code +@item sy_value +This is an @code{expressionS} that describes the value of the symbol. It might +refer to one or more other symbols; if so, its true value may not be known +until @code{resolve_symbol_value} is called in @code{write_object_file}. + +The expression is often simply a constant. Before @code{resolve_symbol_value} +is called, the value is the offset from the frag (@pxref{Frags}). Afterward, +the frag address has been added in. + +@item sy_resolved +This field is non-zero if the symbol's value has been completely resolved. It +is used during the final pass over the symbol table. + +@item sy_resolving +This field is used to detect loops while resolving the symbol's value. + +@item sy_used_in_reloc +This field is non-zero if the symbol is used by a relocation entry. If a local +symbol is used in a relocation entry, it must be possible to redirect those +relocations to other symbols, or this symbol cannot be removed from the final +symbol list. + +@item sy_next +@itemx sy_previous +These pointers to other @code{symbolS} structures describe a singly or doubly +linked list. (If @code{SYMBOLS_NEED_BACKPOINTERS} is not defined, the +@code{sy_previous} field will be omitted; @code{SYMBOLS_NEED_BACKPOINTERS} is +always defined if @code{BFD_ASSEMBLER}.) These fields should be accessed with +the @code{symbol_next} and @code{symbol_previous} macros. + +@item sy_frag +This points to the frag (@pxref{Frags}) that this symbol is attached to. + +@item sy_used +Whether the symbol is used as an operand or in an expression. Note: Not all of +the backends keep this information accurate; backends which use this bit are +responsible for setting it when a symbol is used in backend routines. + +@item sy_mri_common +Whether the symbol is an MRI common symbol created by the @code{COMMON} +pseudo-op when assembling in MRI mode. + +@item bsym +If @code{BFD_ASSEMBLER} is defined, this points to the BFD @code{asymbol} that +will be used in writing the object file. + +@item sy_name_offset +(Only used if @code{BFD_ASSEMBLER} is not defined.) This is the position of +the symbol's name in the string table of the object file. On some formats, +this will start at position 4, with position 0 reserved for unnamed symbols. +This field is not used until @code{write_object_file} is called. + +@item sy_symbol +(Only used if @code{BFD_ASSEMBLER} is not defined.) This is the +format-specific symbol structure, as it would be written into the object file. + +@item sy_number +(Only used if @code{BFD_ASSEMBLER} is not defined.) This is a 24-bit symbol +number, for use in constructing relocation table entries. + +@item sy_obj +This format-specific data is of type @code{OBJ_SYMFIELD_TYPE}. If no macro by +that name is defined in @file{obj-format.h}, this field is not defined. + +@item sy_tc +This processor-specific data is of type @code{TC_SYMFIELD_TYPE}. If no macro +by that name is defined in @file{targ-cpu.h}, this field is not defined. + +@item TARGET_SYMBOL_FIELDS +If this macro is defined, it defines additional fields in the symbol structure. +This macro is obsolete, and should be replaced when possible by uses of +@code{OBJ_SYMFIELD_TYPE} and @code{TC_SYMFIELD_TYPE}. +@end table + +There are a number of access routines used to extract the fields of a +@code{symbolS} structure. When possible, these routines should be used rather +than referring to the fields directly. These routines will work for any GAS +version. + +@table @code +@item S_SET_VALUE +@cindex S_SET_VALUE +Set the symbol's value. + +@item S_GET_VALUE +@cindex S_GET_VALUE +Get the symbol's value. This will cause @code{resolve_symbol_value} to be +called if necessary, so @code{S_GET_VALUE} should only be called when it is +safe to resolve symbols (i.e., after the entire input file has been read and +all symbols have been defined). + +@item S_SET_SEGMENT +@cindex S_SET_SEGMENT +Set the section of the symbol. + +@item S_GET_SEGMENT +@cindex S_GET_SEGMENT +Get the symbol's section. + +@item S_GET_NAME +@cindex S_GET_NAME +Get the name of the symbol. + +@item S_SET_NAME +@cindex S_SET_NAME +Set the name of the symbol. + +@item S_IS_EXTERNAL +@cindex S_IS_EXTERNAL +Return non-zero if the symbol is externally visible. + +@item S_IS_EXTERN +@cindex S_IS_EXTERN +A synonym for @code{S_IS_EXTERNAL}. Don't use it. + +@item S_IS_WEAK +@cindex S_IS_WEAK +Return non-zero if the symbol is weak. + +@item S_IS_COMMON +@cindex S_IS_COMMON +Return non-zero if this is a common symbol. Common symbols are sometimes +represented as undefined symbols with a value, in which case this function will +not be reliable. + +@item S_IS_DEFINED +@cindex S_IS_DEFINED +Return non-zero if this symbol is defined. This function is not reliable when +called on a common symbol. + +@item S_IS_DEBUG +@cindex S_IS_DEBUG +Return non-zero if this is a debugging symbol. + +@item S_IS_LOCAL +@cindex S_IS_LOCAL +Return non-zero if this is a local assembler symbol which should not be +included in the final symbol table. Note that this is not the opposite of +@code{S_IS_EXTERNAL}. The @samp{-L} assembler option affects the return value +of this function. + +@item S_SET_EXTERNAL +@cindex S_SET_EXTERNAL +Mark the symbol as externally visible. + +@item S_CLEAR_EXTERNAL +@cindex S_CLEAR_EXTERNAL +Mark the symbol as not externally visible. + +@item S_SET_WEAK +@cindex S_SET_WEAK +Mark the symbol as weak. + +@item S_GET_TYPE +@item S_GET_DESC +@item S_GET_OTHER +@cindex S_GET_TYPE +@cindex S_GET_DESC +@cindex S_GET_OTHER +Get the @code{type}, @code{desc}, and @code{other} fields of the symbol. These +are only defined for object file formats for which they make sense (primarily +a.out). + +@item S_SET_TYPE +@item S_SET_DESC +@item S_SET_OTHER +@cindex S_SET_TYPE +@cindex S_SET_DESC +@cindex S_SET_OTHER +Set the @code{type}, @code{desc}, and @code{other} fields of the symbol. These +are only defined for object file formats for which they make sense (primarily +a.out). + +@item S_GET_SIZE +@cindex S_GET_SIZE +Get the size of a symbol. This is only defined for object file formats for +which it makes sense (primarily ELF). + +@item S_SET_SIZE +@cindex S_SET_SIZE +Set the size of a symbol. This is only defined for object file formats for +which it makes sense (primarily ELF). +@end table + +@node Expressions +@subsection Expressions +@cindex internals, expressions +@cindex expressions, internal +@cindex expressionS structure + +Expressions are stored in an @code{expressionS} structure. The structure is +defined in @file{expr.h}. + +@cindex expression +The macro @code{expression} will create an @code{expressionS} structure based +on the text found at the global variable @code{input_line_pointer}. + +@cindex make_expr_symbol +@cindex expr_symbol_where +A single @code{expressionS} structure can represent a single operation. +Complex expressions are formed by creating @dfn{expression symbols} and +combining them in @code{expressionS} structures. An expression symbol is +created by calling @code{make_expr_symbol}. An expression symbol should +naturally never appear in a symbol table, and the implementation of +@code{S_IS_LOCAL} (@pxref{Symbols}) reflects that. The function +@code{expr_symbol_where} returns non-zero if a symbol is an expression symbol, +and also returns the file and line for the expression which caused it to be +created. + +The @code{expressionS} structure has two symbol fields, a number field, an +operator field, and a field indicating whether the number is unsigned. + +The operator field is of type @code{operatorT}, and describes how to interpret +the other fields; see the definition in @file{expr.h} for the possibilities. + +An @code{operatorT} value of @code{O_big} indicates either a floating point +number, stored in the global variable @code{generic_floating_point_number}, or +an integer to large to store in an @code{offsetT} type, stored in the global +array @code{generic_bignum}. This rather inflexible approach makes it +impossible to use floating point numbers or large expressions in complex +expressions. + +@node Fixups +@subsection Fixups +@cindex internals, fixups +@cindex fixups +@cindex fixS structure + +A @dfn{fixup} is basically anything which can not be resolved in the first +pass. Sometimes a fixup can be resolved by the end of the assembly; if not, +the fixup becomes a relocation entry in the object file. + +@cindex fix_new +@cindex fix_new_exp +A fixup is created by a call to @code{fix_new} or @code{fix_new_exp}. Both +take a frag (@pxref{Frags}), a position within the frag, a size, an indication +of whether the fixup is PC relative, and a type. In a @code{BFD_ASSEMBLER} +GAS, the type is nominally a @code{bfd_reloc_code_real_type}, but several +targets use other type codes to represent fixups that can not be described as +relocations. + +The @code{fixS} structure has a number of fields, several of which are obsolete +or are only used by a particular target. The important fields are: + +@table @code +@item fx_frag +The frag (@pxref{Frags}) this fixup is in. + +@item fx_where +The location within the frag where the fixup occurs. + +@item fx_addsy +The symbol this fixup is against. Typically, the value of this symbol is added +into the object contents. This may be NULL. + +@item fx_subsy +The value of this symbol is subtracted from the object contents. This is +normally NULL. + +@item fx_offset +A number which is added into the fixup. + +@item fx_addnumber +Some CPU backends use this field to convey information between +@code{md_apply_fix} and @code{tc_gen_reloc}. The machine independent code does +not use it. + +@item fx_next +The next fixup in the section. + +@item fx_r_type +The type of the fixup. This field is only defined if @code{BFD_ASSEMBLER}, or +if the target defines @code{NEED_FX_R_TYPE}. + +@item fx_size +The size of the fixup. This is mostly used for error checking. + +@item fx_pcrel +Whether the fixup is PC relative. + +@item fx_done +Non-zero if the fixup has been applied, and no relocation entry needs to be +generated. + +@item fx_file +@itemx fx_line +The file and line where the fixup was created. + +@item tc_fix_data +This has the type @code{TC_FIX_TYPE}, and is only defined if the target defines +that macro. +@end table + +@node Frags +@subsection Frags +@cindex internals, frags +@cindex frags +@cindex fragS structure. + +The @code{fragS} structure is defined in @file{as.h}. Each frag represents a +portion of the final object file. As GAS reads the source file, it creates +frags to hold the data that it reads. At the end of the assembly the frags and +fixups are processed to produce the final contents. + +@table @code +@item fr_address +The address of the frag. This is not set until the assembler rescans the list +of all frags after the entire input file is parsed. The function +@code{relax_segment} fills in this field. + +@item fr_next +Pointer to the next frag in this (sub)section. + +@item fr_fix +Fixed number of characters we know we're going to emit to the output file. May +be zero. + +@item fr_var +Variable number of characters we may output, after the initial @code{fr_fix} +characters. May be zero. + +@item fr_offset +The interpretation of this field is controlled by @code{fr_type}. Generally, +if @code{fr_var} is non-zero, this is a repeat count: the @code{fr_var} +characters are output @code{fr_offset} times. + +@item line +Holds line number info when an assembler listing was requested. + +@item fr_type +Relaxation state. This field indicates the interpretation of @code{fr_offset}, +@code{fr_symbol} and the variable-length tail of the frag, as well as the +treatment it gets in various phases of processing. It does not affect the +initial @code{fr_fix} characters; they are always supposed to be output +verbatim (fixups aside). See below for specific values this field can have. + +@item fr_subtype +Relaxation substate. If the macro @code{md_relax_frag} isn't defined, this is +assumed to be an index into @code{TC_GENERIC_RELAX_TABLE} for the generic +relaxation code to process (@pxref{Relaxation}). If @code{md_relax_frag} is +defined, this field is available for any use by the CPU-specific code. + +@item fr_symbol +This normally indicates the symbol to use when relaxing the frag according to +@code{fr_type}. + +@item fr_opcode +Points to the lowest-addressed byte of the opcode, for use in relaxation. + +@item fr_pcrel_adjust +@itemx fr_bsr +These fields are only used in the NS32k configuration. But since @code{struct +frag} is defined before the CPU-specific header files are included, they must +unconditionally be defined. + +@item fr_file +@itemx fr_line +The file and line where this frag was last modified. + +@item fr_literal +Declared as a one-character array, this last field grows arbitrarily large to +hold the actual contents of the frag. +@end table + +These are the possible relaxation states, provided in the enumeration type +@code{relax_stateT}, and the interpretations they represent for the other +fields: + +@table @code +@item rs_align +@itemx rs_align_code +The start of the following frag should be aligned on some boundary. In this +frag, @code{fr_offset} is the logarithm (base 2) of the alignment in bytes. +(For example, if alignment on an 8-byte boundary were desired, @code{fr_offset} +would have a value of 3.) The variable characters indicate the fill pattern to +be used. The @code{fr_subtype} field holds the maximum number of bytes to skip +when doing this alignment. If more bytes are needed, the alignment is not +done. An @code{fr_subtype} value of 0 means no maximum, which is the normal +case. Target backends can use @code{rs_align_code} to handle certain types of +alignment differently. + +@item rs_broken_word +This indicates that ``broken word'' processing should be done (@pxref{Broken +words}). If broken word processing is not necessary on the target machine, +this enumerator value will not be defined. + +@item rs_fill +The variable characters are to be repeated @code{fr_offset} times. If +@code{fr_offset} is 0, this frag has a length of @code{fr_fix}. Most frags +have this type. + +@item rs_machine_dependent +Displacement relaxation is to be done on this frag. The target is indicated by +@code{fr_symbol} and @code{fr_offset}, and @code{fr_subtype} indicates the +particular machine-specific addressing mode desired. @xref{Relaxation}. + +@item rs_org +The start of the following frag should be pushed back to some specific offset +within the section. (Some assemblers use the value as an absolute address; GAS +does not handle final absolute addresses, but rather requires that the linker +set them.) The offset is given by @code{fr_symbol} and @code{fr_offset}; one +character from the variable-length tail is used as the fill character. +@end table + +@cindex frchainS structure +A chain of frags is built up for each subsection. The data structure +describing a chain is called a @code{frchainS}, and contains the following +fields: + +@table @code +@item frch_root +Points to the first frag in the chain. May be NULL if there are no frags in +this chain. +@item frch_last +Points to the last frag in the chain, or NULL if there are none. +@item frch_next +Next in the list of @code{frchainS} structures. +@item frch_seg +Indicates the section this frag chain belongs to. +@item frch_subseg +Subsection (subsegment) number of this frag chain. +@item fix_root, fix_tail +(Defined only if @code{BFD_ASSEMBLER} is defined). Point to first and last +@code{fixS} structures associated with this subsection. +@item frch_obstack +Not currently used. Intended to be used for frag allocation for this +subsection. This should reduce frag generation caused by switching sections. +@item frch_frag_now +The current frag for this subsegment. +@end table + +A @code{frchainS} corresponds to a subsection; each section has a list of +@code{frchainS} records associated with it. In most cases, only one subsection +of each section is used, so the list will only be one element long, but any +processing of frag chains should be prepared to deal with multiple chains per +section. + +After the input files have been completely processed, and no more frags are to +be generated, the frag chains are joined into one per section for further +processing. After this point, it is safe to operate on one chain per section. + +The assembler always has a current frag, named @code{frag_now}. More space is +allocated for the current frag using the @code{frag_more} function; this +returns a pointer to the amount of requested space. Relaxing is done using +variant frags allocated by @code{frag_var} or @code{frag_variant} +(@pxref{Relaxation}). + +@node GAS processing +@section What GAS does when it runs +@cindex internals, overview + +This is a quick look at what an assembler run looks like. + +@itemize @bullet +@item +The assembler initializes itself by calling various init routines. + +@item +For each source file, the @code{read_a_source_file} function reads in the file +and parses it. The global variable @code{input_line_pointer} points to the +current text; it is guaranteed to be correct up to the end of the line, but not +farther. + +@item +For each line, the assembler passes labels to the @code{colon} function, and +isolates the first word. If it looks like a pseudo-op, the word is looked up +in the pseudo-op hash table @code{po_hash} and dispatched to a pseudo-op +routine. Otherwise, the target dependent @code{md_assemble} routine is called +to parse the instruction. + +@item +When pseudo-ops or instructions output data, they add it to a frag, calling +@code{frag_more} to get space to store it in. + +@item +Pseudo-ops and instructions can also output fixups created by @code{fix_new} or +@code{fix_new_exp}. + +@item +For certain targets, instructions can create variant frags which are used to +store relaxation information (@pxref{Relaxation}). + +@item +When the input file is finished, the @code{write_object_file} routine is +called. It assigns addresses to all the frags (@code{relax_segment}), resolves +all the fixups (@code{fixup_segment}), resolves all the symbol values (using +@code{resolve_symbol_value}), and finally writes out the file (in the +@code{BFD_ASSEMBLER} case, this is done by simply calling @code{bfd_close}). +@end itemize + +@node Porting GAS +@section Porting GAS +@cindex porting + +Each GAS target specifies two main things: the CPU file and the object format +file. Two main switches in the @file{configure.in} file handle this. The +first switches on CPU type to set the shell variable @code{cpu_type}. The +second switches on the entire target to set the shell variable @code{fmt}. + +The configure script uses the value of @code{cpu_type} to select two files in +the @file{config} directory: @file{tc-@var{CPU}.c} and @file{tc-@var{CPU}.h}. +The configuration process will create a file named @file{targ-cpu.h} in the +build directory which includes @file{tc-@var{CPU}.h}. + +The configure script also uses the value of @code{fmt} to select two files: +@file{obj-@var{fmt}.c} and @file{obj-@var{fmt}.h}. The configuration process +will create a file named @file{obj-format.h} in the build directory which +includes @file{obj-@var{fmt}.h}. + +You can also set the emulation in the configure script by setting the @code{em} +variable. Normally the default value of @samp{generic} is fine. The +configuration process will create a file named @file{targ-env.h} in the build +directory which includes @file{te-@var{em}.h}. + +Porting GAS to a new CPU requires writing the @file{tc-@var{CPU}} files. +Porting GAS to a new object file format requires writing the +@file{obj-@var{fmt}} files. There is sometimes some interaction between these +two files, but it is normally minimal. + +The best approach is, of course, to copy existing files. The documentation +below assumes that you are looking at existing files to see usage details. + +These interfaces have grown over time, and have never been carefully thought +out or designed. Nothing about the interfaces described here is cast in stone. +It is possible that they will change from one version of the assembler to the +next. Also, new macros are added all the time as they are needed. + +@menu +* CPU backend:: Writing a CPU backend +* Object format backend:: Writing an object format backend +* Emulations:: Writing emulation files +@end menu + +@node CPU backend +@subsection Writing a CPU backend +@cindex CPU backend +@cindex @file{tc-@var{CPU}} + +The CPU backend files are the heart of the assembler. They are the only parts +of the assembler which actually know anything about the instruction set of the +processor. + +You must define a reasonably small list of macros and functions in the CPU +backend files. You may define a large number of additional macros in the CPU +backend files, not all of which are documented here. You must, of course, +define macros in the @file{.h} file, which is included by every assembler +source file. You may define the functions as macros in the @file{.h} file, or +as functions in the @file{.c} file. + +@table @code +@item TC_@var{CPU} +@cindex TC_@var{CPU} +By convention, you should define this macro in the @file{.h} file. For +example, @file{tc-m68k.h} defines @code{TC_M68K}. You might have to use this +if it is necessary to add CPU specific code to the object format file. + +@item TARGET_FORMAT +This macro is the BFD target name to use when creating the output file. This +will normally depend upon the @code{OBJ_@var{FMT}} macro. + +@item TARGET_ARCH +This macro is the BFD architecture to pass to @code{bfd_set_arch_mach}. + +@item TARGET_MACH +This macro is the BFD machine number to pass to @code{bfd_set_arch_mach}. If +it is not defined, GAS will use 0. + +@item TARGET_BYTES_BIG_ENDIAN +You should define this macro to be non-zero if the target is big endian, and +zero if the target is little endian. + +@item md_shortopts +@itemx md_longopts +@itemx md_longopts_size +@itemx md_parse_option +@itemx md_show_usage +@cindex md_shortopts +@cindex md_longopts +@cindex md_longopts_size +@cindex md_parse_option +@cindex md_show_usage +GAS uses these variables and functions during option processing. +@code{md_shortopts} is a @code{const char *} which GAS adds to the machine +independent string passed to @code{getopt}. @code{md_longopts} is a +@code{struct option []} which GAS adds to the machine independent long options +passed to @code{getopt}; you may use @code{OPTION_MD_BASE}, defined in +@file{as.h}, as the start of a set of long option indices, if necessary. +@code{md_longopts_size} is a @code{size_t} holding the size @code{md_longopts}. +GAS will call @code{md_parse_option} whenever @code{getopt} returns an +unrecognized code, presumably indicating a special code value which appears in +@code{md_longopts}. GAS will call @code{md_show_usage} when a usage message is +printed; it should print a description of the machine specific options. + +@item md_begin +@cindex md_begin +GAS will call this function at the start of the assembly, after the command +line arguments have been parsed and all the machine independent initializations +have been completed. + +@item md_cleanup +@cindex md_cleanup +If you define this macro, GAS will call it at the end of each input file. + +@item md_assemble +@cindex md_assemble +GAS will call this function for each input line which does not contain a +pseudo-op. The argument is a null terminated string. The function should +assemble the string as an instruction with operands. Normally +@code{md_assemble} will do this by calling @code{frag_more} and writing out +some bytes (@pxref{Frags}). @code{md_assemble} will call @code{fix_new} to +create fixups as needed (@pxref{Fixups}). Targets which need to do special +purpose relaxation will call @code{frag_var}. + +@item md_pseudo_table +@cindex md_pseudo_table +This is a const array of type @code{pseudo_typeS}. It is a mapping from +pseudo-op names to functions. You should use this table to implement +pseudo-ops which are specific to the CPU. + +@item tc_conditional_pseudoop +@cindex tc_conditional_pseudoop +If this macro is defined, GAS will call it with a @code{pseudo_typeS} argument. +It should return non-zero if the pseudo-op is a conditional which controls +whether code is assembled, such as @samp{.if}. GAS knows about the normal +conditional pseudo-ops,and you should normally not have to define this macro. + +@item comment_chars +@cindex comment_chars +This is a null terminated @code{const char} array of characters which start a +comment. + +@item tc_comment_chars +@cindex tc_comment_chars +If this macro is defined, GAS will use it instead of @code{comment_chars}. + +@item line_comment_chars +@cindex line_comment_chars +This is a null terminated @code{const char} array of characters which start a +comment when they appear at the start of a line. + +@item line_separator_chars +@cindex line_separator_chars +This is a null terminated @code{const char} array of characters which separate +lines (the semicolon is such a character by default, and need not be listed in +this array). + +@item EXP_CHARS +@cindex EXP_CHARS +This is a null terminated @code{const char} array of characters which may be +used as the exponent character in a floating point number. This is normally +@code{"eE"}. + +@item FLT_CHARS +@cindex FLT_CHARS +This is a null terminated @code{const char} array of characters which may be +used to indicate a floating point constant. A zero followed by one of these +characters is assumed to be followed by a floating point number; thus they +operate the way that @code{0x} is used to indicate a hexadecimal constant. +Usually this includes @samp{r} and @samp{f}. + +@item LEX_AT +@cindex LEX_AT +You may define this macro to the lexical type of the @kbd{@}} character. The +default is zero. + +Lexical types are a combination of @code{LEX_NAME} and @code{LEX_BEGIN_NAME}, +both defined in @file{read.h}. @code{LEX_NAME} indicates that the character +may appear in a name. @code{LEX_BEGIN_NAME} indicates that the character may +appear at the beginning of a nem. + +@item LEX_BR +@cindex LEX_BR +You may define this macro to the lexical type of the brace characters @kbd{@{}, +@kbd{@}}, @kbd{[}, and @kbd{]}. The default value is zero. + +@item LEX_PCT +@cindex LEX_PCT +You may define this macro to the lexical type of the @kbd{%} character. The +default value is zero. + +@item LEX_QM +@cindex LEX_QM +You may define this macro to the lexical type of the @kbd{?} character. The +default value it zero. + +@item LEX_DOLLAR +@cindex LEX_DOLLAR +You may define this macro to the lexical type of the @kbd{$} character. The +default value is @code{LEX_NAME | LEX_BEGIN_NAME}. + +@item SINGLE_QUOTE_STRINGS +@cindex SINGLE_QUOTE_STRINGS +If you define this macro, GAS will treat single quotes as string delimiters. +Normally only double quotes are accepted as string delimiters. + +@item NO_STRING_ESCAPES +@cindex NO_STRING_ESCAPES +If you define this macro, GAS will not permit escape sequences in a string. + +@item ONLY_STANDARD_ESCAPES +@cindex ONLY_STANDARD_ESCAPES +If you define this macro, GAS will warn about the use of nonstandard escape +sequences in a string. + +@item md_start_line_hook +@cindex md_start_line_hook +If you define this macro, GAS will call it at the start of each line. + +@item LABELS_WITHOUT_COLONS +@cindex LABELS_WITHOUT_COLONS +If you define this macro, GAS will assume that any text at the start of a line +is a label, even if it does not have a colon. + +@item TC_START_LABEL +@cindex TC_START_LABEL +You may define this macro to control what GAS considers to be a label. The +default definition is to accept any name followed by a colon character. + +@item NO_PSEUDO_DOT +@cindex NO_PSEUDO_DOT +If you define this macro, GAS will not require pseudo-ops to start with a +@kbd{.} character. + +@item TC_EQUAL_IN_INSN +@cindex TC_EQUAL_IN_INSN +If you define this macro, it should return nonzero if the instruction is +permitted to contain an @kbd{=} character. GAS will use this to decide if a +@kbd{=} is an assignment or an instruction. + +@item TC_EOL_IN_INSN +@cindex TC_EOL_IN_INSN +If you define this macro, it should return nonzero if the current input line +pointer should be treated as the end of a line. + +@item md_parse_name +@cindex md_parse_name +If this macro is defined, GAS will call it for any symbol found in an +expression. You can define this to handle special symbols in a special way. +If a symbol always has a certain value, you should normally enter it in the +symbol table, perhaps using @code{reg_section}. + +@item md_undefined_symbol +@cindex md_undefined_symbol +GAS will call this function when a symbol table lookup fails, before it +creates a new symbol. Typically this would be used to supply symbols whose +name or value changes dynamically, possibly in a context sensitive way. +Predefined symbols with fixed values, such as register names or condition +codes, are typically entered directly into the symbol table when @code{md_begin} +is called. + +@item md_operand +@cindex md_operand +GAS will call this function for any expression that can not be recognized. +When the function is called, @code{input_line_pointer} will point to the start +of the expression. + +@item tc_unrecognized_line +@cindex tc_unrecognized_line +If you define this macro, GAS will call it when it finds a line that it can not +parse. + +@item md_do_align +@cindex md_do_align +You may define this macro to handle an alignment directive. GAS will call it +when the directive is seen in the input file. For example, the i386 backend +uses this to generate efficient nop instructions of varying lengths, depending +upon the number of bytes that the alignment will skip. + +@item HANDLE_ALIGN +@cindex HANDLE_ALIGN +You may define this macro to do special handling for an alignment directive. +GAS will call it at the end of the assembly. + +@item md_flush_pending_output +@cindex md_flush_pending_output +If you define this macro, GAS will call it each time it skips any space because of a +space filling or alignment or data allocation pseudo-op. + +@item TC_PARSE_CONS_EXPRESSION +@cindex TC_PARSE_CONS_EXPRESSION +You may define this macro to parse an expression used in a data allocation +pseudo-op such as @code{.word}. You can use this to recognize relocation +directives that may appear in such directives. + +@item BITFIELD_CONS_EXPRESSION +@cindex BITFIELD_CONS_EXPRESSION +If you define this macro, GAS will recognize bitfield instructions in data +allocation pseudo-ops, as used on the i960. + +@item REPEAT_CONS_EXPRESSION +@cindex REPEAT_CONS_EXPRESSION +If you define this macro, GAS will recognize repeat counts in data allocation +pseudo-ops, as used on the MIPS. + +@item md_cons_align +@cindex md_cons_align +You may define this macro to do any special alignment before a data allocation +pseudo-op. + +@item TC_CONS_FIX_NEW +@cindex TC_CONS_FIX_NEW +You may define this macro to generate a fixup for a data allocation pseudo-op. + +@item md_number_to_chars +@cindex md_number_to_chars +This should just call either @code{number_to_chars_bigendian} or +@code{number_to_chars_littleendian}, whichever is appropriate. On targets like +the MIPS which support options to change the endianness, which function to call +is a runtime decision. On other targets, @code{md_number_to_chars} can be a +simple macro. + +@item md_reloc_size +@cindex md_reloc_size +This variable is only used in the original version of gas (not +@code{BFD_ASSEMBLER} and not @code{MANY_SEGMENTS}). It holds the size of a +relocation entry. + +@item WORKING_DOT_WORD +@itemx md_short_jump_size +@itemx md_long_jump_size +@itemx md_create_short_jump +@itemx md_create_long_jump +@cindex WORKING_DOT_WORD +@cindex md_short_jump_size +@cindex md_long_jump_size +@cindex md_create_short_jump +@cindex md_create_long_jump +If @code{WORKING_DOT_WORD} is defined, GAS will not do broken word processing +(@pxref{Broken words}). Otherwise, you should set @code{md_short_jump_size} to +the size of a short jump (a jump that is just long enough to jump around a long +jmp) and @code{md_long_jump_size} to the size of a long jump (a jump that can +go anywhere in the function), You should define @code{md_create_short_jump} to +create a short jump around a long jump, and define @code{md_create_long_jump} +to create a long jump. + +@item md_estimate_size_before_relax +@cindex md_estimate_size_before_relax +This function returns an estimate of the size of a @code{rs_machine_dependent} +frag before any relaxing is done. It may also create any necessary +relocations. + +@item md_relax_frag +@cindex md_relax_frag +This macro may be defined to relax a frag. GAS will call this with the frag +and the change in size of all previous frags; @code{md_relax_frag} should +return the change in size of the frag. @xref{Relaxation}. + +@item TC_GENERIC_RELAX_TABLE +@cindex TC_GENERIC_RELAX_TABLE +If you do not define @code{md_relax_frag}, you may define +@code{TC_GENERIC_RELAX_TABLE} as a table of @code{relax_typeS} structures. The +machine independent code knows how to use such a table to relax PC relative +references. See @file{tc-m68k.c} for an example. @xref{Relaxation}. + +@item md_prepare_relax_scan +@cindex md_prepare_relax_scan +If defined, it is a C statement that is invoked prior to scanning +the relax table. + +@item LINKER_RELAXING_SHRINKS_ONLY +@cindex LINKER_RELAXING_SHRINKS_ONLY +If you define this macro, and the global variable @samp{linkrelax} is set +(because of a command line option, or unconditionally in @code{md_begin}), a +@samp{.align} directive will cause extra space to be allocated. The linker can +then discard this space when relaxing the section. + +@item md_convert_frag +@cindex md_convert_frag +GAS will call this for each rs_machine_dependent fragment. +The instruction is completed using the data from the relaxation pass. +It may also create any necessary relocations. +@xref{Relaxation}. + +@item md_apply_fix +@cindex md_apply_fix +GAS will call this for each fixup. It should store the correct value in the +object file. + +@item TC_HANDLES_FX_DONE +@cindex TC_HANDLES_FX_DONE +If this macro is defined, it means that @code{md_apply_fix} correctly sets the +@code{fx_done} field in the fixup. + +@item tc_gen_reloc +@cindex tc_gen_reloc +A @code{BFD_ASSEMBLER} GAS will call this to generate a reloc. GAS will pass +the resulting reloc to @code{bfd_install_relocation}. This currently works +poorly, as @code{bfd_install_relocation} often does the wrong thing, and +instances of @code{tc_gen_reloc} have been written to work around the problems, +which in turns makes it difficult to fix @code{bfd_install_relocation}. + +@item RELOC_EXPANSION_POSSIBLE +@cindex RELOC_EXPANSION_POSSIBLE +If you define this macro, it means that @code{tc_gen_reloc} may return multiple +relocation entries for a single fixup. In this case, the return value of +@code{tc_gen_reloc} is a pointer to a null terminated array. + +@item MAX_RELOC_EXPANSION +@cindex MAX_RELOC_EXPANSION +You must define this if @code{RELOC_EXPANSION_POSSIBLE} is defined; it +indicates the largest number of relocs which @code{tc_gen_reloc} may return for +a single fixup. + +@item tc_fix_adjustable +@cindex tc_fix_adjustable +You may define this macro to indicate whether a fixup against a locally defined +symbol should be adjusted to be against the section symbol. It should return a +non-zero value if the adjustment is acceptable. + +@item MD_PCREL_FROM_SECTION +@cindex MD_PCREL_FROM_SECTION +If you define this macro, it should return the offset between the address of a +PC relative fixup and the position from which the PC relative adjustment should +be made. On many processors, the base of a PC relative instruction is the next +instruction, so this macro would return the length of an instruction. + +@item md_pcrel_from +@cindex md_pcrel_from +This is the default value of @code{MD_PCREL_FROM_SECTION}. The difference is +that @code{md_pcrel_from} does not take a section argument. + +@item tc_frob_label +@cindex tc_frob_label +If you define this macro, GAS will call it each time a label is defined. + +@item md_section_align +@cindex md_section_align +GAS will call this function for each section at the end of the assembly, to +permit the CPU backend to adjust the alignment of a section. + +@item tc_frob_section +@cindex tc_frob_section +If you define this macro, a @code{BFD_ASSEMBLER} GAS will call it for each +section at the end of the assembly. + +@item tc_frob_file_before_adjust +@cindex tc_frob_file_before_adjust +If you define this macro, GAS will call it after the symbol values are +resolved, but before the fixups have been changed from local symbols to section +symbols. + +@item tc_frob_symbol +@cindex tc_frob_symbol +If you define this macro, GAS will call it for each symbol. You can indicate +that the symbol should not be included in the object file by definining this +macro to set its second argument to a non-zero value. + +@item tc_frob_file +@cindex tc_frob_file +If you define this macro, GAS will call it after the symbol table has been +completed, but before the relocations have been generated. + +@item tc_frob_file_after_relocs +If you define this macro, GAS will call it after the relocs have been +generated. + +@item LISTING_HEADER +A string to use on the header line of a listing. The default value is simply +@code{"GAS LISTING"}. + +@item LISTING_WORD_SIZE +The number of bytes to put into a word in a listing. This affects the way the +bytes are clumped together in the listing. For example, a value of 2 might +print @samp{1234 5678} where a value of 1 would print @samp{12 34 56 78}. The +default value is 4. + +@item LISTING_LHS_WIDTH +The number of words of data to print on the first line of a listing for a +particular source line, where each word is @code{LISTING_WORD_SIZE} bytes. The +default value is 1. + +@item LISTING_LHS_WIDTH_SECOND +Like @code{LISTING_LHS_WIDTH}, but applying to the second and subsequent line +of the data printed for a particular source line. The default value is 1. + +@item LISTING_LHS_CONT_LINES +The maximum number of continuation lines to print in a listing for a particular +source line. The default value is 4. + +@item LISTING_RHS_WIDTH +The maximum number of characters to print from one line of the input file. The +default value is 100. +@end table + +@node Object format backend +@subsection Writing an object format backend +@cindex object format backend +@cindex @file{obj-@var{fmt}} + +As with the CPU backend, the object format backend must define a few things, +and may define some other things. The interface to the object format backend +is generally simpler; most of the support for an object file format consists of +defining a number of pseudo-ops. + +The object format @file{.h} file must include @file{targ-cpu.h}. + +This section will only define the @code{BFD_ASSEMBLER} version of GAS. It is +impossible to support a new object file format using any other version anyhow, +as the original GAS version only supports a.out, and the @code{MANY_SEGMENTS} +GAS version only supports COFF. + +@table @code +@item OBJ_@var{format} +@cindex OBJ_@var{format} +By convention, you should define this macro in the @file{.h} file. For +example, @file{obj-elf.h} defines @code{OBJ_ELF}. You might have to use this +if it is necessary to add object file format specific code to the CPU file. + +@item obj_begin +If you define this macro, GAS will call it at the start of the assembly, after +the command line arguments have been parsed and all the machine independent +initializations have been completed. + +@item obj_app_file +@cindex obj_app_file +If you define this macro, GAS will invoke it when it sees a @code{.file} +pseudo-op or a @samp{#} line as used by the C preprocessor. + +@item OBJ_COPY_SYMBOL_ATTRIBUTES +@cindex OBJ_COPY_SYMBOL_ATTRIBUTES +You should define this macro to copy object format specific information from +one symbol to another. GAS will call it when one symbol is equated to +another. + +@item obj_fix_adjustable +@cindex obj_fix_adjustable +You may define this macro to indicate whether a fixup against a locally defined +symbol should be adjusted to be against the section symbol. It should return a +non-zero value if the adjustment is acceptable. + +@item obj_sec_sym_ok_for_reloc +@cindex obj_sec_sym_ok_for_reloc +You may define this macro to indicate that it is OK to use a section symbol in +a relocateion entry. If it is not, GAS will define a new symbol at the start +of a section. + +@item EMIT_SECTION_SYMBOLS +@cindex EMIT_SECTION_SYMBOLS +You should define this macro with a zero value if you do not want to include +section symbols in the output symbol table. The default value for this macro +is one. + +@item obj_adjust_symtab +@cindex obj_adjust_symtab +If you define this macro, GAS will invoke it just before setting the symbol +table of the output BFD. For example, the COFF support uses this macro to +generate a @code{.file} symbol if none was generated previously. + +@item SEPARATE_STAB_SECTIONS +@cindex SEPARATE_STAB_SECTIONS +You may define this macro to indicate that stabs should be placed in separate +sections, as in ELF. + +@item INIT_STAB_SECTION +@cindex INIT_STAB_SECTION +You may define this macro to initialize the stabs section in the output file. + +@item OBJ_PROCESS_STAB +@cindex OBJ_PROCESS_STAB +You may define this macro to do specific processing on a stabs entry. + +@item obj_frob_section +@cindex obj_frob_section +If you define this macro, GAS will call it for each section at the end of the +assembly. + +@item obj_frob_file_before_adjust +@cindex obj_frob_file_before_adjust +If you define this macro, GAS will call it after the symbol values are +resolved, but before the fixups have been changed from local symbols to section +symbols. + +@item obj_frob_symbol +@cindex obj_frob_symbol +If you define this macro, GAS will call it for each symbol. You can indicate +that the symbol should not be included in the object file by definining this +macro to set its second argument to a non-zero value. + +@item obj_frob_file +@cindex obj_frob_file +If you define this macro, GAS will call it after the symbol table has been +completed, but before the relocations have been generated. + +@item obj_frob_file_after_relocs +If you define this macro, GAS will call it after the relocs have been +generated. +@end table + +@node Emulations +@subsection Writing emulation files + +Normally you do not have to write an emulation file. You can just use +@file{te-generic.h}. + +If you do write your own emulation file, it must include @file{obj-format.h}. + +An emulation file will often define @code{TE_@var{EM}}; this may then be used +in other files to change the output. + +@node Relaxation +@section Relaxation +@cindex relaxation + +@dfn{Relaxation} is a generic term used when the size of some instruction or +data depends upon the value of some symbol or other data. + +GAS knows to relax a particular type of PC relative relocation using a table. +You can also define arbitrarily complex forms of relaxation yourself. + +@menu +* Relaxing with a table:: Relaxing with a table +* General relaxing:: General relaxing +@end menu + +@node Relaxing with a table +@subsection Relaxing with a table + +If you do not define @code{md_relax_frag}, and you do define +@code{TC_GENERIC_RELAX_TABLE}, GAS will relax @code{rs_machine_dependent} frags +based on the frag subtype and the displacement to some specified target +address. The basic idea is that several machines have different addressing +modes for instructions that can specify different ranges of values, with +successive modes able to access wider ranges, including the entirety of the +previous range. Smaller ranges are assumed to be more desirable (perhaps the +instruction requires one word instead of two or three); if this is not the +case, don't describe the smaller-range, inferior mode. + +The @code{fr_subtype} field of a frag is an index into a CPU-specific +relaxation table. That table entry indicates the range of values that can be +stored, the number of bytes that will have to be added to the frag to +accomodate the addressing mode, and the index of the next entry to examine if +the value to be stored is outside the range accessible by the current +addressing mode. The @code{fr_symbol} field of the frag indicates what symbol +is to be accessed; the @code{fr_offset} field is added in. + +If the @code{fr_pcrel_adjust} field is set, which currently should only happen +for the NS32k family, the @code{TC_PCREL_ADJUST} macro is called on the frag to +compute an adjustment to be made to the displacement. + +The value fitted by the relaxation code is always assumed to be a displacement +from the current frag. (More specifically, from @code{fr_fix} bytes into the +frag.) +@ignore +This seems kinda silly. What about fitting small absolute values? I suppose +@code{md_assemble} is supposed to take care of that, but if the operand is a +difference between symbols, it might not be able to, if the difference was not +computable yet. +@end ignore + +The end of the relaxation sequence is indicated by a ``next'' value of 0. This +means that the first entry in the table can't be used. + +For some configurations, the linker can do relaxing within a section of an +object file. If call instructions of various sizes exist, the linker can +determine which should be used in each instance, when a symbol's value is +resolved. In order for the linker to avoid wasting space and having to insert +no-op instructions, it must be able to expand or shrink the section contents +while still preserving intra-section references and meeting alignment +requirements. + +For the i960 using b.out format, no expansion is done; instead, each +@samp{.align} directive causes extra space to be allocated, enough that when +the linker is relaxing a section and removing unneeded space, it can discard +some or all of this extra padding and cause the following data to be correctly +aligned. + +For the H8/300, I think the linker expands calls that can't reach, and doesn't +worry about alignment issues; the cpu probably never needs any significant +alignment beyond the instruction size. + +The relaxation table type contains these fields: + +@table @code +@item long rlx_forward +Forward reach, must be non-negative. +@item long rlx_backward +Backward reach, must be zero or negative. +@item rlx_length +Length in bytes of this addressing mode. +@item rlx_more +Index of the next-longer relax state, or zero if there is no next relax state. +@end table + +The relaxation is done in @code{relax_segment} in @file{write.c}. The +difference in the length fields between the original mode and the one finally +chosen by the relaxing code is taken as the size by which the current frag will +be increased in size. For example, if the initial relaxing mode has a length +of 2 bytes, and because of the size of the displacement, it gets upgraded to a +mode with a size of 6 bytes, it is assumed that the frag will grow by 4 bytes. +(The initial two bytes should have been part of the fixed portion of the frag, +since it is already known that they will be output.) This growth must be +effected by @code{md_convert_frag}; it should increase the @code{fr_fix} field +by the appropriate size, and fill in the appropriate bytes of the frag. +(Enough space for the maximum growth should have been allocated in the call to +frag_var as the second argument.) + +If relocation records are needed, they should be emitted by +@code{md_estimate_size_before_relax}. This function should examine the target +symbol of the supplied frag and correct the @code{fr_subtype} of the frag if +needed. When this function is called, if the symbol has not yet been defined, +it will not become defined later; however, its value may still change if the +section it is in gets relaxed. + +Usually, if the symbol is in the same section as the frag (given by the +@var{sec} argument), the narrowest likely relaxation mode is stored in +@code{fr_subtype}, and that's that. + +If the symbol is undefined, or in a different section (and therefore moveable +to an arbitrarily large distance), the largest available relaxation mode is +specified, @code{fix_new} is called to produce the relocation record, +@code{fr_fix} is increased to include the relocated field (remember, this +storage was allocated when @code{frag_var} was called), and @code{frag_wane} is +called to convert the frag to an @code{rs_fill} frag with no variant part. +Sometimes changing addressing modes may also require rewriting the instruction. +It can be accessed via @code{fr_opcode} or @code{fr_fix}. + +Sometimes @code{fr_var} is increased instead, and @code{frag_wane} is not +called. I'm not sure, but I think this is to keep @code{fr_fix} referring to +an earlier byte, and @code{fr_subtype} set to @code{rs_machine_dependent} so +that @code{md_convert_frag} will get called. + +@node General relaxing +@subsection General relaxing + +If using a simple table is not suitable, you may implement arbitrarily complex +relaxation semantics yourself. For example, the MIPS backend uses this to emit +different instruction sequences depending upon the size of the symbol being +accessed. + +When you assemble an instruction that may need relaxation, you should allocate +a frag using @code{frag_var} or @code{frag_variant} with a type of +@code{rs_machine_dependent}. You should store some sort of information in the +@code{fr_subtype} field so that you can figure out what to do with the frag +later. + +When GAS reaches the end of the input file, it will look through the frags and +work out their final sizes. + +GAS will first call @code{md_estimate_size_before_relax} on each +@code{rs_machine_dependent} frag. This function must return an estimated size +for the frag. + +GAS will then loop over the frags, calling @code{md_relax_frag} on each +@code{rs_machine_dependent} frag. This function should return the change in +size of the frag. GAS will keep looping over the frags until none of the frags +changes size. + +@node Broken words +@section Broken words +@cindex internals, broken words +@cindex broken words + +Some compilers, including GCC, will sometimes emit switch tables specifying +16-bit @code{.word} displacements to branch targets, and branch instructions +that load entries from that table to compute the target address. If this is +done on a 32-bit machine, there is a chance (at least with really large +functions) that the displacement will not fit in 16 bits. The assembler +handles this using a concept called @dfn{broken words}. This idea is well +named, since there is an implied promise that the 16-bit field will in fact +hold the specified displacement. + +If broken word processing is enabled, and a situation like this is encountered, +the assembler will insert a jump instruction into the instruction stream, close +enough to be reached with the 16-bit displacement. This jump instruction will +transfer to the real desired target address. Thus, as long as the @code{.word} +value really is used as a displacement to compute an address to jump to, the +net effect will be correct (minus a very small efficiency cost). If +@code{.word} directives with label differences for values are used for other +purposes, however, things may not work properly. For targets which use broken +words, the @samp{-K} option will warn when a broken word is discovered. + +The broken word code is turned off by the @code{WORKING_DOT_WORD} macro. It +isn't needed if @code{.word} emits a value large enough to contain an address +(or, more correctly, any possible difference between two addresses). + +@node Internal functions +@section Internal functions + +This section describes basic internal functions used by GAS. + +@menu +* Warning and error messages:: Warning and error messages +* Hash tables:: Hash tables +@end menu + +@node Warning and error messages +@subsection Warning and error messages + +@deftypefun @{@} int had_warnings (void) +@deftypefunx @{@} int had_errors (void) +Returns non-zero if any warnings or errors, respectively, have been printed +during this invocation. +@end deftypefun + +@deftypefun @{@} void as_perror (const char *@var{gripe}, const char *@var{filename}) +Displays a BFD or system error, then clears the error status. +@end deftypefun + +@deftypefun @{@} void as_tsktsk (const char *@var{format}, ...) +@deftypefunx @{@} void as_warn (const char *@var{format}, ...) +@deftypefunx @{@} void as_bad (const char *@var{format}, ...) +@deftypefunx @{@} void as_fatal (const char *@var{format}, ...) +These functions display messages about something amiss with the input file, or +internal problems in the assembler itself. The current file name and line +number are printed, followed by the supplied message, formatted using +@code{vfprintf}, and a final newline. + +An error indicated by @code{as_bad} will result in a non-zero exit status when +the assembler has finished. Calling @code{as_fatal} will result in immediate +termination of the assembler process. +@end deftypefun + +@deftypefun @{@} void as_warn_where (char *@var{file}, unsigned int @var{line}, const char *@var{format}, ...) +@deftypefunx @{@} void as_bad_where (char *@var{file}, unsigned int @var{line}, const char *@var{format}, ...) +These variants permit specification of the file name and line number, and are +used when problems are detected when reprocessing information saved away when +processing some earlier part of the file. For example, fixups are processed +after all input has been read, but messages about fixups should refer to the +original filename and line number that they are applicable to. +@end deftypefun + +@deftypefun @{@} void fprint_value (FILE *@var{file}, valueT @var{val}) +@deftypefunx @{@} void sprint_value (char *@var{buf}, valueT @var{val}) +These functions are helpful for converting a @code{valueT} value into printable +format, in case it's wider than modes that @code{*printf} can handle. If the +type is narrow enough, a decimal number will be produced; otherwise, it will be +in hexadecimal. The value itself is not examined to make this determination. +@end deftypefun + +@node Hash tables +@subsection Hash tables +@cindex hash tables + +@deftypefun @{@} @{struct hash_control *@} hash_new (void) +Creates the hash table control structure. +@end deftypefun + +@deftypefun @{@} void hash_die (struct hash_control *) +Destroy a hash table. +@end deftypefun + +@deftypefun @{@} PTR hash_delete (struct hash_control *, const char *) +Deletes entry from the hash table, returns the value it had. +@end deftypefun + +@deftypefun @{@} PTR hash_replace (struct hash_control *, const char *, PTR) +Updates the value for an entry already in the table, returning the old value. +If no entry was found, just returns NULL. +@end deftypefun + +@deftypefun @{@} @{const char *@} hash_insert (struct hash_control *, const char *, PTR) +Inserting a value already in the table is an error. +Returns an error message or NULL. +@end deftypefun + +@deftypefun @{@} @{const char *@} hash_jam (struct hash_control *, const char *, PTR) +Inserts if the value isn't already present, updates it if it is. +@end deftypefun + +@node Test suite +@section Test suite +@cindex test suite + +The test suite is kind of lame for most processors. Often it only checks to +see if a couple of files can be assembled without the assembler reporting any +errors. For more complete testing, write a test which either examines the +assembler listing, or runs @code{objdump} and examines its output. For the +latter, the TCL procedure @code{run_dump_test} may come in handy. It takes the +base name of a file, and looks for @file{@var{file}.d}. This file should +contain as its initial lines a set of variable settings in @samp{#} comments, +in the form: + +@example + #@var{varname}: @var{value} +@end example + +The @var{varname} may be @code{objdump}, @code{nm}, or @code{as}, in which case +it specifies the options to be passed to the specified programs. Exactly one +of @code{objdump} or @code{nm} must be specified, as that also specifies which +program to run after the assembler has finished. If @var{varname} is +@code{source}, it specifies the name of the source file; otherwise, +@file{@var{file}.s} is used. If @var{varname} is @code{name}, it specifies the +name of the test to be used in the @code{pass} or @code{fail} messages. + +The non-commented parts of the file are interpreted as regular expressions, one +per line. Blank lines in the @code{objdump} or @code{nm} output are skipped, +as are blank lines in the @code{.d} file; the other lines are tested to see if +the regular expression matches the program output. If it does not, the test +fails. + +Note that this means the tests must be modified if the @code{objdump} output +style is changed. + +@bye +@c Local Variables: +@c fill-column: 79 +@c End: diff --git a/contrib/binutils/gas/ecoff.c b/contrib/binutils/gas/ecoff.c new file mode 100644 index 0000000..60e111f --- /dev/null +++ b/contrib/binutils/gas/ecoff.c @@ -0,0 +1,5426 @@ +/* ECOFF debugging support. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + This file was put together by Ian Lance Taylor <ian@cygnus.com>. A + good deal of it comes directly from mips-tfile.c, by Michael + Meissner <meissner@osf.org>. + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +/* This file is compiled conditionally for those targets which use + ECOFF debugging information (e.g., MIPS ECOFF, MIPS ELF, Alpha + ECOFF). */ + +#ifdef ECOFF_DEBUGGING + +#include "coff/internal.h" +#include "coff/symconst.h" +#include "ecoff.h" +#include "aout/stab_gnu.h" + +#include <ctype.h> + +/* Why isn't this in coff/sym.h? */ +#define ST_RFDESCAPE 0xfff + +/* This file constructs the information used by the ECOFF debugging + format. It just builds a large block of data. + + We support both ECOFF style debugging and stabs debugging (the + stabs symbols are encapsulated in ECOFF symbols). This should let + us handle anything the compiler might throw at us. */ + +/* Here is a brief description of the MIPS ECOFF symbol table, by + Michael Meissner. The MIPS symbol table has the following pieces: + + Symbolic Header + | + +-- Auxiliary Symbols + | + +-- Dense number table + | + +-- Optimizer Symbols + | + +-- External Strings + | + +-- External Symbols + | + +-- Relative file descriptors + | + +-- File table + | + +-- Procedure table + | + +-- Line number table + | + +-- Local Strings + | + +-- Local Symbols + + The symbolic header points to each of the other tables, and also + contains the number of entries. It also contains a magic number + and MIPS compiler version number, such as 2.0. + + The auxiliary table is a series of 32 bit integers, that are + referenced as needed from the local symbol table. Unlike standard + COFF, the aux. information does not follow the symbol that uses + it, but rather is a separate table. In theory, this would allow + the MIPS compilers to collapse duplicate aux. entries, but I've not + noticed this happening with the 1.31 compiler suite. The different + types of aux. entries are: + + 1) dnLow: Low bound on array dimension. + + 2) dnHigh: High bound on array dimension. + + 3) isym: Index to the local symbol which is the start of the + function for the end of function first aux. entry. + + 4) width: Width of structures and bitfields. + + 5) count: Count of ranges for variant part. + + 6) rndx: A relative index into the symbol table. The relative + index field has two parts: rfd which is a pointer into the + relative file index table or ST_RFDESCAPE which says the next + aux. entry is the file number, and index: which is the pointer + into the local symbol within a given file table. This is for + things like references to types defined in another file. + + 7) Type information: This is like the COFF type bits, except it + is 32 bits instead of 16; they still have room to add new + basic types; and they can handle more than 6 levels of array, + pointer, function, etc. Each type information field contains + the following structure members: + + a) fBitfield: a bit that says this is a bitfield, and the + size in bits follows as the next aux. entry. + + b) continued: a bit that says the next aux. entry is a + continuation of the current type information (in case + there are more than 6 levels of array/ptr/function). + + c) bt: an integer containing the base type before adding + array, pointer, function, etc. qualifiers. The + current base types that I have documentation for are: + + btNil -- undefined + btAdr -- address - integer same size as ptr + btChar -- character + btUChar -- unsigned character + btShort -- short + btUShort -- unsigned short + btInt -- int + btUInt -- unsigned int + btLong -- long + btULong -- unsigned long + btFloat -- float (real) + btDouble -- Double (real) + btStruct -- Structure (Record) + btUnion -- Union (variant) + btEnum -- Enumerated + btTypedef -- defined via a typedef isymRef + btRange -- subrange of int + btSet -- pascal sets + btComplex -- fortran complex + btDComplex -- fortran double complex + btIndirect -- forward or unnamed typedef + btFixedDec -- Fixed Decimal + btFloatDec -- Float Decimal + btString -- Varying Length Character String + btBit -- Aligned Bit String + btPicture -- Picture + btVoid -- Void (MIPS cc revision >= 2.00) + + d) tq0 - tq5: type qualifier fields as needed. The + current type qualifier fields I have documentation for + are: + + tqNil -- no more qualifiers + tqPtr -- pointer + tqProc -- procedure + tqArray -- array + tqFar -- 8086 far pointers + tqVol -- volatile + + + The dense number table is used in the front ends, and disappears by + the time the .o is created. + + With the 1.31 compiler suite, the optimization symbols don't seem + to be used as far as I can tell. + + The linker is the first entity that creates the relative file + descriptor table, and I believe it is used so that the individual + file table pointers don't have to be rewritten when the objects are + merged together into the program file. + + Unlike COFF, the basic symbol & string tables are split into + external and local symbols/strings. The relocation information + only goes off of the external symbol table, and the debug + information only goes off of the internal symbol table. The + external symbols can have links to an appropriate file index and + symbol within the file to give it the appropriate type information. + Because of this, the external symbols are actually larger than the + internal symbols (to contain the link information), and contain the + local symbol structure as a member, though this member is not the + first member of the external symbol structure (!). I suspect this + split is to make strip easier to deal with. + + Each file table has offsets for where the line numbers, local + strings, local symbols, and procedure table starts from within the + global tables, and the indexs are reset to 0 for each of those + tables for the file. + + The procedure table contains the binary equivalents of the .ent + (start of the function address), .frame (what register is the + virtual frame pointer, constant offset from the register to obtain + the VFP, and what register holds the return address), .mask/.fmask + (bitmask of saved registers, and where the first register is stored + relative to the VFP) assembler directives. It also contains the + low and high bounds of the line numbers if debugging is turned on. + + The line number table is a compressed form of the normal COFF line + table. Each line number entry is either 1 or 3 bytes long, and + contains a signed delta from the previous line, and an unsigned + count of the number of instructions this statement takes. + + The local symbol table contains the following fields: + + 1) iss: index to the local string table giving the name of the + symbol. + + 2) value: value of the symbol (address, register number, etc.). + + 3) st: symbol type. The current symbol types are: + + stNil -- Nuthin' special + stGlobal -- external symbol + stStatic -- static + stParam -- procedure argument + stLocal -- local variable + stLabel -- label + stProc -- External Procedure + stBlock -- beginning of block + stEnd -- end (of anything) + stMember -- member (of anything) + stTypedef -- type definition + stFile -- file name + stRegReloc -- register relocation + stForward -- forwarding address + stStaticProc -- Static procedure + stConstant -- const + + 4) sc: storage class. The current storage classes are: + + scText -- text symbol + scData -- initialized data symbol + scBss -- un-initialized data symbol + scRegister -- value of symbol is register number + scAbs -- value of symbol is absolute + scUndefined -- who knows? + scCdbLocal -- variable's value is IN se->va.?? + scBits -- this is a bit field + scCdbSystem -- value is IN debugger's address space + scRegImage -- register value saved on stack + scInfo -- symbol contains debugger information + scUserStruct -- addr in struct user for current process + scSData -- load time only small data + scSBss -- load time only small common + scRData -- load time only read only data + scVar -- Var parameter (fortranpascal) + scCommon -- common variable + scSCommon -- small common + scVarRegister -- Var parameter in a register + scVariant -- Variant record + scSUndefined -- small undefined(external) data + scInit -- .init section symbol + + 5) index: pointer to a local symbol or aux. entry. + + + + For the following program: + + #include <stdio.h> + + main(){ + printf("Hello World!\n"); + return 0; + } + + Mips-tdump produces the following information: + + Global file header: + magic number 0x162 + # sections 2 + timestamp 645311799, Wed Jun 13 17:16:39 1990 + symbolic header offset 284 + symbolic header size 96 + optional header 56 + flags 0x0 + + Symbolic header, magic number = 0x7009, vstamp = 1.31: + + Info Offset Number Bytes + ==== ====== ====== ===== + + Line numbers 380 4 4 [13] + Dense numbers 0 0 0 + Procedures Tables 384 1 52 + Local Symbols 436 16 192 + Optimization Symbols 0 0 0 + Auxiliary Symbols 628 39 156 + Local Strings 784 80 80 + External Strings 864 144 144 + File Tables 1008 2 144 + Relative Files 0 0 0 + External Symbols 1152 20 320 + + File #0, "hello2.c" + + Name index = 1 Readin = No + Merge = No Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 0 15 15 784 + Local symbols 0 6 72 436 + Line numbers 0 13 13 380 + Optimization symbols 0 0 0 0 + Procedures 0 1 52 384 + Auxiliary symbols 0 14 56 628 + Relative Files 0 0 0 0 + + There are 6 local symbols, starting at 436 + + Symbol# 0: "hello2.c" + End+1 symbol = 6 + String index = 1 + Storage class = Text Index = 6 + Symbol type = File Value = 0 + + Symbol# 1: "main" + End+1 symbol = 5 + Type = int + String index = 10 + Storage class = Text Index = 12 + Symbol type = Proc Value = 0 + + Symbol# 2: "" + End+1 symbol = 4 + String index = 0 + Storage class = Text Index = 4 + Symbol type = Block Value = 8 + + Symbol# 3: "" + First symbol = 2 + String index = 0 + Storage class = Text Index = 2 + Symbol type = End Value = 28 + + Symbol# 4: "main" + First symbol = 1 + String index = 10 + Storage class = Text Index = 1 + Symbol type = End Value = 52 + + Symbol# 5: "hello2.c" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 14 auxiliary table entries, starting at 628. + + * #0 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #1 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #2 8, [ 8/ 0], [ 2 0:0 0:0:0:0:0:0] + * #3 16, [ 16/ 0], [ 4 0:0 0:0:0:0:0:0] + * #4 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #5 32, [ 32/ 0], [ 8 0:0 0:0:0:0:0:0] + * #6 40, [ 40/ 0], [10 0:0 0:0:0:0:0:0] + * #7 44, [ 44/ 0], [11 0:0 0:0:0:0:0:0] + * #8 12, [ 12/ 0], [ 3 0:0 0:0:0:0:0:0] + * #9 20, [ 20/ 0], [ 5 0:0 0:0:0:0:0:0] + * #10 28, [ 28/ 0], [ 7 0:0 0:0:0:0:0:0] + * #11 36, [ 36/ 0], [ 9 0:0 0:0:0:0:0:0] + #12 5, [ 5/ 0], [ 1 1:0 0:0:0:0:0:0] + #13 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + + There are 1 procedure descriptor entries, starting at 0. + + Procedure descriptor 0: + Name index = 10 Name = "main" + .mask 0x80000000,-4 .fmask 0x00000000,0 + .frame $29,24,$31 + Opt. start = -1 Symbols start = 1 + First line # = 3 Last line # = 6 + Line Offset = 0 Address = 0x00000000 + + There are 4 bytes holding line numbers, starting at 380. + Line 3, delta 0, count 2 + Line 4, delta 1, count 3 + Line 5, delta 1, count 2 + Line 6, delta 1, count 6 + + File #1, "/usr/include/stdio.h" + + Name index = 1 Readin = No + Merge = Yes Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 15 65 65 799 + Local symbols 6 10 120 508 + Line numbers 0 0 0 380 + Optimization symbols 0 0 0 0 + Procedures 1 0 0 436 + Auxiliary symbols 14 25 100 684 + Relative Files 0 0 0 0 + + There are 10 local symbols, starting at 442 + + Symbol# 0: "/usr/include/stdio.h" + End+1 symbol = 10 + String index = 1 + Storage class = Text Index = 10 + Symbol type = File Value = 0 + + Symbol# 1: "_iobuf" + End+1 symbol = 9 + String index = 22 + Storage class = Info Index = 9 + Symbol type = Block Value = 20 + + Symbol# 2: "_cnt" + Type = int + String index = 29 + Storage class = Info Index = 4 + Symbol type = Member Value = 0 + + Symbol# 3: "_ptr" + Type = ptr to char + String index = 34 + Storage class = Info Index = 15 + Symbol type = Member Value = 32 + + Symbol# 4: "_base" + Type = ptr to char + String index = 39 + Storage class = Info Index = 16 + Symbol type = Member Value = 64 + + Symbol# 5: "_bufsiz" + Type = int + String index = 45 + Storage class = Info Index = 4 + Symbol type = Member Value = 96 + + Symbol# 6: "_flag" + Type = short + String index = 53 + Storage class = Info Index = 3 + Symbol type = Member Value = 128 + + Symbol# 7: "_file" + Type = char + String index = 59 + Storage class = Info Index = 2 + Symbol type = Member Value = 144 + + Symbol# 8: "" + First symbol = 1 + String index = 0 + Storage class = Info Index = 1 + Symbol type = End Value = 0 + + Symbol# 9: "/usr/include/stdio.h" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 25 auxiliary table entries, starting at 642. + + * #14 -1, [4095/1048575], [63 1:1 f:f:f:f:f:f] + #15 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + #16 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + * #17 196656, [ 48/ 48], [12 0:0 3:0:0:0:0:0] + * #18 8191, [4095/ 1], [63 1:1 0:0:0:0:f:1] + * #19 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #20 20479, [4095/ 4], [63 1:1 0:0:0:0:f:4] + * #21 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #22 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #23 2, [ 2/ 0], [ 0 0:1 0:0:0:0:0:0] + * #24 160, [ 160/ 0], [40 0:0 0:0:0:0:0:0] + * #25 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #26 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #27 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #28 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #29 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #30 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #31 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #32 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #33 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #34 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #35 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #36 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #37 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #38 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + + There are 0 procedure descriptor entries, starting at 1. + + There are 20 external symbols, starting at 1152 + + Symbol# 0: "_iob" + Type = array [3 {160}] of struct _iobuf { ifd = 1, index = 1 } + String index = 0 Ifd = 1 + Storage class = Nil Index = 17 + Symbol type = Global Value = 60 + + Symbol# 1: "fopen" + String index = 5 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 2: "fdopen" + String index = 11 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 3: "freopen" + String index = 18 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 4: "popen" + String index = 26 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 5: "tmpfile" + String index = 32 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 6: "ftell" + String index = 40 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 7: "rewind" + String index = 46 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 8: "setbuf" + String index = 53 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 9: "setbuffer" + String index = 60 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 10: "setlinebuf" + String index = 70 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 11: "fgets" + String index = 81 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 12: "gets" + String index = 87 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 13: "ctermid" + String index = 92 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 14: "cuserid" + String index = 100 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 15: "tempnam" + String index = 108 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 16: "tmpnam" + String index = 116 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 17: "sprintf" + String index = 123 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 18: "main" + Type = int + String index = 131 Ifd = 0 + Storage class = Text Index = 1 + Symbol type = Proc Value = 0 + + Symbol# 19: "printf" + String index = 136 Ifd = 0 + Storage class = Undefined Index = 1048575 + Symbol type = Proc Value = 0 + + The following auxiliary table entries were unused: + + #0 0 0x00000000 void + #2 8 0x00000008 char + #3 16 0x00000010 short + #4 24 0x00000018 int + #5 32 0x00000020 long + #6 40 0x00000028 float + #7 44 0x0000002c double + #8 12 0x0000000c unsigned char + #9 20 0x00000014 unsigned short + #10 28 0x0000001c unsigned int + #11 36 0x00000024 unsigned long + #14 0 0x00000000 void + #15 24 0x00000018 int + #19 32 0x00000020 long + #20 40 0x00000028 float + #21 44 0x0000002c double + #22 12 0x0000000c unsigned char + #23 20 0x00000014 unsigned short + #24 28 0x0000001c unsigned int + #25 36 0x00000024 unsigned long + #26 48 0x00000030 struct no name { ifd = -1, index = 1048575 } +*/ + +/* Redefinition of of storage classes as an enumeration for better + debugging. */ + +typedef enum sc { + sc_Nil = scNil, /* no storage class */ + sc_Text = scText, /* text symbol */ + sc_Data = scData, /* initialized data symbol */ + sc_Bss = scBss, /* un-initialized data symbol */ + sc_Register = scRegister, /* value of symbol is register number */ + sc_Abs = scAbs, /* value of symbol is absolute */ + sc_Undefined = scUndefined, /* who knows? */ + sc_CdbLocal = scCdbLocal, /* variable's value is IN se->va.?? */ + sc_Bits = scBits, /* this is a bit field */ + sc_CdbSystem = scCdbSystem, /* value is IN CDB's address space */ + sc_RegImage = scRegImage, /* register value saved on stack */ + sc_Info = scInfo, /* symbol contains debugger information */ + sc_UserStruct = scUserStruct, /* addr in struct user for current process */ + sc_SData = scSData, /* load time only small data */ + sc_SBss = scSBss, /* load time only small common */ + sc_RData = scRData, /* load time only read only data */ + sc_Var = scVar, /* Var parameter (fortran,pascal) */ + sc_Common = scCommon, /* common variable */ + sc_SCommon = scSCommon, /* small common */ + sc_VarRegister = scVarRegister, /* Var parameter in a register */ + sc_Variant = scVariant, /* Variant record */ + sc_SUndefined = scSUndefined, /* small undefined(external) data */ + sc_Init = scInit, /* .init section symbol */ + sc_Max = scMax /* Max storage class+1 */ +} sc_t; + +/* Redefinition of symbol type. */ + +typedef enum st { + st_Nil = stNil, /* Nuthin' special */ + st_Global = stGlobal, /* external symbol */ + st_Static = stStatic, /* static */ + st_Param = stParam, /* procedure argument */ + st_Local = stLocal, /* local variable */ + st_Label = stLabel, /* label */ + st_Proc = stProc, /* " " Procedure */ + st_Block = stBlock, /* beginning of block */ + st_End = stEnd, /* end (of anything) */ + st_Member = stMember, /* member (of anything - struct/union/enum */ + st_Typedef = stTypedef, /* type definition */ + st_File = stFile, /* file name */ + st_RegReloc = stRegReloc, /* register relocation */ + st_Forward = stForward, /* forwarding address */ + st_StaticProc = stStaticProc, /* load time only static procs */ + st_Constant = stConstant, /* const */ + st_Str = stStr, /* string */ + st_Number = stNumber, /* pure number (ie. 4 NOR 2+2) */ + st_Expr = stExpr, /* 2+2 vs. 4 */ + st_Type = stType, /* post-coercion SER */ + st_Max = stMax /* max type+1 */ +} st_t; + +/* Redefinition of type qualifiers. */ + +typedef enum tq { + tq_Nil = tqNil, /* bt is what you see */ + tq_Ptr = tqPtr, /* pointer */ + tq_Proc = tqProc, /* procedure */ + tq_Array = tqArray, /* duh */ + tq_Far = tqFar, /* longer addressing - 8086/8 land */ + tq_Vol = tqVol, /* volatile */ + tq_Max = tqMax /* Max type qualifier+1 */ +} tq_t; + +/* Redefinition of basic types. */ + +typedef enum bt { + bt_Nil = btNil, /* undefined */ + bt_Adr = btAdr, /* address - integer same size as pointer */ + bt_Char = btChar, /* character */ + bt_UChar = btUChar, /* unsigned character */ + bt_Short = btShort, /* short */ + bt_UShort = btUShort, /* unsigned short */ + bt_Int = btInt, /* int */ + bt_UInt = btUInt, /* unsigned int */ + bt_Long = btLong, /* long */ + bt_ULong = btULong, /* unsigned long */ + bt_Float = btFloat, /* float (real) */ + bt_Double = btDouble, /* Double (real) */ + bt_Struct = btStruct, /* Structure (Record) */ + bt_Union = btUnion, /* Union (variant) */ + bt_Enum = btEnum, /* Enumerated */ + bt_Typedef = btTypedef, /* defined via a typedef, isymRef points */ + bt_Range = btRange, /* subrange of int */ + bt_Set = btSet, /* pascal sets */ + bt_Complex = btComplex, /* fortran complex */ + bt_DComplex = btDComplex, /* fortran double complex */ + bt_Indirect = btIndirect, /* forward or unnamed typedef */ + bt_FixedDec = btFixedDec, /* Fixed Decimal */ + bt_FloatDec = btFloatDec, /* Float Decimal */ + bt_String = btString, /* Varying Length Character String */ + bt_Bit = btBit, /* Aligned Bit String */ + bt_Picture = btPicture, /* Picture */ + bt_Void = btVoid, /* Void */ + bt_Max = btMax /* Max basic type+1 */ +} bt_t; + +#define N_TQ itqMax + +/* States for whether to hash type or not. */ +typedef enum hash_state { + hash_no = 0, /* don't hash type */ + hash_yes = 1, /* ok to hash type, or use previous hash */ + hash_record = 2 /* ok to record hash, but don't use prev. */ +} hash_state_t; + +/* Types of different sized allocation requests. */ +enum alloc_type { + alloc_type_none, /* dummy value */ + alloc_type_scope, /* nested scopes linked list */ + alloc_type_vlinks, /* glue linking pages in varray */ + alloc_type_shash, /* string hash element */ + alloc_type_thash, /* type hash element */ + alloc_type_tag, /* struct/union/tag element */ + alloc_type_forward, /* element to hold unknown tag */ + alloc_type_thead, /* head of type hash list */ + alloc_type_varray, /* general varray allocation */ + alloc_type_lineno, /* line number list */ + alloc_type_last /* last+1 element for array bounds */ +}; + +/* Types of auxiliary type information. */ +enum aux_type { + aux_tir, /* TIR type information */ + aux_rndx, /* relative index into symbol table */ + aux_dnLow, /* low dimension */ + aux_dnHigh, /* high dimension */ + aux_isym, /* symbol table index (end of proc) */ + aux_iss, /* index into string space (not used) */ + aux_width, /* width for non-default sized struc fields */ + aux_count /* count of ranges for variant arm */ +}; + +/* Structures to provide n-number of virtual arrays, each of which can + grow linearly, and which are written in the object file as + sequential pages. On systems with a BSD malloc, the + MAX_CLUSTER_PAGES should be 1 less than a power of two, since + malloc adds it's overhead, and rounds up to the next power of 2. + Pages are linked together via a linked list. + + If PAGE_SIZE is > 4096, the string length in the shash_t structure + can't be represented (assuming there are strings > 4096 bytes). */ + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 /* size of varray pages */ +#endif + +#define PAGE_USIZE ((unsigned long) PAGE_SIZE) + + +#ifndef MAX_CLUSTER_PAGES /* # pages to get from system */ +#define MAX_CLUSTER_PAGES 63 +#endif + +/* Linked list connecting separate page allocations. */ +typedef struct vlinks { + struct vlinks *prev; /* previous set of pages */ + struct vlinks *next; /* next set of pages */ + union page *datum; /* start of page */ + unsigned long start_index; /* starting index # of page */ +} vlinks_t; + + +/* Virtual array header. */ +typedef struct varray { + vlinks_t *first; /* first page link */ + vlinks_t *last; /* last page link */ + unsigned long num_allocated; /* # objects allocated */ + unsigned short object_size; /* size in bytes of each object */ + unsigned short objects_per_page; /* # objects that can fit on a page */ + unsigned short objects_last_page; /* # objects allocated on last page */ +} varray_t; + +#ifndef MALLOC_CHECK +#define OBJECTS_PER_PAGE(type) (PAGE_SIZE / sizeof (type)) +#else +#define OBJECTS_PER_PAGE(type) ((sizeof (type) > 1) ? 1 : PAGE_SIZE) +#endif + +#define INIT_VARRAY(type) { /* macro to initialize a varray */ \ + (vlinks_t *)0, /* first */ \ + (vlinks_t *)0, /* last */ \ + 0, /* num_allocated */ \ + sizeof (type), /* object_size */ \ + OBJECTS_PER_PAGE (type), /* objects_per_page */ \ + OBJECTS_PER_PAGE (type), /* objects_last_page */ \ +} + + +/* Master type for indexes within the symbol table. */ +typedef unsigned long symint_t; + + +/* Linked list support for nested scopes (file, block, structure, etc.). */ +typedef struct scope { + struct scope *prev; /* previous scope level */ + struct scope *free; /* free list pointer */ + struct localsym *lsym; /* pointer to local symbol node */ + st_t type; /* type of the node */ +} scope_t; + + +/* For a local symbol we store a gas symbol as well as the debugging + information we generate. The gas symbol will be NULL if this is + only a debugging symbol. */ +typedef struct localsym { + const char *name; /* symbol name */ + symbolS *as_sym; /* symbol as seen by gas */ + bfd_vma addend; /* addend to as_sym value */ + struct efdr *file_ptr; /* file pointer */ + struct ecoff_proc *proc_ptr; /* proc pointer */ + struct localsym *begin_ptr; /* symbol at start of block */ + struct ecoff_aux *index_ptr; /* index value to be filled in */ + struct forward *forward_ref; /* forward references to this symbol */ + long sym_index; /* final symbol index */ + EXTR ecoff_sym; /* ECOFF debugging symbol */ +} localsym_t; + + +/* For aux information we keep the type and the data. */ +typedef struct ecoff_aux { + enum aux_type type; /* aux type */ + AUXU data; /* aux data */ +} aux_t; + +/* For a procedure we store the gas symbol as well as the PDR + debugging information. */ +typedef struct ecoff_proc { + localsym_t *sym; /* associated symbol */ + PDR pdr; /* ECOFF debugging info */ +} proc_t; + +/* Number of proc_t structures allocated. */ +static unsigned long proc_cnt; + + +/* Forward reference list for tags referenced, but not yet defined. */ +typedef struct forward { + struct forward *next; /* next forward reference */ + struct forward *free; /* free list pointer */ + aux_t *ifd_ptr; /* pointer to store file index */ + aux_t *index_ptr; /* pointer to store symbol index */ +} forward_t; + + +/* Linked list support for tags. The first tag in the list is always + the current tag for that block. */ +typedef struct tag { + struct tag *free; /* free list pointer */ + struct shash *hash_ptr; /* pointer to the hash table head */ + struct tag *same_name; /* tag with same name in outer scope */ + struct tag *same_block; /* next tag defined in the same block. */ + struct forward *forward_ref; /* list of forward references */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ + symint_t ifd; /* file # tag defined in */ + localsym_t *sym; /* file's local symbols */ +} tag_t; + + +/* Head of a block's linked list of tags. */ +typedef struct thead { + struct thead *prev; /* previous block */ + struct thead *free; /* free list pointer */ + struct tag *first_tag; /* first tag in block defined */ +} thead_t; + + +/* Union containing pointers to each the small structures which are freed up. */ +typedef union small_free { + scope_t *f_scope; /* scope structure */ + thead_t *f_thead; /* tag head structure */ + tag_t *f_tag; /* tag element structure */ + forward_t *f_forward; /* forward tag reference */ +} small_free_t; + + +/* String hash table entry. */ + +typedef struct shash { + char *string; /* string we are hashing */ + symint_t indx; /* index within string table */ + EXTR *esym_ptr; /* global symbol pointer */ + localsym_t *sym_ptr; /* local symbol pointer */ + localsym_t *end_ptr; /* symbol pointer to end block */ + tag_t *tag_ptr; /* tag pointer */ + proc_t *proc_ptr; /* procedure descriptor pointer */ +} shash_t; + + +/* Type hash table support. The size of the hash table must fit + within a page with the other extended file descriptor information. + Because unique types which are hashed are fewer in number than + strings, we use a smaller hash value. */ + +#define HASHBITS 30 + +#ifndef THASH_SIZE +#define THASH_SIZE 113 +#endif + +typedef struct thash { + struct thash *next; /* next hash value */ + AUXU type; /* type we are hashing */ + symint_t indx; /* index within string table */ +} thash_t; + + +/* Extended file descriptor that contains all of the support necessary + to add things to each file separately. */ +typedef struct efdr { + FDR fdr; /* File header to be written out */ + FDR *orig_fdr; /* original file header */ + char *name; /* filename */ + int fake; /* whether this is faked .file */ + symint_t void_type; /* aux. pointer to 'void' type */ + symint_t int_type; /* aux. pointer to 'int' type */ + scope_t *cur_scope; /* current nested scopes */ + symint_t file_index; /* current file number */ + int nested_scopes; /* # nested scopes */ + varray_t strings; /* local strings */ + varray_t symbols; /* local symbols */ + varray_t procs; /* procedures */ + varray_t aux_syms; /* auxiliary symbols */ + struct efdr *next_file; /* next file descriptor */ + /* string/type hash tables */ + struct hash_control *str_hash; /* string hash table */ + thash_t *thash_head[THASH_SIZE]; +} efdr_t; + +/* Pre-initialized extended file structure. */ +static const efdr_t init_file = +{ + { /* FDR structure */ + 0, /* adr: memory address of beginning of file */ + 0, /* rss: file name (of source, if known) */ + 0, /* issBase: file's string space */ + 0, /* cbSs: number of bytes in the ss */ + 0, /* isymBase: beginning of symbols */ + 0, /* csym: count file's of symbols */ + 0, /* ilineBase: file's line symbols */ + 0, /* cline: count of file's line symbols */ + 0, /* ioptBase: file's optimization entries */ + 0, /* copt: count of file's optimization entries */ + 0, /* ipdFirst: start of procedures for this file */ + 0, /* cpd: count of procedures for this file */ + 0, /* iauxBase: file's auxiliary entries */ + 0, /* caux: count of file's auxiliary entries */ + 0, /* rfdBase: index into the file indirect table */ + 0, /* crfd: count file indirect entries */ + langC, /* lang: language for this file */ + 1, /* fMerge: whether this file can be merged */ + 0, /* fReadin: true if read in (not just created) */ + TARGET_BYTES_BIG_ENDIAN, /* fBigendian: if 1, compiled on big endian machine */ + GLEVEL_2, /* glevel: level this file was compiled with */ + 0, /* reserved: reserved for future use */ + 0, /* cbLineOffset: byte offset from header for this file ln's */ + 0, /* cbLine: size of lines for this file */ + }, + + (FDR *)0, /* orig_fdr: original file header pointer */ + (char *)0, /* name: pointer to filename */ + 0, /* fake: whether this is a faked .file */ + 0, /* void_type: ptr to aux node for void type */ + 0, /* int_type: ptr to aux node for int type */ + (scope_t *)0, /* cur_scope: current scope being processed */ + 0, /* file_index: current file # */ + 0, /* nested_scopes: # nested scopes */ + INIT_VARRAY (char), /* strings: local string varray */ + INIT_VARRAY (localsym_t), /* symbols: local symbols varray */ + INIT_VARRAY (proc_t), /* procs: procedure varray */ + INIT_VARRAY (aux_t), /* aux_syms: auxiliary symbols varray */ + + (struct efdr *)0, /* next_file: next file structure */ + + (struct hash_control *)0, /* str_hash: string hash table */ + { 0 }, /* thash_head: type hash table */ +}; + + +static efdr_t *first_file; /* first file descriptor */ +static efdr_t **last_file_ptr = &first_file; /* file descriptor tail */ + + +/* Line number information is kept in a list until the assembly is + finished. */ +typedef struct lineno_list { + struct lineno_list *next; /* next element in list */ + efdr_t *file; /* file this line is in */ + proc_t *proc; /* procedure this line is in */ + fragS *frag; /* fragment this line number is in */ + unsigned long paddr; /* offset within fragment */ + long lineno; /* actual line number */ +} lineno_list_t; + +static lineno_list_t *first_lineno; +static lineno_list_t *last_lineno; +static lineno_list_t **last_lineno_ptr = &first_lineno; + +/* Sometimes there will be some .loc statements before a .ent. We + keep them in this list so that we can fill in the procedure pointer + after we see the .ent. */ +static lineno_list_t *noproc_lineno; + +/* Union of various things that are held in pages. */ +typedef union page { + char byte [ PAGE_SIZE ]; + unsigned char ubyte [ PAGE_SIZE ]; + efdr_t file [ PAGE_SIZE / sizeof (efdr_t) ]; + FDR ofile [ PAGE_SIZE / sizeof (FDR) ]; + proc_t proc [ PAGE_SIZE / sizeof (proc_t) ]; + localsym_t sym [ PAGE_SIZE / sizeof (localsym_t) ]; + aux_t aux [ PAGE_SIZE / sizeof (aux_t) ]; + DNR dense [ PAGE_SIZE / sizeof (DNR) ]; + scope_t scope [ PAGE_SIZE / sizeof (scope_t) ]; + vlinks_t vlinks [ PAGE_SIZE / sizeof (vlinks_t) ]; + shash_t shash [ PAGE_SIZE / sizeof (shash_t) ]; + thash_t thash [ PAGE_SIZE / sizeof (thash_t) ]; + tag_t tag [ PAGE_SIZE / sizeof (tag_t) ]; + forward_t forward [ PAGE_SIZE / sizeof (forward_t) ]; + thead_t thead [ PAGE_SIZE / sizeof (thead_t) ]; + lineno_list_t lineno [ PAGE_SIZE / sizeof (lineno_list_t) ]; +} page_t; + + +/* Structure holding allocation information for small sized structures. */ +typedef struct alloc_info { + char *alloc_name; /* name of this allocation type (must be first) */ + page_t *cur_page; /* current page being allocated from */ + small_free_t free_list; /* current free list if any */ + int unallocated; /* number of elements unallocated on page */ + int total_alloc; /* total number of allocations */ + int total_free; /* total number of frees */ + int total_pages; /* total number of pages allocated */ +} alloc_info_t; + + +/* Type information collected together. */ +typedef struct type_info { + bt_t basic_type; /* basic type */ + int orig_type; /* original COFF-based type */ + int num_tq; /* # type qualifiers */ + int num_dims; /* # dimensions */ + int num_sizes; /* # sizes */ + int extra_sizes; /* # extra sizes not tied with dims */ + tag_t * tag_ptr; /* tag pointer */ + int bitfield; /* symbol is a bitfield */ + tq_t type_qualifiers[N_TQ]; /* type qualifiers (ptr, func, array)*/ + symint_t dimensions [N_TQ]; /* dimensions for each array */ + symint_t sizes [N_TQ+2]; /* sizes of each array slice + size of + struct/union/enum + bitfield size */ +} type_info_t; + +/* Pre-initialized type_info struct. */ +static const type_info_t type_info_init = { + bt_Nil, /* basic type */ + T_NULL, /* original COFF-based type */ + 0, /* # type qualifiers */ + 0, /* # dimensions */ + 0, /* # sizes */ + 0, /* sizes not tied with dims */ + NULL, /* ptr to tag */ + 0, /* bitfield */ + { /* type qualifiers */ + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + }, + { /* dimensions */ + 0, + 0, + 0, + 0, + 0, + 0 + }, + { /* sizes */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, +}; + +/* Global hash table for the tags table and global table for file + descriptors. */ + +static varray_t file_desc = INIT_VARRAY (efdr_t); + +static struct hash_control *tag_hash; + +/* Static types for int and void. Also, remember the last function's + type (which is set up when we encounter the declaration for the + function, and used when the end block for the function is emitted. */ + +static type_info_t int_type_info; +static type_info_t void_type_info; +static type_info_t last_func_type_info; +static symbolS *last_func_sym_value; + + +/* Convert COFF basic type to ECOFF basic type. The T_NULL type + really should use bt_Void, but this causes the current ecoff GDB to + issue unsupported type messages, and the Ultrix 4.00 dbx (aka MIPS + 2.0) doesn't understand it, even though the compiler generates it. + Maybe this will be fixed in 2.10 or 2.20 of the MIPS compiler + suite, but for now go with what works. + + It would make sense for the .type and .scl directives to use the + ECOFF numbers directly, rather than using the COFF numbers and + mapping them. Unfortunately, this is historically what mips-tfile + expects, and changing gcc now would be a considerable pain (the + native compiler generates debugging information internally, rather + than via the assembler, so it will never use .type or .scl). */ + +static const bt_t map_coff_types[] = { + bt_Nil, /* T_NULL */ + bt_Nil, /* T_ARG */ + bt_Char, /* T_CHAR */ + bt_Short, /* T_SHORT */ + bt_Int, /* T_INT */ + bt_Long, /* T_LONG */ + bt_Float, /* T_FLOAT */ + bt_Double, /* T_DOUBLE */ + bt_Struct, /* T_STRUCT */ + bt_Union, /* T_UNION */ + bt_Enum, /* T_ENUM */ + bt_Enum, /* T_MOE */ + bt_UChar, /* T_UCHAR */ + bt_UShort, /* T_USHORT */ + bt_UInt, /* T_UINT */ + bt_ULong /* T_ULONG */ +}; + +/* Convert COFF storage class to ECOFF storage class. */ +static const sc_t map_coff_storage[] = { + sc_Nil, /* 0: C_NULL */ + sc_Abs, /* 1: C_AUTO auto var */ + sc_Undefined, /* 2: C_EXT external */ + sc_Data, /* 3: C_STAT static */ + sc_Register, /* 4: C_REG register */ + sc_Undefined, /* 5: C_EXTDEF ??? */ + sc_Text, /* 6: C_LABEL label */ + sc_Text, /* 7: C_ULABEL user label */ + sc_Info, /* 8: C_MOS member of struct */ + sc_Abs, /* 9: C_ARG argument */ + sc_Info, /* 10: C_STRTAG struct tag */ + sc_Info, /* 11: C_MOU member of union */ + sc_Info, /* 12: C_UNTAG union tag */ + sc_Info, /* 13: C_TPDEF typedef */ + sc_Data, /* 14: C_USTATIC ??? */ + sc_Info, /* 15: C_ENTAG enum tag */ + sc_Info, /* 16: C_MOE member of enum */ + sc_Register, /* 17: C_REGPARM register parameter */ + sc_Bits, /* 18; C_FIELD bitfield */ + sc_Nil, /* 19 */ + sc_Nil, /* 20 */ + sc_Nil, /* 21 */ + sc_Nil, /* 22 */ + sc_Nil, /* 23 */ + sc_Nil, /* 24 */ + sc_Nil, /* 25 */ + sc_Nil, /* 26 */ + sc_Nil, /* 27 */ + sc_Nil, /* 28 */ + sc_Nil, /* 29 */ + sc_Nil, /* 30 */ + sc_Nil, /* 31 */ + sc_Nil, /* 32 */ + sc_Nil, /* 33 */ + sc_Nil, /* 34 */ + sc_Nil, /* 35 */ + sc_Nil, /* 36 */ + sc_Nil, /* 37 */ + sc_Nil, /* 38 */ + sc_Nil, /* 39 */ + sc_Nil, /* 40 */ + sc_Nil, /* 41 */ + sc_Nil, /* 42 */ + sc_Nil, /* 43 */ + sc_Nil, /* 44 */ + sc_Nil, /* 45 */ + sc_Nil, /* 46 */ + sc_Nil, /* 47 */ + sc_Nil, /* 48 */ + sc_Nil, /* 49 */ + sc_Nil, /* 50 */ + sc_Nil, /* 51 */ + sc_Nil, /* 52 */ + sc_Nil, /* 53 */ + sc_Nil, /* 54 */ + sc_Nil, /* 55 */ + sc_Nil, /* 56 */ + sc_Nil, /* 57 */ + sc_Nil, /* 58 */ + sc_Nil, /* 59 */ + sc_Nil, /* 60 */ + sc_Nil, /* 61 */ + sc_Nil, /* 62 */ + sc_Nil, /* 63 */ + sc_Nil, /* 64 */ + sc_Nil, /* 65 */ + sc_Nil, /* 66 */ + sc_Nil, /* 67 */ + sc_Nil, /* 68 */ + sc_Nil, /* 69 */ + sc_Nil, /* 70 */ + sc_Nil, /* 71 */ + sc_Nil, /* 72 */ + sc_Nil, /* 73 */ + sc_Nil, /* 74 */ + sc_Nil, /* 75 */ + sc_Nil, /* 76 */ + sc_Nil, /* 77 */ + sc_Nil, /* 78 */ + sc_Nil, /* 79 */ + sc_Nil, /* 80 */ + sc_Nil, /* 81 */ + sc_Nil, /* 82 */ + sc_Nil, /* 83 */ + sc_Nil, /* 84 */ + sc_Nil, /* 85 */ + sc_Nil, /* 86 */ + sc_Nil, /* 87 */ + sc_Nil, /* 88 */ + sc_Nil, /* 89 */ + sc_Nil, /* 90 */ + sc_Nil, /* 91 */ + sc_Nil, /* 92 */ + sc_Nil, /* 93 */ + sc_Nil, /* 94 */ + sc_Nil, /* 95 */ + sc_Nil, /* 96 */ + sc_Nil, /* 97 */ + sc_Nil, /* 98 */ + sc_Nil, /* 99 */ + sc_Text, /* 100: C_BLOCK block start/end */ + sc_Text, /* 101: C_FCN function start/end */ + sc_Info, /* 102: C_EOS end of struct/union/enum */ + sc_Nil, /* 103: C_FILE file start */ + sc_Nil, /* 104: C_LINE line number */ + sc_Nil, /* 105: C_ALIAS combined type info */ + sc_Nil, /* 106: C_HIDDEN ??? */ +}; + +/* Convert COFF storage class to ECOFF symbol type. */ +static const st_t map_coff_sym_type[] = { + st_Nil, /* 0: C_NULL */ + st_Local, /* 1: C_AUTO auto var */ + st_Global, /* 2: C_EXT external */ + st_Static, /* 3: C_STAT static */ + st_Local, /* 4: C_REG register */ + st_Global, /* 5: C_EXTDEF ??? */ + st_Label, /* 6: C_LABEL label */ + st_Label, /* 7: C_ULABEL user label */ + st_Member, /* 8: C_MOS member of struct */ + st_Param, /* 9: C_ARG argument */ + st_Block, /* 10: C_STRTAG struct tag */ + st_Member, /* 11: C_MOU member of union */ + st_Block, /* 12: C_UNTAG union tag */ + st_Typedef, /* 13: C_TPDEF typedef */ + st_Static, /* 14: C_USTATIC ??? */ + st_Block, /* 15: C_ENTAG enum tag */ + st_Member, /* 16: C_MOE member of enum */ + st_Param, /* 17: C_REGPARM register parameter */ + st_Member, /* 18; C_FIELD bitfield */ + st_Nil, /* 19 */ + st_Nil, /* 20 */ + st_Nil, /* 21 */ + st_Nil, /* 22 */ + st_Nil, /* 23 */ + st_Nil, /* 24 */ + st_Nil, /* 25 */ + st_Nil, /* 26 */ + st_Nil, /* 27 */ + st_Nil, /* 28 */ + st_Nil, /* 29 */ + st_Nil, /* 30 */ + st_Nil, /* 31 */ + st_Nil, /* 32 */ + st_Nil, /* 33 */ + st_Nil, /* 34 */ + st_Nil, /* 35 */ + st_Nil, /* 36 */ + st_Nil, /* 37 */ + st_Nil, /* 38 */ + st_Nil, /* 39 */ + st_Nil, /* 40 */ + st_Nil, /* 41 */ + st_Nil, /* 42 */ + st_Nil, /* 43 */ + st_Nil, /* 44 */ + st_Nil, /* 45 */ + st_Nil, /* 46 */ + st_Nil, /* 47 */ + st_Nil, /* 48 */ + st_Nil, /* 49 */ + st_Nil, /* 50 */ + st_Nil, /* 51 */ + st_Nil, /* 52 */ + st_Nil, /* 53 */ + st_Nil, /* 54 */ + st_Nil, /* 55 */ + st_Nil, /* 56 */ + st_Nil, /* 57 */ + st_Nil, /* 58 */ + st_Nil, /* 59 */ + st_Nil, /* 60 */ + st_Nil, /* 61 */ + st_Nil, /* 62 */ + st_Nil, /* 63 */ + st_Nil, /* 64 */ + st_Nil, /* 65 */ + st_Nil, /* 66 */ + st_Nil, /* 67 */ + st_Nil, /* 68 */ + st_Nil, /* 69 */ + st_Nil, /* 70 */ + st_Nil, /* 71 */ + st_Nil, /* 72 */ + st_Nil, /* 73 */ + st_Nil, /* 74 */ + st_Nil, /* 75 */ + st_Nil, /* 76 */ + st_Nil, /* 77 */ + st_Nil, /* 78 */ + st_Nil, /* 79 */ + st_Nil, /* 80 */ + st_Nil, /* 81 */ + st_Nil, /* 82 */ + st_Nil, /* 83 */ + st_Nil, /* 84 */ + st_Nil, /* 85 */ + st_Nil, /* 86 */ + st_Nil, /* 87 */ + st_Nil, /* 88 */ + st_Nil, /* 89 */ + st_Nil, /* 90 */ + st_Nil, /* 91 */ + st_Nil, /* 92 */ + st_Nil, /* 93 */ + st_Nil, /* 94 */ + st_Nil, /* 95 */ + st_Nil, /* 96 */ + st_Nil, /* 97 */ + st_Nil, /* 98 */ + st_Nil, /* 99 */ + st_Block, /* 100: C_BLOCK block start/end */ + st_Proc, /* 101: C_FCN function start/end */ + st_End, /* 102: C_EOS end of struct/union/enum */ + st_File, /* 103: C_FILE file start */ + st_Nil, /* 104: C_LINE line number */ + st_Nil, /* 105: C_ALIAS combined type info */ + st_Nil, /* 106: C_HIDDEN ??? */ +}; + + +/* Keep track of different sized allocation requests. */ +static alloc_info_t alloc_counts[ (int)alloc_type_last ]; + +/* Record whether we have seen any debugging information. */ +int ecoff_debugging_seen = 0; + +/* Various statics. */ +static efdr_t *cur_file_ptr = (efdr_t *) 0; /* current file desc. header */ +static proc_t *cur_proc_ptr = (proc_t *) 0; /* current procedure header */ +static proc_t *first_proc_ptr = (proc_t *) 0; /* first procedure header */ +static thead_t *top_tag_head = (thead_t *) 0; /* top level tag head */ +static thead_t *cur_tag_head = (thead_t *) 0; /* current tag head */ +#ifdef ECOFF_DEBUG +static int debug = 0; /* trace functions */ +#endif +static int stabs_seen = 0; /* != 0 if stabs have been seen */ + +static int current_file_idx; +static const char *current_stabs_filename; + +/* Pseudo symbol to use when putting stabs into the symbol table. */ +#ifndef STABS_SYMBOL +#define STABS_SYMBOL "@stabs" +#endif + +static char stabs_symbol[] = STABS_SYMBOL; + +/* Prototypes for functions defined in this file. */ + +static void add_varray_page PARAMS ((varray_t *vp)); +static symint_t add_string PARAMS ((varray_t *vp, + struct hash_control *hash_tbl, + const char *str, + shash_t **ret_hash)); +static localsym_t *add_ecoff_symbol PARAMS ((const char *str, st_t type, + sc_t storage, symbolS *sym, + bfd_vma addend, symint_t value, + symint_t indx)); +static symint_t add_aux_sym_symint PARAMS ((symint_t aux_word)); +static symint_t add_aux_sym_rndx PARAMS ((int file_index, + symint_t sym_index)); +static symint_t add_aux_sym_tir PARAMS ((type_info_t *t, + hash_state_t state, + thash_t **hash_tbl)); +static tag_t *get_tag PARAMS ((const char *tag, localsym_t *sym, + bt_t basic_type)); +static void add_unknown_tag PARAMS ((tag_t *ptag)); +static void add_procedure PARAMS ((char *func)); +static void add_file PARAMS ((const char *file_name, int indx, int fake)); +#ifdef ECOFF_DEBUG +static char *sc_to_string PARAMS ((sc_t storage_class)); +static char *st_to_string PARAMS ((st_t symbol_type)); +#endif +static void mark_stabs PARAMS ((int)); +static char *ecoff_add_bytes PARAMS ((char **buf, char **bufend, + char *bufptr, unsigned long need)); +static unsigned long ecoff_padding_adjust + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset, char **bufptrptr)); +static unsigned long ecoff_build_lineno + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset, long *linecntptr)); +static unsigned long ecoff_build_symbols + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_procs + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_aux + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_strings PARAMS ((char **buf, char **bufend, + unsigned long offset, + varray_t *vp)); +static unsigned long ecoff_build_ss + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_fdr + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static void ecoff_setup_ext PARAMS ((void)); +static page_t *allocate_cluster PARAMS ((unsigned long npages)); +static page_t *allocate_page PARAMS ((void)); +static scope_t *allocate_scope PARAMS ((void)); +static void free_scope PARAMS ((scope_t *ptr)); +static vlinks_t *allocate_vlinks PARAMS ((void)); +static shash_t *allocate_shash PARAMS ((void)); +static thash_t *allocate_thash PARAMS ((void)); +static tag_t *allocate_tag PARAMS ((void)); +static void free_tag PARAMS ((tag_t *ptr)); +static forward_t *allocate_forward PARAMS ((void)); +static thead_t *allocate_thead PARAMS ((void)); +static void free_thead PARAMS ((thead_t *ptr)); +static lineno_list_t *allocate_lineno_list PARAMS ((void)); +static void generate_ecoff_stab PARAMS ((int, const char *, int, int, int)); + +/* This function should be called when the assembler starts up. */ + +void +ecoff_read_begin_hook () +{ + tag_hash = hash_new (); + top_tag_head = allocate_thead (); + top_tag_head->first_tag = (tag_t *) NULL; + top_tag_head->free = (thead_t *) NULL; + top_tag_head->prev = cur_tag_head; + cur_tag_head = top_tag_head; +} + +/* This function should be called when a symbol is created. */ + +void +ecoff_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + /* Make sure that we have a file pointer, but only if we have seen a + file. If we haven't seen a file, then this is a probably special + symbol created by md_begin which may required special handling at + some point. Creating a dummy file with a dummy name is certainly + wrong. */ + if (cur_file_ptr == (efdr_t *) NULL + && seen_at_least_1_file ()) + add_file ((const char *) NULL, 0, 1); + symbolP->ecoff_file = cur_file_ptr; + symbolP->ecoff_symbol = NULL; + symbolP->ecoff_extern_size = 0; +} + +/* Add a page to a varray object. */ + +static void +add_varray_page (vp) + varray_t *vp; /* varray to add page to */ +{ + vlinks_t *new_links = allocate_vlinks (); + +#ifdef MALLOC_CHECK + if (vp->object_size > 1) + new_links->datum = (page_t *) xcalloc (1, vp->object_size); + else +#endif + new_links->datum = allocate_page (); + + alloc_counts[(int)alloc_type_varray].total_alloc++; + alloc_counts[(int)alloc_type_varray].total_pages++; + + new_links->start_index = vp->num_allocated; + vp->objects_last_page = 0; + + if (vp->first == (vlinks_t *) NULL) /* first allocation? */ + vp->first = vp->last = new_links; + else + { /* 2nd or greater allocation */ + new_links->prev = vp->last; + vp->last->next = new_links; + vp->last = new_links; + } +} + +/* Add a string (and null pad) to one of the string tables. */ + +static symint_t +add_string (vp, hash_tbl, str, ret_hash) + varray_t *vp; /* string obstack */ + struct hash_control *hash_tbl; /* ptr to hash table */ + const char *str; /* string */ + shash_t **ret_hash; /* return hash pointer */ +{ + register unsigned long len = strlen (str); + register shash_t *hash_ptr; + + if (len >= PAGE_USIZE) + as_fatal ("String too big (%lu bytes)", len); + + hash_ptr = (shash_t *) hash_find (hash_tbl, str); + if (hash_ptr == (shash_t *) NULL) + { + register const char *err; + + if (vp->objects_last_page + len >= PAGE_USIZE) + { + vp->num_allocated = + ((vp->num_allocated + PAGE_USIZE - 1) / PAGE_USIZE) * PAGE_USIZE; + add_varray_page (vp); + } + + hash_ptr = allocate_shash (); + hash_ptr->indx = vp->num_allocated; + + hash_ptr->string = &vp->last->datum->byte[vp->objects_last_page]; + + vp->objects_last_page += len + 1; + vp->num_allocated += len + 1; + + strcpy (hash_ptr->string, str); + + err = hash_insert (hash_tbl, str, (char *) hash_ptr); + if (err) + as_fatal ("Inserting \"%s\" into string hash table: %s", + str, err); + } + + if (ret_hash != (shash_t **) NULL) + *ret_hash = hash_ptr; + + return hash_ptr->indx; +} + +/* Add debugging information for a symbol. */ + +static localsym_t * +add_ecoff_symbol (str, type, storage, sym_value, addend, value, indx) + const char *str; /* symbol name */ + st_t type; /* symbol type */ + sc_t storage; /* storage class */ + symbolS *sym_value; /* associated symbol. */ + bfd_vma addend; /* addend to sym_value. */ + symint_t value; /* value of symbol */ + symint_t indx; /* index to local/aux. syms */ +{ + localsym_t *psym; + register scope_t *pscope; + register thead_t *ptag_head; + register tag_t *ptag; + register tag_t *ptag_next; + register varray_t *vp; + register int scope_delta = 0; + shash_t *hash_ptr = (shash_t *) NULL; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + vp = &cur_file_ptr->symbols; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + psym = &vp->last->datum->sym[ vp->objects_last_page++ ]; + + if (str == (const char *) NULL && sym_value != (symbolS *) NULL) + psym->name = S_GET_NAME (sym_value); + else + psym->name = str; + psym->as_sym = sym_value; + if (sym_value != (symbolS *) NULL) + sym_value->ecoff_symbol = psym; + psym->addend = addend; + psym->file_ptr = cur_file_ptr; + psym->proc_ptr = cur_proc_ptr; + psym->begin_ptr = (localsym_t *) NULL; + psym->index_ptr = (aux_t *) NULL; + psym->forward_ref = (forward_t *) NULL; + psym->sym_index = -1; + memset (&psym->ecoff_sym, 0, sizeof (EXTR)); + psym->ecoff_sym.asym.value = value; + psym->ecoff_sym.asym.st = (unsigned) type; + psym->ecoff_sym.asym.sc = (unsigned) storage; + psym->ecoff_sym.asym.index = indx; + + /* If there is an associated symbol, we wait until the end of the + assembly before deciding where to put the name (it may be just an + external symbol). Otherwise, this is just a debugging symbol and + the name should go with the current file. */ + if (sym_value == (symbolS *) NULL) + psym->ecoff_sym.asym.iss = ((str == (const char *) NULL) + ? 0 + : add_string (&cur_file_ptr->strings, + cur_file_ptr->str_hash, + str, + &hash_ptr)); + + ++vp->num_allocated; + + if (ECOFF_IS_STAB (&psym->ecoff_sym.asym)) + return psym; + + /* Save the symbol within the hash table if this is a static + item, and it has a name. */ + if (hash_ptr != (shash_t *) NULL + && (type == st_Global || type == st_Static || type == st_Label + || type == st_Proc || type == st_StaticProc)) + hash_ptr->sym_ptr = psym; + + /* push or pop a scope if appropriate. */ + switch (type) + { + default: + break; + + case st_File: /* beginning of file */ + case st_Proc: /* procedure */ + case st_StaticProc: /* static procedure */ + case st_Block: /* begin scope */ + pscope = allocate_scope (); + pscope->prev = cur_file_ptr->cur_scope; + pscope->lsym = psym; + pscope->type = type; + cur_file_ptr->cur_scope = pscope; + + if (type != st_File) + scope_delta = 1; + + /* For every block type except file, struct, union, or + enumeration blocks, push a level on the tag stack. We omit + file types, so that tags can span file boundaries. */ + if (type != st_File && storage != sc_Info) + { + ptag_head = allocate_thead (); + ptag_head->first_tag = 0; + ptag_head->prev = cur_tag_head; + cur_tag_head = ptag_head; + } + break; + + case st_End: + pscope = cur_file_ptr->cur_scope; + if (pscope == (scope_t *) NULL) + as_fatal ("too many st_End's"); + else + { + st_t begin_type = (st_t) pscope->lsym->ecoff_sym.asym.st; + + psym->begin_ptr = pscope->lsym; + + if (begin_type != st_File) + scope_delta = -1; + + /* Except for file, structure, union, or enumeration end + blocks remove all tags created within this scope. */ + if (begin_type != st_File && storage != sc_Info) + { + ptag_head = cur_tag_head; + cur_tag_head = ptag_head->prev; + + for (ptag = ptag_head->first_tag; + ptag != (tag_t *) NULL; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *) NULL) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_tag (ptag); + } + + free_thead (ptag_head); + } + + cur_file_ptr->cur_scope = pscope->prev; + + /* block begin gets next sym #. This is set when we know + the symbol index value. */ + + /* Functions push two or more aux words as follows: + 1st word: index+1 of the end symbol (filled in later). + 2nd word: type of the function (plus any aux words needed). + Also, tie the external pointer back to the function begin symbol. */ + if (begin_type != st_File && begin_type != st_Block) + { + symint_t ty; + varray_t *svp = &cur_file_ptr->aux_syms; + + pscope->lsym->ecoff_sym.asym.index = add_aux_sym_symint (0); + pscope->lsym->index_ptr = + &svp->last->datum->aux[svp->objects_last_page - 1]; + ty = add_aux_sym_tir (&last_func_type_info, + hash_no, + &cur_file_ptr->thash_head[0]); + +/* This seems to be unnecessary. I'm not even sure what it is + * intended to do. It's from mips-tfile. + * if (last_func_sym_value != (symbolS *) NULL) + * { + * last_func_sym_value->ifd = cur_file_ptr->file_index; + * last_func_sym_value->index = ty; + * } + */ + } + + free_scope (pscope); + } + } + + cur_file_ptr->nested_scopes += scope_delta; + +#ifdef ECOFF_DEBUG + if (debug && type != st_File + && (debug > 2 || type == st_Block || type == st_End + || type == st_Proc || type == st_StaticProc)) + { + char *sc_str = sc_to_string (storage); + char *st_str = st_to_string (type); + int depth = cur_file_ptr->nested_scopes + (scope_delta < 0); + + fprintf (stderr, + "\tlsym\tv= %10ld, depth= %2d, sc= %-12s", + value, depth, sc_str); + + if (str_start && str_end_p1 - str_start > 0) + fprintf (stderr, " st= %-11s name= %.*s\n", st_str, str_end_p1 - str_start, str_start); + else + { + unsigned long len = strlen (st_str); + fprintf (stderr, " st= %.*s\n", len-1, st_str); + } + } +#endif + + return psym; +} + +/* Add an auxiliary symbol (passing a symint). This is actually used + for integral aux types, not just symints. */ + +static symint_t +add_aux_sym_symint (aux_word) + symint_t aux_word; /* auxiliary information word */ +{ + register varray_t *vp; + register aux_t *aux_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + vp = &cur_file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[vp->objects_last_page++]; + aux_ptr->type = aux_isym; + aux_ptr->data.isym = aux_word; + + return vp->num_allocated++; +} + + +/* Add an auxiliary symbol (passing a file/symbol index combo). */ + +static symint_t +add_aux_sym_rndx (file_index, sym_index) + int file_index; + symint_t sym_index; +{ + register varray_t *vp; + register aux_t *aux_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + vp = &cur_file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[vp->objects_last_page++]; + aux_ptr->type = aux_rndx; + aux_ptr->data.rndx.rfd = file_index; + aux_ptr->data.rndx.index = sym_index; + + return vp->num_allocated++; +} + +/* Add an auxiliary symbol (passing the basic type and possibly + type qualifiers). */ + +static symint_t +add_aux_sym_tir (t, state, hash_tbl) + type_info_t *t; /* current type information */ + hash_state_t state; /* whether to hash type or not */ + thash_t **hash_tbl; /* pointer to hash table to use */ +{ + register varray_t *vp; + register aux_t *aux_ptr; + static AUXU init_aux; + symint_t ret; + int i; + AUXU aux; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + vp = &cur_file_ptr->aux_syms; + + aux = init_aux; + aux.ti.bt = (int) t->basic_type; + aux.ti.continued = 0; + aux.ti.fBitfield = t->bitfield; + + aux.ti.tq0 = (int) t->type_qualifiers[0]; + aux.ti.tq1 = (int) t->type_qualifiers[1]; + aux.ti.tq2 = (int) t->type_qualifiers[2]; + aux.ti.tq3 = (int) t->type_qualifiers[3]; + aux.ti.tq4 = (int) t->type_qualifiers[4]; + aux.ti.tq5 = (int) t->type_qualifiers[5]; + + + /* For anything that adds additional information, we must not hash, + so check here, and reset our state. */ + + if (state != hash_no + && (t->type_qualifiers[0] == tq_Array + || t->type_qualifiers[1] == tq_Array + || t->type_qualifiers[2] == tq_Array + || t->type_qualifiers[3] == tq_Array + || t->type_qualifiers[4] == tq_Array + || t->type_qualifiers[5] == tq_Array + || t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum + || t->bitfield + || t->num_dims > 0)) + state = hash_no; + + /* See if we can hash this type, and save some space, but some types + can't be hashed (because they contain arrays or continuations), + and others can be put into the hash list, but cannot use existing + types because other aux entries precede this one. */ + + if (state != hash_no) + { + register thash_t *hash_ptr; + register symint_t hi; + + hi = aux.isym & ((1 << HASHBITS) - 1); + hi %= THASH_SIZE; + + for (hash_ptr = hash_tbl[hi]; + hash_ptr != (thash_t *)0; + hash_ptr = hash_ptr->next) + { + if (aux.isym == hash_ptr->type.isym) + break; + } + + if (hash_ptr != (thash_t *) NULL && state == hash_yes) + return hash_ptr->indx; + + if (hash_ptr == (thash_t *) NULL) + { + hash_ptr = allocate_thash (); + hash_ptr->next = hash_tbl[hi]; + hash_ptr->type = aux; + hash_ptr->indx = vp->num_allocated; + hash_tbl[hi] = hash_ptr; + } + } + + /* Everything is set up, add the aux symbol. */ + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[ vp->objects_last_page++ ]; + aux_ptr->type = aux_tir; + aux_ptr->data = aux; + + ret = vp->num_allocated++; + + /* Add bitfield length if it exists. + + NOTE: Mips documentation claims bitfield goes at the end of the + AUX record, but the DECstation compiler emits it here. + (This would only make a difference for enum bitfields.) + + Also note: We use the last size given since gcc may emit 2 + for an enum bitfield. */ + + if (t->bitfield) + (void) add_aux_sym_symint ((symint_t)t->sizes[t->num_sizes-1]); + + + /* Add tag information if needed. Structure, union, and enum + references add 2 aux symbols: a [file index, symbol index] + pointer to the structure type, and the current file index. */ + + if (t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum) + { + register symint_t file_index = t->tag_ptr->ifd; + register localsym_t *sym = t->tag_ptr->sym; + register forward_t *forward_ref = allocate_forward (); + + if (sym != (localsym_t *) NULL) + { + forward_ref->next = sym->forward_ref; + sym->forward_ref = forward_ref; + } + else + { + forward_ref->next = t->tag_ptr->forward_ref; + t->tag_ptr->forward_ref = forward_ref; + } + + (void) add_aux_sym_rndx (ST_RFDESCAPE, indexNil); + forward_ref->index_ptr + = &vp->last->datum->aux[ vp->objects_last_page - 1]; + + (void) add_aux_sym_symint (file_index); + forward_ref->ifd_ptr + = &vp->last->datum->aux[ vp->objects_last_page - 1]; + } + + /* Add information about array bounds if they exist. */ + for (i = 0; i < t->num_dims; i++) + { + (void) add_aux_sym_rndx (ST_RFDESCAPE, + cur_file_ptr->int_type); + + (void) add_aux_sym_symint (cur_file_ptr->file_index); /* file index*/ + (void) add_aux_sym_symint ((symint_t) 0); /* low bound */ + (void) add_aux_sym_symint (t->dimensions[i] - 1); /* high bound*/ + (void) add_aux_sym_symint ((t->dimensions[i] == 0) /* stride */ + ? 0 + : (t->sizes[i] * 8) / t->dimensions[i]); + }; + + /* NOTE: Mips documentation claims that the bitfield width goes here. + But it needs to be emitted earlier. */ + + return ret; +} + +/* Add a tag to the tag table (unless it already exists). */ + +static tag_t * +get_tag (tag, sym, basic_type) + const char *tag; /* tag name */ + localsym_t *sym; /* tag start block */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ +{ + shash_t *hash_ptr; + const char *err; + tag_t *tag_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + hash_ptr = (shash_t *) hash_find (tag_hash, tag); + + if (hash_ptr != (shash_t *) NULL + && hash_ptr->tag_ptr != (tag_t *) NULL) + { + tag_ptr = hash_ptr->tag_ptr; + if (sym != (localsym_t *) NULL) + { + tag_ptr->basic_type = basic_type; + tag_ptr->ifd = cur_file_ptr->file_index; + tag_ptr->sym = sym; + } + return tag_ptr; + } + + if (hash_ptr == (shash_t *) NULL) + { + char *perm; + + perm = xmalloc ((unsigned long) (strlen (tag) + 1)); + strcpy (perm, tag); + hash_ptr = allocate_shash (); + err = hash_insert (tag_hash, perm, (char *) hash_ptr); + if (err) + as_fatal ("Inserting \"%s\" into tag hash table: %s", + tag, err); + hash_ptr->string = perm; + } + + tag_ptr = allocate_tag (); + tag_ptr->forward_ref = (forward_t *) NULL; + tag_ptr->hash_ptr = hash_ptr; + tag_ptr->same_name = hash_ptr->tag_ptr; + tag_ptr->basic_type = basic_type; + tag_ptr->sym = sym; + tag_ptr->ifd = ((sym == (localsym_t *) NULL) + ? (symint_t) -1 + : cur_file_ptr->file_index); + tag_ptr->same_block = cur_tag_head->first_tag; + + cur_tag_head->first_tag = tag_ptr; + hash_ptr->tag_ptr = tag_ptr; + + return tag_ptr; +} + +/* Add an unknown {struct, union, enum} tag. */ + +static void +add_unknown_tag (ptag) + tag_t *ptag; /* pointer to tag information */ +{ + shash_t *hash_ptr = ptag->hash_ptr; + char *name = hash_ptr->string; + localsym_t *sym; + forward_t **pf; + +#ifdef ECOFF_DEBUG + if (debug > 1) + { + char *agg_type = "{unknown aggregate type}"; + switch (ptag->basic_type) + { + case bt_Struct: agg_type = "struct"; break; + case bt_Union: agg_type = "union"; break; + case bt_Enum: agg_type = "enum"; break; + default: break; + } + + fprintf (stderr, "unknown %s %.*s found\n", agg_type, + hash_ptr->len, name_start); + } +#endif + + sym = add_ecoff_symbol (name, + st_Block, + sc_Info, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + + (void) add_ecoff_symbol (name, + st_End, + sc_Info, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + + for (pf = &sym->forward_ref; *pf != (forward_t *) NULL; pf = &(*pf)->next) + ; + *pf = ptag->forward_ref; +} + +/* Add a procedure to the current file's list of procedures, and record + this is the current procedure. */ + +static void +add_procedure (func) + char *func; /* func name */ +{ + register varray_t *vp; + register proc_t *new_proc_ptr; + symbolS *sym; + +#ifdef ECOFF_DEBUG + if (debug) + fputc ('\n', stderr); +#endif + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal ("no current file pointer"); + + vp = &cur_file_ptr->procs; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + cur_proc_ptr = new_proc_ptr = &vp->last->datum->proc[vp->objects_last_page++]; + + if (first_proc_ptr == (proc_t *) NULL) + first_proc_ptr = new_proc_ptr; + + vp->num_allocated++; + + new_proc_ptr->pdr.isym = -1; + new_proc_ptr->pdr.iline = -1; + new_proc_ptr->pdr.lnLow = -1; + new_proc_ptr->pdr.lnHigh = -1; + + /* Set the BSF_FUNCTION flag for the symbol. */ + sym = symbol_find_or_make (func); + sym->bsym->flags |= BSF_FUNCTION; + + /* Push the start of the function. */ + new_proc_ptr->sym = add_ecoff_symbol ((const char *) NULL, st_Proc, sc_Text, + sym, (bfd_vma) 0, (symint_t) 0, + (symint_t) 0); + + ++proc_cnt; + + /* Fill in the linenos preceding the .ent, if any. */ + if (noproc_lineno != (lineno_list_t *) NULL) + { + lineno_list_t *l; + + for (l = noproc_lineno; l != (lineno_list_t *) NULL; l = l->next) + l->proc = new_proc_ptr; + *last_lineno_ptr = noproc_lineno; + while (*last_lineno_ptr != NULL) + { + last_lineno = *last_lineno_ptr; + last_lineno_ptr = &last_lineno->next; + } + noproc_lineno = (lineno_list_t *) NULL; + } +} + +/* Add a new filename, and set up all of the file relative + virtual arrays (strings, symbols, aux syms, etc.). Record + where the current file structure lives. */ + +static void +add_file (file_name, indx, fake) + const char *file_name; /* file name */ + int indx; + int fake; +{ + register int first_ch; + register efdr_t *fil_ptr; + +#ifdef ECOFF_DEBUG + if (debug) + fprintf (stderr, "\tfile\t%.*s\n", len, file_start); +#endif + + /* If the file name is NULL, then no .file symbol appeared, and we + want to use the actual file name. */ + if (file_name == (const char *) NULL) + { + char *file; + + if (first_file != (efdr_t *) NULL) + as_fatal ("fake .file after real one"); + as_where (&file, (unsigned int *) NULL); + file_name = (const char *) file; + + if (! symbol_table_frozen) + generate_asm_lineno = 1; + } + else + generate_asm_lineno = 0; + +#ifndef NO_LISTING + if (listing) + listing_source_file (file_name); +#endif + + current_stabs_filename = file_name; + + /* If we're creating stabs, then we don't actually make a new FDR. + Instead, we just create a stabs symbol. */ + if (stabs_seen) + { + (void) add_ecoff_symbol (file_name, st_Nil, sc_Nil, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, 0, ECOFF_MARK_STAB (N_SOL)); + return; + } + + first_ch = *file_name; + + /* FIXME: We can't safely merge files which have line number + information (fMerge will be zero in this case). Otherwise, we + get incorrect line number debugging info. See for instance + ecoff_build_lineno, which will end up setting all file->fdr.* + fields multiple times, resulting in incorrect debug info. In + order to make this work right, all line number and symbol info + for the same source file has to be adjacent in the object file, + so that a single file descriptor can be used to point to them. + This would require maintaining file specific lists of line + numbers and symbols for each file, so that they can be merged + together (or output together) when two .file pseudo-ops are + merged into one file descriptor. */ + + /* See if the file has already been created. */ + for (fil_ptr = first_file; + fil_ptr != (efdr_t *) NULL; + fil_ptr = fil_ptr->next_file) + { + if (first_ch == fil_ptr->name[0] + && strcmp (file_name, fil_ptr->name) == 0 + && fil_ptr->fdr.fMerge) + { + cur_file_ptr = fil_ptr; + if (! fake) + cur_file_ptr->fake = 0; + break; + } + } + + /* If this is a new file, create it. */ + if (fil_ptr == (efdr_t *) NULL) + { + if (file_desc.objects_last_page == file_desc.objects_per_page) + add_varray_page (&file_desc); + + fil_ptr = cur_file_ptr = + &file_desc.last->datum->file[file_desc.objects_last_page++]; + *fil_ptr = init_file; + + fil_ptr->file_index = current_file_idx++; + ++file_desc.num_allocated; + + fil_ptr->fake = fake; + + /* Allocate the string hash table. */ + fil_ptr->str_hash = hash_new (); + + /* Make sure 0 byte in string table is null */ + add_string (&fil_ptr->strings, + fil_ptr->str_hash, + "", + (shash_t **)0); + + if (strlen (file_name) > PAGE_USIZE - 2) + as_fatal ("Filename goes over one page boundary."); + + /* Push the start of the filename. We assume that the filename + will be stored at string offset 1. */ + (void) add_ecoff_symbol (file_name, st_File, sc_Text, + (symbolS *) NULL, (bfd_vma) 0, + (symint_t) 0, (symint_t) 0); + fil_ptr->fdr.rss = 1; + fil_ptr->name = &fil_ptr->strings.last->datum->byte[1]; + + /* Update the linked list of file descriptors. */ + *last_file_ptr = fil_ptr; + last_file_ptr = &fil_ptr->next_file; + + /* Add void & int types to the file (void should be first to catch + errant 0's within the index fields). */ + fil_ptr->void_type = add_aux_sym_tir (&void_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + + fil_ptr->int_type = add_aux_sym_tir (&int_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + /* gas used to have a bug that if the file does not have any + symbol, it either will abort or will not build the file, + the following is to get around that problem. ---kung*/ +#if 0 + if (generate_asm_lineno) + { + mark_stabs (0); + (void) add_ecoff_symbol (file_name, st_Nil, sc_Nil, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, 0, ECOFF_MARK_STAB (N_SO)); + (void) add_ecoff_symbol ("void:t1=1", st_Nil, sc_Nil, + (symbolS *) NULL, (bfd_vma) 0, 0, + ECOFF_MARK_STAB (N_LSYM)); + } +#endif + } +} + +/* This function is called when the assembler notices a preprocessor + directive switching to a new file. This will not happen in + compiler output, only in hand coded assembler. */ + +void +ecoff_new_file (name) + const char *name; +{ + if (cur_file_ptr != NULL && strcmp (cur_file_ptr->name, name) == 0) + return; + add_file (name, 0, 0); + generate_asm_lineno = 1; +} + +#ifdef ECOFF_DEBUG + +/* Convert storage class to string. */ + +static char * +sc_to_string(storage_class) + sc_t storage_class; +{ + switch(storage_class) + { + case sc_Nil: return "Nil,"; + case sc_Text: return "Text,"; + case sc_Data: return "Data,"; + case sc_Bss: return "Bss,"; + case sc_Register: return "Register,"; + case sc_Abs: return "Abs,"; + case sc_Undefined: return "Undefined,"; + case sc_CdbLocal: return "CdbLocal,"; + case sc_Bits: return "Bits,"; + case sc_CdbSystem: return "CdbSystem,"; + case sc_RegImage: return "RegImage,"; + case sc_Info: return "Info,"; + case sc_UserStruct: return "UserStruct,"; + case sc_SData: return "SData,"; + case sc_SBss: return "SBss,"; + case sc_RData: return "RData,"; + case sc_Var: return "Var,"; + case sc_Common: return "Common,"; + case sc_SCommon: return "SCommon,"; + case sc_VarRegister: return "VarRegister,"; + case sc_Variant: return "Variant,"; + case sc_SUndefined: return "SUndefined,"; + case sc_Init: return "Init,"; + case sc_Max: return "Max,"; + } + + return "???,"; +} + +#endif /* DEBUG */ + +#ifdef ECOFF_DEBUG + +/* Convert symbol type to string. */ + +static char * +st_to_string(symbol_type) + st_t symbol_type; +{ + switch(symbol_type) + { + case st_Nil: return "Nil,"; + case st_Global: return "Global,"; + case st_Static: return "Static,"; + case st_Param: return "Param,"; + case st_Local: return "Local,"; + case st_Label: return "Label,"; + case st_Proc: return "Proc,"; + case st_Block: return "Block,"; + case st_End: return "End,"; + case st_Member: return "Member,"; + case st_Typedef: return "Typedef,"; + case st_File: return "File,"; + case st_RegReloc: return "RegReloc,"; + case st_Forward: return "Forward,"; + case st_StaticProc: return "StaticProc,"; + case st_Constant: return "Constant,"; + case st_Str: return "String,"; + case st_Number: return "Number,"; + case st_Expr: return "Expr,"; + case st_Type: return "Type,"; + case st_Max: return "Max,"; + } + + return "???,"; +} + +#endif /* DEBUG */ + +/* Parse .begin directives which have a label as the first argument + which gives the location of the start of the block. */ + +void +ecoff_directive_begin (ignore) + int ignore; +{ + char *name; + char name_end; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (".begin directive without a preceding .file directive"); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".begin directive without a preceding .ent directive"); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + (void) add_ecoff_symbol ((const char *) NULL, st_Block, sc_Text, + symbol_find_or_make (name), + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + *input_line_pointer = name_end; + + /* The line number follows, but we don't use it. */ + (void) get_absolute_expression (); + demand_empty_rest_of_line (); +} + +/* Parse .bend directives which have a label as the first argument + which gives the location of the end of the block. */ + +void +ecoff_directive_bend (ignore) + int ignore; +{ + char *name; + char name_end; + symbolS *endsym; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (".bend directive without a preceding .file directive"); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".bend directive without a preceding .ent directive"); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + /* The value is the distance between the .bend directive and the + corresponding symbol. We fill in the offset when we write out + the symbol. */ + endsym = symbol_find (name); + if (endsym == (symbolS *) NULL) + as_warn (".bend directive names unknown symbol"); + else + (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, endsym, + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + *input_line_pointer = name_end; + + /* The line number follows, but we don't use it. */ + (void) get_absolute_expression (); + demand_empty_rest_of_line (); +} + +/* COFF debugging information is provided as a series of directives + (.def, .scl, etc.). We build up information as we read the + directives in the following static variables, and file it away when + we reach the .endef directive. */ +static char *coff_sym_name; +static type_info_t coff_type; +static sc_t coff_storage_class; +static st_t coff_symbol_typ; +static int coff_is_function; +static char *coff_tag; +static valueT coff_value; +static symbolS *coff_sym_value; +static bfd_vma coff_sym_addend; +static int coff_inside_enumeration; + +/* Handle a .def directive: start defining a symbol. */ + +void +ecoff_directive_def (ignore) + int ignore; +{ + char *name; + char name_end; + + ecoff_debugging_seen = 1; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + name_end = get_symbol_end (); + + if (coff_sym_name != (char *) NULL) + as_warn (".def pseudo-op used inside of .def/.endef; ignored"); + else if (*name == '\0') + as_warn ("Empty symbol name in .def; ignored"); + else + { + if (coff_sym_name != (char *) NULL) + free (coff_sym_name); + if (coff_tag != (char *) NULL) + free (coff_tag); + coff_sym_name = (char *) xmalloc ((unsigned long) (strlen (name) + 1)); + strcpy (coff_sym_name, name); + coff_type = type_info_init; + coff_storage_class = sc_Nil; + coff_symbol_typ = st_Nil; + coff_is_function = 0; + coff_tag = (char *) NULL; + coff_value = 0; + coff_sym_value = (symbolS *) NULL; + coff_sym_addend = 0; + } + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +/* Handle a .dim directive, used to give dimensions for an array. The + arguments are comma separated numbers. mips-tfile assumes that + there will not be more than 6 dimensions, and gdb won't read any + more than that anyhow, so I will also make that assumption. */ + +void +ecoff_directive_dim (ignore) + int ignore; +{ + int dimens[N_TQ]; + int i; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".dim pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + for (i = 0; i < N_TQ; i++) + { + SKIP_WHITESPACE (); + dimens[i] = get_absolute_expression (); + if (*input_line_pointer == ',') + ++input_line_pointer; + else + { + if (*input_line_pointer != '\n' + && *input_line_pointer != ';') + as_warn ("Badly formed .dim directive"); + break; + } + } + + if (i == N_TQ) + --i; + + /* The dimensions are stored away in reverse order. */ + for (; i >= 0; i--) + { + if (coff_type.num_dims >= N_TQ) + { + as_warn ("Too many .dim entries"); + break; + } + coff_type.dimensions[coff_type.num_dims] = dimens[i]; + ++coff_type.num_dims; + } + + demand_empty_rest_of_line (); +} + +/* Handle a .scl directive, which sets the COFF storage class of the + symbol. */ + +void +ecoff_directive_scl (ignore) + int ignore; +{ + long val; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".scl pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + val = get_absolute_expression (); + + coff_symbol_typ = map_coff_sym_type[val]; + coff_storage_class = map_coff_storage[val]; + + demand_empty_rest_of_line (); +} + +/* Handle a .size directive. For some reason mips-tfile.c thinks that + .size can have multiple arguments. We humor it, although gcc will + never generate more than one argument. */ + +void +ecoff_directive_size (ignore) + int ignore; +{ + int sizes[N_TQ]; + int i; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".size pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + for (i = 0; i < N_TQ; i++) + { + SKIP_WHITESPACE (); + sizes[i] = get_absolute_expression (); + if (*input_line_pointer == ',') + ++input_line_pointer; + else + { + if (*input_line_pointer != '\n' + && *input_line_pointer != ';') + as_warn ("Badly formed .size directive"); + break; + } + } + + if (i == N_TQ) + --i; + + /* The sizes are stored away in reverse order. */ + for (; i >= 0; i--) + { + if (coff_type.num_sizes >= N_TQ) + { + as_warn ("Too many .size entries"); + break; + } + coff_type.sizes[coff_type.num_sizes] = sizes[i]; + ++coff_type.num_sizes; + } + + demand_empty_rest_of_line (); +} + +/* Handle the .type directive, which gives the COFF type of the + symbol. */ + +void +ecoff_directive_type (ignore) + int ignore; +{ + long val; + tq_t *tq_ptr; + tq_t *tq_shft; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".type pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + val = get_absolute_expression (); + + coff_type.orig_type = BTYPE (val); + coff_type.basic_type = map_coff_types[coff_type.orig_type]; + + tq_ptr = &coff_type.type_qualifiers[N_TQ]; + while (val &~ N_BTMASK) + { + if (tq_ptr == &coff_type.type_qualifiers[0]) + { + /* FIXME: We could handle this by setting the continued bit. + There would still be a limit: the .type argument can not + be infinite. */ + as_warn ("The type of %s is too complex; it will be simplified", + coff_sym_name); + break; + } + if (ISPTR (val)) + *--tq_ptr = tq_Ptr; + else if (ISFCN (val)) + *--tq_ptr = tq_Proc; + else if (ISARY (val)) + *--tq_ptr = tq_Array; + else + as_fatal ("Unrecognized .type argument"); + + val = DECREF (val); + } + + tq_shft = &coff_type.type_qualifiers[0]; + while (tq_ptr != &coff_type.type_qualifiers[N_TQ]) + *tq_shft++ = *tq_ptr++; + + if (tq_shft != &coff_type.type_qualifiers[0] && tq_shft[-1] == tq_Proc) + { + /* If this is a function, ignore it, so that we don't get two + entries (one from the .ent, and one for the .def that + precedes it). Save the type information so that the end + block can properly add it after the begin block index. For + MIPS knows what reason, we must strip off the function type + at this point. */ + coff_is_function = 1; + tq_shft[-1] = tq_Nil; + } + + while (tq_shft != &coff_type.type_qualifiers[N_TQ]) + *tq_shft++ = tq_Nil; + + demand_empty_rest_of_line (); +} + +/* Handle the .tag directive, which gives the name of a structure, + union or enum. */ + +void +ecoff_directive_tag (ignore) + int ignore; +{ + char *name; + char name_end; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".tag pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + coff_tag = (char *) xmalloc ((unsigned long) (strlen (name) + 1)); + strcpy (coff_tag, name); + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +/* Handle the .val directive, which gives the value of the symbol. It + may be the name of a static or global symbol. */ + +void +ecoff_directive_val (ignore) + int ignore; +{ + expressionS exp; + + if (coff_sym_name == (char *) NULL) + { + as_warn (".val pseudo-op used outside of .def/.endef; ignored"); + demand_empty_rest_of_line (); + return; + } + + expression (&exp); + if (exp.X_op != O_constant && exp.X_op != O_symbol) + { + as_bad (".val expression is too copmlex"); + demand_empty_rest_of_line (); + return; + } + + if (exp.X_op == O_constant) + coff_value = exp.X_add_number; + else + { + coff_sym_value = exp.X_add_symbol; + coff_sym_addend = exp.X_add_number; + } + + demand_empty_rest_of_line (); +} + +/* Handle the .endef directive, which terminates processing of COFF + debugging information for a symbol. */ + +void +ecoff_directive_endef (ignore) + int ignore; +{ + char *name; + symint_t indx; + localsym_t *sym; + + demand_empty_rest_of_line (); + + if (coff_sym_name == (char *) NULL) + { + as_warn (".endef pseudo-op used before .def; ignored"); + return; + } + + name = coff_sym_name; + coff_sym_name = (char *) NULL; + + /* If the symbol is a static or external, we have already gotten the + appropriate type and class, so make sure we don't override those + values. This is needed because there are some type and classes + that are not in COFF, such as short data, etc. */ + if (coff_sym_value != (symbolS *) NULL) + { + coff_symbol_typ = st_Nil; + coff_storage_class = sc_Nil; + } + + coff_type.extra_sizes = coff_tag != (char *) NULL; + if (coff_type.num_dims > 0) + { + int diff = coff_type.num_dims - coff_type.num_sizes; + int i = coff_type.num_dims - 1; + int j; + + if (coff_type.num_sizes != 1 || diff < 0) + { + as_warn ("Bad COFF debugging info"); + return; + } + + /* If this is an array, make sure the same number of dimensions + and sizes were passed, creating extra sizes for multiply + dimensioned arrays if not passed. */ + coff_type.extra_sizes = 0; + if (diff) + { + j = (sizeof (coff_type.sizes) / sizeof (coff_type.sizes[0])) - 1; + while (j >= 0) + { + coff_type.sizes[j] = (((j - diff) >= 0) + ? coff_type.sizes[j - diff] + : 0); + j--; + } + + coff_type.num_sizes = i + 1; + for (i--; i >= 0; i--) + coff_type.sizes[i] = (coff_type.dimensions[i + 1] == 0 + ? 0 + : (coff_type.sizes[i + 1] + / coff_type.dimensions[i + 1])); + } + } + else if (coff_symbol_typ == st_Member + && coff_type.num_sizes - coff_type.extra_sizes == 1) + { + /* Is this a bitfield? This is indicated by a structure memeber + having a size field that isn't an array. */ + coff_type.bitfield = 1; + } + + /* Except for enumeration members & begin/ending of scopes, put the + type word in the aux. symbol table. */ + if (coff_symbol_typ == st_Block || coff_symbol_typ == st_End) + indx = 0; + else if (coff_inside_enumeration) + indx = cur_file_ptr->void_type; + else + { + if (coff_type.basic_type == bt_Struct + || coff_type.basic_type == bt_Union + || coff_type.basic_type == bt_Enum) + { + if (coff_tag == (char *) NULL) + { + as_warn ("No tag specified for %s", name); + return; + } + + coff_type.tag_ptr = get_tag (coff_tag, (localsym_t *) NULL, + coff_type.basic_type); + } + + if (coff_is_function) + { + last_func_type_info = coff_type; + last_func_sym_value = coff_sym_value; + return; + } + + indx = add_aux_sym_tir (&coff_type, + hash_yes, + &cur_file_ptr->thash_head[0]); + } + + /* Do any last minute adjustments that are necessary. */ + switch (coff_symbol_typ) + { + default: + break; + + /* For the beginning of structs, unions, and enumerations, the + size info needs to be passed in the value field. */ + case st_Block: + if (coff_type.num_sizes - coff_type.num_dims - coff_type.extra_sizes + != 1) + { + as_warn ("Bad COFF debugging information"); + return; + } + else + coff_value = coff_type.sizes[0]; + + coff_inside_enumeration = (coff_type.orig_type == T_ENUM); + break; + + /* For the end of structs, unions, and enumerations, omit the + name which is always ".eos". This needs to be done last, so + that any error reporting above gives the correct name. */ + case st_End: + free (name); + name = (char *) NULL; + coff_value = 0; + coff_inside_enumeration = 0; + break; + + /* Members of structures and unions that aren't bitfields, need + to adjust the value from a byte offset to a bit offset. + Members of enumerations do not have the value adjusted, and + can be distinguished by indx == indexNil. For enumerations, + update the maximum enumeration value. */ + case st_Member: + if (! coff_type.bitfield && ! coff_inside_enumeration) + coff_value *= 8; + + break; + } + + /* Add the symbol. */ + sym = add_ecoff_symbol (name, + coff_symbol_typ, + coff_storage_class, + coff_sym_value, + coff_sym_addend, + (symint_t) coff_value, + indx); + + /* deal with struct, union, and enum tags. */ + if (coff_symbol_typ == st_Block) + { + /* Create or update the tag information. */ + tag_t *tag_ptr = get_tag (name, + sym, + coff_type.basic_type); + forward_t **pf; + + /* Remember any forward references. */ + for (pf = &sym->forward_ref; + *pf != (forward_t *) NULL; + pf = &(*pf)->next) + ; + *pf = tag_ptr->forward_ref; + tag_ptr->forward_ref = (forward_t *) NULL; + } +} + +/* Parse .end directives. */ + +void +ecoff_directive_end (ignore) + int ignore; +{ + char *name; + char name_end; + register int ch; + symbolS *ent; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (".end directive without a preceding .file directive"); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".end directive without a preceding .ent directive"); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + ch = *name; + if (! is_name_beginner (ch)) + { + as_warn (".end directive has no name"); + *input_line_pointer = name_end; + demand_empty_rest_of_line (); + return; + } + + /* The value is the distance between the .end directive and the + corresponding symbol. We create a fake symbol to hold the + current location, and put in the offset when we write out the + symbol. */ + ent = symbol_find (name); + if (ent == (symbolS *) NULL) + as_warn (".end directive names unknown symbol"); + else + { + (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + if (stabs_seen && generate_asm_lineno) + { + char *n; + + n = xmalloc (strlen (name) + 4); + strcpy (n, name); + strcat (n, ":F1"); + (void) add_ecoff_symbol ((const char *) n, stGlobal, scText, + ent, (bfd_vma) 0, 0, + ECOFF_MARK_STAB (N_FUN)); + } + } + + cur_proc_ptr = (proc_t *) NULL; + + *input_line_pointer = name_end; + demand_empty_rest_of_line (); +} + +/* Parse .ent directives. */ + +void +ecoff_directive_ent (ignore) + int ignore; +{ + char *name; + char name_end; + register int ch; + + if (cur_file_ptr == (efdr_t *) NULL) + add_file ((const char *) NULL, 0, 1); + + if (cur_proc_ptr != (proc_t *) NULL) + { + as_warn ("second .ent directive found before .end directive"); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + ch = *name; + if (! is_name_beginner (ch)) + { + as_warn (".ent directive has no name"); + *input_line_pointer = name_end; + demand_empty_rest_of_line (); + return; + } + + add_procedure (name); + + *input_line_pointer = name_end; + + /* The .ent directive is sometimes followed by a number. I'm not + really sure what the number means. I don't see any way to store + the information in the PDR. The Irix 4 assembler seems to ignore + the information. */ + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + } + if (isdigit (*input_line_pointer) || *input_line_pointer == '-') + (void) get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .extern directives. */ + +void +ecoff_directive_extern (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolp; + valueT size; + + name = input_line_pointer; + c = get_symbol_end (); + symbolp = symbol_find_or_make (name); + *input_line_pointer = c; + + S_SET_EXTERNAL (symbolp); + + if (*input_line_pointer == ',') + ++input_line_pointer; + size = get_absolute_expression (); + + symbolp->ecoff_extern_size = size; +} + +/* Parse .file directives. */ + +void +ecoff_directive_file (ignore) + int ignore; +{ + int indx; + char *name; + int len; + + if (cur_proc_ptr != (proc_t *) NULL) + { + as_warn ("No way to handle .file within .ent/.end section"); + demand_empty_rest_of_line (); + return; + } + + indx = (int) get_absolute_expression (); + + /* FIXME: we don't have to save the name here. */ + name = demand_copy_C_string (&len); + + add_file (name, indx - 1, 0); + + demand_empty_rest_of_line (); +} + +/* Parse .fmask directives. */ + +void +ecoff_directive_fmask (ignore) + int ignore; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".fmask outside of .ent"); + demand_empty_rest_of_line (); + return; + } + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .fmask directive"); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.fregmask = val; + cur_proc_ptr->pdr.fregoffset = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .frame directives. */ + +void +ecoff_directive_frame (ignore) + int ignore; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".frame outside of .ent"); + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.framereg = tc_get_register (1); + + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',' + || get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .frame directive"); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.frameoffset = val; + + cur_proc_ptr->pdr.pcreg = tc_get_register (0); + +#if 0 /* Alpha-OSF1 adds "the offset of saved $a0 from $sp", according + to Sandro. I don't yet know where this value should be stored, if + anywhere. */ + demand_empty_rest_of_line (); +#else + s_ignore (42); +#endif +} + +/* Parse .mask directives. */ + +void +ecoff_directive_mask (ignore) + int ignore; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (".mask outside of .ent"); + demand_empty_rest_of_line (); + return; + } + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn ("Bad .mask directive"); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.regmask = val; + cur_proc_ptr->pdr.regoffset = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .loc directives. */ + +void +ecoff_directive_loc (ignore) + int ignore; +{ + lineno_list_t *list; + symint_t lineno; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (".loc before .file"); + demand_empty_rest_of_line (); + return; + } + + if (now_seg != text_section) + { + as_warn (".loc outside of .text"); + demand_empty_rest_of_line (); + return; + } + + /* Skip the file number. */ + SKIP_WHITESPACE (); + get_absolute_expression (); + SKIP_WHITESPACE (); + + lineno = get_absolute_expression (); + +#ifndef NO_LISTING + if (listing) + listing_source_line (lineno); +#endif + + /* If we're building stabs, then output a special label rather than + ECOFF line number info. */ + if (stabs_seen) + { + (void) add_ecoff_symbol ((char *) NULL, st_Label, sc_Text, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, 0, lineno); + return; + } + + list = allocate_lineno_list (); + + list->next = (lineno_list_t *) NULL; + list->file = cur_file_ptr; + list->proc = cur_proc_ptr; + list->frag = frag_now; + list->paddr = frag_now_fix (); + list->lineno = lineno; + + /* We don't want to merge files which have line numbers. */ + cur_file_ptr->fdr.fMerge = 0; + + /* A .loc directive will sometimes appear before a .ent directive, + which means that cur_proc_ptr will be NULL here. Arrange to + patch this up. */ + if (cur_proc_ptr == (proc_t *) NULL) + { + lineno_list_t **pl; + + pl = &noproc_lineno; + while (*pl != (lineno_list_t *) NULL) + pl = &(*pl)->next; + *pl = list; + } + else + { + last_lineno = list; + *last_lineno_ptr = list; + last_lineno_ptr = &list->next; + } +} + +/* The MIPS assembler sometimes inserts nop instructions in the + instruction stream. When this happens, we must patch up the .loc + information so that it points to the instruction after the nop. */ + +void +ecoff_fix_loc (old_frag, old_frag_offset) + fragS *old_frag; + unsigned long old_frag_offset; +{ + if (last_lineno != NULL + && last_lineno->frag == old_frag + && last_lineno->paddr == old_frag_offset) + { + last_lineno->frag = frag_now; + last_lineno->paddr = frag_now_fix (); + } +} + +/* Make sure the @stabs symbol is emitted. */ + +static void +mark_stabs (ignore) + int ignore; +{ + if (! stabs_seen) + { + /* Add a dummy @stabs dymbol. */ + stabs_seen = 1; + (void) add_ecoff_symbol (stabs_symbol, stNil, scInfo, + (symbolS *) NULL, + (bfd_vma) 0, (symint_t) -1, + ECOFF_MARK_STAB (0)); + } +} + +/* Parse .weakext directives. */ + +void +ecoff_directive_weakext (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolP; + expressionS exp; + + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + + if (*input_line_pointer == ',') + { + if (S_IS_DEFINED (symbolP)) + { + as_bad ("Ignoring attempt to redefine symbol `%s'.", + S_GET_NAME (symbolP)); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + SKIP_WHITESPACE (); + if (! is_end_of_line[(unsigned char) *input_line_pointer]) + { + expression (&exp); + if (exp.X_op != O_symbol) + { + as_bad ("bad .weakext directive"); + ignore_rest_of_line(); + return; + } + symbolP->sy_value = exp; + } + } + + S_SET_WEAK (symbolP); + + demand_empty_rest_of_line (); +} + +/* Handle .stabs directives. The actual parsing routine is done by a + generic routine. This routine is called via OBJ_PROCESS_STAB. + When this is called, input_line_pointer will be pointing at the + value field of the stab. + + .stabs directives have five fields: + "string" a string, encoding the type information. + code a numeric code, defined in <stab.h> + 0 a zero + desc a zero or line number + value a numeric value or an address. + + If the value is relocatable, we transform this into: + iss points as an index into string space + value value from lookup of the name + st st from lookup of the name + sc sc from lookup of the name + index code|CODE_MASK + + If the value is not relocatable, we transform this into: + iss points as an index into string space + value value + st st_Nil + sc sc_Nil + index code|CODE_MASK + + .stabn directives have four fields (string is null): + code a numeric code, defined in <stab.h> + 0 a zero + desc a zero or a line number + value a numeric value or an address. */ + +void +ecoff_stab (sec, what, string, type, other, desc) + segT sec; + int what; + const char *string; + int type; + int other; + int desc; +{ + efdr_t *save_file_ptr = cur_file_ptr; + symbolS *sym; + symint_t value; + bfd_vma addend; + st_t st; + sc_t sc; + symint_t indx; + localsym_t *hold = NULL; + + ecoff_debugging_seen = 1; + + /* We don't handle .stabd. */ + if (what != 's' && what != 'n') + { + as_bad (".stab%c is not supported", what); + return; + } + + /* A .stabn uses a null name, not an empty string. */ + if (what == 'n') + string = NULL; + + /* We ignore the other field. */ + if (other != 0) + as_warn (".stab%c: ignoring non-zero other field", what); + + /* Make sure we have a current file. */ + if (cur_file_ptr == (efdr_t *) NULL) + { + add_file ((const char *) NULL, 0, 1); + save_file_ptr = cur_file_ptr; + } + + /* For stabs in ECOFF, the first symbol must be @stabs. This is a + signal to gdb. */ + if (stabs_seen == 0) + mark_stabs (0); + + /* Line number stabs are handled differently, since they have two + values, the line number and the address of the label. We use the + index field (aka desc) to hold the line number, and the value + field to hold the address. The symbol type is st_Label, which + should be different from the other stabs, so that gdb can + recognize it. */ + if (type == N_SLINE) + { + SYMR dummy_symr; + char *name; + char name_end; + +#ifndef NO_LISTING + if (listing) + listing_source_line ((unsigned int) desc); +#endif + + dummy_symr.index = desc; + if (dummy_symr.index != desc) + { + as_warn ("Line number (%d) for .stab%c directive cannot fit in index field (20 bits)", + desc, what); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + sym = symbol_find_or_make (name); + *input_line_pointer = name_end; + + value = 0; + addend = 0; + st = st_Label; + sc = sc_Text; + indx = desc; + } + else + { +#ifndef NO_LISTING + if (listing && (type == N_SO || type == N_SOL)) + listing_source_file (string); +#endif + + if (isdigit (*input_line_pointer) + || *input_line_pointer == '-' + || *input_line_pointer == '+') + { + st = st_Nil; + sc = sc_Nil; + sym = (symbolS *) NULL; + value = get_absolute_expression (); + addend = 0; + } + else if (! is_name_beginner ((unsigned char) *input_line_pointer)) + { + as_warn ("Illegal .stab%c directive, bad character", what); + return; + } + else + { + expressionS exp; + + sc = sc_Nil; + st = st_Nil; + + expression (&exp); + if (exp.X_op == O_constant) + { + sym = NULL; + value = exp.X_add_number; + addend = 0; + } + else if (exp.X_op == O_symbol) + { + sym = exp.X_add_symbol; + value = 0; + addend = exp.X_add_number; + } + else + { + sym = make_expr_symbol (&exp); + value = 0; + addend = 0; + } + } + + indx = ECOFF_MARK_STAB (type); + } + + /* Don't store the stabs symbol we are creating as the type of the + ECOFF symbol. We want to compute the type of the ECOFF symbol + independently. */ + if (sym != (symbolS *) NULL) + hold = sym->ecoff_symbol; + + (void) add_ecoff_symbol (string, st, sc, sym, addend, value, indx); + + if (sym != (symbolS *) NULL) + sym->ecoff_symbol = hold; + + /* Restore normal file type. */ + cur_file_ptr = save_file_ptr; +} + +/* Frob an ECOFF symbol. Small common symbols go into a special + .scommon section rather than bfd_com_section. */ + +void +ecoff_frob_symbol (sym) + symbolS *sym; +{ + if (S_IS_COMMON (sym) + && S_GET_VALUE (sym) > 0 + && S_GET_VALUE (sym) <= bfd_get_gp_size (stdoutput)) + { + static asection scom_section; + static asymbol scom_symbol; + + /* We must construct a fake section similar to bfd_com_section + but with the name .scommon. */ + if (scom_section.name == NULL) + { + scom_section = bfd_com_section; + scom_section.name = ".scommon"; + scom_section.output_section = &scom_section; + scom_section.symbol = &scom_symbol; + scom_section.symbol_ptr_ptr = &scom_section.symbol; + scom_symbol = *bfd_com_section.symbol; + scom_symbol.name = ".scommon"; + scom_symbol.section = &scom_section; + } + S_SET_SEGMENT (sym, &scom_section); + } + + /* Double check weak symbols. */ + if (sym->bsym->flags & BSF_WEAK) + { + if (S_IS_COMMON (sym)) + as_bad ("Symbol `%s' can not be both weak and common", + S_GET_NAME (sym)); + } +} + +/* Add bytes to the symbolic information buffer. */ + +static char * +ecoff_add_bytes (buf, bufend, bufptr, need) + char **buf; + char **bufend; + char *bufptr; + unsigned long need; +{ + unsigned long at; + unsigned long want; + + at = bufptr - *buf; + need -= *bufend - bufptr; + if (need < PAGE_SIZE) + need = PAGE_SIZE; + want = (*bufend - *buf) + need; + *buf = xrealloc (*buf, want); + *bufend = *buf + want; + return *buf + at; +} + +/* Adjust the symbolic information buffer to the alignment required + for the ECOFF target debugging information. */ + +static unsigned long +ecoff_padding_adjust (backend, buf, bufend, offset, bufptrptr) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; + char **bufptrptr; +{ + bfd_size_type align; + + align = backend->debug_align; + if ((offset & (align - 1)) != 0) + { + unsigned long add; + + add = align - (offset & (align - 1)); + if (*bufend - (*buf + offset) < add) + (void) ecoff_add_bytes (buf, bufend, *buf + offset, add); + memset (*buf + offset, 0, add); + offset += add; + if (bufptrptr != (char **) NULL) + *bufptrptr = *buf + offset; + } + + return offset; +} + +/* Build the line number information. */ + +static unsigned long +ecoff_build_lineno (backend, buf, bufend, offset, linecntptr) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; + long *linecntptr; +{ + char *bufptr; + register lineno_list_t *l; + lineno_list_t *last; + efdr_t *file; + proc_t *proc; + unsigned long c; + long iline; + long totcount; + lineno_list_t first; + + if (linecntptr != (long *) NULL) + *linecntptr = 0; + + bufptr = *buf + offset; + + file = (efdr_t *) NULL; + proc = (proc_t *) NULL; + last = (lineno_list_t *) NULL; + c = offset; + iline = 0; + totcount = 0; + + /* For some reason the address of the first procedure is ignored + when reading line numbers. This doesn't matter if the address of + the first procedure is 0, but when gcc is generating MIPS + embedded PIC code, it will put strings in the .text section + before the first procedure. We cope by inserting a dummy line if + the address of the first procedure is not 0. Hopefully this + won't screw things up too badly. */ + if (first_proc_ptr != (proc_t *) NULL + && first_lineno != (lineno_list_t *) NULL + && ((S_GET_VALUE (first_proc_ptr->sym->as_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (first_proc_ptr->sym->as_sym))) + != 0)) + { + first.file = first_lineno->file; + first.proc = first_lineno->proc; + first.frag = &zero_address_frag; + first.paddr = 0; + first.lineno = 0; + + first.next = first_lineno; + first_lineno = &first; + } + + for (l = first_lineno; l != (lineno_list_t *) NULL; l = l->next) + { + long count; + long delta; + + /* Get the offset to the memory address of the next line number + (in words). Do this first, so that we can skip ahead to the + next useful line number entry. */ + if (l->next == (lineno_list_t *) NULL) + { + /* We want a count of zero, but it will be decremented + before it is used. */ + count = 1; + } + else if (l->next->frag->fr_address + l->next->paddr + > l->frag->fr_address + l->paddr) + { + count = ((l->next->frag->fr_address + l->next->paddr + - (l->frag->fr_address + l->paddr)) + >> 2); + } + else + { + /* Don't change last, so we still get the right delta. */ + continue; + } + + if (l->file != file || l->proc != proc) + { + if (l->proc != proc && proc != (proc_t *) NULL) + proc->pdr.lnHigh = last->lineno; + if (l->file != file && file != (efdr_t *) NULL) + { + file->fdr.cbLine = c - file->fdr.cbLineOffset; + file->fdr.cline = totcount + count; + if (linecntptr != (long *) NULL) + *linecntptr += totcount + count; + totcount = 0; + } + + if (l->file != file) + { + efdr_t *last_file = file; + + file = l->file; + if (last_file != (efdr_t *) NULL) + file->fdr.ilineBase + = last_file->fdr.ilineBase + last_file->fdr.cline; + else + file->fdr.ilineBase = 0; + file->fdr.cbLineOffset = c; + } + if (l->proc != proc) + { + proc = l->proc; + if (proc != (proc_t *) NULL) + { + proc->pdr.lnLow = l->lineno; + proc->pdr.cbLineOffset = c - file->fdr.cbLineOffset; + proc->pdr.iline = totcount; + } + } + + last = (lineno_list_t *) NULL; + } + + totcount += count; + + /* Get the offset to this line number. */ + if (last == (lineno_list_t *) NULL) + delta = 0; + else + delta = l->lineno - last->lineno; + + /* Put in the offset to this line number. */ + while (delta != 0) + { + int setcount; + + /* 1 is added to each count read. */ + --count; + /* We can only adjust the word count by up to 15 words at a + time. */ + if (count <= 0x0f) + { + setcount = count; + count = 0; + } + else + { + setcount = 0x0f; + count -= 0x0f; + } + if (delta >= -7 && delta <= 7) + { + if (bufptr >= *bufend) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); + *bufptr++ = setcount + (delta << 4); + delta = 0; + ++c; + } + else + { + int set; + + if (*bufend - bufptr < 3) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 3); + *bufptr++ = setcount + (8 << 4); + if (delta < -0x8000) + { + set = -0x8000; + delta += 0x8000; + } + else if (delta > 0x7fff) + { + set = 0x7fff; + delta -= 0x7fff; + } + else + { + set = delta; + delta = 0; + } + *bufptr++ = set >> 8; + *bufptr++ = set & 0xffff; + c += 3; + } + } + + /* Finish adjusting the count. */ + while (count > 0) + { + if (bufptr >= *bufend) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); + /* 1 is added to each count read. */ + --count; + if (count > 0x0f) + { + *bufptr++ = 0x0f; + count -= 0x0f; + } + else + { + *bufptr++ = count; + count = 0; + } + ++c; + } + + ++iline; + last = l; + } + + if (proc != (proc_t *) NULL) + proc->pdr.lnHigh = last->lineno; + if (file != (efdr_t *) NULL) + { + file->fdr.cbLine = c - file->fdr.cbLineOffset; + file->fdr.cline = totcount; + } + + if (linecntptr != (long *) NULL) + *linecntptr += totcount; + + c = ecoff_padding_adjust (backend, buf, bufend, c, &bufptr); + + return c; +} + +/* Build and swap out the symbols. */ + +static unsigned long +ecoff_build_symbols (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_sym_size = backend->external_sym_size; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = backend->swap_sym_out; + char *sym_out; + long isym; + vlinks_t *file_link; + + sym_out = *buf + offset; + + isym = 0; + + /* The symbols are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int ifilesym; + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *sym_link; + + fil_ptr->fdr.isymBase = isym; + ifilesym = isym; + for (sym_link = fil_ptr->symbols.first; + sym_link != (vlinks_t *) NULL; + sym_link = sym_link->next) + { + int sym_cnt; + localsym_t *sym_ptr; + localsym_t *sym_end; + + if (sym_link->next == (vlinks_t *) NULL) + sym_cnt = fil_ptr->symbols.objects_last_page; + else + sym_cnt = fil_ptr->symbols.objects_per_page; + sym_ptr = sym_link->datum->sym; + sym_end = sym_ptr + sym_cnt; + for (; sym_ptr < sym_end; sym_ptr++) + { + int local; + symbolS *as_sym; + forward_t *f; + + know (sym_ptr->file_ptr == fil_ptr); + + /* If there is no associated gas symbol, then this + is a pure debugging symbol. We have already + added the name (if any) to fil_ptr->strings. + Otherwise we must decide whether this is an + external or a local symbol (actually, it may be + both if the local provides additional debugging + information for the external). */ + local = 1; + as_sym = sym_ptr->as_sym; + if (as_sym != (symbolS *) NULL) + { + symint_t indx; + + /* The value of a block start symbol is the + offset from the start of the procedure. For + other symbols we just use the gas value (but + we must offset it by the vma of the section, + just as BFD does, because BFD will not see + this value). */ + if (sym_ptr->ecoff_sym.asym.st == (int) st_Block + && sym_ptr->ecoff_sym.asym.sc == (int) sc_Text) + { + symbolS *begin_sym; + + know (sym_ptr->proc_ptr != (proc_t *) NULL); + begin_sym = sym_ptr->proc_ptr->sym->as_sym; + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_sym)) + as_warn (".begin/.bend in different segments"); + sym_ptr->ecoff_sym.asym.value = + S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); + } + else + sym_ptr->ecoff_sym.asym.value = + (S_GET_VALUE (as_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (as_sym)) + + sym_ptr->addend); + + sym_ptr->ecoff_sym.weakext = S_IS_WEAK (as_sym); + + /* Set st_Proc to st_StaticProc for local + functions. */ + if (sym_ptr->ecoff_sym.asym.st == st_Proc + && S_IS_DEFINED (as_sym) + && ! S_IS_EXTERNAL (as_sym) + && ! S_IS_WEAK (as_sym)) + sym_ptr->ecoff_sym.asym.st = st_StaticProc; + + /* Get the type and storage class based on where + the symbol actually wound up. Traditionally, + N_LBRAC and N_RBRAC are *not* relocated. */ + indx = sym_ptr->ecoff_sym.asym.index; + if (sym_ptr->ecoff_sym.asym.st == st_Nil + && sym_ptr->ecoff_sym.asym.sc == sc_Nil + && (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) + || ((ECOFF_UNMARK_STAB (indx) != N_LBRAC) + && (ECOFF_UNMARK_STAB (indx) != N_RBRAC)))) + { + segT seg; + const char *segname; + st_t st; + sc_t sc; + + seg = S_GET_SEGMENT (as_sym); + segname = segment_name (seg); + + if (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) + && (S_IS_EXTERNAL (as_sym) + || S_IS_WEAK (as_sym) + || ! S_IS_DEFINED (as_sym))) + { + if ((as_sym->bsym->flags & BSF_FUNCTION) != 0) + st = st_Proc; + else + st = st_Global; + } + else if (seg == text_section) + st = st_Label; + else + st = st_Static; + + if (! S_IS_DEFINED (as_sym)) + { + if (as_sym->ecoff_extern_size == 0 + || (as_sym->ecoff_extern_size + > bfd_get_gp_size (stdoutput))) + sc = sc_Undefined; + else + { + sc = sc_SUndefined; + sym_ptr->ecoff_sym.asym.value = + as_sym->ecoff_extern_size; + } +#ifdef S_SET_SIZE + S_SET_SIZE (as_sym, as_sym->ecoff_extern_size); +#endif + } + else if (S_IS_COMMON (as_sym)) + { + if (S_GET_VALUE (as_sym) > 0 + && (S_GET_VALUE (as_sym) + <= bfd_get_gp_size (stdoutput))) + sc = sc_SCommon; + else + sc = sc_Common; + } + else if (seg == text_section) + sc = sc_Text; + else if (seg == data_section) + sc = sc_Data; + else if (strcmp (segname, ".rdata") == 0 + || strcmp (segname, ".rodata") == 0) + sc = sc_RData; + else if (strcmp (segname, ".sdata") == 0) + sc = sc_SData; + else if (seg == bss_section) + sc = sc_Bss; + else if (strcmp (segname, ".sbss") == 0) + sc = sc_SBss; + else if (seg == &bfd_abs_section) + sc = sc_Abs; + else + { + /* This must be a user named section. + This is not possible in ECOFF, but it + is in ELF. */ + sc = sc_Data; + } + + sym_ptr->ecoff_sym.asym.st = (int) st; + sym_ptr->ecoff_sym.asym.sc = (int) sc; + } + + /* This is just an external symbol if it is + outside a procedure and it has a type. + FIXME: g++ will generate symbols which have + different names in the debugging information + than the actual symbol. Should we handle + them here? */ + if ((S_IS_EXTERNAL (as_sym) + || S_IS_WEAK (as_sym) + || ! S_IS_DEFINED (as_sym)) + && sym_ptr->proc_ptr == (proc_t *) NULL + && sym_ptr->ecoff_sym.asym.st != (int) st_Nil + && ! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym)) + local = 0; + + /* This is just an external symbol if it is a + common symbol. */ + if (S_IS_COMMON (as_sym)) + local = 0; + + /* If an st_end symbol has an associated gas + symbol, then it is a local label created for + a .bend or .end directive. Stabs line + numbers will have \001 in the names. */ + if (local + && sym_ptr->ecoff_sym.asym.st != st_End + && strchr (sym_ptr->name, '\001') == 0) + sym_ptr->ecoff_sym.asym.iss = + add_string (&fil_ptr->strings, + fil_ptr->str_hash, + sym_ptr->name, + (shash_t **) NULL); + } + + /* We now know the index of this symbol; fill in + locations that have been waiting for that + information. */ + if (sym_ptr->begin_ptr != (localsym_t *) NULL) + { + localsym_t *begin_ptr; + st_t begin_type; + + know (local); + begin_ptr = sym_ptr->begin_ptr; + know (begin_ptr->sym_index != -1); + sym_ptr->ecoff_sym.asym.index = begin_ptr->sym_index; + if (sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) + sym_ptr->ecoff_sym.asym.iss = + begin_ptr->ecoff_sym.asym.iss; + + begin_type = begin_ptr->ecoff_sym.asym.st; + if (begin_type == st_File + || begin_type == st_Block) + { + begin_ptr->ecoff_sym.asym.index = + isym - ifilesym + 1; + (*swap_sym_out) (stdoutput, + &begin_ptr->ecoff_sym.asym, + (*buf + + offset + + (begin_ptr->sym_index + * external_sym_size))); + } + else + { + know (begin_ptr->index_ptr != (aux_t *) NULL); + begin_ptr->index_ptr->data.isym = + isym - ifilesym + 1; + } + + /* The value of the symbol marking the end of a + procedure is the size of the procedure. The + value of the symbol marking the end of a + block is the offset from the start of the + procedure to the block. */ + if (begin_type == st_Proc + || begin_type == st_StaticProc) + { + know (as_sym != (symbolS *) NULL); + know (begin_ptr->as_sym != (symbolS *) NULL); + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_ptr->as_sym)) + as_warn (".begin/.bend in different segments"); + sym_ptr->ecoff_sym.asym.value = + (S_GET_VALUE (as_sym) + - S_GET_VALUE (begin_ptr->as_sym)); + + /* If the size is odd, this is probably a + mips16 function; force it to be even. */ + if ((sym_ptr->ecoff_sym.asym.value & 1) != 0) + ++sym_ptr->ecoff_sym.asym.value; + +#ifdef S_SET_SIZE + S_SET_SIZE (begin_ptr->as_sym, + sym_ptr->ecoff_sym.asym.value); +#endif + } + else if (begin_type == st_Block + && sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) + { + symbolS *begin_sym; + + know (as_sym != (symbolS *) NULL); + know (sym_ptr->proc_ptr != (proc_t *) NULL); + begin_sym = sym_ptr->proc_ptr->sym->as_sym; + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_sym)) + as_warn (".begin/.bend in different segments"); + sym_ptr->ecoff_sym.asym.value = + S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); + } + } + + for (f = sym_ptr->forward_ref; + f != (forward_t *) NULL; + f = f->next) + { + know (local); + f->ifd_ptr->data.isym = fil_ptr->file_index; + f->index_ptr->data.rndx.index = isym - ifilesym; + } + + if (local) + { + if (*bufend - sym_out < external_sym_size) + sym_out = ecoff_add_bytes (buf, bufend, + sym_out, + external_sym_size); + (*swap_sym_out) (stdoutput, &sym_ptr->ecoff_sym.asym, + sym_out); + sym_out += external_sym_size; + + sym_ptr->sym_index = isym; + + if (sym_ptr->proc_ptr != (proc_t *) NULL + && sym_ptr->proc_ptr->sym == sym_ptr) + sym_ptr->proc_ptr->pdr.isym = isym - ifilesym; + + ++isym; + } + + /* Record the local symbol index and file number in + case this is an external symbol. Note that this + destroys the asym.index field. */ + if (as_sym != (symbolS *) NULL + && as_sym->ecoff_symbol == sym_ptr) + { + if ((sym_ptr->ecoff_sym.asym.st == st_Proc + || sym_ptr->ecoff_sym.asym.st == st_StaticProc) + && local) + sym_ptr->ecoff_sym.asym.index = isym - ifilesym - 1; + sym_ptr->ecoff_sym.ifd = fil_ptr->file_index; + } + } + } + fil_ptr->fdr.csym = isym - fil_ptr->fdr.isymBase; + } + } + + return offset + isym * external_sym_size; +} + +/* Swap out the procedure information. */ + +static unsigned long +ecoff_build_procs (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_pdr_size = backend->external_pdr_size; + void (* const swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)) + = backend->swap_pdr_out; + char *pdr_out; + long iproc; + vlinks_t *file_link; + + pdr_out = *buf + offset; + + iproc = 0; + + /* The procedures are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *proc_link; + int first; + + fil_ptr->fdr.ipdFirst = iproc; + first = 1; + for (proc_link = fil_ptr->procs.first; + proc_link != (vlinks_t *) NULL; + proc_link = proc_link->next) + { + int prc_cnt; + proc_t *proc_ptr; + proc_t *proc_end; + + if (proc_link->next == (vlinks_t *) NULL) + prc_cnt = fil_ptr->procs.objects_last_page; + else + prc_cnt = fil_ptr->procs.objects_per_page; + proc_ptr = proc_link->datum->proc; + proc_end = proc_ptr + prc_cnt; + for (; proc_ptr < proc_end; proc_ptr++) + { + symbolS *adr_sym; + unsigned long adr; + + adr_sym = proc_ptr->sym->as_sym; + adr = (S_GET_VALUE (adr_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (adr_sym))); + if (first) + { + /* This code used to force the adr of the very + first fdr to be 0. However, the native tools + don't do that, and I can't remember why it + used to work that way, so I took it out. */ + fil_ptr->fdr.adr = adr; + first = 0; + } + proc_ptr->pdr.adr = adr - fil_ptr->fdr.adr; + if (*bufend - pdr_out < external_pdr_size) + pdr_out = ecoff_add_bytes (buf, bufend, + pdr_out, + external_pdr_size); + (*swap_pdr_out) (stdoutput, &proc_ptr->pdr, pdr_out); + pdr_out += external_pdr_size; + ++iproc; + } + } + fil_ptr->fdr.cpd = iproc - fil_ptr->fdr.ipdFirst; + } + } + + return offset + iproc * external_pdr_size; +} + +/* Swap out the aux information. */ + +static unsigned long +ecoff_build_aux (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + int bigendian; + union aux_ext *aux_out; + long iaux; + vlinks_t *file_link; + + bigendian = bfd_big_endian (stdoutput); + + aux_out = (union aux_ext *) (*buf + offset); + + iaux = 0; + + /* The aux entries are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *aux_link; + + fil_ptr->fdr.fBigendian = bigendian; + fil_ptr->fdr.iauxBase = iaux; + for (aux_link = fil_ptr->aux_syms.first; + aux_link != (vlinks_t *) NULL; + aux_link = aux_link->next) + { + int aux_cnt; + aux_t *aux_ptr; + aux_t *aux_end; + + if (aux_link->next == (vlinks_t *) NULL) + aux_cnt = fil_ptr->aux_syms.objects_last_page; + else + aux_cnt = fil_ptr->aux_syms.objects_per_page; + aux_ptr = aux_link->datum->aux; + aux_end = aux_ptr + aux_cnt; + for (; aux_ptr < aux_end; aux_ptr++) + { + if (*bufend - (char *) aux_out < sizeof (union aux_ext)) + aux_out = ((union aux_ext *) + ecoff_add_bytes (buf, bufend, + (char *) aux_out, + sizeof (union aux_ext))); + switch (aux_ptr->type) + { + case aux_tir: + (*backend->swap_tir_out) (bigendian, + &aux_ptr->data.ti, + &aux_out->a_ti); + break; + case aux_rndx: + (*backend->swap_rndx_out) (bigendian, + &aux_ptr->data.rndx, + &aux_out->a_rndx); + break; + case aux_dnLow: + AUX_PUT_DNLOW (bigendian, aux_ptr->data.dnLow, + aux_out); + break; + case aux_dnHigh: + AUX_PUT_DNHIGH (bigendian, aux_ptr->data.dnHigh, + aux_out); + break; + case aux_isym: + AUX_PUT_ISYM (bigendian, aux_ptr->data.isym, + aux_out); + break; + case aux_iss: + AUX_PUT_ISS (bigendian, aux_ptr->data.iss, + aux_out); + break; + case aux_width: + AUX_PUT_WIDTH (bigendian, aux_ptr->data.width, + aux_out); + break; + case aux_count: + AUX_PUT_COUNT (bigendian, aux_ptr->data.count, + aux_out); + break; + } + + ++aux_out; + ++iaux; + } + } + fil_ptr->fdr.caux = iaux - fil_ptr->fdr.iauxBase; + } + } + + return ecoff_padding_adjust (backend, buf, bufend, + offset + iaux * sizeof (union aux_ext), + (char **) NULL); +} + +/* Copy out the strings from a varray_t. This returns the number of + bytes copied, rather than the new offset. */ + +static unsigned long +ecoff_build_strings (buf, bufend, offset, vp) + char **buf; + char **bufend; + unsigned long offset; + varray_t *vp; +{ + unsigned long istr; + char *str_out; + vlinks_t *str_link; + + str_out = *buf + offset; + + istr = 0; + + for (str_link = vp->first; + str_link != (vlinks_t *) NULL; + str_link = str_link->next) + { + unsigned long str_cnt; + + if (str_link->next == (vlinks_t *) NULL) + str_cnt = vp->objects_last_page; + else + str_cnt = vp->objects_per_page; + + if (*bufend - str_out < str_cnt) + str_out = ecoff_add_bytes (buf, bufend, str_out, str_cnt); + + memcpy (str_out, str_link->datum->byte, str_cnt); + str_out += str_cnt; + istr += str_cnt; + } + + return istr; +} + +/* Dump out the local strings. */ + +static unsigned long +ecoff_build_ss (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + long iss; + vlinks_t *file_link; + + iss = 0; + + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + long ss_cnt; + + fil_ptr->fdr.issBase = iss; + ss_cnt = ecoff_build_strings (buf, bufend, offset + iss, + &fil_ptr->strings); + fil_ptr->fdr.cbSs = ss_cnt; + iss += ss_cnt; + } + } + + return ecoff_padding_adjust (backend, buf, bufend, offset + iss, + (char **) NULL); +} + +/* Swap out the file descriptors. */ + +static unsigned long +ecoff_build_fdr (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_fdr_size = backend->external_fdr_size; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = backend->swap_fdr_out; + long ifile; + char *fdr_out; + vlinks_t *file_link; + + ifile = 0; + + fdr_out = *buf + offset; + + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + if (*bufend - fdr_out < external_fdr_size) + fdr_out = ecoff_add_bytes (buf, bufend, fdr_out, + external_fdr_size); + (*swap_fdr_out) (stdoutput, &fil_ptr->fdr, fdr_out); + fdr_out += external_fdr_size; + ++ifile; + } + } + + return offset + ifile * external_fdr_size; +} + +/* Set up the external symbols. These are supposed to be handled by + the backend. This routine just gets the right information and + calls a backend function to deal with it. */ + +static void +ecoff_setup_ext () +{ + register symbolS *sym; + + for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) + { + if (sym->ecoff_symbol == NULL) + continue; + + /* If this is a local symbol, then force the fields to zero. */ + if (! S_IS_EXTERNAL (sym) + && ! S_IS_WEAK (sym) + && S_IS_DEFINED (sym)) + { + sym->ecoff_symbol->ecoff_sym.asym.value = 0; + sym->ecoff_symbol->ecoff_sym.asym.st = (int) st_Nil; + sym->ecoff_symbol->ecoff_sym.asym.sc = (int) sc_Nil; + sym->ecoff_symbol->ecoff_sym.asym.index = indexNil; + } + + obj_ecoff_set_ext (sym, &sym->ecoff_symbol->ecoff_sym); + } +} + +/* Build the ECOFF debugging information. */ + +unsigned long +ecoff_build_debug (hdr, bufp, backend) + HDRR *hdr; + char **bufp; + const struct ecoff_debug_swap *backend; +{ + const bfd_size_type external_pdr_size = backend->external_pdr_size; + tag_t *ptag; + tag_t *ptag_next; + efdr_t *fil_ptr; + int end_warning; + efdr_t *hold_file_ptr; + proc_t * hold_proc_ptr; + symbolS *sym; + char *buf; + char *bufend; + unsigned long offset; + + /* Make sure we have a file. */ + if (first_file == (efdr_t *) NULL) + add_file ((const char *) NULL, 0, 1); + + /* Handle any top level tags. */ + for (ptag = top_tag_head->first_tag; + ptag != (tag_t *) NULL; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *) NULL) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_tag (ptag); + } + + free_thead (top_tag_head); + + /* Look through the symbols. Add debugging information for each + symbol that has not already received it. */ + hold_file_ptr = cur_file_ptr; + hold_proc_ptr = cur_proc_ptr; + cur_proc_ptr = (proc_t *) NULL; + for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) + { + if (sym->ecoff_symbol != NULL + || sym->ecoff_file == (efdr_t *) NULL + || (sym->bsym->flags & BSF_SECTION_SYM) != 0) + continue; + + cur_file_ptr = sym->ecoff_file; + add_ecoff_symbol ((const char *) NULL, st_Nil, sc_Nil, sym, + (bfd_vma) 0, S_GET_VALUE (sym), indexNil); + } + cur_proc_ptr = hold_proc_ptr; + cur_file_ptr = hold_file_ptr; + + /* Output an ending symbol for all the files. We have to do this + here for the last file, so we may as well do it for all of the + files. */ + end_warning = 0; + for (fil_ptr = first_file; + fil_ptr != (efdr_t *) NULL; + fil_ptr = fil_ptr->next_file) + { + cur_file_ptr = fil_ptr; + while (cur_file_ptr->cur_scope != (scope_t *) NULL + && cur_file_ptr->cur_scope->prev != (scope_t *) NULL) + { + cur_file_ptr->cur_scope = cur_file_ptr->cur_scope->prev; + if (! end_warning && ! cur_file_ptr->fake) + { + as_warn ("Missing .end or .bend at end of file"); + end_warning = 1; + } + } + if (cur_file_ptr->cur_scope != (scope_t *) NULL) + (void) add_ecoff_symbol ((const char *) NULL, + st_End, sc_Text, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + } + + /* Build the symbolic information. */ + offset = 0; + buf = xmalloc (PAGE_SIZE); + bufend = buf + PAGE_SIZE; + + /* Build the line number information. */ + hdr->cbLineOffset = offset; + offset = ecoff_build_lineno (backend, &buf, &bufend, offset, + &hdr->ilineMax); + hdr->cbLine = offset - hdr->cbLineOffset; + + /* We don't use dense numbers at all. */ + hdr->idnMax = 0; + hdr->cbDnOffset = 0; + + /* We can't build the PDR table until we have built the symbols, + because a PDR contains a symbol index. However, we set aside + space at this point. */ + hdr->ipdMax = proc_cnt; + hdr->cbPdOffset = offset; + if (bufend - (buf + offset) < proc_cnt * external_pdr_size) + (void) ecoff_add_bytes (&buf, &bufend, buf + offset, + proc_cnt * external_pdr_size); + offset += proc_cnt * external_pdr_size; + + /* Build the local symbols. */ + hdr->cbSymOffset = offset; + offset = ecoff_build_symbols (backend, &buf, &bufend, offset); + hdr->isymMax = (offset - hdr->cbSymOffset) / backend->external_sym_size; + + /* Building the symbols initializes the symbol index in the PDR's. + Now we can swap out the PDR's. */ + (void) ecoff_build_procs (backend, &buf, &bufend, hdr->cbPdOffset); + + /* We don't use optimization symbols. */ + hdr->ioptMax = 0; + hdr->cbOptOffset = 0; + + /* Swap out the auxiliary type information. */ + hdr->cbAuxOffset = offset; + offset = ecoff_build_aux (backend, &buf, &bufend, offset); + hdr->iauxMax = (offset - hdr->cbAuxOffset) / sizeof (union aux_ext); + + /* Copy out the local strings. */ + hdr->cbSsOffset = offset; + offset = ecoff_build_ss (backend, &buf, &bufend, offset); + hdr->issMax = offset - hdr->cbSsOffset; + + /* We don't use relative file descriptors. */ + hdr->crfd = 0; + hdr->cbRfdOffset = 0; + + /* Swap out the file descriptors. */ + hdr->cbFdOffset = offset; + offset = ecoff_build_fdr (backend, &buf, &bufend, offset); + hdr->ifdMax = (offset - hdr->cbFdOffset) / backend->external_fdr_size; + + /* Set up the external symbols, which are handled by the BFD back + end. */ + hdr->issExtMax = 0; + hdr->cbSsExtOffset = 0; + hdr->iextMax = 0; + hdr->cbExtOffset = 0; + ecoff_setup_ext (); + + know ((offset & (backend->debug_align - 1)) == 0); + + /* FIXME: This value should be determined from the .verstamp directive, + with reasonable defaults in config files. */ +#ifdef TC_ALPHA + hdr->vstamp = 0x030b; +#else + hdr->vstamp = 0x020b; +#endif + + *bufp = buf; + return offset; +} + +/* Allocate a cluster of pages. */ + +#ifndef MALLOC_CHECK + +static page_t * +allocate_cluster (npages) + unsigned long npages; +{ + register page_t *value = (page_t *) xmalloc (npages * PAGE_USIZE); + +#ifdef ECOFF_DEBUG + if (debug > 3) + fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, value); +#endif + + memset (value, 0, npages * PAGE_USIZE); + + return value; +} + + +static page_t *cluster_ptr = NULL; +static unsigned long pages_left = 0; + +#endif /* MALLOC_CHECK */ + +/* Allocate one page (which is initialized to 0). */ + +static page_t * +allocate_page () +{ +#ifndef MALLOC_CHECK + + if (pages_left == 0) + { + pages_left = MAX_CLUSTER_PAGES; + cluster_ptr = allocate_cluster (pages_left); + } + + pages_left--; + return cluster_ptr++; + +#else /* MALLOC_CHECK */ + + page_t *ptr; + + ptr = xmalloc (PAGE_USIZE); + memset (ptr, 0, PAGE_USIZE); + return ptr; + +#endif /* MALLOC_CHECK */ +} + +/* Allocate scoping information. */ + +static scope_t * +allocate_scope () +{ + register scope_t *ptr; + static scope_t initial_scope; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int)alloc_type_scope].free_list.f_scope; + if (ptr != (scope_t *) NULL) + alloc_counts[ (int)alloc_type_scope ].free_list.f_scope = ptr->free; + else + { + register int unallocated = alloc_counts[(int)alloc_type_scope].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_scope].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (scope_t); + alloc_counts[(int)alloc_type_scope].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_scope].total_pages++; + } + + ptr = &cur_page->scope[--unallocated]; + alloc_counts[(int)alloc_type_scope].unallocated = unallocated; + } + +#else + + ptr = (scope_t *) xmalloc (sizeof (scope_t)); + +#endif + + alloc_counts[(int)alloc_type_scope].total_alloc++; + *ptr = initial_scope; + return ptr; +} + +/* Free scoping information. */ + +static void +free_scope (ptr) + scope_t *ptr; +{ + alloc_counts[(int)alloc_type_scope].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = alloc_counts[(int)alloc_type_scope].free_list.f_scope; + alloc_counts[(int)alloc_type_scope].free_list.f_scope = ptr; +#else + free ((PTR) ptr); +#endif +} + +/* Allocate links for pages in a virtual array. */ + +static vlinks_t * +allocate_vlinks () +{ + register vlinks_t *ptr; + static vlinks_t initial_vlinks; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int)alloc_type_vlinks].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_vlinks].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (vlinks_t); + alloc_counts[(int)alloc_type_vlinks].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_vlinks].total_pages++; + } + + ptr = &cur_page->vlinks[--unallocated]; + alloc_counts[(int)alloc_type_vlinks].unallocated = unallocated; + +#else + + ptr = (vlinks_t *) xmalloc (sizeof (vlinks_t)); + +#endif + + alloc_counts[(int)alloc_type_vlinks].total_alloc++; + *ptr = initial_vlinks; + return ptr; +} + +/* Allocate string hash buckets. */ + +static shash_t * +allocate_shash () +{ + register shash_t *ptr; + static shash_t initial_shash; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int)alloc_type_shash].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_shash].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (shash_t); + alloc_counts[(int)alloc_type_shash].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_shash].total_pages++; + } + + ptr = &cur_page->shash[--unallocated]; + alloc_counts[(int)alloc_type_shash].unallocated = unallocated; + +#else + + ptr = (shash_t *) xmalloc (sizeof (shash_t)); + +#endif + + alloc_counts[(int)alloc_type_shash].total_alloc++; + *ptr = initial_shash; + return ptr; +} + +/* Allocate type hash buckets. */ + +static thash_t * +allocate_thash () +{ + register thash_t *ptr; + static thash_t initial_thash; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int)alloc_type_thash].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_thash].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (thash_t); + alloc_counts[(int)alloc_type_thash].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_thash].total_pages++; + } + + ptr = &cur_page->thash[--unallocated]; + alloc_counts[(int)alloc_type_thash].unallocated = unallocated; + +#else + + ptr = (thash_t *) xmalloc (sizeof (thash_t)); + +#endif + + alloc_counts[(int)alloc_type_thash].total_alloc++; + *ptr = initial_thash; + return ptr; +} + +/* Allocate structure, union, or enum tag information. */ + +static tag_t * +allocate_tag () +{ + register tag_t *ptr; + static tag_t initial_tag; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int)alloc_type_tag].free_list.f_tag; + if (ptr != (tag_t *) NULL) + alloc_counts[(int)alloc_type_tag].free_list.f_tag = ptr->free; + else + { + register int unallocated = alloc_counts[(int)alloc_type_tag].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_tag].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (tag_t); + alloc_counts[(int)alloc_type_tag].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_tag].total_pages++; + } + + ptr = &cur_page->tag[--unallocated]; + alloc_counts[(int)alloc_type_tag].unallocated = unallocated; + } + +#else + + ptr = (tag_t *) xmalloc (sizeof (tag_t)); + +#endif + + alloc_counts[(int)alloc_type_tag].total_alloc++; + *ptr = initial_tag; + return ptr; +} + +/* Free scoping information. */ + +static void +free_tag (ptr) + tag_t *ptr; +{ + alloc_counts[(int)alloc_type_tag].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = alloc_counts[(int)alloc_type_tag].free_list.f_tag; + alloc_counts[(int)alloc_type_tag].free_list.f_tag = ptr; +#else + free ((PTR_T) ptr); +#endif +} + +/* Allocate forward reference to a yet unknown tag. */ + +static forward_t * +allocate_forward () +{ + register forward_t *ptr; + static forward_t initial_forward; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int)alloc_type_forward].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_forward].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (forward_t); + alloc_counts[(int)alloc_type_forward].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_forward].total_pages++; + } + + ptr = &cur_page->forward[--unallocated]; + alloc_counts[(int)alloc_type_forward].unallocated = unallocated; + +#else + + ptr = (forward_t *) xmalloc (sizeof (forward_t)); + +#endif + + alloc_counts[(int)alloc_type_forward].total_alloc++; + *ptr = initial_forward; + return ptr; +} + +/* Allocate head of type hash list. */ + +static thead_t * +allocate_thead () +{ + register thead_t *ptr; + static thead_t initial_thead; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int)alloc_type_thead].free_list.f_thead; + if (ptr != (thead_t *) NULL) + alloc_counts[ (int)alloc_type_thead ].free_list.f_thead = ptr->free; + else + { + register int unallocated = alloc_counts[(int)alloc_type_thead].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_thead].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (thead_t); + alloc_counts[(int)alloc_type_thead].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_thead].total_pages++; + } + + ptr = &cur_page->thead[--unallocated]; + alloc_counts[(int)alloc_type_thead].unallocated = unallocated; + } + +#else + + ptr = (thead_t *) xmalloc (sizeof (thead_t)); + +#endif + + alloc_counts[(int)alloc_type_thead].total_alloc++; + *ptr = initial_thead; + return ptr; +} + +/* Free scoping information. */ + +static void +free_thead (ptr) + thead_t *ptr; +{ + alloc_counts[(int)alloc_type_thead].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = (thead_t *) alloc_counts[(int)alloc_type_thead].free_list.f_thead; + alloc_counts[(int)alloc_type_thead].free_list.f_thead = ptr; +#else + free ((PTR_T) ptr); +#endif +} + +static lineno_list_t * +allocate_lineno_list () +{ + register lineno_list_t *ptr; + static lineno_list_t initial_lineno_list; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int)alloc_type_lineno].unallocated; + register page_t *cur_page = alloc_counts[(int)alloc_type_lineno].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (lineno_list_t); + alloc_counts[(int)alloc_type_lineno].cur_page = cur_page = allocate_page (); + alloc_counts[(int)alloc_type_lineno].total_pages++; + } + + ptr = &cur_page->lineno[--unallocated]; + alloc_counts[(int)alloc_type_lineno].unallocated = unallocated; + +#else + + ptr = (lineno_list_t *) xmalloc (sizeof (lineno_list_t)); + +#endif + + alloc_counts[(int)alloc_type_lineno].total_alloc++; + *ptr = initial_lineno_list; + return ptr; +} + +void +ecoff_set_gp_prolog_size (sz) + int sz; +{ + if (cur_proc_ptr == 0) + return; + + cur_proc_ptr->pdr.gp_prologue = sz; + if (cur_proc_ptr->pdr.gp_prologue != sz) + { + as_warn ("GP prologue size exceeds field size, using 0 instead"); + cur_proc_ptr->pdr.gp_prologue = 0; + } + + cur_proc_ptr->pdr.gp_used = 1; +} + +static void +generate_ecoff_stab (what, string, type, other, desc) + int what; + const char *string; + int type; + int other; + int desc; +{ + efdr_t *save_file_ptr = cur_file_ptr; + symbolS *sym; + symint_t value; + st_t st; + sc_t sc; + symint_t indx; + localsym_t *hold = NULL; + + /* We don't handle .stabd. */ + if (what != 's' && what != 'n') + { + as_bad (".stab%c is not supported", what); + return; + } + + /* We ignore the other field. */ + if (other != 0) + as_warn (".stab%c: ignoring non-zero other field", what); + + /* Make sure we have a current file. */ + if (cur_file_ptr == (efdr_t *) NULL) + { + add_file ((const char *) NULL, 0, 1); + save_file_ptr = cur_file_ptr; + } + + /* For stabs in ECOFF, the first symbol must be @stabs. This is a + signal to gdb. */ + if (stabs_seen == 0) + mark_stabs (0); + + /* Line number stabs are handled differently, since they have two + values, the line number and the address of the label. We use the + index field (aka desc) to hold the line number, and the value + field to hold the address. The symbol type is st_Label, which + should be different from the other stabs, so that gdb can + recognize it. */ + if (type == N_SLINE) + { + SYMR dummy_symr; + +#ifndef NO_LISTING + if (listing) + listing_source_line ((unsigned int) desc); +#endif + + dummy_symr.index = desc; + if (dummy_symr.index != desc) + { + as_warn ("Line number (%d) for .stab%c directive cannot fit in index field (20 bits)", + desc, what); + return; + } + + sym = symbol_find_or_make ((char *)string); + value = 0; + st = st_Label; + sc = sc_Text; + indx = desc; + } + else + { +#ifndef NO_LISTING + if (listing && (type == N_SO || type == N_SOL)) + listing_source_file (string); +#endif + + sym = symbol_find_or_make ((char *)string); + sc = sc_Nil; + st = st_Nil; + value = 0; + indx = ECOFF_MARK_STAB (type); + } + + /* Don't store the stabs symbol we are creating as the type of the + ECOFF symbol. We want to compute the type of the ECOFF symbol + independently. */ + if (sym != (symbolS *) NULL) + hold = sym->ecoff_symbol; + + (void) add_ecoff_symbol (string, st, sc, sym, (bfd_vma) 0, value, indx); + + if (sym != (symbolS *) NULL) + sym->ecoff_symbol = hold; + + /* Restore normal file type. */ + cur_file_ptr = save_file_ptr; +} + +int +ecoff_no_current_file () +{ + return cur_file_ptr == (efdr_t *) NULL; +} + +void +ecoff_generate_asm_lineno (filename, lineno) + const char *filename; + int lineno; +{ + lineno_list_t *list; + + /* this potential can cause problem, when we start to see stab half the + way thru the file */ +/* + if (stabs_seen) + ecoff_generate_asm_line_stab(filename, lineno); +*/ + + if (current_stabs_filename == (char *)NULL || strcmp (current_stabs_filename, filename)) + { + add_file (filename, 0, 1); + generate_asm_lineno = 1; + } + + list = allocate_lineno_list (); + + list->next = (lineno_list_t *) NULL; + list->file = cur_file_ptr; + list->proc = cur_proc_ptr; + list->frag = frag_now; + list->paddr = frag_now_fix (); + list->lineno = lineno; + + /* We don't want to merge files which have line numbers. */ + cur_file_ptr->fdr.fMerge = 0; + + /* A .loc directive will sometimes appear before a .ent directive, + which means that cur_proc_ptr will be NULL here. Arrange to + patch this up. */ + if (cur_proc_ptr == (proc_t *) NULL) + { + lineno_list_t **pl; + + pl = &noproc_lineno; + while (*pl != (lineno_list_t *) NULL) + pl = &(*pl)->next; + *pl = list; + } + else + { + last_lineno = list; + *last_lineno_ptr = list; + last_lineno_ptr = &list->next; + } +} + +static int line_label_cnt = 0; +void +ecoff_generate_asm_line_stab (filename, lineno) + char *filename; + int lineno; +{ + char *ll; + + if (strcmp (current_stabs_filename, filename)) + { + add_file (filename, 0, 1); + generate_asm_lineno = 1; + } + + line_label_cnt++; + /* generate local label $LMnn */ + ll = xmalloc(10); + sprintf(ll, "$LM%d", line_label_cnt); + colon (ll); + + /* generate stab for the line */ + generate_ecoff_stab ('n', ll, N_SLINE, 0, lineno); + +} + +#endif /* ECOFF_DEBUGGING */ diff --git a/contrib/binutils/gas/ecoff.h b/contrib/binutils/gas/ecoff.h new file mode 100644 index 0000000..a835477 --- /dev/null +++ b/contrib/binutils/gas/ecoff.h @@ -0,0 +1,111 @@ +/* ecoff.h -- header file for ECOFF debugging support + Copyright (C) 1993, 94, 95, 1996 Free Software Foundation, Inc. + Contributed by Cygnus Support. + Put together by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifdef ECOFF_DEBUGGING + +#ifndef GAS_ECOFF_H +#define GAS_ECOFF_H + +#include "coff/sym.h" +#include "coff/ecoff.h" + +/* Whether we have seen any ECOFF debugging information. */ +extern int ecoff_debugging_seen; + +/* This function should be called at the start of assembly, by + obj_read_begin_hook. */ +extern void ecoff_read_begin_hook PARAMS ((void)); + +/* This function should be called when the assembler switches to a new + file. */ +extern void ecoff_new_file PARAMS ((const char *)); + +/* This function should be called when a new symbol is created, by + obj_symbol_new_hook. */ +extern void ecoff_symbol_new_hook PARAMS ((struct symbol *)); + +/* This function should be called by the obj_frob_symbol hook. */ +extern void ecoff_frob_symbol PARAMS ((struct symbol *)); + +/* Build the ECOFF debugging information. This should be called by + obj_frob_file. This fills in the counts in *HDR; the offsets are + filled in relative to the start of the *BUFP. It sets *BUFP to a + block of memory holding the debugging information. It returns the + length of *BUFP. */ +extern unsigned long ecoff_build_debug + PARAMS ((HDRR *hdr, char **bufp, const struct ecoff_debug_swap *)); + +/* Functions to handle the ECOFF debugging directives. */ +extern void ecoff_directive_begin PARAMS ((int)); +extern void ecoff_directive_bend PARAMS ((int)); +extern void ecoff_directive_end PARAMS ((int)); +extern void ecoff_directive_ent PARAMS ((int)); +extern void ecoff_directive_fmask PARAMS ((int)); +extern void ecoff_directive_frame PARAMS ((int)); +extern void ecoff_directive_loc PARAMS ((int)); +extern void ecoff_directive_mask PARAMS ((int)); + +/* Other ECOFF directives. */ +extern void ecoff_directive_extern PARAMS ((int)); +extern void ecoff_directive_weakext PARAMS ((int)); + +/* Functions to handle the COFF debugging directives. */ +extern void ecoff_directive_def PARAMS ((int)); +extern void ecoff_directive_dim PARAMS ((int)); +extern void ecoff_directive_endef PARAMS ((int)); +extern void ecoff_directive_file PARAMS ((int)); +extern void ecoff_directive_scl PARAMS ((int)); +extern void ecoff_directive_size PARAMS ((int)); +extern void ecoff_directive_tag PARAMS ((int)); +extern void ecoff_directive_type PARAMS ((int)); +extern void ecoff_directive_val PARAMS ((int)); + +/* Handle stabs. */ +extern void ecoff_stab PARAMS ((segT sec, int what, const char *string, + int type, int other, int desc)); + +/* Set the GP prologue size. */ +extern void ecoff_set_gp_prolog_size PARAMS ((int sz)); + +/* This routine is called from the ECOFF code to set the external + information for a symbol. */ +#ifndef obj_ecoff_set_ext +extern void obj_ecoff_set_ext PARAMS ((struct symbol *, EXTR *)); +#endif + +/* This routine is used to patch up a line number directive when + instructions are moved around. */ +extern void ecoff_fix_loc PARAMS ((fragS *, unsigned long)); + +/* This function is called from read.c to peek at cur_file_ptr. */ +extern int ecoff_no_current_file PARAMS ((void)); + +/* This routine is called from read.c to generate line number for .s + file. */ +extern void ecoff_generate_asm_lineno PARAMS ((const char *, int)); + +/* This routine is called from read.c to generate line number stabs + for .s file. */ +extern void ecoff_generate_asm_line_stab PARAMS ((char *, int)); + +#endif /* ! GAS_ECOFF_H */ +#endif /* ECOFF_DEBUGGING */ diff --git a/contrib/binutils/gas/emul-target.h b/contrib/binutils/gas/emul-target.h new file mode 100644 index 0000000..3704050 --- /dev/null +++ b/contrib/binutils/gas/emul-target.h @@ -0,0 +1,43 @@ +#ifndef emul_init +#define emul_init common_emul_init +#endif + +#ifndef emul_bfd_name +#define emul_bfd_name default_emul_bfd_name +#endif + +#ifndef emul_local_labels_fb +#define emul_local_labels_fb 0 +#endif + +#ifndef emul_local_labels_dollar +#define emul_local_labels_dollar 0 +#endif + +#ifndef emul_leading_underscore +#define emul_leading_underscore 2 +#endif + +#ifndef emul_strip_underscore +#define emul_strip_underscore 0 +#endif + +#ifndef emul_default_endian +#define emul_default_endian 2 +#endif + +#ifndef emul_fake_label_name +#define emul_fake_label_name 0 +#endif + +struct emulation emul_struct_name = { + 0, + emul_name, + emul_init, + emul_bfd_name, + emul_local_labels_fb, emul_local_labels_dollar, + emul_leading_underscore, emul_strip_underscore, + emul_default_endian, + emul_fake_label_name, + emul_format, +}; diff --git a/contrib/binutils/gas/emul.h b/contrib/binutils/gas/emul.h new file mode 100644 index 0000000..97c46d8 --- /dev/null +++ b/contrib/binutils/gas/emul.h @@ -0,0 +1,23 @@ +#ifndef EMUL_DEFS +#define EMUL_DEFS + +struct emulation { + void (*match) PARAMS ((const char *)); + const char *name; + void (*init) PARAMS ((void)); + const char *(*bfd_name) PARAMS ((void)); + unsigned local_labels_fb : 1; + unsigned local_labels_dollar : 1; + unsigned leading_underscore : 2; + unsigned strip_underscore : 1; + unsigned default_endian : 2; + const char *fake_label_name; + const struct format_ops *format; +}; + +COMMON struct emulation *this_emulation; + +extern const char *default_emul_bfd_name PARAMS ((void)); +extern void common_emul_init PARAMS ((void)); + +#endif diff --git a/contrib/binutils/gas/expr.c b/contrib/binutils/gas/expr.c new file mode 100644 index 0000000..d69f65a --- /dev/null +++ b/contrib/binutils/gas/expr.c @@ -0,0 +1,1627 @@ +/* expr.c -operands, expressions- + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * This is really a branch office of as-read.c. I split it out to clearly + * distinguish the world of expressions from the world of statements. + * (It also gives smaller files to re-compile.) + * Here, "operand"s are of expressions, not instructions. + */ + +#include <ctype.h> +#include <string.h> + +#include "as.h" +#include "obstack.h" + +static void floating_constant PARAMS ((expressionS * expressionP)); +static void integer_constant PARAMS ((int radix, expressionS * expressionP)); +static void mri_char_constant PARAMS ((expressionS *)); +static void current_location PARAMS ((expressionS *)); +static void clean_up_expression PARAMS ((expressionS * expressionP)); +static segT operand PARAMS ((expressionS *)); +static operatorT operator PARAMS ((void)); + +extern const char EXP_CHARS[], FLT_CHARS[]; + +/* We keep a mapping of expression symbols to file positions, so that + we can provide better error messages. */ + +struct expr_symbol_line +{ + struct expr_symbol_line *next; + symbolS *sym; + char *file; + unsigned int line; +}; + +static struct expr_symbol_line *expr_symbol_lines; + +/* Build a dummy symbol to hold a complex expression. This is how we + build expressions up out of other expressions. The symbol is put + into the fake section expr_section. */ + +symbolS * +make_expr_symbol (expressionP) + expressionS *expressionP; +{ + const char *fake; + symbolS *symbolP; + struct expr_symbol_line *n; + + if (expressionP->X_op == O_symbol + && expressionP->X_add_number == 0) + return expressionP->X_add_symbol; + + fake = FAKE_LABEL_NAME; + + /* Putting constant symbols in absolute_section rather than + expr_section is convenient for the old a.out code, for which + S_GET_SEGMENT does not always retrieve the value put in by + S_SET_SEGMENT. */ + symbolP = symbol_create (fake, + (expressionP->X_op == O_constant + ? absolute_section + : expr_section), + 0, &zero_address_frag); + symbolP->sy_value = *expressionP; + + if (expressionP->X_op == O_constant) + resolve_symbol_value (symbolP); + + n = (struct expr_symbol_line *) xmalloc (sizeof *n); + n->sym = symbolP; + as_where (&n->file, &n->line); + n->next = expr_symbol_lines; + expr_symbol_lines = n; + + return symbolP; +} + +/* Return the file and line number for an expr symbol. Return + non-zero if something was found, 0 if no information is known for + the symbol. */ + +int +expr_symbol_where (sym, pfile, pline) + symbolS *sym; + char **pfile; + unsigned int *pline; +{ + register struct expr_symbol_line *l; + + for (l = expr_symbol_lines; l != NULL; l = l->next) + { + if (l->sym == sym) + { + *pfile = l->file; + *pline = l->line; + return 1; + } + } + + return 0; +} + +/* + * Build any floating-point literal here. + * Also build any bignum literal here. + */ + +/* Seems atof_machine can backscan through generic_bignum and hit whatever + happens to be loaded before it in memory. And its way too complicated + for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, + and never write into the early words, thus they'll always be zero. + I hate Dean's floating-point code. Bleh. */ +LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6]; +FLONUM_TYPE generic_floating_point_number = +{ + &generic_bignum[6], /* low (JF: Was 0) */ + &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* high JF: (added +6) */ + 0, /* leader */ + 0, /* exponent */ + 0 /* sign */ +}; +/* If nonzero, we've been asked to assemble nan, +inf or -inf */ +int generic_floating_point_magic; + +static void +floating_constant (expressionP) + expressionS *expressionP; +{ + /* input_line_pointer->*/ + /* floating-point constant. */ + int error_code; + + error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS, + &generic_floating_point_number); + + if (error_code) + { + if (error_code == ERROR_EXPONENT_OVERFLOW) + { + as_bad ("bad floating-point constant: exponent overflow, probably assembling junk"); + } + else + { + as_bad ("bad floating-point constant: unknown error code=%d.", error_code); + } + } + expressionP->X_op = O_big; + /* input_line_pointer->just after constant, */ + /* which may point to whitespace. */ + expressionP->X_add_number = -1; +} + +static void +integer_constant (radix, expressionP) + int radix; + expressionS *expressionP; +{ + char *start; /* start of number. */ + char *suffix = NULL; + char c; + valueT number; /* offset or (absolute) value */ + short int digit; /* value of next digit in current radix */ + short int maxdig = 0;/* highest permitted digit value. */ + int too_many_digits = 0; /* if we see >= this number of */ + char *name; /* points to name of symbol */ + symbolS *symbolP; /* points to symbol */ + + int small; /* true if fits in 32 bits. */ + + /* May be bignum, or may fit in 32 bits. */ + /* Most numbers fit into 32 bits, and we want this case to be fast. + so we pretend it will fit into 32 bits. If, after making up a 32 + bit number, we realise that we have scanned more digits than + comfortably fit into 32 bits, we re-scan the digits coding them + into a bignum. For decimal and octal numbers we are + conservative: Some numbers may be assumed bignums when in fact + they do fit into 32 bits. Numbers of any radix can have excess + leading zeros: We strive to recognise this and cast them back + into 32 bits. We must check that the bignum really is more than + 32 bits, and change it back to a 32-bit number if it fits. The + number we are looking for is expected to be positive, but if it + fits into 32 bits as an unsigned number, we let it be a 32-bit + number. The cavalier approach is for speed in ordinary cases. */ + /* This has been extended for 64 bits. We blindly assume that if + you're compiling in 64-bit mode, the target is a 64-bit machine. + This should be cleaned up. */ + +#ifdef BFD64 +#define valuesize 64 +#else /* includes non-bfd case, mostly */ +#define valuesize 32 +#endif + + if (flag_m68k_mri && radix == 0) + { + int flt = 0; + + /* In MRI mode, the number may have a suffix indicating the + radix. For that matter, it might actually be a floating + point constant. */ + for (suffix = input_line_pointer; isalnum (*suffix); suffix++) + { + if (*suffix == 'e' || *suffix == 'E') + flt = 1; + } + + if (suffix == input_line_pointer) + { + radix = 10; + suffix = NULL; + } + else + { + c = *--suffix; + if (islower (c)) + c = toupper (c); + if (c == 'B') + radix = 2; + else if (c == 'D') + radix = 10; + else if (c == 'O' || c == 'Q') + radix = 8; + else if (c == 'H') + radix = 16; + else if (suffix[1] == '.' || c == 'E' || flt) + { + floating_constant (expressionP); + return; + } + else + { + radix = 10; + suffix = NULL; + } + } + } + + switch (radix) + { + case 2: + maxdig = 2; + too_many_digits = valuesize + 1; + break; + case 8: + maxdig = radix = 8; + too_many_digits = (valuesize + 2) / 3 + 1; + break; + case 16: + maxdig = radix = 16; + too_many_digits = (valuesize + 3) / 4 + 1; + break; + case 10: + maxdig = radix = 10; + too_many_digits = (valuesize + 12) / 4; /* very rough */ + } +#undef valuesize + start = input_line_pointer; + c = *input_line_pointer++; + for (number = 0; + (digit = hex_value (c)) < maxdig; + c = *input_line_pointer++) + { + number = number * radix + digit; + } + /* c contains character after number. */ + /* input_line_pointer->char after c. */ + small = (input_line_pointer - start - 1) < too_many_digits; + if (!small) + { + /* + * we saw a lot of digits. manufacture a bignum the hard way. + */ + LITTLENUM_TYPE *leader; /*->high order littlenum of the bignum. */ + LITTLENUM_TYPE *pointer; /*->littlenum we are frobbing now. */ + long carry; + + leader = generic_bignum; + generic_bignum[0] = 0; + generic_bignum[1] = 0; + input_line_pointer = start; /*->1st digit. */ + c = *input_line_pointer++; + for (; + (carry = hex_value (c)) < maxdig; + c = *input_line_pointer++) + { + for (pointer = generic_bignum; + pointer <= leader; + pointer++) + { + long work; + + work = carry + radix * *pointer; + *pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + if (carry) + { + if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) + { + /* room to grow a longer bignum. */ + *++leader = carry; + } + } + } + /* again, c is char after number, */ + /* input_line_pointer->after c. */ + know (LITTLENUM_NUMBER_OF_BITS == 16); + if (leader < generic_bignum + 2) + { + /* will fit into 32 bits. */ + number = + ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK); + small = 1; + } + else + { + number = leader - generic_bignum + 1; /* number of littlenums in the bignum. */ + } + } + + if (flag_m68k_mri && suffix != NULL && input_line_pointer - 1 == suffix) + c = *input_line_pointer++; + + if (small) + { + /* + * here with number, in correct radix. c is the next char. + * note that unlike un*x, we allow "011f" "0x9f" to + * both mean the same as the (conventional) "9f". this is simply easier + * than checking for strict canonical form. syntax sux! + */ + + if (LOCAL_LABELS_FB && c == 'b') + { + /* + * backward ref to local label. + * because it is backward, expect it to be defined. + */ + /* Construct a local label. */ + name = fb_label_name ((int) number, 0); + + /* seen before, or symbol is defined: ok */ + symbolP = symbol_find (name); + if ((symbolP != NULL) && (S_IS_DEFINED (symbolP))) + { + /* local labels are never absolute. don't waste time + checking absoluteness. */ + know (SEG_NORMAL (S_GET_SEGMENT (symbolP))); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + } + else + { + /* either not seen or not defined. */ + /* @@ Should print out the original string instead of + the parsed number. */ + as_bad ("backw. ref to unknown label \"%d:\", 0 assumed.", + (int) number); + expressionP->X_op = O_constant; + } + + expressionP->X_add_number = 0; + } /* case 'b' */ + else if (LOCAL_LABELS_FB && c == 'f') + { + /* + * forward reference. expect symbol to be undefined or + * unknown. undefined: seen it before. unknown: never seen + * it before. + * construct a local label name, then an undefined symbol. + * don't create a xseg frag for it: caller may do that. + * just return it as never seen before. + */ + name = fb_label_name ((int) number, 1); + symbolP = symbol_find_or_make (name); + /* we have no need to check symbol properties. */ +#ifndef many_segments + /* since "know" puts its arg into a "string", we + can't have newlines in the argument. */ + know (S_GET_SEGMENT (symbolP) == undefined_section || S_GET_SEGMENT (symbolP) == text_section || S_GET_SEGMENT (symbolP) == data_section); +#endif + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } /* case 'f' */ + else if (LOCAL_LABELS_DOLLAR && c == '$') + { + /* If the dollar label is *currently* defined, then this is just + another reference to it. If it is not *currently* defined, + then this is a fresh instantiation of that number, so create + it. */ + + if (dollar_label_defined ((long) number)) + { + name = dollar_label_name ((long) number, 0); + symbolP = symbol_find (name); + know (symbolP != NULL); + } + else + { + name = dollar_label_name ((long) number, 1); + symbolP = symbol_find_or_make (name); + } + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } /* case '$' */ + else + { + expressionP->X_op = O_constant; +#ifdef TARGET_WORD_SIZE + /* Sign extend NUMBER. */ + number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1); +#endif + expressionP->X_add_number = number; + input_line_pointer--; /* restore following character. */ + } /* really just a number */ + } + else + { + /* not a small number */ + expressionP->X_op = O_big; + expressionP->X_add_number = number; /* number of littlenums */ + input_line_pointer--; /*->char following number. */ + } +} + +/* Parse an MRI multi character constant. */ + +static void +mri_char_constant (expressionP) + expressionS *expressionP; +{ + int i; + + if (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + { + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + return; + } + + /* In order to get the correct byte ordering, we must build the + number in reverse. */ + for (i = SIZE_OF_LARGE_NUMBER - 1; i >= 0; i--) + { + int j; + + generic_bignum[i] = 0; + for (j = 0; j < CHARS_PER_LITTLENUM; j++) + { + if (*input_line_pointer == '\'') + { + if (input_line_pointer[1] != '\'') + break; + ++input_line_pointer; + } + generic_bignum[i] <<= 8; + generic_bignum[i] += *input_line_pointer; + ++input_line_pointer; + } + + if (i < SIZE_OF_LARGE_NUMBER - 1) + { + /* If there is more than one littlenum, left justify the + last one to make it match the earlier ones. If there is + only one, we can just use the value directly. */ + for (; j < CHARS_PER_LITTLENUM; j++) + generic_bignum[i] <<= 8; + } + + if (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + break; + } + + if (i < 0) + { + as_bad ("Character constant too large"); + i = 0; + } + + if (i > 0) + { + int c; + int j; + + c = SIZE_OF_LARGE_NUMBER - i; + for (j = 0; j < c; j++) + generic_bignum[j] = generic_bignum[i + j]; + i = c; + } + + know (LITTLENUM_NUMBER_OF_BITS == 16); + if (i > 2) + { + expressionP->X_op = O_big; + expressionP->X_add_number = i; + } + else + { + expressionP->X_op = O_constant; + if (i < 2) + expressionP->X_add_number = generic_bignum[0] & LITTLENUM_MASK; + else + expressionP->X_add_number = + (((generic_bignum[1] & LITTLENUM_MASK) + << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK)); + } + + /* Skip the final closing quote. */ + ++input_line_pointer; +} + +/* Return an expression representing the current location. This + handles the magic symbol `.'. */ + +static void +current_location (expressionp) + expressionS *expressionp; +{ + if (now_seg == absolute_section) + { + expressionp->X_op = O_constant; + expressionp->X_add_number = abs_section_offset; + } + else + { + symbolS *symbolp; + + symbolp = symbol_new (FAKE_LABEL_NAME, now_seg, + (valueT) frag_now_fix (), + frag_now); + expressionp->X_op = O_symbol; + expressionp->X_add_symbol = symbolp; + expressionp->X_add_number = 0; + } +} + +/* + * Summary of operand(). + * + * in: Input_line_pointer points to 1st char of operand, which may + * be a space. + * + * out: A expressionS. + * The operand may have been empty: in this case X_op == O_absent. + * Input_line_pointer->(next non-blank) char after operand. + */ + +static segT +operand (expressionP) + expressionS *expressionP; +{ + char c; + symbolS *symbolP; /* points to symbol */ + char *name; /* points to name of symbol */ + segT segment; + + /* All integers are regarded as unsigned unless they are negated. + This is because the only thing which cares whether a number is + unsigned is the code in emit_expr which extends constants into + bignums. It should only sign extend negative numbers, so that + something like ``.quad 0x80000000'' is not sign extended even + though it appears negative if valueT is 32 bits. */ + expressionP->X_unsigned = 1; + + /* digits, assume it is a bignum. */ + + SKIP_WHITESPACE (); /* leading whitespace is part of operand. */ + c = *input_line_pointer++; /* input_line_pointer->past char in c. */ + + switch (c) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + input_line_pointer--; + + integer_constant (flag_m68k_mri ? 0 : 10, expressionP); + break; + + case '0': + /* non-decimal radix */ + + if (flag_m68k_mri) + { + char *s; + + /* Check for a hex constant. */ + for (s = input_line_pointer; hex_p (*s); s++) + ; + if (*s == 'h' || *s == 'H') + { + --input_line_pointer; + integer_constant (0, expressionP); + break; + } + } + + c = *input_line_pointer; + switch (c) + { + case 'o': + case 'O': + case 'q': + case 'Q': + case '8': + case '9': + if (flag_m68k_mri) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ + default: + default_case: + if (c && strchr (FLT_CHARS, c)) + { + input_line_pointer++; + floating_constant (expressionP); + expressionP->X_add_number = -(isupper (c) ? tolower (c) : c); + } + else + { + /* The string was only zero */ + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + } + + break; + + case 'x': + case 'X': + if (flag_m68k_mri) + goto default_case; + input_line_pointer++; + integer_constant (16, expressionP); + break; + + case 'b': + if (LOCAL_LABELS_FB && ! flag_m68k_mri) + { + /* This code used to check for '+' and '-' here, and, in + some conditions, fall through to call + integer_constant. However, that didn't make sense, + as integer_constant only accepts digits. */ + /* Some of our code elsewhere does permit digits greater + than the expected base; for consistency, do the same + here. */ + if (input_line_pointer[1] < '0' + || input_line_pointer[1] > '9') + { + /* Parse this as a back reference to label 0. */ + input_line_pointer--; + integer_constant (10, expressionP); + break; + } + /* Otherwise, parse this as a binary number. */ + } + /* Fall through. */ + case 'B': + input_line_pointer++; + if (flag_m68k_mri) + goto default_case; + integer_constant (2, expressionP); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + integer_constant (flag_m68k_mri ? 0 : 8, expressionP); + break; + + case 'f': + if (LOCAL_LABELS_FB) + { + /* If it says "0f" and it could possibly be a floating point + number, make it one. Otherwise, make it a local label, + and try to deal with parsing the rest later. */ + if (!input_line_pointer[1] + || (is_end_of_line[0xff & input_line_pointer[1]])) + goto is_0f_label; + { + char *cp = input_line_pointer + 1; + int r = atof_generic (&cp, ".", EXP_CHARS, + &generic_floating_point_number); + switch (r) + { + case 0: + case ERROR_EXPONENT_OVERFLOW: + if (*cp == 'f' || *cp == 'b') + /* looks like a difference expression */ + goto is_0f_label; + else + goto is_0f_float; + default: + as_fatal ("expr.c(operand): bad atof_generic return val %d", + r); + } + } + + /* Okay, now we've sorted it out. We resume at one of these + two labels, depending on what we've decided we're probably + looking at. */ + is_0f_label: + input_line_pointer--; + integer_constant (10, expressionP); + break; + + is_0f_float: + /* fall through */ + ; + } + + case 'd': + case 'D': + if (flag_m68k_mri) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ + case 'F': + case 'r': + case 'e': + case 'E': + case 'g': + case 'G': + input_line_pointer++; + floating_constant (expressionP); + expressionP->X_add_number = -(isupper (c) ? tolower (c) : c); + break; + + case '$': + if (LOCAL_LABELS_DOLLAR) + { + integer_constant (10, expressionP); + break; + } + else + goto default_case; + } + + break; + + case '(': + case '[': + /* didn't begin with digit & not a name */ + segment = expression (expressionP); + /* Expression() will pass trailing whitespace */ + if ((c == '(' && *input_line_pointer++ != ')') + || (c == '[' && *input_line_pointer++ != ']')) + { + as_bad ("Missing ')' assumed"); + input_line_pointer--; + } + SKIP_WHITESPACE (); + /* here with input_line_pointer->char after "(...)" */ + return segment; + + case 'E': + if (! flag_m68k_mri || *input_line_pointer != '\'') + goto de_fault; + as_bad ("EBCDIC constants are not supported"); + /* Fall through. */ + case 'A': + if (! flag_m68k_mri || *input_line_pointer != '\'') + goto de_fault; + ++input_line_pointer; + /* Fall through. */ + case '\'': + if (! flag_m68k_mri) + { + /* Warning: to conform to other people's assemblers NO + ESCAPEMENT is permitted for a single quote. The next + character, parity errors and all, is taken as the value + of the operand. VERY KINKY. */ + expressionP->X_op = O_constant; + expressionP->X_add_number = *input_line_pointer++; + break; + } + + mri_char_constant (expressionP); + break; + + case '+': + (void) operand (expressionP); + break; + + case '"': + /* Double quote is the bitwise not operator in MRI mode. */ + if (! flag_m68k_mri) + goto de_fault; + /* Fall through. */ + case '~': + /* ~ is permitted to start a label on the Delta. */ + if (is_name_beginner (c)) + goto isname; + case '!': + case '-': + { + operand (expressionP); + if (expressionP->X_op == O_constant) + { + /* input_line_pointer -> char after operand */ + if (c == '-') + { + expressionP->X_add_number = - expressionP->X_add_number; + /* Notice: '-' may overflow: no warning is given. This is + compatible with other people's assemblers. Sigh. */ + expressionP->X_unsigned = 0; + } + else if (c == '~' || c == '"') + expressionP->X_add_number = ~ expressionP->X_add_number; + else + expressionP->X_add_number = ! expressionP->X_add_number; + } + else if (expressionP->X_op != O_illegal + && expressionP->X_op != O_absent) + { + expressionP->X_add_symbol = make_expr_symbol (expressionP); + if (c == '-') + expressionP->X_op = O_uminus; + else if (c == '~' || c == '"') + expressionP->X_op = O_bit_not; + else + expressionP->X_op = O_logical_not; + expressionP->X_add_number = 0; + } + else + as_warn ("Unary operator %c ignored because bad operand follows", + c); + } + break; + + case '$': + /* $ is the program counter when in MRI mode, or when DOLLAR_DOT + is defined. */ +#ifndef DOLLAR_DOT + if (! flag_m68k_mri) + goto de_fault; +#endif + if (flag_m68k_mri && hex_p (*input_line_pointer)) + { + /* In MRI mode, $ is also used as the prefix for a + hexadecimal constant. */ + integer_constant (16, expressionP); + break; + } + + if (is_part_of_name (*input_line_pointer)) + goto isname; + + current_location (expressionP); + break; + + case '.': + if (!is_part_of_name (*input_line_pointer)) + { + current_location (expressionP); + break; + } + else if ((strncasecmp (input_line_pointer, "startof.", 8) == 0 + && ! is_part_of_name (input_line_pointer[8])) + || (strncasecmp (input_line_pointer, "sizeof.", 7) == 0 + && ! is_part_of_name (input_line_pointer[7]))) + { + int start; + + start = (input_line_pointer[1] == 't' + || input_line_pointer[1] == 'T'); + input_line_pointer += start ? 8 : 7; + SKIP_WHITESPACE (); + if (*input_line_pointer != '(') + as_bad ("syntax error in .startof. or .sizeof."); + else + { + char *buf; + + ++input_line_pointer; + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ')') + as_bad ("syntax error in .startof. or .sizeof."); + else + ++input_line_pointer; + } + break; + } + else + { + goto isname; + } + case ',': + case '\n': + case '\0': + eol: + /* can't imagine any other kind of operand */ + expressionP->X_op = O_absent; + input_line_pointer--; + break; + + case '%': + if (! flag_m68k_mri) + goto de_fault; + integer_constant (2, expressionP); + break; + + case '@': + if (! flag_m68k_mri) + goto de_fault; + integer_constant (8, expressionP); + break; + + case ':': + if (! flag_m68k_mri) + goto de_fault; + + /* In MRI mode, this is a floating point constant represented + using hexadecimal digits. */ + + ++input_line_pointer; + integer_constant (16, expressionP); + break; + + case '*': + if (! flag_m68k_mri || is_part_of_name (*input_line_pointer)) + goto de_fault; + + current_location (expressionP); + break; + + default: + de_fault: + if (is_end_of_line[(unsigned char) c]) + goto eol; + if (is_name_beginner (c)) /* here if did not begin with a digit */ + { + /* + * Identifier begins here. + * This is kludged for speed, so code is repeated. + */ + isname: + name = --input_line_pointer; + c = get_symbol_end (); + +#ifdef md_parse_name + /* This is a hook for the backend to parse certain names + specially in certain contexts. If a name always has a + specific value, it can often be handled by simply + entering it in the symbol table. */ + if (md_parse_name (name, expressionP)) + { + *input_line_pointer = c; + break; + } +#endif + +#ifdef TC_I960 + /* The MRI i960 assembler permits + lda sizeof code,g13 + FIXME: This should use md_parse_name. */ + if (flag_mri + && (strcasecmp (name, "sizeof") == 0 + || strcasecmp (name, "startof") == 0)) + { + int start; + char *buf; + + start = (name[1] == 't' + || name[1] == 'T'); + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + break; + } +#endif + + symbolP = symbol_find_or_make (name); + + /* If we have an absolute symbol or a reg, then we know its + value now. */ + segment = S_GET_SEGMENT (symbolP); + if (segment == absolute_section) + { + expressionP->X_op = O_constant; + expressionP->X_add_number = S_GET_VALUE (symbolP); + } + else if (segment == reg_section) + { + expressionP->X_op = O_register; + expressionP->X_add_number = S_GET_VALUE (symbolP); + } + else + { + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } + *input_line_pointer = c; + } + else + { + /* Let the target try to parse it. Success is indicated by changing + the X_op field to something other than O_absent and pointing + input_line_pointer passed the expression. If it can't parse the + expression, X_op and input_line_pointer should be unchanged. */ + expressionP->X_op = O_absent; + --input_line_pointer; + md_operand (expressionP); + if (expressionP->X_op == O_absent) + { + ++input_line_pointer; + as_bad ("Bad expression"); + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + } + } + break; + } + + /* + * It is more 'efficient' to clean up the expressionS when they are created. + * Doing it here saves lines of code. + */ + clean_up_expression (expressionP); + SKIP_WHITESPACE (); /*->1st char after operand. */ + know (*input_line_pointer != ' '); + + /* The PA port needs this information. */ + if (expressionP->X_add_symbol) + expressionP->X_add_symbol->sy_used = 1; + + switch (expressionP->X_op) + { + default: + return absolute_section; + case O_symbol: + return S_GET_SEGMENT (expressionP->X_add_symbol); + case O_register: + return reg_section; + } +} /* operand() */ + +/* Internal. Simplify a struct expression for use by expr() */ + +/* + * In: address of a expressionS. + * The X_op field of the expressionS may only take certain values. + * Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT. + * Out: expressionS may have been modified: + * 'foo-foo' symbol references cancelled to 0, + * which changes X_op from O_subtract to O_constant. + * Unused fields zeroed to help expr(). + */ + +static void +clean_up_expression (expressionP) + expressionS *expressionP; +{ + switch (expressionP->X_op) + { + case O_illegal: + case O_absent: + expressionP->X_add_number = 0; + /* Fall through. */ + case O_big: + case O_constant: + case O_register: + expressionP->X_add_symbol = NULL; + /* Fall through. */ + case O_symbol: + case O_uminus: + case O_bit_not: + expressionP->X_op_symbol = NULL; + break; + case O_subtract: + if (expressionP->X_op_symbol == expressionP->X_add_symbol + || ((expressionP->X_op_symbol->sy_frag + == expressionP->X_add_symbol->sy_frag) + && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol)) + && (S_GET_VALUE (expressionP->X_op_symbol) + == S_GET_VALUE (expressionP->X_add_symbol)))) + { + addressT diff = (S_GET_VALUE (expressionP->X_add_symbol) + - S_GET_VALUE (expressionP->X_op_symbol)); + + expressionP->X_op = O_constant; + expressionP->X_add_symbol = NULL; + expressionP->X_op_symbol = NULL; + expressionP->X_add_number += diff; + } + break; + default: + break; + } +} + +/* Expression parser. */ + +/* + * We allow an empty expression, and just assume (absolute,0) silently. + * Unary operators and parenthetical expressions are treated as operands. + * As usual, Q==quantity==operand, O==operator, X==expression mnemonics. + * + * We used to do a aho/ullman shift-reduce parser, but the logic got so + * warped that I flushed it and wrote a recursive-descent parser instead. + * Now things are stable, would anybody like to write a fast parser? + * Most expressions are either register (which does not even reach here) + * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. + * So I guess it doesn't really matter how inefficient more complex expressions + * are parsed. + * + * After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK. + * Also, we have consumed any leading or trailing spaces (operand does that) + * and done all intervening operators. + * + * This returns the segment of the result, which will be + * absolute_section or the segment of a symbol. + */ + +#undef __ +#define __ O_illegal + +static operatorT op_encoding[256] = +{ /* maps ASCII->operators */ + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + + __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, + __, __, O_multiply, O_add, __, O_subtract, __, O_divide, + __, __, __, __, __, __, __, __, + __, __, __, __, O_lt, __, O_gt, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, O_bit_exclusive_or, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, O_bit_inclusive_or, __, __, __, + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ +}; + + +/* + * Rank Examples + * 0 operand, (expression) + * 1 || + * 2 && + * 3 = <> < <= >= > + * 4 + - + * 5 used for * / % in MRI mode + * 6 & ^ ! | + * 7 * / % << >> + * 8 unary - unary ~ + */ +static operator_rankT op_rank[] = +{ + 0, /* O_illegal */ + 0, /* O_absent */ + 0, /* O_constant */ + 0, /* O_symbol */ + 0, /* O_symbol_rva */ + 0, /* O_register */ + 0, /* O_bit */ + 8, /* O_uminus */ + 8, /* O_bit_not */ + 8, /* O_logical_not */ + 7, /* O_multiply */ + 7, /* O_divide */ + 7, /* O_modulus */ + 7, /* O_left_shift */ + 7, /* O_right_shift */ + 6, /* O_bit_inclusive_or */ + 6, /* O_bit_or_not */ + 6, /* O_bit_exclusive_or */ + 6, /* O_bit_and */ + 4, /* O_add */ + 4, /* O_subtract */ + 3, /* O_eq */ + 3, /* O_ne */ + 3, /* O_lt */ + 3, /* O_le */ + 3, /* O_ge */ + 3, /* O_gt */ + 2, /* O_logical_and */ + 1 /* O_logical_or */ +}; + +/* Initialize the expression parser. */ + +void +expr_begin () +{ + /* In MRI mode for the m68k, multiplication and division have lower + precedence than the bit wise operators. */ + if (flag_m68k_mri) + { + op_rank[O_multiply] = 5; + op_rank[O_divide] = 5; + op_rank[O_modulus] = 5; + op_encoding['"'] = O_bit_not; + } + + /* Verify that X_op field is wide enough. */ + { + expressionS e; + e.X_op = O_max; + assert (e.X_op == O_max); + } +} + +/* Return the encoding for the operator at INPUT_LINE_POINTER. + Advance INPUT_LINE_POINTER to the last character in the operator + (i.e., don't change it for a single character operator). */ + +static inline operatorT +operator () +{ + int c; + operatorT ret; + + c = *input_line_pointer; + + switch (c) + { + default: + return op_encoding[c]; + + case '<': + switch (input_line_pointer[1]) + { + default: + return op_encoding[c]; + case '<': + ret = O_left_shift; + break; + case '>': + ret = O_ne; + break; + case '=': + ret = O_le; + break; + } + ++input_line_pointer; + return ret; + + case '>': + switch (input_line_pointer[1]) + { + default: + return op_encoding[c]; + case '>': + ret = O_right_shift; + break; + case '=': + ret = O_ge; + break; + } + ++input_line_pointer; + return ret; + + case '!': + /* We accept !! as equivalent to ^ for MRI compatibility. */ + if (input_line_pointer[1] != '!') + { + if (flag_m68k_mri) + return O_bit_inclusive_or; + return op_encoding[c]; + } + ++input_line_pointer; + return O_bit_exclusive_or; + + case '|': + if (input_line_pointer[1] != '|') + return op_encoding[c]; + + ++input_line_pointer; + return O_logical_or; + + case '&': + if (input_line_pointer[1] != '&') + return op_encoding[c]; + + ++input_line_pointer; + return O_logical_and; + } + + /*NOTREACHED*/ +} + +/* Parse an expression. */ + +segT +expr (rank, resultP) + operator_rankT rank; /* Larger # is higher rank. */ + expressionS *resultP; /* Deliver result here. */ +{ + segT retval; + expressionS right; + operatorT op_left; + operatorT op_right; + + know (rank >= 0); + + retval = operand (resultP); + + know (*input_line_pointer != ' '); /* Operand() gobbles spaces. */ + + op_left = operator (); + while (op_left != O_illegal && op_rank[(int) op_left] > rank) + { + segT rightseg; + + input_line_pointer++; /*->after 1st character of operator. */ + + rightseg = expr (op_rank[(int) op_left], &right); + if (right.X_op == O_absent) + { + as_warn ("missing operand; zero assumed"); + right.X_op = O_constant; + right.X_add_number = 0; + right.X_add_symbol = NULL; + right.X_op_symbol = NULL; + } + + know (*input_line_pointer != ' '); + + if (retval == undefined_section) + { + if (SEG_NORMAL (rightseg)) + retval = rightseg; + } + else if (! SEG_NORMAL (retval)) + retval = rightseg; + else if (SEG_NORMAL (rightseg) + && retval != rightseg +#ifdef DIFF_EXPR_OK + && op_left != O_subtract +#endif + ) + as_bad ("operation combines symbols in different segments"); + + op_right = operator (); + + know (op_right == O_illegal || op_rank[(int) op_right] <= op_rank[(int) op_left]); + know ((int) op_left >= (int) O_multiply + && (int) op_left <= (int) O_logical_or); + + /* input_line_pointer->after right-hand quantity. */ + /* left-hand quantity in resultP */ + /* right-hand quantity in right. */ + /* operator in op_left. */ + + if (resultP->X_op == O_big) + { + as_warn ("left operand is a %s; integer 0 assumed", + resultP->X_add_number > 0 ? "bignum" : "float"); + resultP->X_op = O_constant; + resultP->X_add_number = 0; + resultP->X_add_symbol = NULL; + resultP->X_op_symbol = NULL; + } + if (right.X_op == O_big) + { + as_warn ("right operand is a %s; integer 0 assumed", + right.X_add_number > 0 ? "bignum" : "float"); + right.X_op = O_constant; + right.X_add_number = 0; + right.X_add_symbol = NULL; + right.X_op_symbol = NULL; + } + + /* Optimize common cases. */ + if (op_left == O_add && right.X_op == O_constant) + { + /* X + constant. */ + resultP->X_add_number += right.X_add_number; + } + /* This case comes up in PIC code. */ + else if (op_left == O_subtract + && right.X_op == O_symbol + && resultP->X_op == O_symbol + && (right.X_add_symbol->sy_frag + == resultP->X_add_symbol->sy_frag) + && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol))) + + { + resultP->X_add_number -= right.X_add_number; + resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol) + - S_GET_VALUE (right.X_add_symbol)); + resultP->X_op = O_constant; + resultP->X_add_symbol = 0; + } + else if (op_left == O_subtract && right.X_op == O_constant) + { + /* X - constant. */ + resultP->X_add_number -= right.X_add_number; + } + else if (op_left == O_add && resultP->X_op == O_constant) + { + /* Constant + X. */ + resultP->X_op = right.X_op; + resultP->X_add_symbol = right.X_add_symbol; + resultP->X_op_symbol = right.X_op_symbol; + resultP->X_add_number += right.X_add_number; + retval = rightseg; + } + else if (resultP->X_op == O_constant && right.X_op == O_constant) + { + /* Constant OP constant. */ + offsetT v = right.X_add_number; + if (v == 0 && (op_left == O_divide || op_left == O_modulus)) + { + as_warn ("division by zero"); + v = 1; + } + switch (op_left) + { + default: abort (); + case O_multiply: resultP->X_add_number *= v; break; + case O_divide: resultP->X_add_number /= v; break; + case O_modulus: resultP->X_add_number %= v; break; + case O_left_shift: resultP->X_add_number <<= v; break; + case O_right_shift: + /* We always use unsigned shifts, to avoid relying on + characteristics of the compiler used to compile gas. */ + resultP->X_add_number = + (offsetT) ((valueT) resultP->X_add_number >> (valueT) v); + break; + case O_bit_inclusive_or: resultP->X_add_number |= v; break; + case O_bit_or_not: resultP->X_add_number |= ~v; break; + case O_bit_exclusive_or: resultP->X_add_number ^= v; break; + case O_bit_and: resultP->X_add_number &= v; break; + case O_add: resultP->X_add_number += v; break; + case O_subtract: resultP->X_add_number -= v; break; + case O_eq: + resultP->X_add_number = + resultP->X_add_number == v ? ~ (offsetT) 0 : 0; + break; + case O_ne: + resultP->X_add_number = + resultP->X_add_number != v ? ~ (offsetT) 0 : 0; + break; + case O_lt: + resultP->X_add_number = + resultP->X_add_number < v ? ~ (offsetT) 0 : 0; + break; + case O_le: + resultP->X_add_number = + resultP->X_add_number <= v ? ~ (offsetT) 0 : 0; + break; + case O_ge: + resultP->X_add_number = + resultP->X_add_number >= v ? ~ (offsetT) 0 : 0; + break; + case O_gt: + resultP->X_add_number = + resultP->X_add_number > v ? ~ (offsetT) 0 : 0; + break; + case O_logical_and: + resultP->X_add_number = resultP->X_add_number && v; + break; + case O_logical_or: + resultP->X_add_number = resultP->X_add_number || v; + break; + } + } + else if (resultP->X_op == O_symbol + && right.X_op == O_symbol + && (op_left == O_add + || op_left == O_subtract + || (resultP->X_add_number == 0 + && right.X_add_number == 0))) + { + /* Symbol OP symbol. */ + resultP->X_op = op_left; + resultP->X_op_symbol = right.X_add_symbol; + if (op_left == O_add) + resultP->X_add_number += right.X_add_number; + else if (op_left == O_subtract) + resultP->X_add_number -= right.X_add_number; + } + else + { + /* The general case. */ + resultP->X_add_symbol = make_expr_symbol (resultP); + resultP->X_op_symbol = make_expr_symbol (&right); + resultP->X_op = op_left; + resultP->X_add_number = 0; + resultP->X_unsigned = 1; + } + + op_left = op_right; + } /* While next operator is >= this rank. */ + + /* The PA port needs this information. */ + if (resultP->X_add_symbol) + resultP->X_add_symbol->sy_used = 1; + + return resultP->X_op == O_constant ? absolute_section : retval; +} + +/* + * get_symbol_end() + * + * This lives here because it belongs equally in expr.c & read.c. + * Expr.c is just a branch office read.c anyway, and putting it + * here lessens the crowd at read.c. + * + * Assume input_line_pointer is at start of symbol name. + * Advance input_line_pointer past symbol name. + * Turn that character into a '\0', returning its former value. + * This allows a string compare (RMS wants symbol names to be strings) + * of the symbol name. + * There will always be a char following symbol name, because all good + * lines end in end-of-line. + */ +char +get_symbol_end () +{ + char c; + + /* We accept \001 in a name in case this is being called with a + constructed string. */ + if (is_name_beginner (c = *input_line_pointer++) || c == '\001') + while (is_part_of_name (c = *input_line_pointer++) + || c == '\001') + ; + *--input_line_pointer = 0; + return (c); +} + + +unsigned int +get_single_number () +{ + expressionS exp; + operand (&exp); + return exp.X_add_number; + +} + +/* end of expr.c */ diff --git a/contrib/binutils/gas/expr.h b/contrib/binutils/gas/expr.h new file mode 100644 index 0000000..5002556 --- /dev/null +++ b/contrib/binutils/gas/expr.h @@ -0,0 +1,155 @@ +/* expr.h -> header file for expr.c + Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * By popular demand, we define a struct to represent an expression. + * This will no doubt mutate as expressions become baroque. + * + * Currently, we support expressions like "foo OP bar + 42". In other + * words we permit a (possibly undefined) symbol, a (possibly + * undefined) symbol and the operation used to combine the symbols, + * and an (absolute) augend. RMS says this is so we can have 1-pass + * assembly for any compiler emissions, and a 'case' statement might + * emit 'undefined1 - undefined2'. + * + * The type of an expression used to be stored as a segment. That got + * confusing because it overloaded the concept of a segment. I added + * an operator field, instead. + */ + +/* This is the type of an expression. The operator types are also + used while parsing an expression. + + NOTE: This enumeration must match the op_rank array in expr.c. */ + +typedef enum +{ + /* An illegal expression. */ + O_illegal, + /* A nonexistent expression. */ + O_absent, + /* X_add_number (a constant expression). */ + O_constant, + /* X_add_symbol + X_add_number. */ + O_symbol, + /* X_add_symbol + X_add_number - the base address of the image. */ + O_symbol_rva, + /* A register (X_add_number is register number). */ + O_register, + /* A big value. If X_add_number is negative or 0, the value is in + generic_floating_point_number. Otherwise the value is in + generic_bignum, and X_add_number is the number of LITTLENUMs in + the value. */ + O_big, + /* (- X_add_symbol) + X_add_number. */ + O_uminus, + /* (~ X_add_symbol) + X_add_number. */ + O_bit_not, + /* (! X_add_symbol) + X_add_number. */ + O_logical_not, + /* (X_add_symbol * X_op_symbol) + X_add_number. */ + O_multiply, + /* (X_add_symbol / X_op_symbol) + X_add_number. */ + O_divide, + /* X_add_symbol % X_op_symbol) + X_add_number. */ + O_modulus, + /* X_add_symbol << X_op_symbol) + X_add_number. */ + O_left_shift, + /* X_add_symbol >> X_op_symbol) + X_add_number. */ + O_right_shift, + /* X_add_symbol | X_op_symbol) + X_add_number. */ + O_bit_inclusive_or, + /* X_add_symbol |~ X_op_symbol) + X_add_number. */ + O_bit_or_not, + /* X_add_symbol ^ X_op_symbol) + X_add_number. */ + O_bit_exclusive_or, + /* X_add_symbol & X_op_symbol) + X_add_number. */ + O_bit_and, + /* X_add_symbol + X_op_symbol) + X_add_number. */ + O_add, + /* X_add_symbol - X_op_symbol) + X_add_number. */ + O_subtract, + /* (X_add_symbol == X_op_symbol) + X_add_number. */ + O_eq, + /* (X_add_symbol != X_op_symbol) + X_add_number. */ + O_ne, + /* (X_add_symbol < X_op_symbol) + X_add_number. */ + O_lt, + /* (X_add_symbol <= X_op_symbol) + X_add_number. */ + O_le, + /* (X_add_symbol >= X_op_symbol) + X_add_number. */ + O_ge, + /* (X_add_symbol > X_op_symbol) + X_add_number. */ + O_gt, + /* (X_add_symbol && X_op_symbol) + X_add_number. */ + O_logical_and, + /* (X_add_symbol || X_op_symbol) + X_add_number. */ + O_logical_or, + /* this must be the largest value */ + O_max +} operatorT; + +typedef struct expressionS +{ + /* The main symbol. */ + struct symbol *X_add_symbol; + /* The second symbol, if needed. */ + struct symbol *X_op_symbol; + /* A number to add. */ + offsetT X_add_number; + /* The type of the expression. We can't assume that an arbitrary + compiler can handle a bitfield of enum type. FIXME: We could + check this using autoconf. */ +#ifdef __GNUC__ + operatorT X_op : 5; +#else + unsigned X_op : 5; +#endif + /* Non-zero if X_add_number should be regarded as unsigned. This is + only valid for O_constant expressions. It is only used when an + O_constant must be extended into a bignum (i.e., it is not used + when performing arithmetic on these values). + FIXME: This field is not set very reliably. */ + unsigned int X_unsigned : 1; +} expressionS; + +/* "result" should be type (expressionS *). */ +#define expression(result) expr (0, result) + +/* If an expression is O_big, look here for its value. These common + data may be clobbered whenever expr() is called. */ +/* Flonums returned here. Big enough to hold most precise flonum. */ +extern FLONUM_TYPE generic_floating_point_number; +/* Bignums returned here. */ +extern LITTLENUM_TYPE generic_bignum[]; +/* Number of littlenums in above. */ +#define SIZE_OF_LARGE_NUMBER (20) + +typedef char operator_rankT; + +extern char get_symbol_end PARAMS ((void)); +extern void expr_begin PARAMS ((void)); +extern segT expr PARAMS ((int rank, expressionS * resultP)); +extern unsigned int get_single_number PARAMS ((void)); +extern struct symbol *make_expr_symbol PARAMS ((expressionS * expressionP)); +extern int expr_symbol_where + PARAMS ((struct symbol *, char **, unsigned int *)); + +/* end of expr.h */ diff --git a/contrib/binutils/gas/flonum-copy.c b/contrib/binutils/gas/flonum-copy.c new file mode 100644 index 0000000..5bcc5cc --- /dev/null +++ b/contrib/binutils/gas/flonum-copy.c @@ -0,0 +1,73 @@ +/* flonum_copy.c - copy a flonum + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "as.h" + +void +flonum_copy (in, out) + FLONUM_TYPE *in; + FLONUM_TYPE *out; +{ + unsigned int in_length; /* 0 origin */ + unsigned int out_length; /* 0 origin */ + + out->sign = in->sign; + in_length = in->leader - in->low; + + if (in->leader < in->low) + { + out->leader = out->low - 1; /* 0.0 case */ + } + else + { + out_length = out->high - out->low; + /* + * Assume no GAPS in packing of littlenums. + * I.e. sizeof(array) == sizeof(element) * number_of_elements. + */ + if (in_length <= out_length) + { + { + /* + * For defensive programming, zero any high-order littlenums we don't need. + * This is destroying evidence and wasting time, so why bother??? + */ + if (in_length < out_length) + { + memset ((char *) (out->low + in_length + 1), '\0', out_length - in_length); + } + } + memcpy ((void *) (out->low), (void *) (in->low), ((in_length + 1) * sizeof (LITTLENUM_TYPE))); + out->exponent = in->exponent; + out->leader = in->leader - in->low + out->low; + } + else + { + int shorten; /* 1-origin. Number of littlenums we drop. */ + + shorten = in_length - out_length; + /* Assume out_length >= 0 ! */ + memcpy ((void *) (out->low), (void *) (in->low + shorten), ((out_length + 1) * sizeof (LITTLENUM_TYPE))); + out->leader = out->high; + out->exponent = in->exponent + shorten; + } + } /* if any significant bits */ +} /* flonum_copy() */ + +/* end of flonum_copy.c */ diff --git a/contrib/binutils/gas/flonum-konst.c b/contrib/binutils/gas/flonum-konst.c new file mode 100644 index 0000000..22bba05 --- /dev/null +++ b/contrib/binutils/gas/flonum-konst.c @@ -0,0 +1,209 @@ +/* flonum_const.c - Useful Flonum constants + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include <ansidecl.h> +#include "flonum.h" +/* JF: I added the last entry to this table, and I'm not + sure if its right or not. Could go either way. I wish + I really understood this stuff. */ + + +const int table_size_of_flonum_powers_of_ten = 13; + +static const LITTLENUM_TYPE zero[] = +{1}; + +/***********************************************************************\ + * * + * Warning: the low order bits may be WRONG here. * + * I took this from a suspect bc(1) script. * + * "minus_X"[] is supposed to be 10^(2^-X) expressed in base 2^16. * + * The radix point is just AFTER the highest element of the [] * + * * + * Because bc rounds DOWN for printing (I think), the lowest * + * significance littlenums should probably have 1 added to them. * + * * + \***********************************************************************/ + +/* JF: If this equals 6553/(2^16)+39321/(2^32)+... it approaches .1 */ +static const LITTLENUM_TYPE minus_1[] = +{ + 39322, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, + 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 6553}; +static const LITTLENUM_TYPE plus_1[] = +{10}; + +/* JF: If this equals 655/(2^16) + 23592/(2^32) + ... it approaches .01 */ +static const LITTLENUM_TYPE minus_2[] = +{ + 10486, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 49807, + 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 655}; +static const LITTLENUM_TYPE plus_2[] = +{100}; + +/* This approaches .0001 */ +static const LITTLENUM_TYPE minus_3[] = +{ + 52534, 20027, 37329, 65116, 64067, 60397, 14784, 18979, 33659, 19503, + 2726, 9542, 629, 2202, 40475, 10590, 4299, 47815, 36280, 6}; +static const LITTLENUM_TYPE plus_3[] = +{10000}; + +/* JF: this approaches 1e-8 */ +static const LITTLENUM_TYPE minus_4[] = +{ + 22517, 49501, 54293, 19424, 60699, 6716, 24348, 22618, 23904, 21327, + 3919, 44703, 19149, 28803, 48959, 6259, 50273, 62237, 42}; +/* This equals 1525 * 2^16 + 57600 */ +static const LITTLENUM_TYPE plus_4[] = +{57600, 1525}; + +/* This approaches 1e-16 */ +static const LITTLENUM_TYPE minus_5[] = +{ + 22199, 45957, 17005, 26266, 10526, 16260, 55017, 35680, 40443, 19789, + 17356, 30195, 55905, 28426, 63010, 44197, 1844}; +static const LITTLENUM_TYPE plus_5[] = +{28609, 34546, 35}; + +static const LITTLENUM_TYPE minus_6[] = +{ + 30926, 26518, 13110, 43018, 54982, 48258, 24658, 15209, 63366, 11929, + 20069, 43857, 60487, 51}; +static const LITTLENUM_TYPE plus_6[] = +{61313, 34220, 16731, 11629, 1262}; + +static const LITTLENUM_TYPE minus_7[] = +{ + 29819, 14733, 21490, 40602, 31315, 65186, 2695}; +static const LITTLENUM_TYPE plus_7[] = +{ + 7937, 49002, 60772, 28216, 38893, 55975, 63988, 59711, 20227, 24}; + +static const LITTLENUM_TYPE minus_8[] = +{ + 27579, 64807, 12543, 794, 13907, 61297, 12013, 64360, 15961, 20566, + 24178, 15922, 59427, 110}; +static const LITTLENUM_TYPE plus_8[] = +{ + 15873, 11925, 39177, 991, 14589, 3861, 58415, 9076, 62956, 54223, + 56328, 50180, 45274, 48333, 32537, 42547, 9731, 59679, 590}; + +static const LITTLENUM_TYPE minus_9[] = +{ + 11042, 8464, 58971, 63429, 6022, 63485, 5500, 53464, 47545, 50068, + 56988, 22819, 49708, 54493, 9920, 47667, 40409, 35764, 10383, 54466, + 32702, 17493, 32420, 34382, 22750, 20681, 12300}; +static const LITTLENUM_TYPE plus_9[] = +{ + 20678, 27614, 28272, 53066, 55311, 54677, 29038, 9906, 26288, 44486, + 13860, 7445, 54106, 15426, 21518, 25599, 29632, 52309, 61207, 26105, + 10482, 21948, 51191, 32988, 60892, 62574, 61390, 24540, 21495, 5}; + +static const LITTLENUM_TYPE minus_10[] = +{ + 6214, 48771, 23471, 30163, 31763, 38013, 57001, 11770, 18263, 36366, + 20742, 45086, 56969, 53231, 37856, 55814, 38057, 15692, 46761, 8713, + 6102, 20083, 8269, 11839, 11571, 50963, 15649, 11698, 40675, 2308}; +static const LITTLENUM_TYPE plus_10[] = +{ + 63839, 36576, 45712, 44516, 37803, 29482, 4966, 30556, 37961, 23310, + 27070, 44972, 29507, 48257, 45209, 7494, 17831, 38728, 41577, 29443, + 36016, 7955, 35339, 35479, 36011, 14553, 49618, 5588, 25396, 28}; + +static const LITTLENUM_TYPE minus_11[] = +{ + 16663, 56882, 61983, 7804, 36555, 32060, 34502, 1000, 14356, 21681, + 6605, 34767, 51411, 59048, 53614, 39850, 30079, 6496, 6846, 26841, + 40778, 19578, 59899, 44085, 54016, 24259, 11232, 21229, 21313, 81}; +static const LITTLENUM_TYPE plus_11[] = +{ + 92, 9054, 62707, 17993, 7821, 56838, 13992, 21321, 29637, 48426, + 42982, 38668, 49574, 28820, 18200, 18927, 53979, 16219, 37484, 2516, + 44642, 14665, 11587, 41926, 13556, 23956, 54320, 6661, 55766, 805}; + +static const LITTLENUM_TYPE minus_12[] = +{ + 33202, 45969, 58804, 56734, 16482, 26007, 44984, 49334, 31007, 32944, + 44517, 63329, 47131, 15291, 59465, 2264, 23218, 11829, 59771, 38798, + 31051, 28748, 23129, 40541, 41562, 35108, 50620, 59014, 51817, 6613}; +static const LITTLENUM_TYPE plus_12[] = +{ + 10098, 37922, 58070, 7432, 10470, 63465, 23718, 62190, 47420, 7009, + 38443, 4587, 45596, 38472, 52129, 52779, 29012, 13559, 48688, 31678, + 41753, 58662, 10668, 36067, 29906, 56906, 21461, 46556, 59571, 9}; + +static const LITTLENUM_TYPE minus_13[] = +{ + 45309, 27592, 37144, 34637, 34328, 41671, 34620, 24135, 53401, 22112, + 21576, 45147, 39310, 44051, 48572, 3676, 46544, 59768, 33350, 2323, + 49524, 61568, 3903, 36487, 36356, 30903, 14975, 9035, 29715, 667}; +static const LITTLENUM_TYPE plus_13[] = +{ + 18788, 16960, 6318, 45685, 55400, 46230, 35794, 25588, 7253, 55541, + 49716, 59760, 63592, 8191, 63765, 58530, 44667, 13294, 10001, 55586, + 47887, 18738, 9509, 40896, 42506, 52580, 4171, 325, 12329, 98}; + +/* Shut up complaints about differing pointer types. They only differ + in the const attribute, but there isn't any easy way to do this + */ +#define X (LITTLENUM_TYPE *) + +const FLONUM_TYPE flonum_negative_powers_of_ten[] = +{ + {X zero, X zero, X zero, 0, '+'}, + {X minus_1, X minus_1 + 19, X minus_1 + 19, -20, '+'}, + {X minus_2, X minus_2 + 19, X minus_2 + 19, -20, '+'}, + {X minus_3, X minus_3 + 19, X minus_3 + 19, -20, '+'}, + {X minus_4, X minus_4 + 18, X minus_4 + 18, -20, '+'}, + {X minus_5, X minus_5 + 16, X minus_5 + 16, -20, '+'}, + {X minus_6, X minus_6 + 13, X minus_6 + 13, -20, '+'}, + {X minus_7, X minus_7 + 6, X minus_7 + 6, -20, '+'}, + {X minus_8, X minus_8 + 13, X minus_8 + 13, -40, '+'}, + {X minus_9, X minus_9 + 26, X minus_9 + 26, -80, '+'}, + {X minus_10, X minus_10 + 29, X minus_10 + 29, -136, '+'}, + {X minus_11, X minus_11 + 29, X minus_11 + 29, -242, '+'}, + {X minus_12, X minus_12 + 29, X minus_12 + 29, -455, '+'}, + {X minus_13, X minus_13 + 29, X minus_13 + 29, -880, '+'}, +}; + +const FLONUM_TYPE flonum_positive_powers_of_ten[] = +{ + {X zero, X zero, X zero, 0, '+'}, + {X plus_1, X plus_1 + 0, X plus_1 + 0, 0, '+'}, + {X plus_2, X plus_2 + 0, X plus_2 + 0, 0, '+'}, + {X plus_3, X plus_3 + 0, X plus_3 + 0, 0, '+'}, + {X plus_4, X plus_4 + 1, X plus_4 + 1, 0, '+'}, + {X plus_5, X plus_5 + 2, X plus_5 + 2, 1, '+'}, + {X plus_6, X plus_6 + 4, X plus_6 + 4, 2, '+'}, + {X plus_7, X plus_7 + 9, X plus_7 + 9, 4, '+'}, + {X plus_8, X plus_8 + 18, X plus_8 + 18, 8, '+'}, + {X plus_9, X plus_9 + 29, X plus_9 + 29, 24, '+'}, + {X plus_10, X plus_10 + 29, X plus_10 + 29, 77, '+'}, + {X plus_11, X plus_11 + 29, X plus_11 + 29, 183, '+'}, + {X plus_12, X plus_12 + 29, X plus_12 + 29, 396, '+'}, + {X plus_13, X plus_13 + 29, X plus_13 + 29, 821, '+'}, +}; + +#ifdef VMS +void dummy1 () { } +#endif +/* end of flonum_const.c */ diff --git a/contrib/binutils/gas/flonum-mult.c b/contrib/binutils/gas/flonum-mult.c new file mode 100644 index 0000000..434a73b --- /dev/null +++ b/contrib/binutils/gas/flonum-mult.c @@ -0,0 +1,200 @@ +/* flonum_mult.c - multiply two flonums + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of Gas, the GNU Assembler. + + The GNU assembler is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the GNU Assembler General + Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + the GNU Assembler, but only under the conditions described in the + GNU Assembler General Public License. A copy of this license is + supposed to have been given to you along with the GNU Assembler + so you can know your rights and responsibilities. It should be + in a file named COPYING. Among other things, the copyright + notice and this notice must be preserved on all copies. */ + +#include <ansidecl.h> +#include "flonum.h" + +/* plan for a . b => p(roduct) + + + +-------+-------+-/ /-+-------+-------+ + | a | a | ... | a | a | + | A | A-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-------+ + | b | b | ... | b | b | + | B | B-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + | p | p | ... | p | ... | p | p | + | A+B+1| A+B | | N | | 1 | 0 | + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + + /^\ + (carry) a .b ... | ... a .b a .b + A B | 0 1 0 0 + | + ... | ... a .b + | 1 0 + | + | ... + | + | + | + | ___ + | \ + +----- P = > a .b + N /__ i j + + N = 0 ... A+B + + for all i,j where i+j=N + [i,j integers > 0] + + a[], b[], p[] may not intersect. + Zero length factors signify 0 significant bits: treat as 0.0. + 0.0 factors do the right thing. + Zero length product OK. + + I chose the ForTran accent "foo[bar]" instead of the C accent "*garply" + because I felt the ForTran way was more intuitive. The C way would + probably yield better code on most C compilers. Dean Elsner. + (C style also gives deeper insight [to me] ... oh well ...) + */ + +void +flonum_multip (a, b, product) + const FLONUM_TYPE *a; + const FLONUM_TYPE *b; + FLONUM_TYPE *product; +{ + int size_of_a; /* 0 origin */ + int size_of_b; /* 0 origin */ + int size_of_product; /* 0 origin */ + int size_of_sum; /* 0 origin */ + int extra_product_positions; /* 1 origin */ + unsigned long work; + unsigned long carry; + long exponent; + LITTLENUM_TYPE *q; + long significant; /* TRUE when we emit a non-0 littlenum */ + /* ForTran accent follows. */ + int P; /* Scan product low-order -> high. */ + int N; /* As in sum above. */ + int A; /* Which [] of a? */ + int B; /* Which [] of b? */ + + if ((a->sign != '-' && a->sign != '+') || (b->sign != '-' && b->sign != '+')) + { + /* ... + Got to fail somehow. Any suggestions? */ + product->sign = 0; + return; + } + product->sign = (a->sign == b->sign) ? '+' : '-'; + size_of_a = a->leader - a->low; + size_of_b = b->leader - b->low; + exponent = a->exponent + b->exponent; + size_of_product = product->high - product->low; + size_of_sum = size_of_a + size_of_b; + extra_product_positions = size_of_product - size_of_sum; + if (extra_product_positions < 0) + { + P = extra_product_positions; /* P < 0 */ + exponent -= extra_product_positions; /* Increases exponent. */ + } + else + { + P = 0; + } + carry = 0; + significant = 0; + for (N = 0; N <= size_of_sum; N++) + { + work = carry; + carry = 0; + for (A = 0; A <= N; A++) + { + B = N - A; + if (A <= size_of_a && B <= size_of_b && B >= 0) + { +#ifdef TRACE + printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", A, a->low[A], B, b->low[B], work); +#endif + /* Watch out for sign extension! Without the casts, on + the DEC Alpha, the multiplication result is *signed* + int, which gets sign-extended to convert to the + unsigned long! */ + work += (unsigned long) a->low[A] * (unsigned long) b->low[B]; + carry += work >> LITTLENUM_NUMBER_OF_BITS; + work &= LITTLENUM_MASK; +#ifdef TRACE + printf ("work=%08x carry=%04x\n", work, carry); +#endif + } + } + significant |= work; + if (significant || P < 0) + { + if (P >= 0) + { + product->low[P] = work; +#ifdef TRACE + printf ("P=%d. work[p]:=%04x\n", P, work); +#endif + } + P++; + } + else + { + extra_product_positions++; + exponent++; + } + } + /* + * [P]-> position # size_of_sum + 1. + * This is where 'carry' should go. + */ +#ifdef TRACE + printf ("final carry =%04x\n", carry); +#endif + if (carry) + { + if (extra_product_positions > 0) + { + product->low[P] = carry; + } + else + { + /* No room at high order for carry littlenum. */ + /* Shift right 1 to make room for most significant littlenum. */ + exponent++; + P--; + for (q = product->low + P; q >= product->low; q--) + { + work = *q; + *q = carry; + carry = work; + } + } + } + else + { + P--; + } + product->leader = product->low + P; + product->exponent = exponent; +} + +/* end of flonum_mult.c */ diff --git a/contrib/binutils/gas/flonum.h b/contrib/binutils/gas/flonum.h new file mode 100644 index 0000000..6684f49 --- /dev/null +++ b/contrib/binutils/gas/flonum.h @@ -0,0 +1,110 @@ +/* flonum.h - Floating point package + + Copyright (C) 1987, 90, 91, 92, 94, 95, 1996 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/***********************************************************************\ + * * + * Arbitrary-precision floating point arithmetic. * + * * + * * + * Notation: a floating point number is expressed as * + * MANTISSA * (2 ** EXPONENT). * + * * + * If this offends more traditional mathematicians, then * + * please tell me your nomenclature for flonums! * + * * + \***********************************************************************/ + +#include "bignum.h" + +/***********************************************************************\ + * * + * Variable precision floating point numbers. * + * * + * Exponent is the place value of the low littlenum. E.g.: * + * If 0: low points to the units littlenum. * + * If 1: low points to the LITTLENUM_RADIX littlenum. * + * If -1: low points to the 1/LITTLENUM_RADIX littlenum. * + * * + \***********************************************************************/ + +/* JF: A sign value of 0 means we have been asked to assemble NaN + A sign value of 'P' means we've been asked to assemble +Inf + A sign value of 'N' means we've been asked to assemble -Inf + */ +struct FLONUM_STRUCT +{ + LITTLENUM_TYPE *low; /* low order littlenum of a bignum */ + LITTLENUM_TYPE *high; /* high order littlenum of a bignum */ + LITTLENUM_TYPE *leader; /* -> 1st non-zero littlenum */ + /* If flonum is 0.0, leader==low-1 */ + long exponent; /* base LITTLENUM_RADIX */ + char sign; /* '+' or '-' */ +}; + +typedef struct FLONUM_STRUCT FLONUM_TYPE; + + +/***********************************************************************\ + * * + * Since we can (& do) meet with exponents like 10^5000, it * + * is silly to make a table of ~ 10,000 entries, one for each * + * power of 10. We keep a table where item [n] is a struct * + * FLONUM_FLOATING_POINT representing 10^(2^n). We then * + * multiply appropriate entries from this table to get any * + * particular power of 10. For the example of 10^5000, a table * + * of just 25 entries suffices: 10^(2^-12)...10^(2^+12). * + * * + \***********************************************************************/ + + +extern const FLONUM_TYPE flonum_positive_powers_of_ten[]; +extern const FLONUM_TYPE flonum_negative_powers_of_ten[]; +extern const int table_size_of_flonum_powers_of_ten; +/* Flonum_XXX_powers_of_ten[] table has */ +/* legal indices from 0 to */ +/* + this number inclusive. */ + + + +/***********************************************************************\ + * * + * Declare worker functions. * + * * + \***********************************************************************/ + +int atof_generic PARAMS ((char **address_of_string_pointer, + const char *string_of_decimal_marks, + const char *string_of_decimal_exponent_marks, + FLONUM_TYPE * address_of_generic_floating_point_number)); + +void flonum_copy PARAMS ((FLONUM_TYPE * in, FLONUM_TYPE * out)); +void flonum_multip PARAMS ((const FLONUM_TYPE * a, const FLONUM_TYPE * b, + FLONUM_TYPE * product)); + +/***********************************************************************\ + * * + * Declare error codes. * + * * + \***********************************************************************/ + +#define ERROR_EXPONENT_OVERFLOW (2) + +/* end of flonum.h */ diff --git a/contrib/binutils/gas/frags.c b/contrib/binutils/gas/frags.c new file mode 100644 index 0000000..0418b40 --- /dev/null +++ b/contrib/binutils/gas/frags.c @@ -0,0 +1,354 @@ +/* frags.c - manage frags - + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +extern fragS zero_address_frag; +extern fragS bss_address_frag; + +/* Initialization for frag routines. */ +void +frag_init () +{ + zero_address_frag.fr_type = rs_fill; + bss_address_frag.fr_type = rs_fill; +} + +/* Allocate a frag on the specified obstack. + Call this routine from everywhere else, so that all the weird alignment + hackery can be done in just one place. */ +fragS * +frag_alloc (ob) + struct obstack *ob; +{ + fragS *ptr; + int oalign; + + (void) obstack_alloc (ob, 0); + oalign = obstack_alignment_mask (ob); + obstack_alignment_mask (ob) = 0; + ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG); + obstack_alignment_mask (ob) = oalign; + memset (ptr, 0, SIZEOF_STRUCT_FRAG); + return ptr; +} + +/* + * frag_grow() + * + * Try to augment current frag by nchars chars. + * If there is no room, close of the current frag with a ".fill 0" + * and begin a new frag. Unless the new frag has nchars chars available + * do not return. Do not set up any fields of *now_frag. + */ +void +frag_grow (nchars) + unsigned int nchars; +{ + if (obstack_room (&frchain_now->frch_obstack) < nchars) + { + unsigned int n, oldn; + long oldc; + + frag_wane (frag_now); + frag_new (0); + oldn = (unsigned) -1; + oldc = frchain_now->frch_obstack.chunk_size; + frchain_now->frch_obstack.chunk_size = 2 * nchars; + while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars + && n < oldn) + { + frag_wane (frag_now); + frag_new (0); + oldn = n; + } + frchain_now->frch_obstack.chunk_size = oldc; + } + if (obstack_room (&frchain_now->frch_obstack) < nchars) + as_fatal ("Can't extend frag %d. chars", nchars); +} + +/* + * frag_new() + * + * Call this to close off a completed frag, and start up a new (empty) + * frag, in the same subsegment as the old frag. + * [frchain_now remains the same but frag_now is updated.] + * Because this calculates the correct value of fr_fix by + * looking at the obstack 'frags', it needs to know how many + * characters at the end of the old frag belong to (the maximal) + * fr_var: the rest must belong to fr_fix. + * It doesn't actually set up the old frag's fr_var: you may have + * set fr_var == 1, but allocated 10 chars to the end of the frag: + * in this case you pass old_frags_var_max_size == 10. + * + * Make a new frag, initialising some components. Link new frag at end + * of frchain_now. + */ +void +frag_new (old_frags_var_max_size) + /* Number of chars (already allocated on obstack frags) in + variable_length part of frag. */ + int old_frags_var_max_size; +{ + fragS *former_last_fragP; + frchainS *frchP; + + assert (frchain_now->frch_last == frag_now); + + /* Fix up old frag's fr_fix. */ + frag_now->fr_fix = frag_now_fix () - old_frags_var_max_size; + /* Make sure its type is valid. */ + assert (frag_now->fr_type != 0); + + /* This will align the obstack so the next struct we allocate on it + will begin at a correct boundary. */ + obstack_finish (&frchain_now->frch_obstack); + frchP = frchain_now; + know (frchP); + former_last_fragP = frchP->frch_last; + assert (former_last_fragP != 0); + assert (former_last_fragP == frag_now); + frag_now = frag_alloc (&frchP->frch_obstack); + + as_where (&frag_now->fr_file, &frag_now->fr_line); + + /* Generally, frag_now->points to an address rounded up to next + alignment. However, characters will add to obstack frags + IMMEDIATELY after the struct frag, even if they are not starting + at an alignment address. */ + former_last_fragP->fr_next = frag_now; + frchP->frch_last = frag_now; + +#ifndef NO_LISTING + { + extern struct list_info_struct *listing_tail; + frag_now->line = listing_tail; + } +#endif + + assert (frchain_now->frch_last == frag_now); + + frag_now->fr_next = NULL; +} /* frag_new() */ + +/* + * frag_more() + * + * Start a new frag unless we have n more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Return the address of the 1st char to write into. Advance + * frag_now_growth past the new chars. + */ + +char * +frag_more (nchars) + int nchars; +{ + register char *retval; + + if (now_seg == absolute_section) + { + as_bad ("attempt to allocate data in absolute section"); + subseg_set (text_section, 0); + } + + if (mri_common_symbol != NULL) + { + as_bad ("attempt to allocate data in common section"); + mri_common_symbol = NULL; + } + + frag_grow (nchars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, nchars); + return (retval); +} /* frag_more() */ + +/* + * frag_var() + * + * Start a new frag unless we have max_chars more chars of room in the current frag. + * Close off the old frag with a .fill 0. + * + * Set up a machine_dependent relaxable frag, then start a new frag. + * Return the address of the 1st char of the var part of the old frag + * to write into. + */ + +char * +frag_var (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + offsetT offset; + char *opcode; +{ + register char *retval; + + frag_grow (max_chars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, max_chars); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + /* Default these to zero. Only the ns32k uses these but they can't be + conditionally included in `struct frag'. See as.h. */ + frag_now->fr_targ.ns32k.pcrel_adjust = 0; + frag_now->fr_targ.ns32k.bsr = 0; + as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_new (max_chars); + return (retval); +} + +/* + * frag_variant() + * + * OVE: This variant of frag_var assumes that space for the tail has been + * allocated by caller. + * No call to frag_grow is done. + */ + +char * +frag_variant (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + offsetT offset; + char *opcode; +{ + register char *retval; + + retval = obstack_next_free (&frchain_now->frch_obstack); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; + /* Default these to zero. Only the ns32k uses these but they can't be + conditionally included in `struct frag'. See as.h. */ + frag_now->fr_targ.ns32k.pcrel_adjust = 0; + frag_now->fr_targ.ns32k.bsr = 0; + as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_new (max_chars); + return (retval); +} /* frag_variant() */ + +/* + * frag_wane() + * + * Reduce the variable end of a frag to a harmless state. + */ +void +frag_wane (fragP) + register fragS *fragP; +{ + fragP->fr_type = rs_fill; + fragP->fr_offset = 0; + fragP->fr_var = 0; +} + +/* Make an alignment frag. The size of this frag will be adjusted to + force the next frag to have the appropriate alignment. ALIGNMENT + is the power of two to which to align. FILL_CHARACTER is the + character to use to fill in any bytes which are skipped. MAX is + the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + +void +frag_align (alignment, fill_character, max) + int alignment; + int fill_character; + int max; +{ + if (now_seg == absolute_section) + { + addressT new_off; + + new_off = ((abs_section_offset + alignment - 1) + &~ ((1 << alignment) - 1)); + if (max == 0 || new_off - abs_section_offset <= max) + abs_section_offset = new_off; + } + else + { + char *p; + + p = frag_var (rs_align, 1, 1, (relax_substateT) max, + (symbolS *) 0, (offsetT) alignment, (char *) 0); + *p = fill_character; + } +} + +/* Make an alignment frag like frag_align, but fill with a repeating + pattern rather than a single byte. ALIGNMENT is the power of two + to which to align. FILL_PATTERN is the fill pattern to repeat in + the bytes which are skipped. N_FILL is the number of bytes in + FILL_PATTERN. MAX is the maximum number of characters to skip when + doing the alignment, or 0 if there is no maximum. */ + +void +frag_align_pattern (alignment, fill_pattern, n_fill, max) + int alignment; + const char *fill_pattern; + int n_fill; + int max; +{ + char *p; + + p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max, + (symbolS *) 0, (offsetT) alignment, (char *) 0); + memcpy (p, fill_pattern, n_fill); +} + +int +frag_now_fix () +{ + if (now_seg == absolute_section) + return abs_section_offset; + return ((char*)obstack_next_free (&frchain_now->frch_obstack) + - frag_now->fr_literal); +} + +void +frag_append_1_char (datum) + int datum; +{ + if (obstack_room (&frchain_now->frch_obstack) <= 1) + { + frag_wane (frag_now); + frag_new (0); + } + obstack_1grow (&frchain_now->frch_obstack, datum); +} + +/* end of frags.c */ diff --git a/contrib/binutils/gas/frags.h b/contrib/binutils/gas/frags.h new file mode 100644 index 0000000..53877a9 --- /dev/null +++ b/contrib/binutils/gas/frags.h @@ -0,0 +1,73 @@ +/* frags.h - Header file for the frag concept. + Copyright (C) 1987, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifdef ANSI_PROTOTYPES +struct obstack; +#endif + +#if 0 +/* + * A macro to speed up appending exactly 1 char + * to current frag. + */ +/* JF changed < 1 to <= 1 to avoid a race conditon */ +#define FRAG_APPEND_1_CHAR(datum) \ +{ \ + if (obstack_room( &frags ) <= 1) {\ + frag_wane (frag_now); \ + frag_new (0); \ + } \ + obstack_1grow( &frags, datum ); \ +} +#else +extern void frag_append_1_char PARAMS ((int)); +#define FRAG_APPEND_1_CHAR(X) frag_append_1_char (X) +#endif + + +void frag_init PARAMS ((void)); +fragS *frag_alloc PARAMS ((struct obstack *)); +void frag_grow PARAMS ((unsigned int nchars)); +char *frag_more PARAMS ((int nchars)); +void frag_align PARAMS ((int alignment, int fill_character, int max)); +void frag_align_pattern PARAMS ((int alignment, + const char *fill_pattern, + int n_fill, + int max)); +void frag_new PARAMS ((int old_frags_var_max_size)); +void frag_wane PARAMS ((fragS * fragP)); + +char *frag_variant PARAMS ((relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS * symbol, + offsetT offset, + char *opcode)); + +char *frag_var PARAMS ((relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS * symbol, + offsetT offset, + char *opcode)); + +/* end of frags.h */ diff --git a/contrib/binutils/gas/gasp.c b/contrib/binutils/gas/gasp.c new file mode 100644 index 0000000..3fb51b8 --- /dev/null +++ b/contrib/binutils/gas/gasp.c @@ -0,0 +1,3739 @@ +/* gasp.c - Gnu assembler preprocessor main program. + Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GASP, the GNU Assembler Preprocessor. + + GASP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GASP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GASP; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + +This program translates the input macros and stuff into a form +suitable for gas to consume. + + + gasp [-sdhau] [-c char] [-o <outfile>] <infile>* + + -s copy source to output + -c <char> comments are started with <char> instead of ! + -u allow unreasonable stuff + -p print line numbers + -d print debugging stats + -s semi colons start comments + -a use alternate syntax + Pseudo ops can start with or without a . + Labels have to be in first column. + -I specify include dir + Macro arg parameters subsituted by name, don't need the &. + String can start with ' too. + Strings can be surrounded by <..> + A %<exp> in a string evaluates the expression + Literal char in a string with ! + + +*/ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <ctype.h> + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef NEED_MALLOC_DECLARATION +extern char *malloc (); +#endif + +#include "ansidecl.h" +#include "libiberty.h" +#include "sb.h" +#include "macro.h" + +char *program_version = "1.2"; + +/* This is normally declared in as.h, but we don't include that. We + need the function because other files linked with gasp.c might call + it. */ +extern void as_abort PARAMS ((const char *, int, const char *)); + +#define MAX_INCLUDES 30 /* Maximum include depth */ +#define MAX_REASONABLE 1000 /* Maximum number of expansions */ + +int unreasonable; /* -u on command line */ +int stats; /* -d on command line */ +int print_line_number; /* -p flag on command line */ +int copysource; /* -c flag on command line */ +int warnings; /* Number of WARNINGs generated so far. */ +int errors; /* Number of ERRORs generated so far. */ +int fatals; /* Number of fatal ERRORs generated so far (either 0 or 1). */ +int alternate = 0; /* -a on command line */ +int mri = 0; /* -M on command line */ +char comment_char = '!'; +int radix = 10; /* Default radix */ + +int had_end; /* Seen .END */ + +/* The output stream */ +FILE *outfile; + +/* the attributes of each character are stored as a bit pattern + chartype, which gives us quick tests. */ + + +#define FIRSTBIT 1 +#define NEXTBIT 2 +#define SEPBIT 4 +#define WHITEBIT 8 +#define COMMENTBIT 16 +#define BASEBIT 32 +#define ISCOMMENTCHAR(x) (chartype[(unsigned)(x)] & COMMENTBIT) +#define ISFIRSTCHAR(x) (chartype[(unsigned)(x)] & FIRSTBIT) +#define ISNEXTCHAR(x) (chartype[(unsigned)(x)] & NEXTBIT) +#define ISSEP(x) (chartype[(unsigned)(x)] & SEPBIT) +#define ISWHITE(x) (chartype[(unsigned)(x)] & WHITEBIT) +#define ISBASE(x) (chartype[(unsigned)(x)] & BASEBIT) +static char chartype[256]; + + +/* Conditional assembly uses the `ifstack'. Each aif pushes another + entry onto the stack, and sets the on flag if it should. The aelse + sets hadelse, and toggles on. An aend pops a level. We limit to + 100 levels of nesting, not because we're facists pigs with read + only minds, but because more than 100 levels of nesting is probably + a bug in the user's macro structure. */ + +#define IFNESTING 100 +struct + { + int on; /* is the level being output */ + int hadelse; /* has an aelse been seen */ + } +ifstack[IFNESTING]; +int ifi; + +/* The final and intermediate results of expression evaluation are kept in + exp_t's. Note that a symbol is not an sb, but a pointer into the input + line. It must be coped somewhere safe before the next line is read in. */ + +typedef struct + { + char *name; + int len; + } +symbol; + +typedef struct + { + int value; /* constant part */ + symbol add_symbol; /* name part */ + symbol sub_symbol; /* name part */ + } +exp_t; + + +/* Hashing is done in a pretty standard way. A hash_table has a + pointer to a vector of pointers to hash_entrys, and the size of the + vector. A hash_entry contains a union of all the info we like to + store in hash table. If there is a hash collision, hash_entries + with the same hash are kept in a chain. */ + +/* What the data in a hash_entry means */ +typedef enum + { + hash_integer, /* name->integer mapping */ + hash_string, /* name->string mapping */ + hash_macro, /* name is a macro */ + hash_formal /* name is a formal argument */ + } hash_type; + +typedef struct hs + { + sb key; /* symbol name */ + hash_type type; /* symbol meaning */ + union + { + sb s; + int i; + struct macro_struct *m; + struct formal_struct *f; + } value; + struct hs *next; /* next hash_entry with same hash key */ + } hash_entry; + +typedef struct + { + hash_entry **table; + int size; + } hash_table; + + +/* Structures used to store macros. + + Each macro knows its name and included text. It gets built with a + list of formal arguments, and also keeps a hash table which points + into the list to speed up formal search. Each formal knows its + name and its default value. Each time the macro is expanded, the + formals get the actual values attatched to them. */ + +/* describe the formal arguments to a macro */ + +typedef struct formal_struct + { + struct formal_struct *next; /* next formal in list */ + sb name; /* name of the formal */ + sb def; /* the default value */ + sb actual; /* the actual argument (changed on each expansion) */ + int index; /* the index of the formal 0..formal_count-1 */ + } +formal_entry; + +/* describe the macro. */ + +typedef struct macro_struct + { + sb sub; /* substitution text. */ + int formal_count; /* number of formal args. */ + formal_entry *formals; /* pointer to list of formal_structs */ + hash_table formal_hash; /* hash table of formals. */ + } +macro_entry; + +/* how we nest files and expand macros etc. + + we keep a stack of of include_stack structs. each include file + pushes a new level onto the stack. we keep an sb with a pushback + too. unget chars are pushed onto the pushback sb, getchars first + checks the pushback sb before reading from the input stream. + + small things are expanded by adding the text of the item onto the + pushback sb. larger items are grown by pushing a new level and + allocating the entire pushback buf for the item. each time + something like a macro is expanded, the stack index is changed. we + can then perform an exitm by popping all entries off the stack with + the same stack index. if we're being reasonable, we can detect + recusive expansion by checking the index is reasonably small. + */ + +typedef enum + { + include_file, include_repeat, include_while, include_macro + } include_type; + +struct include_stack + { + sb pushback; /* current pushback stream */ + int pushback_index; /* next char to read from stream */ + FILE *handle; /* open file */ + sb name; /* name of file */ + int linecount; /* number of lines read so far */ + include_type type; + int index; /* index of this layer */ + } +include_stack[MAX_INCLUDES]; + +struct include_stack *sp; +#define isp (sp - include_stack) + +/* Include file list */ + +typedef struct include_path +{ + struct include_path *next; + sb path; +} include_path; + +include_path *paths_head; +include_path *paths_tail; + + +static void quit PARAMS ((void)); +static void hash_new_table PARAMS ((int, hash_table *)); +static int hash PARAMS ((sb *)); +static hash_entry *hash_create PARAMS ((hash_table *, sb *)); +static void hash_add_to_string_table PARAMS ((hash_table *, sb *, sb *, int)); +static void hash_add_to_int_table PARAMS ((hash_table *, sb *, int)); +static hash_entry *hash_lookup PARAMS ((hash_table *, sb *)); +static void checkconst PARAMS ((int, exp_t *)); +static int sb_strtol PARAMS ((int, sb *, int, int *)); +static int level_0 PARAMS ((int, sb *, exp_t *)); +static int level_1 PARAMS ((int, sb *, exp_t *)); +static int level_2 PARAMS ((int, sb *, exp_t *)); +static int level_3 PARAMS ((int, sb *, exp_t *)); +static int level_4 PARAMS ((int, sb *, exp_t *)); +static int level_5 PARAMS ((int, sb *, exp_t *)); +static int exp_parse PARAMS ((int, sb *, exp_t *)); +static void exp_string PARAMS ((exp_t *, sb *)); +static int exp_get_abs PARAMS ((const char *, int, sb *, int *)); +#if 0 +static void strip_comments PARAMS ((sb *)); +#endif +static void unget PARAMS ((int)); +static void include_buf PARAMS ((sb *, sb *, include_type, int)); +static void include_print_where_line PARAMS ((FILE *)); +static void include_print_line PARAMS ((FILE *)); +static int get_line PARAMS ((sb *)); +static int grab_label PARAMS ((sb *, sb *)); +static void change_base PARAMS ((int, sb *, sb *)); +static void do_end PARAMS ((sb *)); +static void do_assign PARAMS ((int, int, sb *)); +static void do_radix PARAMS ((sb *)); +static int get_opsize PARAMS ((int, sb *, int *)); +static int eol PARAMS ((int, sb *)); +static void do_data PARAMS ((int, sb *, int)); +static void do_datab PARAMS ((int, sb *)); +static void do_align PARAMS ((int, sb *)); +static void do_res PARAMS ((int, sb *, int)); +static void do_export PARAMS ((sb *)); +static void do_print PARAMS ((int, sb *)); +static void do_heading PARAMS ((int, sb *)); +static void do_page PARAMS ((void)); +static void do_form PARAMS ((int, sb *)); +static int get_any_string PARAMS ((int, sb *, sb *, int, int)); +static int skip_openp PARAMS ((int, sb *)); +static int skip_closep PARAMS ((int, sb *)); +static int dolen PARAMS ((int, sb *, sb *)); +static int doinstr PARAMS ((int, sb *, sb *)); +static int dosubstr PARAMS ((int, sb *, sb *)); +static void process_assigns PARAMS ((int, sb *, sb *)); +static int get_and_process PARAMS ((int, sb *, sb *)); +static void process_file PARAMS ((void)); +static void free_old_entry PARAMS ((hash_entry *)); +static void do_assigna PARAMS ((int, sb *)); +static void do_assignc PARAMS ((int, sb *)); +static void do_reg PARAMS ((int, sb *)); +static int condass_lookup_name PARAMS ((sb *, int, sb *, int)); +static int whatcond PARAMS ((int, sb *, int *)); +static int istrue PARAMS ((int, sb *)); +static void do_aif PARAMS ((int, sb *)); +static void do_aelse PARAMS ((void)); +static void do_aendi PARAMS ((void)); +static int condass_on PARAMS ((void)); +static void do_if PARAMS ((int, sb *, int)); +static int get_mri_string PARAMS ((int, sb *, sb *, int)); +static void do_ifc PARAMS ((int, sb *, int)); +static void do_aendr PARAMS ((void)); +static void do_awhile PARAMS ((int, sb *)); +static void do_aendw PARAMS ((void)); +static void do_exitm PARAMS ((void)); +static void do_arepeat PARAMS ((int, sb *)); +static void do_endm PARAMS ((void)); +static void do_irp PARAMS ((int, sb *, int)); +static void do_local PARAMS ((int, sb *)); +static void do_macro PARAMS ((int, sb *)); +static int macro_op PARAMS ((int, sb *)); +static int getstring PARAMS ((int, sb *, sb *)); +static void do_sdata PARAMS ((int, sb *, int)); +static void do_sdatab PARAMS ((int, sb *)); +static int new_file PARAMS ((const char *)); +static void do_include PARAMS ((int, sb *)); +static void include_pop PARAMS ((void)); +static int get PARAMS ((void)); +static int linecount PARAMS ((void)); +static int include_next_index PARAMS ((void)); +static void chartype_init PARAMS ((void)); +static int process_pseudo_op PARAMS ((int, sb *, sb *)); +static void add_keyword PARAMS ((const char *, int)); +static void process_init PARAMS ((void)); +static void do_define PARAMS ((const char *)); +static void show_usage PARAMS ((FILE *, int)); +static void show_help PARAMS ((void)); + +#define FATAL(x) \ + do { include_print_where_line (stderr); fprintf x ; fatals++; quit(); } while(0) +#define ERROR(x) \ + do { include_print_where_line (stderr); fprintf x; errors++; } while(0) +#define WARNING(x) \ + do { include_print_where_line (stderr); fprintf x; warnings++;} while(0) + + + +/* exit the program and return the right ERROR code. */ +static void +quit () +{ + int exitcode; + if (fatals + errors) + exitcode = 1; + else + exitcode = 0; + + if (stats) + { + int i; + for (i = 0; i < sb_max_power_two; i++) + { + fprintf (stderr, "strings size %8d : %d\n", 1<<i, string_count[i]); + } + } + exit (exitcode); +} + +/* hash table maintenance. */ + +/* build a new hash table with size buckets, and fill in the info at ptr. */ + +static void +hash_new_table (size, ptr) + int size; + hash_table *ptr; +{ + int i; + ptr->size = size; + ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *))); + /* Fill with null-pointer, not zero-bit-pattern. */ + for (i = 0; i < size; i++) + ptr->table[i] = 0; +} + +/* calculate and return the hash value of the sb at key. */ + +static int +hash (key) + sb *key; +{ + int k = 0x1234; + int i; + char *p = key->ptr; + for (i = 0; i < key->len; i++) + { + k ^= (k << 2) ^ *p; + p++; + } + return k & 0xf0fff; +} + +/* lookup key in hash_table tab, if present, then return it, otherwise + build a new one and fill it with hash_integer. */ + +static +hash_entry * +hash_create (tab, key) + hash_table *tab; + sb *key; +{ + int k = hash (key) % tab->size; + hash_entry *p; + hash_entry **table = tab->table; + + p = table[k]; + + while (1) + { + if (!p) + { + hash_entry *n = (hash_entry *) xmalloc (sizeof (hash_entry)); + n->next = table[k]; + sb_new (&n->key); + sb_add_sb (&n->key, key); + table[k] = n; + n->type = hash_integer; + return n; + } + if (strncmp (table[k]->key.ptr, key->ptr, key->len) == 0) + { + return p; + } + p = p->next; + } +} + +/* add sb name with key into hash_table tab. if replacing old value + and again, then ERROR. */ + +static +void +hash_add_to_string_table (tab, key, name, again) + hash_table *tab; + sb *key; + sb *name; + int again; +{ + hash_entry *ptr = hash_create (tab, key); + if (ptr->type == hash_integer) + { + sb_new (&ptr->value.s); + } + if (ptr->value.s.len) + { + if (!again) + ERROR ((stderr, "redefinition not allowed\n")); + } + + ptr->type = hash_string; + sb_reset (&ptr->value.s); + + sb_add_sb (&ptr->value.s, name); +} + +/* add integer name to hash_table tab with sb key. */ + +static +void +hash_add_to_int_table (tab, key, name) + hash_table *tab; + sb *key; + int name; +{ + hash_entry *ptr = hash_create (tab, key); + ptr->value.i = name; +} + +/* lookup sb key in hash_table tab. if found return hash_entry result, + else 0. */ + +static +hash_entry * +hash_lookup (tab, key) + hash_table *tab; + sb *key; +{ + int k = hash (key) % tab->size; + hash_entry **table = tab->table; + hash_entry *p = table[k]; + while (p) + { + if (p->key.len == key->len + && strncmp (p->key.ptr, key->ptr, key->len) == 0) + return p; + p = p->next; + } + return 0; +} + + +/* expressions + + are handled in a really simple recursive decent way. each bit of + the machine takes an index into an sb and a pointer to an exp_t, + modifies the *exp_t and returns the index of the first character + past the part of the expression parsed. + + expression precedence: + ( ) + unary + - ~ + * / + + - + & + | ~ + +*/ + + +/* make sure that the exp_t at term is constant, if not the give the op ERROR. */ + +static +void +checkconst (op, term) + int op; + exp_t *term; +{ + if (term->add_symbol.len + || term->sub_symbol.len) + { + ERROR ((stderr, "the %c operator cannot take non-absolute arguments.\n", op)); + } +} + +/* turn the number in string at idx into a number of base, + fill in ptr and return the index of the first character not in the + number. */ + +static +int +sb_strtol (idx, string, base, ptr) + int idx; + sb *string; + int base; + int *ptr; +{ + int value = 0; + idx = sb_skip_white (idx, string); + + while (idx < string->len) + { + int ch = string->ptr[idx]; + int dig = 0; + if (isdigit (ch)) + dig = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + dig = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + dig = ch - 'A' + 10; + else + break; + + if (dig >= base) + break; + + value = value * base + dig; + idx++; + } + *ptr = value; + return idx; +} + +static int +level_0 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + lhs->add_symbol.len = 0; + lhs->add_symbol.name = 0; + + lhs->sub_symbol.len = 0; + lhs->sub_symbol.name = 0; + + idx = sb_skip_white (idx, string); + + lhs->value = 0; + + if (isdigit (string->ptr[idx])) + { + idx = sb_strtol (idx, string, 10, &lhs->value); + } + else if (ISFIRSTCHAR (string->ptr[idx])) + { + int len = 0; + lhs->add_symbol.name = string->ptr + idx; + while (idx < string->len && ISNEXTCHAR (string->ptr[idx])) + { + idx++; + len++; + } + lhs->add_symbol.len = len; + } + else if (string->ptr[idx] == '"') + { + sb acc; + sb_new (&acc); + ERROR ((stderr, "string where expression expected.\n")); + idx = getstring (idx, string, &acc); + sb_kill (&acc); + } + else + { + ERROR ((stderr, "can't find primary in expression.\n")); + idx++; + } + return sb_skip_white (idx, string); +} + + + +static int +level_1 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + idx = sb_skip_white (idx, string); + + switch (string->ptr[idx]) + { + case '+': + idx = level_1 (idx + 1, string, lhs); + break; + case '~': + idx = level_1 (idx + 1, string, lhs); + checkconst ('~', lhs); + lhs->value = ~lhs->value; + break; + case '-': + { + symbol t; + idx = level_1 (idx + 1, string, lhs); + lhs->value = -lhs->value; + t = lhs->add_symbol; + lhs->add_symbol = lhs->sub_symbol; + lhs->sub_symbol = t; + break; + } + case '(': + idx++; + idx = level_5 (sb_skip_white (idx, string), string, lhs); + if (string->ptr[idx] != ')') + ERROR ((stderr, "misplaced closing parens.\n")); + else + idx++; + break; + default: + idx = level_0 (idx, string, lhs); + break; + } + return sb_skip_white (idx, string); +} + +static int +level_2 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + exp_t rhs; + + idx = level_1 (idx, string, lhs); + + while (idx < string->len && (string->ptr[idx] == '*' + || string->ptr[idx] == '/')) + { + char op = string->ptr[idx++]; + idx = level_1 (idx, string, &rhs); + switch (op) + { + case '*': + checkconst ('*', lhs); + checkconst ('*', &rhs); + lhs->value *= rhs.value; + break; + case '/': + checkconst ('/', lhs); + checkconst ('/', &rhs); + if (rhs.value == 0) + ERROR ((stderr, "attempt to divide by zero.\n")); + else + lhs->value /= rhs.value; + break; + } + } + return sb_skip_white (idx, string); +} + + +static int +level_3 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + exp_t rhs; + + idx = level_2 (idx, string, lhs); + + while (idx < string->len + && (string->ptr[idx] == '+' + || string->ptr[idx] == '-')) + { + char op = string->ptr[idx++]; + idx = level_2 (idx, string, &rhs); + switch (op) + { + case '+': + lhs->value += rhs.value; + if (lhs->add_symbol.name && rhs.add_symbol.name) + { + ERROR ((stderr, "can't add two relocatable expressions\n")); + } + /* change nn+symbol to symbol + nn */ + if (rhs.add_symbol.name) + { + lhs->add_symbol = rhs.add_symbol; + } + break; + case '-': + lhs->value -= rhs.value; + lhs->sub_symbol = rhs.add_symbol; + break; + } + } + return sb_skip_white (idx, string); +} + +static int +level_4 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + exp_t rhs; + + idx = level_3 (idx, string, lhs); + + while (idx < string->len && + string->ptr[idx] == '&') + { + char op = string->ptr[idx++]; + idx = level_3 (idx, string, &rhs); + switch (op) + { + case '&': + checkconst ('&', lhs); + checkconst ('&', &rhs); + lhs->value &= rhs.value; + break; + } + } + return sb_skip_white (idx, string); +} + +static int +level_5 (idx, string, lhs) + int idx; + sb *string; + exp_t *lhs; +{ + exp_t rhs; + + idx = level_4 (idx, string, lhs); + + while (idx < string->len + && (string->ptr[idx] == '|' || string->ptr[idx] == '~')) + { + char op = string->ptr[idx++]; + idx = level_4 (idx, string, &rhs); + switch (op) + { + case '|': + checkconst ('|', lhs); + checkconst ('|', &rhs); + lhs->value |= rhs.value; + break; + case '~': + checkconst ('~', lhs); + checkconst ('~', &rhs); + lhs->value ^= rhs.value; + break; + } + } + return sb_skip_white (idx, string); +} + + +/* parse the expression at offset idx into string, fill up res with + the result. return the index of the first char past the expression. + */ + +static int +exp_parse (idx, string, res) + int idx; + sb *string; + exp_t *res; +{ + return level_5 (sb_skip_white (idx, string), string, res); +} + + +/* turn the expression at exp into text and glue it onto the end of + string. */ + +static void +exp_string (exp, string) + exp_t *exp; + sb *string; +{ + int np = 0; + int ad = 0; + sb_reset (string); + + if (exp->add_symbol.len) + { + sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len); + np = 1; + ad = 1; + } + if (exp->value) + { + char buf[20]; + if (np) + sb_add_char (string, '+'); + sprintf (buf, "%d", exp->value); + sb_add_string (string, buf); + np = 1; + ad = 1; + } + if (exp->sub_symbol.len) + { + sb_add_char (string, '-'); + sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len); + np = 0; + ad = 1; + } + + if (!ad) + sb_add_char (string, '0'); +} + + +/* parse the expression at offset idx into sb in, return the value in val. + if the expression is not constant, give ERROR emsg. returns the index + of the first character past the end of the expression. */ + +static int +exp_get_abs (emsg, idx, in, val) + const char *emsg; + int idx; + sb *in; + int *val; +{ + exp_t res; + idx = exp_parse (idx, in, &res); + if (res.add_symbol.len || res.sub_symbol.len) + ERROR ((stderr, emsg)); + *val = res.value; + return idx; +} + + +sb label; /* current label parsed from line */ +hash_table assign_hash_table; /* hash table for all assigned variables */ +hash_table keyword_hash_table; /* hash table for keyword */ +hash_table vars; /* hash table for eq variables */ + +#define in_comment ';' + +#if 0 +static void +strip_comments (out) + sb *out; +{ + char *s = out->ptr; + int i = 0; + for (i = 0; i < out->len; i++) + { + if (ISCOMMENTCHAR(s[i])) + { + out->len = i; + return; + } + } +} +#endif + +/* push back character ch so that it can be read again. */ + +static void +unget (ch) + int ch; +{ + if (ch == '\n') + { + sp->linecount--; + } + if (sp->pushback_index) + sp->pushback_index--; + else + sb_add_char (&sp->pushback, ch); +} + +/* push the sb ptr onto the include stack, with the given name, type and index. */ + +static +void +include_buf (name, ptr, type, index) + sb *name; + sb *ptr; + include_type type; + int index; +{ + sp++; + if (sp - include_stack >= MAX_INCLUDES) + FATAL ((stderr, "unreasonable nesting.\n")); + sb_new (&sp->name); + sb_add_sb (&sp->name, name); + sp->handle = 0; + sp->linecount = 1; + sp->pushback_index = 0; + sp->type = type; + sp->index = index; + sb_new (&sp->pushback); + sb_add_sb (&sp->pushback, ptr); +} + + +/* used in ERROR messages, print info on where the include stack is onto file. */ +static +void +include_print_where_line (file) + FILE *file; +{ + struct include_stack *p = include_stack + 1; + + while (p <= sp) + { + fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - 1); + p++; + } +} + +/* used in listings, print the line number onto file. */ +static void +include_print_line (file) + FILE *file; +{ + int n; + struct include_stack *p = include_stack + 1; + + n = fprintf (file, "%4d", p->linecount); + p++; + while (p <= sp) + { + n += fprintf (file, ".%d", p->linecount); + p++; + } + while (n < 8 * 3) + { + fprintf (file, " "); + n++; + } +} + + +/* read a line from the top of the include stack into sb in. */ + +static int +get_line (in) + sb *in; +{ + int online = 0; + int more = 1; + + if (copysource) + { + putc (comment_char, outfile); + if (print_line_number) + include_print_line (outfile); + } + + while (1) + { + int ch = get (); + + while (ch == '\r') + ch = get (); + + if (ch == EOF) + { + if (online) + { + WARNING ((stderr, "End of file not at start of line.\n")); + if (copysource) + putc ('\n', outfile); + ch = '\n'; + } + else + more = 0; + break; + } + + if (copysource) + { + putc (ch, outfile); + } + + if (ch == '\n') + { + ch = get (); + online = 0; + if (ch == '+') + { + /* continued line */ + if (copysource) + { + putc (comment_char, outfile); + putc ('+', outfile); + } + ch = get (); + } + else + { + if (ch != EOF) + unget (ch); + break; + } + } + else + { + sb_add_char (in, ch); + } + online++; + } + + return more; +} + +/* find a label from sb in and put it in out. */ + +static int +grab_label (in, out) + sb *in; + sb *out; +{ + int i = 0; + sb_reset (out); + if (ISFIRSTCHAR (in->ptr[i])) + { + sb_add_char (out, in->ptr[i]); + i++; + while ((ISNEXTCHAR (in->ptr[i]) + || in->ptr[i] == '\\' + || in->ptr[i] == '&') + && i < in->len) + { + sb_add_char (out, in->ptr[i]); + i++; + } + } + return i; +} + +/* find all strange base stuff and turn into decimal. also + find all the other numbers and convert them from the default radix */ + +static void +change_base (idx, in, out) + int idx; + sb *in; + sb *out; +{ + char buffer[20]; + + while (idx < in->len) + { + if (in->ptr[idx] == '\\' + && idx + 1 < in->len + && in->ptr[idx + 1] == '(') + { + idx += 2; + while (idx < in->len + && in->ptr[idx] != ')') + { + sb_add_char (out, in->ptr[idx]); + idx++; + } + if (idx < in->len) + idx++; + } + else if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri) + { + int base; + int value; + switch (in->ptr[idx]) + { + case 'b': + case 'B': + base = 2; + break; + case 'q': + case 'Q': + base = 8; + break; + case 'h': + case 'H': + base = 16; + break; + case 'd': + case 'D': + base = 10; + break; + default: + ERROR ((stderr, "Illegal base character %c.\n", in->ptr[idx])); + base = 10; + break; + } + + idx = sb_strtol (idx + 2, in, base, &value); + sprintf (buffer, "%d", value); + sb_add_string (out, buffer); + } + else if (ISFIRSTCHAR (in->ptr[idx])) + { + /* copy entire names through quickly */ + sb_add_char (out, in->ptr[idx]); + idx++; + while (idx < in->len && ISNEXTCHAR (in->ptr[idx])) + { + sb_add_char (out, in->ptr[idx]); + idx++; + } + } + else if (isdigit (in->ptr[idx])) + { + int value; + /* all numbers must start with a digit, let's chew it and + spit out decimal */ + idx = sb_strtol (idx, in, radix, &value); + sprintf (buffer, "%d", value); + sb_add_string (out, buffer); + + /* skip all undigsested letters */ + while (idx < in->len && ISNEXTCHAR (in->ptr[idx])) + { + sb_add_char (out, in->ptr[idx]); + idx++; + } + } + else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + /* copy entire names through quickly */ + sb_add_char (out, in->ptr[idx]); + idx++; + while (idx < in->len && in->ptr[idx] != tchar) + { + sb_add_char (out, in->ptr[idx]); + idx++; + } + } + else + { + /* nothing special, just pass it through */ + sb_add_char (out, in->ptr[idx]); + idx++; + } + } + +} + +/* .end */ +static void +do_end (in) + sb *in; +{ + had_end = 1; + if (mri) + fprintf (outfile, "%s\n", sb_name (in)); +} + +/* .assign */ + +static void +do_assign (again, idx, in) + int again; + int idx; + sb *in; +{ + /* stick label in symbol table with following value */ + exp_t e; + sb acc; + + sb_new (&acc); + idx = exp_parse (idx, in, &e); + exp_string (&e, &acc); + hash_add_to_string_table (&assign_hash_table, &label, &acc, again); + sb_kill (&acc); +} + + +/* .radix [b|q|d|h] */ + +static +void +do_radix (ptr) + sb *ptr; +{ + int idx = sb_skip_white (0, ptr); + switch (ptr->ptr[idx]) + { + case 'B': + case 'b': + radix = 2; + break; + case 'q': + case 'Q': + radix = 8; + break; + case 'd': + case 'D': + radix = 10; + break; + case 'h': + case 'H': + radix = 16; + break; + default: + ERROR ((stderr, "radix is %c must be one of b, q, d or h", radix)); + } +} + + +/* Parse off a .b, .w or .l */ + +static int +get_opsize (idx, in, size) + int idx; + sb *in; + int *size; +{ + *size = 4; + if (in->ptr[idx] == '.') + { + idx++; + } + switch (in->ptr[idx]) + { + case 'b': + case 'B': + *size = 1; + break; + case 'w': + case 'W': + *size = 2; + break; + case 'l': + case 'L': + *size = 4; + break; + case ' ': + case '\t': + break; + default: + ERROR ((stderr, "size must be one of b, w or l, is %c.\n", in->ptr[idx])); + break; + } + idx++; + + return idx; +} + +static +int eol(idx, line) + int idx; + sb *line; +{ + idx = sb_skip_white (idx, line); + if (idx < line->len + && ISCOMMENTCHAR(line->ptr[idx])) + return 1; + if (idx >= line->len) + return 1; + return 0; +} + +/* .data [.b|.w|.l] <data>* + or d[bwl] <data>* */ + +static void +do_data (idx, in, size) + int idx; + sb *in; + int size; +{ + int opsize = 4; + char *opname = ".yikes!"; + sb acc; + sb_new (&acc); + + if (!size) + { + idx = get_opsize (idx, in, &opsize); + } + else { + opsize = size; + } + switch (opsize) + { + case 4: + opname = ".long"; + break; + case 2: + opname = ".short"; + break; + case 1: + opname = ".byte"; + break; + } + + + fprintf (outfile, "%s\t", opname); + + idx = sb_skip_white (idx, in); + + if (alternate + && idx < in->len + && in->ptr[idx] == '"') + { + int i; + idx = getstring (idx, in, &acc); + for (i = 0; i < acc.len; i++) + { + if (i) + fprintf(outfile,","); + fprintf (outfile, "%d", acc.ptr[i]); + } + } + else + { + while (!eol (idx, in)) + { + exp_t e; + idx = exp_parse (idx, in, &e); + exp_string (&e, &acc); + sb_add_char (&acc, 0); + fprintf (outfile, acc.ptr); + if (idx < in->len && in->ptr[idx] == ',') + { + fprintf (outfile, ","); + idx++; + } + } + } + sb_kill (&acc); + sb_print_at (outfile, idx, in); + fprintf (outfile, "\n"); +} + +/* .datab [.b|.w|.l] <repeat>,<fill> */ + +static void +do_datab (idx, in) + int idx; + sb *in; +{ + int opsize; + int repeat; + int fill; + + idx = get_opsize (idx, in, &opsize); + + idx = exp_get_abs ("datab repeat must be constant.\n", idx, in, &repeat); + idx = sb_skip_comma (idx, in); + idx = exp_get_abs ("datab data must be absolute.\n", idx, in, &fill); + + fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill); +} + +/* .align <size> */ + +static void +do_align (idx, in) + int idx; + sb *in; +{ + int al, have_fill, fill; + + idx = exp_get_abs ("align needs absolute expression.\n", idx, in, &al); + idx = sb_skip_white (idx, in); + have_fill = 0; + fill = 0; + if (! eol (idx, in)) + { + idx = sb_skip_comma (idx, in); + idx = exp_get_abs (".align needs absolute fill value.\n", idx, in, + &fill); + have_fill = 1; + } + + if (al != 1 + && al != 2 + && al != 4) + WARNING ((stderr, "alignment must be one of 1, 2 or 4.\n")); + + fprintf (outfile, ".align %d", al); + if (have_fill) + fprintf (outfile, ",%d", fill); + fprintf (outfile, "\n"); +} + +/* .res[.b|.w|.l] <size> */ + +static void +do_res (idx, in, type) + int idx; + sb *in; + int type; +{ + int size = 4; + int count = 0; + + idx = get_opsize (idx, in, &size); + while (!eol(idx, in)) + { + idx = sb_skip_white (idx, in); + if (in->ptr[idx] == ',') + idx++; + idx = exp_get_abs ("res needs absolute expression for fill count.\n", idx, in, &count); + + if (type == 'c' || type == 'z') + count++; + + fprintf (outfile, ".space %d\n", count * size); + } +} + + +/* .export */ + +static void +do_export (in) + sb *in; +{ + fprintf (outfile, ".global %s\n", sb_name (in)); +} + +/* .print [list] [nolist] */ + +static void +do_print (idx, in) + int idx; + sb *in; +{ + idx = sb_skip_white (idx, in); + while (idx < in->len) + { + if (strncasecmp (in->ptr + idx, "LIST", 4) == 0) + { + fprintf (outfile, ".list\n"); + idx += 4; + } + else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0) + { + fprintf (outfile, ".nolist\n"); + idx += 6; + } + idx++; + } +} + +/* .head */ +static void +do_heading (idx, in) + int idx; + sb *in; +{ + sb head; + sb_new (&head); + idx = getstring (idx, in, &head); + fprintf (outfile, ".title \"%s\"\n", sb_name (&head)); + sb_kill (&head); +} + +/* .page */ + +static void +do_page () +{ + fprintf (outfile, ".eject\n"); +} + +/* .form [lin=<value>] [col=<value>] */ +static void +do_form (idx, in) + int idx; + sb *in; +{ + int lines = 60; + int columns = 132; + idx = sb_skip_white (idx, in); + + while (idx < in->len) + { + + if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0) + { + idx += 4; + idx = exp_get_abs ("form LIN= needs absolute expresssion.\n", idx, in, &lines); + } + + if (strncasecmp (in->ptr + idx, "COL=", 4) == 0) + { + idx += 4; + idx = exp_get_abs ("form COL= needs absolute expresssion.\n", idx, in, &columns); + } + + idx++; + } + fprintf (outfile, ".psize %d,%d\n", lines, columns); + +} + + +/* Fetch string from the input stream, + rules: + 'Bxyx<whitespace> -> return 'Bxyza + %<char> -> return string of decimal value of x + "<string>" -> return string + xyx<whitespace> -> return xyz +*/ +static int +get_any_string (idx, in, out, expand, pretend_quoted) + int idx; + sb *in; + sb *out; + int expand; + int pretend_quoted; +{ + sb_reset (out); + idx = sb_skip_white (idx, in); + + if (idx < in->len) + { + if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx])) + { + while (!ISSEP (in->ptr[idx])) + sb_add_char (out, in->ptr[idx++]); + } + else if (in->ptr[idx] == '%' + && alternate + && expand) + { + int val; + char buf[20]; + /* Turns the next expression into a string */ + idx = exp_get_abs ("% operator needs absolute expression", + idx + 1, + in, + &val); + sprintf(buf, "%d", val); + sb_add_string (out, buf); + } + else if (in->ptr[idx] == '"' + || in->ptr[idx] == '<' + || (alternate && in->ptr[idx] == '\'')) + { + if (alternate && expand) + { + /* Keep the quotes */ + sb_add_char (out, '\"'); + + idx = getstring (idx, in, out); + sb_add_char (out, '\"'); + + } + else { + idx = getstring (idx, in, out); + } + } + else + { + while (idx < in->len + && (in->ptr[idx] == '"' + || in->ptr[idx] == '\'' + || pretend_quoted + || !ISSEP (in->ptr[idx]))) + { + if (in->ptr[idx] == '"' + || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + sb_add_char (out, in->ptr[idx++]); + while (idx < in->len + && in->ptr[idx] != tchar) + sb_add_char (out, in->ptr[idx++]); + if (idx == in->len) + return idx; + } + sb_add_char (out, in->ptr[idx++]); + } + } + } + + return idx; +} + + +/* skip along sb in starting at idx, suck off whitespace a ( and more + whitespace. return the idx of the next char */ + +static int +skip_openp (idx, in) + int idx; + sb *in; +{ + idx = sb_skip_white (idx, in); + if (in->ptr[idx] != '(') + ERROR ((stderr, "misplaced ( .\n")); + idx = sb_skip_white (idx + 1, in); + return idx; +} + +/* skip along sb in starting at idx, suck off whitespace a ) and more + whitespace. return the idx of the next char */ + +static int +skip_closep (idx, in) + int idx; + sb *in; +{ + idx = sb_skip_white (idx, in); + if (in->ptr[idx] != ')') + ERROR ((stderr, "misplaced ).\n")); + idx = sb_skip_white (idx + 1, in); + return idx; +} + +/* .len */ + +static int +dolen (idx, in, out) + int idx; + sb *in; + sb *out; +{ + + sb stringout; + char buffer[10]; + + sb_new (&stringout); + idx = skip_openp (idx, in); + idx = get_and_process (idx, in, &stringout); + idx = skip_closep (idx, in); + sprintf (buffer, "%d", stringout.len); + sb_add_string (out, buffer); + + sb_kill (&stringout); + return idx; +} + + +/* .instr */ + +static +int +doinstr (idx, in, out) + int idx; + sb *in; + sb *out; +{ + sb string; + sb search; + int i; + int start; + int res; + char buffer[10]; + + sb_new (&string); + sb_new (&search); + idx = skip_openp (idx, in); + idx = get_and_process (idx, in, &string); + idx = sb_skip_comma (idx, in); + idx = get_and_process (idx, in, &search); + idx = sb_skip_comma (idx, in); + if (isdigit (in->ptr[idx])) + { + idx = exp_get_abs (".instr needs absolute expresson.\n", idx, in, &start); + } + else + { + start = 0; + } + idx = skip_closep (idx, in); + res = -1; + for (i = start; i < string.len; i++) + { + if (strncmp (string.ptr + i, search.ptr, search.len) == 0) + { + res = i; + break; + } + } + sprintf (buffer, "%d", res); + sb_add_string (out, buffer); + sb_kill (&string); + sb_kill (&search); + return idx; +} + + +static int +dosubstr (idx, in, out) + int idx; + sb *in; + sb *out; +{ + sb string; + int pos; + int len; + sb_new (&string); + + idx = skip_openp (idx, in); + idx = get_and_process (idx, in, &string); + idx = sb_skip_comma (idx, in); + idx = exp_get_abs ("need absolute position.\n", idx, in, &pos); + idx = sb_skip_comma (idx, in); + idx = exp_get_abs ("need absolute length.\n", idx, in, &len); + idx = skip_closep (idx, in); + + + if (len < 0 || pos < 0 || + pos > string.len + || pos + len > string.len) + { + sb_add_string (out, " "); + } + else + { + sb_add_char (out, '"'); + while (len > 0) + { + sb_add_char (out, string.ptr[pos++]); + len--; + } + sb_add_char (out, '"'); + } + sb_kill(&string); + return idx; +} + +/* scan line, change tokens in the hash table to their replacements */ +static void +process_assigns (idx, in, buf) + int idx; + sb *in; + sb *buf; +{ + while (idx < in->len) + { + hash_entry *ptr; + if (in->ptr[idx] == '\\' + && idx + 1 < in->len + && in->ptr[idx + 1] == '(') + { + do + { + sb_add_char (buf, in->ptr[idx]); + idx++; + } + while (idx < in->len && in->ptr[idx - 1] != ')'); + } + else if (in->ptr[idx] == '\\' + && idx + 1 < in->len + && in->ptr[idx + 1] == '&') + { + idx = condass_lookup_name (in, idx + 2, buf, 1); + } + else if (in->ptr[idx] == '\\' + && idx + 1 < in->len + && in->ptr[idx + 1] == '$') + { + idx = condass_lookup_name (in, idx + 2, buf, 0); + } + else if (idx + 3 < in->len + && in->ptr[idx] == '.' + && toupper ((unsigned char) in->ptr[idx + 1]) == 'L' + && toupper ((unsigned char) in->ptr[idx + 2]) == 'E' + && toupper ((unsigned char) in->ptr[idx + 3]) == 'N') + idx = dolen (idx + 4, in, buf); + else if (idx + 6 < in->len + && in->ptr[idx] == '.' + && toupper ((unsigned char) in->ptr[idx + 1]) == 'I' + && toupper ((unsigned char) in->ptr[idx + 2]) == 'N' + && toupper ((unsigned char) in->ptr[idx + 3]) == 'S' + && toupper ((unsigned char) in->ptr[idx + 4]) == 'T' + && toupper ((unsigned char) in->ptr[idx + 5]) == 'R') + idx = doinstr (idx + 6, in, buf); + else if (idx + 7 < in->len + && in->ptr[idx] == '.' + && toupper ((unsigned char) in->ptr[idx + 1]) == 'S' + && toupper ((unsigned char) in->ptr[idx + 2]) == 'U' + && toupper ((unsigned char) in->ptr[idx + 3]) == 'B' + && toupper ((unsigned char) in->ptr[idx + 4]) == 'S' + && toupper ((unsigned char) in->ptr[idx + 5]) == 'T' + && toupper ((unsigned char) in->ptr[idx + 6]) == 'R') + idx = dosubstr (idx + 7, in, buf); + else if (ISFIRSTCHAR (in->ptr[idx])) + { + /* may be a simple name subsitution, see if we have a word */ + sb acc; + int cur = idx + 1; + while (cur < in->len + && (ISNEXTCHAR (in->ptr[cur]))) + cur++; + + sb_new (&acc); + sb_add_buffer (&acc, in->ptr + idx, cur - idx); + ptr = hash_lookup (&assign_hash_table, &acc); + if (ptr) + { + /* Found a definition for it */ + sb_add_sb (buf, &ptr->value.s); + } + else + { + /* No definition, just copy the word */ + sb_add_sb (buf, &acc); + } + sb_kill (&acc); + idx = cur; + } + else + { + sb_add_char (buf, in->ptr[idx++]); + } + } +} + +static int +get_and_process (idx, in, out) + int idx; + sb *in; + sb *out; +{ + sb t; + sb_new (&t); + idx = get_any_string (idx, in, &t, 1, 0); + process_assigns (0, &t, out); + sb_kill (&t); + return idx; +} + +static +void +process_file () +{ + sb line; + sb t1, t2; + sb acc; + sb label_in; + int more; + + sb_new (&line); + sb_new (&t1); + sb_new (&t2); + sb_new(&acc); + sb_new (&label_in); + sb_reset (&line); + more = get_line (&line); + while (more) + { + /* Find any label and pseudo op that we're intested in */ + int l; + if (line.len == 0) + { + if (condass_on ()) + fprintf (outfile, "\n"); + } + else if (mri + && (line.ptr[0] == '*' + || line.ptr[0] == '!')) + { + /* MRI line comment. */ + fprintf (outfile, sb_name (&line)); + } + else + { + l = grab_label (&line, &label_in); + sb_reset (&label); + + if (line.ptr[l] == ':') + l++; + while (ISWHITE (line.ptr[l]) && l < line.len) + l++; + + if (label_in.len) + { + int do_assigns; + + /* Munge the label, unless this is EQU or ASSIGN. */ + do_assigns = 1; + if (l < line.len + && (line.ptr[l] == '.' || alternate || mri)) + { + int lx = l; + + if (line.ptr[lx] == '.') + ++lx; + if (lx + 3 <= line.len + && strncasecmp ("EQU", line.ptr + lx, 3) == 0 + && (lx + 3 == line.len + || ! ISFIRSTCHAR (line.ptr[lx + 3]))) + do_assigns = 0; + else if (lx + 6 <= line.len + && strncasecmp ("ASSIGN", line.ptr + lx, 6) == 0 + && (lx + 6 == line.len + || ! ISFIRSTCHAR (line.ptr[lx + 6]))) + do_assigns = 0; + } + + if (do_assigns) + process_assigns (0, &label_in, &label); + else + sb_add_sb (&label, &label_in); + } + + if (l < line.len) + { + if (process_pseudo_op (l, &line, &acc)) + { + + + + } + else if (condass_on ()) + { + if (macro_op (l, &line)) + { + + + } + else + { + { + if (label.len) + { + fprintf (outfile, "%s:\t", sb_name (&label)); + } + else + fprintf (outfile, "\t"); + sb_reset(&t1); + process_assigns (l, &line, &t1); + sb_reset (&t2); + change_base (0, &t1, &t2); + fprintf (outfile, "%s\n", sb_name (&t2)); + } + } + } + } + else { + /* Only a label on this line */ + if (label.len && condass_on()) + { + fprintf (outfile, "%s:\n", sb_name (&label)); + } + } + } + + if (had_end) + break; + sb_reset (&line); + more = get_line (&line); + } + + if (!had_end && !mri) + WARNING ((stderr, "END missing from end of file.\n")); +} + + + + + +static void +free_old_entry (ptr) + hash_entry *ptr; +{ + if (ptr) + { + if (ptr->type == hash_string) + sb_kill(&ptr->value.s); + } +} + +/* name: .ASSIGNA <value> */ + +static void +do_assigna (idx, in) + int idx; + sb *in; +{ + sb tmp; + int val; + sb_new (&tmp); + + process_assigns (idx, in, &tmp); + idx = exp_get_abs (".ASSIGNA needs constant expression argument.\n", 0, &tmp, &val); + + if (!label.len) + { + ERROR ((stderr, ".ASSIGNA without label.\n")); + } + else + { + hash_entry *ptr = hash_create (&vars, &label); + free_old_entry (ptr); + ptr->type = hash_integer; + ptr->value.i = val; + } + sb_kill (&tmp); +} + +/* name: .ASSIGNC <string> */ + +static void +do_assignc (idx, in) + int idx; + sb *in; +{ + sb acc; + sb_new (&acc); + idx = getstring (idx, in, &acc); + + if (!label.len) + { + ERROR ((stderr, ".ASSIGNS without label.\n")); + } + else + { + hash_entry *ptr = hash_create (&vars, &label); + free_old_entry (ptr); + ptr->type = hash_string; + sb_new (&ptr->value.s); + sb_add_sb (&ptr->value.s, &acc); + } + sb_kill (&acc); +} + + +/* name: .REG (reg) */ + +static void +do_reg (idx, in) + int idx; + sb *in; +{ + /* remove reg stuff from inside parens */ + sb what; + if (!mri) + idx = skip_openp (idx, in); + else + idx = sb_skip_white (idx, in); + sb_new (&what); + while (idx < in->len + && (mri + ? ! eol (idx, in) + : in->ptr[idx] != ')')) + { + sb_add_char (&what, in->ptr[idx]); + idx++; + } + hash_add_to_string_table (&assign_hash_table, &label, &what, 1); + sb_kill (&what); +} + + +static int +condass_lookup_name (inbuf, idx, out, warn) + sb *inbuf; + int idx; + sb *out; + int warn; +{ + hash_entry *ptr; + sb condass_acc; + sb_new (&condass_acc); + + while (idx < inbuf->len + && ISNEXTCHAR (inbuf->ptr[idx])) + { + sb_add_char (&condass_acc, inbuf->ptr[idx++]); + } + + if (inbuf->ptr[idx] == '\'') + idx++; + ptr = hash_lookup (&vars, &condass_acc); + + + if (!ptr) + { + if (warn) + { + WARNING ((stderr, "Can't find preprocessor variable %s.\n", sb_name (&condass_acc))); + } + else + { + sb_add_string (out, "0"); + } + } + else + { + if (ptr->type == hash_integer) + { + char buffer[30]; + sprintf (buffer, "%d", ptr->value.i); + sb_add_string (out, buffer); + } + else + { + sb_add_sb (out, &ptr->value.s); + } + } + sb_kill (&condass_acc); + return idx; +} + +#define EQ 1 +#define NE 2 +#define GE 3 +#define LT 4 +#define LE 5 +#define GT 6 +#define NEVER 7 + +static int +whatcond (idx, in, val) + int idx; + sb *in; + int *val; +{ + int cond; + + idx = sb_skip_white (idx, in); + cond = NEVER; + if (idx + 1 < in->len) + { + char *p; + char a, b; + + p = in->ptr + idx; + a = toupper ((unsigned char) p[0]); + b = toupper ((unsigned char) p[1]); + if (a == 'E' && b == 'Q') + cond = EQ; + else if (a == 'N' && b == 'E') + cond = NE; + else if (a == 'L' && b == 'T') + cond = LT; + else if (a == 'L' && b == 'E') + cond = LE; + else if (a == 'G' && b == 'T') + cond = GT; + else if (a == 'G' && b == 'E') + cond = GE; + } + if (cond == NEVER) + { + ERROR ((stderr, "Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n")); + cond = NEVER; + } + idx = sb_skip_white (idx + 2, in); + *val = cond; + return idx; +} + +static int +istrue (idx, in) + int idx; + sb *in; +{ + int res; + sb acc_a; + sb cond; + sb acc_b; + sb_new (&acc_a); + sb_new (&cond); + sb_new (&acc_b); + idx = sb_skip_white (idx, in); + + if (in->ptr[idx] == '"') + { + int cond; + int same; + /* This is a string comparision */ + idx = getstring (idx, in, &acc_a); + idx = whatcond (idx, in, &cond); + idx = getstring (idx, in, &acc_b); + same = acc_a.len == acc_b.len && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0); + + if (cond != EQ && cond != NE) + { + ERROR ((stderr, "Comparison operator for strings must be EQ or NE\n")); + res = 0; + } + else + res = (cond != EQ) ^ same; + } + else + /* This is a numeric expression */ + { + int vala; + int valb; + int cond; + idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &vala); + idx = whatcond (idx, in, &cond); + idx = sb_skip_white (idx, in); + if (in->ptr[idx] == '"') + { + WARNING ((stderr, "String compared against expression.\n")); + res = 0; + } + else + { + idx = exp_get_abs ("Conditional operator must have absolute operands.\n", idx, in, &valb); + switch (cond) + { + default: + res = 42; + break; + case EQ: + res = vala == valb; + break; + case NE: + res = vala != valb; + break; + case LT: + res = vala < valb; + break; + case LE: + res = vala <= valb; + break; + case GT: + res = vala > valb; + break; + case GE: + res = vala >= valb; + break; + case NEVER: + res = 0; + break; + } + } + } + + sb_kill (&acc_a); + sb_kill (&cond); + sb_kill (&acc_b); + return res; +} + +/* .AIF */ +static void +do_aif (idx, in) + int idx; + sb *in; +{ + if (ifi >= IFNESTING) + { + FATAL ((stderr, "AIF nesting unreasonable.\n")); + } + ifi++; + ifstack[ifi].on = ifstack[ifi-1].on ? istrue (idx, in) : 0; + ifstack[ifi].hadelse = 0; +} + + +/* .AELSE */ +static void +do_aelse () +{ + ifstack[ifi].on = ifstack[ifi-1].on ? !ifstack[ifi].on : 0; + if (ifstack[ifi].hadelse) + { + ERROR ((stderr, "Multiple AELSEs in AIF.\n")); + } + ifstack[ifi].hadelse = 1; +} + + +/* .AENDI */ +static void +do_aendi () +{ + if (ifi != 0) + { + ifi--; + } + else + { + ERROR ((stderr, "AENDI without AIF.\n")); + } +} + +static int +condass_on () +{ + return ifstack[ifi].on; +} + +/* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT. */ + +static void +do_if (idx, in, cond) + int idx; + sb *in; + int cond; +{ + int val; + int res; + + if (ifi >= IFNESTING) + { + FATAL ((stderr, "IF nesting unreasonable.\n")); + } + + idx = exp_get_abs ("Conditional operator must have absolute operands.\n", + idx, in, &val); + switch (cond) + { + default: + case EQ: res = val == 0; break; + case NE: res = val != 0; break; + case LT: res = val < 0; break; + case LE: res = val <= 0; break; + case GE: res = val >= 0; break; + case GT: res = val > 0; break; + } + + ifi++; + ifstack[ifi].on = ifstack[ifi-1].on ? res: 0; + ifstack[ifi].hadelse = 0; +} + +/* Get a string for the MRI IFC or IFNC pseudo-ops. */ + +static int +get_mri_string (idx, in, val, terminator) + int idx; + sb *in; + sb *val; + int terminator; +{ + idx = sb_skip_white (idx, in); + + if (idx < in->len + && in->ptr[idx] == '\'') + { + sb_add_char (val, '\''); + for (++idx; idx < in->len; ++idx) + { + sb_add_char (val, in->ptr[idx]); + if (in->ptr[idx] == '\'') + { + ++idx; + if (idx >= in->len + || in->ptr[idx] != '\'') + break; + } + } + idx = sb_skip_white (idx, in); + } + else + { + int i; + + while (idx < in->len + && in->ptr[idx] != terminator) + { + sb_add_char (val, in->ptr[idx]); + ++idx; + } + i = val->len - 1; + while (i >= 0 && ISWHITE (val->ptr[i])) + --i; + val->len = i + 1; + } + + return idx; +} + +/* MRI IFC, IFNC. */ + +static void +do_ifc (idx, in, ifnc) + int idx; + sb *in; + int ifnc; +{ + sb first; + sb second; + int res; + + if (ifi >= IFNESTING) + { + FATAL ((stderr, "IF nesting unreasonable.\n")); + } + + sb_new (&first); + sb_new (&second); + + idx = get_mri_string (idx, in, &first, ','); + + if (idx >= in->len || in->ptr[idx] != ',') + { + ERROR ((stderr, "Bad format for IF or IFNC.\n")); + return; + } + + idx = get_mri_string (idx + 1, in, &second, ';'); + + res = (first.len == second.len + && strncmp (first.ptr, second.ptr, first.len) == 0); + res ^= ifnc; + + ifi++; + ifstack[ifi].on = ifstack[ifi-1].on ? res : 0; + ifstack[ifi].hadelse = 0; +} + +/* .ENDR */ +static void +do_aendr () +{ + if (!mri) + ERROR ((stderr, "AENDR without a AREPEAT.\n")); + else + ERROR ((stderr, "ENDR without a REPT.\n")); +} + +/* .AWHILE */ + +static +void +do_awhile (idx, in) + int idx; + sb *in; +{ + int line = linecount (); + sb exp; + sb sub; + int doit; + + sb_new (&sub); + sb_new (&exp); + + process_assigns (idx, in, &exp); + doit = istrue (0, &exp); + + if (! buffer_and_nest ("AWHILE", "AENDW", &sub, get_line)) + FATAL ((stderr, "AWHILE without a AENDW at %d.\n", line - 1)); + + /* Turn + .AWHILE exp + foo + .AENDW + into + foo + .AWHILE exp + foo + .ENDW + */ + + if (doit) + { + int index = include_next_index (); + + sb copy; + sb_new (©); + sb_add_sb (©, &sub); + sb_add_sb (©, in); + sb_add_string (©, "\n"); + sb_add_sb (©, &sub); + sb_add_string (©, "\t.AENDW\n"); + /* Push another WHILE */ + include_buf (&exp, ©, include_while, index); + sb_kill (©); + } + sb_kill (&exp); + sb_kill (&sub); +} + + +/* .AENDW */ + +static void +do_aendw () +{ + ERROR ((stderr, "AENDW without a AENDW.\n")); +} + + +/* .EXITM + + Pop things off the include stack until the type and index changes */ + +static void +do_exitm () +{ + include_type type = sp->type; + if (type == include_repeat + || type == include_while + || type == include_macro) + { + int index = sp->index; + include_pop (); + while (sp->index == index + && sp->type == type) + { + include_pop (); + } + } +} + +/* .AREPEAT */ + +static void +do_arepeat (idx, in) + int idx; + sb *in; +{ + int line = linecount (); + sb exp; /* buffer with expression in it */ + sb copy; /* expanded repeat block */ + sb sub; /* contents of AREPEAT */ + int rc; + int ret; + char buffer[30]; + + sb_new (&exp); + sb_new (©); + sb_new (&sub); + process_assigns (idx, in, &exp); + idx = exp_get_abs ("AREPEAT must have absolute operand.\n", 0, &exp, &rc); + if (!mri) + ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line); + else + ret = buffer_and_nest ("REPT", "ENDR", &sub, get_line); + if (! ret) + FATAL ((stderr, "AREPEAT without a AENDR at %d.\n", line - 1)); + if (rc > 0) + { + /* Push back the text following the repeat, and another repeat block + so + .AREPEAT 20 + foo + .AENDR + gets turned into + foo + .AREPEAT 19 + foo + .AENDR + */ + int index = include_next_index (); + sb_add_sb (©, &sub); + if (rc > 1) + { + if (!mri) + sprintf (buffer, "\t.AREPEAT %d\n", rc - 1); + else + sprintf (buffer, "\tREPT %d\n", rc - 1); + sb_add_string (©, buffer); + sb_add_sb (©, &sub); + if (!mri) + sb_add_string (©, " .AENDR\n"); + else + sb_add_string (©, " ENDR\n"); + } + + include_buf (&exp, ©, include_repeat, index); + } + sb_kill (&exp); + sb_kill (&sub); + sb_kill (©); +} + +/* .ENDM */ + +static void +do_endm () +{ + ERROR ((stderr, ".ENDM without a matching .MACRO.\n")); +} + +/* MRI IRP pseudo-op. */ + +static void +do_irp (idx, in, irpc) + int idx; + sb *in; + int irpc; +{ + const char *err; + sb out; + + sb_new (&out); + + err = expand_irp (irpc, idx, in, &out, get_line, comment_char); + if (err != NULL) + ERROR ((stderr, "%s\n", err)); + + fprintf (outfile, "%s", sb_terminate (&out)); + + sb_kill (&out); +} + +/* MACRO PROCESSING */ + +/* Parse off LOCAL n1, n2,... Invent a label name for it */ +static +void +do_local (idx, line) + int idx; + sb *line; +{ + ERROR ((stderr, "LOCAL outside of MACRO")); +} + +static void +do_macro (idx, in) + int idx; + sb *in; +{ + const char *err; + int line = linecount (); + + err = define_macro (idx, in, &label, get_line, (const char **) NULL); + if (err != NULL) + ERROR ((stderr, "macro at line %d: %s\n", line - 1, err)); +} + +static int +macro_op (idx, in) + int idx; + sb *in; +{ + const char *err; + sb out; + sb name; + + if (! macro_defined) + return 0; + + sb_terminate (in); + if (! check_macro (in->ptr + idx, &out, comment_char, &err)) + return 0; + + if (err != NULL) + ERROR ((stderr, "%s\n", err)); + + sb_new (&name); + sb_add_string (&name, "macro expansion"); + + include_buf (&name, &out, include_macro, include_next_index ()); + + sb_kill (&name); + sb_kill (&out); + + return 1; +} + +/* STRING HANDLING */ + +static int +getstring (idx, in, acc) + int idx; + sb *in; + sb *acc; +{ + idx = sb_skip_white (idx, in); + + while (idx < in->len + && (in->ptr[idx] == '"' + || in->ptr[idx] == '<' + || (in->ptr[idx] == '\'' && alternate))) + { + if (in->ptr[idx] == '<') + { + if (alternate || mri) + { + int nest = 0; + idx++; + while ((in->ptr[idx] != '>' || nest) + && idx < in->len) + { + if (in->ptr[idx] == '!') + { + idx++ ; + sb_add_char (acc, in->ptr[idx++]); + } + else { + if (in->ptr[idx] == '>') + nest--; + if (in->ptr[idx] == '<') + nest++; + sb_add_char (acc, in->ptr[idx++]); + } + } + idx++; + } + else { + int code; + idx++; + idx = exp_get_abs ("Character code in string must be absolute expression.\n", + idx, in, &code); + sb_add_char (acc, code); + + if (in->ptr[idx] != '>') + ERROR ((stderr, "Missing > for character code.\n")); + idx++; + } + } + else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + idx++; + while (idx < in->len) + { + if (alternate && in->ptr[idx] == '!') + { + idx++ ; + sb_add_char (acc, in->ptr[idx++]); + } + else { + if (in->ptr[idx] == tchar) + { + idx++; + if (idx >= in->len || in->ptr[idx] != tchar) + break; + } + sb_add_char (acc, in->ptr[idx]); + idx++; + } + } + } + } + + return idx; +} + +/* .SDATA[C|Z] <string> */ + +static +void +do_sdata (idx, in, type) + int idx; + sb *in; + int type; +{ + int nc = 0; + int pidx = -1; + sb acc; + sb_new (&acc); + fprintf (outfile, ".byte\t"); + + while (!eol (idx, in)) + { + int i; + sb_reset (&acc); + idx = sb_skip_white (idx, in); + while (!eol (idx, in)) + { + pidx = idx = get_any_string (idx, in, &acc, 0, 1); + if (type == 'c') + { + if (acc.len > 255) + { + ERROR ((stderr, "string for SDATAC longer than 255 characters (%d).\n", acc.len)); + } + fprintf (outfile, "%d", acc.len); + nc = 1; + } + + for (i = 0; i < acc.len; i++) + { + if (nc) + { + fprintf (outfile, ","); + } + fprintf (outfile, "%d", acc.ptr[i]); + nc = 1; + } + + if (type == 'z') + { + if (nc) + fprintf (outfile, ","); + fprintf (outfile, "0"); + } + idx = sb_skip_comma (idx, in); + if (idx == pidx) break; + } + if (!alternate && in->ptr[idx] != ',' && idx != in->len) + { + fprintf (outfile, "\n"); + ERROR ((stderr, "illegal character in SDATA line (0x%x).\n", in->ptr[idx])); + break; + } + idx++; + } + sb_kill (&acc); + fprintf (outfile, "\n"); +} + +/* .SDATAB <count> <string> */ + +static void +do_sdatab (idx, in) + int idx; + sb *in; +{ + int repeat; + int i; + sb acc; + sb_new (&acc); + + idx = exp_get_abs ("Must have absolute SDATAB repeat count.\n", idx, in, &repeat); + if (repeat <= 0) + { + ERROR ((stderr, "Must have positive SDATAB repeat count (%d).\n", repeat)); + repeat = 1; + } + + idx = sb_skip_comma (idx, in); + idx = getstring (idx, in, &acc); + + for (i = 0; i < repeat; i++) + { + if (i) + fprintf (outfile, "\t"); + fprintf (outfile, ".byte\t"); + sb_print (outfile, &acc); + fprintf (outfile, "\n"); + } + sb_kill (&acc); + +} + +static int +new_file (name) + const char *name; +{ + FILE *newone = fopen (name, "r"); + if (!newone) + return 0; + + if (isp == MAX_INCLUDES) + FATAL ((stderr, "Unreasonable include depth (%ld).\n", (long) isp)); + + sp++; + sp->handle = newone; + + sb_new (&sp->name); + sb_add_string (&sp->name, name); + + sp->linecount = 1; + sp->pushback_index = 0; + sp->type = include_file; + sp->index = 0; + sb_new (&sp->pushback); + return 1; +} + +static void +do_include (idx, in) + int idx; + sb *in; +{ + sb t; + sb cat; + include_path *includes; + + sb_new (&t); + sb_new (&cat); + + if (! mri) + idx = getstring (idx, in, &t); + else + { + idx = sb_skip_white (idx, in); + while (idx < in->len && ! ISWHITE (in->ptr[idx])) + { + sb_add_char (&t, in->ptr[idx]); + ++idx; + } + } + + for (includes = paths_head; includes; includes = includes->next) + { + sb_reset (&cat); + sb_add_sb (&cat, &includes->path); + sb_add_char (&cat, '/'); + sb_add_sb (&cat, &t); + if (new_file (sb_name (&cat))) + { + break; + } + } + if (!includes) + { + if (! new_file (sb_name (&t))) + FATAL ((stderr, "Can't open include file `%s'.\n", sb_name (&t))); + } + sb_kill (&cat); + sb_kill (&t); +} + +static void +include_pop () +{ + if (sp != include_stack) + { + if (sp->handle) + fclose (sp->handle); + sp--; + } +} + +/* Get the next character from the include stack. If there's anything + in the pushback buffer, take that first. If we're at eof, pop from + the stack and try again. Keep the linecount up to date. */ + +static int +get () +{ + int r; + + if (sp->pushback.len != sp->pushback_index) + { + r = (char) (sp->pushback.ptr[sp->pushback_index++]); + /* When they've all gone, reset the pointer */ + if (sp->pushback_index == sp->pushback.len) + { + sp->pushback.len = 0; + sp->pushback_index = 0; + } + } + else if (sp->handle) + { + r = getc (sp->handle); + } + else + r = EOF; + + if (r == EOF && isp) + { + include_pop (); + r = get (); + while (r == EOF && isp) + { + include_pop (); + r = get (); + } + return r; + } + if (r == '\n') + { + sp->linecount++; + } + + return r; +} + +static int +linecount () +{ + return sp->linecount; +} + +static int +include_next_index () +{ + static int index; + if (!unreasonable + && index > MAX_REASONABLE) + FATAL ((stderr, "Unreasonable expansion (-u turns off check).\n")); + return ++index; +} + + +/* Initialize the chartype vector. */ + +static void +chartype_init () +{ + int x; + for (x = 0; x < 256; x++) + { + if (isalpha (x) || x == '_' || x == '$') + chartype[x] |= FIRSTBIT; + + if (mri && x == '.') + chartype[x] |= FIRSTBIT; + + if (isdigit (x) || isalpha (x) || x == '_' || x == '$') + chartype[x] |= NEXTBIT; + + if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';' + || x == '"' || x == '<' || x == '>' || x == ')' || x == '(') + chartype[x] |= SEPBIT; + + if (x == 'b' || x == 'B' + || x == 'q' || x == 'Q' + || x == 'h' || x == 'H' + || x == 'd' || x == 'D') + chartype [x] |= BASEBIT; + + if (x == ' ' || x == '\t') + chartype[x] |= WHITEBIT; + + if (x == comment_char) + chartype[x] |= COMMENTBIT; + } +} + + + +/* What to do with all the keywords */ +#define PROCESS 0x1000 /* Run substitution over the line */ +#define LAB 0x2000 /* Spit out the label */ + +#define K_EQU (PROCESS|1) +#define K_ASSIGN (PROCESS|2) +#define K_REG (PROCESS|3) +#define K_ORG (PROCESS|4) +#define K_RADIX (PROCESS|5) +#define K_DATA (LAB|PROCESS|6) +#define K_DATAB (LAB|PROCESS|7) +#define K_SDATA (LAB|PROCESS|8) +#define K_SDATAB (LAB|PROCESS|9) +#define K_SDATAC (LAB|PROCESS|10) +#define K_SDATAZ (LAB|PROCESS|11) +#define K_RES (LAB|PROCESS|12) +#define K_SRES (LAB|PROCESS|13) +#define K_SRESC (LAB|PROCESS|14) +#define K_SRESZ (LAB|PROCESS|15) +#define K_EXPORT (LAB|PROCESS|16) +#define K_GLOBAL (LAB|PROCESS|17) +#define K_PRINT (LAB|PROCESS|19) +#define K_FORM (LAB|PROCESS|20) +#define K_HEADING (LAB|PROCESS|21) +#define K_PAGE (LAB|PROCESS|22) +#define K_IMPORT (LAB|PROCESS|23) +#define K_PROGRAM (LAB|PROCESS|24) +#define K_END (PROCESS|25) +#define K_INCLUDE (PROCESS|26) +#define K_IGNORED (PROCESS|27) +#define K_ASSIGNA (PROCESS|28) +#define K_ASSIGNC (29) +#define K_AIF (PROCESS|30) +#define K_AELSE (PROCESS|31) +#define K_AENDI (PROCESS|32) +#define K_AREPEAT (PROCESS|33) +#define K_AENDR (PROCESS|34) +#define K_AWHILE (35) +#define K_AENDW (PROCESS|36) +#define K_EXITM (37) +#define K_MACRO (PROCESS|38) +#define K_ENDM (39) +#define K_ALIGN (PROCESS|LAB|40) +#define K_ALTERNATE (41) +#define K_DB (LAB|PROCESS|42) +#define K_DW (LAB|PROCESS|43) +#define K_DL (LAB|PROCESS|44) +#define K_LOCAL (45) +#define K_IFEQ (PROCESS|46) +#define K_IFNE (PROCESS|47) +#define K_IFLT (PROCESS|48) +#define K_IFLE (PROCESS|49) +#define K_IFGE (PROCESS|50) +#define K_IFGT (PROCESS|51) +#define K_IFC (PROCESS|52) +#define K_IFNC (PROCESS|53) +#define K_IRP (PROCESS|54) +#define K_IRPC (PROCESS|55) + + +struct keyword +{ + char *name; + int code; + int extra; +}; + +static struct keyword kinfo[] = +{ + { "EQU", K_EQU, 0 }, + { "ALTERNATE", K_ALTERNATE, 0 }, + { "ASSIGN", K_ASSIGN, 0 }, + { "REG", K_REG, 0 }, + { "ORG", K_ORG, 0 }, + { "RADIX", K_RADIX, 0 }, + { "DATA", K_DATA, 0 }, + { "DB", K_DB, 0 }, + { "DW", K_DW, 0 }, + { "DL", K_DL, 0 }, + { "DATAB", K_DATAB, 0 }, + { "SDATA", K_SDATA, 0 }, + { "SDATAB", K_SDATAB, 0 }, + { "SDATAZ", K_SDATAZ, 0 }, + { "SDATAC", K_SDATAC, 0 }, + { "RES", K_RES, 0 }, + { "SRES", K_SRES, 0 }, + { "SRESC", K_SRESC, 0 }, + { "SRESZ", K_SRESZ, 0 }, + { "EXPORT", K_EXPORT, 0 }, + { "GLOBAL", K_GLOBAL, 0 }, + { "PRINT", K_PRINT, 0 }, + { "FORM", K_FORM, 0 }, + { "HEADING", K_HEADING, 0 }, + { "PAGE", K_PAGE, 0 }, + { "PROGRAM", K_IGNORED, 0 }, + { "END", K_END, 0 }, + { "INCLUDE", K_INCLUDE, 0 }, + { "ASSIGNA", K_ASSIGNA, 0 }, + { "ASSIGNC", K_ASSIGNC, 0 }, + { "AIF", K_AIF, 0 }, + { "AELSE", K_AELSE, 0 }, + { "AENDI", K_AENDI, 0 }, + { "AREPEAT", K_AREPEAT, 0 }, + { "AENDR", K_AENDR, 0 }, + { "EXITM", K_EXITM, 0 }, + { "MACRO", K_MACRO, 0 }, + { "ENDM", K_ENDM, 0 }, + { "AWHILE", K_AWHILE, 0 }, + { "ALIGN", K_ALIGN, 0 }, + { "AENDW", K_AENDW, 0 }, + { "ALTERNATE", K_ALTERNATE, 0 }, + { "LOCAL", K_LOCAL, 0 }, + { NULL, 0, 0 } +}; + +/* Although the conditional operators are handled by gas, we need to + handle them here as well, in case they are used in a recursive + macro to end the recursion. */ + +static struct keyword mrikinfo[] = +{ + { "IFEQ", K_IFEQ, 0 }, + { "IFNE", K_IFNE, 0 }, + { "IFLT", K_IFLT, 0 }, + { "IFLE", K_IFLE, 0 }, + { "IFGE", K_IFGE, 0 }, + { "IFGT", K_IFGT, 0 }, + { "IFC", K_IFC, 0 }, + { "IFNC", K_IFNC, 0 }, + { "ELSEC", K_AELSE, 0 }, + { "ENDC", K_AENDI, 0 }, + { "MEXIT", K_EXITM, 0 }, + { "REPT", K_AREPEAT, 0 }, + { "IRP", K_IRP, 0 }, + { "IRPC", K_IRPC, 0 }, + { "ENDR", K_AENDR, 0 }, + { NULL, 0, 0 } +}; + +/* Look for a pseudo op on the line. If one's there then call + its handler. */ + +static int +process_pseudo_op (idx, line, acc) + int idx; + sb *line; + sb *acc; +{ + int oidx = idx; + + if (line->ptr[idx] == '.' || alternate || mri) + { + /* Scan forward and find pseudo name */ + char *in; + hash_entry *ptr; + + char *s; + char *e; + if (line->ptr[idx] == '.') + idx++; + in = line->ptr + idx; + s = in; + e = s; + sb_reset (acc); + + while (idx < line->len && *e && ISFIRSTCHAR (*e)) + { + sb_add_char (acc, *e); + e++; + idx++; + } + + ptr = hash_lookup (&keyword_hash_table, acc); + + if (!ptr) + { +#if 0 + /* This one causes lots of pain when trying to preprocess + ordinary code */ + WARNING ((stderr, "Unrecognised pseudo op `%s'.\n", sb_name (acc))); +#endif + return 0; + } + if (ptr->value.i & LAB) + { /* output the label */ + if (label.len) + { + fprintf (outfile, "%s:\t", sb_name (&label)); + } + else + fprintf (outfile, "\t"); + } + + if (mri && ptr->value.i == K_END) + { + sb t; + + sb_new (&t); + sb_add_buffer (&t, line->ptr + oidx, idx - oidx); + fprintf (outfile, "\t%s", sb_name (&t)); + sb_kill (&t); + } + + if (ptr->value.i & PROCESS) + { + /* Polish the rest of the line before handling the pseudo op */ +#if 0 + strip_comments(line); +#endif + sb_reset (acc); + process_assigns (idx, line, acc); + sb_reset(line); + change_base (0, acc, line); + idx = 0; + } + if (!condass_on ()) + { + switch (ptr->value.i) + { + case K_AIF: + do_aif (idx, line); + break; + case K_AELSE: + do_aelse (); + break; + case K_AENDI: + do_aendi (); + break; + } + return 1; + } + else + { + switch (ptr->value.i) + { + case K_ALTERNATE: + alternate = 1; + macro_init (1, mri, 0, exp_get_abs); + return 1; + case K_AELSE: + do_aelse (); + return 1; + case K_AENDI: + do_aendi (); + return 1; + case K_ORG: + ERROR ((stderr, "ORG command not allowed.\n")); + break; + case K_RADIX: + do_radix (line); + return 1; + case K_DB: + do_data (idx, line, 1); + return 1; + case K_DW: + do_data (idx, line, 2); + return 1; + case K_DL: + do_data (idx, line, 4); + return 1; + case K_DATA: + do_data (idx, line, 0); + return 1; + case K_DATAB: + do_datab (idx, line); + return 1; + case K_SDATA: + do_sdata (idx, line, 0); + return 1; + case K_SDATAB: + do_sdatab (idx, line); + return 1; + case K_SDATAC: + do_sdata (idx, line, 'c'); + return 1; + case K_SDATAZ: + do_sdata (idx, line, 'z'); + return 1; + case K_ASSIGN: + do_assign (0, 0, line); + return 1; + case K_AIF: + do_aif (idx, line); + return 1; + case K_AREPEAT: + do_arepeat (idx, line); + return 1; + case K_AENDW: + do_aendw (); + return 1; + case K_AWHILE: + do_awhile (idx, line); + return 1; + case K_AENDR: + do_aendr (); + return 1; + case K_EQU: + do_assign (1, idx, line); + return 1; + case K_ALIGN: + do_align (idx, line); + return 1; + case K_RES: + do_res (idx, line, 0); + return 1; + case K_SRES: + do_res (idx, line, 's'); + return 1; + case K_INCLUDE: + do_include (idx, line); + return 1; + case K_LOCAL: + do_local (idx, line); + return 1; + case K_MACRO: + do_macro (idx, line); + return 1; + case K_ENDM: + do_endm (); + return 1; + case K_SRESC: + do_res (idx, line, 'c'); + return 1; + case K_PRINT: + do_print (idx, line); + return 1; + case K_FORM: + do_form (idx, line); + return 1; + case K_HEADING: + do_heading (idx, line); + return 1; + case K_PAGE: + do_page (); + return 1; + case K_GLOBAL: + case K_EXPORT: + do_export (line); + return 1; + case K_IMPORT: + return 1; + case K_SRESZ: + do_res (idx, line, 'z'); + return 1; + case K_IGNORED: + return 1; + case K_END: + do_end (line); + return 1; + case K_ASSIGNA: + do_assigna (idx, line); + return 1; + case K_ASSIGNC: + do_assignc (idx, line); + return 1; + case K_EXITM: + do_exitm (); + return 1; + case K_REG: + do_reg (idx, line); + return 1; + case K_IFEQ: + do_if (idx, line, EQ); + return 1; + case K_IFNE: + do_if (idx, line, NE); + return 1; + case K_IFLT: + do_if (idx, line, LT); + return 1; + case K_IFLE: + do_if (idx, line, LE); + return 1; + case K_IFGE: + do_if (idx, line, GE); + return 1; + case K_IFGT: + do_if (idx, line, GT); + return 1; + case K_IFC: + do_ifc (idx, line, 0); + return 1; + case K_IFNC: + do_ifc (idx, line, 1); + return 1; + case K_IRP: + do_irp (idx, line, 0); + return 1; + case K_IRPC: + do_irp (idx, line, 1); + return 1; + } + } + } + return 0; +} + + + +/* Add a keyword to the hash table. */ + +static void +add_keyword (name, code) + const char *name; + int code; +{ + sb label; + int j; + + sb_new (&label); + sb_add_string (&label, name); + + hash_add_to_int_table (&keyword_hash_table, &label, code); + + sb_reset (&label); + for (j = 0; name[j]; j++) + sb_add_char (&label, name[j] - 'A' + 'a'); + hash_add_to_int_table (&keyword_hash_table, &label, code); + + sb_kill (&label); +} + +/* Build the keyword hash table - put each keyword in the table twice, + once upper and once lower case.*/ + +static void +process_init () +{ + int i; + + for (i = 0; kinfo[i].name; i++) + add_keyword (kinfo[i].name, kinfo[i].code); + + if (mri) + { + for (i = 0; mrikinfo[i].name; i++) + add_keyword (mrikinfo[i].name, mrikinfo[i].code); + } +} + + +static void +do_define (string) + const char *string; +{ + sb label; + int res = 1; + hash_entry *ptr; + sb_new (&label); + + + while (*string) + { + if (*string == '=') + { + sb value; + sb_new (&value); + string++; + while (*string) + { + sb_add_char (&value, *string); + string++; + } + exp_get_abs ("Invalid expression on command line.\n", 0, &value, &res); + sb_kill (&value); + break; + } + sb_add_char (&label, *string); + + string ++; + } + + ptr = hash_create (&vars, &label); + free_old_entry (ptr); + ptr->type = hash_integer; + ptr->value.i = res; + sb_kill (&label); +} +char *program_name; + +/* The list of long options. */ +static struct option long_options[] = +{ + { "alternate", no_argument, 0, 'a' }, + { "include", required_argument, 0, 'I' }, + { "commentchar", required_argument, 0, 'c' }, + { "copysource", no_argument, 0, 's' }, + { "debug", no_argument, 0, 'd' }, + { "help", no_argument, 0, 'h' }, + { "mri", no_argument, 0, 'M' }, + { "output", required_argument, 0, 'o' }, + { "print", no_argument, 0, 'p' }, + { "unreasonable", no_argument, 0, 'u' }, + { "version", no_argument, 0, 'v' }, + { "define", required_argument, 0, 'd' }, + { NULL, no_argument, 0, 0 } +}; + +/* Show a usage message and exit. */ +static void +show_usage (file, status) + FILE *file; + int status; +{ + fprintf (file, "\ +Usage: %s \n\ + [-a] [--alternate] enter alternate macro mode\n\ + [-c char] [--commentchar char] change the comment character from !\n\ + [-d] [--debug] print some debugging info\n\ + [-h] [--help] print this message\n\ + [-M] [--mri] enter MRI compatibility mode\n\ + [-o out] [--output out] set the output file\n\ + [-p] [--print] print line numbers\n", program_name); + fprintf (file, "\ + [-s] [--copysource] copy source through as comments \n\ + [-u] [--unreasonable] allow unreasonable nesting\n\ + [-v] [--version] print the program version\n\ + [-Dname=value] create preprocessor variable called name, with value\n\ + [-Ipath] add to include path list\n\ + [in-file]\n"); + if (status == 0) + printf ("\nReport bugs to bug-gnu-utils@prep.ai.mit.edu\n"); + exit (status); +} + +/* Display a help message and exit. */ +static void +show_help () +{ + printf ("%s: Gnu Assembler Macro Preprocessor\n", + program_name); + show_usage (stdout, 0); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + int opt; + char *out_name = 0; + sp = include_stack; + + ifstack[0].on = 1; + ifi = 0; + + + + program_name = argv[0]; + xmalloc_set_program_name (program_name); + + hash_new_table (101, &keyword_hash_table); + hash_new_table (101, &assign_hash_table); + hash_new_table (101, &vars); + + sb_new (&label); + + while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options, + (int *) NULL)) + != EOF) + { + switch (opt) + { + case 'o': + out_name = optarg; + break; + case 'u': + unreasonable = 1; + break; + case 'I': + { + include_path *p = (include_path *) xmalloc (sizeof (include_path)); + sb_new (&p->path); + sb_add_string (&p->path, optarg); + if (paths_tail) + paths_tail->next = p; + else + paths_head = p; + paths_tail = p; + } + break; + case 'p': + print_line_number = 1; + break; + case 'c': + comment_char = optarg[0]; + break; + case 'a': + alternate = 1; + break; + case 's': + copysource = 1; + break; + case 'd': + stats = 1; + break; + case 'D': + do_define (optarg); + break; + case 'M': + mri = 1; + comment_char = ';'; + break; + case 'h': + show_help (); + /*NOTREACHED*/ + case 'v': + /* This output is intended to follow the GNU standards document. */ + printf ("GNU assembler pre-processor %s\n", program_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"); + exit (0); + /*NOTREACHED*/ + case 0: + break; + default: + show_usage (stderr, 1); + /*NOTREACHED*/ + } + } + + process_init (); + + macro_init (alternate, mri, 0, exp_get_abs); + + if (out_name) { + outfile = fopen (out_name, "w"); + if (!outfile) + { + fprintf (stderr, "%s: Can't open output file `%s'.\n", + program_name, out_name); + exit (1); + } + } + else { + outfile = stdout; + } + + chartype_init (); + if (!outfile) + outfile = stdout; + + /* Process all the input files */ + + while (optind < argc) + { + if (new_file (argv[optind])) + { + process_file (); + } + else + { + fprintf (stderr, "%s: Can't open input file `%s'.\n", + program_name, argv[optind]); + exit (1); + } + optind++; + } + + quit (); + return 0; +} + +/* This function is used because an abort in some of the other files + may be compiled into as_abort because they include as.h. */ + +void +as_abort (file, line, fn) + const char *file, *fn; + int line; +{ + fprintf (stderr, "Internal error, aborting at %s line %d", file, line); + if (fn) + fprintf (stderr, " in %s", fn); + fprintf (stderr, "\nPlease report this bug.\n"); + exit (1); +} diff --git a/contrib/binutils/gas/gdbinit.in b/contrib/binutils/gas/gdbinit.in new file mode 100644 index 0000000..e946726 --- /dev/null +++ b/contrib/binutils/gas/gdbinit.in @@ -0,0 +1,39 @@ +dir @srcdir@ +dir . + +break as_warn +break as_warn_where +break as_bad +break as_bad_where +break as_fatal +break as_perror +break as_assert +break as_abort + +define pe +call print_expr ($) +end + +document pe +Print *$ as an expressionS, expanding parameters. +end + +define ps +call print_symbol_value ($) +end + +document ps +Print *$ as a symbolS, including expression value. +end + +define pf +call print_fixup ($) +end + +document pf +Print *$ as a fixS, including symbol value. +end + +# Put this last, in case it fails. + +break abort diff --git a/contrib/binutils/gas/hash.c b/contrib/binutils/gas/hash.c new file mode 100644 index 0000000..51a3d84 --- /dev/null +++ b/contrib/binutils/gas/hash.c @@ -0,0 +1,1028 @@ +/* hash.c - hash table lookup strings - + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * BUGS, GRIPES, APOLOGIA etc. + * + * A typical user doesn't need ALL this: I intend to make a library out + * of it one day - Dean Elsner. + * Also, I want to change the definition of a symbol to (address,length) + * so I can put arbitrary binary in the names stored. [see hsh.c for that] + * + * This slime is common coupled inside the module. Com-coupling (and other + * vandalism) was done to speed running time. The interfaces at the + * module's edges are adequately clean. + * + * There is no way to (a) run a test script through this heap and (b) + * compare results with previous scripts, to see if we have broken any + * code. Use GNU (f)utilities to do this. A few commands assist test. + * The testing is awkward: it tries to be both batch & interactive. + * For now, interactive rules! + */ + +/* + * The idea is to implement a symbol table. A test jig is here. + * Symbols are arbitrary strings; they can't contain '\0'. + * [See hsh.c for a more general symbol flavour.] + * Each symbol is associated with a char*, which can point to anything + * you want, allowing an arbitrary property list for each symbol. + * + * The basic operations are: + * + * new creates symbol table, returns handle + * find (symbol) returns char* + * insert (symbol,char*) error if symbol already in table + * delete (symbol) returns char* if symbol was in table + * apply so you can delete all symbols before die() + * die destroy symbol table (free up memory) + * + * Supplementary functions include: + * + * say how big? what % full? + * replace (symbol,newval) report previous value + * jam (symbol,value) assert symbol:=value + * + * You, the caller, have control over errors: this just reports them. + * + * This package requires malloc(), free(). + * Malloc(size) returns NULL or address of char[size]. + * Free(address) frees same. + */ + +/* + * The code and its structures are re-enterent. + * + * Before you do anything else, you must call hash_new() which will + * return the address of a hash-table-control-block. You then use + * this address as a handle of the symbol table by passing it to all + * the other hash_...() functions. The only approved way to recover + * the memory used by the symbol table is to call hash_die() with the + * handle of the symbol table. + * + * Before you call hash_die() you normally delete anything pointed to + * by individual symbols. After hash_die() you can't use that symbol + * table again. + * + * The char* you associate with a symbol may not be NULL (0) because + * NULL is returned whenever a symbol is not in the table. Any other + * value is OK, except DELETED, #defined below. + * + * When you supply a symbol string for insertion, YOU MUST PRESERVE THE + * STRING until that symbol is deleted from the table. The reason is that + * only the address you supply, NOT the symbol string itself, is stored + * in the symbol table. + * + * You may delete and add symbols arbitrarily. + * Any or all symbols may have the same 'value' (char *). In fact, these + * routines don't do anything with your symbol values. + * + * You have no right to know where the symbol:char* mapping is stored, + * because it moves around in memory; also because we may change how it + * works and we don't want to break your code do we? However the handle + * (address of struct hash_control) is never changed in + * the life of the symbol table. + * + * What you CAN find out about a symbol table is: + * how many slots are in the hash table? + * how many slots are filled with symbols? + * (total hashes,collisions) for (reads,writes) (*) + * All of the above values vary in time. + * (*) some of these numbers will not be meaningful if we change the + * internals. */ + +/* + * I N T E R N A L + * + * Hash table is an array of hash_entries; each entry is a pointer to a + * a string and a user-supplied value 1 char* wide. + * + * The array always has 2 ** n elements, n>0, n integer. + * There is also a 'wall' entry after the array, which is always empty + * and acts as a sentinel to stop running off the end of the array. + * When the array gets too full, we create a new array twice as large + * and re-hash the symbols into the new array, then forget the old array. + * (Of course, we copy the values into the new array before we junk the + * old array!) + * + */ + +#include <stdio.h> + +#ifndef FALSE +#define FALSE (0) +#define TRUE (!FALSE) +#endif /* no FALSE yet */ + +#include <ctype.h> +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#include "as.h" + +#define error as_fatal + +static char _deleted_[1]; +#define DELETED ((PTR)_deleted_) /* guarenteed unique address */ +#define START_POWER (10) /* power of two: size of new hash table */ + +/* TRUE if a symbol is in entry @ ptr. */ +#define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED) + +enum stat_enum { + /* Number of slots in hash table. The wall does not count here. + We expect this is always a power of 2. */ + STAT_SIZE = 0, + /* Number of hash_ask calls. */ + STAT_ACCESS, + STAT_ACCESS_w, + /* Number of collisions (total). This may exceed STAT_ACCESS if we + have lots of collisions/access. */ + STAT_COLLIDE, + STAT_COLLIDE_w, + /* Slots used right now. */ + STAT_USED, + /* How many string compares? */ + STAT_STRCMP, + STAT_STRCMP_w, + /* Size of statistics block... this must be last. */ + STATLENGTH +}; +#define STAT__READ (0) /* reading */ +#define STAT__WRITE (1) /* writing */ + +/* When we grow a hash table, by what power of two do we increase it? */ +#define GROW_FACTOR 1 +/* When should we grow it? */ +#define FULL_VALUE(N) ((N) / 2) + +/* #define SUSPECT to do runtime checks */ +/* #define TEST to be a test jig for hash...() */ + +#ifdef TEST +/* TEST: use smaller hash table */ +#undef START_POWER +#define START_POWER (3) +#undef START_SIZE +#define START_SIZE (8) +#undef START_FULL +#define START_FULL (4) +#endif + +struct hash_entry +{ + const char *hash_string; /* points to where the symbol string is */ + /* NULL means slot is not used */ + /* DELETED means slot was deleted */ + PTR hash_value; /* user's datum, associated with symbol */ + unsigned long h; +}; + +struct hash_control { + struct hash_entry *hash_where;/* address of hash table */ + int hash_sizelog; /* Log of ( hash_mask + 1 ) */ + int hash_mask; /* masks a hash into index into table */ + int hash_full; /* when hash_stat[STAT_USED] exceeds this, */ + /* grow table */ + struct hash_entry *hash_wall; /* point just after last (usable) entry */ + /* here we have some statistics */ + int hash_stat[STATLENGTH]; /* lies & statistics */ +}; + +/*------------------ plan ---------------------------------- i = internal + + struct hash_control * c; + struct hash_entry * e; i + int b[z]; buffer for statistics + z size of b + char * s; symbol string (address) [ key ] + char * v; value string (address) [datum] + boolean f; TRUE if we found s in hash table i + char * t; error string; 0 means OK + int a; access type [0...n) i + + c=hash_new () create new hash_control + + hash_die (c) destroy hash_control (and hash table) + table should be empty. + doesn't check if table is empty. + c has no meaning after this. + + hash_say (c,b,z) report statistics of hash_control. + also report number of available statistics. + + v=hash_delete (c,s) delete symbol, return old value if any. + ask() NULL means no old value. + f + + v=hash_replace (c,s,v) replace old value of s with v. + ask() NULL means no old value: no table change. + f + + t=hash_insert (c,s,v) insert (s,v) in c. + ask() return error string. + f it is an error to insert if s is already + in table. + if any error, c is unchanged. + + t=hash_jam (c,s,v) assert that new value of s will be v. i + ask() it may decide to GROW the table. i + f i + grow() i + t=hash_grow (c) grow the hash table. i + jam() will invoke JAM. i + + ?=hash_apply (c,y) apply y() to every symbol in c. + y evtries visited in 'unspecified' order. + + v=hash_find (c,s) return value of s, or NULL if s not in c. + ask() + f + + f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i + code() maintain collision stats in c. i + + .=hash_code (c,s) compute hash-code for s, i + from parameters of c. i + + */ + +/* Returned by hash_ask() to stop extra testing. hash_ask() wants to + return both a slot and a status. This is the status. TRUE: found + symbol FALSE: absent: empty or deleted slot Also returned by + hash_jam(). TRUE: we replaced a value FALSE: we inserted a value. */ +static char hash_found; + +static struct hash_entry *hash_ask PARAMS ((struct hash_control *, + const char *, int)); +static int hash_code PARAMS ((struct hash_control *, const char *)); +static const char *hash_grow PARAMS ((struct hash_control *)); + +/* Create a new hash table. Return NULL if failed; otherwise return handle + (address of struct hash). */ +struct hash_control * +hash_new () +{ + struct hash_control *retval; + struct hash_entry *room; /* points to hash table */ + struct hash_entry *wall; + struct hash_entry *entry; + int *ip; /* scan stats block of struct hash_control */ + int *nd; /* limit of stats block */ + + room = (struct hash_entry *) xmalloc (sizeof (struct hash_entry) + /* +1 for the wall entry */ + * ((1 << START_POWER) + 1)); + retval = (struct hash_control *) xmalloc (sizeof (struct hash_control)); + + nd = retval->hash_stat + STATLENGTH; + for (ip = retval->hash_stat; ip < nd; ip++) + *ip = 0; + + retval->hash_stat[STAT_SIZE] = 1 << START_POWER; + retval->hash_mask = (1 << START_POWER) - 1; + retval->hash_sizelog = START_POWER; + /* works for 1's compl ok */ + retval->hash_where = room; + retval->hash_wall = + wall = room + (1 << START_POWER); + retval->hash_full = FULL_VALUE (1 << START_POWER); + for (entry = room; entry <= wall; entry++) + entry->hash_string = NULL; + return retval; +} + +/* + * h a s h _ d i e ( ) + * + * Table should be empty, but this is not checked. + * To empty the table, try hash_apply()ing a symbol deleter. + * Return to free memory both the hash table and it's control + * block. + * 'handle' has no meaning after this function. + * No errors are recoverable. + */ +void +hash_die (handle) + struct hash_control *handle; +{ + free ((char *) handle->hash_where); + free ((char *) handle); +} + +#ifdef TEST +/* + * h a s h _ s a y ( ) + * + * Return the size of the statistics table, and as many statistics as + * we can until either (a) we have run out of statistics or (b) caller + * has run out of buffer. + * NOTE: hash_say treats all statistics alike. + * These numbers may change with time, due to insertions, deletions + * and expansions of the table. + * The first "statistic" returned is the length of hash_stat[]. + * Then contents of hash_stat[] are read out (in ascending order) + * until your buffer or hash_stat[] is exausted. + */ +static void +hash_say (handle, buffer, bufsiz) + struct hash_control *handle; + int buffer[ /*bufsiz*/ ]; + int bufsiz; +{ + int *nd; /* limit of statistics block */ + int *ip; /* scan statistics */ + + ip = handle->hash_stat; + nd = ip + min (bufsiz - 1, STATLENGTH); + if (bufsiz > 0) /* trust nothing! bufsiz<=0 is dangerous */ + { + *buffer++ = STATLENGTH; + for (; ip < nd; ip++, buffer++) + { + *buffer = *ip; + } + } +} +#endif + +/* + * h a s h _ d e l e t e ( ) + * + * Try to delete a symbol from the table. + * If it was there, return its value (and adjust STAT_USED). + * Otherwise, return NULL. + * Anyway, the symbol is not present after this function. + * + */ +PTR /* NULL if string not in table, else */ +/* returns value of deleted symbol */ +hash_delete (handle, string) + struct hash_control *handle; + const char *string; +{ + PTR retval; + struct hash_entry *entry; + + entry = hash_ask (handle, string, STAT__WRITE); + if (hash_found) + { + retval = entry->hash_value; + entry->hash_string = DELETED; + handle->hash_stat[STAT_USED] -= 1; +#ifdef SUSPECT + if (handle->hash_stat[STAT_USED] < 0) + { + error ("hash_delete"); + } +#endif /* def SUSPECT */ + } + else + { + retval = NULL; + } + return (retval); +} + +/* + * h a s h _ r e p l a c e ( ) + * + * Try to replace the old value of a symbol with a new value. + * Normally return the old value. + * Return NULL and don't change the table if the symbol is not already + * in the table. + */ +PTR +hash_replace (handle, string, value) + struct hash_control *handle; + const char *string; + PTR value; +{ + struct hash_entry *entry; + char *retval; + + entry = hash_ask (handle, string, STAT__WRITE); + if (hash_found) + { + retval = entry->hash_value; + entry->hash_value = value; + } + else + { + retval = NULL; + } + ; + return retval; +} + +/* + * h a s h _ i n s e r t ( ) + * + * Insert a (symbol-string, value) into the hash table. + * Return an error string, 0 means OK. + * It is an 'error' to insert an existing symbol. + */ + +const char * /* return error string */ +hash_insert (handle, string, value) + struct hash_control *handle; + const char *string; + PTR value; +{ + struct hash_entry *entry; + const char *retval; + + retval = 0; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow (handle); + } + if (!retval) + { + entry = hash_ask (handle, string, STAT__WRITE); + if (hash_found) + { + retval = "exists"; + } + else + { + entry->hash_value = value; + entry->hash_string = string; + handle->hash_stat[STAT_USED] += 1; + } + } + return retval; +} + +/* + * h a s h _ j a m ( ) + * + * Regardless of what was in the symbol table before, after hash_jam() + * the named symbol has the given value. The symbol is either inserted or + * (its value is) replaced. + * An error message string is returned, 0 means OK. + * + * WARNING: this may decide to grow the hashed symbol table. + * To do this, we call hash_grow(), WHICH WILL recursively CALL US. + * + * We report status internally: hash_found is TRUE if we replaced, but + * false if we inserted. + */ +const char * +hash_jam (handle, string, value) + struct hash_control *handle; + const char *string; + PTR value; +{ + const char *retval; + struct hash_entry *entry; + + retval = 0; + if (handle->hash_stat[STAT_USED] > handle->hash_full) + { + retval = hash_grow (handle); + } + if (!retval) + { + entry = hash_ask (handle, string, STAT__WRITE); + if (!hash_found) + { + entry->hash_string = string; + handle->hash_stat[STAT_USED] += 1; + } + entry->hash_value = value; + } + return retval; +} + +/* + * h a s h _ g r o w ( ) + * + * Grow a new (bigger) hash table from the old one. + * We choose to double the hash table's size. + * Return a human-scrutible error string: 0 if OK. + * Warning! This uses hash_jam(), which had better not recurse + * back here! Hash_jam() conditionally calls us, but we ALWAYS + * call hash_jam()! + * Internal. + */ +static const char * +hash_grow (handle) /* make a hash table grow */ + struct hash_control *handle; +{ + struct hash_entry *newwall; + struct hash_entry *newwhere; + struct hash_entry *newtrack; + struct hash_entry *oldtrack; + struct hash_entry *oldwhere; + struct hash_entry *oldwall; + int temp; + int newsize; + const char *string; + const char *retval; +#ifdef SUSPECT + int oldused; +#endif + + /* + * capture info about old hash table + */ + oldwhere = handle->hash_where; + oldwall = handle->hash_wall; +#ifdef SUSPECT + oldused = handle->hash_stat[STAT_USED]; +#endif + /* + * attempt to get enough room for a hash table twice as big + */ + temp = handle->hash_stat[STAT_SIZE]; + newwhere = ((struct hash_entry *) + xmalloc ((unsigned long) ((temp << (GROW_FACTOR + 1)) + /* +1 for wall slot */ + * sizeof (struct hash_entry)))); + if (newwhere == NULL) + return "no_room"; + + /* + * have enough room: now we do all the work. + * double the size of everything in handle. + */ + handle->hash_mask = ((handle->hash_mask + 1) << GROW_FACTOR) - 1; + handle->hash_stat[STAT_SIZE] <<= GROW_FACTOR; + newsize = handle->hash_stat[STAT_SIZE]; + handle->hash_where = newwhere; + handle->hash_full <<= GROW_FACTOR; + handle->hash_sizelog += GROW_FACTOR; + handle->hash_wall = newwall = newwhere + newsize; + /* Set all those pesky new slots to vacant. */ + for (newtrack = newwhere; newtrack <= newwall; newtrack++) + newtrack->hash_string = NULL; + /* We will do a scan of the old table, the hard way, using the + * new control block to re-insert the data into new hash table. */ + handle->hash_stat[STAT_USED] = 0; + for (oldtrack = oldwhere; oldtrack < oldwall; oldtrack++) + if (((string = oldtrack->hash_string) != NULL) && string != DELETED) + if ((retval = hash_jam (handle, string, oldtrack->hash_value))) + return retval; + +#ifdef SUSPECT + if (handle->hash_stat[STAT_USED] != oldused) + return "hash_used"; +#endif + + /* We have a completely faked up control block. + Return the old hash table. */ + free ((char *) oldwhere); + + return 0; +} + +#ifdef TEST +/* + * h a s h _ a p p l y ( ) + * + * Use this to scan each entry in symbol table. + * For each symbol, this calls (applys) a nominated function supplying the + * symbol's value (and the symbol's name). + * The idea is you use this to destroy whatever is associted with + * any values in the table BEFORE you destroy the table with hash_die. + * Of course, you can use it for other jobs; whenever you need to + * visit all extant symbols in the table. + * + * We choose to have a call-you-back idea for two reasons: + * asthetic: it is a neater idea to use apply than an explicit loop + * sensible: if we ever had to grow the symbol table (due to insertions) + * then we would lose our place in the table when we re-hashed + * symbols into the new table in a different order. + * + * The order symbols are visited depends entirely on the hashing function. + * Whenever you insert a (symbol, value) you risk expanding the table. If + * you do expand the table, then the hashing function WILL change, so you + * MIGHT get a different order of symbols visited. In other words, if you + * want the same order of visiting symbols as the last time you used + * hash_apply() then you better not have done any hash_insert()s or + * hash_jam()s since the last time you used hash_apply(). + * + * In future we may use the value returned by your nominated function. + * One idea is to abort the scan if, after applying the function to a + * certain node, the function returns a certain code. + * + * The function you supply should be of the form: + * void myfunct(string,value) + * char * string; |* the symbol's name *| + * char * value; |* the symbol's value *| + * { + * |* ... *| + * } + * + */ +void +hash_apply (handle, function) + struct hash_control *handle; + void (*function) (); +{ + struct hash_entry *entry; + struct hash_entry *wall; + + wall = handle->hash_wall; + for (entry = handle->hash_where; entry < wall; entry++) + { + if (islive (entry)) /* silly code: tests entry->string twice! */ + { + (*function) (entry->hash_string, entry->hash_value); + } + } +} +#endif + +/* + * h a s h _ f i n d ( ) + * + * Given symbol string, find value (if any). + * Return found value or NULL. + */ +PTR +hash_find (handle, string) + struct hash_control *handle; + const char *string; +{ + struct hash_entry *entry; + + entry = hash_ask (handle, string, STAT__READ); + if (hash_found) + return entry->hash_value; + else + return NULL; +} + +/* + * h a s h _ a s k ( ) + * + * Searches for given symbol string. + * Return the slot where it OUGHT to live. It may be there. + * Return hash_found: TRUE only if symbol is in that slot. + * Access argument is to help keep statistics in control block. + * Internal. + */ +static struct hash_entry * /* string slot, may be empty or deleted */ +hash_ask (handle, string, access_type) + struct hash_control *handle; + const char *string; + int access_type; +{ + const char *s; + struct hash_entry *slot; + int collision; /* count collisions */ + int strcmps; + int hcode; + + /* start looking here */ + hcode = hash_code (handle, string); + slot = handle->hash_where + (hcode & handle->hash_mask); + + handle->hash_stat[STAT_ACCESS + access_type] += 1; + collision = strcmps = 0; + hash_found = FALSE; + while (((s = slot->hash_string) != NULL) && s != DELETED) + { + if (string == s) + { + hash_found = TRUE; + break; + } + if (slot->h == hcode) + { + if (!strcmp (string, s)) + { + hash_found = TRUE; + break; + } + strcmps++; + } + collision++; + slot++; + } + /* + * slot: return: + * in use: we found string slot + * at empty: + * at wall: we fell off: wrap round ???? + * in table: dig here slot + * at DELETED: dig here slot + */ + if (slot == handle->hash_wall) + { + slot = handle->hash_where;/* now look again */ + while (((s = slot->hash_string) != NULL) && s != DELETED) + { + if (string == s) + { + hash_found = TRUE; + break; + } + if (slot->h == hcode) + { + if (!strcmp (string, s)) + { + hash_found = TRUE; + break; + } + strcmps++; + } + collision++; + slot++; + } + /* + * slot: return: + * in use: we found it slot + * empty: wall: ERROR IMPOSSIBLE !!!! + * in table: dig here slot + * DELETED:dig here slot + */ + } + handle->hash_stat[STAT_COLLIDE + access_type] += collision; + handle->hash_stat[STAT_STRCMP + access_type] += strcmps; + if (!hash_found) + slot->h = hcode; + return slot; /* also return hash_found */ +} + +/* + * h a s h _ c o d e + * + * Does hashing of symbol string to hash number. + * Internal. + */ +static int +hash_code (handle, string) + struct hash_control *handle; + const char *string; +{ +#if 1 /* There seems to be some interesting property of this function + that prevents the bfd version below from being an adequate + substitute. @@ Figure out what this property is! */ + long h; /* hash code built here */ + long c; /* each character lands here */ + int n; /* Amount to shift h by */ + + n = (handle->hash_sizelog - 3); + h = 0; + while ((c = *string++) != 0) + { + h += c; + h = (h << 3) + (h >> n) + c; + } + return h; +#else + /* from bfd */ + unsigned long h = 0; + unsigned int len = 0; + unsigned int c; + + while ((c = *string++) != 0) + { + h += c + (c << 17); + h ^= h >> 2; + ++len; + } + h += len + (len << 17); + h ^= h >> 2; + return h; +#endif +} + +void +hash_print_statistics (file, name, h) + FILE *file; + const char *name; + struct hash_control *h; +{ + unsigned long sz, used, pct; + + if (h == 0) + return; + + sz = h->hash_stat[STAT_SIZE]; + used = h->hash_stat[STAT_USED]; + pct = (used * 100 + sz / 2) / sz; + + fprintf (file, "%s hash statistics:\n\t%lu/%lu slots used (%lu%%)\n", + name, used, sz, pct); + +#define P(name, off) \ + fprintf (file, "\t%-16s %6dr + %6dw = %7d\n", name, \ + h->hash_stat[off+STAT__READ], \ + h->hash_stat[off+STAT__WRITE], \ + h->hash_stat[off+STAT__READ] + h->hash_stat[off+STAT__WRITE]) + + P ("accesses:", STAT_ACCESS); + P ("collisions:", STAT_COLLIDE); + P ("string compares:", STAT_STRCMP); + +#undef P +} + +/* + * Here is a test program to exercise above. + */ +#ifdef TEST + +#define TABLES (6) /* number of hash tables to maintain */ +/* (at once) in any testing */ +#define STATBUFSIZE (12) /* we can have 12 statistics */ + +int statbuf[STATBUFSIZE]; /* display statistics here */ +char answer[100]; /* human farts here */ +char *hashtable[TABLES]; /* we test many hash tables at once */ +char *h; /* points to curent hash_control */ +char **pp; +char *p; +char *name; +char *value; +int size; +int used; +char command; +int number; /* number 0:TABLES-1 of current hashed */ +/* symbol table */ + +main () +{ + void applicatee (); + void destroy (); + char *what (); + int *ip; + + number = 0; + h = 0; + printf ("type h <RETURN> for help\n"); + for (;;) + { + printf ("hash_test command: "); + gets (answer); + command = answer[0]; + if (isupper (command)) + command = tolower (command); /* ecch! */ + switch (command) + { + case '#': + printf ("old hash table #=%d.\n", number); + whattable (); + break; + case '?': + for (pp = hashtable; pp < hashtable + TABLES; pp++) + { + printf ("address of hash table #%d control block is %xx\n" + ,pp - hashtable, *pp); + } + break; + case 'a': + hash_apply (h, applicatee); + break; + case 'd': + hash_apply (h, destroy); + hash_die (h); + break; + case 'f': + p = hash_find (h, name = what ("symbol")); + printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT"); + break; + case 'h': + printf ("# show old, select new default hash table number\n"); + printf ("? display all hashtable control block addresses\n"); + printf ("a apply a simple display-er to each symbol in table\n"); + printf ("d die: destroy hashtable\n"); + printf ("f find value of nominated symbol\n"); + printf ("h this help\n"); + printf ("i insert value into symbol\n"); + printf ("j jam value into symbol\n"); + printf ("n new hashtable\n"); + printf ("r replace a value with another\n"); + printf ("s say what %% of table is used\n"); + printf ("q exit this program\n"); + printf ("x delete a symbol from table, report its value\n"); + break; + case 'i': + p = hash_insert (h, name = what ("symbol"), value = what ("value")); + if (p) + { + printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, + p); + } + break; + case 'j': + p = hash_jam (h, name = what ("symbol"), value = what ("value")); + if (p) + { + printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p); + } + break; + case 'n': + h = hashtable[number] = (char *) hash_new (); + break; + case 'q': + exit (EXIT_SUCCESS); + case 'r': + p = hash_replace (h, name = what ("symbol"), value = what ("value")); + printf ("old value was \"%s\"\n", p ? p : "{}"); + break; + case 's': + hash_say (h, statbuf, STATBUFSIZE); + for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++) + { + printf ("%d ", *ip); + } + printf ("\n"); + break; + case 'x': + p = hash_delete (h, name = what ("symbol")); + printf ("old value was \"%s\"\n", p ? p : "{}"); + break; + default: + printf ("I can't understand command \"%c\"\n", command); + break; + } + } +} + +char * +what (description) + char *description; +{ + char *retval; + char *malloc (); + + printf (" %s : ", description); + gets (answer); + /* will one day clean up answer here */ + retval = malloc (strlen (answer) + 1); + if (!retval) + { + error ("room"); + } + (void) strcpy (retval, answer); + return (retval); +} + +void +destroy (string, value) + char *string; + char *value; +{ + free (string); + free (value); +} + + +void +applicatee (string, value) + char *string; + char *value; +{ + printf ("%.20s-%.20s\n", string, value); +} + +whattable () /* determine number: what hash table to use */ + /* also determine h: points to hash_control */ +{ + + for (;;) + { + printf (" what hash table (%d:%d) ? ", 0, TABLES - 1); + gets (answer); + sscanf (answer, "%d", &number); + if (number >= 0 && number < TABLES) + { + h = hashtable[number]; + if (!h) + { + printf ("warning: current hash-table-#%d. has no hash-control\n", number); + } + return; + } + else + { + printf ("invalid hash table number: %d\n", number); + } + } +} + + + +#endif /* #ifdef TEST */ + +/* end of hash.c */ diff --git a/contrib/binutils/gas/hash.h b/contrib/binutils/gas/hash.h new file mode 100644 index 0000000..fb229c8 --- /dev/null +++ b/contrib/binutils/gas/hash.h @@ -0,0 +1,45 @@ +/* hash.h - for hash.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef hashH +#define hashH + +struct hash_control; + +/* returns control block */ +struct hash_control *hash_new PARAMS ((void)); +void hash_die PARAMS ((struct hash_control *)); +/* returns previous value */ +PTR hash_delete PARAMS ((struct hash_control *, const char *str)); +/* returns previous value */ +PTR hash_replace PARAMS ((struct hash_control *, const char *str, PTR val)); +/* returns error string or null */ +const char *hash_insert PARAMS ((struct hash_control *, const char *str, + PTR val)); +/* returns value */ +PTR hash_find PARAMS ((struct hash_control *, const char *str)); +/* returns error text or null (internal) */ +const char *hash_jam PARAMS ((struct hash_control *, const char *str, + PTR val)); + +void hash_print_statistics PARAMS ((FILE *, const char *, + struct hash_control *)); +#endif /* #ifdef hashH */ + +/* end of hash.c */ diff --git a/contrib/binutils/gas/input-file.c b/contrib/binutils/gas/input-file.c new file mode 100644 index 0000000..be029c2 --- /dev/null +++ b/contrib/binutils/gas/input-file.c @@ -0,0 +1,248 @@ +/* input_file.c - Deal with Input Files - + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Confines all details of reading source bytes to this module. + * All O/S specific crocks should live here. + * What we lose in "efficiency" we gain in modularity. + * Note we don't need to #include the "as.h" file. No common coupling! + */ + +#include <stdio.h> +#include <string.h> + +#include "as.h" +#include "input-file.h" + +static int input_file_get PARAMS ((char **)); + +/* This variable is non-zero if the file currently being read should be + preprocessed by app. It is zero if the file can be read straight in. + */ +int preprocess = 0; + +/* + * This code opens a file, then delivers BUFFER_SIZE character + * chunks of the file on demand. + * BUFFER_SIZE is supposed to be a number chosen for speed. + * The caller only asks once what BUFFER_SIZE is, and asks before + * the nature of the input files (if any) is known. + */ + +#define BUFFER_SIZE (32 * 1024) + +/* + * We use static data: the data area is not sharable. + */ + +static FILE *f_in; +static char *file_name; + +/* Struct for saving the state of this module for file includes. */ +struct saved_file + { + FILE *f_in; + char *file_name; + int preprocess; + char *app_save; + }; + +/* These hooks accomodate most operating systems. */ + +void +input_file_begin () +{ + f_in = (FILE *) 0; +} + +void +input_file_end () +{ +} + +/* Return BUFFER_SIZE. */ +unsigned int +input_file_buffer_size () +{ + return (BUFFER_SIZE); +} + +int +input_file_is_open () +{ + return f_in != (FILE *) 0; +} + +/* Push the state of our input, returning a pointer to saved info that + can be restored with input_file_pop (). */ +char * +input_file_push () +{ + register struct saved_file *saved; + + saved = (struct saved_file *) xmalloc (sizeof *saved); + + saved->f_in = f_in; + saved->file_name = file_name; + saved->preprocess = preprocess; + if (preprocess) + saved->app_save = app_push (); + + input_file_begin (); /* Initialize for new file */ + + return (char *) saved; +} + +void +input_file_pop (arg) + char *arg; +{ + register struct saved_file *saved = (struct saved_file *) arg; + + input_file_end (); /* Close out old file */ + + f_in = saved->f_in; + file_name = saved->file_name; + preprocess = saved->preprocess; + if (preprocess) + app_pop (saved->app_save); + + free (arg); +} + +void +input_file_open (filename, pre) + char *filename; /* "" means use stdin. Must not be 0. */ + int pre; +{ + int c; + char buf[80]; + + preprocess = pre; + + assert (filename != 0); /* Filename may not be NULL. */ + if (filename[0]) + { /* We have a file name. Suck it and see. */ + f_in = fopen (filename, "r"); + file_name = filename; + } + else + { /* use stdin for the input file. */ + f_in = stdin; + file_name = "{standard input}"; /* For error messages. */ + } + if (f_in == (FILE *) 0) + { + as_bad ("Can't open %s for reading.", file_name); + as_perror ("%s", file_name); + return; + } + + c = getc (f_in); + if (c == '#') + { /* Begins with comment, may not want to preprocess */ + c = getc (f_in); + if (c == 'N') + { + fgets (buf, 80, f_in); + if (!strcmp (buf, "O_APP\n")) + preprocess = 0; + if (!strchr (buf, '\n')) + ungetc ('#', f_in); /* It was longer */ + else + ungetc ('\n', f_in); + } + else if (c == '\n') + ungetc ('\n', f_in); + else + ungetc ('#', f_in); + } + else + ungetc (c, f_in); +} + +/* Close input file. */ +void +input_file_close () +{ + if (f_in != NULL) + { + fclose (f_in); + } /* don't close a null file pointer */ + f_in = 0; +} /* input_file_close() */ + +/* This function is passed to do_scrub_chars. */ + +static int +input_file_get (from) + char **from; +{ + static char buf[BUFFER_SIZE]; + int size; + + size = fread (buf, sizeof (char), sizeof buf, f_in); + if (size < 0) + { + as_perror ("Can't read from %s", file_name); + size = 0; + } + *from = buf; + return size; +} + +/* Read a buffer from the input file. */ + +char * +input_file_give_next_buffer (where) + char *where; /* Where to place 1st character of new buffer. */ +{ + char *return_value; /* -> Last char of what we read, + 1. */ + register int size; + + if (f_in == (FILE *) 0) + return 0; + /* + * fflush (stdin); could be done here if you want to synchronise + * stdin and stdout, for the case where our input file is stdin. + * Since the assembler shouldn't do any output to stdout, we + * don't bother to synch output and input. + */ + if (preprocess) + size = do_scrub_chars (input_file_get, where, BUFFER_SIZE); + else + size = fread (where, sizeof (char), BUFFER_SIZE, f_in); + if (size < 0) + { + as_perror ("Can't read from %s", file_name); + size = 0; + } + if (size) + return_value = where + size; + else + { + if (fclose (f_in)) + as_perror ("Can't close %s", file_name); + f_in = (FILE *) 0; + return_value = 0; + } + return (return_value); +} + +/* end of input-file.c */ diff --git a/contrib/binutils/gas/input-file.h b/contrib/binutils/gas/input-file.h new file mode 100644 index 0000000..129bf28 --- /dev/null +++ b/contrib/binutils/gas/input-file.h @@ -0,0 +1,68 @@ +/* input_file.h header for input-file.c + Copyright (C) 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/*"input_file.c":Operating-system dependant functions to read source files.*/ + + +/* + * No matter what the operating system, this module must provide the + * following services to its callers. + * + * input_file_begin() Call once before anything else. + * + * input_file_end() Call once after everything else. + * + * input_file_buffer_size() Call anytime. Returns largest possible + * delivery from + * input_file_give_next_buffer(). + * + * input_file_open(name) Call once for each input file. + * + * input_file_give_next_buffer(where) Call once to get each new buffer. + * Return 0: no more chars left in file, + * the file has already been closed. + * Otherwise: return a pointer to just + * after the last character we read + * into the buffer. + * If we can only read 0 characters, then + * end-of-file is faked. + * + * input_file_push() Push state, which can be restored + * later. Does implicit input_file_begin. + * Returns char * to saved state. + * + * input_file_pop (arg) Pops previously saved state. + * + * input_file_close () Closes opened file. + * + * All errors are reported (using as_perror) so caller doesn't have to think + * about I/O errors. No I/O errors are fatal: an end-of-file may be faked. + */ + +char *input_file_give_next_buffer PARAMS ((char *where)); +char *input_file_push PARAMS ((void)); +unsigned int input_file_buffer_size PARAMS ((void)); +int input_file_is_open PARAMS ((void)); +void input_file_begin PARAMS ((void)); +void input_file_close PARAMS ((void)); +void input_file_end PARAMS ((void)); +void input_file_open PARAMS ((char *filename, int pre)); +void input_file_pop PARAMS ((char *arg)); + +/* end of input_file.h */ diff --git a/contrib/binutils/gas/input-scrub.c b/contrib/binutils/gas/input-scrub.c new file mode 100644 index 0000000..5271065 --- /dev/null +++ b/contrib/binutils/gas/input-scrub.c @@ -0,0 +1,507 @@ +/* input_scrub.c - Break up input buffers into whole numbers of lines. + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include <errno.h> /* Need this to make errno declaration right */ +#include "as.h" +#include "input-file.h" +#include "sb.h" + +/* + * O/S independent module to supply buffers of sanitised source code + * to rest of assembler. We get sanitised input data of arbitrary length. + * We break these buffers on line boundaries, recombine pieces that + * were broken across buffers, and return a buffer of full lines to + * the caller. + * The last partial line begins the next buffer we build and return to caller. + * The buffer returned to caller is preceeded by BEFORE_STRING and followed + * by AFTER_STRING, as sentinels. The last character before AFTER_STRING + * is a newline. + * Also looks after line numbers, for e.g. error messages. + */ + +/* + * We don't care how filthy our buffers are, but our callers assume + * that the following sanitation has already been done. + * + * No comments, reduce a comment to a space. + * Reduce a tab to a space unless it is 1st char of line. + * All multiple tabs and spaces collapsed into 1 char. Tab only + * legal if 1st char of line. + * # line file statements converted to .line x;.file y; statements. + * Escaped newlines at end of line: remove them but add as many newlines + * to end of statement as you removed in the middle, to synch line numbers. + */ + +#define BEFORE_STRING ("\n") +#define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */ +#define BEFORE_SIZE (1) +#define AFTER_SIZE (1) + +static char *buffer_start; /*->1st char of full buffer area. */ +static char *partial_where; /*->after last full line in buffer. */ +static int partial_size; /* >=0. Number of chars in partial line in buffer. */ +static char save_source[AFTER_SIZE]; +/* Because we need AFTER_STRING just after last */ +/* full line, it clobbers 1st part of partial */ +/* line. So we preserve 1st part of partial */ +/* line here. */ +static unsigned int buffer_length; /* What is the largest size buffer that */ +/* input_file_give_next_buffer() could */ +/* return to us? */ + +/* The index into an sb structure we are reading from. -1 if none. */ +static int sb_index = -1; + +/* If we are reading from an sb structure, this is it. */ +static sb from_sb; + +/* The number of nested sb structures we have included. */ +int macro_nest; + +/* We can have more than one source file open at once, though the info for all + but the latest one are saved off in a struct input_save. These files remain + open, so we are limited by the number of open files allowed by the + underlying OS. We may also sequentially read more than one source file in an + assembly. */ + +/* We must track the physical file and line number for error messages. We also + track a "logical" file and line number corresponding to (C?) compiler + source line numbers. Whenever we open a file we must fill in + physical_input_file. So if it is NULL we have not opened any files yet. */ + +static char *physical_input_file; +static char *logical_input_file; + +typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ +/* A line ends in '\n' or eof. */ + +static line_numberT physical_input_line; +static int logical_input_line; + +/* Struct used to save the state of the input handler during include files */ +struct input_save + { + char *buffer_start; + char *partial_where; + int partial_size; + char save_source[AFTER_SIZE]; + unsigned int buffer_length; + char *physical_input_file; + char *logical_input_file; + line_numberT physical_input_line; + int logical_input_line; + int sb_index; + sb from_sb; + struct input_save *next_saved_file; /* Chain of input_saves */ + char *input_file_save; /* Saved state of input routines */ + char *saved_position; /* Caller's saved position in buf */ + }; + +static struct input_save *input_scrub_push PARAMS ((char *saved_position)); +static char *input_scrub_pop PARAMS ((struct input_save *arg)); +static void as_1_char PARAMS ((unsigned int c, FILE * stream)); + +/* Saved information about the file that .include'd this one. When we hit EOF, + we automatically pop to that file. */ + +static struct input_save *next_saved_file; + +/* Push the state of input reading and scrubbing so that we can #include. + The return value is a 'void *' (fudged for old compilers) to a save + area, which can be restored by passing it to input_scrub_pop(). */ +static struct input_save * +input_scrub_push (saved_position) + char *saved_position; +{ + register struct input_save *saved; + + saved = (struct input_save *) xmalloc (sizeof *saved); + + saved->saved_position = saved_position; + saved->buffer_start = buffer_start; + saved->partial_where = partial_where; + saved->partial_size = partial_size; + saved->buffer_length = buffer_length; + saved->physical_input_file = physical_input_file; + saved->logical_input_file = logical_input_file; + saved->physical_input_line = physical_input_line; + saved->logical_input_line = logical_input_line; + saved->sb_index = sb_index; + saved->from_sb = from_sb; + memcpy (saved->save_source, save_source, sizeof (save_source)); + saved->next_saved_file = next_saved_file; + saved->input_file_save = input_file_push (); + + input_file_begin (); /* Reinitialize! */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + buffer_length = input_file_buffer_size (); + sb_index = -1; + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + return saved; +} /* input_scrub_push() */ + +static char * +input_scrub_pop (saved) + struct input_save *saved; +{ + char *saved_position; + + input_scrub_end (); /* Finish off old buffer */ + + input_file_pop (saved->input_file_save); + saved_position = saved->saved_position; + buffer_start = saved->buffer_start; + buffer_length = saved->buffer_length; + physical_input_file = saved->physical_input_file; + logical_input_file = saved->logical_input_file; + physical_input_line = saved->physical_input_line; + logical_input_line = saved->logical_input_line; + sb_index = saved->sb_index; + from_sb = saved->from_sb; + partial_where = saved->partial_where; + partial_size = saved->partial_size; + next_saved_file = saved->next_saved_file; + memcpy (save_source, saved->save_source, sizeof (save_source)); + + free (saved); + return saved_position; +} + + +void +input_scrub_begin () +{ + know (strlen (BEFORE_STRING) == BEFORE_SIZE); + know (strlen (AFTER_STRING) == AFTER_SIZE || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1)); + + input_file_begin (); + + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + /* Line number things. */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + physical_input_file = NULL; /* No file read yet. */ + next_saved_file = NULL; /* At EOF, don't pop to any other file */ + do_scrub_begin (flag_m68k_mri); +} + +void +input_scrub_end () +{ + if (buffer_start) + { + free (buffer_start); + buffer_start = 0; + input_file_end (); + } +} + +/* Start reading input from a new file. */ + +char * /* Return start of caller's part of buffer. */ +input_scrub_new_file (filename) + char *filename; +{ + input_file_open (filename, !flag_no_comments); + physical_input_file = filename[0] ? filename : "{standard input}"; + physical_input_line = 0; + + partial_size = 0; + return (buffer_start + BEFORE_SIZE); +} + + +/* Include a file from the current file. Save our state, cause it to + be restored on EOF, and begin handling a new file. Same result as + input_scrub_new_file. */ + +char * +input_scrub_include_file (filename, position) + char *filename; + char *position; +{ + next_saved_file = input_scrub_push (position); + return input_scrub_new_file (filename); +} + +/* Start getting input from an sb structure. This is used when + expanding a macro. */ + +void +input_scrub_include_sb (from, position) + sb *from; + char *position; +{ + if (macro_nest > max_macro_nest) + as_fatal ("macros nested too deeply"); + ++macro_nest; + + next_saved_file = input_scrub_push (position); + + sb_new (&from_sb); + /* Add the sentinel required by read.c. */ + sb_add_char (&from_sb, '\n'); + sb_add_sb (&from_sb, from); + sb_index = 1; + + /* These variables are reset by input_scrub_push. Restore them + since we are, after all, still at the same point in the file. */ + logical_input_line = next_saved_file->logical_input_line; + logical_input_file = next_saved_file->logical_input_file; +} + +void +input_scrub_close () +{ + input_file_close (); +} + +char * +input_scrub_next_buffer (bufp) + char **bufp; +{ + register char *limit; /*->just after last char of buffer. */ + + if (sb_index >= 0) + { + if (sb_index >= from_sb.len) + { + sb_kill (&from_sb); + cond_finish_check (macro_nest); + --macro_nest; + partial_where = NULL; + if (next_saved_file != NULL) + *bufp = input_scrub_pop (next_saved_file); + return partial_where; + } + + partial_where = from_sb.ptr + from_sb.len; + partial_size = 0; + *bufp = from_sb.ptr + sb_index; + sb_index = from_sb.len; + return partial_where; + } + + *bufp = buffer_start + BEFORE_SIZE; + + if (partial_size) + { + memcpy (buffer_start + BEFORE_SIZE, partial_where, + (unsigned int) partial_size); + memcpy (buffer_start + BEFORE_SIZE, save_source, AFTER_SIZE); + } + limit = input_file_give_next_buffer (buffer_start + + BEFORE_SIZE + + partial_size); + if (limit) + { + register char *p; /* Find last newline. */ + + for (p = limit - 1; *p != '\n'; --p) + ; + ++p; + + while (p <= buffer_start + BEFORE_SIZE) + { + int limoff; + + limoff = limit - buffer_start; + buffer_length += input_file_buffer_size (); + buffer_start = xrealloc (buffer_start, + (BEFORE_SIZE + + 2 * buffer_length + + AFTER_SIZE)); + *bufp = buffer_start + BEFORE_SIZE; + limit = input_file_give_next_buffer (buffer_start + limoff); + + if (limit == NULL) + { + as_warn ("partial line at end of file ignored"); + partial_where = NULL; + if (next_saved_file) + *bufp = input_scrub_pop (next_saved_file); + return NULL; + } + + for (p = limit - 1; *p != '\n'; --p) + ; + ++p; + } + + partial_where = p; + partial_size = limit - p; + memcpy (save_source, partial_where, (int) AFTER_SIZE); + memcpy (partial_where, AFTER_STRING, (int) AFTER_SIZE); + } + else + { + partial_where = 0; + if (partial_size > 0) + { + as_warn ("Partial line at end of file ignored"); + } + /* If we should pop to another file at EOF, do it. */ + if (next_saved_file) + { + *bufp = input_scrub_pop (next_saved_file); /* Pop state */ + /* partial_where is now correct to return, since we popped it. */ + } + } + return (partial_where); +} /* input_scrub_next_buffer() */ + +/* + * The remaining part of this file deals with line numbers, error + * messages and so on. + */ + + +int +seen_at_least_1_file () /* TRUE if we opened any file. */ +{ + return (physical_input_file != NULL); +} + +void +bump_line_counters () +{ + if (sb_index < 0) + { + ++physical_input_line; + if (logical_input_line >= 0) + ++logical_input_line; + } +} + +/* + * new_logical_line() + * + * Tells us what the new logical line number and file are. + * If the line_number is -1, we don't change the current logical line + * number. If it is -2, we decrement the logical line number (this is + * to support the .appfile pseudo-op inserted into the stream by + * do_scrub_chars). + * If the fname is NULL, we don't change the current logical file name. + */ +void +new_logical_line (fname, line_number) + char *fname; /* DON'T destroy it! We point to it! */ + int line_number; +{ + if (fname) + { + logical_input_file = fname; + } /* if we have a file name */ + + if (line_number >= 0) + logical_input_line = line_number; + else if (line_number == -2 && logical_input_line > 0) + --logical_input_line; +} /* new_logical_line() */ + +/* + * a s _ w h e r e () + * + * Return the current file name and line number. + * namep should be char * const *, but there are compilers which screw + * up declarations like that, and it's easier to avoid it. + */ +void +as_where (namep, linep) + char **namep; + unsigned int *linep; +{ + if (logical_input_file != NULL + && (linep == NULL || logical_input_line >= 0)) + { + *namep = logical_input_file; + if (linep != NULL) + *linep = logical_input_line; + } + else if (physical_input_file != NULL) + { + *namep = physical_input_file; + if (linep != NULL) + *linep = physical_input_line; + } + else + { + *namep = 0; + if (linep != NULL) + *linep = 0; + } +} /* as_where() */ + + + + +/* + * a s _ h o w m u c h () + * + * Output to given stream how much of line we have scanned so far. + * Assumes we have scanned up to and including input_line_pointer. + * No free '\n' at end of line. + */ +void +as_howmuch (stream) + FILE *stream; /* Opened for write please. */ +{ + register char *p; /* Scan input line. */ + /* register char c; JF unused */ + + for (p = input_line_pointer - 1; *p != '\n'; --p) + { + } + ++p; /* p->1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + as_1_char ((unsigned char) *p, stream); + } +} + +static void +as_1_char (c, stream) + unsigned int c; + FILE *stream; +{ + if (c > 127) + { + (void) putc ('%', stream); + c -= 128; + } + if (c < 32) + { + (void) putc ('^', stream); + c += '@'; + } + (void) putc (c, stream); +} + +/* end of input_scrub.c */ diff --git a/contrib/binutils/gas/itbl-lex.l b/contrib/binutils/gas/itbl-lex.l new file mode 100644 index 0000000..1703eda --- /dev/null +++ b/contrib/binutils/gas/itbl-lex.l @@ -0,0 +1,112 @@ +/* itbl-lex.l + Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +%{ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "itbl-parse.h" + +#ifdef DEBUG +#define DBG(x) printf x +#define MDBG(x) printf x +#else +#define DBG(x) +#define MDBG(x) +#endif + +int insntbl_line = 1; +%} + +ALNUM [A-Za-z0-9_] +DIGIT [0-9] +ALPHA [A-Za-z_] +HEX [0-9A-Fa-f] + +%% + +"creg"|"CREG" { + return CREG; + } +"dreg"|"DREG" { + return DREG; + } +"greg"|"GREG" { + return GREG; + } +"immed"|"IMMED" { + return IMMED; + } +"addr"|"ADDR" { + return ADDR; + } +"insn"|"INSN" { + return INSN; + } +"p"{DIGIT} { + yytext[yyleng] = 0; + yylval.processor = strtoul (yytext+1, 0, 0); + return PNUM; + } +{DIGIT}+ { + yytext[yyleng] = 0; + yylval.num = strtoul (yytext, 0, 0); + return NUM; + } +"0x"{HEX}+ { + yytext[yyleng] = 0; + yylval.num = strtoul (yytext, 0, 0); + return NUM; + } +{ALPHA}{ALNUM}* { + yytext[yyleng] = 0; + yylval.str = strdup (yytext); + return ID; + } +";"|"#" { + int c; + while ((c = input ()) != EOF) + { + if (c == '\n') + { + unput (c); + break; + } + } + } +"\n" { + insntbl_line++; + MDBG (("in lex, NL = %d (x%x)\n", NL, NL)); + return NL; + } +" "|"\t" { + } +. { + MDBG (("char = %x, %d\n", yytext[0], yytext[0])); + return yytext[0]; + } +%% + +int +yywrap () + { + return 1; + } diff --git a/contrib/binutils/gas/itbl-ops.c b/contrib/binutils/gas/itbl-ops.c new file mode 100644 index 0000000..58fc3eb --- /dev/null +++ b/contrib/binutils/gas/itbl-ops.c @@ -0,0 +1,921 @@ +/* itbl-ops.c + Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/*======================================================================*/ +/* + * Herein lies the support for dynamic specification of processor + * instructions and registers. Mnemonics, values, and formats for each + * instruction and register are specified in an ascii file consisting of + * table entries. The grammar for the table is defined in the document + * "Processor instruction table specification". + * + * Instructions use the gnu assembler syntax, with the addition of + * allowing mnemonics for register. + * Eg. "func $2,reg3,0x100,symbol ; comment" + * func - opcode name + * $n - register n + * reg3 - mnemonic for processor's register defined in table + * 0xddd..d - immediate value + * symbol - address of label or external symbol + * + * First, itbl_parse reads in the table of register and instruction + * names and formats, and builds a list of entries for each + * processor/type combination. lex and yacc are used to parse + * the entries in the table and call functions defined here to + * add each entry to our list. + * + * Then, when assembling or disassembling, these functions are called to + * 1) get information on a processor's registers and + * 2) assemble/disassemble an instruction. + * To assemble(disassemble) an instruction, the function + * itbl_assemble(itbl_disassemble) is called to search the list of + * instruction entries, and if a match is found, uses the format + * described in the instruction entry structure to complete the action. + * + * Eg. Suppose we have a Mips coprocessor "cop3" with data register "d2" + * and we want to define function "pig" which takes two operands. + * + * Given the table entries: + * "p3 insn pig 0x1:24-21 dreg:20-16 immed:15-0" + * "p3 dreg d2 0x2" + * and that the instruction encoding for coprocessor pz has encoding: + * #define MIPS_ENCODE_COP_NUM(z) ((0x21|(z<<1))<<25) + * #define ITBL_ENCODE_PNUM(pnum) MIPS_ENCODE_COP_NUM(pnum) + * + * a structure to describe the instruction might look something like: + * struct itbl_entry = { + * e_processor processor = e_p3 + * e_type type = e_insn + * char *name = "pig" + * uint value = 0x1 + * uint flags = 0 + * struct itbl_range range = 24-21 + * struct itbl_field *field = { + * e_type type = e_dreg + * struct itbl_range range = 20-16 + * struct itbl_field *next = { + * e_type type = e_immed + * struct itbl_range range = 15-0 + * struct itbl_field *next = 0 + * }; + * }; + * struct itbl_entry *next = 0 + * }; + * + * And the assembler instructions: + * "pig d2,0x100" + * "pig $2,0x100" + * + * would both assemble to the hex value: + * "0x4e220100" + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "itbl-ops.h" +#include "itbl-parse.h" + +/* #define DEBUG */ + +#ifdef DEBUG +#include <assert.h> +#define ASSERT(x) assert(x) +#define DBG(x) printf x +#else +#define ASSERT(x) +#define DBG(x) +#endif + +#ifndef min +#define min(a,b) (a<b?a:b) +#endif + +int itbl_have_entries = 0; + +/*======================================================================*/ +/* structures for keeping itbl format entries */ + +struct itbl_range + { + int sbit; /* mask starting bit position */ + int ebit; /* mask ending bit position */ + }; + +struct itbl_field + { + e_type type; /* dreg/creg/greg/immed/symb */ + struct itbl_range range; /* field's bitfield range within instruction */ + unsigned long flags; /* field flags */ + struct itbl_field *next; /* next field in list */ + }; + + +/* These structures define the instructions and registers for a processor. + * If the type is an instruction, the structure defines the format of an + * instruction where the fields are the list of operands. + * The flags field below uses the same values as those defined in the + * gnu assembler and are machine specific. */ +struct itbl_entry + { + e_processor processor; /* processor number */ + e_type type; /* dreg/creg/greg/insn */ + char *name; /* mnemionic name for insn/register */ + unsigned long value; /* opcode/instruction mask/register number */ + unsigned long flags; /* effects of the instruction */ + struct itbl_range range; /* bit range within instruction for value */ + struct itbl_field *fields; /* list of operand definitions (if any) */ + struct itbl_entry *next; /* next entry */ + }; + + +/* local data and structures */ + +static int itbl_num_opcodes = 0; +/* Array of entries for each processor and entry type */ +static struct itbl_entry *entries[e_nprocs][e_ntypes] = +{ + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +/* local prototypes */ +static unsigned long build_opcode PARAMS ((struct itbl_entry *e)); +static e_type get_type PARAMS ((int yytype)); +static e_processor get_processor PARAMS ((int yyproc)); +static struct itbl_entry **get_entries PARAMS ((e_processor processor, + e_type type)); +static struct itbl_entry *find_entry_byname PARAMS ((e_processor processor, + e_type type, char *name)); +static struct itbl_entry *find_entry_byval PARAMS ((e_processor processor, + e_type type, unsigned long val, struct itbl_range *r)); +static struct itbl_entry *alloc_entry PARAMS ((e_processor processor, + e_type type, char *name, unsigned long value)); +static unsigned long apply_range PARAMS ((unsigned long value, + struct itbl_range r)); +static unsigned long extract_range PARAMS ((unsigned long value, + struct itbl_range r)); +static struct itbl_field *alloc_field PARAMS ((e_type type, int sbit, + int ebit, unsigned long flags)); + + +/*======================================================================*/ +/* Interfaces to the parser */ + + +/* Open the table and use lex and yacc to parse the entries. + * Return 1 for failure; 0 for success. */ + +int +itbl_parse (char *insntbl) +{ + extern FILE *yyin; + extern int yyparse (void); + yyin = fopen (insntbl, "r"); + if (yyin == 0) + { + printf ("Can't open processor instruction specification file \"%s\"\n", + insntbl); + return 1; + } + else + { + while (yyparse ()); + } + fclose (yyin); + itbl_have_entries = 1; + return 0; +} + +/* Add a register entry */ + +struct itbl_entry * +itbl_add_reg (int yyprocessor, int yytype, char *regname, + int regnum) +{ +#if 0 +#include "as.h" +#include "symbols.h" + /* Since register names don't have a prefix, we put them in the symbol table so + they can't be used as symbols. This also simplifies argument parsing as + we can let gas parse registers for us. The recorded register number is + regnum. */ + /* Use symbol_create here instead of symbol_new so we don't try to + output registers into the object file's symbol table. */ + symbol_table_insert (symbol_create (regname, reg_section, + regnum, &zero_address_frag)); +#endif + return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname, + (unsigned long) regnum); +} + +/* Add an instruction entry */ + +struct itbl_entry * +itbl_add_insn (int yyprocessor, char *name, unsigned long value, + int sbit, int ebit, unsigned long flags) +{ + struct itbl_entry *e; + e = alloc_entry (get_processor (yyprocessor), e_insn, name, value); + if (e) + { + e->range.sbit = sbit; + e->range.ebit = ebit; + e->flags = flags; + itbl_num_opcodes++; + } + return e; +} + +/* Add an operand to an instruction entry */ + +struct itbl_field * +itbl_add_operand (struct itbl_entry *e, int yytype, int sbit, + int ebit, unsigned long flags) +{ + struct itbl_field *f, **last_f; + if (!e) + return 0; + /* Add to end of fields' list. */ + f = alloc_field (get_type (yytype), sbit, ebit, flags); + if (f) + { + last_f = &e->fields; + while (*last_f) + last_f = &(*last_f)->next; + *last_f = f; + f->next = 0; + } + return f; +} + + +/*======================================================================*/ +/* Interfaces for assembler and disassembler */ + +#ifndef STAND_ALONE +#include "as.h" +#include "symbols.h" +static void append_insns_as_macros (void); + +/* initialize for gas */ +void +itbl_init (void) +{ + struct itbl_entry *e, **es; + e_processor procn; + e_type type; + + if (!itbl_have_entries) + return; + + /* Since register names don't have a prefix, put them in the symbol table so + they can't be used as symbols. This simplifies argument parsing as + we can let gas parse registers for us. */ + /* Use symbol_create instead of symbol_new so we don't try to + output registers into the object file's symbol table. */ + + for (type = e_regtype0; type < e_nregtypes; type++) + for (procn = e_p0; procn < e_nprocs; procn++) + { + es = get_entries (procn, type); + for (e = *es; e; e = e->next) + { + symbol_table_insert (symbol_create (e->name, reg_section, + e->value, &zero_address_frag)); + } + } + append_insns_as_macros (); +} + + +/* Append insns to opcodes table and increase number of opcodes + * Structure of opcodes table: + * struct itbl_opcode + * { + * const char *name; + * const char *args; - string describing the arguments. + * unsigned long match; - opcode, or ISA level if pinfo=INSN_MACRO + * unsigned long mask; - opcode mask, or macro id if pinfo=INSN_MACRO + * unsigned long pinfo; - insn flags, or INSN_MACRO + * }; + * examples: + * {"li", "t,i", 0x34000000, 0xffe00000, WR_t }, + * {"li", "t,I", 0, (int) M_LI, INSN_MACRO }, + */ + +static char *form_args (struct itbl_entry *e); +static void +append_insns_as_macros (void) +{ + struct ITBL_OPCODE_STRUCT *new_opcodes, *o; + struct itbl_entry *e, **es; + int n, id, size, new_size, new_num_opcodes; + + if (!itbl_have_entries) + return; + + if (!itbl_num_opcodes) /* no new instructions to add! */ + { + return; + } + DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES)); + + new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes; + ASSERT (new_num_opcodes >= itbl_num_opcodes); + + size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES; + ASSERT (size >= 0); + DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0]))); + + new_size = sizeof (struct ITBL_OPCODE_STRUCT) * new_num_opcodes; + ASSERT (new_size > size); + + /* FIXME since ITBL_OPCODES culd be a static table, + we can't realloc or delete the old memory. */ + new_opcodes = (struct ITBL_OPCODE_STRUCT *) malloc (new_size); + if (!new_opcodes) + { + printf ("Unable to allocate memory for new instructions\n"); + return; + } + if (size) /* copy prexisting opcodes table */ + memcpy (new_opcodes, ITBL_OPCODES, size); + + /* FIXME! some NUMOPCODES are calculated expressions. + These need to be changed before itbls can be supported. */ + + id = ITBL_NUM_MACROS; /* begin the next macro id after the last */ + o = &new_opcodes[ITBL_NUM_OPCODES]; /* append macro to opcodes list */ + for (n = e_p0; n < e_nprocs; n++) + { + es = get_entries (n, e_insn); + for (e = *es; e; e = e->next) + { + /* name, args, mask, match, pinfo + * {"li", "t,i", 0x34000000, 0xffe00000, WR_t }, + * {"li", "t,I", 0, (int) M_LI, INSN_MACRO }, + * Construct args from itbl_fields. + */ + o->name = e->name; + o->args = strdup (form_args (e)); + o->mask = apply_range (e->value, e->range); + /* FIXME how to catch durring assembly? */ + /* mask to identify this insn */ + o->match = apply_range (e->value, e->range); + o->pinfo = 0; + +#ifdef USE_MACROS + o->mask = id++; /* FIXME how to catch durring assembly? */ + o->match = 0; /* for macros, the insn_isa number */ + o->pinfo = INSN_MACRO; +#endif + + /* Don't add instructions which caused an error */ + if (o->args) + o++; + else + new_num_opcodes--; + } + } + ITBL_OPCODES = new_opcodes; + ITBL_NUM_OPCODES = new_num_opcodes; + + /* FIXME + At this point, we can free the entries, as they should have + been added to the assembler's tables. + Don't free name though, since name is being used by the new + opcodes table. + + Eventually, we should also free the new opcodes table itself + on exit. + */ +} + +static char * +form_args (struct itbl_entry *e) +{ + static char s[31]; + char c = 0, *p = s; + struct itbl_field *f; + + ASSERT (e); + for (f = e->fields; f; f = f->next) + { + switch (f->type) + { + case e_dreg: + c = 'd'; + break; + case e_creg: + c = 't'; + break; + case e_greg: + c = 's'; + break; + case e_immed: + c = 'i'; + break; + case e_addr: + c = 'a'; + break; + default: + c = 0; /* ignore; unknown field type */ + } + if (c) + { + if (p != s) + *p++ = ','; + *p++ = c; + } + } + *p = 0; + return s; +} +#endif /* !STAND_ALONE */ + + +/* Get processor's register name from val */ + +unsigned long +itbl_get_reg_val (char *name) +{ + e_type t; + e_processor p; + int r = 0; + for (p = e_p0; p < e_nprocs; p++) + for (t = e_regtype0; t < e_nregtypes; t++) + { + if (r = itbl_get_val (p, t, name), r) + return r; + } + return 0; +} + +char * +itbl_get_name (e_processor processor, e_type type, unsigned long val) +{ + struct itbl_entry *r; + /* type depends on instruction passed */ + r = find_entry_byval (processor, type, val, 0); + if (r) + return r->name; + else + return 0; /* error; invalid operand */ +} + +/* Get processor's register value from name */ + +unsigned long +itbl_get_val (e_processor processor, e_type type, char *name) +{ + struct itbl_entry *r; + /* type depends on instruction passed */ + r = find_entry_byname (processor, type, name); + if (r) + return r->value; + else + return 0; /* error; invalid operand */ +} + + +/* Assemble instruction "name" with operands "s". + * name - name of instruction + * s - operands + * returns - long word for assembled instruction */ + +unsigned long +itbl_assemble (char *name, char *s) +{ + unsigned long opcode; + struct itbl_entry *e; + struct itbl_field *f; + char *n; + int processor; + + if (!name || !*name) + return 0; /* error! must have a opcode name/expr */ + + /* find entry in list of instructions for all processors */ + for (processor = 0; processor < e_nprocs; processor++) + { + e = find_entry_byname (processor, e_insn, name); + if (e) + break; + } + if (!e) + return 0; /* opcode not in table; invalid instrustion */ + opcode = build_opcode (e); + + /* parse opcode's args (if any) */ + for (f = e->fields; f; f = f->next) /* for each arg, ... */ + { + struct itbl_entry *r; + unsigned long value; + if (!s || !*s) + return 0; /* error - not enough operands */ + n = itbl_get_field (&s); + /* n should be in form $n or 0xhhh (are symbol names valid?? */ + switch (f->type) + { + case e_dreg: + case e_creg: + case e_greg: + /* Accept either a string name + * or '$' followed by the register number */ + if (*n == '$') + { + n++; + value = strtol (n, 0, 10); + /* FIXME! could have "0l"... then what?? */ + if (value == 0 && *n != '0') + return 0; /* error; invalid operand */ + } + else + { + r = find_entry_byname (e->processor, f->type, n); + if (r) + value = r->value; + else + return 0; /* error; invalid operand */ + } + break; + case e_addr: + /* use assembler's symbol table to find symbol */ + /* FIXME!! Do we need this? + if so, what about relocs?? + my_getExpression (&imm_expr, s); + return 0; /-* error; invalid operand *-/ + break; + */ + /* If not a symbol, fall thru to IMMED */ + case e_immed: + if (*n == '0' && *(n + 1) == 'x') /* hex begins 0x... */ + { + n += 2; + value = strtol (n, 0, 16); + /* FIXME! could have "0xl"... then what?? */ + } + else + { + value = strtol (n, 0, 10); + /* FIXME! could have "0l"... then what?? */ + if (value == 0 && *n != '0') + return 0; /* error; invalid operand */ + } + break; + default: + return 0; /* error; invalid field spec */ + } + opcode |= apply_range (value, f->range); + } + if (s && *s) + return 0; /* error - too many operands */ + return opcode; /* done! */ +} + +/* Disassemble instruction "insn". + * insn - instruction + * s - buffer to hold disassembled instruction + * returns - 1 if succeeded; 0 if failed + */ + +int +itbl_disassemble (char *s, unsigned long insn) +{ + e_processor processor; + struct itbl_entry *e; + struct itbl_field *f; + + if (!ITBL_IS_INSN (insn)) + return 0; /* error*/ + processor = get_processor (ITBL_DECODE_PNUM (insn)); + + /* find entry in list */ + e = find_entry_byval (processor, e_insn, insn, 0); + if (!e) + return 0; /* opcode not in table; invalid instrustion */ + strcpy (s, e->name); + + /* parse insn's args (if any) */ + for (f = e->fields; f; f = f->next) /* for each arg, ... */ + { + struct itbl_entry *r; + unsigned long value; + + if (f == e->fields) /* first operand is preceeded by tab */ + strcat (s, "\t"); + else /* ','s separate following operands */ + strcat (s, ","); + value = extract_range (insn, f->range); + /* n should be in form $n or 0xhhh (are symbol names valid?? */ + switch (f->type) + { + case e_dreg: + case e_creg: + case e_greg: + /* Accept either a string name + * or '$' followed by the register number */ + r = find_entry_byval (e->processor, f->type, value, &f->range); + if (r) + strcat (s, r->name); + else + sprintf (s, "%s$%d", s, value); + break; + case e_addr: + /* use assembler's symbol table to find symbol */ + /* FIXME!! Do we need this? + * if so, what about relocs?? + */ + /* If not a symbol, fall thru to IMMED */ + case e_immed: + sprintf (s, "%s0x%x", s, value); + break; + default: + return 0; /* error; invalid field spec */ + } + } + return 1; /* done! */ +} + +/*======================================================================*/ +/* + * Local functions for manipulating private structures containing + * the names and format for the new instructions and registers + * for each processor. + */ + +/* Calculate instruction's opcode and function values from entry */ + +static unsigned long +build_opcode (struct itbl_entry *e) +{ + unsigned long opcode; + + opcode = apply_range (e->value, e->range); + opcode |= ITBL_ENCODE_PNUM (e->processor); + return opcode; +} + +/* Calculate absolute value given the relative value and bit position range + * within the instruction. + * The range is inclusive where 0 is least significant bit. + * A range of { 24, 20 } will have a mask of + * bit 3 2 1 + * pos: 1098 7654 3210 9876 5432 1098 7654 3210 + * bin: 0000 0001 1111 0000 0000 0000 0000 0000 + * hex: 0 1 f 0 0 0 0 0 + * mask: 0x01f00000. + */ + +static unsigned long +apply_range (unsigned long rval, struct itbl_range r) +{ + unsigned long mask; + unsigned long aval; + int len = MAX_BITPOS - r.sbit; + + ASSERT (r.sbit >= r.ebit); + ASSERT (MAX_BITPOS >= r.sbit); + ASSERT (r.ebit >= 0); + + /* create mask by truncating 1s by shifting */ + mask = 0xffffffff << len; + mask = mask >> len; + mask = mask >> r.ebit; + mask = mask << r.ebit; + + aval = (rval << r.ebit) & mask; + return aval; +} + +/* Calculate relative value given the absolute value and bit position range + * within the instruction. */ + +static unsigned long +extract_range (unsigned long aval, struct itbl_range r) +{ + unsigned long mask; + unsigned long rval; + int len = MAX_BITPOS - r.sbit; + + /* create mask by truncating 1s by shifting */ + mask = 0xffffffff << len; + mask = mask >> len; + mask = mask >> r.ebit; + mask = mask << r.ebit; + + rval = (aval & mask) >> r.ebit; + return rval; +} + +/* Extract processor's assembly instruction field name from s; + * forms are "n args" "n,args" or "n" */ +/* Return next argument from string pointer "s" and advance s. + * delimiters are " ,\0" */ + +char * +itbl_get_field (char **S) +{ + static char n[128]; + char *p, *ps, *s; + int len; + + s = *S; + if (!s || !*s) + return 0; + p = s + strlen (s); + if (ps = strchr (s, ','), ps) + p = ps; + if (ps = strchr (s, ' '), ps) + p = min (p, ps); + if (ps = strchr (s, '\0'), ps) + p = min (p, ps); + if (p == 0) + return 0; /* error! */ + len = p - s; + ASSERT (128 > len + 1); + strncpy (n, s, len); + n[len] = 0; + if (s[len] == '\0') + s = 0; /* no more args */ + else + s += len + 1; /* advance to next arg */ + + *S = s; + return n; +} + +/* Search entries for a given processor and type + * to find one matching the name "n". + * Return a pointer to the entry */ + +static struct itbl_entry * +find_entry_byname (e_processor processor, + e_type type, char *n) +{ + struct itbl_entry *e, **es; + + es = get_entries (processor, type); + for (e = *es; e; e = e->next) /* for each entry, ... */ + { + if (!strcmp (e->name, n)) + return e; + } + return 0; +} + +/* Search entries for a given processor and type + * to find one matching the value "val" for the range "r". + * Return a pointer to the entry. + * This function is used for disassembling fields of an instruction. + */ + +static struct itbl_entry * +find_entry_byval (e_processor processor, e_type type, + unsigned long val, struct itbl_range *r) +{ + struct itbl_entry *e, **es; + unsigned long eval; + + es = get_entries (processor, type); + for (e = *es; e; e = e->next) /* for each entry, ... */ + { + if (processor != e->processor) + continue; + /* For insns, we might not know the range of the opcode, + * so a range of 0 will allow this routine to match against + * the range of the entry to be compared with. + * This could cause ambiguities. + * For operands, we get an extracted value and a range. + */ + /* if range is 0, mask val against the range of the compared entry. */ + if (r == 0) /* if no range passed, must be whole 32-bits + * so create 32-bit value from entry's range */ + { + eval = apply_range (e->value, e->range); + val &= apply_range (0xffffffff, e->range); + } + else if (r->sbit == e->range.sbit && r->ebit == e->range.ebit + || e->range.sbit == 0 && e->range.ebit == 0) + { + eval = apply_range (e->value, *r); + val = apply_range (val, *r); + } + else + continue; + if (val == eval) + return e; + } + return 0; +} + +/* Return a pointer to the list of entries for a given processor and type. */ + +static struct itbl_entry ** +get_entries (e_processor processor, e_type type) +{ + return &entries[processor][type]; +} + +/* Return an integral value for the processor passed from yyparse. */ + +static e_processor +get_processor (int yyproc) +{ + /* translate from yacc's processor to enum */ + if (yyproc >= e_p0 && yyproc < e_nprocs) + return (e_processor) yyproc; + return e_invproc; /* error; invalid processor */ +} + +/* Return an integral value for the entry type passed from yyparse. */ + +static e_type +get_type (int yytype) +{ + switch (yytype) + { + /* translate from yacc's type to enum */ + case INSN: + return e_insn; + case DREG: + return e_dreg; + case CREG: + return e_creg; + case GREG: + return e_greg; + case ADDR: + return e_addr; + case IMMED: + return e_immed; + default: + return e_invtype; /* error; invalid type */ + } +} + + +/* Allocate and initialize an entry */ + +static struct itbl_entry * +alloc_entry (e_processor processor, e_type type, + char *name, unsigned long value) +{ + struct itbl_entry *e, **es; + if (!name) + return 0; + e = (struct itbl_entry *) malloc (sizeof (struct itbl_entry)); + if (e) + { + memset (e, 0, sizeof (struct itbl_entry)); + e->name = (char *) malloc (sizeof (strlen (name)) + 1); + if (e->name) + strcpy (e->name, name); + e->processor = processor; + e->type = type; + e->value = value; + es = get_entries (e->processor, e->type); + e->next = *es; + *es = e; + } + return e; +} + +/* Allocate and initialize an entry's field */ + +static struct itbl_field * +alloc_field (e_type type, int sbit, int ebit, + unsigned long flags) +{ + struct itbl_field *f; + f = (struct itbl_field *) malloc (sizeof (struct itbl_field)); + if (f) + { + memset (f, 0, sizeof (struct itbl_field)); + f->type = type; + f->range.sbit = sbit; + f->range.ebit = ebit; + f->flags = flags; + } + return f; +} diff --git a/contrib/binutils/gas/itbl-ops.h b/contrib/binutils/gas/itbl-ops.h new file mode 100644 index 0000000..2946eff --- /dev/null +++ b/contrib/binutils/gas/itbl-ops.h @@ -0,0 +1,109 @@ +/* itbl-ops.h + Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* External functions, constants and defines for itbl support */ + +#include "ansidecl.h" + +/* Include file notes: "expr.h" needed before targ-*.h, + * "targ-env.h" includes the chain of target dependant headers, + * "targ-cpu.h" has the HAVE_ITBL_CPU define, and + * as.h includes them all */ +#include "as.h" + +#ifdef HAVE_ITBL_CPU +#include "itbl-cpu.h" +#endif + +/* Defaults for definitions required by generic code */ +#ifndef ITBL_NUMBER_OF_PROCESSORS +#define ITBL_NUMBER_OF_PROCESSORS 1 +#endif + +#ifndef ITBL_MAX_BITPOS +#define ITBL_MAX_BITPOS 31 +#endif + +#ifndef ITBL_TYPE +#define ITBL_TYPE unsigned long +#endif + +#ifndef ITBL_IS_INSN +#define ITBL_IS_INSN(insn) 1 +#endif + +#ifndef ITBL_DECODE_PNUM +#define ITBL_DECODE_PNUM(insn) 0 +#endif + +#ifndef ITBL_ENCODE_PNUM +#define ITBL_ENCODE_PNUM(pnum) 0 +#endif + +typedef ITBL_TYPE t_insn; + +/* types of entries */ +typedef enum + { + e_insn, + e_dreg, + e_regtype0 = e_dreg, + e_creg, + e_greg, + e_addr, + e_nregtypes = e_greg + 1, + e_immed, + e_ntypes, + e_invtype /* invalid type */ + } e_type; + +typedef enum + { + e_p0, + e_nprocs = NUMBER_OF_PROCESSORS, + e_invproc /* invalid processor */ + } e_processor; + +/* 0 means an instruction table was not specified. */ +extern int itbl_have_entries; + +/* These routines are visible to the main part of the assembler */ + +int itbl_parse PARAMS ((char *insntbl)); +void itbl_init PARAMS ((void)); +char *itbl_get_field PARAMS ((char **s)); +unsigned long itbl_assemble PARAMS ((char *name, char *operands)); +int itbl_disassemble PARAMS ((char *str, unsigned long insn)); +int itbl_parse PARAMS ((char *tbl)); /* parses insn tbl */ +unsigned long itbl_get_reg_val PARAMS ((char *name)); +unsigned long itbl_get_val PARAMS ((e_processor processor, e_type type, + char *name)); +char *itbl_get_name PARAMS ((e_processor processor, e_type type, + unsigned long val)); + +/* These routines are called by the table parser used to build the + dynamic list of new processor instructions and registers. */ + +struct itbl_entry *itbl_add_reg PARAMS ((int yyproc, int yytype, + char *regname, int regnum)); +struct itbl_entry *itbl_add_insn PARAMS ((int yyproc, char *name, + unsigned long value, int sbit, int ebit, unsigned long flags)); +struct itbl_field *itbl_add_operand PARAMS ((struct itbl_entry * e, int yytype, + int sbit, int ebit, unsigned long flags)); diff --git a/contrib/binutils/gas/itbl-parse.y b/contrib/binutils/gas/itbl-parse.y new file mode 100644 index 0000000..7966ee8 --- /dev/null +++ b/contrib/binutils/gas/itbl-parse.y @@ -0,0 +1,459 @@ +/* itbl-parse.y + Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +%{ + +/* + +Yacc grammar for instruction table entries. + +======================================================================= +Original Instruction table specification document: + + MIPS Coprocessor Table Specification + ==================================== + +This document describes the format of the MIPS coprocessor table. The +table specifies a list of valid functions, data registers and control +registers that can be used in coprocessor instructions. This list, +together with the coprocessor instruction classes listed below, +specifies the complete list of coprocessor instructions that will +be recognized and assembled by the GNU assembler. In effect, +this makes the GNU assembler table-driven, where the table is +specified by the programmer. + +The table is an ordinary text file that the GNU assembler reads when +it starts. Using the information in the table, the assembler +generates an internal list of valid coprocessor registers and +functions. The assembler uses this internal list in addition to the +standard MIPS registers and instructions which are built-in to the +assembler during code generation. + +To specify the coprocessor table when invoking the GNU assembler, use +the command line option "--itbl file", where file is the +complete name of the table, including path and extension. + +Examples: + + gas -t cop.tbl test.s -o test.o + gas -t /usr/local/lib/cop.tbl test.s -o test.o + gas --itbl d:\gnu\data\cop.tbl test.s -o test.o + +Only one table may be supplied during a single invocation of +the assembler. + + +Instruction classes +=================== + +Below is a list of the valid coprocessor instruction classes for +any given coprocessor "z". These instructions are already recognized +by the assembler, and are listed here only for reference. + +Class format instructions +------------------------------------------------- +Class1: + op base rt offset + LWCz rt,offset (base) + SWCz rt,offset (base) +Class2: + COPz sub rt rd 0 + MTCz rt,rd + MFCz rt,rd + CTCz rt,rd + CFCz rt,rd +Class3: + COPz CO cofun + COPz cofun +Class4: + COPz BC br offset + BCzT offset + BCzF offset +Class5: + COPz sub rt rd 0 + DMFCz rt,rd + DMTCz rt,rd +Class6: + op base rt offset + LDCz rt,offset (base) + SDCz rt,offset (base) +Class7: + COPz BC br offset + BCzTL offset + BCzFL offset + +The coprocessor table defines coprocessor-specific registers that can +be used with all of the above classes of instructions, where +appropriate. It also defines additional coprocessor-specific +functions for Class3 (COPz cofun) instructions, Thus, the table allows +the programmer to use convenient mnemonics and operands for these +functions, instead of the COPz mmenmonic and cofun operand. + +The names of the MIPS general registers and their aliases are defined +by the assembler and will be recognized as valid register names by the +assembler when used (where allowed) in coprocessor instructions. +However, the names and values of all coprocessor data and control +register mnemonics must be specified in the coprocessor table. + + +Table Grammar +============= + +Here is the grammar for the coprocessor table: + + table -> entry* + + entry -> [z entrydef] [comment] '\n' + + entrydef -> type name val + entrydef -> 'insn' name val funcdef ; type of entry (instruction) + + z -> 'p'['0'..'3'] ; processor number + type -> ['dreg' | 'creg' | 'greg' ] ; type of entry (register) + ; 'dreg', 'creg' or 'greg' specifies a data, control, or general + ; register mnemonic, respectively + name -> [ltr|dec]* ; mnemonic of register/function + val -> [dec|hex] ; register/function number (integer constant) + + funcdef -> frange flags fields + ; bitfield range for opcode + ; list of fields' formats + fields -> field* + field -> [','] ftype frange flags + flags -> ['*' flagexpr] + flagexpr -> '[' flagexpr ']' + flagexpr -> val '|' flagexpr + ftype -> [ type | 'immed' | 'addr' ] + ; 'immed' specifies an immediate value; see grammar for "val" above + ; 'addr' specifies a C identifier; name of symbol to be resolved at + ; link time + frange -> ':' val '-' val ; starting to ending bit positions, where + ; where 0 is least significant bit + frange -> (null) ; default range of 31-0 will be assumed + + comment -> [';'|'#'] [char]* + char -> any printable character + ltr -> ['a'..'z'|'A'..'Z'] + dec -> ['0'..'9']* ; value in decimal + hex -> '0x'['0'..'9' | 'a'..'f' | 'A'..'F']* ; value in hexidecimal + + +Examples +======== + +Example 1: + +The table: + + p1 dreg d1 1 ; data register "d1" for COP1 has value 1 + p1 creg c3 3 ; ctrl register "c3" for COP1 has value 3 + p3 func fill 0x1f:24-20 ; function "fill" for COP3 has value 31 and + ; no fields + +will allow the assembler to accept the following coprocessor instructions: + + LWC1 d1,0x100 ($2) + fill + +Here, the general purpose register "$2", and instruction "LWC1", are standard +mnemonics built-in to the MIPS assembler. + + +Example 2: + +The table: + + p3 dreg d3 3 ; data register "d3" for COP3 has value 3 + p3 creg c2 22 ; control register "c2" for COP3 has value 22 + p3 func fee 0x1f:24-20 dreg:17-13 creg:12-8 immed:7-0 + ; function "fee" for COP3 has value 31, and 3 fields + ; consisting of a data register, a control register, + ; and an immediate value. + +will allow the assembler to accept the following coprocessor instruction: + + fee d3,c2,0x1 + +and will emit the object code: + + 31-26 25 24-20 19-18 17-13 12-8 7-0 + COPz CO fun dreg creg immed + 010011 1 11111 00 00011 10110 00000001 + + 0x4ff07601 + + +Example 3: + +The table: + + p3 dreg d3 3 ; data register "d3" for COP3 has value 3 + p3 creg c2 22 ; control register "c2" for COP3 has value 22 + p3 func fuu 0x01f00001 dreg:17-13 creg:12-8 + +will allow the assembler to accept the following coprocessor +instruction: + + fuu d3,c2 + +and will emit the object code: + + 31-26 25 24-20 19-18 17-13 12-8 7-0 + COPz CO fun dreg creg + 010011 1 11111 00 00011 10110 00000001 + + 0x4ff07601 + +In this way, the programmer can force arbitrary bits of an instruction +to have predefined values. + +======================================================================= +Additional notes: + +Encoding of ranges: +To handle more than one bit position range within an instruction, +use 0s to mask out the ranges which don't apply. +May decide to modify the syntax to allow commas separate multiple +ranges within an instruction (range','range). + +Changes in grammar: + The number of parms argument to the function entry +was deleted from the original format such that we now count the fields. + +---- +FIXME! should really change lexical analyzer +to recognize 'dreg' etc. in context sensative way. +Currently function names or mnemonics may be incorrectly parsed as keywords + +FIXME! hex is ambiguous with any digit + +*/ + +#include <stdio.h> +#include "itbl-ops.h" + +/* #define DEBUG */ + +#ifdef DEBUG +#ifndef DBG_LVL +#define DBG_LVL 1 +#endif +#else +#define DBG_LVL 0 +#endif + +#if DBG_LVL >= 1 +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +#if DBG_LVL >= 2 +#define DBGL2(x) printf x +#else +#define DBGL2(x) +#endif + +static int sbit, ebit; +static struct itbl_entry *insn=0; +extern int insntbl_line; +int yyparse PARAMS ((void)); +int yylex PARAMS ((void)); +static int yyerror PARAMS ((const char *)); + +%} + +%union + { + char *str; + int num; + int processor; + unsigned long val; + } + +%token DREG CREG GREG IMMED ADDR INSN NUM ID NL PNUM +%type <val> value flags flagexpr +%type <num> number NUM ftype regtype pnum PNUM +%type <str> ID name + +%start insntbl + +%% + +insntbl: + entrys + ; + +entrys: + entry entrys + | + ; + +entry: + pnum regtype name value NL + { + DBG (("line %d: entry pnum=%d type=%d name=%s value=x%x\n", + insntbl_line, $1, $2, $3, $4)); + itbl_add_reg ($1, $2, $3, $4); + } + | pnum INSN name value range flags + { + DBG (("line %d: entry pnum=%d type=INSN name=%s value=x%x", + insntbl_line, $1, $3, $4)); + DBG ((" sbit=%d ebit=%d flags=0x%x\n", sbit, ebit, $6)); + insn=itbl_add_insn ($1, $3, $4, sbit, ebit, $6); + } + fieldspecs NL + | NL + | error NL + ; + +fieldspecs: + ',' fieldspec fieldspecs + | fieldspec fieldspecs + | + ; + +ftype: + regtype + { + DBGL2 (("ftype\n")); + $$ = $1; + } + | ADDR + { + DBGL2 (("addr\n")); + $$ = ADDR; + } + | IMMED + { + DBGL2 (("immed\n")); + $$ = IMMED; + } + ; + +fieldspec: + ftype range flags + { + DBG (("line %d: field type=%d sbit=%d ebit=%d, flags=0x%x\n", + insntbl_line, $1, sbit, ebit, $3)); + itbl_add_operand (insn, $1, sbit, ebit, $3); + } + ; + +flagexpr: + NUM '|' flagexpr + { + $$ = $1 | $3; + } + | '[' flagexpr ']' + { + $$ = $2; + } + | NUM + { + $$ = $1; + } + ; + +flags: + '*' flagexpr + { + DBGL2 (("flags=%d\n", $2)); + $$ = $2; + } + | + { + $$ = 0; + } + ; + +range: + ':' NUM '-' NUM + { + DBGL2 (("range %d %d\n", $2, $4)); + sbit = $2; + ebit = $4; + } + | + { + sbit = 31; + ebit = 0; + } + ; + +pnum: + PNUM + { + DBGL2 (("pnum=%d\n",$1)); + $$ = $1; + } + ; + +regtype: + DREG + { + DBGL2 (("dreg\n")); + $$ = DREG; + } + | CREG + { + DBGL2 (("creg\n")); + $$ = CREG; + } + | GREG + { + DBGL2 (("greg\n")); + $$ = GREG; + } + ; + +name: + ID + { + DBGL2 (("name=%s\n",$1)); + $$ = $1; + } + ; + +number: + NUM + { + DBGL2 (("num=%d\n",$1)); + $$ = $1; + } + ; + +value: + NUM + { + DBGL2 (("val=x%x\n",$1)); + $$ = $1; + } + ; +%% + +static int +yyerror (msg) + const char *msg; +{ + printf ("line %d: %s\n", insntbl_line, msg); + return 0; +} diff --git a/contrib/binutils/gas/link.cmd b/contrib/binutils/gas/link.cmd new file mode 100644 index 0000000..a035ca8 --- /dev/null +++ b/contrib/binutils/gas/link.cmd @@ -0,0 +1,10 @@ +ALIGN=1024 +RESNUM 0x0000, 0x8000 +; Putting in .lit1 gives errors. +ORDER .data=0x80002000, .data1, .lit, .bss +; Let's put this on the command line so it goes first, which is what +; GDB expects. +; LOAD /s2/amd/29k/lib/crt0.o +LOAD /s2/amd/29k/lib/libqcb0h.lib +LOAD /s2/amd/29k/lib/libscb0h.lib +LOAD /s2/amd/29k/lib/libacb0h.lib diff --git a/contrib/binutils/gas/listing.c b/contrib/binutils/gas/listing.c new file mode 100644 index 0000000..f0c2295 --- /dev/null +++ b/contrib/binutils/gas/listing.c @@ -0,0 +1,1241 @@ +/* listing.c - mainting assembly listings + Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* + Contributed by Steve Chamberlain + sac@cygnus.com + + + A listing page looks like: + + LISTING_HEADER sourcefilename pagenumber + TITLE LINE + SUBTITLE LINE + linenumber address data source + linenumber address data source + linenumber address data source + linenumber address data source + + If not overridden, the listing commands are: + + .title "stuff" + Put "stuff" onto the title line + .sbttl "stuff" + Put stuff onto the subtitle line + + If these commands come within 10 lines of the top of the page, they + will affect the page they are on, as well as any subsequent page + + .eject + Thow a page + .list + Increment the enable listing counter + .nolist + Decrement the enable listing counter + + .psize Y[,X] + Set the paper size to X wide and Y high. Setting a psize Y of + zero will suppress form feeds except where demanded by .eject + + If the counter goes below zero, listing is suppressed. + + + Listings are a maintained by read calling various listing_<foo> + functions. What happens most is that the macro NO_LISTING is not + defined (from the Makefile), then the macro LISTING_NEWLINE expands + into a call to listing_newline. The call is done from read.c, every + time it sees a newline, and -l is on the command line. + + The function listing_newline remembers the frag associated with the + newline, and creates a new frag - note that this is wasteful, but not + a big deal, since listing slows things down a lot anyway. The + function also rememebers when the filename changes. + + When all the input has finished, and gas has had a chance to settle + down, the listing is output. This is done by running down the list of + frag/source file records, and opening the files as needed and printing + out the bytes and chars associated with them. + + The only things which the architecture can change about the listing + are defined in these macros: + + LISTING_HEADER The name of the architecture + LISTING_WORD_SIZE The make of the number of bytes in a word, this determines + the clumping of the output data. eg a value of + 2 makes words look like 1234 5678, whilst 1 + would make the same value look like 12 34 56 + 78 + LISTING_LHS_WIDTH Number of words of above size for the lhs + + LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs + for the second line + + LISTING_LHS_CONT_LINES Max number of lines to use up for a continutation + LISTING_RHS_WIDTH Number of chars from the input file to print + on a line +*/ + +#include <ctype.h> + +#include "as.h" +#include <obstack.h> +#include "input-file.h" +#include "subsegs.h" + +#ifndef NO_LISTING +#ifndef LISTING_HEADER +#define LISTING_HEADER "GAS LISTING" +#endif +#ifndef LISTING_WORD_SIZE +#define LISTING_WORD_SIZE 4 +#endif +#ifndef LISTING_LHS_WIDTH +#define LISTING_LHS_WIDTH 1 +#endif +#ifndef LISTING_LHS_WIDTH_SECOND +#define LISTING_LHS_WIDTH_SECOND 1 +#endif +#ifndef LISTING_RHS_WIDTH +#define LISTING_RHS_WIDTH 100 +#endif +#ifndef LISTING_LHS_CONT_LINES +#define LISTING_LHS_CONT_LINES 4 +#endif + + + + +/* This structure remembers which .s were used */ +typedef struct file_info_struct +{ + char *filename; + int linenum; + FILE *file; + struct file_info_struct *next; + int at_end; +} + +file_info_type; + + +/* this structure rememebrs which line from which file goes into which + frag */ +typedef struct list_info_struct +{ + /* Frag which this line of source is nearest to */ + fragS *frag; + /* The actual line in the source file */ + unsigned int line; + /* Pointer to the file info struct for the file which this line + belongs to */ + file_info_type *file; + + /* Next in list */ + struct list_info_struct *next; + + + /* Pointer to the file info struct for the high level language + source line that belongs here */ + file_info_type *hll_file; + + /* High level language source line */ + int hll_line; + + + /* Pointer to any error message associated with this line */ + char *message; + + enum + { + EDICT_NONE, + EDICT_SBTTL, + EDICT_TITLE, + EDICT_NOLIST, + EDICT_LIST, + EDICT_NOLIST_NEXT, + EDICT_EJECT + } edict; + char *edict_arg; + +} + +list_info_type; + + +static struct list_info_struct *head; +struct list_info_struct *listing_tail; +extern int listing; + +static int paper_width = 200; +static int paper_height = 60; + +/* File to output listings to. */ +static FILE *list_file; + +/* this static array is used to keep the text of data to be printed + before the start of the line. + It is stored so we can give a bit more info on the next line. To much, and large + initialized arrays will use up lots of paper. + */ + +static char data_buffer[100]; +static unsigned int data_buffer_size; + + +/* Prototypes. */ +static void listing_message PARAMS ((const char *name, const char *message)); +static file_info_type *file_info PARAMS ((const char *file_name)); +static void new_frag PARAMS ((void)); +static char *buffer_line PARAMS ((file_info_type *file, + char *line, unsigned int size)); +static void listing_page PARAMS ((list_info_type *list)); +static unsigned int calc_hex PARAMS ((list_info_type *list)); +static void print_lines PARAMS ((list_info_type *, unsigned int, + char *, unsigned int)); +static void list_symbol_table PARAMS ((void)); +static void print_source PARAMS ((file_info_type *current_file, + list_info_type *list, + char *buffer, + unsigned int width)); +static int debugging_pseudo PARAMS ((char *line)); +static void listing_listing PARAMS ((char *name)); + + +static void +listing_message (name, message) + const char *name; + const char *message; +{ + unsigned int l = strlen (name) + strlen (message) + 1; + char *n = (char *) xmalloc (l); + strcpy (n, name); + strcat (n, message); + if (listing_tail != (list_info_type *) NULL) + { + listing_tail->message = n; + } +} + +void +listing_warning (message) + const char *message; +{ + listing_message ("Warning:", message); +} + +void +listing_error (message) + const char *message; +{ + listing_message ("Error:", message); +} + + + + +static file_info_type *file_info_head; + +static file_info_type * +file_info (file_name) + const char *file_name; +{ + /* Find an entry with this file name */ + file_info_type *p = file_info_head; + + while (p != (file_info_type *) NULL) + { + if (strcmp (p->filename, file_name) == 0) + return p; + p = p->next; + } + + /* Make new entry */ + + p = (file_info_type *) xmalloc (sizeof (file_info_type)); + p->next = file_info_head; + file_info_head = p; + p->filename = xmalloc ((unsigned long) strlen (file_name) + 1); + strcpy (p->filename, file_name); + p->linenum = 0; + p->at_end = 0; + + p->file = fopen (p->filename, "r"); + if (p->file) + fgetc (p->file); + + return p; +} + + +static void +new_frag () +{ + + frag_wane (frag_now); + frag_new (0); + +} + +void +listing_newline (ps) + char *ps; +{ + char *file; + unsigned int line; + static unsigned int last_line = 0xffff; + static char *last_file = NULL; + list_info_type *new; + + if (listing == 0) + return; + + if (now_seg == absolute_section) + return; + + as_where (&file, &line); + if (line != last_line || (last_file && file && strcmp(file, last_file))) + { + last_line = line; + last_file = file; + new_frag (); + + new = (list_info_type *) xmalloc (sizeof (list_info_type)); + new->frag = frag_now; + new->line = line; + new->file = file_info (file); + + if (listing_tail) + { + listing_tail->next = new; + } + else + { + head = new; + } + listing_tail = new; + new->next = (list_info_type *) NULL; + new->message = (char *) NULL; + new->edict = EDICT_NONE; + new->hll_file = (file_info_type *) NULL; + new->hll_line = 0; + new_frag (); + } +} + +/* Attach all current frags to the previous line instead of the + current line. This is called by the MIPS backend when it discovers + that it needs to add some NOP instructions; the added NOP + instructions should go with the instruction that has the delay, not + with the new instruction. */ + +void +listing_prev_line () +{ + list_info_type *l; + fragS *f; + + if (head == (list_info_type *) NULL + || head == listing_tail) + return; + + new_frag (); + + for (l = head; l->next != listing_tail; l = l->next) + ; + + for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next) + if (f->line == listing_tail) + f->line = l; + + listing_tail->frag = frag_now; + new_frag (); +} + +/* + This function returns the next source line from the file supplied, + truncated to size. It appends a fake line to the end of each input + file to make +*/ + +static char * +buffer_line (file, line, size) + file_info_type * file; + char *line; + unsigned int size; +{ + unsigned int count = 0; + int c; + + char *p = line; + + /* If we couldn't open the file, return an empty line */ + if (file->file == (FILE *) NULL || file->at_end) + { + return ""; + } + + if (file->linenum == 0) + rewind (file->file); + + c = fgetc (file->file); + + size -= 1; /* leave room for null */ + + while (c != EOF && c != '\n') + { + if (count < size) + *p++ = c; + count++; + + c = fgetc (file->file); + + } + if (c == EOF) + { + file->at_end = 1; + *p++ = '.'; + *p++ = '.'; + *p++ = '.'; + } + file->linenum++; + *p++ = 0; + return line; +} + + +static const char *fn; + +static unsigned int eject; /* Eject pending */ +static unsigned int page; /* Current page number */ +static char *title; /* current title */ +static char *subtitle; /* current subtitle */ +static unsigned int on_page; /* number of lines printed on current page */ + + +static void +listing_page (list) + list_info_type *list; +{ + /* Grope around, see if we can see a title or subtitle edict coming up + soon (we look down 10 lines of the page and see if it's there)*/ + if ((eject || (on_page >= paper_height)) && paper_height != 0) + { + unsigned int c = 10; + int had_title = 0; + int had_subtitle = 0; + + page++; + + while (c != 0 && list) + { + if (list->edict == EDICT_SBTTL && !had_subtitle) + { + had_subtitle = 1; + subtitle = list->edict_arg; + } + if (list->edict == EDICT_TITLE && !had_title) + { + had_title = 1; + title = list->edict_arg; + } + list = list->next; + c--; + } + + + if (page > 1) + { + fprintf (list_file, "\f"); + } + + fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page); + fprintf (list_file, "%s\n", title); + fprintf (list_file, "%s\n", subtitle); + on_page = 3; + eject = 0; + } +} + + +static unsigned int +calc_hex (list) + list_info_type * list; +{ + list_info_type *first = list; + unsigned int address = (unsigned int) ~0; + + fragS *frag; + fragS *frag_ptr; + + unsigned int byte_in_frag; + + + /* Find first frag which says it belongs to this line */ + frag = list->frag; + while (frag && frag->line != list) + frag = frag->fr_next; + + frag_ptr = frag; + + data_buffer_size = 0; + + /* Dump all the frags which belong to this line */ + while (frag_ptr != (fragS *) NULL && frag_ptr->line == first) + { + /* Print as many bytes from the fixed part as is sensible */ + byte_in_frag = 0; + while (byte_in_frag < frag_ptr->fr_fix && data_buffer_size < sizeof (data_buffer) - 10) + { + if (address == ~0) + { + address = frag_ptr->fr_address; + } + + sprintf (data_buffer + data_buffer_size, + "%02X", + (frag_ptr->fr_literal[byte_in_frag]) & 0xff); + data_buffer_size += 2; + byte_in_frag++; + } + { + unsigned int var_rep_max = byte_in_frag; + unsigned int var_rep_idx = byte_in_frag; + + /* Print as many bytes from the variable part as is sensible */ + while ((byte_in_frag + < frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset) + && data_buffer_size < sizeof (data_buffer) - 10) + { + if (address == ~0) + { + address = frag_ptr->fr_address; + } + sprintf (data_buffer + data_buffer_size, + "%02X", + (frag_ptr->fr_literal[var_rep_idx]) & 0xff); +#if 0 + data_buffer[data_buffer_size++] = '*'; + data_buffer[data_buffer_size++] = '*'; +#endif + data_buffer_size += 2; + + var_rep_idx++; + byte_in_frag++; + + if (var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var) + var_rep_idx = var_rep_max; + } + } + + frag_ptr = frag_ptr->fr_next; + } + data_buffer[data_buffer_size++] = 0; + return address; +} + + + + + + +static void +print_lines (list, lineno, string, address) + list_info_type *list; + unsigned int lineno; + char *string; + unsigned int address; +{ + unsigned int idx; + unsigned int nchars; + unsigned int lines; + unsigned int byte_in_word = 0; + char *src = data_buffer; + + /* Print the stuff on the first line */ + listing_page (list); + nchars = (LISTING_WORD_SIZE * 2 + 1) * LISTING_LHS_WIDTH; + /* Print the hex for the first line */ + if (address == ~0) + { + fprintf (list_file, "% 4d ", lineno); + for (idx = 0; idx < nchars; idx++) + fprintf (list_file, " "); + + fprintf (list_file, "\t%s\n", string ? string : ""); + on_page++; + listing_page (0); + + } + else + { + if (had_errors ()) + { + fprintf (list_file, "% 4d ???? ", lineno); + } + else + { + fprintf (list_file, "% 4d %04x ", lineno, address); + } + + /* And the data to go along with it */ + idx = 0; + + while (*src && idx < nchars) + { + fprintf (list_file, "%c%c", src[0], src[1]); + src += 2; + byte_in_word++; + if (byte_in_word == LISTING_WORD_SIZE) + { + fprintf (list_file, " "); + idx++; + byte_in_word = 0; + } + idx += 2; + } + + for (; idx < nchars; idx++) + fprintf (list_file, " "); + + fprintf (list_file, "\t%s\n", string ? string : ""); + on_page++; + listing_page (list); + if (list->message) + { + fprintf (list_file, "**** %s\n", list->message); + listing_page (list); + on_page++; + } + + for (lines = 0; + lines < LISTING_LHS_CONT_LINES + && *src; + lines++) + { + nchars = ((LISTING_WORD_SIZE * 2) + 1) * LISTING_LHS_WIDTH_SECOND - 1; + idx = 0; + /* Print any more lines of data, but more compactly */ + fprintf (list_file, "% 4d ", lineno); + + while (*src && idx < nchars) + { + fprintf (list_file, "%c%c", src[0], src[1]); + src += 2; + idx += 2; + byte_in_word++; + if (byte_in_word == LISTING_WORD_SIZE) + { + fprintf (list_file, " "); + idx++; + byte_in_word = 0; + } + } + + fprintf (list_file, "\n"); + on_page++; + listing_page (list); + + } + + + } +} + + +static void +list_symbol_table () +{ + extern symbolS *symbol_rootP; + int got_some = 0; + + symbolS *ptr; + eject = 1; + listing_page (0); + + for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) + { + if (ptr->sy_frag->line) + { + if (S_GET_NAME (ptr)) + { + char buf[30], fmt[8]; + valueT val = S_GET_VALUE (ptr); + + /* @@ Note that this is dependent on the compilation options, + not solely on the target characteristics. */ + if (sizeof (val) == 4 && sizeof (int) == 4) + sprintf (buf, "%08lx", (unsigned long) val); + else if (sizeof (val) <= sizeof (unsigned long)) + { + sprintf (fmt, "%%0%lulx", + (unsigned long) (sizeof (val) * 2)); + sprintf (buf, fmt, (unsigned long) val); + } +#if defined (BFD64) + else if (sizeof (val) > 4) + sprintf_vma (buf, val); +#endif + else + abort (); + + if (!got_some) + { + fprintf (list_file, "DEFINED SYMBOLS\n"); + on_page++; + got_some = 1; + } + + fprintf (list_file, "%20s:%-5d %s:%s %s\n", + ptr->sy_frag->line->file->filename, + ptr->sy_frag->line->line, + segment_name (S_GET_SEGMENT (ptr)), + buf, S_GET_NAME (ptr)); + + on_page++; + listing_page (0); + } + } + + } + if (!got_some) + { + fprintf (list_file, "NO DEFINED SYMBOLS\n"); + on_page++; + } + fprintf (list_file, "\n"); + on_page++; + listing_page (0); + + got_some = 0; + + for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) + { + if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0) + { + if (ptr->sy_frag->line == 0 +#ifdef S_IS_REGISTER + && !S_IS_REGISTER (ptr) +#endif + && S_GET_SEGMENT (ptr) != reg_section) + { + if (!got_some) + { + got_some = 1; + fprintf (list_file, "UNDEFINED SYMBOLS\n"); + on_page++; + listing_page (0); + } + fprintf (list_file, "%s\n", S_GET_NAME (ptr)); + on_page++; + listing_page (0); + } + } + } + if (!got_some) + { + fprintf (list_file, "NO UNDEFINED SYMBOLS\n"); + on_page++; + listing_page (0); + } +} + +static void +print_source (current_file, list, buffer, width) + file_info_type *current_file; + list_info_type *list; + char *buffer; + unsigned int width; +{ + if (current_file->file) + { + while (current_file->linenum < list->hll_line + && !current_file->at_end) + { + char *p = buffer_line (current_file, buffer, width); + fprintf (list_file, "%4d:%-13s **** %s\n", current_file->linenum, + current_file->filename, p); + on_page++; + listing_page (list); + } + } +} + +/* Sometimes the user doesn't want to be bothered by the debugging + records inserted by the compiler, see if the line is suspicious */ + +static int +debugging_pseudo (line) + char *line; +{ + while (isspace (*line)) + line++; + + if (*line != '.') + return 0; + + line++; + + if (strncmp (line, "def", 3) == 0) + return 1; + if (strncmp (line, "val", 3) == 0) + return 1; + if (strncmp (line, "scl", 3) == 0) + return 1; + if (strncmp (line, "line", 4) == 0) + return 1; + if (strncmp (line, "endef", 5) == 0) + return 1; + if (strncmp (line, "ln", 2) == 0) + return 1; + if (strncmp (line, "type", 4) == 0) + return 1; + if (strncmp (line, "size", 4) == 0) + return 1; + if (strncmp (line, "dim", 3) == 0) + return 1; + if (strncmp (line, "tag", 3) == 0) + return 1; + + if (strncmp (line, "stabs", 5) == 0) + return 1; + if (strncmp (line, "stabn", 5) == 0) + return 1; + + return 0; + +} + +static void +listing_listing (name) + char *name; +{ + list_info_type *list = head; + file_info_type *current_hll_file = (file_info_type *) NULL; + char *message; + char *buffer; + char *p; + int show_listing = 1; + unsigned int width; + + buffer = xmalloc (LISTING_RHS_WIDTH); + eject = 1; + list = head; + + while (list != (list_info_type *) NULL && 0) + { + if (list->next) + list->frag = list->next->frag; + list = list->next; + + } + + list = head->next; + + + while (list) + { + width = LISTING_RHS_WIDTH > paper_width ? paper_width : + LISTING_RHS_WIDTH; + + switch (list->edict) + { + case EDICT_LIST: + show_listing++; + break; + case EDICT_NOLIST: + show_listing--; + break; + case EDICT_NOLIST_NEXT: + break; + case EDICT_EJECT: + break; + case EDICT_NONE: + break; + case EDICT_TITLE: + title = list->edict_arg; + break; + case EDICT_SBTTL: + subtitle = list->edict_arg; + break; + default: + abort (); + } + + if (show_listing > 0) + { + /* Scan down the list and print all the stuff which can be done + with this line (or lines). */ + message = 0; + + if (list->hll_file) + { + current_hll_file = list->hll_file; + } + + if (current_hll_file && list->hll_line && listing & LISTING_HLL) + { + print_source (current_hll_file, list, buffer, width); + } + + while (list->file->file + && list->file->linenum < list->line + && !list->file->at_end) + { + unsigned int address; + + p = buffer_line (list->file, buffer, width); + + if (list->file->linenum < list->line) + address = ~ (unsigned int) 0; + else + address = calc_hex (list); + + if (!((listing & LISTING_NODEBUG) && debugging_pseudo (p))) + print_lines (list, list->file->linenum, p, address); + } + + if (list->edict == EDICT_EJECT) + { + eject = 1; + } + } + else + { + while (list->file->file + && list->file->linenum < list->line + && !list->file->at_end) + p = buffer_line (list->file, buffer, width); + } + + if (list->edict == EDICT_NOLIST_NEXT) + --show_listing; + + list = list->next; + } + free (buffer); +} + +void +listing_print (name) + char *name; +{ + int using_stdout; + file_info_type *fi; + + title = ""; + subtitle = ""; + + if (name == NULL) + { + list_file = stdout; + using_stdout = 1; + } + else + { + list_file = fopen (name, "w"); + if (list_file != NULL) + using_stdout = 0; + else + { + as_perror ("can't open list file: %s", name); + list_file = stdout; + using_stdout = 1; + } + } + + if (listing & LISTING_NOFORM) + { + paper_height = 0; + } + + if (listing & LISTING_LISTING) + { + listing_listing (name); + } + + if (listing & LISTING_SYMBOLS) + { + list_symbol_table (); + } + + if (! using_stdout) + { + if (fclose (list_file) == EOF) + as_perror ("error closing list file: %s", name); + } + + for (fi = file_info_head; fi != NULL; fi = fi->next) + { + if (fi->file != NULL) + { + fclose (fi->file); + fi->file = NULL; + } + } +} + + +void +listing_file (name) + const char *name; +{ + fn = name; +} + +void +listing_eject (ignore) + int ignore; +{ + if (listing) + listing_tail->edict = EDICT_EJECT; +} + +void +listing_flags (ignore) + int ignore; +{ + while ((*input_line_pointer++) && (*input_line_pointer != '\n')) + input_line_pointer++; + +} + +/* Turn listing on or off. An argument of 0 means to turn off + listing. An argument of 1 means to turn on listing. An argument + of 2 means to turn off listing, but as of the next line; that is, + the current line should be listed, but the next line should not. */ + +void +listing_list (on) + int on; +{ + if (listing) + { + switch (on) + { + case 0: + if (listing_tail->edict == EDICT_LIST) + listing_tail->edict = EDICT_NONE; + else + listing_tail->edict = EDICT_NOLIST; + break; + case 1: + if (listing_tail->edict == EDICT_NOLIST + || listing_tail->edict == EDICT_NOLIST_NEXT) + listing_tail->edict = EDICT_NONE; + else + listing_tail->edict = EDICT_LIST; + break; + case 2: + listing_tail->edict = EDICT_NOLIST_NEXT; + break; + default: + abort (); + } + } +} + + +void +listing_psize (width_only) + int width_only; +{ + if (! width_only) + { + paper_height = get_absolute_expression (); + + if (paper_height < 0 || paper_height > 1000) + { + paper_height = 0; + as_warn ("strange paper height, set to no form"); + } + + if (*input_line_pointer != ',') + { + demand_empty_rest_of_line (); + return; + } + + ++input_line_pointer; + } + + paper_width = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +void +listing_nopage (ignore) + int ignore; +{ + paper_height = 0; +} + +void +listing_title (depth) + int depth; +{ + int quoted; + char *start; + char *ttl; + unsigned int length; + + SKIP_WHITESPACE (); + if (*input_line_pointer != '\"') + quoted = 0; + else + { + quoted = 1; + ++input_line_pointer; + } + + start = input_line_pointer; + + while (*input_line_pointer) + { + if (quoted + ? *input_line_pointer == '\"' + : is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (listing) + { + length = input_line_pointer - start; + ttl = xmalloc (length + 1); + memcpy (ttl, start, length); + ttl[length] = 0; + listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE; + listing_tail->edict_arg = ttl; + } + if (quoted) + input_line_pointer++; + demand_empty_rest_of_line (); + return; + } + else if (*input_line_pointer == '\n') + { + as_bad ("New line in title"); + demand_empty_rest_of_line (); + return; + } + else + { + input_line_pointer++; + } + } +} + + + +void +listing_source_line (line) + unsigned int line; +{ + if (listing) + { + new_frag (); + listing_tail->hll_line = line; + new_frag (); + } +} + +void +listing_source_file (file) + const char *file; +{ + if (listing) + listing_tail->hll_file = file_info (file); +} + + + +#else + + +/* Dummy functions for when compiled without listing enabled */ + +void +listing_flags (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_list (on) + int on; +{ + s_ignore (0); +} + +void +listing_eject (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_psize (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_nopage (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_title (depth) + int depth; +{ + s_ignore (0); +} + +void +listing_file (name) + const char *name; +{ + +} + +void +listing_newline (name) + char *name; +{ + +} + +void +listing_source_line (n) + unsigned int n; +{ + +} +void +listing_source_file (n) + const char *n; +{ + +} + +#endif diff --git a/contrib/binutils/gas/listing.h b/contrib/binutils/gas/listing.h new file mode 100644 index 0000000..8e36b64 --- /dev/null +++ b/contrib/binutils/gas/listing.h @@ -0,0 +1,60 @@ +/* This file is listing.h + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef __listing_h__ +#define __listing_h__ + +#define LISTING_LISTING 1 +#define LISTING_SYMBOLS 2 +#define LISTING_NOFORM 4 +#define LISTING_HLL 8 +#define LISTING_NODEBUG 16 +#define LISTING_NOCOND 32 + +#define LISTING_DEFAULT (LISTING_LISTING | LISTING_HLL | LISTING_SYMBOLS) + +#ifndef NO_LISTING +#define LISTING_NEWLINE() { if (listing) listing_newline(input_line_pointer); } +#else +#define LISTING_NEWLINE() {;} +#endif + +#define LISTING_SKIP_COND() ((listing & LISTING_NOCOND) != 0) + +void listing_eject PARAMS ((int)); +void listing_error PARAMS ((const char *message)); +void listing_file PARAMS ((const char *name)); +void listing_flags PARAMS ((int)); +void listing_list PARAMS ((int on)); +void listing_newline PARAMS ((char *ps)); +void listing_prev_line PARAMS ((void)); +void listing_print PARAMS ((char *name)); +void listing_psize PARAMS ((int)); +void listing_nopage PARAMS ((int)); +void listing_source_file PARAMS ((const char *)); +void listing_source_line PARAMS ((unsigned int)); +void listing_title PARAMS ((int depth)); +void listing_warning PARAMS ((const char *message)); +void listing_width PARAMS ((unsigned int x)); + +#endif /* __listing_h__ */ + +/* end of listing.h */ diff --git a/contrib/binutils/gas/literal.c b/contrib/binutils/gas/literal.c new file mode 100644 index 0000000..a3f8fc4 --- /dev/null +++ b/contrib/binutils/gas/literal.c @@ -0,0 +1,95 @@ +/* as.c - GAS literal pool management. + Copyright (C) 1994 Free Software Foundation, Inc. + Written by Ken Raeburn (raeburn@cygnus.com). + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This isn't quite a "constant" pool. Some of the values may get + adjusted at run time, e.g., for symbolic relocations when shared + libraries are in use. It's more of a "literal" pool. + + On the Alpha, this should be used for .lita and .lit8. (Is there + ever a .lit4?) On the MIPS, it could be used for .lit4 as well. + + The expressions passed here should contain either constants or symbols, + not a combination of both. Typically, the constant pool is accessed + with some sort of GP register, so the size of the pool must be kept down + if possible. The exception is section offsets -- if you're storing a + pointer to the start of .data, for example, and your machine provides + for 16-bit signed addends, you might want to store .data+32K, so that + you can access all of the first 64K of .data with the one pointer. + + This isn't a requirement, just a guideline that can help keep .o file + size down. */ + +#include "as.h" +#include "subsegs.h" + +#if defined (BFD_ASSEMBLER) && defined (NEED_LITERAL_POOL) + +valueT +add_to_literal_pool (sym, addend, sec, size) + symbolS *sym; + valueT addend; + segT sec; + int size; +{ + segT current_section = now_seg; + int current_subsec = now_subseg; + valueT offset; + bfd_reloc_code_real_type reloc_type; + char *p; + segment_info_type *seginfo = seg_info (sec); + fixS *fixp; + + offset = 0; + /* @@ This assumes all entries in a given section will be of the same + size... Probably correct, but unwise to rely on. */ + /* This must always be called with the same subsegment. */ + if (seginfo->frchainP) + for (fixp = seginfo->frchainP->fix_root; + fixp != (fixS *) NULL; + fixp = fixp->fx_next, offset += size) + { + if (fixp->fx_addsy == sym && fixp->fx_offset == addend) + return offset; + } + + subseg_set (sec, 0); + p = frag_more (size); + memset (p, 0, size); + + switch (size) + { + case 4: + reloc_type = BFD_RELOC_32; + break; + case 8: + reloc_type = BFD_RELOC_64; + break; + default: + abort (); + } + fix_new (frag_now, p - frag_now->fr_literal, size, sym, addend, 0, + reloc_type); + + subseg_set (current_section, current_subsec); + offset = seginfo->literal_pool_size; + seginfo->literal_pool_size += size; + return offset; +} +#endif /* BFD_ASSEMBLER */ diff --git a/contrib/binutils/gas/macro.c b/contrib/binutils/gas/macro.c new file mode 100644 index 0000000..e2f1ff9 --- /dev/null +++ b/contrib/binutils/gas/macro.c @@ -0,0 +1,1231 @@ +/* macro.c - macro support for gas and gasp + Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include <stdio.h> +#ifdef HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include <ctype.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include "libiberty.h" +#include "sb.h" +#include "hash.h" +#include "macro.h" + +/* The routines in this file handle macro definition and expansion. + They are called by both gasp and gas. */ + +/* Structures used to store macros. + + Each macro knows its name and included text. It gets built with a + list of formal arguments, and also keeps a hash table which points + into the list to speed up formal search. Each formal knows its + name and its default value. Each time the macro is expanded, the + formals get the actual values attatched to them. */ + +/* describe the formal arguments to a macro */ + +typedef struct formal_struct + { + struct formal_struct *next; /* next formal in list */ + sb name; /* name of the formal */ + sb def; /* the default value */ + sb actual; /* the actual argument (changed on each expansion) */ + int index; /* the index of the formal 0..formal_count-1 */ + } +formal_entry; + +/* Other values found in the index field of a formal_entry. */ +#define QUAL_INDEX (-1) +#define NARG_INDEX (-2) +#define LOCAL_INDEX (-3) + +/* describe the macro. */ + +typedef struct macro_struct + { + sb sub; /* substitution text. */ + int formal_count; /* number of formal args. */ + formal_entry *formals; /* pointer to list of formal_structs */ + struct hash_control *formal_hash; /* hash table of formals. */ + } +macro_entry; + +/* Internal functions. */ + +static int get_token PARAMS ((int, sb *, sb *)); +static int getstring PARAMS ((int, sb *, sb *)); +static int get_any_string PARAMS ((int, sb *, sb *, int, int)); +static int do_formals PARAMS ((macro_entry *, int, sb *)); +static int get_apost_token PARAMS ((int, sb *, sb *, int)); +static int sub_actual + PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int)); +static const char *macro_expand_body + PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int, int)); +static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int)); + +#define ISWHITE(x) ((x) == ' ' || (x) == '\t') + +#define ISSEP(x) \ + ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ + || (x) == '<' || (x) == '>' || (x) == ')' || (x) == '(') + +#define ISBASE(x) \ + ((x) == 'b' || (x) == 'B' \ + || (x) == 'q' || (x) == 'Q' \ + || (x) == 'h' || (x) == 'H' \ + || (x) == 'd' || (x) == 'D') + +/* The macro hash table. */ + +static struct hash_control *macro_hash; + +/* Whether any macros have been defined. */ + +int macro_defined; + +/* Whether we are in GASP alternate mode. */ + +static int macro_alternate; + +/* Whether we are in MRI mode. */ + +static int macro_mri; + +/* Whether we should strip '@' characters. */ + +static int macro_strip_at; + +/* Function to use to parse an expression. */ + +static int (*macro_expr) PARAMS ((const char *, int, sb *, int *)); + +/* Number of macro expansions that have been done. */ + +static int macro_number; + +/* Initialize macro processing. */ + +void +macro_init (alternate, mri, strip_at, expr) + int alternate; + int mri; + int strip_at; + int (*expr) PARAMS ((const char *, int, sb *, int *)); +{ + macro_hash = hash_new (); + macro_defined = 0; + macro_alternate = alternate; + macro_mri = mri; + macro_strip_at = strip_at; + macro_expr = expr; +} + +/* Read input lines till we get to a TO string. + Increase nesting depth if we get a FROM string. + Put the results into sb at PTR. + Add a new input line to an sb using GET_LINE. + Return 1 on success, 0 on unexpected EOF. */ + +int +buffer_and_nest (from, to, ptr, get_line) + const char *from; + const char *to; + sb *ptr; + int (*get_line) PARAMS ((sb *)); +{ + int from_len = strlen (from); + int to_len = strlen (to); + int depth = 1; + int line_start = ptr->len; + + int more = get_line (ptr); + + while (more) + { + /* Try and find the first pseudo op on the line */ + int i = line_start; + + if (! macro_alternate && ! macro_mri) + { + /* With normal syntax we can suck what we want till we get + to the dot. With the alternate, labels have to start in + the first column, since we cant tell what's a label and + whats a pseudoop */ + + /* Skip leading whitespace */ + while (i < ptr->len && ISWHITE (ptr->ptr[i])) + i++; + + /* Skip over a label */ + while (i < ptr->len + && (isalnum ((unsigned char) ptr->ptr[i]) + || ptr->ptr[i] == '_' + || ptr->ptr[i] == '$')) + i++; + + /* And a colon */ + if (i < ptr->len + && ptr->ptr[i] == ':') + i++; + + } + /* Skip trailing whitespace */ + while (i < ptr->len && ISWHITE (ptr->ptr[i])) + i++; + + if (i < ptr->len && (ptr->ptr[i] == '.' + || macro_alternate + || macro_mri)) + { + if (ptr->ptr[i] == '.') + i++; + if (strncasecmp (ptr->ptr + i, from, from_len) == 0) + depth++; + if (strncasecmp (ptr->ptr + i, to, to_len) == 0) + { + depth--; + if (depth == 0) + { + /* Reset the string to not include the ending rune */ + ptr->len = line_start; + break; + } + } + } + + /* Add a CR to the end and keep running */ + sb_add_char (ptr, '\n'); + line_start = ptr->len; + more = get_line (ptr); + } + + /* Return 1 on success, 0 on unexpected EOF. */ + return depth == 0; +} + +/* Pick up a token. */ + +static int +get_token (idx, in, name) + int idx; + sb *in; + sb *name; +{ + if (idx < in->len + && (isalpha ((unsigned char) in->ptr[idx]) + || in->ptr[idx] == '_' + || in->ptr[idx] == '$')) + { + sb_add_char (name, in->ptr[idx++]); + while (idx < in->len + && (isalnum ((unsigned char) in->ptr[idx]) + || in->ptr[idx] == '_' + || in->ptr[idx] == '$')) + { + sb_add_char (name, in->ptr[idx++]); + } + } + /* Ignore trailing & */ + if (macro_alternate && idx < in->len && in->ptr[idx] == '&') + idx++; + return idx; +} + +/* Pick up a string. */ + +static int +getstring (idx, in, acc) + int idx; + sb *in; + sb *acc; +{ + idx = sb_skip_white (idx, in); + + while (idx < in->len + && (in->ptr[idx] == '"' + || in->ptr[idx] == '<' + || (in->ptr[idx] == '\'' && macro_alternate))) + { + if (in->ptr[idx] == '<') + { + if (macro_alternate || macro_mri) + { + int nest = 0; + idx++; + while ((in->ptr[idx] != '>' || nest) + && idx < in->len) + { + if (in->ptr[idx] == '!') + { + idx++ ; + sb_add_char (acc, in->ptr[idx++]); + } + else + { + if (in->ptr[idx] == '>') + nest--; + if (in->ptr[idx] == '<') + nest++; + sb_add_char (acc, in->ptr[idx++]); + } + } + idx++; + } + else + { + int code; + idx++; + idx = ((*macro_expr) + ("character code in string must be absolute expression", + idx, in, &code)); + sb_add_char (acc, code); + +#if 0 + if (in->ptr[idx] != '>') + ERROR ((stderr, "Missing > for character code.\n")); +#endif + idx++; + } + } + else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + idx++; + while (idx < in->len) + { + if (macro_alternate && in->ptr[idx] == '!') + { + idx++ ; + sb_add_char (acc, in->ptr[idx++]); + } + else + { + if (in->ptr[idx] == tchar) + { + idx++; + if (idx >= in->len || in->ptr[idx] != tchar) + break; + } + sb_add_char (acc, in->ptr[idx]); + idx++; + } + } + } + } + + return idx; +} + +/* Fetch string from the input stream, + rules: + 'Bxyx<whitespace> -> return 'Bxyza + %<char> -> return string of decimal value of x + "<string>" -> return string + xyx<whitespace> -> return xyz +*/ + +static int +get_any_string (idx, in, out, expand, pretend_quoted) + int idx; + sb *in; + sb *out; + int expand; + int pretend_quoted; +{ + sb_reset (out); + idx = sb_skip_white (idx, in); + + if (idx < in->len) + { + if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx])) + { + while (!ISSEP (in->ptr[idx])) + sb_add_char (out, in->ptr[idx++]); + } + else if (in->ptr[idx] == '%' + && macro_alternate + && expand) + { + int val; + char buf[20]; + /* Turns the next expression into a string */ + idx = (*macro_expr) ("% operator needs absolute expression", + idx + 1, + in, + &val); + sprintf(buf, "%d", val); + sb_add_string (out, buf); + } + else if (in->ptr[idx] == '"' + || in->ptr[idx] == '<' + || (macro_alternate && in->ptr[idx] == '\'')) + { + if (macro_alternate + && ! macro_strip_at + && expand) + { + /* Keep the quotes */ + sb_add_char (out, '\"'); + + idx = getstring (idx, in, out); + sb_add_char (out, '\"'); + } + else + { + idx = getstring (idx, in, out); + } + } + else + { + while (idx < in->len + && (in->ptr[idx] == '"' + || in->ptr[idx] == '\'' + || pretend_quoted + || (in->ptr[idx] != ' ' + && in->ptr[idx] != '\t' + && in->ptr[idx] != ',' + && in->ptr[idx] != '<'))) + { + if (in->ptr[idx] == '"' + || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + sb_add_char (out, in->ptr[idx++]); + while (idx < in->len + && in->ptr[idx] != tchar) + sb_add_char (out, in->ptr[idx++]); + if (idx == in->len) + return idx; + } + sb_add_char (out, in->ptr[idx++]); + } + } + } + + return idx; +} + +/* Pick up the formal parameters of a macro definition. */ + +static int +do_formals (macro, idx, in) + macro_entry *macro; + int idx; + sb *in; +{ + formal_entry **p = ¯o->formals; + + macro->formal_count = 0; + macro->formal_hash = hash_new (); + while (idx < in->len) + { + formal_entry *formal; + + formal = (formal_entry *) xmalloc (sizeof (formal_entry)); + + sb_new (&formal->name); + sb_new (&formal->def); + sb_new (&formal->actual); + + idx = sb_skip_white (idx, in); + idx = get_token (idx, in, &formal->name); + if (formal->name.len == 0) + break; + idx = sb_skip_white (idx, in); + if (formal->name.len) + { + /* This is a formal */ + if (idx < in->len && in->ptr[idx] == '=') + { + /* Got a default */ + idx = get_any_string (idx + 1, in, &formal->def, 1, 0); + } + } + + /* Add to macro's hash table */ + hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); + + formal->index = macro->formal_count; + idx = sb_skip_comma (idx, in); + macro->formal_count++; + *p = formal; + p = &formal->next; + *p = NULL; + } + + if (macro_mri) + { + formal_entry *formal; + const char *name; + + /* Add a special NARG formal, which macro_expand will set to the + number of arguments. */ + formal = (formal_entry *) xmalloc (sizeof (formal_entry)); + + sb_new (&formal->name); + sb_new (&formal->def); + sb_new (&formal->actual); + + /* The same MRI assemblers which treat '@' characters also use + the name $NARG. At least until we find an exception. */ + if (macro_strip_at) + name = "$NARG"; + else + name = "NARG"; + + sb_add_string (&formal->name, name); + + /* Add to macro's hash table */ + hash_jam (macro->formal_hash, name, formal); + + formal->index = NARG_INDEX; + *p = formal; + formal->next = NULL; + } + + return idx; +} + +/* Define a new macro. Returns NULL on success, otherwise returns an + error message. If NAMEP is not NULL, *NAMEP is set to the name of + the macro which was defined. */ + +const char * +define_macro (idx, in, label, get_line, namep) + int idx; + sb *in; + sb *label; + int (*get_line) PARAMS ((sb *)); + const char **namep; +{ + macro_entry *macro; + sb name; + const char *namestr; + + macro = (macro_entry *) xmalloc (sizeof (macro_entry)); + sb_new (¯o->sub); + sb_new (&name); + + macro->formal_count = 0; + macro->formals = 0; + + idx = sb_skip_white (idx, in); + if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) + return "unexpected end of file in macro definition"; + if (label != NULL && label->len != 0) + { + sb_add_sb (&name, label); + if (in->ptr[idx] == '(') + { + /* It's the label: MACRO (formals,...) sort */ + idx = do_formals (macro, idx + 1, in); + if (in->ptr[idx] != ')') + return "missing ) after formals"; + } + else + { + /* It's the label: MACRO formals,... sort */ + idx = do_formals (macro, idx, in); + } + } + else + { + idx = get_token (idx, in, &name); + idx = sb_skip_comma (idx, in); + idx = do_formals (macro, idx, in); + } + + /* and stick it in the macro hash table */ + for (idx = 0; idx < name.len; idx++) + if (isupper (name.ptr[idx])) + name.ptr[idx] = tolower (name.ptr[idx]); + namestr = sb_terminate (&name); + hash_jam (macro_hash, namestr, (PTR) macro); + + macro_defined = 1; + + if (namep != NULL) + *namep = namestr; + + return NULL; +} + +/* Scan a token, and then skip KIND. */ + +static int +get_apost_token (idx, in, name, kind) + int idx; + sb *in; + sb *name; + int kind; +{ + idx = get_token (idx, in, name); + if (idx < in->len + && in->ptr[idx] == kind + && (! macro_mri || macro_strip_at) + && (! macro_strip_at || kind == '@')) + idx++; + return idx; +} + +/* Substitute the actual value for a formal parameter. */ + +static int +sub_actual (start, in, t, formal_hash, kind, out, copyifnotthere) + int start; + sb *in; + sb *t; + struct hash_control *formal_hash; + int kind; + sb *out; + int copyifnotthere; +{ + int src; + formal_entry *ptr; + + src = get_apost_token (start, in, t, kind); + /* See if it's in the macro's hash table, unless this is + macro_strip_at and kind is '@' and the token did not end in '@'. */ + if (macro_strip_at + && kind == '@' + && (src == start || in->ptr[src - 1] != '@')) + ptr = NULL; + else + ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); + if (ptr) + { + if (ptr->actual.len) + { + sb_add_sb (out, &ptr->actual); + } + else + { + sb_add_sb (out, &ptr->def); + } + } + else if (copyifnotthere) + { + sb_add_sb (out, t); + } + else + { + sb_add_char (out, '\\'); + sb_add_sb (out, t); + } + return src; +} + +/* Expand the body of a macro. */ + +static const char * +macro_expand_body (in, out, formals, formal_hash, comment_char, locals) + sb *in; + sb *out; + formal_entry *formals; + struct hash_control *formal_hash; + int comment_char; + int locals; +{ + sb t; + int src = 0; + int inquote = 0; + formal_entry *loclist = NULL; + + sb_new (&t); + + while (src < in->len) + { + if (in->ptr[src] == '&') + { + sb_reset (&t); + if (macro_mri) + { + if (src + 1 < in->len && in->ptr[src + 1] == '&') + src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); + else + sb_add_char (out, in->ptr[src++]); + } + else + { + /* FIXME: Why do we do this? It prevents people from + using the & operator in a macro. */ + src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); + } + } + else if (in->ptr[src] == '\\') + { + src++; + if (in->ptr[src] == comment_char && comment_char != '\0') + { + /* This is a comment, just drop the rest of the line */ + while (src < in->len + && in->ptr[src] != '\n') + src++; + } + else if (in->ptr[src] == '(') + { + /* Sub in till the next ')' literally */ + src++; + while (src < in->len && in->ptr[src] != ')') + { + sb_add_char (out, in->ptr[src++]); + } + if (in->ptr[src] == ')') + src++; + else + return "missplaced )"; + } + else if (in->ptr[src] == '@') + { + /* Sub in the macro invocation number */ + + char buffer[6]; + src++; + sprintf (buffer, "%05d", macro_number); + sb_add_string (out, buffer); + } + else if (in->ptr[src] == '&') + { + /* This is a preprocessor variable name, we don't do them + here */ + sb_add_char (out, '\\'); + sb_add_char (out, '&'); + src++; + } + else if (macro_mri + && isalnum ((unsigned char) in->ptr[src])) + { + int ind; + formal_entry *f; + + if (isdigit ((unsigned char) in->ptr[src])) + ind = in->ptr[src] - '0'; + else if (isupper ((unsigned char) in->ptr[src])) + ind = in->ptr[src] - 'A' + 10; + else + ind = in->ptr[src] - 'a' + 10; + ++src; + for (f = formals; f != NULL; f = f->next) + { + if (f->index == ind - 1) + { + if (f->actual.len != 0) + sb_add_sb (out, &f->actual); + else + sb_add_sb (out, &f->def); + break; + } + } + } + else + { + sb_reset (&t); + src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); + } + } + else if ((macro_alternate || macro_mri) + && (isalpha ((unsigned char) in->ptr[src]) + || in->ptr[src] == '_' + || in->ptr[src] == '$') + && (! inquote + || ! macro_strip_at + || (src > 0 && in->ptr[src - 1] == '@'))) + { + if (! locals + || src + 5 >= in->len + || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 + || ! ISWHITE (in->ptr[src + 5])) + { + sb_reset (&t); + src = sub_actual (src, in, &t, formal_hash, + (macro_strip_at && inquote) ? '@' : '\'', + out, 1); + } + else + { + formal_entry *f; + + src = sb_skip_white (src + 5, in); + while (in->ptr[src] != '\n' && in->ptr[src] != comment_char) + { + static int loccnt; + char buf[20]; + const char *err; + + f = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&f->name); + sb_new (&f->def); + sb_new (&f->actual); + f->index = LOCAL_INDEX; + f->next = loclist; + loclist = f; + + src = get_token (src, in, &f->name); + ++loccnt; + sprintf (buf, "LL%04x", loccnt); + sb_add_string (&f->actual, buf); + + err = hash_jam (formal_hash, sb_terminate (&f->name), f); + if (err != NULL) + return err; + + src = sb_skip_comma (src, in); + } + } + } + else if (comment_char != '\0' + && in->ptr[src] == comment_char + && src + 1 < in->len + && in->ptr[src + 1] == comment_char + && !inquote) + { + /* Two comment chars in a row cause the rest of the line to + be dropped. */ + while (src < in->len && in->ptr[src] != '\n') + src++; + } + else if (in->ptr[src] == '"' + || (macro_mri && in->ptr[src] == '\'')) + { + inquote = !inquote; + sb_add_char (out, in->ptr[src++]); + } + else if (in->ptr[src] == '@' && macro_strip_at) + { + ++src; + if (src < in->len + && in->ptr[src] == '@') + { + sb_add_char (out, '@'); + ++src; + } + } + else if (macro_mri + && in->ptr[src] == '=' + && src + 1 < in->len + && in->ptr[src + 1] == '=') + { + formal_entry *ptr; + + sb_reset (&t); + src = get_token (src + 2, in, &t); + ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); + if (ptr == NULL) + { + /* FIXME: We should really return a warning string here, + but we can't, because the == might be in the MRI + comment field, and, since the nature of the MRI + comment field depends upon the exact instruction + being used, we don't have enough information here to + figure out whether it is or not. Instead, we leave + the == in place, which should cause a syntax error if + it is not in a comment. */ + sb_add_char (out, '='); + sb_add_char (out, '='); + sb_add_sb (out, &t); + } + else + { + if (ptr->actual.len) + { + sb_add_string (out, "-1"); + } + else + { + sb_add_char (out, '0'); + } + } + } + else + { + sb_add_char (out, in->ptr[src++]); + } + } + + sb_kill (&t); + + while (loclist != NULL) + { + formal_entry *f; + + f = loclist->next; + hash_delete (formal_hash, sb_terminate (&loclist->name)); + sb_kill (&loclist->name); + sb_kill (&loclist->def); + sb_kill (&loclist->actual); + free (loclist); + loclist = f; + } + + return NULL; +} + +/* Assign values to the formal parameters of a macro, and expand the + body. */ + +static const char * +macro_expand (idx, in, m, out, comment_char) + int idx; + sb *in; + macro_entry *m; + sb *out; + int comment_char; +{ + sb t; + formal_entry *ptr; + formal_entry *f; + int is_positional = 0; + int is_keyword = 0; + int narg = 0; + const char *err; + + sb_new (&t); + + /* Reset any old value the actuals may have */ + for (f = m->formals; f; f = f->next) + sb_reset (&f->actual); + f = m->formals; + while (f != NULL && f->index < 0) + f = f->next; + + if (macro_mri) + { + /* The macro may be called with an optional qualifier, which may + be referred to in the macro body as \0. */ + if (idx < in->len && in->ptr[idx] == '.') + { + formal_entry *n; + + n = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&n->name); + sb_new (&n->def); + sb_new (&n->actual); + n->index = QUAL_INDEX; + + n->next = m->formals; + m->formals = n; + + idx = get_any_string (idx + 1, in, &n->actual, 1, 0); + } + } + + /* Peel off the actuals and store them away in the hash tables' actuals */ + idx = sb_skip_white (idx, in); + while (idx < in->len && in->ptr[idx] != comment_char) + { + int scan; + + /* Look and see if it's a positional or keyword arg */ + scan = idx; + while (scan < in->len + && !ISSEP (in->ptr[scan]) + && (!macro_alternate && in->ptr[scan] != '=')) + scan++; + if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') + { + is_keyword = 1; + if (is_positional) + return "can't mix positional and keyword arguments"; + + /* This is a keyword arg, fetch the formal name and + then the actual stuff */ + sb_reset (&t); + idx = get_token (idx, in, &t); + if (in->ptr[idx] != '=') + return "confusion in formal parameters"; + + /* Lookup the formal in the macro's list */ + ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); + if (!ptr) + return "macro formal argument does not exist"; + else + { + /* Insert this value into the right place */ + sb_reset (&ptr->actual); + idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0); + if (ptr->actual.len > 0) + ++narg; + } + } + else + { + /* This is a positional arg */ + is_positional = 1; + if (is_keyword) + return "can't mix positional and keyword arguments"; + + if (!f) + { + formal_entry **pf; + int c; + + if (!macro_mri) + return "too many positional arguments"; + + f = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&f->name); + sb_new (&f->def); + sb_new (&f->actual); + f->next = NULL; + + c = -1; + for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) + if ((*pf)->index >= c) + c = (*pf)->index + 1; + if (c == -1) + c = 0; + *pf = f; + f->index = c; + } + + sb_reset (&f->actual); + idx = get_any_string (idx, in, &f->actual, 1, 0); + if (f->actual.len > 0) + ++narg; + do + { + f = f->next; + } + while (f != NULL && f->index < 0); + } + + if (! macro_mri) + idx = sb_skip_comma (idx, in); + else + { + if (in->ptr[idx] == ',') + ++idx; + if (ISWHITE (in->ptr[idx])) + break; + } + } + + if (macro_mri) + { + char buffer[20]; + + sb_reset (&t); + sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); + ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); + sb_reset (&ptr->actual); + sprintf (buffer, "%d", narg); + sb_add_string (&ptr->actual, buffer); + } + + err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, + comment_char, 1); + if (err != NULL) + return err; + + /* Discard any unnamed formal arguments. */ + if (macro_mri) + { + formal_entry **pf; + + pf = &m->formals; + while (*pf != NULL) + { + if ((*pf)->name.len != 0) + pf = &(*pf)->next; + else + { + sb_kill (&(*pf)->name); + sb_kill (&(*pf)->def); + sb_kill (&(*pf)->actual); + f = (*pf)->next; + free (*pf); + *pf = f; + } + } + } + + sb_kill (&t); + macro_number++; + + return NULL; +} + +/* Check for a macro. If one is found, put the expansion into + *EXPAND. COMMENT_CHAR is the comment character--this is used by + gasp. Return 1 if a macro is found, 0 otherwise. */ + +int +check_macro (line, expand, comment_char, error) + const char *line; + sb *expand; + int comment_char; + const char **error; +{ + const char *s; + char *copy, *cs; + macro_entry *macro; + sb line_sb; + + if (! isalpha ((unsigned char) *line) + && *line != '_' + && *line != '$' + && (! macro_mri || *line != '.')) + return 0; + + s = line + 1; + while (isalnum ((unsigned char) *s) + || *s == '_' + || *s == '$') + ++s; + + copy = (char *) xmalloc (s - line + 1); + memcpy (copy, line, s - line); + copy[s - line] = '\0'; + for (cs = copy; *cs != '\0'; cs++) + if (isupper (*cs)) + *cs = tolower (*cs); + + macro = (macro_entry *) hash_find (macro_hash, copy); + + if (macro == NULL) + return 0; + + /* Wrap the line up in an sb. */ + sb_new (&line_sb); + while (*s != '\0' && *s != '\n' && *s != '\r') + sb_add_char (&line_sb, *s++); + + sb_new (expand); + *error = macro_expand (0, &line_sb, macro, expand, comment_char); + + sb_kill (&line_sb); + + return 1; +} + +/* Delete a macro. */ + +void +delete_macro (name) + const char *name; +{ + hash_delete (macro_hash, name); +} + +/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a + combined macro definition and execution. This returns NULL on + success, or an error message otherwise. */ + +const char * +expand_irp (irpc, idx, in, out, get_line, comment_char) + int irpc; + int idx; + sb *in; + sb *out; + int (*get_line) PARAMS ((sb *)); + int comment_char; +{ + const char *mn; + sb sub; + formal_entry f; + struct hash_control *h; + const char *err; + + if (irpc) + mn = "IRPC"; + else + mn = "IRP"; + + idx = sb_skip_white (idx, in); + + sb_new (&sub); + if (! buffer_and_nest (mn, "ENDR", &sub, get_line)) + return "unexpected end of file in irp or irpc"; + + sb_new (&f.name); + sb_new (&f.def); + sb_new (&f.actual); + + idx = get_token (idx, in, &f.name); + if (f.name.len == 0) + return "missing model parameter"; + + h = hash_new (); + err = hash_jam (h, sb_terminate (&f.name), &f); + if (err != NULL) + return err; + + f.index = 1; + f.next = NULL; + + sb_reset (out); + + idx = sb_skip_comma (idx, in); + if (idx >= in->len || in->ptr[idx] == comment_char) + { + /* Expand once with a null string. */ + err = macro_expand_body (&sub, out, &f, h, comment_char, 0); + if (err != NULL) + return err; + } + else + { + if (irpc && in->ptr[idx] == '"') + ++idx; + while (idx < in->len && in->ptr[idx] != comment_char) + { + if (!irpc) + idx = get_any_string (idx, in, &f.actual, 1, 0); + else + { + if (in->ptr[idx] == '"') + { + int nxt; + + nxt = sb_skip_white (idx + 1, in); + if (nxt >= in->len || in->ptr[nxt] == comment_char) + { + idx = nxt; + break; + } + } + sb_reset (&f.actual); + sb_add_char (&f.actual, in->ptr[idx]); + ++idx; + } + err = macro_expand_body (&sub, out, &f, h, comment_char, 0); + if (err != NULL) + return err; + if (!irpc) + idx = sb_skip_comma (idx, in); + else + idx = sb_skip_white (idx, in); + } + } + + hash_die (h); + sb_kill (&sub); + + return NULL; +} diff --git a/contrib/binutils/gas/macro.h b/contrib/binutils/gas/macro.h new file mode 100644 index 0000000..7b73064 --- /dev/null +++ b/contrib/binutils/gas/macro.h @@ -0,0 +1,52 @@ +/* macro.h - header file for macro support for gas and gasp + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef MACRO_H + +#define MACRO_H + +#include "ansidecl.h" +#include "sb.h" + +/* Whether any macros have been defined. */ + +extern int macro_defined; + +/* The macro nesting level. */ + +extern int macro_nest; + +extern int buffer_and_nest + PARAMS ((const char *, const char *, sb *, int (*) PARAMS ((sb *)))); +extern void macro_init + PARAMS ((int alternate, int mri, int strip_at, + int (*) PARAMS ((const char *, int, sb *, int *)))); +extern const char *define_macro + PARAMS ((int idx, sb *in, sb *label, int (*get_line) PARAMS ((sb *)), + const char **namep)); +extern int check_macro PARAMS ((const char *, sb *, int, const char **)); +extern void delete_macro PARAMS ((const char *)); +extern const char *expand_irp + PARAMS ((int, int, sb *, sb *, int (*) PARAMS ((sb *)), int)); + +#endif diff --git a/contrib/binutils/gas/messages.c b/contrib/binutils/gas/messages.c new file mode 100644 index 0000000..1e06232 --- /dev/null +++ b/contrib/binutils/gas/messages.c @@ -0,0 +1,537 @@ +/* messages.c - error reporter - + Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +#include <stdio.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#ifdef USE_STDARG +#include <stdarg.h> +#endif + +#ifdef USE_VARARGS +#include <varargs.h> +#endif + +#if !defined (USE_STDARG) && !defined (USE_VARARGS) +/* Roll our own. */ +#define va_alist REST +#define va_dcl +typedef int * va_list; +#define va_start(ARGS) ARGS = &REST +#define va_end(ARGS) +#endif + +static void identify PARAMS ((char *)); +static void as_show_where PARAMS ((void)); +static void as_warn_internal PARAMS ((char *, unsigned int, char *)); +static void as_bad_internal PARAMS ((char *, unsigned int, char *)); + +/* + * Despite the rest of the comments in this file, (FIXME-SOON), + * here is the current scheme for error messages etc: + * + * as_fatal() is used when gas is quite confused and + * continuing the assembly is pointless. In this case we + * exit immediately with error status. + * + * as_bad() is used to mark errors that result in what we + * presume to be a useless object file. Say, we ignored + * something that might have been vital. If we see any of + * these, assembly will continue to the end of the source, + * no object file will be produced, and we will terminate + * with error status. The new option, -Z, tells us to + * produce an object file anyway but we still exit with + * error status. The assumption here is that you don't want + * this object file but we could be wrong. + * + * as_warn() is used when we have an error from which we + * have a plausible error recovery. eg, masking the top + * bits of a constant that is longer than will fit in the + * destination. In this case we will continue to assemble + * the source, although we may have made a bad assumption, + * and we will produce an object file and return normal exit + * status (ie, no error). The new option -X tells us to + * treat all as_warn() errors as as_bad() errors. That is, + * no object file will be produced and we will exit with + * error status. The idea here is that we don't kill an + * entire make because of an error that we knew how to + * correct. On the other hand, sometimes you might want to + * stop the make at these points. + * + * as_tsktsk() is used when we see a minor error for which + * our error recovery action is almost certainly correct. + * In this case, we print a message and then assembly + * continues as though no error occurred. + */ + +static void +identify (file) + char *file; +{ + static int identified; + if (identified) + return; + identified++; + + if (!file) + { + unsigned int x; + as_where (&file, &x); + } + + if (file) + fprintf (stderr, "%s: ", file); + fprintf (stderr, "Assembler messages:\n"); +} + +static int warning_count; /* Count of number of warnings issued */ + +int +had_warnings () +{ + return (warning_count); +} + +/* Nonzero if we've hit a 'bad error', and should not write an obj file, + and exit with a nonzero error code */ + +static int error_count; + +int +had_errors () +{ + return (error_count); +} + + +/* Print the current location to stderr. */ + +static void +as_show_where () +{ + char *file; + unsigned int line; + + as_where (&file, &line); + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); +} + +/* + * a s _ p e r r o r + * + * Like perror(3), but with more info. + */ + +void +as_perror (gripe, filename) + const char *gripe; /* Unpunctuated error theme. */ + const char *filename; +{ + const char *errtxt; + + as_show_where (); + fprintf (stderr, gripe, filename); +#ifdef BFD_ASSEMBLER + errtxt = bfd_errmsg (bfd_get_error ()); +#else + errtxt = xstrerror (errno); +#endif + fprintf (stderr, ": %s\n", errtxt); + errno = 0; +#ifdef BFD_ASSEMBLER + bfd_set_error (bfd_error_no_error); +#endif +} + +/* + * a s _ t s k t s k () + * + * Send to stderr a string as a warning, and locate warning + * in input file(s). + * Please only use this for when we have some recovery action. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifdef USE_STDARG +void +as_tsktsk (const char *format,...) +{ + va_list args; + + as_show_where (); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + (void) putc ('\n', stderr); +} /* as_tsktsk() */ +#else +void +as_tsktsk (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + + as_show_where (); + va_start (args); + vfprintf (stderr, format, args); + va_end (args); + (void) putc ('\n', stderr); +} /* as_tsktsk() */ +#endif /* not NO_STDARG */ + +/* The common portion of as_warn and as_warn_where. */ + +static void +as_warn_internal (file, line, buffer) + char *file; + unsigned int line; + char *buffer; +{ + ++warning_count; + + if (file == NULL) + as_where (&file, &line); + + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); + fprintf (stderr, "Warning: "); + fputs (buffer, stderr); + (void) putc ('\n', stderr); +#ifndef NO_LISTING + listing_warning (buffer); +#endif +} + +/* + * a s _ w a r n () + * + * Send to stderr a string as a warning, and locate warning + * in input file(s). + * Please only use this for when we have some recovery action. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifdef USE_STDARG +void +as_warn (const char *format,...) +{ + va_list args; + char buffer[200]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal ((char *) NULL, 0, buffer); + } +} /* as_warn() */ +#else +/*VARARGS1 */ +void +as_warn (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + char buffer[200]; + + if (!flag_no_warnings) + { + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal ((char *) NULL, 0, buffer); + } +} /* as_warn() */ +#endif /* not NO_STDARG */ + +/* as_warn_where, like as_bad but the file name and line number are + passed in. Unfortunately, we have to repeat the function in order + to handle the varargs correctly and portably. */ + +#ifdef USE_STDARG +void +as_warn_where (char *file, unsigned int line, const char *format,...) +{ + va_list args; + char buffer[200]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal (file, line, buffer); + } +} /* as_warn() */ +#else +/*VARARGS1 */ +void +as_warn_where (file, line, format, va_alist) + char *file; + unsigned int line; + const char *format; + va_dcl +{ + va_list args; + char buffer[200]; + + if (!flag_no_warnings) + { + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal (file, line, buffer); + } +} /* as_warn() */ +#endif /* not NO_STDARG */ + +/* The common portion of as_bad and as_bad_where. */ + +static void +as_bad_internal (file, line, buffer) + char *file; + unsigned int line; + char *buffer; +{ + ++error_count; + + if (file == NULL) + as_where (&file, &line); + + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); + fprintf (stderr, "Error: "); + fputs (buffer, stderr); + (void) putc ('\n', stderr); +#ifndef NO_LISTING + listing_error (buffer); +#endif +} + +/* + * a s _ b a d () + * + * Send to stderr a string as a warning, and locate warning in input file(s). + * Please us when there is no recovery, but we want to continue processing + * but not produce an object file. + * Please explain in string (which may have '\n's) what recovery was done. + */ + +#ifdef USE_STDARG +void +as_bad (const char *format,...) +{ + va_list args; + char buffer[200]; + + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal ((char *) NULL, 0, buffer); +} + +#else +/*VARARGS1 */ +void +as_bad (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + char buffer[200]; + + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal ((char *) NULL, 0, buffer); +} +#endif /* not NO_STDARG */ + +/* as_bad_where, like as_bad but the file name and line number are + passed in. Unfortunately, we have to repeat the function in order + to handle the varargs correctly and portably. */ + +#ifdef USE_STDARG +void +as_bad_where (char *file, unsigned int line, const char *format,...) +{ + va_list args; + char buffer[200]; + + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal (file, line, buffer); +} + +#else +/*VARARGS1 */ +void +as_bad_where (file, line, format, va_alist) + char *file; + unsigned int line; + const char *format; + va_dcl +{ + va_list args; + char buffer[200]; + + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal (file, line, buffer); +} +#endif /* not NO_STDARG */ + +/* + * a s _ f a t a l () + * + * Send to stderr a string as a fatal message, and print location of error in + * input file(s). + * Please only use this for when we DON'T have some recovery action. + * It xexit()s with a warning status. + */ + +#ifdef USE_STDARG +void +as_fatal (const char *format,...) +{ + va_list args; + + as_show_where (); + va_start (args, format); + fprintf (stderr, "Fatal error: "); + vfprintf (stderr, format, args); + (void) putc ('\n', stderr); + va_end (args); + xexit (EXIT_FAILURE); +} /* as_fatal() */ +#else +/*VARARGS1*/ +void +as_fatal (format, va_alist) + char *format; + va_dcl +{ + va_list args; + + as_show_where (); + va_start (args); + fprintf (stderr, "Fatal error: "); + vfprintf (stderr, format, args); + (void) putc ('\n', stderr); + va_end (args); + xexit (EXIT_FAILURE); +} /* as_fatal() */ +#endif /* not NO_STDARG */ + +/* + * as_assert: Indicate assertion failure. + * Arguments: Filename, line number, optional function name. + */ + +void +as_assert (file, line, fn) + const char *file, *fn; + int line; +{ + as_show_where (); + fprintf (stderr, "Internal error!\n"); + fprintf (stderr, "Assertion failure"); + if (fn) + fprintf (stderr, " in %s", fn); + fprintf (stderr, " at %s line %d.\n", file, line); + fprintf (stderr, "Please report this bug.\n"); + xexit (EXIT_FAILURE); +} + +/* as_abort: Print a friendly message saying how totally hosed we are, + and exit without producing a core file. */ +void +as_abort (file, line, fn) + const char *file, *fn; + int line; +{ + as_show_where (); + fprintf (stderr, "Internal error, aborting at %s line %d", file, line); + if (fn) + fprintf (stderr, " in %s", fn); + fprintf (stderr, "\nPlease report this bug.\n"); + xexit (EXIT_FAILURE); +} + +/* Support routines. */ + +void +fprint_value (file, val) + FILE *file; + valueT val; +{ + if (sizeof (val) <= sizeof (long)) + { + fprintf (file, "%ld", (long) val); + return; + } +#ifdef BFD_ASSEMBLER + if (sizeof (val) <= sizeof (bfd_vma)) + { + fprintf_vma (file, val); + return; + } +#endif + abort (); +} + +void +sprint_value (buf, val) + char *buf; + valueT val; +{ + if (sizeof (val) <= sizeof (long)) + { + sprintf (buf, "%ld", (long) val); + return; + } +#ifdef BFD_ASSEMBLER + if (sizeof (val) <= sizeof (bfd_vma)) + { + sprintf_vma (buf, val); + return; + } +#endif + abort (); +} + +/* end of messages.c */ diff --git a/contrib/binutils/gas/obj.h b/contrib/binutils/gas/obj.h new file mode 100644 index 0000000..a4aaf25 --- /dev/null +++ b/contrib/binutils/gas/obj.h @@ -0,0 +1,79 @@ +/* obj.h - defines the object dependent hooks for all object + format backends. + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +char *obj_default_output_file_name PARAMS ((void)); +void obj_emit_relocations PARAMS ((char **where, fixS * fixP, + relax_addressT segment_address_in_file)); +void obj_emit_strings PARAMS ((char **where)); +void obj_emit_symbols PARAMS ((char **where, symbolS * symbols)); +#ifndef obj_read_begin_hook +void obj_read_begin_hook PARAMS ((void)); +#endif +#ifndef BFD_ASSEMBLER +void obj_crawl_symbol_chain PARAMS ((object_headers * headers)); +void obj_header_append PARAMS ((char **where, object_headers * headers)); +#ifndef obj_pre_write_hook +void obj_pre_write_hook PARAMS ((object_headers * headers)); +#endif +#endif + +#ifndef obj_symbol_new_hook +void obj_symbol_new_hook PARAMS ((symbolS * symbolP)); +#endif + +void obj_symbol_to_chars PARAMS ((char **where, symbolS * symbolP)); + +extern const pseudo_typeS obj_pseudo_table[]; + +#ifdef BFD_ASSEMBLER +struct format_ops { + int flavor; + unsigned dfl_leading_underscore : 1; + unsigned emit_section_symbols : 1; + void (*frob_symbol) PARAMS ((symbolS *, int *)); + void (*frob_file) PARAMS ((void)); + void (*frob_file_after_relocs) PARAMS ((void)); + bfd_vma (*s_get_size) PARAMS ((symbolS *)); + void (*s_set_size) PARAMS ((symbolS *, bfd_vma)); + bfd_vma (*s_get_align) PARAMS ((symbolS *)); + void (*s_set_align) PARAMS ((symbolS *, bfd_vma)); + void (*copy_symbol_attributes) PARAMS ((symbolS *, symbolS *)); + void (*generate_asm_lineno) PARAMS ((const char *, int)); + void (*process_stab) PARAMS ((segT, int, const char *, int, int, int)); + int (*sec_sym_ok_for_reloc) PARAMS ((asection *)); + void (*pop_insert) PARAMS ((void)); + /* For configurations using ECOFF_DEBUGGING, this callback is used. */ + void (*ecoff_set_ext) PARAMS ((symbolS *, struct ecoff_extr *)); + + void (*read_begin_hook) PARAMS ((void)); + void (*symbol_new_hook) PARAMS ((symbolS *)); +}; + +extern const struct format_ops elf_format_ops; +extern const struct format_ops ecoff_format_ops; +extern const struct format_ops coff_format_ops; + +#ifndef this_format +COMMON const struct format_ops *this_format; +#endif +#endif + +/* end of obj.h */ diff --git a/contrib/binutils/gas/output-file.c b/contrib/binutils/gas/output-file.c new file mode 100644 index 0000000..c53281b --- /dev/null +++ b/contrib/binutils/gas/output-file.c @@ -0,0 +1,154 @@ +/* output-file.c - Deal with the output file + Copyright (C) 1987, 90, 91, 93, 92, 94, 95, 1996 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#include "as.h" + +#include "output-file.h" + +#ifdef BFD_HEADERS +#define USE_BFD +#endif + +#ifdef BFD_ASSEMBLER +#define USE_BFD +#ifndef TARGET_MACH +#define TARGET_MACH 0 +#endif +#endif + +#ifdef USE_BFD +#include "bfd.h" +bfd *stdoutput; + +void +output_file_create (name) + char *name; +{ + if (name[0] == '-' && name[1] == '\0') + { + as_fatal ("Can't open a bfd on stdout %s ", name); + } + else if (!(stdoutput = bfd_openw (name, TARGET_FORMAT))) + { + as_perror ("FATAL: Can't create %s", name); + exit (EXIT_FAILURE); + } + bfd_set_format (stdoutput, bfd_object); +#ifdef BFD_ASSEMBLER + bfd_set_arch_mach (stdoutput, TARGET_ARCH, TARGET_MACH); +#endif +} + +void +output_file_close (filename) + char *filename; +{ +#ifdef BFD_ASSEMBLER + /* Close the bfd. */ + if (bfd_close (stdoutput) == 0) + { + bfd_perror (filename); + as_perror ("FATAL: Can't close %s\n", filename); + exit (EXIT_FAILURE); + } +#else + /* Close the bfd without getting bfd to write out anything by itself */ + if (bfd_close_all_done (stdoutput) == 0) + { + as_perror ("FATAL: Can't close %s\n", filename); + exit (EXIT_FAILURE); + } +#endif + stdoutput = NULL; /* Trust nobody! */ +} + +#ifndef BFD_ASSEMBLER +void +output_file_append (where, length, filename) + char *where; + long length; + char *filename; +{ + abort (); +} +#endif + +#else + +static FILE *stdoutput; + +void +output_file_create (name) + char *name; +{ + if (name[0] == '-' && name[1] == '\0') + { + stdoutput = stdout; + return; + } + + stdoutput = fopen (name, "wb"); + + /* Some systems don't grok "b" in fopen modes. */ + if (stdoutput == NULL) + stdoutput = fopen (name, "w"); + + if (stdoutput == NULL) + { + as_perror ("FATAL: Can't create %s", name); + exit (EXIT_FAILURE); + } +} + +void +output_file_close (filename) + char *filename; +{ + if (EOF == fclose (stdoutput)) + { + as_perror ("FATAL: Can't close %s", filename); + exit (EXIT_FAILURE); + } + stdoutput = NULL; /* Trust nobody! */ +} + +void +output_file_append (where, length, filename) + char *where; + long length; + char *filename; +{ + for (; length; length--, where++) + { + (void) putc (*where, stdoutput); + if (ferror (stdoutput)) + /* if ( EOF == (putc( *where, stdoutput )) ) */ + { + as_perror ("Failed to emit an object byte", filename); + as_fatal ("Can't continue"); + } + } +} + +#endif + +/* end of output-file.c */ diff --git a/contrib/binutils/gas/output-file.h b/contrib/binutils/gas/output-file.h new file mode 100644 index 0000000..942f1ef --- /dev/null +++ b/contrib/binutils/gas/output-file.h @@ -0,0 +1,25 @@ +/* This file is output-file.h + + Copyright (C) 1987-1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +void output_file_append PARAMS ((char *where, long length, char *filename)); +void output_file_close PARAMS ((char *filename)); +void output_file_create PARAMS ((char *name)); + +/* end of output-file.h */ diff --git a/contrib/binutils/gas/read.c b/contrib/binutils/gas/read.c new file mode 100644 index 0000000..85d221d --- /dev/null +++ b/contrib/binutils/gas/read.c @@ -0,0 +1,4350 @@ +/* read.c - read a source file - + Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#if 0 +#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will + change this a bit. But then, GNU isn't + spozed to run on your machine anyway. + (RMS is so shortsighted sometimes.) + */ +#else +#define MASK_CHAR ((int)(unsigned char)-1) +#endif + + +/* This is the largest known floating point format (for now). It will + grow when we do 4361 style flonums. */ + +#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16) + +/* Routines that read assembler source text to build spagetti in memory. + Another group of these functions is in the expr.c module. */ + +/* for isdigit() */ +#include <ctype.h> + +#include "as.h" +#include "subsegs.h" +#include "sb.h" +#include "macro.h" +#include "obstack.h" +#include "listing.h" +#include "ecoff.h" + +#ifndef TC_START_LABEL +#define TC_START_LABEL(x,y) (x==':') +#endif + +/* The NOP_OPCODE is for the alignment fill value. + * fill it a nop instruction so that the disassembler does not choke + * on it + */ +#ifndef NOP_OPCODE +#define NOP_OPCODE 0x00 +#endif + +char *input_line_pointer; /*->next char of source file to parse. */ + +int generate_asm_lineno = 0; /* flag to generate line stab for .s file */ + +#if BITS_PER_CHAR != 8 +/* The following table is indexed by[(char)] and will break if + a char does not have exactly 256 states (hopefully 0:255!)! */ +die horribly; +#endif + +#ifndef LEX_AT +/* The m88k unfortunately uses @ as a label beginner. */ +#define LEX_AT 0 +#endif + +#ifndef LEX_BR +/* The RS/6000 assembler uses {,},[,] as parts of symbol names. */ +#define LEX_BR 0 +#endif + +#ifndef LEX_PCT +/* The Delta 68k assembler permits % inside label names. */ +#define LEX_PCT 0 +#endif + +#ifndef LEX_QM +/* The PowerPC Windows NT assemblers permits ? inside label names. */ +#define LEX_QM 0 +#endif + +#ifndef LEX_DOLLAR +/* The a29k assembler does not permits labels to start with $. */ +#define LEX_DOLLAR 3 +#endif + +#ifndef LEX_TILDE +/* The Delta 68k assembler permits ~ at start of label names. */ +#define LEX_TILDE 0 +#endif + +/* used by is_... macros. our ctype[] */ +char lex_type[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */ + 0, 0, 0, 0, LEX_DOLLAR, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, LEX_QM, /* 0123456789:;<=>? */ + LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + + +/* + * In: a character. + * Out: 1 if this character ends a line. + */ +#define _ (0) +char is_end_of_line[256] = +{ +#ifdef CR_EOL + _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */ +#else + _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */ +#endif + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ +#ifdef TC_HPPA + _,99, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* _!"#$%&'()*+,-./ */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0123456789:;<=>? */ +#else + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, /* 0123456789:;<=>? */ +#endif + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */ +}; +#undef _ + +/* Functions private to this file. */ + +static char *buffer; /* 1st char of each buffer of lines is here. */ +static char *buffer_limit; /*->1 + last char in buffer. */ + +/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 in the + tc-<CPU>.h file. See the "Porting GAS" section of the internals manual. */ +int target_big_endian = TARGET_BYTES_BIG_ENDIAN; + +static char *old_buffer; /* JF a hack */ +static char *old_input; +static char *old_limit; + +/* Variables for handling include file directory list. */ + +char **include_dirs; /* List of pointers to directories to + search for .include's */ +int include_dir_count; /* How many are in the list */ +int include_dir_maxlen = 1;/* Length of longest in list */ + +#ifndef WORKING_DOT_WORD +struct broken_word *broken_words; +int new_broken_words; +#endif + +/* The current offset into the absolute section. We don't try to + build frags in the absolute section, since no data can be stored + there. We just keep track of the current offset. */ +addressT abs_section_offset; + +/* If this line had an MRI style label, it is stored in this variable. + This is used by some of the MRI pseudo-ops. */ +symbolS *line_label; + +/* This global variable is used to support MRI common sections. We + translate such sections into a common symbol. This variable is + non-NULL when we are in an MRI common section. */ +symbolS *mri_common_symbol; + +/* In MRI mode, after a dc.b pseudo-op with an odd number of bytes, we + need to align to an even byte boundary unless the next pseudo-op is + dc.b, ds.b, or dcb.b. This variable is set to 1 if an alignment + may be needed. */ +static int mri_pending_align; + +static void cons_worker PARAMS ((int, int)); +static int scrub_from_string PARAMS ((char **)); +static void do_align PARAMS ((int, char *, int, int)); +static void s_align PARAMS ((int, int)); +static int hex_float PARAMS ((int, char *)); +static void do_org PARAMS ((segT, expressionS *, int)); +char *demand_copy_string PARAMS ((int *lenP)); +static segT get_segmented_expression PARAMS ((expressionS *expP)); +static segT get_known_segmented_expression PARAMS ((expressionS * expP)); +static void pobegin PARAMS ((void)); +static int get_line_sb PARAMS ((sb *)); + + +void +read_begin () +{ + const char *p; + + pobegin (); + obj_read_begin_hook (); + + /* Something close -- but not too close -- to a multiple of 1024. + The debugging malloc I'm using has 24 bytes of overhead. */ + obstack_begin (¬es, chunksize); + obstack_begin (&cond_obstack, chunksize); + + /* Use machine dependent syntax */ + for (p = line_separator_chars; *p; p++) + is_end_of_line[(unsigned char) *p] = 1; + /* Use more. FIXME-SOMEDAY. */ + + if (flag_mri) + lex_type['?'] = 3; +} + +/* set up pseudo-op tables */ + +static struct hash_control *po_hash; + +static const pseudo_typeS potable[] = +{ + {"abort", s_abort, 0}, + {"align", s_align_ptwo, 0}, + {"ascii", stringer, 0}, + {"asciz", stringer, 1}, + {"balign", s_align_bytes, 0}, + {"balignw", s_align_bytes, -2}, + {"balignl", s_align_bytes, -4}, +/* block */ + {"byte", cons, 1}, + {"comm", s_comm, 0}, + {"common", s_mri_common, 0}, + {"common.s", s_mri_common, 1}, + {"data", s_data, 0}, + {"dc", cons, 2}, + {"dc.b", cons, 1}, + {"dc.d", float_cons, 'd'}, + {"dc.l", cons, 4}, + {"dc.s", float_cons, 'f'}, + {"dc.w", cons, 2}, + {"dc.x", float_cons, 'x'}, + {"dcb", s_space, 2}, + {"dcb.b", s_space, 1}, + {"dcb.d", s_float_space, 'd'}, + {"dcb.l", s_space, 4}, + {"dcb.s", s_float_space, 'f'}, + {"dcb.w", s_space, 2}, + {"dcb.x", s_float_space, 'x'}, + {"ds", s_space, 2}, + {"ds.b", s_space, 1}, + {"ds.d", s_space, 8}, + {"ds.l", s_space, 4}, + {"ds.p", s_space, 12}, + {"ds.s", s_space, 4}, + {"ds.w", s_space, 2}, + {"ds.x", s_space, 12}, + {"debug", s_ignore, 0}, +#ifdef S_SET_DESC + {"desc", s_desc, 0}, +#endif +/* dim */ + {"double", float_cons, 'd'}, +/* dsect */ + {"eject", listing_eject, 0}, /* Formfeed listing */ + {"else", s_else, 0}, + {"elsec", s_else, 0}, + {"end", s_end, 0}, + {"endc", s_endif, 0}, + {"endif", s_endif, 0}, +/* endef */ + {"equ", s_set, 0}, + {"equiv", s_set, 1}, + {"err", s_err, 0}, + {"exitm", s_mexit, 0}, +/* extend */ + {"extern", s_ignore, 0}, /* We treat all undef as ext */ + {"appfile", s_app_file, 1}, + {"appline", s_app_line, 0}, + {"fail", s_fail, 0}, + {"file", s_app_file, 0}, + {"fill", s_fill, 0}, + {"float", float_cons, 'f'}, + {"format", s_ignore, 0}, + {"global", s_globl, 0}, + {"globl", s_globl, 0}, + {"hword", cons, 2}, + {"if", s_if, (int) O_ne}, + {"ifc", s_ifc, 0}, + {"ifdef", s_ifdef, 0}, + {"ifeq", s_if, (int) O_eq}, + {"ifeqs", s_ifeqs, 0}, + {"ifge", s_if, (int) O_ge}, + {"ifgt", s_if, (int) O_gt}, + {"ifle", s_if, (int) O_le}, + {"iflt", s_if, (int) O_lt}, + {"ifnc", s_ifc, 1}, + {"ifndef", s_ifdef, 1}, + {"ifne", s_if, (int) O_ne}, + {"ifnes", s_ifeqs, 1}, + {"ifnotdef", s_ifdef, 1}, + {"include", s_include, 0}, + {"int", cons, 4}, + {"irp", s_irp, 0}, + {"irep", s_irp, 0}, + {"irpc", s_irp, 1}, + {"irepc", s_irp, 1}, + {"lcomm", s_lcomm, 0}, + {"lflags", listing_flags, 0}, /* Listing flags */ + {"linkonce", s_linkonce, 0}, + {"list", listing_list, 1}, /* Turn listing on */ + {"llen", listing_psize, 1}, + {"long", cons, 4}, + {"lsym", s_lsym, 0}, + {"macro", s_macro, 0}, + {"mexit", s_mexit, 0}, + {"mri", s_mri, 0}, + {".mri", s_mri, 0}, /* Special case so .mri works in MRI mode. */ + {"name", s_ignore, 0}, + {"noformat", s_ignore, 0}, + {"nolist", listing_list, 0}, /* Turn listing off */ + {"nopage", listing_nopage, 0}, + {"octa", cons, 16}, + {"offset", s_struct, 0}, + {"org", s_org, 0}, + {"p2align", s_align_ptwo, 0}, + {"p2alignw", s_align_ptwo, -2}, + {"p2alignl", s_align_ptwo, -4}, + {"page", listing_eject, 0}, + {"plen", listing_psize, 0}, + {"print", s_print, 0}, + {"psize", listing_psize, 0}, /* set paper size */ + {"purgem", s_purgem, 0}, + {"quad", cons, 8}, + {"rep", s_rept, 0}, + {"rept", s_rept, 0}, + {"rva", s_rva, 4}, + {"sbttl", listing_title, 1}, /* Subtitle of listing */ +/* scl */ +/* sect */ + {"set", s_set, 0}, + {"short", cons, 2}, + {"single", float_cons, 'f'}, +/* size */ + {"space", s_space, 0}, + {"skip", s_space, 0}, + {"spc", s_ignore, 0}, + {"stabd", s_stab, 'd'}, + {"stabn", s_stab, 'n'}, + {"stabs", s_stab, 's'}, + {"string", stringer, 1}, + {"struct", s_struct, 0}, +/* tag */ + {"text", s_text, 0}, + + /* This is for gcc to use. It's only just been added (2/94), so gcc + won't be able to use it for a while -- probably a year or more. + But once this has been released, check with gcc maintainers + before deleting it or even changing the spelling. */ + {"this_GCC_requires_the_GNU_assembler", s_ignore, 0}, + /* If we're folding case -- done for some targets, not necessarily + all -- the above string in an input file will be converted to + this one. Match it either way... */ + {"this_gcc_requires_the_gnu_assembler", s_ignore, 0}, + + {"title", listing_title, 0}, /* Listing title */ + {"ttl", listing_title, 0}, +/* type */ +/* use */ +/* val */ + {"xcom", s_comm, 0}, + {"xdef", s_globl, 0}, + {"xref", s_ignore, 0}, + {"xstabs", s_xstab, 's'}, + {"word", cons, 2}, + {"zero", s_space, 0}, + {NULL} /* end sentinel */ +}; + +static int pop_override_ok = 0; +static const char *pop_table_name; + +void +pop_insert (table) + const pseudo_typeS *table; +{ + const char *errtxt; + const pseudo_typeS *pop; + for (pop = table; pop->poc_name; pop++) + { + errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); + if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists"))) + as_fatal ("error constructing %s pseudo-op table: %s", pop_table_name, + errtxt); + } +} + +#ifndef md_pop_insert +#define md_pop_insert() pop_insert(md_pseudo_table) +#endif + +#ifndef obj_pop_insert +#define obj_pop_insert() pop_insert(obj_pseudo_table) +#endif + +static void +pobegin () +{ + po_hash = hash_new (); + + /* Do the target-specific pseudo ops. */ + pop_table_name = "md"; + md_pop_insert (); + + /* Now object specific. Skip any that were in the target table. */ + pop_table_name = "obj"; + pop_override_ok = 1; + obj_pop_insert (); + + /* Now portable ones. Skip any that we've seen already. */ + pop_table_name = "standard"; + pop_insert (potable); +} + +#define HANDLE_CONDITIONAL_ASSEMBLY() \ + if (ignore_input ()) \ + { \ + while (! is_end_of_line[(unsigned char) *input_line_pointer++]) \ + if (input_line_pointer == buffer_limit) \ + break; \ + continue; \ + } + + +/* This function is used when scrubbing the characters between #APP + and #NO_APP. */ + +static char *scrub_string; +static char *scrub_string_end; + +static int +scrub_from_string (from) + char **from; +{ + int size; + + *from = scrub_string; + size = scrub_string_end - scrub_string; + scrub_string = scrub_string_end; + return size; +} + +/* read_a_source_file() + * + * We read the file, putting things into a web that + * represents what we have been reading. + */ +void +read_a_source_file (name) + char *name; +{ + register char c; + register char *s; /* string of symbol, '\0' appended */ + register int temp; + pseudo_typeS *pop; + + buffer = input_scrub_new_file (name); + + listing_file (name); + listing_newline (""); + + while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0) + { /* We have another line to parse. */ + know (buffer_limit[-1] == '\n'); /* Must have a sentinel. */ + contin: /* JF this goto is my fault I admit it. + Someone brave please re-write the whole + input section here? Pleeze??? */ + while (input_line_pointer < buffer_limit) + { + /* We have more of this buffer to parse. */ + + /* + * We now have input_line_pointer->1st char of next line. + * If input_line_pointer [-1] == '\n' then we just + * scanned another line: so bump line counters. + */ + if (is_end_of_line[(unsigned char) input_line_pointer[-1]]) + { +#ifdef md_start_line_hook + md_start_line_hook (); +#endif + + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + + line_label = NULL; + + if (flag_m68k_mri +#ifdef LABELS_WITHOUT_COLONS + || 1 +#endif + ) + { + /* Text at the start of a line must be a label, we + run down and stick a colon in. */ + if (is_name_beginner (*input_line_pointer)) + { + char *line_start = input_line_pointer; + char c; + int mri_line_macro; + + LISTING_NEWLINE (); + HANDLE_CONDITIONAL_ASSEMBLY (); + + c = get_symbol_end (); + + /* In MRI mode, the EQU and MACRO pseudoops must + be handled specially. */ + mri_line_macro = 0; + if (flag_m68k_mri) + { + char *rest = input_line_pointer + 1; + + if (*rest == ':') + ++rest; + if (*rest == ' ' || *rest == '\t') + ++rest; + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (line_start, + strncasecmp (rest, "SET", 3) == 0); + continue; + } + if (strncasecmp (rest, "MACRO", 5) == 0 + && (rest[5] == ' ' + || rest[5] == '\t' + || is_end_of_line[(unsigned char) rest[5]])) + mri_line_macro = 1; + } + + /* In MRI mode, we need to handle the MACRO + pseudo-op specially: we don't want to put the + symbol in the symbol table. */ + if (! mri_line_macro) + line_label = colon (line_start); + else + line_label = symbol_create (line_start, + absolute_section, + (valueT) 0, + &zero_address_frag); + + *input_line_pointer = c; + if (c == ':') + input_line_pointer++; + } + } + } + + /* + * We are at the begining of a line, or similar place. + * We expect a well-formed assembler statement. + * A "symbol-name:" is a statement. + * + * Depending on what compiler is used, the order of these tests + * may vary to catch most common case 1st. + * Each test is independent of all other tests at the (top) level. + * PLEASE make a compiler that doesn't use this assembler. + * It is crufty to waste a compiler's time encoding things for this + * assembler, which then wastes more time decoding it. + * (And communicating via (linear) files is silly! + * If you must pass stuff, please pass a tree!) + */ + if ((c = *input_line_pointer++) == '\t' + || c == ' ' + || c == '\f' + || c == 0) + { + c = *input_line_pointer++; + } + know (c != ' '); /* No further leading whitespace. */ + LISTING_NEWLINE (); + /* + * C is the 1st significant character. + * Input_line_pointer points after that character. + */ + if (is_name_beginner (c)) + { + /* want user-defined label or pseudo/opcode */ + HANDLE_CONDITIONAL_ASSEMBLY (); + + s = --input_line_pointer; + c = get_symbol_end (); /* name's delimiter */ + /* + * C is character after symbol. + * That character's place in the input line is now '\0'. + * S points to the beginning of the symbol. + * [In case of pseudo-op, s->'.'.] + * Input_line_pointer->'\0' where c was. + */ + if (TC_START_LABEL(c, input_line_pointer)) + { + if (flag_m68k_mri) + { + char *rest = input_line_pointer + 1; + + /* In MRI mode, \tsym: set 0 is permitted. */ + + if (*rest == ':') + ++rest; + if (*rest == ' ' || *rest == '\t') + ++rest; + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (s, 1); + continue; + } + } + + line_label = colon (s); /* user-defined label */ + *input_line_pointer++ = ':'; /* Put ':' back for error messages' sake. */ + /* Input_line_pointer->after ':'. */ + SKIP_WHITESPACE (); + + + } + else if (c == '=' + || ((c == ' ' || c == '\t') + && input_line_pointer[1] == '=' +#ifdef TC_EQUAL_IN_INSN + && ! TC_EQUAL_IN_INSN (c, input_line_pointer) +#endif + )) + { + equals (s, 1); + demand_empty_rest_of_line (); + } + else + { /* expect pseudo-op or machine instruction */ + pop = NULL; + +#define IGNORE_OPCODE_CASE +#ifdef IGNORE_OPCODE_CASE + { + char *s2 = s; + while (*s2) + { + if (isupper (*s2)) + *s2 = tolower (*s2); + s2++; + } + } +#endif + + if (flag_m68k_mri +#ifdef NO_PSEUDO_DOT + || 1 +#endif + ) + { + /* The MRI assembler and the m88k use pseudo-ops + without a period. */ + pop = (pseudo_typeS *) hash_find (po_hash, s); + if (pop != NULL && pop->poc_handler == NULL) + pop = NULL; + } + + if (pop != NULL + || (! flag_m68k_mri && *s == '.')) + { + /* + * PSEUDO - OP. + * + * WARNING: c has next char, which may be end-of-line. + * We lookup the pseudo-op table with s+1 because we + * already know that the pseudo-op begins with a '.'. + */ + + if (pop == NULL) + pop = (pseudo_typeS *) hash_find (po_hash, s + 1); + + /* In MRI mode, we may need to insert an + automatic alignment directive. What a hack + this is. */ + if (mri_pending_align + && (pop == NULL + || ! ((pop->poc_handler == cons + && pop->poc_val == 1) + || (pop->poc_handler == s_space + && pop->poc_val == 1) +#ifdef tc_conditional_pseudoop + || tc_conditional_pseudoop (pop) +#endif + || pop->poc_handler == s_if + || pop->poc_handler == s_ifdef + || pop->poc_handler == s_ifc + || pop->poc_handler == s_ifeqs + || pop->poc_handler == s_else + || pop->poc_handler == s_endif + || pop->poc_handler == s_globl + || pop->poc_handler == s_ignore))) + { + do_align (1, (char *) NULL, 0, 0); + mri_pending_align = 0; + if (line_label != NULL) + { + line_label->sy_frag = frag_now; + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + + /* Print the error msg now, while we still can */ + if (pop == NULL) + { + as_bad ("Unknown pseudo-op: `%s'", s); + *input_line_pointer = c; + s_ignore (0); + continue; + } + + /* Put it back for error messages etc. */ + *input_line_pointer = c; + /* The following skip of whitespace is compulsory. + A well shaped space is sometimes all that separates + keyword from operands. */ + if (c == ' ' || c == '\t') + input_line_pointer++; + /* + * Input_line is restored. + * Input_line_pointer->1st non-blank char + * after pseudo-operation. + */ + (*pop->poc_handler) (pop->poc_val); + + /* If that was .end, just get out now. */ + if (pop->poc_handler == s_end) + goto quit; + } + else + { + int inquote = 0; + + /* WARNING: c has char, which may be end-of-line. */ + /* Also: input_line_pointer->`\0` where c was. */ + *input_line_pointer = c; + while (!is_end_of_line[(unsigned char) *input_line_pointer] + || inquote +#ifdef TC_EOL_IN_INSN + || TC_EOL_IN_INSN (input_line_pointer) +#endif + ) + { + if (flag_m68k_mri && *input_line_pointer == '\'') + inquote = ! inquote; + input_line_pointer++; + } + + c = *input_line_pointer; + *input_line_pointer = '\0'; + +#ifdef OBJ_GENERATE_ASM_LINENO + if (generate_asm_lineno == 0) + { + if (ecoff_no_current_file ()) + generate_asm_lineno = 1; + } + if (generate_asm_lineno == 1) + { + unsigned int lineno; + char *s; + + as_where (&s, &lineno); + OBJ_GENERATE_ASM_LINENO (s, lineno); + } +#endif + + if (macro_defined) + { + sb out; + const char *err; + + if (check_macro (s, &out, '\0', &err)) + { + if (err != NULL) + as_bad (err); + *input_line_pointer++ = c; + input_scrub_include_sb (&out, + input_line_pointer); + sb_kill (&out); + buffer_limit = + input_scrub_next_buffer (&input_line_pointer); + continue; + } + } + + if (mri_pending_align) + { + do_align (1, (char *) NULL, 0, 0); + mri_pending_align = 0; + if (line_label != NULL) + { + line_label->sy_frag = frag_now; + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + + md_assemble (s); /* Assemble 1 instruction. */ + + *input_line_pointer++ = c; + + /* We resume loop AFTER the end-of-line from + this instruction. */ + } /* if (*s=='.') */ + } /* if c==':' */ + continue; + } /* if (is_name_beginner(c) */ + + + /* Empty statement? */ + if (is_end_of_line[(unsigned char) c]) + continue; + + if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) + && isdigit (c)) + { + /* local label ("4:") */ + char *backup = input_line_pointer; + + HANDLE_CONDITIONAL_ASSEMBLY (); + + temp = c - '0'; + + while (isdigit (*input_line_pointer)) + { + temp = (temp * 10) + *input_line_pointer - '0'; + ++input_line_pointer; + } /* read the whole number */ + + if (LOCAL_LABELS_DOLLAR + && *input_line_pointer == '$' + && *(input_line_pointer + 1) == ':') + { + input_line_pointer += 2; + + if (dollar_label_defined (temp)) + { + as_fatal ("label \"%d$\" redefined", temp); + } + + define_dollar_label (temp); + colon (dollar_label_name (temp, 0)); + continue; + } + + if (LOCAL_LABELS_FB + && *input_line_pointer++ == ':') + { + fb_label_instance_inc (temp); + colon (fb_label_name (temp, 0)); + continue; + } + + input_line_pointer = backup; + } /* local label ("4:") */ + + if (c && strchr (line_comment_chars, c)) + { /* Its a comment. Better say APP or NO_APP */ + char *ends; + char *new_buf; + char *new_tmp; + unsigned int new_length; + char *tmp_buf = 0; + + bump_line_counters (); + s = input_line_pointer; + if (strncmp (s, "APP\n", 4)) + continue; /* We ignore it */ + s += 4; + + ends = strstr (s, "#NO_APP\n"); + + if (!ends) + { + unsigned int tmp_len; + unsigned int num; + + /* The end of the #APP wasn't in this buffer. We + keep reading in buffers until we find the #NO_APP + that goes with this #APP There is one. The specs + guarentee it. . . */ + tmp_len = buffer_limit - s; + tmp_buf = xmalloc (tmp_len + 1); + memcpy (tmp_buf, s, tmp_len); + do + { + new_tmp = input_scrub_next_buffer (&buffer); + if (!new_tmp) + break; + else + buffer_limit = new_tmp; + input_line_pointer = buffer; + ends = strstr (buffer, "#NO_APP\n"); + if (ends) + num = ends - buffer; + else + num = buffer_limit - buffer; + + tmp_buf = xrealloc (tmp_buf, tmp_len + num); + memcpy (tmp_buf + tmp_len, buffer, num); + tmp_len += num; + } + while (!ends); + + input_line_pointer = ends ? ends + 8 : NULL; + + s = tmp_buf; + ends = s + tmp_len; + + } + else + { + input_line_pointer = ends + 8; + } + + scrub_string = s; + scrub_string_end = ends; + + new_length = ends - s; + new_buf = (char *) xmalloc (new_length); + new_tmp = new_buf; + for (;;) + { + int space; + int size; + + space = (new_buf + new_length) - new_tmp; + size = do_scrub_chars (scrub_from_string, new_tmp, space); + + if (size < space) + { + new_tmp += size; + break; + } + + new_buf = xrealloc (new_buf, new_length + 100); + new_tmp = new_buf + new_length; + new_length += 100; + } + + if (tmp_buf) + free (tmp_buf); + old_buffer = buffer; + old_input = input_line_pointer; + old_limit = buffer_limit; + buffer = new_buf; + input_line_pointer = new_buf; + buffer_limit = new_tmp; + continue; + } + + HANDLE_CONDITIONAL_ASSEMBLY (); + +#ifdef tc_unrecognized_line + if (tc_unrecognized_line (c)) + continue; +#endif + + /* as_warn("Junk character %d.",c); Now done by ignore_rest */ + input_line_pointer--; /* Report unknown char as ignored. */ + ignore_rest_of_line (); + } /* while (input_line_pointer<buffer_limit) */ + +#ifdef md_after_pass_hook + md_after_pass_hook (); +#endif + + if (old_buffer) + { + free (buffer); + bump_line_counters (); + if (old_input != 0) + { + buffer = old_buffer; + input_line_pointer = old_input; + buffer_limit = old_limit; + old_buffer = 0; + goto contin; + } + } + } /* while (more buffers to scan) */ + + quit: + +#ifdef md_cleanup + md_cleanup(); +#endif + input_scrub_close (); /* Close the input file */ +} + +/* For most MRI pseudo-ops, the line actually ends at the first + nonquoted space. This function looks for that point, stuffs a null + in, and sets *STOPCP to the character that used to be there, and + returns the location. + + Until I hear otherwise, I am going to assume that this is only true + for the m68k MRI assembler. */ + +char * +mri_comment_field (stopcp) + char *stopcp; +{ +#ifdef TC_M68K + + char *s; + int inquote = 0; + + know (flag_m68k_mri); + + for (s = input_line_pointer; + ((! is_end_of_line[(unsigned char) *s] && *s != ' ' && *s != '\t') + || inquote); + s++) + { + if (*s == '\'') + inquote = ! inquote; + } + *stopcp = *s; + *s = '\0'; + return s; + +#else + + char *s; + + for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++) + ; + *stopcp = *s; + *s = '\0'; + return s; + +#endif + +} + +/* Skip to the end of an MRI comment field. */ + +void +mri_comment_end (stop, stopc) + char *stop; + int stopc; +{ + know (flag_mri); + + input_line_pointer = stop; + *stop = stopc; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; +} + +void +s_abort (ignore) + int ignore; +{ + as_fatal (".abort detected. Abandoning ship."); +} + +/* Guts of .align directive. N is the power of two to which to align. + FILL may be NULL, or it may point to the bytes of the fill pattern. + LEN is the length of whatever FILL points to, if anything. MAX is + the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + +static void +do_align (n, fill, len, max) + int n; + char *fill; + int len; + int max; +{ + char default_fill; + +#ifdef md_do_align + md_do_align (n, fill, len, max, just_record_alignment); +#endif + + if (fill == NULL) + { + /* FIXME: Fix this right for BFD! */ + if (now_seg != data_section && now_seg != bss_section) + default_fill = NOP_OPCODE; + else + default_fill = 0; + fill = &default_fill; + len = 1; + } + + /* Only make a frag if we HAVE to. . . */ + if (n != 0 && !need_pass_2) + { + if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); + } + +#ifdef md_do_align + just_record_alignment: +#endif + + record_alignment (now_seg, n); +} + +/* Handle the .align pseudo-op. A positive ARG is a default alignment + (in bytes). A negative ARG is the negative of the length of the + fill pattern. BYTES_P is non-zero if the alignment value should be + interpreted as the byte boundary, rather than the power of 2. */ + +static void +s_align (arg, bytes_p) + int arg; + int bytes_p; +{ + register unsigned int align; + char *stop = NULL; + char stopc; + offsetT fill = 0; + int max; + int fill_p; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (arg < 0) + align = 0; + else + align = arg; /* Default value from pseudo-op table */ + } + else + { + align = get_absolute_expression (); + SKIP_WHITESPACE (); + } + + if (bytes_p) + { + /* Convert to a power of 2. */ + if (align != 0) + { + unsigned int i; + + for (i = 0; (align & 1) == 0; align >>= 1, ++i) + ; + if (align != 1) + as_bad ("Alignment not a power of 2"); + align = i; + } + } + + if (align > 15) + { + align = 15; + as_bad ("Alignment too large: %u assumed", align); + } + + if (*input_line_pointer != ',') + { + fill_p = 0; + max = 0; + } + else + { + ++input_line_pointer; + if (*input_line_pointer == ',') + fill_p = 0; + else + { + fill = get_absolute_expression (); + SKIP_WHITESPACE (); + fill_p = 1; + } + + if (*input_line_pointer != ',') + max = 0; + else + { + ++input_line_pointer; + max = get_absolute_expression (); + } + } + + if (! fill_p) + { + if (arg < 0) + as_warn ("expected fill pattern missing"); + do_align (align, (char *) NULL, 0, max); + } + else + { + int fill_len; + + if (arg >= 0) + fill_len = 1; + else + fill_len = - arg; + if (fill_len <= 1) + { + char fill_char; + + fill_char = fill; + do_align (align, &fill_char, fill_len, max); + } + else + { + char ab[16]; + + if (fill_len > sizeof ab) + abort (); + md_number_to_chars (ab, fill, fill_len); + do_align (align, ab, fill_len, max); + } + } + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +/* Handle the .align pseudo-op on machines where ".align 4" means + align to a 4 byte boundary. */ + +void +s_align_bytes (arg) + int arg; +{ + s_align (arg, 1); +} + +/* Handle the .align pseud-op on machines where ".align 4" means align + to a 2**4 boundary. */ + +void +s_align_ptwo (arg) + int arg; +{ + s_align (arg, 0); +} + +void +s_comm (ignore) + int ignore; +{ + register char *name; + register char c; + register char *p; + offsetT temp; + register symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("Expected comma after symbol-name: rest of line ignored."); + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) + { + as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp); + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + as_bad ("Ignoring attempt to re-define symbol `%s'.", + S_GET_NAME (symbolP)); + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) temp) + as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) temp); + } + else + { + S_SET_VALUE (symbolP, (valueT) temp); + S_SET_EXTERNAL (symbolP); + } +#ifdef OBJ_VMS + { + extern int flag_one; + if ( (!temp) || !flag_one) + S_GET_OTHER(symbolP) = const_flag; + } +#endif /* not OBJ_VMS */ + know (symbolP->sy_frag == &zero_address_frag); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} /* s_comm() */ + +/* The MRI COMMON pseudo-op. We handle this by creating a common + symbol with the appropriate name. We make s_space do the right + thing by increasing the size. */ + +void +s_mri_common (small) + int small; +{ + char *name; + char c; + char *alc = NULL; + symbolS *sym; + offsetT align; + char *stop = NULL; + char stopc; + + if (! flag_mri) + { + s_comm (0); + return; + } + + stop = mri_comment_field (&stopc); + + SKIP_WHITESPACE (); + + name = input_line_pointer; + if (! isdigit ((unsigned char) *name)) + c = get_symbol_end (); + else + { + do + { + ++input_line_pointer; + } + while (isdigit ((unsigned char) *input_line_pointer)); + c = *input_line_pointer; + *input_line_pointer = '\0'; + + if (line_label != NULL) + { + alc = (char *) xmalloc (strlen (S_GET_NAME (line_label)) + + (input_line_pointer - name) + + 1); + sprintf (alc, "%s%s", name, S_GET_NAME (line_label)); + name = alc; + } + } + + sym = symbol_find_or_make (name); + *input_line_pointer = c; + if (alc != NULL) + free (alc); + + if (*input_line_pointer != ',') + align = 0; + else + { + ++input_line_pointer; + align = get_absolute_expression (); + } + + if (S_IS_DEFINED (sym) && ! S_IS_COMMON (sym)) + { + as_bad ("attempt to re-define symbol `%s'", S_GET_NAME (sym)); + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + + S_SET_EXTERNAL (sym); + mri_common_symbol = sym; + +#ifdef S_SET_ALIGN + if (align != 0) + S_SET_ALIGN (sym, align); +#endif + + if (line_label != NULL) + { + line_label->sy_value.X_op = O_symbol; + line_label->sy_value.X_add_symbol = sym; + line_label->sy_value.X_add_number = S_GET_VALUE (sym); + line_label->sy_frag = &zero_address_frag; + S_SET_SEGMENT (line_label, expr_section); + } + + /* FIXME: We just ignore the small argument, which distinguishes + COMMON and COMMON.S. I don't know what we can do about it. */ + + /* Ignore the type and hptype. */ + if (*input_line_pointer == ',') + input_line_pointer += 2; + if (*input_line_pointer == ',') + input_line_pointer += 2; + + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +void +s_data (ignore) + int ignore; +{ + segT section; + register int temp; + + temp = get_absolute_expression (); + if (flag_readonly_data_in_text) + { + section = text_section; + temp += 1000; + } + else + section = data_section; + + subseg_set (section, (subsegT) temp); + +#ifdef OBJ_VMS + const_flag = 0; +#endif + demand_empty_rest_of_line (); +} + +/* Handle the .appfile pseudo-op. This is automatically generated by + do_scrub_chars when a preprocessor # line comment is seen with a + file name. This default definition may be overridden by the object + or CPU specific pseudo-ops. This function is also the default + definition for .file; the APPFILE argument is 1 for .appfile, 0 for + .file. */ + +void +s_app_file (appfile) + int appfile; +{ + register char *s; + int length; + + /* Some assemblers tolerate immediately following '"' */ + if ((s = demand_copy_string (&length)) != 0) + { + /* If this is a fake .appfile, a fake newline was inserted into + the buffer. Passing -2 to new_logical_line tells it to + account for it. */ + new_logical_line (s, appfile ? -2 : -1); + + /* In MRI mode, the preprocessor may have inserted an extraneous + backquote. */ + if (flag_m68k_mri + && *input_line_pointer == '\'' + && is_end_of_line[(unsigned char) input_line_pointer[1]]) + ++input_line_pointer; + + demand_empty_rest_of_line (); +#ifdef LISTING + if (listing) + listing_source_file (s); +#endif + } +#ifdef obj_app_file + obj_app_file (s); +#endif +} + +/* Handle the .appline pseudo-op. This is automatically generated by + do_scrub_chars when a preprocessor # line comment is seen. This + default definition may be overridden by the object or CPU specific + pseudo-ops. */ + +void +s_app_line (ignore) + int ignore; +{ + int l; + + /* The given number is that of the next line. */ + l = get_absolute_expression () - 1; + if (l < 0) + /* Some of the back ends can't deal with non-positive line numbers. + Besides, it's silly. */ + as_warn ("Line numbers must be positive; line number %d rejected.", l+1); + else + { + new_logical_line ((char *) NULL, l); +#ifdef LISTING + if (listing) + listing_source_line (l); +#endif + } + demand_empty_rest_of_line (); +} + +/* Handle the .end pseudo-op. Actually, the real work is done in + read_a_source_file. */ + +void +s_end (ignore) + int ignore; +{ + if (flag_mri) + { + /* The MRI assembler permits the start symbol to follow .end, + but we don't support that. */ + SKIP_WHITESPACE (); + if (! is_end_of_line[(unsigned char) *input_line_pointer] + && *input_line_pointer != '*' + && *input_line_pointer != '!') + as_warn ("start address not supported"); + } +} + +/* Handle the .err pseudo-op. */ + +void +s_err (ignore) + int ignore; +{ + as_bad (".err encountered"); + demand_empty_rest_of_line (); +} + +/* Handle the MRI fail pseudo-op. */ + +void +s_fail (ignore) + int ignore; +{ + offsetT temp; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + temp = get_absolute_expression (); + if (temp >= 500) + as_warn (".fail %ld encountered", (long) temp); + else + as_bad (".fail %ld encountered", (long) temp); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +void +s_fill (ignore) + int ignore; +{ + long temp_repeat = 0; + long temp_size = 1; + register long temp_fill = 0; + char *p; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + temp_repeat = get_absolute_expression (); + if (*input_line_pointer == ',') + { + input_line_pointer++; + temp_size = get_absolute_expression (); + if (*input_line_pointer == ',') + { + input_line_pointer++; + temp_fill = get_absolute_expression (); + } + } + /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */ +#define BSD_FILL_SIZE_CROCK_8 (8) + if (temp_size > BSD_FILL_SIZE_CROCK_8) + { + as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8); + temp_size = BSD_FILL_SIZE_CROCK_8; + } + if (temp_size < 0) + { + as_warn ("Size negative: .fill ignored."); + temp_size = 0; + } + else if (temp_repeat <= 0) + { + if (temp_repeat < 0) + as_warn ("Repeat < 0, .fill ignored"); + temp_size = 0; + } + + if (temp_size && !need_pass_2) + { + p = frag_var (rs_fill, (int) temp_size, (int) temp_size, + (relax_substateT) 0, (symbolS *) 0, (offsetT) temp_repeat, + (char *) 0); + memset (p, 0, (unsigned int) temp_size); + /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX + * flavoured AS. The following bizzare behaviour is to be + * compatible with above. I guess they tried to take up to 8 + * bytes from a 4-byte expression and they forgot to sign + * extend. Un*x Sux. */ +#define BSD_FILL_SIZE_CROCK_4 (4) + md_number_to_chars (p, (valueT) temp_fill, + (temp_size > BSD_FILL_SIZE_CROCK_4 + ? BSD_FILL_SIZE_CROCK_4 + : (int) temp_size)); + /* Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes) + * but emits no error message because it seems a legal thing to do. + * It is a degenerate case of .fill but could be emitted by a compiler. + */ + } + demand_empty_rest_of_line (); +} + +void +s_globl (ignore) + int ignore; +{ + char *name; + int c; + symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_SET_EXTERNAL (symbolP); + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +/* Handle the MRI IRP and IRPC pseudo-ops. */ + +void +s_irp (irpc) + int irpc; +{ + char *file; + unsigned int line; + sb s; + const char *err; + sb out; + + as_where (&file, &line); + + sb_new (&s); + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&out); + + err = expand_irp (irpc, 0, &s, &out, get_line_sb, '\0'); + if (err != NULL) + as_bad_where (file, line, "%s", err); + + sb_kill (&s); + + input_scrub_include_sb (&out, input_line_pointer); + sb_kill (&out); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Handle the .linkonce pseudo-op. This tells the assembler to mark + the section to only be linked once. However, this is not supported + by most object file formats. This takes an optional argument, + which is what to do about duplicates. */ + +void +s_linkonce (ignore) + int ignore; +{ + enum linkonce_type type; + + SKIP_WHITESPACE (); + + type = LINKONCE_DISCARD; + + if (! is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *s; + char c; + + s = input_line_pointer; + c = get_symbol_end (); + if (strcasecmp (s, "discard") == 0) + type = LINKONCE_DISCARD; + else if (strcasecmp (s, "one_only") == 0) + type = LINKONCE_ONE_ONLY; + else if (strcasecmp (s, "same_size") == 0) + type = LINKONCE_SAME_SIZE; + else if (strcasecmp (s, "same_contents") == 0) + type = LINKONCE_SAME_CONTENTS; + else + as_warn ("unrecognized .linkonce type `%s'", s); + + *input_line_pointer = c; + } + +#ifdef obj_handle_link_once + obj_handle_link_once (type); +#else /* ! defined (obj_handle_link_once) */ +#ifdef BFD_ASSEMBLER + { + flagword flags; + + if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0) + as_warn (".linkonce is not supported for this object file format"); + + flags = bfd_get_section_flags (stdoutput, now_seg); + flags |= SEC_LINK_ONCE; + switch (type) + { + default: + abort (); + case LINKONCE_DISCARD: + flags |= SEC_LINK_DUPLICATES_DISCARD; + break; + case LINKONCE_ONE_ONLY: + flags |= SEC_LINK_DUPLICATES_ONE_ONLY; + break; + case LINKONCE_SAME_SIZE: + flags |= SEC_LINK_DUPLICATES_SAME_SIZE; + break; + case LINKONCE_SAME_CONTENTS: + flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; + break; + } + if (! bfd_set_section_flags (stdoutput, now_seg, flags)) + as_bad ("bfd_set_section_flags: %s", + bfd_errmsg (bfd_get_error ())); + } +#else /* ! defined (BFD_ASSEMBLER) */ + as_warn (".linkonce is not supported for this object file format"); +#endif /* ! defined (BFD_ASSEMBLER) */ +#endif /* ! defined (obj_handle_link_once) */ + + demand_empty_rest_of_line (); +} + +void +s_lcomm (needs_align) + /* 1 if this was a ".bss" directive, which may require a 3rd argument + (alignment); 0 if it was an ".lcomm" (2 args only) */ + int needs_align; +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + const int max_alignment = 15; + int align = 0; + segT bss_seg = bss_section; + + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + + /* Accept an optional comma after the name. The comma used to be + required, but Irix 5 cc does not generate it. */ + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + } + + if (*input_line_pointer == '\n') + { + as_bad ("Missing size expression"); + return; + } + + if ((temp = get_absolute_expression ()) < 0) + { + as_warn ("BSS length (%d.) <0! Ignored.", temp); + ignore_rest_of_line (); + return; + } + +#if defined (TC_MIPS) || defined (TC_ALPHA) + if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour + || OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss. */ + if (temp <= bfd_get_gp_size (stdoutput)) + { + bss_seg = subseg_new (".sbss", 1); + seg_info (bss_seg)->bss = 1; +#ifdef BFD_ASSEMBLER + if (! bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC)) + as_warn ("error setting flags for \".sbss\": %s", + bfd_errmsg (bfd_get_error ())); +#endif + } + } +#endif + if (!needs_align) + { + /* FIXME. This needs to be machine independent. */ + if (temp >= 8) + align = 3; + else if (temp >= 4) + align = 2; + else if (temp >= 2) + align = 1; + else + align = 0; + +#ifdef OBJ_EVAX + /* FIXME: This needs to be done in a more general fashion. */ + align = 3; +#endif + + record_alignment(bss_seg, align); + } + + if (needs_align) + { + align = 0; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("Expected comma after size"); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + { + as_bad ("Missing alignment"); + return; + } + align = get_absolute_expression (); + if (align > max_alignment) + { + align = max_alignment; + as_warn ("Alignment too large: %d. assumed.", align); + } + else if (align < 0) + { + align = 0; + as_warn ("Alignment negative. 0 assumed."); + } + record_alignment (bss_seg, align); + } /* if needs align */ + else + { + /* Assume some objects may require alignment on some systems. */ +#if defined (TC_ALPHA) && ! defined (VMS) + if (temp > 1) + { + align = ffs (temp) - 1; + if (temp % (1 << align)) + abort (); + } +#endif + } + + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + + if ( +#if defined(OBJ_AOUT) | defined(OBJ_BOUT) + S_GET_OTHER (symbolP) == 0 && + S_GET_DESC (symbolP) == 0 && +#endif /* OBJ_AOUT or OBJ_BOUT */ + (S_GET_SEGMENT (symbolP) == bss_seg + || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0))) + { + char *pfrag; + + subseg_set (bss_seg, 1); + + if (align) + frag_align (align, 0, 0); + /* detach from old frag */ + if (S_GET_SEGMENT (symbolP) == bss_seg) + symbolP->sy_frag->fr_symbol = NULL; + + symbolP->sy_frag = frag_now; + pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, + (offsetT) temp, (char *) 0); + *pfrag = 0; + + S_SET_SEGMENT (symbolP, bss_seg); + +#ifdef OBJ_COFF + /* The symbol may already have been created with a preceding + ".globl" directive -- be careful not to step on storage class + in that case. Otherwise, set it to static. */ + if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) + { + S_SET_STORAGE_CLASS (symbolP, C_STAT); + } +#endif /* OBJ_COFF */ + +#ifdef S_SET_SIZE + S_SET_SIZE (symbolP, temp); +#endif + } + else + as_bad ("Ignoring attempt to re-define symbol `%s'.", + S_GET_NAME (symbolP)); + + subseg_set (current_seg, current_subseg); + + demand_empty_rest_of_line (); +} /* s_lcomm() */ + +void +s_lsym (ignore) + int ignore; +{ + register char *name; + register char c; + register char *p; + expressionS exp; + register symbolS *symbolP; + + /* we permit ANY defined expression: BSD4.2 demands constants */ + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad ("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line (); + return; + } + input_line_pointer++; + expression (&exp); + if (exp.X_op != O_constant + && exp.X_op != O_register) + { + as_bad ("bad expression"); + ignore_rest_of_line (); + return; + } + *p = 0; + symbolP = symbol_find_or_make (name); + + /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 && + symbolP->sy_desc == 0) out of this test because coff doesn't have + those fields, and I can't see when they'd ever be tripped. I + don't think I understand why they were here so I may have + introduced a bug. As recently as 1.37 didn't have this test + anyway. xoxorich. */ + + if (S_GET_SEGMENT (symbolP) == undefined_section + && S_GET_VALUE (symbolP) == 0) + { + /* The name might be an undefined .global symbol; be sure to + keep the "external" bit. */ + S_SET_SEGMENT (symbolP, + (exp.X_op == O_constant + ? absolute_section + : reg_section)); + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + } + else + { + as_bad ("Symbol %s already defined", name); + } + *p = c; + demand_empty_rest_of_line (); +} /* s_lsym() */ + +/* Read a line into an sb. */ + +static int +get_line_sb (line) + sb *line; +{ + char quote1, quote2, inquote; + + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + + if (input_line_pointer >= buffer_limit) + { + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + if (buffer_limit == 0) + return 0; + } + + /* If app.c sets any other characters to LEX_IS_STRINGQUOTE, this + code needs to be changed. */ + if (! flag_m68k_mri) + quote1 = '"'; + else + quote1 = '\0'; + + quote2 = '\0'; + if (flag_m68k_mri) + quote2 = '\''; +#ifdef LEX_IS_STRINGQUOTE + quote2 = '\''; +#endif + + inquote = '\0'; + while (! is_end_of_line[(unsigned char) *input_line_pointer] + || (inquote != '\0' && *input_line_pointer != '\n')) + { + if (inquote == *input_line_pointer) + inquote = '\0'; + else if (inquote == '\0') + { + if (*input_line_pointer == quote1) + inquote = quote1; + else if (*input_line_pointer == quote2) + inquote = quote2; + } + sb_add_char (line, *input_line_pointer++); + } + while (input_line_pointer < buffer_limit && *input_line_pointer == '\n') + { + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + ++input_line_pointer; + } + return 1; +} + +/* Define a macro. This is an interface to macro.c, which is shared + between gas and gasp. */ + +void +s_macro (ignore) + int ignore; +{ + char *file; + unsigned int line; + sb s; + sb label; + const char *err; + const char *name; + + as_where (&file, &line); + + sb_new (&s); + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&label); + if (line_label != NULL) + sb_add_string (&label, S_GET_NAME (line_label)); + + err = define_macro (0, &s, &label, get_line_sb, &name); + if (err != NULL) + as_bad_where (file, line, "%s", err); + else + { + if (line_label != NULL) + { + S_SET_SEGMENT (line_label, undefined_section); + S_SET_VALUE (line_label, 0); + line_label->sy_frag = &zero_address_frag; + } + + if (((flag_m68k_mri +#ifdef NO_PSEUDO_DOT + || 1 +#endif + ) + && hash_find (po_hash, name) != NULL) + || (! flag_m68k_mri + && *name == '.' + && hash_find (po_hash, name + 1) != NULL)) + as_warn ("attempt to redefine pseudo-op `%s' ignored", + name); + } + + sb_kill (&s); +} + +/* Handle the .mexit pseudo-op, which immediately exits a macro + expansion. */ + +void +s_mexit (ignore) + int ignore; +{ + cond_exit_macro (macro_nest); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Switch in and out of MRI mode. */ + +void +s_mri (ignore) + int ignore; +{ + int on, old_flag; + + on = get_absolute_expression (); + old_flag = flag_mri; + if (on != 0) + { + flag_mri = 1; +#ifdef TC_M68K + flag_m68k_mri = 1; +#endif + } + else + { + flag_mri = 0; + flag_m68k_mri = 0; + } + +#ifdef MRI_MODE_CHANGE + if (on != old_flag) + MRI_MODE_CHANGE (on); +#endif + + demand_empty_rest_of_line (); +} + +/* Handle changing the location counter. */ + +static void +do_org (segment, exp, fill) + segT segment; + expressionS *exp; + int fill; +{ + if (segment != now_seg && segment != absolute_section) + as_bad ("invalid segment \"%s\"; segment \"%s\" assumed", + segment_name (segment), segment_name (now_seg)); + + if (now_seg == absolute_section) + { + if (fill != 0) + as_warn ("ignoring fill value in absolute section"); + if (exp->X_op != O_constant) + { + as_bad ("only constant offsets supported in absolute section"); + exp->X_add_number = 0; + } + abs_section_offset = exp->X_add_number; + } + else + { + char *p; + + p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp->X_add_symbol, + exp->X_add_number, (char *) NULL); + *p = fill; + } +} + +void +s_org (ignore) + int ignore; +{ + register segT segment; + expressionS exp; + register long temp_fill; + + /* The m68k MRI assembler has a different meaning for .org. It + means to create an absolute section at a given address. We can't + support that--use a linker script instead. */ + if (flag_m68k_mri) + { + as_bad ("MRI style ORG pseudo-op not supported"); + ignore_rest_of_line (); + return; + } + + /* Don't believe the documentation of BSD 4.2 AS. There is no such + thing as a sub-segment-relative origin. Any absolute origin is + given a warning, then assumed to be segment-relative. Any + segmented origin expression ("foo+42") had better be in the right + segment or the .org is ignored. + + BSD 4.2 AS warns if you try to .org backwards. We cannot because + we never know sub-segment sizes when we are reading code. BSD + will crash trying to emit negative numbers of filler bytes in + certain .orgs. We don't crash, but see as-write for that code. + + Don't make frag if need_pass_2==1. */ + segment = get_known_segmented_expression (&exp); + if (*input_line_pointer == ',') + { + input_line_pointer++; + temp_fill = get_absolute_expression (); + } + else + temp_fill = 0; + + if (!need_pass_2) + do_org (segment, &exp, temp_fill); + + demand_empty_rest_of_line (); +} /* s_org() */ + +/* Handle parsing for the MRI SECT/SECTION pseudo-op. This should be + called by the obj-format routine which handles section changing + when in MRI mode. It will create a new section, and return it. It + will set *TYPE to the section type: one of 'C' (code), 'D' (data), + 'M' (mixed), or 'R' (romable). If BFD_ASSEMBLER is defined, the + flags will be set in the section. */ + +void +s_mri_sect (type) + char *type; +{ +#ifdef TC_M68K + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + if (! isdigit ((unsigned char) *name)) + c = get_symbol_end (); + else + { + do + { + ++input_line_pointer; + } + while (isdigit ((unsigned char) *input_line_pointer)); + c = *input_line_pointer; + *input_line_pointer = '\0'; + } + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer == ',') + { + int align; + + ++input_line_pointer; + align = get_absolute_expression (); + record_alignment (seg, align); + } + + *type = 'C'; + if (*input_line_pointer == ',') + { + c = *++input_line_pointer; + c = toupper ((unsigned char) c); + if (c == 'C' || c == 'D' || c == 'M' || c == 'R') + *type = c; + else + as_bad ("unrecognized section type"); + ++input_line_pointer; + +#ifdef BFD_ASSEMBLER + { + flagword flags; + + flags = SEC_NO_FLAGS; + if (*type == 'C') + flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE; + else if (*type == 'D' || *type == 'M') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA; + else if (*type == 'R') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM; + if (flags != SEC_NO_FLAGS) + { + if (! bfd_set_section_flags (stdoutput, seg, flags)) + as_warn ("error setting flags for \"%s\": %s", + bfd_section_name (stdoutput, seg), + bfd_errmsg (bfd_get_error ())); + } + } +#endif + } + + /* Ignore the HP type. */ + if (*input_line_pointer == ',') + input_line_pointer += 2; + + demand_empty_rest_of_line (); + +#else /* ! TC_M68K */ +#ifdef TC_I960 + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer != ',') + *type = 'C'; + else + { + char *sectype; + + ++input_line_pointer; + SKIP_WHITESPACE (); + sectype = input_line_pointer; + c = get_symbol_end (); + if (*sectype == '\0') + *type = 'C'; + else if (strcasecmp (sectype, "text") == 0) + *type = 'C'; + else if (strcasecmp (sectype, "data") == 0) + *type = 'D'; + else if (strcasecmp (sectype, "romdata") == 0) + *type = 'R'; + else + as_warn ("unrecognized section type `%s'", sectype); + *input_line_pointer = c; + } + + if (*input_line_pointer == ',') + { + char *seccmd; + + ++input_line_pointer; + SKIP_WHITESPACE (); + seccmd = input_line_pointer; + c = get_symbol_end (); + if (strcasecmp (seccmd, "absolute") == 0) + { + as_bad ("absolute sections are not supported"); + *input_line_pointer = c; + ignore_rest_of_line (); + return; + } + else if (strcasecmp (seccmd, "align") == 0) + { + int align; + + *input_line_pointer = c; + align = get_absolute_expression (); + record_alignment (seg, align); + } + else + { + as_warn ("unrecognized section command `%s'", seccmd); + *input_line_pointer = c; + } + } + + demand_empty_rest_of_line (); + +#else /* ! TC_I960 */ + /* The MRI assembler seems to use different forms of .sect for + different targets. */ + abort (); +#endif /* ! TC_I960 */ +#endif /* ! TC_M68K */ +} + +/* Handle the .print pseudo-op. */ + +void +s_print (ignore) + int ignore; +{ + char *s; + int len; + + s = demand_copy_C_string (&len); + printf ("%s\n", s); + demand_empty_rest_of_line (); +} + +/* Handle the .purgem pseudo-op. */ + +void +s_purgem (ignore) + int ignore; +{ + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + char *name; + char c; + + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + delete_macro (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; + demand_empty_rest_of_line (); +} + +/* Handle the .rept pseudo-op. */ + +void +s_rept (ignore) + int ignore; +{ + int count; + sb one; + sb many; + + count = get_absolute_expression (); + + sb_new (&one); + if (! buffer_and_nest ("REPT", "ENDR", &one, get_line_sb)) + { + as_bad ("rept without endr"); + return; + } + + sb_new (&many); + while (count-- > 0) + sb_add_sb (&many, &one); + + sb_kill (&one); + + input_scrub_include_sb (&many, input_line_pointer); + sb_kill (&many); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Handle the .equ, .equiv and .set directives. If EQUIV is 1, then + this is .equiv, and it is an error if the symbol is already + defined. */ + +void +s_set (equiv) + int equiv; +{ + register char *name; + register char delim; + register char *end_name; + register symbolS *symbolP; + + /* + * Especial apologies for the random logic: + * this just grew, and could be parsed much more simply! + * Dean in haste. + */ + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + *end_name = delim; + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad ("Expected comma after name \"%s\"", name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + *end_name = 0; + + if (name[0] == '.' && name[1] == '\0') + { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + + segment = get_known_segmented_expression (&exp); + + if (!need_pass_2) + do_org (segment, &exp, 0); + + *end_name = delim; + return; + } + + if ((symbolP = symbol_find (name)) == NULL + && (symbolP = md_undefined_symbol (name)) == NULL) + { + symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); +#ifdef OBJ_COFF + /* "set" symbols are local unless otherwise specified. */ + SF_SET_LOCAL (symbolP); +#endif /* OBJ_COFF */ + + } /* make a new symbol */ + + symbol_table_insert (symbolP); + + *end_name = delim; + + if (equiv + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section) + as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP)); + + pseudo_set (symbolP); + demand_empty_rest_of_line (); +} /* s_set() */ + +void +s_space (mult) + int mult; +{ + expressionS exp; + expressionS val; + char *p = 0; + char *stop = NULL; + char stopc; + int bytes; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (flag_mri) + stop = mri_comment_field (&stopc); + + /* In m68k MRI mode, we need to align to a word boundary, unless + this is ds.b. */ + if (flag_m68k_mri && mult > 1) + { + if (now_seg == absolute_section) + { + abs_section_offset += abs_section_offset & 1; + if (line_label != NULL) + S_SET_VALUE (line_label, abs_section_offset); + } + else if (mri_common_symbol != NULL) + { + valueT val; + + val = S_GET_VALUE (mri_common_symbol); + if ((val & 1) != 0) + { + S_SET_VALUE (mri_common_symbol, val + 1); + if (line_label != NULL) + { + know (line_label->sy_value.X_op == O_symbol); + know (line_label->sy_value.X_add_symbol == mri_common_symbol); + line_label->sy_value.X_add_number += 1; + } + } + } + else + { + do_align (1, (char *) NULL, 0, 0); + if (line_label != NULL) + { + line_label->sy_frag = frag_now; + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + } + + bytes = mult; + + expression (&exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + expression (&val); + } + else + { + val.X_op = O_constant; + val.X_add_number = 0; + } + + if (val.X_op != O_constant + || val.X_add_number < - 0x80 + || val.X_add_number > 0xff + || (mult != 0 && mult != 1 && val.X_add_number != 0)) + { + if (exp.X_op != O_constant) + as_bad ("Unsupported variable size or fill value"); + else + { + offsetT i; + + if (mult == 0) + mult = 1; + bytes = mult * exp.X_add_number; + for (i = 0; i < exp.X_add_number; i++) + emit_expr (&val, mult); + } + } + else + { + if (exp.X_op == O_constant) + { + long repeat; + + repeat = exp.X_add_number; + if (mult) + repeat *= mult; + bytes = repeat; + if (repeat <= 0) + { + if (! flag_mri || repeat < 0) + as_warn (".space repeat count is %s, ignored", + repeat ? "negative" : "zero"); + goto getout; + } + + /* If we are in the absolute section, just bump the offset. */ + if (now_seg == absolute_section) + { + abs_section_offset += repeat; + goto getout; + } + + /* If we are secretly in an MRI common section, then + creating space just increases the size of the common + symbol. */ + if (mri_common_symbol != NULL) + { + S_SET_VALUE (mri_common_symbol, + S_GET_VALUE (mri_common_symbol) + repeat); + goto getout; + } + + if (!need_pass_2) + p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0, + (offsetT) repeat, (char *) 0); + } + else + { + if (now_seg == absolute_section) + { + as_bad ("space allocation too complex in absolute section"); + subseg_set (text_section, 0); + } + if (mri_common_symbol != NULL) + { + as_bad ("space allocation too complex in common section"); + mri_common_symbol = NULL; + } + if (!need_pass_2) + p = frag_var (rs_space, 1, 1, (relax_substateT) 0, + make_expr_symbol (&exp), (offsetT) 0, (char *) 0); + } + + if (p) + *p = val.X_add_number; + } + + getout: + + /* In MRI mode, after an odd number of bytes, we must align to an + even word boundary, unless the next instruction is a dc.b, ds.b + or dcb.b. */ + if (flag_mri && (bytes & 1) != 0) + mri_pending_align = 1; + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +/* This is like s_space, but the value is a floating point number with + the given precision. This is for the MRI dcb.s pseudo-op and + friends. */ + +void +s_float_space (float_type) + int float_type; +{ + offsetT count; + int flen; + char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + count = get_absolute_expression (); + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("missing value"); + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + + SKIP_WHITESPACE (); + + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. */ + if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1])) + input_line_pointer += 2; + + /* Accept :xxxx, where the x's are hex digits, for a floating point + with the exact digits specified. */ + if (input_line_pointer[0] == ':') + { + flen = hex_float (float_type, temp); + if (flen < 0) + { + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + } + else + { + char *err; + + err = md_atof (float_type, temp, &flen); + know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know (flen > 0); + if (err) + { + as_bad ("Bad floating literal: %s", err); + if (flag_mri) + mri_comment_end (stop, stopc); + ignore_rest_of_line (); + return; + } + } + + while (--count >= 0) + { + char *p; + + p = frag_more (flen); + memcpy (p, temp, (unsigned int) flen); + } + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +/* Handle the .struct pseudo-op, as found in MIPS assemblers. */ + +void +s_struct (ignore) + int ignore; +{ + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + abs_section_offset = get_absolute_expression (); + subseg_set (absolute_section, 0); + if (flag_mri) + mri_comment_end (stop, stopc); + demand_empty_rest_of_line (); +} + +void +s_text (ignore) + int ignore; +{ + register int temp; + + temp = get_absolute_expression (); + subseg_set (text_section, (subsegT) temp); + demand_empty_rest_of_line (); +#ifdef OBJ_VMS + const_flag &= ~IN_DEFAULT_SECTION; +#endif +} /* s_text() */ + + +void +demand_empty_rest_of_line () +{ + SKIP_WHITESPACE (); + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + input_line_pointer++; + } + else + { + ignore_rest_of_line (); + } + /* Return having already swallowed end-of-line. */ +} /* Return pointing just after end-of-line. */ + +void +ignore_rest_of_line () /* For suspect lines: gives warning. */ +{ + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (isprint (*input_line_pointer)) + as_bad ("Rest of line ignored. First ignored character is `%c'.", + *input_line_pointer); + else + as_bad ("Rest of line ignored. First ignored character valued 0x%x.", + *input_line_pointer); + while (input_line_pointer < buffer_limit + && !is_end_of_line[(unsigned char) *input_line_pointer]) + { + input_line_pointer++; + } + } + input_line_pointer++; /* Return pointing just after end-of-line. */ + know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); +} + +/* + * pseudo_set() + * + * In: Pointer to a symbol. + * Input_line_pointer->expression. + * + * Out: Input_line_pointer->just after any whitespace after expression. + * Tried to set symbol to value of expression. + * Will change symbols type, value, and frag; + */ +void +pseudo_set (symbolP) + symbolS *symbolP; +{ + expressionS exp; +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + int ext; +#endif /* OBJ_AOUT or OBJ_BOUT */ + + know (symbolP); /* NULL pointer is logic error. */ +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + ext = S_IS_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + + (void) expression (&exp); + + if (exp.X_op == O_illegal) + as_bad ("illegal expression; zero assumed"); + else if (exp.X_op == O_absent) + as_bad ("missing expression; zero assumed"); + else if (exp.X_op == O_big) + as_bad ("%s number invalid; zero assumed", + exp.X_add_number > 0 ? "bignum" : "floating point"); + else if (exp.X_op == O_subtract + && (S_GET_SEGMENT (exp.X_add_symbol) + == S_GET_SEGMENT (exp.X_op_symbol)) + && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol)) + && exp.X_add_symbol->sy_frag == exp.X_op_symbol->sy_frag) + { + exp.X_op = O_constant; + exp.X_add_number = (S_GET_VALUE (exp.X_add_symbol) + - S_GET_VALUE (exp.X_op_symbol)); + } + + switch (exp.X_op) + { + case O_illegal: + case O_absent: + case O_big: + exp.X_add_number = 0; + /* Fall through. */ + case O_constant: + S_SET_SEGMENT (symbolP, absolute_section); +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + if (ext) + S_SET_EXTERNAL (symbolP); + else + S_CLEAR_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + symbolP->sy_frag = &zero_address_frag; + break; + + case O_register: + S_SET_SEGMENT (symbolP, reg_section); + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + symbolP->sy_frag = &zero_address_frag; + break; + + case O_symbol: + if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section + || exp.X_add_number != 0) + symbolP->sy_value = exp; + else + { + symbolS *s = exp.X_add_symbol; + + S_SET_SEGMENT (symbolP, S_GET_SEGMENT (s)); +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + if (ext) + S_SET_EXTERNAL (symbolP); + else + S_CLEAR_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE (symbolP, + exp.X_add_number + S_GET_VALUE (s)); + symbolP->sy_frag = s->sy_frag; + copy_symbol_attributes (symbolP, s); + } + break; + + default: + /* The value is some complex expression. + FIXME: Should we set the segment to anything? */ + symbolP->sy_value = exp; + break; + } +} + +/* + * cons() + * + * CONStruct more frag of .bytes, or .words etc. + * Should need_pass_2 be 1 then emit no frag(s). + * This understands EXPRESSIONS. + * + * Bug (?) + * + * This has a split personality. We use expression() to read the + * value. We can detect if the value won't fit in a byte or word. + * But we can't detect if expression() discarded significant digits + * in the case of a long. Not worth the crocks required to fix it. + */ + +/* Select a parser for cons expressions. */ + +/* Some targets need to parse the expression in various fancy ways. + You can define TC_PARSE_CONS_EXPRESSION to do whatever you like + (for example, the HPPA does this). Otherwise, you can define + BITFIELD_CONS_EXPRESSIONS to permit bitfields to be specified, or + REPEAT_CONS_EXPRESSIONS to permit repeat counts. If none of these + are defined, which is the normal case, then only simple expressions + are permitted. */ + +static void +parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes)); + +#ifndef TC_PARSE_CONS_EXPRESSION +#ifdef BITFIELD_CONS_EXPRESSIONS +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES) +static void +parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +#endif +#ifdef REPEAT_CONS_EXPRESSIONS +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES) +static void +parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +#endif + +/* If we haven't gotten one yet, just call expression. */ +#ifndef TC_PARSE_CONS_EXPRESSION +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP) +#endif +#endif + +/* worker to do .byte etc statements */ +/* clobbers input_line_pointer, checks */ +/* end-of-line. */ +static void +cons_worker (nbytes, rva) + register int nbytes; /* 1=.byte, 2=.word, 4=.long */ + int rva; +{ + int c; + expressionS exp; + char *stop = NULL; + char stopc; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (is_it_end_of_statement ()) + { + if (flag_mri) + mri_comment_end (stop, stopc); + demand_empty_rest_of_line (); + return; + } + +#ifdef md_cons_align + md_cons_align (nbytes); +#endif + + c = 0; + do + { + if (flag_m68k_mri) + parse_mri_cons (&exp, (unsigned int) nbytes); + else + TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + + if (rva) + { + if (exp.X_op == O_symbol) + exp.X_op = O_symbol_rva; + else + as_fatal ("rva without symbol"); + } + emit_expr (&exp, (unsigned int) nbytes); + ++c; + } + while (*input_line_pointer++ == ','); + + /* In MRI mode, after an odd number of bytes, we must align to an + even word boundary, unless the next instruction is a dc.b, ds.b + or dcb.b. */ + if (flag_mri && nbytes == 1 && (c & 1) != 0) + mri_pending_align = 1; + + input_line_pointer--; /* Put terminator back into stream. */ + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + + +void +cons (size) + int size; +{ + cons_worker (size, 0); +} + +void +s_rva (size) + int size; +{ + cons_worker (size, 1); +} + + +/* Put the contents of expression EXP into the object file using + NBYTES bytes. If need_pass_2 is 1, this does nothing. */ + +void +emit_expr (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + operatorT op; + register char *p; + valueT extra_digit = 0; + + /* Don't do anything if we are going to make another pass. */ + if (need_pass_2) + return; + + op = exp->X_op; + + /* Allow `.word 0' in the absolute section. */ + if (now_seg == absolute_section) + { + if (op != O_constant || exp->X_add_number != 0) + as_bad ("attempt to store value in absolute section"); + abs_section_offset += nbytes; + return; + } + + /* Handle a negative bignum. */ + if (op == O_uminus + && exp->X_add_number == 0 + && exp->X_add_symbol->sy_value.X_op == O_big + && exp->X_add_symbol->sy_value.X_add_number > 0) + { + int i; + unsigned long carry; + + exp = &exp->X_add_symbol->sy_value; + + /* Negate the bignum: one's complement each digit and add 1. */ + carry = 1; + for (i = 0; i < exp->X_add_number; i++) + { + unsigned long next; + + next = (((~ (generic_bignum[i] & LITTLENUM_MASK)) + & LITTLENUM_MASK) + + carry); + generic_bignum[i] = next & LITTLENUM_MASK; + carry = next >> LITTLENUM_NUMBER_OF_BITS; + } + + /* We can ignore any carry out, because it will be handled by + extra_digit if it is needed. */ + + extra_digit = (valueT) -1; + op = O_big; + } + + if (op == O_absent || op == O_illegal) + { + as_warn ("zero assumed for missing expression"); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_big && exp->X_add_number <= 0) + { + as_bad ("floating point number invalid; zero assumed"); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_register) + { + as_warn ("register value used as expression"); + op = O_constant; + } + + p = frag_more ((int) nbytes); + +#ifndef WORKING_DOT_WORD + /* If we have the difference of two symbols in a word, save it on + the broken_words list. See the code in write.c. */ + if (op == O_subtract && nbytes == 2) + { + struct broken_word *x; + + x = (struct broken_word *) xmalloc (sizeof (struct broken_word)); + x->next_broken_word = broken_words; + broken_words = x; + x->frag = frag_now; + x->word_goes_here = p; + x->dispfrag = 0; + x->add = exp->X_add_symbol; + x->sub = exp->X_op_symbol; + x->addnum = exp->X_add_number; + x->added = 0; + new_broken_words++; + return; + } +#endif + + /* If we have an integer, but the number of bytes is too large to + pass to md_number_to_chars, handle it as a bignum. */ + if (op == O_constant && nbytes > sizeof (valueT)) + { + valueT val; + int gencnt; + + if (! exp->X_unsigned && exp->X_add_number < 0) + extra_digit = (valueT) -1; + val = (valueT) exp->X_add_number; + gencnt = 0; + do + { + generic_bignum[gencnt] = val & LITTLENUM_MASK; + val >>= LITTLENUM_NUMBER_OF_BITS; + ++gencnt; + } + while (val != 0); + op = exp->X_op = O_big; + exp->X_add_number = gencnt; + } + + if (op == O_constant) + { + register valueT get; + register valueT use; + register valueT mask; + valueT hibit; + register valueT unmask; + + /* JF << of >= number of bits in the object is undefined. In + particular SPARC (Sun 4) has problems */ + if (nbytes >= sizeof (valueT)) + { + mask = 0; + if (nbytes > sizeof (valueT)) + hibit = 0; + else + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } + else + { + /* Don't store these bits. */ + mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } + + unmask = ~mask; /* Do store these bits. */ + +#ifdef NEVER + "Do this mod if you want every overflow check to assume SIGNED 2's complement data."; + mask = ~(unmask >> 1); /* Includes sign bit now. */ +#endif + + get = exp->X_add_number; + use = get & unmask; + if ((get & mask) != 0 + && ((get & mask) != mask + || (get & hibit) == 0)) + { /* Leading bits contain both 0s & 1s. */ + as_warn ("Value 0x%lx truncated to 0x%lx.", + (unsigned long) get, (unsigned long) use); + } + /* put bytes in right order. */ + md_number_to_chars (p, use, (int) nbytes); + } + else if (op == O_big) + { + int size; + LITTLENUM_TYPE *nums; + + know (nbytes % CHARS_PER_LITTLENUM == 0); + + size = exp->X_add_number * CHARS_PER_LITTLENUM; + if (nbytes < size) + { + as_warn ("Bignum truncated to %d bytes", nbytes); + size = nbytes; + } + + if (target_big_endian) + { + while (nbytes > size) + { + md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM); + nbytes -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + + nums = generic_bignum + size / CHARS_PER_LITTLENUM; + while (size > 0) + { + --nums; + md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM); + size -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + } + else + { + nums = generic_bignum; + while (size > 0) + { + md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM); + ++nums; + size -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + nbytes -= CHARS_PER_LITTLENUM; + } + + while (nbytes > 0) + { + md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM); + nbytes -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + } + } + else + { + memset (p, 0, nbytes); + + /* Now we need to generate a fixS to record the symbol value. + This is easy for BFD. For other targets it can be more + complex. For very complex cases (currently, the HPPA and + NS32K), you can define TC_CONS_FIX_NEW to do whatever you + want. For simpler cases, you can define TC_CONS_RELOC to be + the name of the reloc code that should be stored in the fixS. + If neither is defined, the code uses NO_RELOC if it is + defined, and otherwise uses 0. */ + +#ifdef BFD_ASSEMBLER +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); +#else + { + bfd_reloc_code_real_type r; + + switch (nbytes) + { + case 1: + r = BFD_RELOC_8; + break; + case 2: + r = BFD_RELOC_16; + break; + case 4: + r = BFD_RELOC_32; + break; + case 8: + r = BFD_RELOC_64; + break; + default: + as_bad ("unsupported BFD relocation size %u", nbytes); + r = BFD_RELOC_32; + break; + } + fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, + 0, r); + } +#endif +#else +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); +#else + /* Figure out which reloc number to use. Use TC_CONS_RELOC if + it is defined, otherwise use NO_RELOC if it is defined, + otherwise use 0. */ +#ifndef TC_CONS_RELOC +#ifdef NO_RELOC +#define TC_CONS_RELOC NO_RELOC +#else +#define TC_CONS_RELOC 0 +#endif +#endif + fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0, + TC_CONS_RELOC); +#endif /* TC_CONS_FIX_NEW */ +#endif /* BFD_ASSEMBLER */ + } +} + +#ifdef BITFIELD_CONS_EXPRESSIONS + +/* i960 assemblers, (eg, asm960), allow bitfields after ".byte" as + w:x,y:z, where w and y are bitwidths and x and y are values. They + then pack them all together. We do a little better in that we allow + them in words, longs, etc. and we'll pack them in target byte order + for you. + + The rules are: pack least significat bit first, if a field doesn't + entirely fit, put it in the next unit. Overflowing the bitfield is + explicitly *not* even a warning. The bitwidth should be considered + a "mask". + + To use this function the tc-XXX.h file should define + BITFIELD_CONS_EXPRESSIONS. */ + +static void +parse_bitfield_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + unsigned int bits_available = BITS_PER_CHAR * nbytes; + char *hold = input_line_pointer; + + (void) expression (exp); + + if (*input_line_pointer == ':') + { /* bitfields */ + long value = 0; + + for (;;) + { + unsigned long width; + + if (*input_line_pointer != ':') + { + input_line_pointer = hold; + break; + } /* next piece is not a bitfield */ + + /* In the general case, we can't allow + full expressions with symbol + differences and such. The relocation + entries for symbols not defined in this + assembly would require arbitrary field + widths, positions, and masks which most + of our current object formats don't + support. + + In the specific case where a symbol + *is* defined in this assembly, we + *could* build fixups and track it, but + this could lead to confusion for the + backends. I'm lazy. I'll take any + SEG_ABSOLUTE. I think that means that + you can use a previous .set or + .equ type symbol. xoxorich. */ + + if (exp->X_op == O_absent) + { + as_warn ("using a bit field width of zero"); + exp->X_add_number = 0; + exp->X_op = O_constant; + } /* implied zero width bitfield */ + + if (exp->X_op != O_constant) + { + *input_line_pointer = '\0'; + as_bad ("field width \"%s\" too complex for a bitfield", hold); + *input_line_pointer = ':'; + demand_empty_rest_of_line (); + return; + } /* too complex */ + + if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes)) + { + as_warn ("field width %lu too big to fit in %d bytes: truncated to %d bits", + width, nbytes, (BITS_PER_CHAR * nbytes)); + width = BITS_PER_CHAR * nbytes; + } /* too big */ + + if (width > bits_available) + { + /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ + input_line_pointer = hold; + exp->X_add_number = value; + break; + } /* won't fit */ + + hold = ++input_line_pointer; /* skip ':' */ + + (void) expression (exp); + if (exp->X_op != O_constant) + { + char cache = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad ("field value \"%s\" too complex for a bitfield", hold); + *input_line_pointer = cache; + demand_empty_rest_of_line (); + return; + } /* too complex */ + + value |= ((~(-1 << width) & exp->X_add_number) + << ((BITS_PER_CHAR * nbytes) - bits_available)); + + if ((bits_available -= width) == 0 + || is_it_end_of_statement () + || *input_line_pointer != ',') + { + break; + } /* all the bitfields we're gonna get */ + + hold = ++input_line_pointer; + (void) expression (exp); + } /* forever loop */ + + exp->X_add_number = value; + exp->X_op = O_constant; + exp->X_unsigned = 1; + } /* if looks like a bitfield */ +} /* parse_bitfield_cons() */ + +#endif /* BITFIELD_CONS_EXPRESSIONS */ + +/* Handle an MRI style string expression. */ + +static void +parse_mri_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + if (*input_line_pointer != '\'' + && (input_line_pointer[1] != '\'' + || (*input_line_pointer != 'A' + && *input_line_pointer != 'E'))) + TC_PARSE_CONS_EXPRESSION (exp, nbytes); + else + { + int scan = 0; + unsigned int result = 0; + + /* An MRI style string. Cut into as many bytes as will fit into + a nbyte chunk, left justify if necessary, and separate with + commas so we can try again later. */ + if (*input_line_pointer == 'A') + ++input_line_pointer; + else if (*input_line_pointer == 'E') + { + as_bad ("EBCDIC constants are not supported"); + ++input_line_pointer; + } + + input_line_pointer++; + for (scan = 0; scan < nbytes; scan++) + { + if (*input_line_pointer == '\'') + { + if (input_line_pointer[1] == '\'') + { + input_line_pointer++; + } + else + break; + } + result = (result << 8) | (*input_line_pointer++); + } + + /* Left justify */ + while (scan < nbytes) + { + result <<= 8; + scan++; + } + /* Create correct expression */ + exp->X_op = O_constant; + exp->X_add_number = result; + /* Fake it so that we can read the next char too */ + if (input_line_pointer[0] != '\'' || + (input_line_pointer[0] == '\'' && input_line_pointer[1] == '\'')) + { + input_line_pointer -= 2; + input_line_pointer[0] = ','; + input_line_pointer[1] = '\''; + } + else + input_line_pointer++; + } +} + +#ifdef REPEAT_CONS_EXPRESSIONS + +/* Parse a repeat expression for cons. This is used by the MIPS + assembler. The format is NUMBER:COUNT; NUMBER appears in the + object file COUNT times. + + To use this for a target, define REPEAT_CONS_EXPRESSIONS. */ + +static void +parse_repeat_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + expressionS count; + register int i; + + expression (exp); + + if (*input_line_pointer != ':') + { + /* No repeat count. */ + return; + } + + ++input_line_pointer; + expression (&count); + if (count.X_op != O_constant + || count.X_add_number <= 0) + { + as_warn ("Unresolvable or nonpositive repeat count; using 1"); + return; + } + + /* The cons function is going to output this expression once. So we + output it count - 1 times. */ + for (i = count.X_add_number - 1; i > 0; i--) + emit_expr (exp, nbytes); +} + +#endif /* REPEAT_CONS_EXPRESSIONS */ + +/* Parse a floating point number represented as a hex constant. This + permits users to specify the exact bits they want in the floating + point number. */ + +static int +hex_float (float_type, bytes) + int float_type; + char *bytes; +{ + int length; + int i; + + switch (float_type) + { + case 'f': + case 'F': + case 's': + case 'S': + length = 4; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + length = 8; + break; + + case 'x': + case 'X': + length = 12; + break; + + case 'p': + case 'P': + length = 12; + break; + + default: + as_bad ("Unknown floating type type '%c'", float_type); + return -1; + } + + /* It would be nice if we could go through expression to parse the + hex constant, but if we get a bignum it's a pain to sort it into + the buffer correctly. */ + i = 0; + while (hex_p (*input_line_pointer) || *input_line_pointer == '_') + { + int d; + + /* The MRI assembler accepts arbitrary underscores strewn about + through the hex constant, so we ignore them as well. */ + if (*input_line_pointer == '_') + { + ++input_line_pointer; + continue; + } + + if (i >= length) + { + as_warn ("Floating point constant too large"); + return -1; + } + d = hex_value (*input_line_pointer) << 4; + ++input_line_pointer; + while (*input_line_pointer == '_') + ++input_line_pointer; + if (hex_p (*input_line_pointer)) + { + d += hex_value (*input_line_pointer); + ++input_line_pointer; + } + if (target_big_endian) + bytes[i] = d; + else + bytes[length - i - 1] = d; + ++i; + } + + if (i < length) + { + if (target_big_endian) + memset (bytes + i, 0, length - i); + else + memset (bytes, 0, length - i); + } + + return length; +} + +/* + * float_cons() + * + * CONStruct some more frag chars of .floats .ffloats etc. + * Makes 0 or more new frags. + * If need_pass_2 == 1, no frags are emitted. + * This understands only floating literals, not expressions. Sorry. + * + * A floating constant is defined by atof_generic(), except it is preceded + * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its + * reading, I decided to be incompatible. This always tries to give you + * rounded bits to the precision of the pseudo-op. Former AS did premature + * truncatation, restored noisy bits instead of trailing 0s AND gave you + * a choice of 2 flavours of noise according to which of 2 floating-point + * scanners you directed AS to use. + * + * In: input_line_pointer->whitespace before, or '0' of flonum. + * + */ + +void +float_cons (float_type) + /* Clobbers input_line-pointer, checks end-of-line. */ + register int float_type; /* 'f':.ffloat ... 'F':.float ... */ +{ + register char *p; + int length; /* Number of chars in an object. */ + register char *err; /* Error from scanning floating literal. */ + char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + do + { + /* input_line_pointer->1st char of a flonum (we hope!). */ + SKIP_WHITESPACE (); + + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. Someone may invent a "z" format and this routine + * has no use for such information. Lusers beware: you get + * diagnostics if your input is ill-conditioned. + */ + if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1])) + input_line_pointer += 2; + + /* Accept :xxxx, where the x's are hex digits, for a floating + point with the exact digits specified. */ + if (input_line_pointer[0] == ':') + { + ++input_line_pointer; + length = hex_float (float_type, temp); + if (length < 0) + { + ignore_rest_of_line (); + return; + } + } + else + { + err = md_atof (float_type, temp, &length); + know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know (length > 0); + if (err) + { + as_bad ("Bad floating literal: %s", err); + ignore_rest_of_line (); + return; + } + } + + if (!need_pass_2) + { + int count; + + count = 1; + +#ifdef REPEAT_CONS_EXPRESSIONS + if (*input_line_pointer == ':') + { + expressionS count_exp; + + ++input_line_pointer; + expression (&count_exp); + if (count_exp.X_op != O_constant + || count_exp.X_add_number <= 0) + { + as_warn ("unresolvable or nonpositive repeat count; using 1"); + } + else + count = count_exp.X_add_number; + } +#endif + + while (--count >= 0) + { + p = frag_more (length); + memcpy (p, temp, (unsigned int) length); + } + } + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; /* Put terminator back into stream. */ + demand_empty_rest_of_line (); +} /* float_cons() */ + +/* + * stringer() + * + * We read 0 or more ',' seperated, double-quoted strings. + * + * Caller should have checked need_pass_2 is FALSE because we don't check it. + */ + + +void +stringer (append_zero) /* Worker to do .ascii etc statements. */ + /* Checks end-of-line. */ + register int append_zero; /* 0: don't append '\0', else 1 */ +{ + register unsigned int c; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* + * The following awkward logic is to parse ZERO or more strings, + * comma seperated. Recall a string expression includes spaces + * before the opening '\"' and spaces after the closing '\"'. + * We fake a leading ',' if there is (supposed to be) + * a 1st, expression. We keep demanding expressions for each + * ','. + */ + if (is_it_end_of_statement ()) + { + c = 0; /* Skip loop. */ + ++input_line_pointer; /* Compensate for end of loop. */ + } + else + { + c = ','; /* Do loop. */ + } + while (c == ',' || c == '<' || c == '"') + { + SKIP_WHITESPACE (); + switch (*input_line_pointer) + { + case '\"': + ++input_line_pointer; /*->1st char of string. */ + while (is_a_char (c = next_char_of_string ())) + { + FRAG_APPEND_1_CHAR (c); + } + if (append_zero) + { + FRAG_APPEND_1_CHAR (0); + } + know (input_line_pointer[-1] == '\"'); + break; + case '<': + input_line_pointer++; + c = get_single_number (); + FRAG_APPEND_1_CHAR (c); + if (*input_line_pointer != '>') + { + as_bad ("Expected <nn>"); + } + input_line_pointer++; + break; + case ',': + input_line_pointer++; + break; + } + SKIP_WHITESPACE (); + c = *input_line_pointer; + } + + demand_empty_rest_of_line (); +} /* stringer() */ + +/* FIXME-SOMEDAY: I had trouble here on characters with the + high bits set. We'll probably also have trouble with + multibyte chars, wide chars, etc. Also be careful about + returning values bigger than 1 byte. xoxorich. */ + +unsigned int +next_char_of_string () +{ + register unsigned int c; + + c = *input_line_pointer++ & CHAR_MASK; + switch (c) + { + case '\"': + c = NOT_A_CHAR; + break; + + case '\n': + as_warn ("Unterminated string: Newline inserted."); + bump_line_counters (); + break; + +#ifndef NO_STRING_ESCAPES + case '\\': + switch (c = *input_line_pointer++) + { + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case 'v': + c = '\013'; + break; + + case '\\': + case '"': + break; /* As itself. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + long number; + int i; + + for (i = 0, number = 0; isdigit (c) && i < 3; c = *input_line_pointer++, i++) + { + number = number * 8 + c - '0'; + } + c = number & 0xff; + } + --input_line_pointer; + break; + + case 'x': + case 'X': + { + long number; + + number = 0; + c = *input_line_pointer++; + while (isxdigit (c)) + { + if (isdigit (c)) + number = number * 16 + c - '0'; + else if (isupper (c)) + number = number * 16 + c - 'A' + 10; + else + number = number * 16 + c - 'a' + 10; + c = *input_line_pointer++; + } + c = number & 0xff; + --input_line_pointer; + } + break; + + case '\n': + /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ + as_warn ("Unterminated string: Newline inserted."); + c = '\n'; + bump_line_counters (); + break; + + default: + +#ifdef ONLY_STANDARD_ESCAPES + as_bad ("Bad escaped character in string, '?' assumed"); + c = '?'; +#endif /* ONLY_STANDARD_ESCAPES */ + + break; + } /* switch on escaped char */ + break; +#endif /* ! defined (NO_STRING_ESCAPES) */ + + default: + break; + } /* switch on char */ + return (c); +} /* next_char_of_string() */ + +static segT +get_segmented_expression (expP) + register expressionS *expP; +{ + register segT retval; + + retval = expression (expP); + if (expP->X_op == O_illegal + || expP->X_op == O_absent + || expP->X_op == O_big) + { + as_bad ("expected address expression; zero assumed"); + expP->X_op = O_constant; + expP->X_add_number = 0; + retval = absolute_section; + } + return retval; +} + +static segT +get_known_segmented_expression (expP) + register expressionS *expP; +{ + register segT retval; + + if ((retval = get_segmented_expression (expP)) == undefined_section) + { + /* There is no easy way to extract the undefined symbol from the + expression. */ + if (expP->X_add_symbol != NULL + && S_GET_SEGMENT (expP->X_add_symbol) != expr_section) + as_warn ("symbol \"%s\" undefined; zero assumed", + S_GET_NAME (expP->X_add_symbol)); + else + as_warn ("some symbol undefined; zero assumed"); + retval = absolute_section; + expP->X_op = O_constant; + expP->X_add_number = 0; + } + know (retval == absolute_section || SEG_NORMAL (retval)); + return (retval); +} /* get_known_segmented_expression() */ + +offsetT +get_absolute_expression () +{ + expressionS exp; + + expression (&exp); + if (exp.X_op != O_constant) + { + if (exp.X_op != O_absent) + as_bad ("bad or irreducible absolute expression; zero assumed"); + exp.X_add_number = 0; + } + return exp.X_add_number; +} + +char /* return terminator */ +get_absolute_expression_and_terminator (val_pointer) + long *val_pointer; /* return value of expression */ +{ + /* FIXME: val_pointer should probably be offsetT *. */ + *val_pointer = (long) get_absolute_expression (); + return (*input_line_pointer++); +} + +/* + * demand_copy_C_string() + * + * Like demand_copy_string, but return NULL if the string contains any '\0's. + * Give a warning if that happens. + */ +char * +demand_copy_C_string (len_pointer) + int *len_pointer; +{ + register char *s; + + if ((s = demand_copy_string (len_pointer)) != 0) + { + register int len; + + for (len = *len_pointer; len > 0; len--) + { + if (*s == 0) + { + s = 0; + len = 1; + *len_pointer = 0; + as_bad ("This string may not contain \'\\0\'"); + } + } + } + return s; +} + +/* + * demand_copy_string() + * + * Demand string, but return a safe (=private) copy of the string. + * Return NULL if we can't read a string here. + */ +char * +demand_copy_string (lenP) + int *lenP; +{ + register unsigned int c; + register int len; + char *retval; + + len = 0; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\"') + { + input_line_pointer++; /* Skip opening quote. */ + + while (is_a_char (c = next_char_of_string ())) + { + obstack_1grow (¬es, c); + len++; + } + /* JF this next line is so demand_copy_C_string will return a + null terminated string. */ + obstack_1grow (¬es, '\0'); + retval = obstack_finish (¬es); + } + else + { + as_warn ("Missing string"); + retval = NULL; + ignore_rest_of_line (); + } + *lenP = len; + return (retval); +} /* demand_copy_string() */ + +/* + * is_it_end_of_statement() + * + * In: Input_line_pointer->next character. + * + * Do: Skip input_line_pointer over all whitespace. + * + * Out: 1 if input_line_pointer->end-of-line. +*/ +int +is_it_end_of_statement () +{ + SKIP_WHITESPACE (); + return (is_end_of_line[(unsigned char) *input_line_pointer]); +} /* is_it_end_of_statement() */ + +void +equals (sym_name, reassign) + char *sym_name; + int reassign; +{ + register symbolS *symbolP; /* symbol we are working with */ + char *stop; + char stopc; + + input_line_pointer++; + if (*input_line_pointer == '=') + input_line_pointer++; + + while (*input_line_pointer == ' ' || *input_line_pointer == '\t') + input_line_pointer++; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (sym_name[0] == '.' && sym_name[1] == '\0') + { + /* Turn '. = mumble' into a .org mumble */ + register segT segment; + expressionS exp; + + segment = get_known_segmented_expression (&exp); + if (!need_pass_2) + do_org (segment, &exp, 0); + } + else + { + symbolP = symbol_find_or_make (sym_name); + /* Permit register names to be redefined. */ + if (! reassign + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section) + as_bad ("symbol `%s' already defined", S_GET_NAME (symbolP)); + pseudo_set (symbolP); + } + + if (flag_mri) + mri_comment_end (stop, stopc); +} /* equals() */ + +/* .include -- include a file at this point. */ + +/* ARGSUSED */ +void +s_include (arg) + int arg; +{ + char *newbuf; + char *filename; + int i; + FILE *try; + char *path; + + if (! flag_m68k_mri) + filename = demand_copy_string (&i); + else + { + SKIP_WHITESPACE (); + i = 0; + while (! is_end_of_line[(unsigned char) *input_line_pointer] + && *input_line_pointer != ' ' + && *input_line_pointer != '\t') + { + obstack_1grow (¬es, *input_line_pointer); + ++input_line_pointer; + ++i; + } + obstack_1grow (¬es, '\0'); + filename = obstack_finish (¬es); + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + demand_empty_rest_of_line (); + path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ ); + for (i = 0; i < include_dir_count; i++) + { + strcpy (path, include_dirs[i]); + strcat (path, "/"); + strcat (path, filename); + if (0 != (try = fopen (path, "r"))) + { + fclose (try); + goto gotit; + } + } + free (path); + path = filename; +gotit: + /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */ + newbuf = input_scrub_include_file (path, input_line_pointer); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} /* s_include() */ + +void +add_include_dir (path) + char *path; +{ + int i; + + if (include_dir_count == 0) + { + include_dirs = (char **) xmalloc (2 * sizeof (*include_dirs)); + include_dirs[0] = "."; /* Current dir */ + include_dir_count = 2; + } + else + { + include_dir_count++; + include_dirs = (char **) realloc (include_dirs, + include_dir_count * sizeof (*include_dirs)); + } + + include_dirs[include_dir_count - 1] = path; /* New one */ + + i = strlen (path); + if (i > include_dir_maxlen) + include_dir_maxlen = i; +} /* add_include_dir() */ + +void +s_ignore (arg) + int arg; +{ + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + ++input_line_pointer; + } + ++input_line_pointer; +} + + +void +read_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "pseudo-op table", po_hash); +} + +/* end of read.c */ diff --git a/contrib/binutils/gas/read.h b/contrib/binutils/gas/read.h new file mode 100644 index 0000000..bd0aa78 --- /dev/null +++ b/contrib/binutils/gas/read.h @@ -0,0 +1,148 @@ +/* read.h - of read.c + Copyright (C) 1986, 90, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern char *input_line_pointer;/* -> char we are parsing now. */ + +#define PERMIT_WHITESPACE /* Define to make whitespace be allowed in */ +/* many syntactically unnecessary places. */ +/* Normally undefined. For compatibility */ +/* with ancient GNU cc. */ +/* #undef PERMIT_WHITESPACE */ + +#ifdef PERMIT_WHITESPACE +#define SKIP_WHITESPACE() {if (* input_line_pointer == ' ') ++ input_line_pointer;} +#else +#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' ) +#endif + + +#define LEX_NAME (1) /* may continue a name */ +#define LEX_BEGIN_NAME (2) /* may begin a name */ + +#define is_name_beginner(c) \ + ( lex_type[(unsigned char) (c)] & LEX_BEGIN_NAME ) +#define is_part_of_name(c) \ + ( lex_type[(unsigned char) (c)] & LEX_NAME ) + +#ifndef is_a_char +#define CHAR_MASK (0xff) +#define NOT_A_CHAR (CHAR_MASK+1) +#define is_a_char(c) (((unsigned)(c)) <= CHAR_MASK) +#endif /* is_a_char() */ + +extern char lex_type[]; +extern char is_end_of_line[]; + +extern int is_it_end_of_statement PARAMS ((void)); + +extern int target_big_endian; + +/* These are initialized by the CPU specific target files (tc-*.c). */ +extern const char comment_chars[]; +extern const char line_comment_chars[]; +extern const char line_separator_chars[]; + +/* This flag whether to generate line info for asm file */ +extern int generate_asm_lineno; + +/* The offset in the absolute section. */ +extern addressT abs_section_offset; + +/* The label on a line, used by some of the pseudo-ops. */ +extern symbolS *line_label; + +/* This is used to support MRI common sections. */ +extern symbolS *mri_common_symbol; + +/* Possible arguments to .linkonce. */ +enum linkonce_type +{ + LINKONCE_UNSET = 0, + LINKONCE_DISCARD, + LINKONCE_ONE_ONLY, + LINKONCE_SAME_SIZE, + LINKONCE_SAME_CONTENTS +}; + +extern void pop_insert PARAMS ((const pseudo_typeS *)); +extern unsigned int get_stab_string_offset + PARAMS ((const char *string, const char *stabstr_secname)); +extern char *demand_copy_C_string PARAMS ((int *len_pointer)); +extern char get_absolute_expression_and_terminator + PARAMS ((long *val_pointer)); +extern offsetT get_absolute_expression PARAMS ((void)); +extern unsigned int next_char_of_string PARAMS ((void)); +extern void s_mri_sect PARAMS ((char *)); +extern char *mri_comment_field PARAMS ((char *)); +extern void mri_comment_end PARAMS ((char *, int)); +extern void add_include_dir PARAMS ((char *path)); +extern void cons PARAMS ((int nbytes)); +extern void demand_empty_rest_of_line PARAMS ((void)); +extern void emit_expr PARAMS ((expressionS *exp, unsigned int nbytes)); +extern void equals PARAMS ((char *sym_name, int reassign)); +extern void float_cons PARAMS ((int float_type)); +extern void ignore_rest_of_line PARAMS ((void)); +extern void pseudo_set PARAMS ((symbolS * symbolP)); +extern void read_a_source_file PARAMS ((char *name)); +extern void read_begin PARAMS ((void)); +extern void s_abort PARAMS ((int)); +extern void s_align_bytes PARAMS ((int arg)); +extern void s_align_ptwo PARAMS ((int)); +extern void s_app_file PARAMS ((int)); +extern void s_app_line PARAMS ((int)); +extern void s_comm PARAMS ((int)); +extern void s_data PARAMS ((int)); +extern void s_desc PARAMS ((int)); +extern void s_else PARAMS ((int arg)); +extern void s_end PARAMS ((int arg)); +extern void s_endif PARAMS ((int arg)); +extern void s_err PARAMS ((int)); +extern void s_fail PARAMS ((int)); +extern void s_fill PARAMS ((int)); +extern void s_float_space PARAMS ((int mult)); +extern void s_globl PARAMS ((int arg)); +extern void s_if PARAMS ((int arg)); +extern void s_ifc PARAMS ((int arg)); +extern void s_ifdef PARAMS ((int arg)); +extern void s_ifeqs PARAMS ((int arg)); +extern void s_ignore PARAMS ((int arg)); +extern void s_include PARAMS ((int arg)); +extern void s_irp PARAMS ((int arg)); +extern void s_lcomm PARAMS ((int needs_align)); +extern void s_linkonce PARAMS ((int)); +extern void s_lsym PARAMS ((int)); +extern void s_macro PARAMS ((int)); +extern void s_mexit PARAMS ((int)); +extern void s_mri PARAMS ((int)); +extern void s_mri_common PARAMS ((int)); +extern void s_org PARAMS ((int)); +extern void s_print PARAMS ((int)); +extern void s_purgem PARAMS ((int)); +extern void s_rept PARAMS ((int)); +extern void s_set PARAMS ((int)); +extern void s_space PARAMS ((int mult)); +extern void s_stab PARAMS ((int what)); +extern void s_struct PARAMS ((int)); +extern void s_text PARAMS ((int)); +extern void stringer PARAMS ((int append_zero)); +extern void s_xstab PARAMS ((int what)); +extern void s_rva PARAMS ((int)); +extern void read_print_statistics PARAMS ((FILE *)); + +/* end of read.h */ diff --git a/contrib/binutils/gas/sb.c b/contrib/binutils/gas/sb.c new file mode 100644 index 0000000..6ec23fc --- /dev/null +++ b/contrib/binutils/gas/sb.c @@ -0,0 +1,289 @@ +/* sb.c - string buffer manipulation routines + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include <stdio.h> +#ifdef HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#include "libiberty.h" +#include "sb.h" + +/* These routines are about manipulating strings. + + They are managed in things called `sb's which is an abbreviation + for string buffers. An sb has to be created, things can be glued + on to it, and at the end of it's life it should be freed. The + contents should never be pointed at whilst it is still growing, + since it could be moved at any time + + eg: + sb_new (&foo); + sb_grow... (&foo,...); + use foo->ptr[*]; + sb_kill (&foo); + +*/ + +#define dsize 5 + +static void sb_check PARAMS ((sb *, int)); + +/* Statistics of sb structures. */ + +int string_count[sb_max_power_two]; + +/* Free list of sb structures. */ + +static sb_list_vector free_list; + +/* initializes an sb. */ + +void +sb_build (ptr, size) + sb *ptr; + int size; +{ + /* see if we can find one to allocate */ + sb_element *e; + + if (size > sb_max_power_two) + abort (); + + e = free_list.size[size]; + if (!e) + { + /* nothing there, allocate one and stick into the free list */ + e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size)); + e->next = free_list.size[size]; + e->size = 1 << size; + free_list.size[size] = e; + string_count[size]++; + } + + /* remove from free list */ + + free_list.size[size] = e->next; + + /* copy into callers world */ + ptr->ptr = e->data; + ptr->pot = size; + ptr->len = 0; + ptr->item = e; +} + + +void +sb_new (ptr) + sb *ptr; +{ + sb_build (ptr, dsize); +} + +/* deallocate the sb at ptr */ + +void +sb_kill (ptr) + sb *ptr; +{ + /* return item to free list */ + ptr->item->next = free_list.size[ptr->pot]; + free_list.size[ptr->pot] = ptr->item; +} + +/* add the sb at s to the end of the sb at ptr */ + +void +sb_add_sb (ptr, s) + sb *ptr; + sb *s; +{ + sb_check (ptr, s->len); + memcpy (ptr->ptr + ptr->len, s->ptr, s->len); + ptr->len += s->len; +} + +/* make sure that the sb at ptr has room for another len characters, + and grow it if it doesn't. */ + +static void +sb_check (ptr, len) + sb *ptr; + int len; +{ + if (ptr->len + len >= 1 << ptr->pot) + { + sb tmp; + int pot = ptr->pot; + while (ptr->len + len >= 1 << pot) + pot++; + sb_build (&tmp, pot); + sb_add_sb (&tmp, ptr); + sb_kill (ptr); + *ptr = tmp; + } +} + +/* make the sb at ptr point back to the beginning. */ + +void +sb_reset (ptr) + sb *ptr; +{ + ptr->len = 0; +} + +/* add character c to the end of the sb at ptr. */ + +void +sb_add_char (ptr, c) + sb *ptr; + int c; +{ + sb_check (ptr, 1); + ptr->ptr[ptr->len++] = c; +} + +/* add null terminated string s to the end of sb at ptr. */ + +void +sb_add_string (ptr, s) + sb *ptr; + const char *s; +{ + int len = strlen (s); + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* add string at s of length len to sb at ptr */ + +void +sb_add_buffer (ptr, s, len) + sb *ptr; + const char *s; + int len; +{ + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* print the sb at ptr to the output file */ + +void +sb_print (outfile, ptr) + FILE *outfile; + sb *ptr; +{ + int i; + int nc = 0; + + for (i = 0; i < ptr->len; i++) + { + if (nc) + { + fprintf (outfile, ","); + } + fprintf (outfile, "%d", ptr->ptr[i]); + nc = 1; + } +} + +void +sb_print_at (outfile, idx, ptr) + FILE *outfile; + int idx; + sb *ptr; +{ + int i; + for (i = idx; i < ptr->len; i++) + putc (ptr->ptr[i], outfile); +} + +/* put a null at the end of the sb at in and return the start of the + string, so that it can be used as an arg to printf %s. */ + +char * +sb_name (in) + sb *in; +{ + /* stick a null on the end of the string */ + sb_add_char (in, 0); + return in->ptr; +} + +/* like sb_name, but don't include the null byte in the string. */ + +char * +sb_terminate (in) + sb *in; +{ + sb_add_char (in, 0); + --in->len; + return in->ptr; +} + +/* start at the index idx into the string in sb at ptr and skip + whitespace. return the index of the first non whitespace character */ + +int +sb_skip_white (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + return idx; +} + +/* start at the index idx into the sb at ptr. skips whitespace, + a comma and any following whitespace. returnes the index of the + next character. */ + +int +sb_skip_comma (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + if (idx < ptr->len + && ptr->ptr[idx] == ',') + idx++; + + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + return idx; +} diff --git a/contrib/binutils/gas/sb.h b/contrib/binutils/gas/sb.h new file mode 100644 index 0000000..7e6daf1 --- /dev/null +++ b/contrib/binutils/gas/sb.h @@ -0,0 +1,99 @@ +/* sb.h - header file for string buffer manipulation routines + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef SB_H + +#define SB_H + +#include <stdio.h> +#include "ansidecl.h" + +/* string blocks + + I had a couple of choices when deciding upon this data structure. + gas uses null terminated strings for all its internal work. This + often means that parts of the program that want to examine + substrings have to manipulate the data in the string to do the + right thing (a common operation is to single out a bit of text by + saving away the character after it, nulling it out, operating on + the substring and then replacing the character which was under the + null). This is a pain and I remember a load of problems that I had with + code in gas which almost got this right. Also, it's harder to grow and + allocate null terminated strings efficiently. + + Obstacks provide all the functionality needed, but are too + complicated, hence the sb. + + An sb is allocated by the caller, and is initialzed to point to an + sb_element. sb_elements are kept on a free lists, and used when + needed, replaced onto the free list when unused. + */ + +#define sb_max_power_two 30 /* don't allow strings more than + 2^sb_max_power_two long */ +/* structure of an sb */ +typedef struct sb + { + char *ptr; /* points to the current block. */ + int len; /* how much is used. */ + int pot; /* the maximum length is 1<<pot */ + struct le *item; + } +sb; + +/* Structure of the free list object of an sb */ +typedef struct le + { + struct le *next; + int size; + char data[1]; + } +sb_element; + +/* The free list */ +typedef struct + { + sb_element *size[sb_max_power_two]; + } sb_list_vector; + +extern int string_count[sb_max_power_two]; + +extern void sb_build PARAMS ((sb *, int)); +extern void sb_new PARAMS ((sb *)); +extern void sb_kill PARAMS ((sb *)); +extern void sb_add_sb PARAMS ((sb *, sb *)); +extern void sb_reset PARAMS ((sb *)); +extern void sb_add_char PARAMS ((sb *, int)); +extern void sb_add_string PARAMS ((sb *, const char *)); +extern void sb_add_buffer PARAMS ((sb *, const char *, int)); +extern void sb_print PARAMS ((FILE *, sb *)); +extern void sb_print_at PARAMS ((FILE *, int, sb *)); +extern char *sb_name PARAMS ((sb *)); +extern char *sb_terminate PARAMS ((sb *)); +extern int sb_skip_white PARAMS ((int, sb *)); +extern int sb_skip_comma PARAMS ((int, sb *)); + +/* Actually in input-scrub.c. */ +extern void input_scrub_include_sb PARAMS ((sb *, char *)); + +#endif /* SB_H */ diff --git a/contrib/binutils/gas/stabs.c b/contrib/binutils/gas/stabs.c new file mode 100644 index 0000000..def437b --- /dev/null +++ b/contrib/binutils/gas/stabs.c @@ -0,0 +1,461 @@ +/* Generic stabs parsing for gas. + Copyright (C) 1989, 90, 91, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2, +or (at your option) any later version. + +GAS is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +the 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, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "as.h" +#include "obstack.h" +#include "subsegs.h" +#include "ecoff.h" + +/* We need this, despite the apparent object format dependency, since + it defines stab types, which all object formats can use now. */ + +#include "aout/stab_gnu.h" + +static void s_stab_generic PARAMS ((int, char *, char *)); + +/* Allow backends to override the names used for the stab sections. */ +#ifndef STAB_SECTION_NAME +#define STAB_SECTION_NAME ".stab" +#endif + +#ifndef STAB_STRING_SECTION_NAME +#define STAB_STRING_SECTION_NAME ".stabstr" +#endif + +/* + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + */ + +/* + * Build a string dictionary entry for a .stabX symbol. + * The symbol is added to the .<secname>str section. + */ + +#ifndef SEPARATE_STAB_SECTIONS +#define SEPARATE_STAB_SECTIONS 0 +#endif + +unsigned int +get_stab_string_offset (string, stabstr_secname) + const char *string; + const char *stabstr_secname; +{ + unsigned int length; + unsigned int retval; + + if (! SEPARATE_STAB_SECTIONS) + abort (); + + retval = 0; + length = strlen (string); + if (length > 0) + { /* Ordinary case. */ + segT save_seg; + subsegT save_subseg; + segT seg; + char *p; + + save_seg = now_seg; + save_subseg = now_subseg; + + /* Create the stab string section. */ + seg = subseg_new (stabstr_secname, 0); + + retval = seg_info (seg)->stabu.stab_string_size; + if (retval <= 0) + { + /* Make sure the first string is empty. */ + p = frag_more (1); + *p = 0; + retval = seg_info (seg)->stabu.stab_string_size = 1; +#ifdef BFD_ASSEMBLER + bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_DEBUGGING); + if (seg->name == stabstr_secname) + seg->name = xstrdup (stabstr_secname); +#endif + } + + p = frag_more (length + 1); + strcpy (p, string); + + seg_info (seg)->stabu.stab_string_size += length + 1; + + subseg_set (save_seg, save_subseg); + } + + return retval; +} + +#ifdef AOUT_STABS +#ifndef OBJ_PROCESS_STAB +#define OBJ_PROCESS_STAB(SEG,W,S,T,O,D) aout_process_stab(W,S,T,O,D) +#endif + +static void aout_process_stab PARAMS ((int, const char *, int, int, int)); + +static void +aout_process_stab (what, string, type, other, desc) + int what; + const char *string; + int type, other, desc; +{ + /* Put the stab information in the symbol table. */ + symbolS *symbol; + + /* Create the symbol now, but only insert it into the symbol chain + after any symbols mentioned in the value expression get into the + symbol chain. This is to avoid "continuation symbols" (where one + ends in "\" and the debug info is continued in the next .stabs + directive) from being separated by other random symbols. */ + symbol = symbol_create (string, undefined_section, 0, + (struct frag *) NULL); + if (what == 's' || what == 'n') + { + /* Pick up the value from the input line. */ + symbol->sy_frag = &zero_address_frag; + pseudo_set (symbol); + } + else + { + /* .stabd sets the name to NULL. Why? */ + S_SET_NAME (symbol, NULL); + symbol->sy_frag = frag_now; + S_SET_VALUE (symbol, (valueT) frag_now_fix ()); + } + + symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP); + + S_SET_TYPE (symbol, type); + S_SET_OTHER (symbol, other); + S_SET_DESC (symbol, desc); +} +#endif + +/* This can handle different kinds of stabs (s,n,d) and different + kinds of stab sections. */ + +static void +s_stab_generic (what, stab_secname, stabstr_secname) + int what; + char *stab_secname; + char *stabstr_secname; +{ + long longint; + char *string; + int type; + int other; + int desc; + + /* The general format is: + .stabs "STRING",TYPE,OTHER,DESC,VALUE + .stabn TYPE,OTHER,DESC,VALUE + .stabd TYPE,OTHER,DESC + At this point input_line_pointer points after the pseudo-op and + any trailing whitespace. The argument what is one of 's', 'n' or + 'd' indicating which type of .stab this is. */ + + if (what != 's') + string = ""; + else + { + int length; + + string = demand_copy_C_string (&length); + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_warn (".stabs: Missing comma"); + ignore_rest_of_line (); + return; + } + } + + if (get_absolute_expression_and_terminator (&longint) != ',') + { + as_warn (".stab%c: Missing comma", what); + ignore_rest_of_line (); + return; + } + type = longint; + + if (get_absolute_expression_and_terminator (&longint) != ',') + { + as_warn (".stab%c: Missing comma", what); + ignore_rest_of_line (); + return; + } + other = longint; + + desc = get_absolute_expression (); + if (what == 's' || what == 'n') + { + if (*input_line_pointer != ',') + { + as_warn (".stab%c: Missing comma", what); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + SKIP_WHITESPACE (); + } + +#ifdef TC_PPC +#ifdef OBJ_ELF + /* Solaris on PowerPC has decided that .stabd can take 4 arguments, so if we were + given 4 arguments, make it a .stabn */ + else if (what == 'd') + { + char *save_location = input_line_pointer; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + input_line_pointer++; + what = 'n'; + } + else + input_line_pointer = save_location; + } +#endif /* OBJ_ELF */ +#endif /* TC_PPC */ + +#ifndef NO_LISTING + if (listing) + { + switch (type) + { + case N_SLINE: + listing_source_line ((unsigned int) desc); + break; + case N_SO: + case N_SOL: + listing_source_file (string); + break; + } + } +#endif /* ! NO_LISTING */ + + /* We have now gathered the type, other, and desc information. For + .stabs or .stabn, input_line_pointer is now pointing at the + value. */ + + if (SEPARATE_STAB_SECTIONS) + /* Output the stab information in a separate section. This is used + at least for COFF and ELF. */ + { + segT saved_seg = now_seg; + subsegT saved_subseg = now_subseg; + fragS *saved_frag = frag_now; + valueT dot; + segT seg; + unsigned int stroff; + char *p; + + static segT cached_sec; + static char *cached_secname; + + dot = frag_now_fix (); + + if (cached_secname && !strcmp (cached_secname, stab_secname)) + { + seg = cached_sec; + subseg_set (seg, 0); + } + else + { + seg = subseg_new (stab_secname, 0); + if (cached_secname) + free (cached_secname); + cached_secname = xstrdup (stab_secname); + cached_sec = seg; + } + + if (! seg_info (seg)->hadone) + { +#ifdef BFD_ASSEMBLER + bfd_set_section_flags (stdoutput, seg, + SEC_READONLY | SEC_RELOC | SEC_DEBUGGING); +#endif +#ifdef INIT_STAB_SECTION + INIT_STAB_SECTION (seg); +#endif + seg_info (seg)->hadone = 1; + } + + stroff = get_stab_string_offset (string, stabstr_secname); + if (what == 's') + { + /* release the string */ + obstack_free (¬es, string); + } + + /* At least for now, stabs in a special stab section are always + output as 12 byte blocks of information. */ + p = frag_more (8); + md_number_to_chars (p, (valueT) stroff, 4); + md_number_to_chars (p + 4, (valueT) type, 1); + md_number_to_chars (p + 5, (valueT) other, 1); + md_number_to_chars (p + 6, (valueT) desc, 2); + + if (what == 's' || what == 'n') + { + /* Pick up the value from the input line. */ + cons (4); + input_line_pointer--; + } + else + { + const char *fake; + symbolS *symbol; + expressionS exp; + + /* Arrange for a value representing the current location. */ + fake = FAKE_LABEL_NAME; + symbol = symbol_new (fake, saved_seg, dot, saved_frag); + + exp.X_op = O_symbol; + exp.X_add_symbol = symbol; + exp.X_add_number = 0; + + emit_expr (&exp, 4); + } + +#ifdef OBJ_PROCESS_STAB + OBJ_PROCESS_STAB (seg, what, string, type, other, desc); +#endif + + subseg_set (saved_seg, saved_subseg); + } + else + { +#ifdef OBJ_PROCESS_STAB + OBJ_PROCESS_STAB (0, what, string, type, other, desc); +#else + abort (); +#endif + } + + demand_empty_rest_of_line (); +} + +/* Regular stab directive. */ + +void +s_stab (what) + int what; +{ + s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME); +} + +/* "Extended stabs", used in Solaris only now. */ + +void +s_xstab (what) + int what; +{ + int length; + char *stab_secname, *stabstr_secname; + static char *saved_secname, *saved_strsecname; + + /* @@ MEMORY LEAK: This allocates a copy of the string, but in most + cases it will be the same string, so we could release the storage + back to the obstack it came from. */ + stab_secname = demand_copy_C_string (&length); + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_bad ("comma missing in .xstabs"); + ignore_rest_of_line (); + return; + } + + /* To get the name of the stab string section, simply add "str" to + the stab section name. */ + if (saved_secname == 0 || strcmp (saved_secname, stab_secname)) + { + stabstr_secname = (char *) xmalloc (strlen (stab_secname) + 4); + strcpy (stabstr_secname, stab_secname); + strcat (stabstr_secname, "str"); + if (saved_secname) + { + free (saved_secname); + free (saved_strsecname); + } + saved_secname = stab_secname; + saved_strsecname = stabstr_secname; + } + s_stab_generic (what, saved_secname, saved_strsecname); +} + +#ifdef S_SET_DESC + +/* Frob invented at RMS' request. Set the n_desc of a symbol. */ + +void +s_desc (ignore) + int ignore; +{ + char *name; + char c; + char *p; + symbolS *symbolP; + int temp; + + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad ("Expected comma after name \"%s\"", name); + *p = c; + ignore_rest_of_line (); + } + else + { + input_line_pointer++; + temp = get_absolute_expression (); + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + S_SET_DESC (symbolP, temp); + } + demand_empty_rest_of_line (); +} /* s_desc() */ + +#endif /* defined (S_SET_DESC) */ diff --git a/contrib/binutils/gas/struc-symbol.h b/contrib/binutils/gas/struc-symbol.h new file mode 100644 index 0000000..0e60cb1 --- /dev/null +++ b/contrib/binutils/gas/struc-symbol.h @@ -0,0 +1,162 @@ +/* struct_symbol.h - Internal symbol structure + Copyright (C) 1987, 1992, 1993, 1994 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __struc_symbol_h__ +#define __struc_symbol_h__ + +#ifdef BFD_ASSEMBLER +/* The BFD code wants to walk the list in both directions. */ +#undef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS +#endif + +/* our version of an nlist node */ +struct symbol +{ +#ifndef BFD_ASSEMBLER + /* The (4-origin) position of sy_name in the symbol table of the object + file. This will be 0 for (nameless) .stabd symbols. + + Not used until write_object_file() time. */ + unsigned long sy_name_offset; + + /* What we write in .o file (if permitted). */ + obj_symbol_type sy_symbol; + + /* The 24 bit symbol number. Symbol numbers start at 0 and are unsigned. */ + long sy_number; +#else + /* BFD symbol */ + asymbol *bsym; +#endif + + /* The value of the symbol. */ + expressionS sy_value; + + /* Forwards and (optionally) backwards chain pointers. */ + struct symbol *sy_next; +#ifdef SYMBOLS_NEED_BACKPOINTERS + struct symbol *sy_previous; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + + /* Pointer to the frag this symbol is attached to, if any. + Otherwise, NULL. */ + struct frag *sy_frag; + + unsigned int written : 1; + /* Whether symbol value has been completely resolved (used during + final pass over symbol table). */ + unsigned int sy_resolved : 1; + /* Whether the symbol value is currently being resolved (used to + detect loops in symbol dependencies). */ + unsigned int sy_resolving : 1; + /* Whether the symbol value is used in a reloc. This is used to + ensure that symbols used in relocs are written out, even if they + are local and would otherwise not be. */ + unsigned int sy_used_in_reloc : 1; + + /* Whether the symbol is used as an operand or in an expression. + NOTE: Not all the backends keep this information accurate; + backends which use this bit are responsible for setting it when + a symbol is used in backend routines. */ + unsigned int sy_used : 1; + + /* This is set if the symbol is defined in an MRI common section. + We handle such sections as single common symbols, so symbols + defined within them must be treated specially by the relocation + routines. */ + unsigned int sy_mri_common : 1; + +#ifdef OBJ_SYMFIELD_TYPE + OBJ_SYMFIELD_TYPE sy_obj; +#endif + +#ifdef TC_SYMFIELD_TYPE + TC_SYMFIELD_TYPE sy_tc; +#endif + +#ifdef TARGET_SYMBOL_FIELDS + TARGET_SYMBOL_FIELDS +#endif +}; + +typedef struct symbol symbolS; + +#ifndef WORKING_DOT_WORD +struct broken_word + { + /* Linked list -- one of these structures per ".word x-y+C" + expression. */ + struct broken_word *next_broken_word; + /* Which frag is this broken word in? */ + fragS *frag; + /* Where in the frag is it? */ + char *word_goes_here; + /* Where to add the break. */ + fragS *dispfrag; /* where to add the break */ + /* Operands of expression. */ + symbolS *add; + symbolS *sub; + offsetT addnum; + + int added; /* nasty thing happend yet? */ + /* 1: added and has a long-jump */ + /* 2: added but uses someone elses long-jump */ + + /* Pointer to broken_word with a similar long-jump. */ + struct broken_word *use_jump; + }; +extern struct broken_word *broken_words; +#endif /* ndef WORKING_DOT_WORD */ + +/* + * Current means for getting from symbols to segments and vice verse. + * This will change for infinite-segments support (e.g. COFF). + */ +extern const segT N_TYPE_seg[]; /* subseg.c */ + +#define SEGMENT_TO_SYMBOL_TYPE(seg) ( seg_N_TYPE [(int) (seg)] ) +extern const short seg_N_TYPE[];/* subseg.c */ + +#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */ + +void symbol_clear_list_pointers PARAMS ((symbolS * symbolP)); + +#ifdef SYMBOLS_NEED_BACKPOINTERS + +void symbol_insert PARAMS ((symbolS * addme, symbolS * target, + symbolS ** rootP, symbolS ** lastP)); +void symbol_remove PARAMS ((symbolS * symbolP, symbolS ** rootP, + symbolS ** lastP)); + +#define symbol_previous(s) ((s)->sy_previous) + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +void verify_symbol_chain PARAMS ((symbolS * rootP, symbolS * lastP)); +void verify_symbol_chain_2 PARAMS ((symbolS * symP)); + +void symbol_append PARAMS ((symbolS * addme, symbolS * target, + symbolS ** rootP, symbolS ** lastP)); + +#define symbol_next(s) ((s)->sy_next) + +#endif /* __struc_symbol_h__ */ + +/* end of struc-symbol.h */ diff --git a/contrib/binutils/gas/subsegs.c b/contrib/binutils/gas/subsegs.c new file mode 100644 index 0000000..2d5b1f7 --- /dev/null +++ b/contrib/binutils/gas/subsegs.c @@ -0,0 +1,593 @@ +/* subsegs.c - subsegments - + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * Segments & sub-segments. + */ + +#include "as.h" + +#include "subsegs.h" +#include "obstack.h" + +frchainS *frchain_root, *frchain_now; + +static struct obstack frchains; + +#ifndef BFD_ASSEMBLER +#ifdef MANY_SEGMENTS +segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; + +#else +/* Commented in "subsegs.h". */ +frchainS *data0_frchainP, *bss0_frchainP; + +#endif /* MANY_SEGMENTS */ +char const *const seg_name[] = +{ + "absolute", +#ifdef MANY_SEGMENTS + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", + "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19", + "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29", + "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39", +#else + "text", + "data", + "bss", +#endif /* MANY_SEGMENTS */ + "unknown", + "ASSEMBLER-INTERNAL-LOGIC-ERROR!", + "expr", + "debug", + "transfert vector preload", + "transfert vector postload", + "register", + "", +}; /* Used by error reporters, dumpers etc. */ +#else /* BFD_ASSEMBLER */ + +/* Gas segment information for bfd_abs_section_ptr and + bfd_und_section_ptr. */ +static segment_info_type *abs_seg_info; +static segment_info_type *und_seg_info; + +#endif /* BFD_ASSEMBLER */ + +static void subseg_set_rest PARAMS ((segT, subsegT)); + +static fragS dummy_frag; + +static frchainS absolute_frchain; + +void +subsegs_begin () +{ + /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know (SEG_ABSOLUTE == 0); + know (SEG_TEXT == 1); + know (SEG_DATA == 2); + know (SEG_BSS == 3); + know (SEG_UNKNOWN == 4); + know (SEG_GOOF == 5); + know (SEG_EXPR == 6); + know (SEG_DEBUG == 7); + know (SEG_NTV == 8); + know (SEG_PTV == 9); + know (SEG_REGISTER == 10); + know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER); +#endif + + obstack_begin (&frchains, chunksize); +#if __GNUC__ >= 2 + obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1; +#endif + + frchain_root = NULL; + frchain_now = NULL; /* Warn new_subseg() that we are booting. */ + + frag_now = &dummy_frag; + +#ifndef BFD_ASSEMBLER + now_subseg = 42; /* Lie for 1st call to subseg_new. */ +#ifdef MANY_SEGMENTS + { + int i; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + subseg_set (i, 0); + segment_info[i].frchainP = frchain_now; + } + } +#else + subseg_set (SEG_DATA, 0); /* .data 0 */ + data0_frchainP = frchain_now; + + subseg_set (SEG_BSS, 0); + bss0_frchainP = frchain_now; + +#endif /* ! MANY_SEGMENTS */ +#endif /* ! BFD_ASSEMBLER */ + + absolute_frchain.frch_seg = absolute_section; + absolute_frchain.frch_subseg = 0; +#ifdef BFD_ASSEMBLER + absolute_frchain.fix_root = absolute_frchain.fix_tail = 0; +#endif + absolute_frchain.frch_frag_now = &zero_address_frag; + absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag; +} + +/* + * subseg_change() + * + * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the + * subsegment. If we are already in the correct subsegment, change nothing. + * This is used eg as a worker for subseg_set [which does make a new frag_now] + * and for changing segments after we have read the source. We construct eg + * fixSs even after the source file is read, so we do have to keep the + * segment context correct. + */ +void +subseg_change (seg, subseg) + register segT seg; + register int subseg; +{ + now_seg = seg; + now_subseg = subseg; + + if (now_seg == absolute_section) + return; + +#ifdef BFD_ASSEMBLER + { + segment_info_type *seginfo; + seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg); + if (! seginfo) + { + seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); + memset ((PTR) seginfo, 0, sizeof (*seginfo)); + seginfo->fix_root = NULL; + seginfo->fix_tail = NULL; + seginfo->bfd_section = seg; + seginfo->sym = 0; + if (seg == bfd_abs_section_ptr) + abs_seg_info = seginfo; + else if (seg == bfd_und_section_ptr) + und_seg_info = seginfo; + else + bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo); + } + } +#else +#ifdef MANY_SEGMENTS + seg_fix_rootP = &segment_info[seg].fix_root; + seg_fix_tailP = &segment_info[seg].fix_tail; +#else + if (seg == SEG_DATA) + { + seg_fix_rootP = &data_fix_root; + seg_fix_tailP = &data_fix_tail; + } + else if (seg == SEG_TEXT) + { + seg_fix_rootP = &text_fix_root; + seg_fix_tailP = &text_fix_tail; + } + else + { + know (seg == SEG_BSS); + seg_fix_rootP = &bss_fix_root; + seg_fix_tailP = &bss_fix_tail; + } + +#endif +#endif +} + +static void +subseg_set_rest (seg, subseg) + segT seg; + subsegT subseg; +{ + register frchainS *frcP; /* crawl frchain chain */ + register frchainS **lastPP; /* address of last pointer */ + frchainS *newP; /* address of new frchain */ + + mri_common_symbol = NULL; + + if (frag_now && frchain_now) + frchain_now->frch_frag_now = frag_now; + + assert (frchain_now == 0 + || now_seg == undefined_section + || now_seg == absolute_section + || frchain_now->frch_last == frag_now); + + subseg_change (seg, (int) subseg); + + if (seg == absolute_section) + { + frchain_now = &absolute_frchain; + frag_now = &zero_address_frag; + return; + } + + assert (frchain_now == 0 + || now_seg == undefined_section + || frchain_now->frch_last == frag_now); + + /* + * Attempt to find or make a frchain for that sub seg. + * Crawl along chain of frchainSs, begins @ frchain_root. + * If we need to make a frchainS, link it into correct + * position of chain rooted in frchain_root. + */ + for (frcP = *(lastPP = &frchain_root); + frcP && frcP->frch_seg <= seg; + frcP = *(lastPP = &frcP->frch_next)) + { + if (frcP->frch_seg == seg + && frcP->frch_subseg >= subseg) + { + break; + } + } + /* + * frcP: Address of the 1st frchainS in correct segment with + * frch_subseg >= subseg. + * We want to either use this frchainS, or we want + * to insert a new frchainS just before it. + * + * If frcP==NULL, then we are at the end of the chain + * of frchainS-s. A NULL frcP means we fell off the end + * of the chain looking for a + * frch_subseg >= subseg, so we + * must make a new frchainS. + * + * If we ever maintain a pointer to + * the last frchainS in the chain, we change that pointer + * ONLY when frcP==NULL. + * + * lastPP: Address of the pointer with value frcP; + * Never NULL. + * May point to frchain_root. + * + */ + if (!frcP + || (frcP->frch_seg > seg + || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ + { + /* + * This should be the only code that creates a frchainS. + */ + newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS)); + newP->frch_subseg = subseg; + newP->frch_seg = seg; +#ifdef BFD_ASSEMBLER + newP->fix_root = NULL; + newP->fix_tail = NULL; +#endif + obstack_begin (&newP->frch_obstack, 5000); +#if __GNUC__ >= 2 + obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1; +#endif + newP->frch_frag_now = frag_alloc (&newP->frch_obstack); + newP->frch_frag_now->fr_type = rs_fill; + + newP->frch_root = newP->frch_last = newP->frch_frag_now; + + *lastPP = newP; + newP->frch_next = frcP; /* perhaps NULL */ + frcP = newP; + } + /* + * Here with frcP pointing to the frchainS for subseg. + */ + frchain_now = frcP; + frag_now = frcP->frch_frag_now; + + assert (frchain_now->frch_last == frag_now); +} + +/* + * subseg_set(segT, subsegT) + * + * If you attempt to change to the current subsegment, nothing happens. + * + * In: segT, subsegT code for new subsegment. + * frag_now -> incomplete frag for current subsegment. + * If frag_now==NULL, then there is no old, incomplete frag, so + * the old frag is not closed off. + * + * Out: now_subseg, now_seg updated. + * Frchain_now points to the (possibly new) struct frchain for this + * sub-segment. + * Frchain_root updated if needed. + */ + +#ifndef BFD_ASSEMBLER + +segT +subseg_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + int i; + + for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++) + { + const char *s; + + s = segment_name ((segT) i); + if (strcmp (segname, s) == 0 + || (segname[0] == '.' + && strcmp (segname + 1, s) == 0)) + { + subseg_set ((segT) i, subseg); + return (segT) i; + } +#ifdef obj_segment_name + s = obj_segment_name ((segT) i); + if (strcmp (segname, s) == 0 + || (segname[0] == '.' + && strcmp (segname + 1, s) == 0)) + { + subseg_set ((segT) i, subseg); + return (segT) i; + } +#endif + } + +#ifdef obj_add_segment + { + segT new_seg; + new_seg = obj_add_segment (segname); + subseg_set (new_seg, subseg); + return new_seg; + } +#else + as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname); + return now_seg; +#endif +} + +void +subseg_set (seg, subseg) /* begin assembly for a new sub-segment */ + register segT seg; /* SEG_DATA or SEG_TEXT */ + register subsegT subseg; +{ +#ifndef MANY_SEGMENTS + know (seg == SEG_DATA + || seg == SEG_TEXT + || seg == SEG_BSS + || seg == SEG_ABSOLUTE); +#endif + + if (seg != now_seg || subseg != now_subseg) + { /* we just changed sub-segments */ + subseg_set_rest (seg, subseg); + } + mri_common_symbol = NULL; +} + +#else /* BFD_ASSEMBLER */ + +segT +subseg_get (segname, force_new) + const char *segname; + int force_new; +{ + segT secptr; + segment_info_type *seginfo; + const char *now_seg_name = (now_seg + ? bfd_get_section_name (stdoutput, now_seg) + : 0); + + if (!force_new + && now_seg_name + && (now_seg_name == segname + || !strcmp (now_seg_name, segname))) + return now_seg; + + if (!force_new) + secptr = bfd_make_section_old_way (stdoutput, segname); + else + secptr = bfd_make_section_anyway (stdoutput, segname); + + seginfo = seg_info (secptr); + if (! seginfo) + { + /* Check whether output_section is set first because secptr may + be bfd_abs_section_ptr. */ + if (secptr->output_section != secptr) + secptr->output_section = secptr; + seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); + memset ((PTR) seginfo, 0, sizeof (*seginfo)); + seginfo->fix_root = NULL; + seginfo->fix_tail = NULL; + seginfo->bfd_section = secptr; + if (secptr == bfd_abs_section_ptr) + abs_seg_info = seginfo; + else if (secptr == bfd_und_section_ptr) + und_seg_info = seginfo; + else + bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo); + seginfo->frchainP = NULL; + seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL; + seginfo->sym = NULL; + seginfo->dot = NULL; + } + return secptr; +} + +segT +subseg_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + segT secptr; + segment_info_type *seginfo; + + secptr = subseg_get (segname, 0); + subseg_set_rest (secptr, subseg); + seginfo = seg_info (secptr); + if (! seginfo->frchainP) + seginfo->frchainP = frchain_now; + return secptr; +} + +/* Like subseg_new, except a new section is always created, even if + a section with that name already exists. */ +segT +subseg_force_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + segT secptr; + segment_info_type *seginfo; + + secptr = subseg_get (segname, 1); + subseg_set_rest (secptr, subseg); + seginfo = seg_info (secptr); + if (! seginfo->frchainP) + seginfo->frchainP = frchain_now; + return secptr; +} + +void +subseg_set (secptr, subseg) + segT secptr; + subsegT subseg; +{ + if (! (secptr == now_seg && subseg == now_subseg)) + subseg_set_rest (secptr, subseg); + mri_common_symbol = NULL; +} + +#ifndef obj_sec_sym_ok_for_reloc +#define obj_sec_sym_ok_for_reloc(SEC) 0 +#endif + +/* Get the gas information we are storing for a section. */ + +segment_info_type * +seg_info (sec) + segT sec; +{ + if (sec == bfd_abs_section_ptr) + return abs_seg_info; + else if (sec == bfd_und_section_ptr) + return und_seg_info; + else + return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec); +} + +symbolS * +section_symbol (sec) + segT sec; +{ + segment_info_type *seginfo = seg_info (sec); + symbolS *s; + + if (seginfo == 0) + abort (); + if (seginfo->sym) + return seginfo->sym; + +#ifndef EMIT_SECTION_SYMBOLS +#define EMIT_SECTION_SYMBOLS 1 +#endif + + if (! EMIT_SECTION_SYMBOLS +#ifdef BFD_ASSEMBLER + || symbol_table_frozen +#endif + ) + /* Here we know it won't be going into the symbol table. */ + s = symbol_create (sec->name, sec, 0, &zero_address_frag); + else + s = symbol_new (sec->name, sec, 0, &zero_address_frag); + S_CLEAR_EXTERNAL (s); + + /* Use the BFD section symbol, if possible. */ + if (obj_sec_sym_ok_for_reloc (sec)) + s->bsym = sec->symbol; + + seginfo->sym = s; + return s; +} + +#endif /* BFD_ASSEMBLER */ + +void +subsegs_print_statistics (file) + FILE *file; +{ + frchainS *frchp; + fprintf (file, "frag chains:\n"); + for (frchp = frchain_root; frchp; frchp = frchp->frch_next) + { + int count = 0; + fragS *fragp; + + /* If frch_subseg is non-zero, it's probably been chained onto + the end of a previous subsection. Don't count it again. */ + if (frchp->frch_subseg != 0) + continue; + + /* Skip gas-internal sections. */ + if (segment_name (frchp->frch_seg)[0] == '*') + continue; + + for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) + { +#if 0 + switch (fragp->fr_type) + { + case rs_fill: + fprintf (file, "f"); break; + case rs_align: + fprintf (file, "a"); break; + case rs_align_code: + fprintf (file, "c"); break; + case rs_org: + fprintf (file, "o"); break; + case rs_machine_dependent: + fprintf (file, "m"); break; + case rs_space: + fprintf (file, "s"); break; + case 0: + fprintf (file, "0"); break; + default: + fprintf (file, "?"); break; + } +#endif + count++; + } + fprintf (file, "\n"); + fprintf (file, "\t%p %-10s\t%10d frags\n", frchp, + segment_name (frchp->frch_seg), count); + } +} + +/* end of subsegs.c */ diff --git a/contrib/binutils/gas/subsegs.h b/contrib/binutils/gas/subsegs.h new file mode 100644 index 0000000..4c8605f --- /dev/null +++ b/contrib/binutils/gas/subsegs.h @@ -0,0 +1,158 @@ +/* subsegs.h -> subsegs.c + Copyright (C) 1987, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * For every sub-segment the user mentions in the ASsembler program, + * we make one struct frchain. Each sub-segment has exactly one struct frchain + * and vice versa. + * + * Struct frchain's are forward chained (in ascending order of sub-segment + * code number). The chain runs through frch_next of each subsegment. + * This makes it hard to find a subsegment's frags + * if programmer uses a lot of them. Most programs only use text0 and + * data0, so they don't suffer. At least this way: + * (1) There are no "arbitrary" restrictions on how many subsegments + * can be programmed; + * (2) Subsegments' frchain-s are (later) chained together in the order in + * which they are emitted for object file viz text then data. + * + * From each struct frchain dangles a chain of struct frags. The frags + * represent code fragments, for that sub-segment, forward chained. + */ + +#include "obstack.h" + +struct frchain /* control building of a frag chain */ +{ /* FRCH = FRagment CHain control */ + struct frag *frch_root; /* 1st struct frag in chain, or NULL */ + struct frag *frch_last; /* last struct frag in chain, or NULL */ + struct frchain *frch_next; /* next in chain of struct frchain-s */ + segT frch_seg; /* SEG_TEXT or SEG_DATA. */ + subsegT frch_subseg; /* subsegment number of this chain */ +#ifdef BFD_ASSEMBLER + fixS *fix_root; /* Root of fixups for this subsegment. */ + fixS *fix_tail; /* Last fixup for this subsegment. */ +#endif + struct obstack frch_obstack; /* for objects in this frag chain */ + fragS *frch_frag_now; /* frag_now for this subsegment */ +}; + +typedef struct frchain frchainS; + +/* All subsegments' chains hang off here. NULL means no frchains yet. */ +extern frchainS *frchain_root; + +/* Frchain we are assembling into now. That is, the current segment's + frag chain, even if it contains no (complete) frags. */ +extern frchainS *frchain_now; + + +typedef struct +{ + frchainS *frchainP; + unsigned int hadone : 1; + + /* This field is set if this is a .bss section which does not really + have any contents. Once upon a time a .bss section did not have + any frags, but that is no longer true. This field prevent the + SEC_HAS_CONTENTS flag from being set for the section even if + there are frags. */ + unsigned int bss : 1; + + int user_stuff; + + /* Fixups for this segment. If BFD_ASSEMBLER, this is only valid + after the frchains are run together. */ + fixS *fix_root; + fixS *fix_tail; + +#if defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + struct internal_scnhdr scnhdr; + enum linkonce_type linkonce; + const char *name; +#endif + + symbolS *dot; + + struct lineno_list *lineno_list_head; + struct lineno_list *lineno_list_tail; + +#ifdef BFD_ASSEMBLER + /* Which BFD section does this gas segment correspond to? */ + asection *bfd_section; + + /* NULL, or pointer to the gas symbol that is the section symbol for + this section. sym->bsym and bfd_section->symbol should be the same. */ + symbolS *sym; +#endif + + union + { + /* Current size of section holding stabs strings. */ + unsigned long stab_string_size; + /* Initial frag for ELF. */ + char *p; + } + stabu; + +#ifdef NEED_LITERAL_POOL + unsigned long literal_pool_size; +#endif + +#ifdef TC_SEGMENT_INFO_TYPE + TC_SEGMENT_INFO_TYPE tc_segment_info_data; +#endif +} segment_info_type; + +#ifdef BFD_ASSEMBLER + +extern segment_info_type *seg_info PARAMS ((segT)); +extern symbolS *section_symbol PARAMS ((segT)); + +#else /* ! BFD_ASSEMBLER */ + +#ifdef MANY_SEGMENTS + +extern segment_info_type segment_info[]; + +#define seg_info(SEC) (&segment_info[SEC]) + +#else + +/* Sentinel for frchain crawling. Points to the 1st data-segment + frchain. (Which is pointed to by the last text-segment frchain.) */ +extern frchainS *data0_frchainP; +extern frchainS *bss0_frchainP; + +/* Dummy so stuff can compile. Should never be used. */ +struct seg_info_trash { + struct { + unsigned stab_string_size : 1; + } stabu; + unsigned hadone : 1; +}; +#define seg_info(S) (abort (), (struct seg_info_trash *) 0) + +#endif + +#endif /* ! BFD_ASSEMBLER */ + +extern void subsegs_print_statistics PARAMS ((FILE *)); + +/* end of subsegs.h */ diff --git a/contrib/binutils/gas/symbols.c b/contrib/binutils/gas/symbols.c new file mode 100644 index 0000000..e1c30d6 --- /dev/null +++ b/contrib/binutils/gas/symbols.c @@ -0,0 +1,1684 @@ +/* symbols.c -symbol table- + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* #define DEBUG_SYMS / * to debug symbol list maintenance */ + +#include <ctype.h> + +#include "as.h" + +#include "obstack.h" /* For "symbols.h" */ +#include "subsegs.h" + +/* This is non-zero if symbols are case sensitive, which is the + default. */ +int symbols_case_sensitive = 1; + +#ifndef WORKING_DOT_WORD +extern int new_broken_words; +#endif + +/* symbol-name => struct symbol pointer */ +static struct hash_control *sy_hash; + +/* Below are commented in "symbols.h". */ +symbolS *symbol_rootP; +symbolS *symbol_lastP; +symbolS abs_symbol; + +#ifdef DEBUG_SYMS +#define debug_verify_symchain verify_symbol_chain +#else +#define debug_verify_symchain(root, last) ((void) 0) +#endif + +struct obstack notes; + +static void fb_label_init PARAMS ((void)); +static long dollar_label_instance PARAMS ((long)); +static long fb_label_instance PARAMS ((long)); + +/* symbol_new() + + Return a pointer to a new symbol. Die if we can't make a new + symbol. Fill in the symbol's values. Add symbol to end of symbol + chain. + + This function should be called in the general case of creating a + symbol. However, if the output file symbol table has already been + set, and you are certain that this symbol won't be wanted in the + output file, you can call symbol_create. */ + +symbolS * +symbol_new (name, segment, valu, frag) + const char *name; + segT segment; + valueT valu; + fragS *frag; +{ + symbolS *symbolP = symbol_create (name, segment, valu, frag); + + /* + * Link to end of symbol chain. + */ +#ifdef BFD_ASSEMBLER + { + extern int symbol_table_frozen; + if (symbol_table_frozen) + abort (); + } +#endif + symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); + + return symbolP; +} + +symbolS * +symbol_create (name, segment, valu, frag) + const char *name; /* It is copied, the caller can destroy/modify */ + segT segment; /* Segment identifier (SEG_<something>) */ + valueT valu; /* Symbol value */ + fragS *frag; /* Associated fragment */ +{ + unsigned int name_length; + char *preserved_copy_of_name; + symbolS *symbolP; + + name_length = strlen (name) + 1; /* +1 for \0 */ + obstack_grow (¬es, name, name_length); + preserved_copy_of_name = obstack_finish (¬es); +#ifdef STRIP_UNDERSCORE + if (preserved_copy_of_name[0] == '_') + preserved_copy_of_name++; +#endif + +#ifdef tc_canonicalize_symbol_name + preserved_copy_of_name = + tc_canonicalize_symbol_name (preserved_copy_of_name); +#endif + + if (! symbols_case_sensitive) + { + unsigned char *s; + + for (s = (unsigned char *) preserved_copy_of_name; *s != '\0'; s++) + if (islower (*s)) + *s = toupper (*s); + } + + symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS)); + + /* symbol must be born in some fixed state. This seems as good as any. */ + memset (symbolP, 0, sizeof (symbolS)); + +#ifdef BFD_ASSEMBLER + symbolP->bsym = bfd_make_empty_symbol (stdoutput); + if (symbolP->bsym == NULL) + as_perror ("%s", "bfd_make_empty_symbol"); + symbolP->bsym->udata.p = (PTR) symbolP; +#endif + S_SET_NAME (symbolP, preserved_copy_of_name); + + S_SET_SEGMENT (symbolP, segment); + S_SET_VALUE (symbolP, valu); + symbol_clear_list_pointers (symbolP); + + symbolP->sy_frag = frag; +#ifndef BFD_ASSEMBLER + symbolP->sy_number = ~0; + symbolP->sy_name_offset = (unsigned int) ~0; +#endif + + obj_symbol_new_hook (symbolP); + +#ifdef tc_symbol_new_hook + tc_symbol_new_hook (symbolP); +#endif + + return symbolP; +} + + +/* + * colon() + * + * We have just seen "<name>:". + * Creates a struct symbol unless it already exists. + * + * Gripes if we are redefining a symbol incompatibly (and ignores it). + * + */ +symbolS * +colon (sym_name) /* just seen "x:" - rattle symbols & frags */ + const char *sym_name; /* symbol name, as a cannonical string */ + /* We copy this string: OK to alter later. */ +{ + register symbolS *symbolP; /* symbol we are working with */ + + /* Sun local labels go out of scope whenever a non-local symbol is + defined. */ + if (LOCAL_LABELS_DOLLAR) + { + int local; + +#ifdef BFD_ASSEMBLER + local = bfd_is_local_label_name (stdoutput, sym_name); +#else + local = LOCAL_LABEL (sym_name); +#endif + + if (! local) + dollar_label_clear (); + } + +#ifndef WORKING_DOT_WORD + if (new_broken_words) + { + struct broken_word *a; + int possible_bytes; + fragS *frag_tmp; + char *frag_opcode; + + extern const int md_short_jump_size; + extern const int md_long_jump_size; + possible_bytes = (md_short_jump_size + + new_broken_words * md_long_jump_size); + + frag_tmp = frag_now; + frag_opcode = frag_var (rs_broken_word, + possible_bytes, + possible_bytes, + (relax_substateT) 0, + (symbolS *) broken_words, + (offsetT) 0, + NULL); + + /* We want to store the pointer to where to insert the jump table in the + fr_opcode of the rs_broken_word frag. This requires a little + hackery. */ + while (frag_tmp + && (frag_tmp->fr_type != rs_broken_word + || frag_tmp->fr_opcode)) + frag_tmp = frag_tmp->fr_next; + know (frag_tmp); + frag_tmp->fr_opcode = frag_opcode; + new_broken_words = 0; + + for (a = broken_words; a && a->dispfrag == 0; a = a->next_broken_word) + a->dispfrag = frag_tmp; + } +#endif /* WORKING_DOT_WORD */ + + if ((symbolP = symbol_find (sym_name)) != 0) + { +#ifdef RESOLVE_SYMBOL_REDEFINITION + if (RESOLVE_SYMBOL_REDEFINITION (symbolP)) + return symbolP; +#endif + /* + * Now check for undefined symbols + */ + if (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP)) + { + if (S_GET_VALUE (symbolP) == 0) + { + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_SET_OTHER(symbolP, const_flag); +#endif + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + S_SET_SEGMENT (symbolP, now_seg); +#ifdef N_UNDF + know (N_UNDF == 0); +#endif /* if we have one, it better be zero. */ + + } + else + { + /* + * There are still several cases to check: + * A .comm/.lcomm symbol being redefined as + * initialized data is OK + * A .comm/.lcomm symbol being redefined with + * a larger size is also OK + * + * This only used to be allowed on VMS gas, but Sun cc + * on the sparc also depends on it. + */ + + if (((!S_IS_DEBUG (symbolP) + && (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP)) + && S_IS_EXTERNAL (symbolP)) + || S_GET_SEGMENT (symbolP) == bss_section) + && (now_seg == data_section + || now_seg == S_GET_SEGMENT (symbolP))) + { + /* + * Select which of the 2 cases this is + */ + if (now_seg != data_section) + { + /* + * New .comm for prev .comm symbol. + * If the new size is larger we just + * change its value. If the new size + * is smaller, we ignore this symbol + */ + if (S_GET_VALUE (symbolP) + < ((unsigned) frag_now_fix ())) + { + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + } + } + else + { + /* It is a .comm/.lcomm being converted to initialized + data. */ + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_SET_OTHER(symbolP, const_flag); +#endif + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + S_SET_SEGMENT (symbolP, now_seg); /* keep N_EXT bit */ + } + } + else + { +#if defined (S_GET_OTHER) && defined (S_GET_DESC) + as_fatal ("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%ld.", + sym_name, + segment_name (S_GET_SEGMENT (symbolP)), + S_GET_OTHER (symbolP), S_GET_DESC (symbolP), + (long) S_GET_VALUE (symbolP)); +#else + as_fatal ("Symbol \"%s\" is already defined as \"%s\"/%ld.", + sym_name, + segment_name (S_GET_SEGMENT (symbolP)), + (long) S_GET_VALUE (symbolP)); +#endif + } + } /* if the undefined symbol has no value */ + } + else + { + /* Don't blow up if the definition is the same */ + if (!(frag_now == symbolP->sy_frag + && S_GET_VALUE (symbolP) == frag_now_fix () + && S_GET_SEGMENT (symbolP) == now_seg)) + as_fatal ("Symbol %s already defined.", sym_name); + } /* if this symbol is not yet defined */ + + } + else + { + symbolP = symbol_new (sym_name, now_seg, (valueT) frag_now_fix (), + frag_now); +#ifdef OBJ_VMS + S_SET_OTHER (symbolP, const_flag); +#endif /* OBJ_VMS */ + + symbol_table_insert (symbolP); + } /* if we have seen this symbol before */ + + if (mri_common_symbol != NULL) + { + /* This symbol is actually being defined within an MRI common + section. This requires special handling. */ + symbolP->sy_value.X_op = O_symbol; + symbolP->sy_value.X_add_symbol = mri_common_symbol; + symbolP->sy_value.X_add_number = S_GET_VALUE (mri_common_symbol); + symbolP->sy_frag = &zero_address_frag; + S_SET_SEGMENT (symbolP, expr_section); + symbolP->sy_mri_common = 1; + } + +#ifdef tc_frob_label + tc_frob_label (symbolP); +#endif +#ifdef obj_frob_label + obj_frob_label (symbolP); +#endif + + return symbolP; +} + + +/* + * symbol_table_insert() + * + * Die if we can't insert the symbol. + * + */ + +void +symbol_table_insert (symbolP) + symbolS *symbolP; +{ + register const char *error_string; + + know (symbolP); + know (S_GET_NAME (symbolP)); + + if ((error_string = hash_jam (sy_hash, S_GET_NAME (symbolP), (PTR) symbolP))) + { + as_fatal ("Inserting \"%s\" into symbol table failed: %s", + S_GET_NAME (symbolP), error_string); + } /* on error */ +} /* symbol_table_insert() */ + +/* + * symbol_find_or_make() + * + * If a symbol name does not exist, create it as undefined, and insert + * it into the symbol table. Return a pointer to it. + */ +symbolS * +symbol_find_or_make (name) + const char *name; +{ + register symbolS *symbolP; + + symbolP = symbol_find (name); + + if (symbolP == NULL) + { + symbolP = symbol_make (name); + + symbol_table_insert (symbolP); + } /* if symbol wasn't found */ + + return (symbolP); +} /* symbol_find_or_make() */ + +symbolS * +symbol_make (name) + CONST char *name; +{ + symbolS *symbolP; + + /* Let the machine description default it, e.g. for register names. */ + symbolP = md_undefined_symbol ((char *) name); + + if (!symbolP) + symbolP = symbol_new (name, undefined_section, (valueT) 0, &zero_address_frag); + + return (symbolP); +} /* symbol_make() */ + +/* + * symbol_find() + * + * Implement symbol table lookup. + * In: A symbol's name as a string: '\0' can't be part of a symbol name. + * Out: NULL if the name was not in the symbol table, else the address + * of a struct symbol associated with that name. + */ + +symbolS * +symbol_find (name) + CONST char *name; +{ +#ifdef STRIP_UNDERSCORE + return (symbol_find_base (name, 1)); +#else /* STRIP_UNDERSCORE */ + return (symbol_find_base (name, 0)); +#endif /* STRIP_UNDERSCORE */ +} /* symbol_find() */ + +symbolS * +symbol_find_base (name, strip_underscore) + CONST char *name; + int strip_underscore; +{ + if (strip_underscore && *name == '_') + name++; + +#ifdef tc_canonicalize_symbol_name + { + char *copy; + + copy = (char *) alloca (strlen (name) + 1); + strcpy (copy, name); + name = tc_canonicalize_symbol_name (copy); + } +#endif + + if (! symbols_case_sensitive) + { + unsigned char *copy; + + copy = (unsigned char *) alloca (strlen (name) + 1); + name = (const char *) copy; + for (; *copy != '\0'; copy++) + if (islower (*copy)) + *copy = toupper (*copy); + } + + return ((symbolS *) hash_find (sy_hash, name)); +} + +/* + * Once upon a time, symbols were kept in a singly linked list. At + * least coff needs to be able to rearrange them from time to time, for + * which a doubly linked list is much more convenient. Loic did these + * as macros which seemed dangerous to me so they're now functions. + * xoxorich. + */ + +/* Link symbol ADDME after symbol TARGET in the chain. */ +void +symbol_append (addme, target, rootPP, lastPP) + symbolS *addme; + symbolS *target; + symbolS **rootPP; + symbolS **lastPP; +{ + if (target == NULL) + { + know (*rootPP == NULL); + know (*lastPP == NULL); + addme->sy_next = NULL; +#ifdef SYMBOLS_NEED_BACKPOINTERS + addme->sy_previous = NULL; +#endif + *rootPP = addme; + *lastPP = addme; + return; + } /* if the list is empty */ + + if (target->sy_next != NULL) + { +#ifdef SYMBOLS_NEED_BACKPOINTERS + target->sy_next->sy_previous = addme; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } + else + { + know (*lastPP == target); + *lastPP = addme; + } /* if we have a next */ + + addme->sy_next = target->sy_next; + target->sy_next = addme; + +#ifdef SYMBOLS_NEED_BACKPOINTERS + addme->sy_previous = target; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + + debug_verify_symchain (symbol_rootP, symbol_lastP); +} + +/* Set the chain pointers of SYMBOL to null. */ +void +symbol_clear_list_pointers (symbolP) + symbolS *symbolP; +{ + symbolP->sy_next = NULL; +#ifdef SYMBOLS_NEED_BACKPOINTERS + symbolP->sy_previous = NULL; +#endif +} + +#ifdef SYMBOLS_NEED_BACKPOINTERS +/* Remove SYMBOLP from the list. */ +void +symbol_remove (symbolP, rootPP, lastPP) + symbolS *symbolP; + symbolS **rootPP; + symbolS **lastPP; +{ + if (symbolP == *rootPP) + { + *rootPP = symbolP->sy_next; + } /* if it was the root */ + + if (symbolP == *lastPP) + { + *lastPP = symbolP->sy_previous; + } /* if it was the tail */ + + if (symbolP->sy_next != NULL) + { + symbolP->sy_next->sy_previous = symbolP->sy_previous; + } /* if not last */ + + if (symbolP->sy_previous != NULL) + { + symbolP->sy_previous->sy_next = symbolP->sy_next; + } /* if not first */ + + debug_verify_symchain (*rootPP, *lastPP); +} + +/* Link symbol ADDME before symbol TARGET in the chain. */ +void +symbol_insert (addme, target, rootPP, lastPP) + symbolS *addme; + symbolS *target; + symbolS **rootPP; + symbolS **lastPP; +{ + if (target->sy_previous != NULL) + { + target->sy_previous->sy_next = addme; + } + else + { + know (*rootPP == target); + *rootPP = addme; + } /* if not first */ + + addme->sy_previous = target->sy_previous; + target->sy_previous = addme; + addme->sy_next = target; + + debug_verify_symchain (*rootPP, *lastPP); +} + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +void +verify_symbol_chain (rootP, lastP) + symbolS *rootP; + symbolS *lastP; +{ + symbolS *symbolP = rootP; + + if (symbolP == NULL) + return; + + for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP)) + { +#ifdef SYMBOLS_NEED_BACKPOINTERS + assert (symbolP->sy_next->sy_previous == symbolP); +#else + /* Walk the list anyways, to make sure pointers are still good. */ + ; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } + + assert (lastP == symbolP); +} + +void +verify_symbol_chain_2 (sym) + symbolS *sym; +{ + symbolS *p = sym, *n = sym; +#ifdef SYMBOLS_NEED_BACKPOINTERS + while (symbol_previous (p)) + p = symbol_previous (p); +#endif + while (symbol_next (n)) + n = symbol_next (n); + verify_symbol_chain (p, n); +} + +/* Resolve the value of a symbol. This is called during the final + pass over the symbol table to resolve any symbols with complex + values. */ + +void +resolve_symbol_value (symp) + symbolS *symp; +{ + int resolved; + + if (symp->sy_resolved) + return; + + resolved = 0; + + if (symp->sy_resolving) + { + as_bad ("Symbol definition loop encountered at %s", + S_GET_NAME (symp)); + S_SET_VALUE (symp, (valueT) 0); + resolved = 1; + } + else + { + offsetT left, right, val; + segT seg_left, seg_right; + + symp->sy_resolving = 1; + + /* Simplify addition or subtraction of a constant by folding the + constant into X_add_number. */ + if (symp->sy_value.X_op == O_add + || symp->sy_value.X_op == O_subtract) + { + resolve_symbol_value (symp->sy_value.X_add_symbol); + resolve_symbol_value (symp->sy_value.X_op_symbol); + if (S_GET_SEGMENT (symp->sy_value.X_op_symbol) == absolute_section) + { + right = S_GET_VALUE (symp->sy_value.X_op_symbol); + if (symp->sy_value.X_op == O_add) + symp->sy_value.X_add_number += right; + else + symp->sy_value.X_add_number -= right; + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_op_symbol = NULL; + } + else if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol) + == absolute_section) + && symp->sy_value.X_op == O_add) + { + left = S_GET_VALUE (symp->sy_value.X_add_symbol); + symp->sy_value.X_add_symbol = symp->sy_value.X_op_symbol; + symp->sy_value.X_add_number += left; + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_op_symbol = NULL; + } + } + + switch (symp->sy_value.X_op) + { + case O_absent: + S_SET_VALUE (symp, 0); + /* Fall through. */ + case O_constant: + S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address); + if (S_GET_SEGMENT (symp) == expr_section) + S_SET_SEGMENT (symp, absolute_section); + resolved = 1; + break; + + case O_symbol: + resolve_symbol_value (symp->sy_value.X_add_symbol); + + if (symp->sy_mri_common) + { + /* This is a symbol inside an MRI common section. The + relocation routines are going to handle it specially. + Don't change the value. */ + S_SET_VALUE (symp, symp->sy_value.X_add_number); + resolved = symp->sy_value.X_add_symbol->sy_resolved; + break; + } + + if (symp->sy_value.X_add_number == 0) + copy_symbol_attributes (symp, symp->sy_value.X_add_symbol); + + /* If we have equated this symbol to an undefined symbol, we + keep X_op set to O_symbol, and we don't change + X_add_number. This permits the routine which writes out + relocation to detect this case, and convert the + relocation to be against the symbol to which this symbol + is equated. */ + if (! S_IS_DEFINED (symp->sy_value.X_add_symbol) + || S_IS_COMMON (symp->sy_value.X_add_symbol)) + { + symp->sy_value.X_op = O_symbol; + S_SET_SEGMENT (symp, + S_GET_SEGMENT (symp->sy_value.X_add_symbol)); + } + else + { + S_SET_VALUE (symp, + (symp->sy_value.X_add_number + + symp->sy_frag->fr_address + + S_GET_VALUE (symp->sy_value.X_add_symbol))); + if (S_GET_SEGMENT (symp) == expr_section + || S_GET_SEGMENT (symp) == undefined_section) + S_SET_SEGMENT (symp, + S_GET_SEGMENT (symp->sy_value.X_add_symbol)); + } + + resolved = symp->sy_value.X_add_symbol->sy_resolved; + break; + + case O_uminus: + case O_bit_not: + case O_logical_not: + resolve_symbol_value (symp->sy_value.X_add_symbol); + if (symp->sy_value.X_op == O_uminus) + val = - S_GET_VALUE (symp->sy_value.X_add_symbol); + else if (symp->sy_value.X_op == O_logical_not) + val = ! S_GET_VALUE (symp->sy_value.X_add_symbol); + else + val = ~ S_GET_VALUE (symp->sy_value.X_add_symbol); + S_SET_VALUE (symp, + (val + + symp->sy_value.X_add_number + + symp->sy_frag->fr_address)); + if (S_GET_SEGMENT (symp) == expr_section + || S_GET_SEGMENT (symp) == undefined_section) + S_SET_SEGMENT (symp, absolute_section); + resolved = symp->sy_value.X_add_symbol->sy_resolved; + break; + + case O_multiply: + case O_divide: + case O_modulus: + case O_left_shift: + case O_right_shift: + case O_bit_inclusive_or: + case O_bit_or_not: + case O_bit_exclusive_or: + case O_bit_and: + case O_add: + case O_subtract: + case O_eq: + case O_ne: + case O_lt: + case O_le: + case O_ge: + case O_gt: + case O_logical_and: + case O_logical_or: + resolve_symbol_value (symp->sy_value.X_add_symbol); + resolve_symbol_value (symp->sy_value.X_op_symbol); + seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol); + seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol); + left = S_GET_VALUE (symp->sy_value.X_add_symbol); + right = S_GET_VALUE (symp->sy_value.X_op_symbol); + + /* Subtraction is permitted if both operands are in the same + section. Otherwise, both operands must be absolute. We + already handled the case of addition or subtraction of a + constant above. This will probably need to be changed + for an object file format which supports arbitrary + expressions, such as IEEE-695. */ + if ((seg_left != absolute_section + || seg_right != absolute_section) + && (symp->sy_value.X_op != O_subtract + || seg_left != seg_right)) + { + char *file; + unsigned int line; + + if (expr_symbol_where (symp, &file, &line)) + { + if (seg_left == undefined_section) + as_bad_where (file, line, + "undefined symbol %s in operation", + S_GET_NAME (symp->sy_value.X_add_symbol)); + if (seg_right == undefined_section) + as_bad_where (file, line, + "undefined symbol %s in operation", + S_GET_NAME (symp->sy_value.X_op_symbol)); + if (seg_left != undefined_section + && seg_right != undefined_section) + as_bad_where (file, line, "invalid section for operation"); + } + else + { + if (seg_left == undefined_section) + as_bad ("undefined symbol %s in operation setting %s", + S_GET_NAME (symp->sy_value.X_add_symbol), + S_GET_NAME (symp)); + if (seg_right == undefined_section) + as_bad ("undefined symbol %s in operation setting %s", + S_GET_NAME (symp->sy_value.X_op_symbol), + S_GET_NAME (symp)); + if (seg_left != undefined_section + && seg_right != undefined_section) + as_bad ("invalid section for operation setting %s", + S_GET_NAME (symp)); + } + } + + switch (symp->sy_value.X_op) + { + case O_multiply: val = left * right; break; + case O_divide: val = left / right; break; + case O_modulus: val = left % right; break; + case O_left_shift: val = left << right; break; + case O_right_shift: val = left >> right; break; + case O_bit_inclusive_or: val = left | right; break; + case O_bit_or_not: val = left |~ right; break; + case O_bit_exclusive_or: val = left ^ right; break; + case O_bit_and: val = left & right; break; + case O_add: val = left + right; break; + case O_subtract: val = left - right; break; + case O_eq: val = left == right ? ~ (offsetT) 0 : 0; + case O_ne: val = left != right ? ~ (offsetT) 0 : 0; + case O_lt: val = left < right ? ~ (offsetT) 0 : 0; + case O_le: val = left <= right ? ~ (offsetT) 0 : 0; + case O_ge: val = left >= right ? ~ (offsetT) 0 : 0; + case O_gt: val = left > right ? ~ (offsetT) 0 : 0; + case O_logical_and: val = left && right; break; + case O_logical_or: val = left || right; break; + default: abort (); + } + S_SET_VALUE (symp, + (symp->sy_value.X_add_number + + symp->sy_frag->fr_address + + val)); + if (S_GET_SEGMENT (symp) == expr_section + || S_GET_SEGMENT (symp) == undefined_section) + S_SET_SEGMENT (symp, absolute_section); + resolved = (symp->sy_value.X_add_symbol->sy_resolved + && symp->sy_value.X_op_symbol->sy_resolved); + break; + + case O_register: + case O_big: + case O_illegal: + /* Give an error (below) if not in expr_section. We don't + want to worry about expr_section symbols, because they + are fictional (they are created as part of expression + resolution), and any problems may not actually mean + anything. */ + break; + } + } + + /* Don't worry if we can't resolve an expr_section symbol. */ + if (resolved) + symp->sy_resolved = 1; + else if (S_GET_SEGMENT (symp) != expr_section) + { + as_bad ("can't resolve value for symbol \"%s\"", S_GET_NAME (symp)); + symp->sy_resolved = 1; + } +} + +/* Dollar labels look like a number followed by a dollar sign. Eg, "42$". + They are *really* local. That is, they go out of scope whenever we see a + label that isn't local. Also, like fb labels, there can be multiple + instances of a dollar label. Therefor, we name encode each instance with + the instance number, keep a list of defined symbols separate from the real + symbol table, and we treat these buggers as a sparse array. */ + +static long *dollar_labels; +static long *dollar_label_instances; +static char *dollar_label_defines; +static long dollar_label_count; +static unsigned long dollar_label_max; + +int +dollar_label_defined (label) + long label; +{ + long *i; + + know ((dollar_labels != NULL) || (dollar_label_count == 0)); + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + return dollar_label_defines[i - dollar_labels]; + + /* if we get here, label isn't defined */ + return 0; +} /* dollar_label_defined() */ + +static long +dollar_label_instance (label) + long label; +{ + long *i; + + know ((dollar_labels != NULL) || (dollar_label_count == 0)); + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + return (dollar_label_instances[i - dollar_labels]); + + /* If we get here, we haven't seen the label before, therefore its instance + count is zero. */ + return 0; +} + +void +dollar_label_clear () +{ + memset (dollar_label_defines, '\0', (unsigned int) dollar_label_count); +} + +#define DOLLAR_LABEL_BUMP_BY 10 + +void +define_dollar_label (label) + long label; +{ + long *i; + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + { + ++dollar_label_instances[i - dollar_labels]; + dollar_label_defines[i - dollar_labels] = 1; + return; + } + + /* if we get to here, we don't have label listed yet. */ + + if (dollar_labels == NULL) + { + dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); + dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); + dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY); + dollar_label_max = DOLLAR_LABEL_BUMP_BY; + dollar_label_count = 0; + } + else if (dollar_label_count == dollar_label_max) + { + dollar_label_max += DOLLAR_LABEL_BUMP_BY; + dollar_labels = (long *) xrealloc ((char *) dollar_labels, + dollar_label_max * sizeof (long)); + dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances, + dollar_label_max * sizeof (long)); + dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max); + } /* if we needed to grow */ + + dollar_labels[dollar_label_count] = label; + dollar_label_instances[dollar_label_count] = 1; + dollar_label_defines[dollar_label_count] = 1; + ++dollar_label_count; +} + +/* + * dollar_label_name() + * + * Caller must copy returned name: we re-use the area for the next name. + * + * The mth occurence of label n: is turned into the symbol "Ln^Am" + * where n is the label number and m is the instance number. "L" makes + * it a label discarded unless debugging and "^A"('\1') ensures no + * ordinary symbol SHOULD get the same name as a local label + * symbol. The first "4:" is "L4^A1" - the m numbers begin at 1. + * + * fb labels get the same treatment, except that ^B is used in place of ^A. + */ + +char * /* Return local label name. */ +dollar_label_name (n, augend) + register long n; /* we just saw "n$:" : n a number */ + register int augend; /* 0 for current instance, 1 for new instance */ +{ + long i; + /* Returned to caller, then copied. used for created names ("4f") */ + static char symbol_name_build[24]; + register char *p; + register char *q; + char symbol_name_temporary[20]; /* build up a number, BACKWARDS */ + + know (n >= 0); + know (augend == 0 || augend == 1); + p = symbol_name_build; + *p++ = 'L'; + + /* Next code just does sprintf( {}, "%d", n); */ + /* label number */ + q = symbol_name_temporary; + for (*q++ = 0, i = n; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p = *--q) != '\0') + ++p; + + *p++ = 1; /* ^A */ + + /* instance number */ + q = symbol_name_temporary; + for (*q++ = 0, i = dollar_label_instance (n) + augend; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p++ = *--q) != '\0');; + + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return symbol_name_build; +} + +/* + * Sombody else's idea of local labels. They are made by "n:" where n + * is any decimal digit. Refer to them with + * "nb" for previous (backward) n: + * or "nf" for next (forward) n:. + * + * We do a little better and let n be any number, not just a single digit, but + * since the other guy's assembler only does ten, we treat the first ten + * specially. + * + * Like someone else's assembler, we have one set of local label counters for + * entire assembly, not one set per (sub)segment like in most assemblers. This + * implies that one can refer to a label in another segment, and indeed some + * crufty compilers have done just that. + * + * Since there could be a LOT of these things, treat them as a sparse array. + */ + +#define FB_LABEL_SPECIAL (10) + +static long fb_low_counter[FB_LABEL_SPECIAL]; +static long *fb_labels; +static long *fb_label_instances; +static long fb_label_count; +static long fb_label_max; + +/* this must be more than FB_LABEL_SPECIAL */ +#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6) + +static void +fb_label_init () +{ + memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter)); +} /* fb_label_init() */ + +/* add one to the instance number of this fb label */ +void +fb_label_instance_inc (label) + long label; +{ + long *i; + + if (label < FB_LABEL_SPECIAL) + { + ++fb_low_counter[label]; + return; + } + + if (fb_labels != NULL) + { + for (i = fb_labels + FB_LABEL_SPECIAL; + i < fb_labels + fb_label_count; ++i) + { + if (*i == label) + { + ++fb_label_instances[i - fb_labels]; + return; + } /* if we find it */ + } /* for each existing label */ + } + + /* if we get to here, we don't have label listed yet. */ + + if (fb_labels == NULL) + { + fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); + fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); + fb_label_max = FB_LABEL_BUMP_BY; + fb_label_count = FB_LABEL_SPECIAL; + + } + else if (fb_label_count == fb_label_max) + { + fb_label_max += FB_LABEL_BUMP_BY; + fb_labels = (long *) xrealloc ((char *) fb_labels, + fb_label_max * sizeof (long)); + fb_label_instances = (long *) xrealloc ((char *) fb_label_instances, + fb_label_max * sizeof (long)); + } /* if we needed to grow */ + + fb_labels[fb_label_count] = label; + fb_label_instances[fb_label_count] = 1; + ++fb_label_count; +} + +static long +fb_label_instance (label) + long label; +{ + long *i; + + if (label < FB_LABEL_SPECIAL) + { + return (fb_low_counter[label]); + } + + if (fb_labels != NULL) + { + for (i = fb_labels + FB_LABEL_SPECIAL; + i < fb_labels + fb_label_count; ++i) + { + if (*i == label) + { + return (fb_label_instances[i - fb_labels]); + } /* if we find it */ + } /* for each existing label */ + } + + /* We didn't find the label, so this must be a reference to the + first instance. */ + return 0; +} + +/* + * fb_label_name() + * + * Caller must copy returned name: we re-use the area for the next name. + * + * The mth occurence of label n: is turned into the symbol "Ln^Bm" + * where n is the label number and m is the instance number. "L" makes + * it a label discarded unless debugging and "^B"('\2') ensures no + * ordinary symbol SHOULD get the same name as a local label + * symbol. The first "4:" is "L4^B1" - the m numbers begin at 1. + * + * dollar labels get the same treatment, except that ^A is used in place of ^B. */ + +char * /* Return local label name. */ +fb_label_name (n, augend) + long n; /* we just saw "n:", "nf" or "nb" : n a number */ + long augend; /* 0 for nb, 1 for n:, nf */ +{ + long i; + /* Returned to caller, then copied. used for created names ("4f") */ + static char symbol_name_build[24]; + register char *p; + register char *q; + char symbol_name_temporary[20]; /* build up a number, BACKWARDS */ + + know (n >= 0); + know (augend == 0 || augend == 1); + p = symbol_name_build; + *p++ = 'L'; + + /* Next code just does sprintf( {}, "%d", n); */ + /* label number */ + q = symbol_name_temporary; + for (*q++ = 0, i = n; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p = *--q) != '\0') + ++p; + + *p++ = 2; /* ^B */ + + /* instance number */ + q = symbol_name_temporary; + for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p++ = *--q) != '\0');; + + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return (symbol_name_build); +} /* fb_label_name() */ + +/* + * decode name that may have been generated by foo_label_name() above. If + * the name wasn't generated by foo_label_name(), then return it unaltered. + * This is used for error messages. + */ + +char * +decode_local_label_name (s) + char *s; +{ + char *p; + char *symbol_decode; + int label_number; + int instance_number; + char *type; + const char *message_format = "\"%d\" (instance number %d of a %s label)"; + + if (s[0] != 'L') + return s; + + for (label_number = 0, p = s + 1; isdigit (*p); ++p) + label_number = (10 * label_number) + *p - '0'; + + if (*p == 1) + type = "dollar"; + else if (*p == 2) + type = "fb"; + else + return s; + + for (instance_number = 0, p++; isdigit (*p); ++p) + instance_number = (10 * instance_number) + *p - '0'; + + symbol_decode = obstack_alloc (¬es, strlen (message_format) + 30); + sprintf (symbol_decode, message_format, label_number, instance_number, type); + + return symbol_decode; +} + +/* Get the value of a symbol. */ + +valueT +S_GET_VALUE (s) + symbolS *s; +{ + if (!s->sy_resolved && !s->sy_resolving && s->sy_value.X_op != O_constant) + resolve_symbol_value (s); + if (s->sy_value.X_op != O_constant) + { + static symbolS *recur; + + /* FIXME: In non BFD assemblers, S_IS_DEFINED and S_IS_COMMON + may call S_GET_VALUE. We use a static symbol to avoid the + immediate recursion. */ + if (recur == s) + return (valueT) s->sy_value.X_add_number; + recur = s; + if (! s->sy_resolved + || s->sy_value.X_op != O_symbol + || (S_IS_DEFINED (s) && ! S_IS_COMMON (s))) + as_bad ("Attempt to get value of unresolved symbol %s", + S_GET_NAME (s)); + recur = NULL; + } + return (valueT) s->sy_value.X_add_number; +} + +/* Set the value of a symbol. */ + +void +S_SET_VALUE (s, val) + symbolS *s; + valueT val; +{ + s->sy_value.X_op = O_constant; + s->sy_value.X_add_number = (offsetT) val; + s->sy_value.X_unsigned = 0; +} + +void +copy_symbol_attributes (dest, src) + symbolS *dest, *src; +{ +#ifdef BFD_ASSEMBLER + /* In an expression, transfer the settings of these flags. + The user can override later, of course. */ +#define COPIED_SYMFLAGS (BSF_FUNCTION) + dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS; +#endif + +#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES + OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src); +#endif +} + +#ifdef BFD_ASSEMBLER + +int +S_IS_EXTERNAL (s) + symbolS *s; +{ + flagword flags = s->bsym->flags; + + /* sanity check */ + if (flags & BSF_LOCAL && flags & BSF_GLOBAL) + abort (); + + return (flags & BSF_GLOBAL) != 0; +} + +int +S_IS_WEAK (s) + symbolS *s; +{ + return (s->bsym->flags & BSF_WEAK) != 0; +} + +int +S_IS_COMMON (s) + symbolS *s; +{ + return bfd_is_com_section (s->bsym->section); +} + +int +S_IS_DEFINED (s) + symbolS *s; +{ + return s->bsym->section != undefined_section; +} + +int +S_IS_DEBUG (s) + symbolS *s; +{ + if (s->bsym->flags & BSF_DEBUGGING) + return 1; + return 0; +} + +int +S_IS_LOCAL (s) + symbolS *s; +{ + flagword flags = s->bsym->flags; + const char *name; + + /* sanity check */ + if (flags & BSF_LOCAL && flags & BSF_GLOBAL) + abort (); + + if (bfd_get_section (s->bsym) == reg_section) + return 1; + + name = S_GET_NAME (s); + return (name != NULL + && ! S_IS_DEBUG (s) + && (strchr (name, '\001') + || strchr (name, '\002') + || (! flag_keep_locals + && (bfd_is_local_label (stdoutput, s->bsym) + || (flag_mri + && name[0] == '?' + && name[1] == '?'))))); +} + +int +S_IS_EXTERN (s) + symbolS *s; +{ + return S_IS_EXTERNAL (s); +} + +int +S_IS_STABD (s) + symbolS *s; +{ + return S_GET_NAME (s) == 0; +} + +CONST char * +S_GET_NAME (s) + symbolS *s; +{ + return s->bsym->name; +} + +segT +S_GET_SEGMENT (s) + symbolS *s; +{ + return s->bsym->section; +} + +void +S_SET_SEGMENT (s, seg) + symbolS *s; + segT seg; +{ + s->bsym->section = seg; +} + +void +S_SET_EXTERNAL (s) + symbolS *s; +{ + if ((s->bsym->flags & BSF_WEAK) != 0) + { + /* Let .weak override .global. */ + return; + } + s->bsym->flags |= BSF_GLOBAL; + s->bsym->flags &= ~(BSF_LOCAL|BSF_WEAK); +} + +void +S_CLEAR_EXTERNAL (s) + symbolS *s; +{ + if ((s->bsym->flags & BSF_WEAK) != 0) + { + /* Let .weak override. */ + return; + } + s->bsym->flags |= BSF_LOCAL; + s->bsym->flags &= ~(BSF_GLOBAL|BSF_WEAK); +} + +void +S_SET_WEAK (s) + symbolS *s; +{ + s->bsym->flags |= BSF_WEAK; + s->bsym->flags &= ~(BSF_GLOBAL|BSF_LOCAL); +} + +void +S_SET_NAME (s, name) + symbolS *s; + char *name; +{ + s->bsym->name = name; +} +#endif /* BFD_ASSEMBLER */ + +void +symbol_begin () +{ + symbol_lastP = NULL; + symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ + sy_hash = hash_new (); + + memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol)); +#ifdef BFD_ASSEMBLER +#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL) + abs_symbol.bsym = bfd_abs_section.symbol; +#endif +#else + /* Can't initialise a union. Sigh. */ + S_SET_SEGMENT (&abs_symbol, absolute_section); +#endif + abs_symbol.sy_value.X_op = O_constant; + abs_symbol.sy_frag = &zero_address_frag; + + if (LOCAL_LABELS_FB) + fb_label_init (); +} + + +int indent_level; + +#if 0 + +static void +indent () +{ + printf ("%*s", indent_level * 4, ""); +} + +#endif + +void +print_symbol_value_1 (file, sym) + FILE *file; + symbolS *sym; +{ + const char *name = S_GET_NAME (sym); + if (!name || !name[0]) + name = "(unnamed)"; + fprintf (file, "sym %lx %s", (unsigned long) sym, name); + if (sym->sy_frag != &zero_address_frag) + fprintf (file, " frag %lx", (long) sym->sy_frag); + if (sym->written) + fprintf (file, " written"); + if (sym->sy_resolved) + fprintf (file, " resolved"); + else if (sym->sy_resolving) + fprintf (file, " resolving"); + if (sym->sy_used_in_reloc) + fprintf (file, " used-in-reloc"); + if (sym->sy_used) + fprintf (file, " used"); + if (S_IS_LOCAL (sym)) + fprintf (file, " local"); + if (S_IS_EXTERN (sym)) + fprintf (file, " extern"); + if (S_IS_DEBUG (sym)) + fprintf (file, " debug"); + if (S_IS_DEFINED (sym)) + fprintf (file, " defined"); + fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym))); + if (sym->sy_resolved) + { + segT s = S_GET_SEGMENT (sym); + + if (s != undefined_section + && s != expr_section) + fprintf (file, " %lx", (long) S_GET_VALUE (sym)); + } + else if (indent_level < 8 && S_GET_SEGMENT (sym) != undefined_section) + { + indent_level++; + fprintf (file, "\n%*s<", indent_level * 4, ""); + print_expr_1 (file, &sym->sy_value); + fprintf (file, ">"); + indent_level--; + } + fflush (file); +} + +void +print_symbol_value (sym) + symbolS *sym; +{ + indent_level = 0; + print_symbol_value_1 (stderr, sym); + fprintf (stderr, "\n"); +} + +void +print_expr_1 (file, exp) + FILE *file; + expressionS *exp; +{ + fprintf (file, "expr %lx ", (long) exp); + switch (exp->X_op) + { + case O_illegal: + fprintf (file, "illegal"); + break; + case O_absent: + fprintf (file, "absent"); + break; + case O_constant: + fprintf (file, "constant %lx", (long) exp->X_add_number); + break; + case O_symbol: + indent_level++; + fprintf (file, "symbol\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">"); + maybe_print_addnum: + if (exp->X_add_number) + fprintf (file, "\n%*s%lx", indent_level * 4, "", + (long) exp->X_add_number); + indent_level--; + break; + case O_register: + fprintf (file, "register #%d", (int) exp->X_add_number); + break; + case O_big: + fprintf (file, "big"); + break; + case O_uminus: + fprintf (file, "uminus -<"); + indent_level++; + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + case O_bit_not: + fprintf (file, "bit_not"); + break; + case O_multiply: + fprintf (file, "multiply"); + break; + case O_divide: + fprintf (file, "divide"); + break; + case O_modulus: + fprintf (file, "modulus"); + break; + case O_left_shift: + fprintf (file, "lshift"); + break; + case O_right_shift: + fprintf (file, "rshift"); + break; + case O_bit_inclusive_or: + fprintf (file, "bit_ior"); + break; + case O_bit_exclusive_or: + fprintf (file, "bit_xor"); + break; + case O_bit_and: + fprintf (file, "bit_and"); + break; + case O_eq: + fprintf (file, "eq"); + break; + case O_ne: + fprintf (file, "ne"); + break; + case O_lt: + fprintf (file, "lt"); + break; + case O_le: + fprintf (file, "le"); + break; + case O_ge: + fprintf (file, "ge"); + break; + case O_gt: + fprintf (file, "gt"); + break; + case O_logical_and: + fprintf (file, "logical_and"); + break; + case O_logical_or: + fprintf (file, "logical_or"); + break; + case O_add: + indent_level++; + fprintf (file, "add\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_op_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + case O_subtract: + indent_level++; + fprintf (file, "subtract\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_op_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + default: + fprintf (file, "{unknown opcode %d}", (int) exp->X_op); + break; + } + fflush (stdout); +} + +void +print_expr (exp) + expressionS *exp; +{ + print_expr_1 (stderr, exp); + fprintf (stderr, "\n"); +} + +void +symbol_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "symbol table", sy_hash); +} + +/* end of symbols.c */ diff --git a/contrib/binutils/gas/symbols.h b/contrib/binutils/gas/symbols.h new file mode 100644 index 0000000..e643881 --- /dev/null +++ b/contrib/binutils/gas/symbols.h @@ -0,0 +1,90 @@ +/* symbols.h - + Copyright (C) 1987, 90, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +extern struct obstack notes; /* eg FixS live here. */ + +extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif + (if we do that at all). */ + +extern symbolS *symbol_rootP; /* all the symbol nodes */ +extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */ + +extern symbolS abs_symbol; + +extern int symbol_table_frozen; + +/* This is non-zero if symbols are case sensitive, which is the + default. */ +extern int symbols_case_sensitive; + +char *decode_local_label_name PARAMS ((char *s)); +symbolS *symbol_find PARAMS ((CONST char *name)); +symbolS *symbol_find_base PARAMS ((CONST char *name, int strip_underscore)); +symbolS *symbol_find_or_make PARAMS ((const char *name)); +symbolS *symbol_make PARAMS ((CONST char *name)); +symbolS *symbol_new PARAMS ((CONST char *name, segT segment, valueT value, + fragS * frag)); +symbolS *symbol_create PARAMS ((CONST char *name, segT segment, valueT value, + fragS * frag)); +symbolS *colon PARAMS ((const char *sym_name)); +void local_colon PARAMS ((int n)); +void symbol_begin PARAMS ((void)); +void symbol_print_statistics PARAMS ((FILE *)); +void symbol_table_insert PARAMS ((symbolS * symbolP)); +void resolve_symbol_value PARAMS ((symbolS *)); + +void print_symbol_value PARAMS ((symbolS *)); +void print_expr PARAMS ((expressionS *)); +void print_expr_1 PARAMS ((FILE *, expressionS *)); +void print_symbol_value_1 PARAMS ((FILE *, symbolS *)); + +int dollar_label_defined PARAMS ((long l)); +void dollar_label_clear PARAMS ((void)); +void define_dollar_label PARAMS ((long l)); +char *dollar_label_name PARAMS ((long l, int augend)); + +void fb_label_instance_inc PARAMS ((long label)); +char *fb_label_name PARAMS ((long n, long augend)); + +extern void copy_symbol_attributes PARAMS ((symbolS *, symbolS *)); + +/* Get and set the values of symbols. These used to be macros. */ +extern valueT S_GET_VALUE PARAMS ((symbolS *)); +extern void S_SET_VALUE PARAMS ((symbolS *, valueT)); + +#ifdef BFD_ASSEMBLER +extern int S_IS_EXTERNAL PARAMS ((symbolS *)); +extern int S_IS_WEAK PARAMS ((symbolS *)); +extern int S_IS_COMMON PARAMS ((symbolS *)); +extern int S_IS_DEFINED PARAMS ((symbolS *)); +extern int S_IS_DEBUG PARAMS ((symbolS *)); +extern int S_IS_LOCAL PARAMS ((symbolS *)); +extern int S_IS_EXTERN PARAMS ((symbolS *)); +extern int S_IS_STABD PARAMS ((symbolS *)); +extern CONST char *S_GET_NAME PARAMS ((symbolS *)); +extern segT S_GET_SEGMENT PARAMS ((symbolS *)); +extern void S_SET_SEGMENT PARAMS ((symbolS *, segT)); +extern void S_SET_EXTERNAL PARAMS ((symbolS *)); +extern void S_SET_NAME PARAMS ((symbolS *, char *)); +extern void S_CLEAR_EXTERNAL PARAMS ((symbolS *)); +extern void S_SET_WEAK PARAMS ((symbolS *)); +#endif + +/* end of symbols.h */ diff --git a/contrib/binutils/gas/tc.h b/contrib/binutils/gas/tc.h new file mode 100644 index 0000000..4e4046c --- /dev/null +++ b/contrib/binutils/gas/tc.h @@ -0,0 +1,112 @@ +/* tc.h - target cpu dependent + + Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* In theory (mine, at least!) the machine dependent part of the assembler + should only have to include one file. This one. -- JF */ + +extern const pseudo_typeS md_pseudo_table[]; + +/* JF moved this here from as.h under the theory that nobody except MACHINE.c + and write.c care about it anyway. */ + +struct relax_type +{ + /* Forward reach. Signed number. > 0. */ + long rlx_forward; + /* Backward reach. Signed number. < 0. */ + long rlx_backward; + + /* Bytes length of this address. */ + unsigned char rlx_length; + + /* Next longer relax-state. 0 means there is no 'next' relax-state. */ + relax_substateT rlx_more; +}; + +typedef struct relax_type relax_typeS; + +extern const int md_reloc_size; /* Size of a relocation record */ + +char *md_atof PARAMS ((int what_statement_type, char *literalP, int *sizeP)); +#ifndef md_estimate_size_before_relax +int md_estimate_size_before_relax PARAMS ((fragS * fragP, segT segment)); +#endif +int md_parse_option PARAMS ((int c, char *arg)); +void md_show_usage PARAMS ((FILE *)); +long md_pcrel_from PARAMS ((fixS * fixP)); +short tc_coff_fix2rtype PARAMS ((fixS * fixP)); +void md_assemble PARAMS ((char *str)); +void md_begin PARAMS ((void)); +#ifndef md_create_long_jump +void md_create_long_jump PARAMS ((char *ptr, addressT from_addr, + addressT to_addr, fragS * frag, + symbolS * to_symbol)); +#endif +#ifndef md_create_short_jump +void md_create_short_jump PARAMS ((char *ptr, addressT from_addr, + addressT to_addr, fragS * frag, + symbolS * to_symbol)); +#endif +void md_number_to_chars PARAMS ((char *buf, valueT val, int n)); + +#ifndef md_operand +void md_operand PARAMS ((expressionS * expressionP)); +#endif + +#ifdef MD_APPLY_FIX3 +int md_apply_fix3 PARAMS ((fixS * fixP, valueT *val, segT seg)); +#endif +#ifdef BFD_ASSEMBLER +int md_apply_fix PARAMS ((fixS * fixP, valueT *val)); +#ifndef md_convert_frag +void md_convert_frag PARAMS ((bfd * headers, segT sec, fragS * fragP)); +#endif +#ifndef tc_headers_hook +void tc_headers_hook PARAMS ((segT *, fixS *)); +#endif +#ifndef RELOC_EXPANSION_POSSIBLE +extern arelent *tc_gen_reloc PARAMS ((asection *, fixS *)); +#else +extern arelent **tc_gen_reloc PARAMS ((asection *, fixS *)); +#endif +#else /* not BFD_ASSEMBLER */ +void md_apply_fix PARAMS ((fixS * fixP, long val)); +#ifndef md_convert_frag +void md_convert_frag PARAMS ((object_headers * headers, segT, fragS * fragP)); +#endif + +#ifndef tc_crawl_symbol_chain +void tc_crawl_symbol_chain PARAMS ((object_headers * headers)); +#endif /* tc_crawl_symbol_chain */ + +#ifndef tc_headers_hook +void tc_headers_hook PARAMS ((object_headers * headers)); +#endif /* tc_headers_hook */ +#endif /* BFD_ASSEMBLER */ + +#ifndef md_section_align +valueT md_section_align PARAMS ((segT seg, valueT size)); +#endif + +#ifndef md_undefined_symbol +symbolS *md_undefined_symbol PARAMS ((char *name)); +#endif + +/* end of tc.h */ diff --git a/contrib/binutils/gas/write.c b/contrib/binutils/gas/write.c new file mode 100644 index 0000000..549dab7 --- /dev/null +++ b/contrib/binutils/gas/write.c @@ -0,0 +1,2779 @@ +/* write.c - emit .o file + Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This thing should be set up to do byteordering correctly. But... */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "output-file.h" + +/* This looks like a good idea. Let's try turning it on always, for now. */ +#undef BFD_FAST_SECTION_FILL +#define BFD_FAST_SECTION_FILL + +/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop + instruction so that the disassembler does not choke on it. */ +#ifndef NOP_OPCODE +#define NOP_OPCODE 0x00 +#endif + +#ifndef TC_ADJUST_RELOC_COUNT +#define TC_ADJUST_RELOC_COUNT(FIXP,COUNT) +#endif + +#ifndef TC_FORCE_RELOCATION +#define TC_FORCE_RELOCATION(FIXP) 0 +#endif + +#ifndef TC_FORCE_RELOCATION_SECTION +#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP) +#endif + +#ifndef MD_PCREL_FROM_SECTION +#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP) +#endif + +#ifndef WORKING_DOT_WORD +extern CONST int md_short_jump_size; +extern CONST int md_long_jump_size; +#endif + +int symbol_table_frozen; +void print_fixup PARAMS ((fixS *)); + +#ifdef BFD_ASSEMBLER +static void renumber_sections PARAMS ((bfd *, asection *, PTR)); + +/* We generally attach relocs to frag chains. However, after we have + chained these all together into a segment, any relocs we add after + that must be attached to a segment. This will include relocs added + in md_estimate_size_for_relax, for example. */ +static int frags_chained = 0; +#endif + +#ifndef BFD_ASSEMBLER + +#ifndef MANY_SEGMENTS +struct frag *text_frag_root; +struct frag *data_frag_root; +struct frag *bss_frag_root; + +struct frag *text_last_frag; /* Last frag in segment. */ +struct frag *data_last_frag; /* Last frag in segment. */ +static struct frag *bss_last_frag; /* Last frag in segment. */ +#endif + +#ifndef BFD +static object_headers headers; +#endif + +long string_byte_count; +char *next_object_file_charP; /* Tracks object file bytes. */ + +#ifndef OBJ_VMS +int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE; +#endif + +#endif /* BFD_ASSEMBLER */ + +static int n_fixups; + +#ifdef BFD_ASSEMBLER +static fixS *fix_new_internal PARAMS ((fragS *, int where, int size, + symbolS *add, symbolS *sub, + offsetT offset, int pcrel, + bfd_reloc_code_real_type r_type)); +#else +static fixS *fix_new_internal PARAMS ((fragS *, int where, int size, + symbolS *add, symbolS *sub, + offsetT offset, int pcrel, + int r_type)); +#endif +#if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) +static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type)); +#endif +static relax_addressT relax_align PARAMS ((relax_addressT addr, int align)); +#if defined (BFD_ASSEMBLER) || ! defined (BFD) +static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *)); +#endif +#ifdef BFD_ASSEMBLER +static void chain_frchains_together PARAMS ((bfd *, segT, PTR)); +static void cvt_frag_to_fill PARAMS ((segT, fragS *)); +static void relax_and_size_seg PARAMS ((bfd *, asection *, PTR)); +static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR)); +static void write_relocs PARAMS ((bfd *, asection *, PTR)); +static void write_contents PARAMS ((bfd *, asection *, PTR)); +static void set_symtab PARAMS ((void)); +#endif +#if defined (BFD_ASSEMBLER) || (! defined (BFD) && ! defined (OBJ_AOUT)) +static void merge_data_into_text PARAMS ((void)); +#endif +#if ! defined (BFD_ASSEMBLER) && ! defined (BFD) +static void cvt_frag_to_fill PARAMS ((object_headers *, segT, fragS *)); +static void remove_subsegs PARAMS ((frchainS *, int, fragS **, fragS **)); +static void relax_and_size_all_segments PARAMS ((void)); +#endif + +/* + * fix_new() + * + * Create a fixS in obstack 'notes'. + */ +static fixS * +fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel, + r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + symbolS *add_symbol; /* X_add_symbol. */ + symbolS *sub_symbol; /* X_op_symbol. */ + offsetT offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type r_type; /* Relocation type */ +#else + int r_type; /* Relocation type */ +#endif +{ + fixS *fixP; + + n_fixups++; + + fixP = (fixS *) obstack_alloc (¬es, sizeof (fixS)); + + fixP->fx_frag = frag; + fixP->fx_where = where; + fixP->fx_size = size; + /* We've made fx_size a narrow field; check that it's wide enough. */ + if (fixP->fx_size != size) + { + as_bad ("field fx_size too small to hold %d", size); + abort (); + } + fixP->fx_addsy = add_symbol; + fixP->fx_subsy = sub_symbol; + fixP->fx_offset = offset; + fixP->fx_pcrel = pcrel; + fixP->fx_plt = 0; +#if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER) + fixP->fx_r_type = r_type; +#endif + fixP->fx_im_disp = 0; + fixP->fx_pcrel_adjust = 0; + fixP->fx_bit_fixP = 0; + fixP->fx_addnumber = 0; + fixP->fx_tcbit = 0; + fixP->fx_done = 0; + fixP->fx_no_overflow = 0; + fixP->fx_signed = 0; + +#ifdef TC_FIX_TYPE + TC_INIT_FIX_DATA(fixP); +#endif + + as_where (&fixP->fx_file, &fixP->fx_line); + + /* Usually, we want relocs sorted numerically, but while + comparing to older versions of gas that have relocs + reverse sorted, it is convenient to have this compile + time option. xoxorich. */ + + { + +#ifdef BFD_ASSEMBLER + fixS **seg_fix_rootP = (frags_chained + ? &seg_info (now_seg)->fix_root + : &frchain_now->fix_root); + fixS **seg_fix_tailP = (frags_chained + ? &seg_info (now_seg)->fix_tail + : &frchain_now->fix_tail); +#endif + +#ifdef REVERSE_SORT_RELOCS + + fixP->fx_next = *seg_fix_rootP; + *seg_fix_rootP = fixP; + +#else /* REVERSE_SORT_RELOCS */ + + fixP->fx_next = NULL; + + if (*seg_fix_tailP) + (*seg_fix_tailP)->fx_next = fixP; + else + *seg_fix_rootP = fixP; + *seg_fix_tailP = fixP; + +#endif /* REVERSE_SORT_RELOCS */ + + } + + return fixP; +} + +/* Create a fixup relative to a symbol (plus a constant). */ + +fixS * +fix_new (frag, where, size, add_symbol, offset, pcrel, r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + symbolS *add_symbol; /* X_add_symbol. */ + offsetT offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type r_type; /* Relocation type */ +#else + int r_type; /* Relocation type */ +#endif +{ + return fix_new_internal (frag, where, size, add_symbol, + (symbolS *) NULL, offset, pcrel, r_type); +} + +/* Create a fixup for an expression. Currently we only support fixups + for difference expressions. That is itself more than most object + file formats support anyhow. */ + +fixS * +fix_new_exp (frag, where, size, exp, pcrel, r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + expressionS *exp; /* Expression. */ + int pcrel; /* TRUE if PC-relative relocation. */ +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type r_type; /* Relocation type */ +#else + int r_type; /* Relocation type */ +#endif +{ + symbolS *add = NULL; + symbolS *sub = NULL; + offsetT off = 0; + + switch (exp->X_op) + { + case O_absent: + break; + + case O_add: + /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if + the difference expression cannot immediately be reduced. */ + { + symbolS *stmp = make_expr_symbol (exp); + exp->X_op = O_symbol; + exp->X_op_symbol = 0; + exp->X_add_symbol = stmp; + exp->X_add_number = 0; + return fix_new_exp (frag, where, size, exp, pcrel, r_type); + } + + case O_symbol_rva: + add = exp->X_add_symbol; + off = exp->X_add_number; + +#if defined(BFD_ASSEMBLER) + r_type = BFD_RELOC_RVA; +#else +#if defined(TC_RVA_RELOC) + r_type = TC_RVA_RELOC; +#else + as_fatal("rva not supported"); +#endif +#endif + break; + + case O_uminus: + sub = exp->X_add_symbol; + off = exp->X_add_number; + break; + + case O_subtract: + sub = exp->X_op_symbol; + /* Fall through. */ + case O_symbol: + add = exp->X_add_symbol; + /* Fall through. */ + case O_constant: + off = exp->X_add_number; + break; + + default: + add = make_expr_symbol (exp); + break; + } + + return fix_new_internal (frag, where, size, add, sub, off, + pcrel, r_type); +} + +/* Append a string onto another string, bumping the pointer along. */ +void +append (charPP, fromP, length) + char **charPP; + char *fromP; + unsigned long length; +{ + /* Don't trust memcpy() of 0 chars. */ + if (length == 0) + return; + + memcpy (*charPP, fromP, length); + *charPP += length; +} + +#ifndef BFD_ASSEMBLER +int section_alignment[SEG_MAXIMUM_ORDINAL]; +#endif + +/* + * This routine records the largest alignment seen for each segment. + * If the beginning of the segment is aligned on the worst-case + * boundary, all of the other alignments within it will work. At + * least one object format really uses this info. + */ +void +record_alignment (seg, align) + /* Segment to which alignment pertains */ + segT seg; + /* Alignment, as a power of 2 (e.g., 1 => 2-byte boundary, 2 => 4-byte + boundary, etc.) */ + int align; +{ + if (seg == absolute_section) + return; +#ifdef BFD_ASSEMBLER + if (align > bfd_get_section_alignment (stdoutput, seg)) + bfd_set_section_alignment (stdoutput, seg, align); +#else + if (align > section_alignment[(int) seg]) + section_alignment[(int) seg] = align; +#endif +} + +#ifdef BFD_ASSEMBLER + +/* Reset the section indices after removing the gas created sections. */ + +static void +renumber_sections (abfd, sec, countparg) + bfd *abfd; + asection *sec; + PTR countparg; +{ + int *countp = (int *) countparg; + + sec->index = *countp; + ++*countp; +} + +#endif /* defined (BFD_ASSEMBLER) */ + +#if defined (BFD_ASSEMBLER) || ! defined (BFD) + +static fragS * +chain_frchains_together_1 (section, frchp) + segT section; + struct frchain *frchp; +{ + fragS dummy, *prev_frag = &dummy; +#ifdef BFD_ASSEMBLER + fixS fix_dummy, *prev_fix = &fix_dummy; +#endif + + for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next) + { + prev_frag->fr_next = frchp->frch_root; + prev_frag = frchp->frch_last; + assert (prev_frag->fr_type != 0); +#ifdef BFD_ASSEMBLER + if (frchp->fix_root != (fixS *) NULL) + { + if (seg_info (section)->fix_root == (fixS *) NULL) + seg_info (section)->fix_root = frchp->fix_root; + prev_fix->fx_next = frchp->fix_root; + seg_info (section)->fix_tail = frchp->fix_tail; + prev_fix = frchp->fix_tail; + } +#endif + } + assert (prev_frag->fr_type != 0); + prev_frag->fr_next = 0; + return prev_frag; +} + +#endif + +#ifdef BFD_ASSEMBLER + +static void +chain_frchains_together (abfd, section, xxx) + bfd *abfd; /* unused */ + segT section; + PTR xxx; /* unused */ +{ + segment_info_type *info; + + /* BFD may have introduced its own sections without using + subseg_new, so it is possible that seg_info is NULL. */ + info = seg_info (section); + if (info != (segment_info_type *) NULL) + info->frchainP->frch_last + = chain_frchains_together_1 (section, info->frchainP); + + /* Now that we've chained the frags together, we must add new fixups + to the segment, not to the frag chain. */ + frags_chained = 1; +} + +#endif + +#if !defined (BFD) && !defined (BFD_ASSEMBLER) + +static void +remove_subsegs (head, seg, root, last) + frchainS *head; + int seg; + fragS **root; + fragS **last; +{ + *root = head->frch_root; + *last = chain_frchains_together_1 (seg, head); +} + +#endif /* BFD */ + +#if defined (BFD_ASSEMBLER) || !defined (BFD) + +#ifdef BFD_ASSEMBLER +static void +cvt_frag_to_fill (sec, fragP) + segT sec; + fragS *fragP; +#else +static void +cvt_frag_to_fill (headersP, sec, fragP) + object_headers *headersP; + segT sec; + fragS *fragP; +#endif +{ + switch (fragP->fr_type) + { + case rs_align: + case rs_align_code: + case rs_org: + case rs_space: +#ifdef HANDLE_ALIGN + HANDLE_ALIGN (fragP); +#endif + know (fragP->fr_next != NULL); + fragP->fr_offset = (fragP->fr_next->fr_address + - fragP->fr_address + - fragP->fr_fix) / fragP->fr_var; + if (fragP->fr_offset < 0) + { + as_bad ("attempt to .org/.space backwards? (%ld)", + (long) fragP->fr_offset); + } + fragP->fr_type = rs_fill; + break; + + case rs_fill: + break; + + case rs_machine_dependent: +#ifdef BFD_ASSEMBLER + md_convert_frag (stdoutput, sec, fragP); +#else + md_convert_frag (headersP, sec, fragP); +#endif + + assert (fragP->fr_next == NULL || (fragP->fr_next->fr_address - fragP->fr_address == fragP->fr_fix)); + + /* + * After md_convert_frag, we make the frag into a ".space 0". + * Md_convert_frag() should set up any fixSs and constants + * required. + */ + frag_wane (fragP); + break; + +#ifndef WORKING_DOT_WORD + case rs_broken_word: + { + struct broken_word *lie; + + if (fragP->fr_subtype) + { + fragP->fr_fix += md_short_jump_size; + for (lie = (struct broken_word *) (fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie = lie->next_broken_word) + if (lie->added == 1) + fragP->fr_fix += md_long_jump_size; + } + frag_wane (fragP); + } + break; +#endif + + default: + BAD_CASE (fragP->fr_type); + break; + } +} + +#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */ + +#ifdef BFD_ASSEMBLER +static void +relax_and_size_seg (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + flagword flags; + fragS *fragp; + segment_info_type *seginfo; + int x; + valueT size, newsize; + + subseg_change (sec, 0); + + flags = bfd_get_section_flags (abfd, sec); + + seginfo = seg_info (sec); + if (seginfo && seginfo->frchainP) + { + relax_segment (seginfo->frchainP->frch_root, sec); + for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) + cvt_frag_to_fill (sec, fragp); + for (fragp = seginfo->frchainP->frch_root; + fragp->fr_next; + fragp = fragp->fr_next) + /* walk to last elt */; + size = fragp->fr_address + fragp->fr_fix; + } + else + size = 0; + + if (size > 0 && ! seginfo->bss) + flags |= SEC_HAS_CONTENTS; + + /* @@ This is just an approximation. */ + if (seginfo && seginfo->fix_root) + flags |= SEC_RELOC; + else + flags &= ~SEC_RELOC; + x = bfd_set_section_flags (abfd, sec, flags); + assert (x == true); + + newsize = md_section_align (sec, size); + x = bfd_set_section_size (abfd, sec, newsize); + assert (x == true); + + /* If the size had to be rounded up, add some padding in the last + non-empty frag. */ + assert (newsize >= size); + if (size != newsize) + { + fragS *last = seginfo->frchainP->frch_last; + fragp = seginfo->frchainP->frch_root; + while (fragp->fr_next != last) + fragp = fragp->fr_next; + last->fr_address = size; + fragp->fr_offset += newsize - size; + } + +#ifdef tc_frob_section + tc_frob_section (sec); +#endif +#ifdef obj_frob_section + obj_frob_section (sec); +#endif +} + +#ifdef DEBUG2 +static void +dump_section_relocs (abfd, sec, stream_) + bfd *abfd; + asection *sec; + char *stream_; +{ + FILE *stream = (FILE *) stream_; + segment_info_type *seginfo = seg_info (sec); + fixS *fixp = seginfo->fix_root; + + if (!fixp) + return; + + fprintf (stream, "sec %s relocs:\n", sec->name); + while (fixp) + { + symbolS *s = fixp->fx_addsy; + if (s) + { + fprintf (stream, " %08x: %s(%s", fixp, S_GET_NAME (s), + s->bsym->section->name); + if (s->bsym->flags & BSF_SECTION_SYM) + { + fprintf (stream, " section sym"); + if (S_GET_VALUE (s)) + fprintf (stream, "+%x", S_GET_VALUE (s)); + } + else + fprintf (stream, "+%x", S_GET_VALUE (s)); + fprintf (stream, ")+%x\n", fixp->fx_offset); + } + else + fprintf (stream, " %08x: type %d no sym\n", fixp, fixp->fx_r_type); + fixp = fixp->fx_next; + } +} +#else +#define dump_section_relocs(ABFD,SEC,STREAM) ((void) 0) +#endif + +#ifndef EMIT_SECTION_SYMBOLS +#define EMIT_SECTION_SYMBOLS 1 +#endif + +static void +adjust_reloc_syms (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + segment_info_type *seginfo = seg_info (sec); + fixS *fixp; + + if (seginfo == NULL) + return; + + dump_section_relocs (abfd, sec, stderr); + + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + if (fixp->fx_done) + /* ignore it */; + else if (fixp->fx_addsy) + { + symbolS *sym; + asection *symsec; + + reduce_fixup: + +#ifdef DEBUG5 + fprintf (stderr, "\n\nadjusting fixup:\n"); + print_fixup (fixp); +#endif + + sym = fixp->fx_addsy; + + /* All symbols should have already been resolved at this + point. It is possible to see unresolved expression + symbols, though, since they are not in the regular symbol + table. */ + if (sym != NULL && ! sym->sy_resolved) + resolve_symbol_value (sym); + if (fixp->fx_subsy != NULL && ! fixp->fx_subsy->sy_resolved) + resolve_symbol_value (fixp->fx_subsy); + + /* If this symbol is equated to an undefined symbol, convert + the fixup to being against that symbol. */ + if (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + { + fixp->fx_offset += sym->sy_value.X_add_number; + sym = sym->sy_value.X_add_symbol; + fixp->fx_addsy = sym; + } + + symsec = S_GET_SEGMENT (sym); + + if (sym != NULL && sym->sy_mri_common) + { + /* These symbols are handled specially in fixup_segment. */ + goto done; + } + + if (bfd_is_abs_section (symsec)) + { + /* The fixup_segment routine will not use this symbol in a + relocation unless TC_FORCE_RELOCATION returns 1. */ + if (TC_FORCE_RELOCATION (fixp)) + { + fixp->fx_addsy->sy_used_in_reloc = 1; +#ifdef UNDEFINED_DIFFERENCE_OK + if (fixp->fx_subsy != NULL) + fixp->fx_subsy->sy_used_in_reloc = 1; +#endif + } + goto done; + } + + /* If it's one of these sections, assume the symbol is + definitely going to be output. The code in + md_estimate_size_before_relax in tc-mips.c uses this test + as well, so if you change this code you should look at that + code. */ + if (bfd_is_und_section (symsec) + || bfd_is_com_section (symsec)) + { + fixp->fx_addsy->sy_used_in_reloc = 1; +#ifdef UNDEFINED_DIFFERENCE_OK + /* We have the difference of an undefined symbol and some + other symbol. Make sure to mark the other symbol as used + in a relocation so that it will always be output. */ + if (fixp->fx_subsy) + fixp->fx_subsy->sy_used_in_reloc = 1; +#endif + goto done; + } + + /* Don't try to reduce relocs which refer to .linkonce + sections. It can lead to confusion when a debugging + section refers to a .linkonce section. I hope this will + always be correct. */ + if (symsec != sec) + { + boolean linkonce; + + linkonce = false; +#ifdef BFD_ASSEMBLER + if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE) + != 0) + linkonce = true; +#endif +#ifdef OBJ_ELF + /* The GNU toolchain uses an extension for ELF: a section + beginning with the magic string .gnu.linkonce is a + linkonce section. */ + if (strncmp (segment_name (symsec), ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0) + linkonce = true; +#endif + + if (linkonce) + { + fixp->fx_addsy->sy_used_in_reloc = 1; +#ifdef UNDEFINED_DIFFERENCE_OK + if (fixp->fx_subsy != NULL) + fixp->fx_subsy->sy_used_in_reloc = 1; +#endif + goto done; + } + } + + /* Since we're reducing to section symbols, don't attempt to reduce + anything that's already using one. */ + if (sym->bsym->flags & BSF_SECTION_SYM) + { + fixp->fx_addsy->sy_used_in_reloc = 1; + goto done; + } + + /* Is there some other reason we can't adjust this one? (E.g., + call/bal links in i960-bout symbols.) */ +#ifdef obj_fix_adjustable + if (! obj_fix_adjustable (fixp)) + { + fixp->fx_addsy->sy_used_in_reloc = 1; + goto done; + } +#endif + + /* Is there some other (target cpu dependent) reason we can't adjust + this one? (E.g. relocations involving function addresses on + the PA. */ +#ifdef tc_fix_adjustable + if (! tc_fix_adjustable (fixp)) + { + fixp->fx_addsy->sy_used_in_reloc = 1; + goto done; + } +#endif + + /* If the section symbol isn't going to be output, the relocs + at least should still work. If not, figure out what to do + when we run into that case. + + We refetch the segment when calling section_symbol, rather + than using symsec, because S_GET_VALUE may wind up changing + the section when it calls resolve_symbol_value. */ + fixp->fx_offset += S_GET_VALUE (sym); + fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym)); + fixp->fx_addsy->sy_used_in_reloc = 1; + + done: + ; + } +#if 1/*def RELOC_REQUIRES_SYMBOL*/ + else + { + /* There was no symbol required by this relocation. However, + BFD doesn't really handle relocations without symbols well. + (At least, the COFF support doesn't.) So for now we fake up + a local symbol in the absolute section. */ + + fixp->fx_addsy = section_symbol (absolute_section); +/* fixp->fx_addsy->sy_used_in_reloc = 1; */ + } +#endif + + dump_section_relocs (abfd, sec, stderr); +} + +static void +write_relocs (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + segment_info_type *seginfo = seg_info (sec); + int i; + unsigned int n; + arelent **relocs; + fixS *fixp; + char *err; + + /* If seginfo is NULL, we did not create this section; don't do + anything with it. */ + if (seginfo == NULL) + return; + + fixup_segment (seginfo->fix_root, sec); + + n = 0; + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + n++; + +#ifndef RELOC_EXPANSION_POSSIBLE + /* Set up reloc information as well. */ + relocs = (arelent **) xmalloc (n * sizeof (arelent *)); + memset ((char*)relocs, 0, n * sizeof (arelent*)); + + i = 0; + for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) + { + arelent *reloc; + bfd_reloc_status_type s; + symbolS *sym; + + if (fixp->fx_done) + { + n--; + continue; + } + + /* If this is an undefined symbol which was equated to another + symbol, then use generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + { + symbolS *n; + + /* We must avoid looping, as that can occur with a badly + written program. */ + n = sym->sy_value.X_add_symbol; + if (n == sym) + break; + fixp->fx_offset += sym->sy_value.X_add_number; + sym = n; + } + fixp->fx_addsy = sym; + + reloc = tc_gen_reloc (sec, fixp); + if (!reloc) + { + n--; + continue; + } + +#if 0 + /* This test is triggered inappropriately for the SH. */ + if (fixp->fx_where + fixp->fx_size + > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) + abort (); +#endif + + s = bfd_install_relocation (stdoutput, reloc, + fixp->fx_frag->fr_literal, + fixp->fx_frag->fr_address, + sec, &err); + switch (s) + { + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow"); + break; + default: + as_fatal ("%s:%u: bad return from bfd_install_relocation", + fixp->fx_file, fixp->fx_line); + } + relocs[i++] = reloc; + } +#else + n = n * MAX_RELOC_EXPANSION; + /* Set up reloc information as well. */ + relocs = (arelent **) xmalloc (n * sizeof (arelent *)); + + i = 0; + for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) + { + arelent **reloc; + char *data; + bfd_reloc_status_type s; + symbolS *sym; + int j; + + if (fixp->fx_done) + { + n--; + continue; + } + + /* If this is an undefined symbol which was equated to another + symbol, then use generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (sym->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) + sym = sym->sy_value.X_add_symbol; + fixp->fx_addsy = sym; + + reloc = tc_gen_reloc (sec, fixp); + + for (j = 0; reloc[j]; j++) + { + relocs[i++] = reloc[j]; + assert(i <= n); + } + data = fixp->fx_frag->fr_literal + fixp->fx_where; + if (fixp->fx_where + fixp->fx_size + > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) + as_bad_where (fixp->fx_file, fixp->fx_line, + "internal error: fixup not contained within frag"); + for (j = 0; reloc[j]; j++) + { + s = bfd_install_relocation (stdoutput, reloc[j], + fixp->fx_frag->fr_literal, + fixp->fx_frag->fr_address, + sec, &err); + switch (s) + { + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + as_bad_where (fixp->fx_file, fixp->fx_line, + "relocation overflow"); + break; + default: + as_fatal ("%s:%u: bad return from bfd_install_relocation", + fixp->fx_file, fixp->fx_line); + } + } + } + n = i; +#endif + +#ifdef DEBUG4 + { + int i, j, nsyms; + asymbol **sympp; + sympp = bfd_get_outsymbols (stdoutput); + nsyms = bfd_get_symcount (stdoutput); + for (i = 0; i < n; i++) + if (((*relocs[i]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) + { + for (j = 0; j < nsyms; j++) + if (sympp[j] == *relocs[i]->sym_ptr_ptr) + break; + if (j == nsyms) + abort (); + } + } +#endif + + if (n) + bfd_set_reloc (stdoutput, sec, relocs, n); + else + bfd_set_section_flags (abfd, sec, + (bfd_get_section_flags (abfd, sec) + & (flagword) ~SEC_RELOC)); + +#ifdef DEBUG3 + { + int i; + arelent *r; + asymbol *s; + fprintf (stderr, "relocs for sec %s\n", sec->name); + for (i = 0; i < n; i++) + { + r = relocs[i]; + s = *r->sym_ptr_ptr; + fprintf (stderr, " reloc %2d @%08x off %4x : sym %-10s addend %x\n", + i, r, r->address, s->name, r->addend); + } + } +#endif +} + +static void +write_contents (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + segment_info_type *seginfo = seg_info (sec); + unsigned long offset = 0; + fragS *f; + + /* Write out the frags. */ + if (seginfo == NULL + || ! (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)) + return; + + for (f = seginfo->frchainP->frch_root; + f; + f = f->fr_next) + { + int x; + unsigned long fill_size; + char *fill_literal; + long count; + + assert (f->fr_type == rs_fill); + if (f->fr_fix) + { + x = bfd_set_section_contents (stdoutput, sec, + f->fr_literal, (file_ptr) offset, + (bfd_size_type) f->fr_fix); + if (x == false) + { + bfd_perror (stdoutput->filename); + as_perror ("FATAL: Can't write %s", stdoutput->filename); + exit (EXIT_FAILURE); + } + offset += f->fr_fix; + } + fill_literal = f->fr_literal + f->fr_fix; + fill_size = f->fr_var; + count = f->fr_offset; + assert (count >= 0); + if (fill_size && count) + { + char buf[256]; + if (fill_size > sizeof(buf)) + { + /* Do it the old way. Can this ever happen? */ + while (count--) + { + x = bfd_set_section_contents (stdoutput, sec, + fill_literal, + (file_ptr) offset, + (bfd_size_type) fill_size); + if (x == false) + { + bfd_perror (stdoutput->filename); + as_perror ("FATAL: Can't write %s", stdoutput->filename); + exit (EXIT_FAILURE); + } + offset += fill_size; + } + } + else + { + /* Build a buffer full of fill objects and output it as + often as necessary. This saves on the overhead of + potentially lots of bfd_set_section_contents calls. */ + int n_per_buf, i; + if (fill_size == 1) + { + n_per_buf = sizeof (buf); + memset (buf, *fill_literal, n_per_buf); + } + else + { + char *bufp; + n_per_buf = sizeof(buf)/fill_size; + for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size) + memcpy(bufp, fill_literal, fill_size); + } + for (; count > 0; count -= n_per_buf) + { + n_per_buf = n_per_buf > count ? count : n_per_buf; + x = bfd_set_section_contents (stdoutput, sec, + buf, (file_ptr) offset, + (bfd_size_type) n_per_buf * fill_size); + if (x != true) + as_fatal ("Cannot write to output file."); + offset += n_per_buf * fill_size; + } + } + } + } +} +#endif + +#if defined(BFD_ASSEMBLER) || (!defined (BFD) && !defined(OBJ_AOUT)) +static void +merge_data_into_text () +{ +#if defined(BFD_ASSEMBLER) || defined(MANY_SEGMENTS) + seg_info (text_section)->frchainP->frch_last->fr_next = + seg_info (data_section)->frchainP->frch_root; + seg_info (text_section)->frchainP->frch_last = + seg_info (data_section)->frchainP->frch_last; + seg_info (data_section)->frchainP = 0; +#else + fixS *tmp; + + text_last_frag->fr_next = data_frag_root; + text_last_frag = data_last_frag; + data_last_frag = NULL; + data_frag_root = NULL; + if (text_fix_root) + { + for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);; + tmp->fx_next = data_fix_root; + text_fix_tail = data_fix_tail; + } + else + text_fix_root = data_fix_root; + data_fix_root = NULL; +#endif +} +#endif /* BFD_ASSEMBLER || (! BFD && ! OBJ_AOUT) */ + +#if !defined (BFD_ASSEMBLER) && !defined (BFD) +static void +relax_and_size_all_segments () +{ + fragS *fragP; + + relax_segment (text_frag_root, SEG_TEXT); + relax_segment (data_frag_root, SEG_DATA); + relax_segment (bss_frag_root, SEG_BSS); + /* + * Now the addresses of frags are correct within the segment. + */ + + know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0); + H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address); + text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers); + + /* + * Join the 2 segments into 1 huge segment. + * To do this, re-compute every rn_address in the SEG_DATA frags. + * Then join the data frags after the text frags. + * + * Determine a_data [length of data segment]. + */ + if (data_frag_root) + { + register relax_addressT slide; + + know ((text_last_frag->fr_type == rs_fill) && (text_last_frag->fr_offset == 0)); + + H_SET_DATA_SIZE (&headers, data_last_frag->fr_address); + data_last_frag->fr_address = H_GET_DATA_SIZE (&headers); + slide = H_GET_TEXT_SIZE (&headers); /* & in file of the data segment. */ +#ifdef OBJ_BOUT +#define RoundUp(N,S) (((N)+(S)-1)&-(S)) + /* For b.out: If the data section has a strict alignment + requirement, its load address in the .o file will be + rounded up from the size of the text section. These + two values are *not* the same! Similarly for the bss + section.... */ + slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]); +#endif + + for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) + { + fragP->fr_address += slide; + } /* for each data frag */ + + know (text_last_frag != 0); + text_last_frag->fr_next = data_frag_root; + } + else + { + H_SET_DATA_SIZE (&headers, 0); + } + +#ifdef OBJ_BOUT + /* See above comments on b.out data section address. */ + { + long bss_vma; + if (data_last_frag == 0) + bss_vma = H_GET_TEXT_SIZE (&headers); + else + bss_vma = data_last_frag->fr_address; + bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]); + bss_address_frag.fr_address = bss_vma; + } +#else /* ! OBJ_BOUT */ + bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers)); + +#endif /* ! OBJ_BOUT */ + + /* Slide all the frags */ + if (bss_frag_root) + { + relax_addressT slide = bss_address_frag.fr_address; + + for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next) + { + fragP->fr_address += slide; + } /* for each bss frag */ + } + + if (bss_last_frag) + H_SET_BSS_SIZE (&headers, + bss_last_frag->fr_address - bss_frag_root->fr_address); + else + H_SET_BSS_SIZE (&headers, 0); +} +#endif /* ! BFD_ASSEMBLER && ! BFD */ + +#if defined (BFD_ASSEMBLER) || !defined (BFD) + +#ifdef BFD_ASSEMBLER +static void +set_symtab () +{ + int nsyms; + asymbol **asympp; + symbolS *symp; + boolean result; + extern PTR bfd_alloc PARAMS ((bfd *, size_t)); + + /* Count symbols. We can't rely on a count made by the loop in + write_object_file, because *_frob_file may add a new symbol or + two. */ + nsyms = 0; + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + nsyms++; + + if (nsyms) + { + int i; + + asympp = (asymbol **) bfd_alloc (stdoutput, + nsyms * sizeof (asymbol *)); + symp = symbol_rootP; + for (i = 0; i < nsyms; i++, symp = symbol_next (symp)) + { + asympp[i] = symp->bsym; + symp->written = 1; + } + } + else + asympp = 0; + result = bfd_set_symtab (stdoutput, asympp, nsyms); + assert (result == true); + symbol_table_frozen = 1; +} +#endif + +void +write_object_file () +{ + struct frchain *frchainP; /* Track along all frchains. */ +#if ! defined (BFD_ASSEMBLER) || ! defined (WORKING_DOT_WORD) + fragS *fragP; /* Track along all frags. */ +#endif + + /* Do we really want to write it? */ + { + int n_warns, n_errs; + n_warns = had_warnings (); + n_errs = had_errors (); + /* The -Z flag indicates that an object file should be generated, + regardless of warnings and errors. */ + if (flag_always_generate_output) + { + if (n_warns || n_errs) + as_warn ("%d error%s, %d warning%s, generating bad object file.\n", + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + else + { + if (n_errs) + as_fatal ("%d error%s, %d warning%s, no object file generated.\n", + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + } + +#ifdef OBJ_VMS + /* Under VMS we try to be compatible with VAX-11 "C". Thus, we call + a routine to check for the definition of the procedure "_main", + and if so -- fix it up so that it can be program entry point. */ + vms_check_for_main (); +#endif /* OBJ_VMS */ + + /* After every sub-segment, we fake an ".align ...". This conforms to + BSD4.2 brane-damage. We then fake ".fill 0" because that is the kind of + frag that requires least thought. ".align" frags like to have a + following frag since that makes calculating their intended length + trivial. + + @@ Is this really necessary?? */ +#ifndef SUB_SEGMENT_ALIGN +#ifdef BFD_ASSEMBLER +#define SUB_SEGMENT_ALIGN(SEG) (0) +#else +#define SUB_SEGMENT_ALIGN(SEG) (2) +#endif +#endif + for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) + { + subseg_set (frchainP->frch_seg, frchainP->frch_subseg); + frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE, 0); + /* frag_align will have left a new frag. + Use this last frag for an empty ".fill". + + For this segment ... + Create a last frag. Do not leave a "being filled in frag". */ + frag_wane (frag_now); + frag_now->fr_fix = 0; + know (frag_now->fr_next == NULL); + } + + /* From now on, we don't care about sub-segments. Build one frag chain + for each segment. Linked thru fr_next. */ + +#ifdef BFD_ASSEMBLER + /* Remove the sections created by gas for its own purposes. */ + { + asection **seclist, *sec; + int i; + + seclist = &stdoutput->sections; + while (seclist && *seclist) + { + sec = *seclist; + while (sec == reg_section || sec == expr_section) + { + sec = sec->next; + *seclist = sec; + stdoutput->section_count--; + if (!sec) + break; + } + if (*seclist) + seclist = &(*seclist)->next; + } + i = 0; + bfd_map_over_sections (stdoutput, renumber_sections, &i); + } + + bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0); +#else + remove_subsegs (frchain_root, SEG_TEXT, &text_frag_root, &text_last_frag); + remove_subsegs (data0_frchainP, SEG_DATA, &data_frag_root, &data_last_frag); + remove_subsegs (bss0_frchainP, SEG_BSS, &bss_frag_root, &bss_last_frag); +#endif + + /* We have two segments. If user gave -R flag, then we must put the + data frags into the text segment. Do this before relaxing so + we know to take advantage of -R and make shorter addresses. */ +#if !defined (OBJ_AOUT) || defined (BFD_ASSEMBLER) + if (flag_readonly_data_in_text) + { + merge_data_into_text (); + } +#endif + +#ifdef BFD_ASSEMBLER + bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0); +#else + relax_and_size_all_segments (); +#endif /* BFD_ASSEMBLER */ + +#ifndef BFD_ASSEMBLER + /* + * + * Crawl the symbol chain. + * + * For each symbol whose value depends on a frag, take the address of + * that frag and subsume it into the value of the symbol. + * After this, there is just one way to lookup a symbol value. + * Values are left in their final state for object file emission. + * We adjust the values of 'L' local symbols, even if we do + * not intend to emit them to the object file, because their values + * are needed for fix-ups. + * + * Unless we saw a -L flag, remove all symbols that begin with 'L' + * from the symbol chain. (They are still pointed to by the fixes.) + * + * Count the remaining symbols. + * Assign a symbol number to each symbol. + * Count the number of string-table chars we will emit. + * Put this info into the headers as appropriate. + * + */ + know (zero_address_frag.fr_address == 0); + string_byte_count = sizeof (string_byte_count); + + obj_crawl_symbol_chain (&headers); + + if (string_byte_count == sizeof (string_byte_count)) + string_byte_count = 0; + + H_SET_STRING_SIZE (&headers, string_byte_count); + + /* + * Addresses of frags now reflect addresses we use in the object file. + * Symbol values are correct. + * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. + * Also converting any machine-dependent frags using md_convert_frag(); + */ + subseg_change (SEG_TEXT, 0); + + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + { + cvt_frag_to_fill (&headers, SEG_TEXT, fragP); + + /* Some assert macros don't work with # directives mixed in. */ +#ifndef NDEBUG + if (!(fragP->fr_next == NULL +#ifdef OBJ_BOUT + || fragP->fr_next == data_frag_root +#endif + || ((fragP->fr_next->fr_address - fragP->fr_address) + == (fragP->fr_fix + fragP->fr_offset * fragP->fr_var)))) + abort (); +#endif + } +#endif /* ! BFD_ASSEMBLER */ + +#ifndef WORKING_DOT_WORD + { + struct broken_word *lie; + struct broken_word **prevP; + + prevP = &broken_words; + for (lie = broken_words; lie; lie = lie->next_broken_word) + if (!lie->added) + { + expressionS exp; + + exp.X_op = O_subtract; + exp.X_add_symbol = lie->add; + exp.X_op_symbol = lie->sub; + exp.X_add_number = lie->addnum; +#ifdef BFD_ASSEMBLER +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp); +#else + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, BFD_RELOC_16); +#endif +#else +#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE) + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, NO_RELOC); +#else +#ifdef TC_NS32K + fix_new_ns32k_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, 0, 2, 0, 0); +#else + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, 0); +#endif /* TC_NS32K */ +#endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */ +#endif /* BFD_ASSEMBLER */ + *prevP = lie->next_broken_word; + } + else + prevP = &(lie->next_broken_word); + + for (lie = broken_words; lie;) + { + struct broken_word *untruth; + char *table_ptr; + addressT table_addr; + addressT from_addr, to_addr; + int n, m; + + fragP = lie->dispfrag; + + /* Find out how many broken_words go here. */ + n = 0; + for (untruth = lie; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word) + if (untruth->added == 1) + n++; + + table_ptr = lie->dispfrag->fr_opcode; + table_addr = lie->dispfrag->fr_address + (table_ptr - lie->dispfrag->fr_literal); + /* Create the jump around the long jumps. This is a short + jump from table_ptr+0 to table_ptr+n*long_jump_size. */ + from_addr = table_addr; + to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; + md_create_short_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add); + table_ptr += md_short_jump_size; + table_addr += md_short_jump_size; + + for (m = 0; lie && lie->dispfrag == fragP; m++, lie = lie->next_broken_word) + { + if (lie->added == 2) + continue; + /* Patch the jump table */ + /* This is the offset from ??? to table_ptr+0 */ + to_addr = table_addr - S_GET_VALUE (lie->sub); +#ifdef BFD_ASSEMBLER + to_addr -= lie->sub->sy_frag->fr_address; +#endif + md_number_to_chars (lie->word_goes_here, to_addr, 2); + for (untruth = lie->next_broken_word; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word) + { + if (untruth->use_jump == lie) + md_number_to_chars (untruth->word_goes_here, to_addr, 2); + } + + /* Install the long jump */ + /* this is a long jump from table_ptr+0 to the final target */ + from_addr = table_addr; + to_addr = S_GET_VALUE (lie->add) + lie->addnum; +#ifdef BFD_ASSEMBLER + to_addr += lie->add->sy_frag->fr_address; +#endif + md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add); + table_ptr += md_long_jump_size; + table_addr += md_long_jump_size; + } + } + } +#endif /* not WORKING_DOT_WORD */ + +#ifndef BFD_ASSEMBLER +#ifndef OBJ_VMS + { /* not vms */ + char *the_object_file; + long object_file_size; + /* + * Scan every FixS performing fixups. We had to wait until now to do + * this because md_convert_frag() may have made some fixSs. + */ + int trsize, drsize; + + subseg_change (SEG_TEXT, 0); + trsize = md_reloc_size * fixup_segment (text_fix_root, SEG_TEXT); + subseg_change (SEG_DATA, 0); + drsize = md_reloc_size * fixup_segment (data_fix_root, SEG_DATA); + H_SET_RELOCATION_SIZE (&headers, trsize, drsize); + + /* FIXME move this stuff into the pre-write-hook */ + H_SET_MAGIC_NUMBER (&headers, magic_number_for_object_file); + H_SET_ENTRY_POINT (&headers, 0); + + obj_pre_write_hook (&headers); /* extra coff stuff */ + + object_file_size = H_GET_FILE_SIZE (&headers); + next_object_file_charP = the_object_file = xmalloc (object_file_size); + + output_file_create (out_file_name); + + obj_header_append (&next_object_file_charP, &headers); + + know ((next_object_file_charP - the_object_file) == H_GET_HEADER_SIZE (&headers)); + + /* + * Emit code. + */ + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + { + register long count; + register char *fill_literal; + register long fill_size; + + PROGRESS (1); + know (fragP->fr_type == rs_fill); + append (&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix); + fill_literal = fragP->fr_literal + fragP->fr_fix; + fill_size = fragP->fr_var; + know (fragP->fr_offset >= 0); + + for (count = fragP->fr_offset; count; count--) + { + append (&next_object_file_charP, fill_literal, (unsigned long) fill_size); + } /* for each */ + + } /* for each code frag. */ + + know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers))); + + /* + * Emit relocations. + */ + obj_emit_relocations (&next_object_file_charP, text_fix_root, (relax_addressT) 0); + know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers))); +#ifdef TC_I960 + /* Make addresses in data relocation directives relative to beginning of + * first data fragment, not end of last text fragment: alignment of the + * start of the data segment may place a gap between the segments. + */ + obj_emit_relocations (&next_object_file_charP, data_fix_root, data0_frchainP->frch_root->fr_address); +#else /* TC_I960 */ + obj_emit_relocations (&next_object_file_charP, data_fix_root, text_last_frag->fr_address); +#endif /* TC_I960 */ + + know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers) + H_GET_DATA_RELOCATION_SIZE (&headers))); + + /* + * Emit line number entries. + */ + OBJ_EMIT_LINENO (&next_object_file_charP, lineno_rootP, the_object_file); + know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers) + H_GET_DATA_RELOCATION_SIZE (&headers) + H_GET_LINENO_SIZE (&headers))); + + /* + * Emit symbols. + */ + obj_emit_symbols (&next_object_file_charP, symbol_rootP); + know ((next_object_file_charP - the_object_file) == (H_GET_HEADER_SIZE (&headers) + H_GET_TEXT_SIZE (&headers) + H_GET_DATA_SIZE (&headers) + H_GET_TEXT_RELOCATION_SIZE (&headers) + H_GET_DATA_RELOCATION_SIZE (&headers) + H_GET_LINENO_SIZE (&headers) + H_GET_SYMBOL_TABLE_SIZE (&headers))); + + /* + * Emit strings. + */ + + if (string_byte_count > 0) + { + obj_emit_strings (&next_object_file_charP); + } /* only if we have a string table */ + +#ifdef BFD_HEADERS + bfd_seek (stdoutput, 0, 0); + bfd_write (the_object_file, 1, object_file_size, stdoutput); +#else + + /* Write the data to the file */ + output_file_append (the_object_file, object_file_size, out_file_name); + free (the_object_file); +#endif + } /* non vms output */ +#else /* OBJ_VMS */ + /* + * Now do the VMS-dependent part of writing the object file + */ + vms_write_object_file (H_GET_TEXT_SIZE (&headers), + H_GET_DATA_SIZE (&headers), + H_GET_BSS_SIZE (&headers), + text_frag_root, data_frag_root); +#endif /* OBJ_VMS */ +#else /* BFD_ASSEMBLER */ + + /* Resolve symbol values. This needs to be done before processing + the relocations. */ + if (symbol_rootP) + { + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + if (!symp->sy_resolved) + resolve_symbol_value (symp); + } + + PROGRESS (1); + +#ifdef tc_frob_file_before_adjust + tc_frob_file_before_adjust (); +#endif +#ifdef obj_frob_file_before_adjust + obj_frob_file_before_adjust (); +#endif + + bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0); + + /* Set up symbol table, and write it out. */ + if (symbol_rootP) + { + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + { + int punt = 0; + const char *name; + + if (symp->sy_mri_common) + { + if (S_IS_EXTERNAL (symp)) + as_bad ("%s: global symbols not supported in common sections", + S_GET_NAME (symp)); + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + continue; + } + + name = S_GET_NAME (symp); + if (name) + { + const char *name2 = decode_local_label_name ((char *)S_GET_NAME (symp)); + /* They only differ if `name' is a fb or dollar local + label name. */ + if (name2 != name && ! S_IS_DEFINED (symp)) + as_bad ("local label %s is not defined", name2); + } + + /* Do it again, because adjust_reloc_syms might introduce + more symbols. They'll probably only be section symbols, + but they'll still need to have the values computed. */ + if (! symp->sy_resolved) + { + if (symp->sy_value.X_op == O_constant) + { + /* This is the normal case; skip the call. */ + S_SET_VALUE (symp, + (S_GET_VALUE (symp) + + symp->sy_frag->fr_address)); + symp->sy_resolved = 1; + } + else + resolve_symbol_value (symp); + } + + /* Skip symbols which were equated to undefined or common + symbols. */ + if (symp->sy_value.X_op == O_symbol + && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp))) + { + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + continue; + } + + /* So far, common symbols have been treated like undefined symbols. + Put them in the common section now. */ + if (S_IS_DEFINED (symp) == 0 + && S_GET_VALUE (symp) != 0) + S_SET_SEGMENT (symp, bfd_com_section_ptr); +#if 0 + printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n", + S_GET_NAME (symp), symp, + S_GET_VALUE (symp), + symp->bsym->flags, + segment_name (symp->bsym->section)); +#endif + +#ifdef obj_frob_symbol + obj_frob_symbol (symp, punt); +#endif +#ifdef tc_frob_symbol + if (! punt || symp->sy_used_in_reloc) + tc_frob_symbol (symp, punt); +#endif + + /* If we don't want to keep this symbol, splice it out of + the chain now. If EMIT_SECTION_SYMBOLS is 0, we never + want section symbols. Otherwise, we skip local symbols + and symbols that the frob_symbol macros told us to punt, + but we keep such symbols if they are used in relocs. */ + if ((! EMIT_SECTION_SYMBOLS + && (symp->bsym->flags & BSF_SECTION_SYM) != 0) + /* Note that S_IS_EXTERN and S_IS_LOCAL are not always + opposites. Sometimes the former checks flags and the + latter examines the name... */ + || (!S_IS_EXTERN (symp) + && (S_IS_LOCAL (symp) || punt) + && ! symp->sy_used_in_reloc)) + { + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + /* After symbol_remove, symbol_next(symp) still returns + the one that came after it in the chain. So we don't + need to do any extra cleanup work here. */ + + continue; + } + + /* Make sure we really got a value for the symbol. */ + if (! symp->sy_resolved) + { + as_bad ("can't resolve value for symbol \"%s\"", + S_GET_NAME (symp)); + symp->sy_resolved = 1; + } + + /* Set the value into the BFD symbol. Up til now the value + has only been kept in the gas symbolS struct. */ + symp->bsym->value = S_GET_VALUE (symp); + } + } + + PROGRESS (1); + + /* Now do any format-specific adjustments to the symbol table, such + as adding file symbols. */ +#ifdef tc_adjust_symtab + tc_adjust_symtab (); +#endif +#ifdef obj_adjust_symtab + obj_adjust_symtab (); +#endif + + /* Now that all the sizes are known, and contents correct, we can + start writing to the file. */ + set_symtab (); + + /* If *_frob_file changes the symbol value at this point, it is + responsible for moving the changed value into symp->bsym->value + as well. Hopefully all symbol value changing can be done in + *_frob_symbol. */ +#ifdef tc_frob_file + tc_frob_file (); +#endif +#ifdef obj_frob_file + obj_frob_file (); +#endif + + bfd_map_over_sections (stdoutput, write_relocs, (char *) 0); + +#ifdef tc_frob_file_after_relocs + tc_frob_file_after_relocs (); +#endif +#ifdef obj_frob_file_after_relocs + obj_frob_file_after_relocs (); +#endif + + bfd_map_over_sections (stdoutput, write_contents, (char *) 0); +#endif /* BFD_ASSEMBLER */ +} +#endif /* ! BFD */ + +/* + * relax_segment() + * + * Now we have a segment, not a crowd of sub-segments, we can make fr_address + * values. + * + * Relax the frags. + * + * After this, all frags in this segment have addresses that are correct + * within the segment. Since segments live in different file addresses, + * these frag addresses may not be the same as final object-file addresses. + */ + +#ifdef TC_GENERIC_RELAX_TABLE + +static int is_dnrange PARAMS ((fragS *, fragS *)); + +/* Subroutines of relax_segment. */ +static int +is_dnrange (f1, f2) + fragS *f1; + fragS *f2; +{ + for (; f1; f1 = f1->fr_next) + if (f1->fr_next == f2) + return 1; + return 0; +} + +/* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE. */ + +long +relax_frag (fragP, stretch) + fragS *fragP; + long stretch; +{ + const relax_typeS *this_type; + const relax_typeS *start_type; + relax_substateT next_state; + relax_substateT this_state; + long aim, target, growth; + symbolS *symbolP = fragP->fr_symbol; + long offset = fragP->fr_offset; + /* Recompute was_address by undoing "+= stretch" done by relax_segment. */ + unsigned long was_address = fragP->fr_address - stretch; + unsigned long address = fragP->fr_address; + const relax_typeS *table = TC_GENERIC_RELAX_TABLE; + + this_state = fragP->fr_subtype; + start_type = this_type = table + this_state; + target = offset; + + if (symbolP) + { +#ifndef DIFF_EXPR_OK +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_BSS) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT)); +#endif + know (symbolP->sy_frag); +#endif + know (!(S_GET_SEGMENT (symbolP) == absolute_section) + || symbolP->sy_frag == &zero_address_frag); + target += + S_GET_VALUE (symbolP) + + symbolP->sy_frag->fr_address; + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. + + Beware zero-length frags. + + There should be a faster way to do this. */ + + if (symbolP->sy_frag->fr_address >= was_address + && is_dnrange (fragP, symbolP->sy_frag)) + { + target += stretch; + } + } + + aim = target - address - fragP->fr_fix; +#ifdef TC_PCREL_ADJUST + /* Currently only the ns32k family needs this */ + aim += TC_PCREL_ADJUST(fragP); +/*#else*/ + /* This machine doesn't want to use pcrel_adjust. + In that case, pcrel_adjust should be zero. */ +/* assert (fragP->fr_targ.ns32k.pcrel_adjust == 0);*/ +#endif +#ifdef md_prepare_relax_scan /* formerly called M68K_AIM_KLUDGE */ + md_prepare_relax_scan (fragP, address, aim, this_state, this_type); +#endif + + if (aim < 0) + { + /* Look backwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim >= this_type->rlx_backward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + else + { + /* Look forwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim <= this_type->rlx_forward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + + growth = this_type->rlx_length - start_type->rlx_length; + if (growth != 0) + fragP->fr_subtype = this_state; + return growth; +} + +#endif /* defined (TC_GENERIC_RELAX_TABLE) */ + +/* Relax_align. Advance location counter to next address that has 'alignment' + lowest order bits all 0s, return size of adjustment made. */ +static relax_addressT +relax_align (address, alignment) + register relax_addressT address; /* Address now. */ + register int alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~((~0) << alignment); + new_address = (address + mask) & (~mask); +#ifdef LINKER_RELAXING_SHRINKS_ONLY + if (linkrelax) + /* We must provide lots of padding, so the linker can discard it + when needed. The linker will not add extra space, ever. */ + new_address += (1 << alignment); +#endif + return (new_address - address); +} + +void +relax_segment (segment_frag_root, segment) + struct frag *segment_frag_root; + segT segment; +{ + register struct frag *fragP; + register relax_addressT address; +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS); +#endif + /* In case md_estimate_size_before_relax() wants to make fixSs. */ + subseg_change (segment, 0); + + /* For each frag in segment: count and store (a 1st guess of) + fr_address. */ + address = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) + { + fragP->fr_address = address; + address += fragP->fr_fix; + + switch (fragP->fr_type) + { + case rs_fill: + address += fragP->fr_offset * fragP->fr_var; + break; + + case rs_align: + case rs_align_code: + { + addressT offset = relax_align (address, (int) fragP->fr_offset); + + if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype) + offset = 0; + + if (offset % fragP->fr_var != 0) + { + as_bad ("alignment padding (%lu bytes) not a multiple of %ld", + (unsigned long) offset, (long) fragP->fr_var); + offset -= (offset % fragP->fr_var); + } + + address += offset; + } + break; + + case rs_org: + case rs_space: + /* Assume .org is nugatory. It will grow with 1st relax. */ + break; + + case rs_machine_dependent: + address += md_estimate_size_before_relax (fragP, segment); + break; + +#ifndef WORKING_DOT_WORD + /* Broken words don't concern us yet */ + case rs_broken_word: + break; +#endif + + default: + BAD_CASE (fragP->fr_type); + break; + } /* switch(fr_type) */ + } /* for each frag in the segment */ + + /* Do relax(). */ + { + long stretch; /* May be any size, 0 or negative. */ + /* Cumulative number of addresses we have */ + /* relaxed this pass. */ + /* We may have relaxed more than one address. */ + long stretched; /* Have we stretched on this pass? */ + /* This is 'cuz stretch may be zero, when, in fact some piece of code + grew, and another shrank. If a branch instruction doesn't fit anymore, + we could be scrod. */ + + do + { + stretch = stretched = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) + { + long growth = 0; + addressT was_address; + offsetT offset; + symbolS *symbolP; + + was_address = fragP->fr_address; + address = fragP->fr_address += stretch; + symbolP = fragP->fr_symbol; + offset = fragP->fr_offset; + + switch (fragP->fr_type) + { + case rs_fill: /* .fill never relaxes. */ + growth = 0; + break; + +#ifndef WORKING_DOT_WORD + /* JF: This is RMS's idea. I do *NOT* want to be blamed + for it I do not want to write it. I do not want to have + anything to do with it. This is not the proper way to + implement this misfeature. */ + case rs_broken_word: + { + struct broken_word *lie; + struct broken_word *untruth; + + /* Yes this is ugly (storing the broken_word pointer + in the symbol slot). Still, this whole chunk of + code is ugly, and I don't feel like doing anything + about it. Think of it as stubbornness in action. */ + growth = 0; + for (lie = (struct broken_word *) (fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie = lie->next_broken_word) + { + + if (lie->added) + continue; + + offset = (lie->add->sy_frag->fr_address + + S_GET_VALUE (lie->add) + + lie->addnum + - (lie->sub->sy_frag->fr_address + + S_GET_VALUE (lie->sub))); + if (offset <= -32768 || offset >= 32767) + { + if (flag_warn_displacement) + { + char buf[50]; + sprint_value (buf, (addressT) lie->addnum); + as_warn (".word %s-%s+%s didn't fit", + S_GET_NAME (lie->add), + S_GET_NAME (lie->sub), + buf); + } + lie->added = 1; + if (fragP->fr_subtype == 0) + { + fragP->fr_subtype++; + growth += md_short_jump_size; + } + for (untruth = lie->next_broken_word; + untruth && untruth->dispfrag == lie->dispfrag; + untruth = untruth->next_broken_word) + if ((untruth->add->sy_frag == lie->add->sy_frag) + && S_GET_VALUE (untruth->add) == S_GET_VALUE (lie->add)) + { + untruth->added = 2; + untruth->use_jump = lie; + } + growth += md_long_jump_size; + } + } + + break; + } /* case rs_broken_word */ +#endif + case rs_align: + case rs_align_code: + { + addressT oldoff, newoff; + + oldoff = relax_align (was_address + fragP->fr_fix, + (int) offset); + newoff = relax_align (address + fragP->fr_fix, + (int) offset); + + if (fragP->fr_subtype != 0) + { + if (oldoff > fragP->fr_subtype) + oldoff = 0; + if (newoff > fragP->fr_subtype) + newoff = 0; + } + + growth = newoff - oldoff; + } + break; + + case rs_org: + { + long target = offset; + long after; + + if (symbolP) + { +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT) + || S_GET_SEGMENT (symbolP) == SEG_BSS); + know (symbolP->sy_frag); + know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (symbolP->sy_frag == &zero_address_frag)); +#endif + target += S_GET_VALUE (symbolP) + + symbolP->sy_frag->fr_address; + } /* if we have a symbol */ + + know (fragP->fr_next); + after = fragP->fr_next->fr_address; + growth = target - after; + if (growth < 0) + { + /* Growth may be negative, but variable part of frag + cannot have fewer than 0 chars. That is, we can't + .org backwards. */ + as_bad ("attempt to .org backwards ignored"); + growth = 0; + } + + growth -= stretch; /* This is an absolute growth factor */ + break; + } + + case rs_space: + if (symbolP) + { + growth = S_GET_VALUE (symbolP); + if (symbolP->sy_frag != &zero_address_frag + || S_IS_COMMON (symbolP) + || ! S_IS_DEFINED (symbolP)) + as_bad_where (fragP->fr_file, fragP->fr_line, + ".space specifies non-absolute value"); + fragP->fr_symbol = 0; + if (growth < 0) + { + as_warn (".space or .fill with negative value, ignored"); + growth = 0; + } + } + else + growth = 0; + break; + + case rs_machine_dependent: +#ifdef md_relax_frag + growth = md_relax_frag (fragP, stretch); +#else +#ifdef TC_GENERIC_RELAX_TABLE + /* The default way to relax a frag is to look through + TC_GENERIC_RELAX_TABLE. */ + growth = relax_frag (fragP, stretch); +#endif /* TC_GENERIC_RELAX_TABLE */ +#endif + break; + + default: + BAD_CASE (fragP->fr_type); + break; + } + if (growth) + { + stretch += growth; + stretched++; + } + } /* For each frag in the segment. */ + } + while (stretched); /* Until nothing further to relax. */ + } /* do_relax */ + + /* + * We now have valid fr_address'es for each frag. + */ + + /* + * All fr_address's are correct, relative to their own segment. + * We have made all the fixS we will ever make. + */ +} /* relax_segment() */ + +#if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) + +#ifndef TC_RELOC_RTSYM_LOC_FIXUP +#define TC_RELOC_RTSYM_LOC_FIXUP(X) (1) +#endif + +/* fixup_segment() + + Go through all the fixS's in a segment and see which ones can be + handled now. (These consist of fixS where we have since discovered + the value of a symbol, or the address of the frag involved.) + For each one, call md_apply_fix to put the fix into the frag data. + + Result is a count of how many relocation structs will be needed to + handle the remaining fixS's that we couldn't completely handle here. + These will be output later by emit_relocations(). */ + +static long +fixup_segment (fixP, this_segment_type) + register fixS *fixP; + segT this_segment_type; /* N_TYPE bits for segment. */ +{ + long seg_reloc_count = 0; + symbolS *add_symbolP; + symbolS *sub_symbolP; + valueT add_number; + int size; + char *place; + long where; + int pcrel, plt; + fragS *fragP; + segT add_symbol_segment = absolute_section; + + /* If the linker is doing the relaxing, we must not do any fixups. + + Well, strictly speaking that's not true -- we could do any that are + PC-relative and don't cross regions that could change size. And for the + i960 (the only machine for which we've got a relaxing linker right now), + we might be able to turn callx/callj into bal anyways in cases where we + know the maximum displacement. */ + if (linkrelax) + { + for (; fixP; fixP = fixP->fx_next) + seg_reloc_count++; + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; + } + + for (; fixP; fixP = fixP->fx_next) + { +#ifdef DEBUG5 + fprintf (stderr, "\nprocessing fixup:\n"); + print_fixup (fixP); +#endif + + fragP = fixP->fx_frag; + know (fragP); + where = fixP->fx_where; + place = fragP->fr_literal + where; + size = fixP->fx_size; + add_symbolP = fixP->fx_addsy; +#ifdef TC_VALIDATE_FIX + TC_VALIDATE_FIX (fixP, this_segment_type, skip); +#endif + sub_symbolP = fixP->fx_subsy; + add_number = fixP->fx_offset; + pcrel = fixP->fx_pcrel; + plt = fixP->fx_plt; + + if (add_symbolP != NULL + && add_symbolP->sy_mri_common) + { + know (add_symbolP->sy_value.X_op == O_symbol); + add_number += S_GET_VALUE (add_symbolP); + fixP->fx_offset = add_number; + add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol; + } + + if (add_symbolP) + add_symbol_segment = S_GET_SEGMENT (add_symbolP); + + if (sub_symbolP) + { + resolve_symbol_value (sub_symbolP); + if (add_symbolP == NULL || add_symbol_segment == absolute_section) + { + if (add_symbolP != NULL) + { + add_number += S_GET_VALUE (add_symbolP); + add_symbolP = NULL; + fixP->fx_addsy = NULL; + } + + /* It's just -sym */ + if (S_GET_SEGMENT (sub_symbolP) == absolute_section) + { + add_number -= S_GET_VALUE (sub_symbolP); + fixP->fx_subsy = NULL; + } + else if (pcrel + && S_GET_SEGMENT (sub_symbolP) == this_segment_type) + { + /* Should try converting to a constant. */ + goto bad_sub_reloc; + } + else + bad_sub_reloc: + as_bad_where (fixP->fx_file, fixP->fx_line, + "Negative of non-absolute symbol %s", + S_GET_NAME (sub_symbolP)); + } + else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment + && SEG_NORMAL (add_symbol_segment)) + { + /* Difference of 2 symbols from same segment. + Can't make difference of 2 undefineds: 'value' means + something different for N_UNDF. */ +#ifdef TC_I960 + /* Makes no sense to use the difference of 2 arbitrary symbols + as the target of a call instruction. */ + if (fixP->fx_tcbit) + as_bad_where (fixP->fx_file, fixP->fx_line, + "callj to difference of 2 symbols"); +#endif /* TC_I960 */ + add_number += S_GET_VALUE (add_symbolP) - + S_GET_VALUE (sub_symbolP); + + add_symbolP = NULL; + pcrel = 0; /* No further pcrel processing. */ + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION_SECTION (fixP, this_segment_type)) + { + fixP->fx_pcrel = 0; + fixP->fx_addsy = NULL; + fixP->fx_subsy = NULL; + } + } + else + { + /* Different segments in subtraction. */ + know (!(S_IS_EXTERNAL (sub_symbolP) + && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); + + if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) + add_number -= S_GET_VALUE (sub_symbolP); + +#ifdef DIFF_EXPR_OK + else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type +#if 0 /* Do this even if it's already described as pc-relative. For example, + on the m68k, an operand of "pc@(foo-.-2)" should address "foo" in a + pc-relative mode. */ + && pcrel +#endif + ) + { + /* Make it pc-relative. */ + add_number += (MD_PCREL_FROM_SECTION (fixP, this_segment_type) + - S_GET_VALUE (sub_symbolP)); + pcrel = 1; + fixP->fx_pcrel = 1; + sub_symbolP = 0; + fixP->fx_subsy = 0; + } +#endif +#ifdef UNDEFINED_DIFFERENCE_OK + /* The PA needs this for PIC code generation. We basically + don't want to do anything if we have the difference of two + symbols at this point. */ + else if (1) + { + /* Leave it alone. */ + } +#endif +#ifdef BFD_ASSEMBLER + else if (fixP->fx_r_type == BFD_RELOC_GPREL32 + || fixP->fx_r_type == BFD_RELOC_GPREL16) + { + /* Leave it alone. */ + } +#endif + else + { + char buf[50]; + sprint_value (buf, fragP->fr_address + where); + as_bad_where (fixP->fx_file, fixP->fx_line, + "Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.", + segment_name (S_GET_SEGMENT (sub_symbolP)), + S_GET_NAME (sub_symbolP), buf); + } + } + } + + if (add_symbolP) + { + if (add_symbol_segment == this_segment_type && pcrel && !plt + && TC_RELOC_RTSYM_LOC_FIXUP (fixP)) + { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ +#ifdef TC_I960 + /* reloc_callj() may replace a 'call' with a 'calls' or a + 'bal', in which cases it modifies *fixP as appropriate. + In the case of a 'calls', no further work is required, + and *fixP has been set up to make the rest of the code + below a no-op. */ + reloc_callj (fixP); +#endif /* TC_I960 */ + + add_number += S_GET_VALUE (add_symbolP); + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type); + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION (fixP)) + { + fixP->fx_pcrel = 0; + fixP->fx_addsy = NULL; + } + } + else + { + if (add_symbol_segment == absolute_section + && ! pcrel) + { +#ifdef TC_I960 + /* See comment about reloc_callj() above. */ + reloc_callj (fixP); +#endif /* TC_I960 */ + add_number += S_GET_VALUE (add_symbolP); + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + + if (!TC_FORCE_RELOCATION (fixP)) + { + fixP->fx_addsy = NULL; + add_symbolP = NULL; + } + } + else if (add_symbol_segment == undefined_section +#ifdef BFD_ASSEMBLER + || bfd_is_com_section (add_symbol_segment) +#endif + ) + { +#ifdef TC_I960 + if ((int) fixP->fx_bit_fixP == 13) + { + /* This is a COBR instruction. They have only a + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ + as_bad_where (fixP->fx_file, fixP->fx_line, + "can't use COBR format with external label"); + fixP->fx_addsy = NULL; + fixP->fx_done = 1; + continue; + } /* COBR */ +#endif /* TC_I960 */ + +#ifdef OBJ_COFF +#ifdef TE_I386AIX + if (S_IS_COMMON (add_symbolP)) + add_number += S_GET_VALUE (add_symbolP); +#endif /* TE_I386AIX */ +#endif /* OBJ_COFF */ + ++seg_reloc_count; + } + else + { + seg_reloc_count++; +#if !(defined (TC_M68K) && defined (OBJ_ELF)) +#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF)) + add_number += S_GET_VALUE (add_symbolP); +#endif +#endif + } + } + } + + if (pcrel) + { + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type); + if (add_symbolP == 0) + { +#ifndef BFD_ASSEMBLER + fixP->fx_addsy = &abs_symbol; +#else + fixP->fx_addsy = section_symbol (absolute_section); +#endif + fixP->fx_addsy->sy_used_in_reloc = 1; + ++seg_reloc_count; + } + } + + if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0) + { + if (size < sizeof (valueT)) + { + valueT mask, hibit; + + /* set all bits to one */ + mask = 0; + mask--; + /* Technically, combining these produces an undefined result + if size is sizeof (valueT), though I think these two + half-way operations should both be defined. And the + compiler should be able to combine them if it's valid on + the host architecture. */ + mask <<= size * 4; + mask <<= size * 4; + hibit = (valueT) 1 << (size * 8 - 1); + if (((add_number & mask) != 0 + || (fixP->fx_signed + && (add_number & hibit) != 0)) + && ((add_number & mask) != mask + || (add_number & hibit) == 0)) + { + char buf[50], buf2[50]; + sprint_value (buf, fragP->fr_address + where); + if (add_number > 1000) + sprint_value (buf2, add_number); + else + sprintf (buf2, "%ld", (long) add_number); + as_bad_where (fixP->fx_file, fixP->fx_line, + "Value of %s too large for field of %d bytes at %s", + buf2, size, buf); + } /* generic error checking */ + } +#ifdef WARN_SIGNED_OVERFLOW_WORD + /* Warn if a .word value is too large when treated as a signed + number. We already know it is not too negative. This is to + catch over-large switches generated by gcc on the 68k. */ + if (!flag_signed_overflow_ok + && size == 2 + && add_number > 0x7fff) + as_bad_where (fixP->fx_file, fixP->fx_line, + "Signed .word overflow; switch may be too large; %ld at 0x%lx", + (long) add_number, + (unsigned long) (fragP->fr_address + where)); +#endif + } /* not a bit fix */ + + if (!fixP->fx_done) + { +#ifdef MD_APPLY_FIX3 + md_apply_fix3 (fixP, &add_number, this_segment_type); +#else +#ifdef BFD_ASSEMBLER + md_apply_fix (fixP, &add_number); +#else + md_apply_fix (fixP, add_number); +#endif +#endif + +#ifndef TC_HANDLES_FX_DONE + /* If the tc-* files haven't been converted, assume it's handling + it the old way, where a null fx_addsy means that the fix has + been applied completely, and no further work is needed. */ + if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0) + fixP->fx_done = 1; +#endif + } +#ifdef TC_VALIDATE_FIX + skip: ; +#endif +#ifdef DEBUG5 + fprintf (stderr, "result:\n"); + print_fixup (fixP); +#endif + } /* For each fixS in this segment. */ + + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; +} + +#endif /* defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) */ + +void +number_to_chars_bigendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n > sizeof (val)|| n <= 0) + abort (); + while (n--) + { + buf[n] = val & 0xff; + val >>= 8; + } +} + +void +number_to_chars_littleendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n > sizeof (val) || n <= 0) + abort (); + while (n--) + { + *buf++ = val & 0xff; + val >>= 8; + } +} + +void +write_print_statistics (file) + FILE *file; +{ + fprintf (stderr, "fixups: %d\n", n_fixups); +} + +/* for debugging */ +extern int indent_level; + +void +print_fixup (fixp) + fixS *fixp; +{ + indent_level = 1; + fprintf (stderr, "fix %lx %s:%d", (long) fixp, fixp->fx_file, fixp->fx_line); + if (fixp->fx_pcrel) + fprintf (stderr, " pcrel"); + if (fixp->fx_pcrel_adjust) + fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust); + if (fixp->fx_im_disp) + { +#ifdef TC_NS32K + fprintf (stderr, " im_disp=%d", fixp->fx_im_disp); +#else + fprintf (stderr, " im_disp"); +#endif + } + if (fixp->fx_tcbit) + fprintf (stderr, " tcbit"); + if (fixp->fx_done) + fprintf (stderr, " done"); + fprintf (stderr, "\n size=%d frag=%lx where=%ld offset=%lx addnumber=%lx", + fixp->fx_size, (long) fixp->fx_frag, (long) fixp->fx_where, + (long) fixp->fx_offset, (long) fixp->fx_addnumber); +#ifdef BFD_ASSEMBLER + fprintf (stderr, "\n %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type), + fixp->fx_r_type); +#else +#ifdef NEED_FX_R_TYPE + fprintf (stderr, " r_type=%d", fixp->fx_r_type); +#endif +#endif + if (fixp->fx_addsy) + { + fprintf (stderr, "\n +<"); + print_symbol_value_1 (stderr, fixp->fx_addsy); + fprintf (stderr, ">"); + } + if (fixp->fx_subsy) + { + fprintf (stderr, "\n -<"); + print_symbol_value_1 (stderr, fixp->fx_subsy); + fprintf (stderr, ">"); + } + fprintf (stderr, "\n"); +} + +/* end of write.c */ diff --git a/contrib/binutils/gas/write.h b/contrib/binutils/gas/write.h new file mode 100644 index 0000000..67372e4 --- /dev/null +++ b/contrib/binutils/gas/write.h @@ -0,0 +1,194 @@ +/* write.h + Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef TC_I960 +#ifdef hpux +#define EXEC_MACHINE_TYPE HP9000S200_ID +#endif +#endif /* TC_I960 */ + +#ifndef BFD_ASSEMBLER + +#ifndef LOCAL_LABEL +#define LOCAL_LABEL(name) (name [0] == 'L' ) +#endif + +#define S_LOCAL_NAME(s) (LOCAL_LABEL (S_GET_NAME (s))) + +#endif /* ! BFD_ASSEMBLER */ + +/* This is the name of a fake symbol which will never appear in the + assembler output. S_IS_LOCAL detects it because of the \001. */ +#define FAKE_LABEL_NAME "L0\001" + +#include "bit_fix.h" + +/* + * FixSs may be built up in any order. + */ + +struct fix +{ + /* These small fields are grouped together for compactness of + this structure, and efficiency of access on some architectures. */ + + /* pc-relative offset adjust */ + char fx_pcrel_adjust; + + /* How many bytes are involved? */ + unsigned char fx_size; + + /* Is this a pc-relative relocation? */ + unsigned fx_pcrel : 1; + + /* Is this a relocation to a procedure linkage table entry? If so, + some of the reductions we try to apply are invalid. A better way + might be to represent PLT entries with different kinds of + symbols, and use normal relocations (with undefined symbols); + look into it for version 2.6. */ + unsigned fx_plt : 1; + + /* Is this value an immediate displacement? */ + /* Only used on i960 and ns32k; merge it into TC_FIX_TYPE sometime. */ + unsigned fx_im_disp : 2; + + /* A bit for the CPU specific code. + This probably can be folded into tc_fix_data, below. */ + unsigned fx_tcbit : 1; + + /* Has this relocation already been applied? */ + unsigned fx_done : 1; + + /* Suppress overflow complaints on large addends. This is used + in the PowerPC ELF config to allow large addends on the + BFD_RELOC_{LO16,HI16,HI16_S} relocations. + + @@ Can this be determined from BFD? */ + unsigned fx_no_overflow : 1; + + /* The value is signed when checking for overflow. */ + unsigned fx_signed : 1; + + /* Which frag does this fix apply to? */ + fragS *fx_frag; + + /* Where is the first byte to fix up? */ + long fx_where; + + /* NULL or Symbol whose value we add in. */ + symbolS *fx_addsy; + + /* NULL or Symbol whose value we subtract. */ + symbolS *fx_subsy; + + /* Absolute number we add in. */ + valueT fx_offset; + + /* Next fixS in linked list, or NULL. */ + struct fix *fx_next; + + /* If NULL, no bitfix's to do. */ + /* Only i960-coff and ns32k use this, and i960-coff stores an + integer. This can probably be folded into tc_fix_data, below. + @@ Alpha also uses it, but only to disable certain relocation + processing. */ + bit_fixS *fx_bit_fixP; + +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type fx_r_type; +#else +#ifdef NEED_FX_R_TYPE + /* Hack for machines where the type of reloc can't be + worked out by looking at how big it is. */ + int fx_r_type; +#endif +#endif + + /* This field is sort of misnamed. It appears to be a sort of random + scratch field, for use by the back ends. The main gas code doesn't + do anything but initialize it to zero. The use of it does need to + be coordinated between the cpu and format files, though. E.g., some + coff targets pass the `addend' field from the cpu file via this + field. I don't know why the `fx_offset' field above can't be used + for that; investigate later and document. KR */ + valueT fx_addnumber; + + /* The location of the instruction which created the reloc, used + in error messages. */ + char *fx_file; + unsigned fx_line; + +#ifdef TC_FIX_TYPE + /* Location where a backend can attach additional data + needed to perform fixups. */ + TC_FIX_TYPE tc_fix_data; +#endif +}; + +typedef struct fix fixS; + +#ifndef BFD_ASSEMBLER +extern char *next_object_file_charP; + +#ifndef MANY_SEGMENTS +COMMON fixS *text_fix_root, *text_fix_tail; /* Chains fixSs. */ +COMMON fixS *data_fix_root, *data_fix_tail; /* Chains fixSs. */ +COMMON fixS *bss_fix_root, *bss_fix_tail; /* Chains fixSs. */ +extern struct frag *text_last_frag; /* Last frag in segment. */ +extern struct frag *data_last_frag; /* Last frag in segment. */ +#endif +COMMON fixS **seg_fix_rootP, **seg_fix_tailP; /* -> one of above. */ +#endif + +extern long string_byte_count; +extern int section_alignment[]; + +extern bit_fixS *bit_fix_new + PARAMS ((int size, int offset, long base_type, long base_adj, long min, + long max, long add)); +extern void append PARAMS ((char **charPP, char *fromP, unsigned long length)); +extern void record_alignment PARAMS ((segT seg, int align)); +extern void write_object_file PARAMS ((void)); +extern long relax_frag PARAMS ((fragS *, long)); +extern void relax_segment + PARAMS ((struct frag * seg_frag_root, segT seg_type)); + +extern void number_to_chars_littleendian PARAMS ((char *, valueT, int)); +extern void number_to_chars_bigendian PARAMS ((char *, valueT, int)); + +#ifdef BFD_ASSEMBLER +extern fixS *fix_new + PARAMS ((fragS * frag, int where, int size, symbolS * add_symbol, + offsetT offset, int pcrel, bfd_reloc_code_real_type r_type)); +extern fixS *fix_new_exp + PARAMS ((fragS * frag, int where, int size, expressionS *exp, int pcrel, + bfd_reloc_code_real_type r_type)); +#else +extern fixS *fix_new + PARAMS ((fragS * frag, int where, int size, symbolS * add_symbol, + offsetT offset, int pcrel, int r_type)); +extern fixS *fix_new_exp + PARAMS ((fragS * frag, int where, int size, expressionS *exp, int pcrel, + int r_type)); +#endif + +extern void write_print_statistics PARAMS ((FILE *)); + +/* end of write.h */ |