]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Initial revision
authorK. Richard Pixley <rich@cygnus>
Thu, 4 Apr 1991 18:19:53 +0000 (18:19 +0000)
committerK. Richard Pixley <rich@cygnus>
Thu, 4 Apr 1991 18:19:53 +0000 (18:19 +0000)
97 files changed:
gas/COPYING [new file with mode: 0644]
gas/ChangeLog [new file with mode: 0644]
gas/Makefile-intel [new file with mode: 0755]
gas/Makefile.generic [new file with mode: 0755]
gas/Makefile.in [new file with mode: 0644]
gas/README [new file with mode: 0644]
gas/app.c [new file with mode: 0644]
gas/as.c [new file with mode: 0644]
gas/as.h [new file with mode: 0644]
gas/atof-generic.c [new file with mode: 0644]
gas/bignum-copy.c [new file with mode: 0644]
gas/bignum.h [new file with mode: 0644]
gas/cond.c [new file with mode: 0644]
gas/config/a.out.h [new file with mode: 0755]
gas/config/atof-ieee.c [new file with mode: 0644]
gas/config/atof-vax.c [new file with mode: 0644]
gas/config/coff.gnu.h [new file with mode: 0755]
gas/config/ho-ansi.h [new file with mode: 0644]
gas/config/ho-cygnus.h [new file with mode: 0755]
gas/config/ho-generic.h [new file with mode: 0644]
gas/config/ho-hpux.h [new file with mode: 0644]
gas/config/ho-i386.h [new file with mode: 0644]
gas/config/ho-sun3.h [new file with mode: 0644]
gas/config/ho-sun386.h [new file with mode: 0644]
gas/config/ho-sun4.h [new file with mode: 0644]
gas/config/ho-sunos.h [new file with mode: 0644]
gas/config/ho-sysv.h [new file with mode: 0644]
gas/config/obj-aout.c [new file with mode: 0644]
gas/config/obj-aout.h [new file with mode: 0644]
gas/config/obj-bout.c [new file with mode: 0644]
gas/config/obj-bout.h [new file with mode: 0644]
gas/config/obj-coff.c [new file with mode: 0644]
gas/config/obj-coff.h [new file with mode: 0644]
gas/config/tc-a29k.c [new file with mode: 0644]
gas/config/tc-a29k.h [new file with mode: 0644]
gas/config/tc-generic.c [new file with mode: 0644]
gas/config/tc-generic.h [new file with mode: 0644]
gas/config/tc-i386.c [new file with mode: 0644]
gas/config/tc-i386.h [new file with mode: 0644]
gas/config/tc-i860.c [new file with mode: 0644]
gas/config/tc-i860.h [new file with mode: 0644]
gas/config/tc-i960.c [new file with mode: 0644]
gas/config/tc-i960.h [new file with mode: 0644]
gas/config/tc-m68851.h [new file with mode: 0644]
gas/config/tc-m68k.c [new file with mode: 0644]
gas/config/tc-m68k.h [new file with mode: 0644]
gas/config/tc-ns32k.c [new file with mode: 0644]
gas/config/tc-ns32k.h [new file with mode: 0644]
gas/config/tc-sparc.c [new file with mode: 0644]
gas/config/tc-sparc.h [new file with mode: 0644]
gas/config/tc-vax.c [new file with mode: 0644]
gas/config/tc-vax.h [new file with mode: 0644]
gas/config/te-generic.h [new file with mode: 0644]
gas/config/te-ic960.h [new file with mode: 0644]
gas/config/te-sun3.h [new file with mode: 0644]
gas/config/vax-inst.h [new file with mode: 0644]
gas/configure [new file with mode: 0755]
gas/configure.in [new file with mode: 0644]
gas/configure.was [new file with mode: 0755]
gas/debug.c [new file with mode: 0644]
gas/expr.c [new file with mode: 0644]
gas/expr.h [new file with mode: 0644]
gas/flonum-const.c [new file with mode: 0755]
gas/flonum-copy.c [new file with mode: 0644]
gas/flonum-mult.c [new file with mode: 0644]
gas/flonum.h [new file with mode: 0644]
gas/frags.c [new file with mode: 0644]
gas/frags.h [new file with mode: 0644]
gas/hash.c [new file with mode: 0644]
gas/hash.h [new file with mode: 0644]
gas/hex-value.c [new file with mode: 0644]
gas/input-file.c [new file with mode: 0644]
gas/input-file.h [new file with mode: 0644]
gas/input-scrub.c [new file with mode: 0644]
gas/messages.c [new file with mode: 0644]
gas/obj.h [new file with mode: 0644]
gas/output-file.c [new file with mode: 0644]
gas/output-file.h [new file with mode: 0644]
gas/read.c [new file with mode: 0644]
gas/read.h [new file with mode: 0644]
gas/strstr.c [new file with mode: 0644]
gas/struc-symbol.h [new file with mode: 0644]
gas/subsegs.c [new file with mode: 0644]
gas/subsegs.h [new file with mode: 0644]
gas/symbols.c [new file with mode: 0644]
gas/symbols.h [new file with mode: 0644]
gas/tc.h [new file with mode: 0644]
gas/testscripts/doboth [new file with mode: 0755]
gas/testscripts/doobjcmp [new file with mode: 0755]
gas/testscripts/dostriptest [new file with mode: 0755]
gas/testscripts/dotest [new file with mode: 0755]
gas/testscripts/dounsortreloc [new file with mode: 0755]
gas/testscripts/dounsortsymbols [new file with mode: 0755]
gas/write.c [new file with mode: 0644]
gas/write.h [new file with mode: 0644]
gas/xmalloc.c [new file with mode: 0644]
gas/xrealloc.c [new file with mode: 0644]

diff --git a/gas/COPYING b/gas/COPYING
new file mode 100644 (file)
index 0000000..9a17037
--- /dev/null
@@ -0,0 +1,249 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                    Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+\f
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gas/ChangeLog b/gas/ChangeLog
new file mode 100644 (file)
index 0000000..3b45c21
--- /dev/null
@@ -0,0 +1,1196 @@
+Fri Jan  4 12:48:22 EST 1991   Jay Fenlason (hack@ai.mit.edu)
+
+       * messages.c  Moved as_perror from input-scrub.c  Modified the
+       error messages to look better.
+
+       * output-file.c Don't call as_fatal, just call exit()
+
+       expr.c Slightly improve checking for foo-foo case in
+       clean_up_expression().  Detect foo: bar: ... foo-bar...
+
+Tue Dec  4 16:29:20 EST 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * m68k.c  Fixed an obscure bug involving AOFF mode with a
+       large constant displacement (Was forgetting to output the
+       extension word.)
+
+       make-gas.com  Added a three line patch from Eric Youngdale that
+       makes it possible to submit make-gas.com to a batch queue.
+
+Wed Nov 21 15:07:51 EST 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * vms.c  (VMS_TBT_Routine_END)  Add a four line patch from
+       Eric Youngdale.
+
+Tue Nov 13 14:02:15 EST 1990   Jay Fenlason (hack@ai.mti.edu)
+
+       * vms-dbg.c (VMS_DBG_record())  Another one character patch from
+       Eric Youngdale.
+
+Mon Oct 29 15:49:21 EST 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * read.c  Replace some as_warn calls with as_bad.
+
+Fri Oct 26 15:21:15 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * i386.c, i860.c, ns32k.c       Add const changes.
+
+Mon Oct 22 14:04:26 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * sparc.c       Add const changes.
+
+       * make-gas.com  define const= for VMS, since many older versions of
+       GCC don't work correctly with const under VMS.
+
+Thu Oct 18 12:44:11 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * i860.c i860-opcode.h  Added patches from rgb@mcc.com
+
+       * read.c, symbols.c, vms.c, + new_file vms-dbg-module.c
+       Added Eric Youngdale's <YOUNGDALE@v6550c.nrl.navy.mil> VMS debugging
+       patches, so debugging GCC output now works.
+
+       * hash.c (hash_grow)  Remember to blank out the wall entry in the new
+       hash table.  This is important on systems where malloc() returns
+       non-zero storage. . .
+
+Tue Oct 16 10:11:35 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * output-file.c (output_file_create)  if output filename is given as
+       '-', write to stdout.
+
+       * m68k.c Finally get the PCREL code to work right.  Add relaxation of
+       PCREL stuff  This small fix from Ken Woodland
+       (kenny%datacube.uucp@uunet.uu.net).
+
+       * m68k.c  Added some const declarations to constants.  (md_relax_table,
+       md_pseudo_table, etc. . .)
+
+Thu Oct 11 11:15:10 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * Makefile, read.c, write.c Include the i860 port.
+       (New files i860.c i860-opcode.h i860.h)
+
+       * m68k.c Fix some addressing modes, (AOFF, AINDEX, etc) to work in
+       PC relative mode.
+
+       * (all over)  Raeburn's const hacking.  This reduces the data-space size by
+       declaring many tables, etc, as 'const'.
+
+Mon Oct 22 22:48:22 1990  John Gilmore  (gnu at cygint)
+
+       Make gas work if you turn on the know() checks.
+
+       * app.c:  Only pass a single space through:  the one after
+       the opcode.  All other whitespace is removed, to match the
+       expectations of the parser in read.c.
+
+       * as.h: Remove obsolete comments.  Remove JF's NDEBUG so
+       that know() can really work if you turn it on.  Make
+       SEG_MAXIMUM_ORDINAL == SEG_REGISTER.
+
+       * expr.c (operand):  Change BITS_PER_INT to 8*sizeof(int).
+
+       * input-scrub.c:  strlen("\0") doesn't return 1...
+       (as_where):  Add space after line number in errors, like gcc.
+
+       * m68k.c (s_bss):  Fake .bss into data section 255.
+       We can't cope with a real "BSS section" yet, but we can at
+       least do the right thing less efficiently (with lots of
+       zeroes).
+
+       * read.c:  Turn lots of as_warn()'s into as_bad()'s.
+
+       * read.h (SKIP_WHITESPACE):  Replace last instance of ASSERT()
+       with know().
+
+       * sparc.c (s_seg):  We can't put frags into the BSS segment
+       yet, so just fake bss seg as 255th data segment.
+
+       * vax.c:  Remove \'s from continued macro *parameters*.  These
+       must have been added after the last time someone turned on
+       know() checking...
+
+       * write.c (relax_segment):  Refine what we know() about the
+       symbols referenced during relaxation.   
+
+       * Makefile (OTHER_ALIGN):  Remove, handled in tables now.
+       Flip options a bit.  These options really ought to go
+       elsewhere.
+
+Sun Oct 21 03:57:21 1990  John Gilmore  (gnu at cygint)
+
+       Sun-3 fixes.
+
+       * expr.c, write.c:  Missing semicolon after know().
+
+       * write.c (fixup_segment):  Allow pc-relative accesses to undefined
+       external symbols.  Previously this would turn off pc-rel calc
+       of displacement, while leaving pc-rel opcode alone, botching.
+
+       * m68k.c (m68k_ip):  Allow pc-relative effective addresses
+       for source operands.  "pea" instructions are a good example
+       where we can shorten from abs long to pc+16bit.
+       (md_convert_frag):  Fix "JBSR" comments to refer to "JSR", the
+       actual instruction.  Insert comments about bug in 68000 bcc
+       and dbcc long code (that doesn't get exercised much).  Add
+       comments about long pcrel displacements for -pic.  Remove
+       "this code has not been tested" comment.
+       (md_estimate_size_before_relax):  Now that fixup_segment
+       doesn't shortcircuit pc-relative fixups for undefined symbols,
+       only output them if -pic; else turn them absolute, which is
+       slightly faster.  More JBSR->JSR comments.
+       (md_parse_options):  Parse -pic.
+
+Fri Oct 19 14:35:20 1990  John Gilmore  (gnu at cygint)
+
+       * Make sparc assembler more compatible with Sun assembler.
+       sparc.c:  reformat pseudo-op table to match main table.
+       (md_assemble):  Add SPECIAL_CASE_FDIV to assemble FDIV*
+       instructions as fdiv followed by fmovs to get around chip bug.
+       (s_common, s_seg):  Accept "bss" section name.
+       (md_assemble):  Handle "set" instructions with absolute
+       operands, that only take one instruction rather than two.
+       sparc-opcode.h (fdiv*):  Mark instructions "S"pecial.
+       subsegs.c (subseg_change):  Move tail pointer too.
+       symbols.c (colon):  Allow new definitions to override .comm symbols,
+       as in VMS.  Sun CC depends on this.
+       write.c (new_fix):  Always take r_type argument, not just on sparc.
+       Chain fixP's in order, using tail pointer, so relocation
+       records come out in forward order like Sun as.  Remove SPARC
+       ifdefs.
+       write.h: Add seg_fix_tailP, data_fix_tailP, text_fix_tailP.
+
+       * am29k.c: Use s_align_bytes rather than a local copy.
+
+       * read.c (s_align):  Rather than ifdef it, make two functions,
+       s_align_bytes and s_align_ptwo.  Individual pseudo-op tables
+       can call whichever one they like.
+
+       * write.c (append):  Move from append.c to here.
+       append.c:  Remove file. 
+
+       * Makefile (MDSRC, mdsrc):  Easy way to edit all md.c's.
+       Fix options.  Add option for -DDEBUG for know() and assert().
+       Remove append.c, am29k.h.  Don't build special read-sparc.o.
+       Remove sparc.h.  "make clean" removes am29k .o's.  Add
+       dependencies on reloc.h.
+
+Thu Oct 18 17:56:34 1990  John Gilmore  (gnu at cygint)
+
+       * Generalize sparc extensions to relocation info.  Gas now
+       keeps relocation information internally in a different format
+       than how it is stored in the resulting .o.  md_ri_to_bytes()
+       converts to external format.  md_reloc_size says how large
+       each relocation record is in external format.
+       sparc.h:  Remove this file.  Rename to reloc.h.  Rename struct
+       to reloc_info_generic.
+       reloc.h:  Add relocation types for AMD 29000.
+       read.c, write.c:  Always call fix_new with reloc-type argument.
+       write.c (emit_relocations): Make md_ri_to_bytes write directly
+       to output area rather than overwriting its argument then
+       bcopying it.
+       md.h:  Declare md_reloc_size and md_ri_to_bytes.
+       i386.c, am29k.c, vax.c, ms32k.c, m68k.c, sparc.c: include reloc.h.
+       (md_reloc_size): Specify correct value.
+       (md_ri_to_bytes):  Convert format from internal to external.
+
+       write.c (write_object_file):  Call md_section_align() which
+       rounds section sizes up if desired. 
+       sparc.c (md_section_align):  Round to 8 byte boundary.
+       i386.c, am29k.c, vax.c, ns32k.c, m68k.c (md_section_align):  Nop.
+
+Mon Oct 15 22:06:11 1990  John Gilmore  (gnu at cygint)
+
+       Changes in support of the AMD 29000 version of gas.
+
+       * am29k-opcode.h:  Add dummy entry to end so we can examine
+       item N+1 without exceeding table.
+
+       * am29k.h:  New include file, derived from sparc.h.  Kludged
+       together, still needs major work to get relocation working.
+
+       * am29k.c:  New file, derived from sparc.c.
+       Put 29k-specific ASM29K pseudo-ops into table.
+       Change comment_chars to ASM29K.
+       Change s_seg to s_use.
+       Change s_sparc_align to s_29k_align, default operand to 4.
+       (define_some_regs):  Define special register names.
+       (md_begin):  Preprocess opcode table to mash together all
+       the variants of single opcodes.  This simplifies later handling.
+       Call define_some_regs to preset special reg names.
+       (parse_operand):  Add, parses out an operand from a stmt.
+       (machine_ip):  Simplify, since 29K is simpler asm language.
+       Handle the various keyletters in the opcode table.
+
+
+       Handle include files in the assembler, with a .include
+       pseudo-op.
+       * as.h (input_scrub_include_file):  declare.
+       * as.c (perform_an_assembly_pass):  Avoid buffer hacking.
+       Start us off in text segment.
+       * read.c (read_a_source_file):  Take a name as argument,
+       internalize all buffer handling.  Don't start a new text
+       subsegment on each entry.  Actually use the start and end
+       pointers returned by input_scrub_next_buffer.
+       (s_include):  Call input_scrub_include_file for .include.
+       * input-scrub.c:  Fix comments.
+       (struct input_save):  Add, for saving state at .include.
+       (input_scrub_push, input_scrub_pop):  Add, push & pop state.
+       (input_scrub_begin):  Initialize next_saved_file.
+       (input_scrub_end):  Free buffer.
+       (input_scrub_include_file):  Add, to include a file.
+       (input_scrub_close):  Add, to close a file.
+       (input_scrub_next_buffer):  Set buffer-start address for
+       caller.  If we hit EOF and were included, pop to previous file.
+       * input-file.c:  Remove old includes.  Remove old file-descriptor
+       hacking code, that was commented out.
+       (struct saved_file):  Add, for saving state at .include.
+       (input_file_push, input_file_pop):  Add, push & pop state.
+       (input_file_open):  Don't buffer all files in one place.
+       (input_file_close):  Add, close input file.
+       * input-file.h: Declare new functions.
+       * app.c: (struct app_save):  Add, for saving state at .include.
+       (app_push, app_pop):  Add, push and pop state.
+       (do_scrub_next_char):  Move its static state variables out so
+       they can be saved and restored.
+
+
+       * app.c:  Allow overriding of character meanings by machine
+       dependent strings.  Avoid wiring character constants into app.c.
+       (do_scrub_begin):  New meanings override old ones, not "OR" them.
+       Only handle /* comments if / is not already in use.
+       (do_scrub_next_char):  Reorganize mass of nested if's
+       into a switch for speed.  Don't assume ';' is line terminator.
+       Reorganize switch on characters, into a switch on their (machine-
+       dependent) lexer table meanings.
+       
+
+       Encapsulate knowledge of segment types in fewer places.
+       This allows us to add the "SEG_REGISTER" type, as well as
+       providing flexibility for eventual COFF/ELF support.
+       * struc-symbol.h (symbol_to_segment, symbol_to_segment_type,
+       set_symbol_segment, set_symbol_segment_keep_ext,
+       segment_name):  Define macros to encapsulate this info.
+       * as.h:  Remove externs for seg_name, seg_N_TYPE, N_TYPE_seg.
+       * symbols.c (symbol_new):  Change 'type' arg to 'seg'.
+       * expr.c, i386.c, m68k.c, ns32k.c, read.c, symbols.c, vax.c,
+       write.c:  Use macros.
+       * i386.c, m68k.c, ns32k.c, vax.c, write.c: Change 2nd arg type of
+       md_estimate_size_before_relax.
+       * expr.c, read.c:  Change 'type' arg to symbol_new.
+       * read.c, symbols.c, vax.c, write.c:  Move md.h to end of includes.
+
+
+       Allow expressions to evaluate to registers.
+       * as.h:  Add SEG_REGISTER.
+       * struc-symbol.h:  Add fake N_REGISTER type.
+       * subseg.c:  Add types to tables.
+       * expr.c (operand):  Symbols of SEG_REGISTER type are
+       immediately evaluated like those of SEG_ABSOLUTE.
+       (clean_up_expression):  Clean up SEG_REGISTER exprs.
+
+
+       Allow machine descriptions to cleanly extend the set of
+       possible operands.
+       * expr.c (operand):  Call md_operand before rejecting an
+       operand as unacceptable.
+       * md.h:  declare.
+       * i386.c, ns32k.c, m68k.c, sparc.c, vax.c:  Define null function.
+       * am29k.c (md_operand):  Use this for %% and & prefix operators.
+       
+
+       Allow machine descriptions to cleanly permit symbols to be
+       predefined upon first usage.
+       * symbols.c (symbol_find_or_make):  Call md_undefined_symbol
+       before making an undefined symbol.
+       * md.h:  declare.
+       * i386.c, ns32k.c, m68k.c, sparc.c, vax.c:  Define null function.
+       * am29k.c (md_undefined_symbol):  use this for the local and
+       global register names; since there are hundreds of them, it
+       only defines them upon their first use.
+       * expr.c (operand):  Call symbol_find_or_make rather than
+       roll our own undefined symbols.
+
+
+       Miscellaneous changes:
+
+       * as.h (know):  Make this useful if DEBUG defined.
+
+       * write.h: Support SPARC-like relocation throughout all
+       versions.
+
+       * read.c (read_a_source_file): Report the name of invalid
+       pseudo-ops.  Don't double-report junk characters.  Close the
+       input file, which gas never used to do.
+       (ignore_rest_of_line):  Report junk chars in ascii if
+       printable.
+       (s_ignore):  Ignore entire statement; used for 'listing
+       control' statements from ASM29K, e.g. .eject.
+
+       * read.c (s_lsym):  Handle register equates too.
+
+       * read.c:  Add most ASM29K pseudo-ops to the master table.
+       Not all are implemented yet.
+
+       * cond.c:  New file, for functions implementing conditional
+       assembly pseudo-ops: .ifdef, .ifndef, .else, .endif, .ifseq,
+       .ifsne, .end.  So far, they are just stubbed out.
+
+       * read.c (pobegin):  Allow the machine dependent pseudo-op
+       table to override the generic one.  Remove #ifdef SPARC
+       on .word, since it can now be overridden.
+
+       * expr.c (operand):  Support radix-2 constants.  Kill off
+       support for octals with digits '8' and '9'.  Initial steps
+       toward more general support for local-labels.
+
+       * symbols.h (symbol_table_lookup):  Remove macro, change all
+       occurrences (in read.c, expr.c, symbols.c) to symbol_find.
+
+       * read.h (is_end_of_line):  Define for external use.
+
+       * i386.c (alloca):  Use builtin_alloca or include or extern.
+
+       * Makefile:  Add ALL and all: entries.  Add asm29k entries.
+       Add cond.c and cond.o.  Remove special handling for messages.o.
+       Add lint entry.
+
+Thu Sep 27 13:43:49 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * m68k.c (get_num)  Fix so that 1:w is treated properly.
+
+       * Makefile  Replace references to a.out.h with a.out.gnu.h
+
+Tue Sep 25 15:50:36 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * sparc.c  (md_number_to_imm)  Fix so that RELOC_32 locations contain
+       zero, so that it will work with some sparc loaders which don't assume
+       that the locations in question do.  A xix line patch from Michael Bloom
+       (usc!srhqla!quad1!psivax!ttidca!mb@zaphod.mps.ohio-state.edu)
+
+Mon Sep 24 11:43:15 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * as.c  #include <sys/types.h> if _POSIX_SOURCE defined.  This because
+       <signal.h> uses pid_t that's defined in it.
+
+       * m68k.c reverse the sense of -l option, and allow :w and :l to
+       override the default size of AOFF indexes.
+
+       Also, allow -l to shorten branches to unknown labels from LONG to WORD.
+
+Thu Sep 13 17:05:09 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * vax.c (md_parse_option)  Don't print a warning msg if given -J
+
+Wed Sep  5 14:26:14 EDT 1990   Jay Fenlason
+
+       * expr.c  (operand)  Don't get garbaged high-order bits when given a
+       lot of leading zeroes.
+
+Tue Sep  4 11:40:21 EDT 1990   Jay Fenlason
+
+       * read.c (pseudo_set) Compain if we're setting the symbol to the
+       difference of two symbols which are in different frags.  (We can't
+       find out how far apart they are.)
+
+Wed Aug 15 12:18:58 EDT 1990   Jay Fenlason
+
+       * m68k.c (m68k_ip_op)  Dyke out the code that deals with parsing
+       :[wl] at the end of expressions since it is handled in get_num()
+       and this was putting the result in the wrong place anyway.
+       Corrected a couple of other references to ->isiz instead of con?->e_siz
+
+Mon Aug 13 15:53:46 EDT 1990   Jay Fenlason
+
+       * read.c  Handle .align specially on the sparc, or any other machine
+       where OTHER_ALIGN is defined.  Added option and comments about it
+       to Makefile.
+
+Fri Aug 10 12:24:33 EDT 1990   Jay Fenlason
+
+       * m68k.c (get_num)  Handle SEG_PASS1 expressions.
+
+Mon Aug  6 16:32:29 EDT 1990   Jay Fenlason
+
+       * write.c  (fixup_segment) Added two patches for the NS32k
+       and SEQUENT  A six line patch from Ian Dall
+       (asgard!aegir!hugin!augean!sibyl!ian@munnari.oz.au)
+
+Wed Aug  1 13:30:48 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * m68k.c  Include REGISTER_PREFIX ifdefs.
+
+       * write.c Include LOCAL_LABEL() and DOT_LABEL_PREFIX feature.
+
+       * vax.c (md_parse_option)  Accept -H option.
+
+       * vms.c New version of case hasher, etc.  These from Eric Youngdale
+         <YOUNGDALE@v6550c.nrl.navy.mil>
+
+Fri Jul 20 13:39:02 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * README        Added README.APOLLO and README.COFF stuff
+
+Wed Jul 18 16:29:22 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * Makefile  Added option for SEQUENT_COMPATABILITY
+
+       * ns32k.c  Add configurable syntax feature from
+               ian@sibyl.eleceng.ua.oz@augean.ua.oz.au
+               and SEQUENT_COMPATABILITY
+
+       * ns32k-opcode.h  Add configurable syntax feature.
+
+Mon Jul 16 11:44:14 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * write.c (relax_segment)  On ns32k, add fragP->fr_pcrel_adjust to
+       aim.
+               (fixup_segment)  On ns32k, don't subtract size from
+       add_number on pcrel external symbols.
+
+       * ns32k.c (md_relax_table)  Use correct max displacements.
+       This is a six-line patch from ian@sibyl.eleceng.ua.oz.au
+
+       * ns32k.c (md_atof, convert_iif)  Emit floating point numbers in
+       the correct byte order.  A seven line patch from
+       ian@sibyl.eleceng.ua.oz.au
+
+       * ns32k.c (all over)  Some lint fixes.
+
+Mon Jul  9 13:17:00 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * app.c (do_scrub_next_char)  If a comment is #{whitespace}
+       don't treat the next line as comment also.
+
+       * m68k.c (...)  Accept apc@(num:[wl]), etc.
+
+       * i386.c (md_assemble) Get bitfields correct when doing cross
+       assembly to 386.  A two line patch from Michael Bloom.
+       (usc!srhqla!quad1!ttidca!mb@zaphod.mps.ohio-state.edu).
+
+       * README.APOLLO a new file with vasta@apollo's name, address
+       and phone # in it.
+
+       * make-gas.com Deleted references to gdb source files.
+
+Fri Jul  6 14:34:27 EDT 1990   Jay Fenlason (hack@ai.mit.edu)
+
+       * i386.c  Ignore the .optim directive
+
+       * input-file.c  Change from _IOLBF to _IOFBF in setbuffer emulation
+       for SYSV.
+
+Mon Jun 18 15:36:49 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
+
+       * sparc.c #ifdef DONTDEF s_sparc_align, since it isn't called from
+         anywhere.
+
+Fri Jun 15 15:53:30 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
+
+       * vax.c (md_parse_option)  make the code agree with the documentation
+         on the behaviour of the -d option.
+
+Thu Jun  7 14:23:54 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
+
+       * atof-ieee.c  (gen_to_words)  Assemble 0r-0 correctly.
+
+       * Makefile Remove last references to gdb*.c files.
+
+       * version.c  New version 1.36
+
+Tue May 22 13:22:26 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
+
+       * Makefile  Mention a work-around for a possible problem with HPUX7.0
+
+Mon May 21 14:06:04 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * sparc.c (sparc_ip): Change error message from "not in hash table"
+       to "unknown opcode".
+
+Wed May 16 15:33:14 EDT 1990   hack@wookumz
+
+       * i386.c (i386_operand)  Print error msg if given an operand like
+       4(mumble) which we can't parse.
+
+       * m68k.c (md_assemble)  Add '3' to the list of operand-places that
+       can be found in 'symbol-dependent info'.  Also change
+       'confusing width' diagnostic to something more meaningful.
+
+Fri May 11 12:09:21 EDT 1990   hack@wookumz
+
+       app.c (do_scrub_next_char)  Don't flush the line after a line
+       consisting of a single '/'  A one-line patch from Mike Kupfer
+       (kupfer@orc.olivetti.com)
+
+       * i386.c (md_assemble)  Call frag_wane() before calling frag_new()
+       A one line patch from Steve Bleazard (steve@robobar.co.uk
+
+Tue May  8 12:56:25 EDT 1990   hack@wookumz
+
+       * atof-generic.c (atof-generic)  Modified the Infinity detection code
+         to accept 0rinfinity and 0r-infinity as well as 0rinf and 0r-inf
+
+Thu Apr 26 15:17:31 EDT 1990   hack@wookumz
+
+       * atof-ieee.c  Change value of NaNs to 0x7fff ffff (float) and
+       0x7fff ffff ffff ffff (double)  If you want some other value for
+       NaN, use .long and spell it out yourself.
+
+       atof-generic.c  (atof_generic)  Cleaned up code that detects NaN
+       and Inf.
+
+       vax.c (md_assemble)  print a useful error message if expression()
+       returns SEG_PASS1 or SEG_DIFFERENCE and we can't deal with those.
+
+Thu Apr 19 10:30:47 EDT 1990   hack@wookumz
+
+       * input-scrub.c (AFTER_STRING)  Make AFTER_STRING contain a null
+       so that the strstr() call when looking for "#NO_APP" after a "#APP"
+       will work.  A two character patch from Bruce Robertson
+       (bruce@heather.pooh.com)
+
+       * Makefile, i386.c  Use atof-ieee.c instead of atof-i386.c
+
+Mon Apr 16 16:20:55 EDT 1990   hack@wookumz
+
+       * m68k.c (md_relax_table)  Many of the offsets were off by two.
+       Fixed some generic spacing problems thoughout the file.
+
+Thu Apr 12 12:22:35 EDT 1990   hack@wookumz
+
+       * sparc.c  (md_ri_to_chars)  Handle little-endian cross assembly.
+
+       * write.c (relax_segment)  Compare addresses correctly to avoid
+         accidentally relaxing a branch that we don't have to.
+         These small changes from John Gilmore (gnu@toad.com)
+
+Fri Apr  6 12:52:15 EDT 1990   hack@wookumz
+
+       * Makefile, expr.c symbols.c  Correctly document the SUN_ASM_SYNTAX
+       option, and make it work.
+
+Tue Mar 20 12:46:59 EST 1990
+
+       * as.c (main)  Only trap SIGHUP, SIGINT, SIGPIPE, and SIGTERM,
+               and only if they aren't being ignored.  A three line patch
+               from Paul Eggert (eggert@twinsun.com)
+
+       * write.c (relax_segment)  Correct typo 'growth - ' should have been
+               growth = 
+
+       * atof-vax.c (next_bits, flonum_gen2vax)  Clean up by sharing some
+               variables.  While we're at it, fix next_bits so that it
+               doesn't use littlenums that don't exist. . .
+
+Tue Mar 13 16:23:21 EST 1990   hack@wookumz
+
+       * Rename atof-m68k.c atof-ieee.c
+
+       * Delete atof-ns32k.c
+
+       * m68k.c sparc.c ns32k.c atof-ieee.c  Call atof-ieee instead of
+               atof-m68k or atof-ns32k
+
+       * Makefile      Compile with atof-ieee.c instead of atof-ns32k.c or
+               atof-m68k.c
+
+Mon Mar 12 14:06:55 EST 1990   hack@wookumz
+
+       * as.c  If the signal handler gets called twice, exit immediatly.
+
+       * ns32k.c  Call gen_to_words with a pointer of the proper type, and
+         call md_number_to_chars to put the results in the proper byte-order.
+         Whoever wrote this code was *sloppy*!
+
+       * Makefile ns32k.o depends on ns32k.c
+
+       * vax.c  (md_parse_option)  If VMS, accept -+ and -h options.
+
+       * vms.c (VMS_Case_Hack_Symbol)  Replace #if NO_CASE_HACKING
+               with references to the -h option.  These small VMS patches
+               from Angel Li (angel@flipper.miami.edu).
+
+Thu Mar  8 19:18:59 EST 1990   hack@wookumz
+       * vms.c         Some trivial patches from Eric Youngdale
+                       (YOUNGDALE@v6550c.nrl.navy.mil)
+
+Wed Mar  7 17:12:09 EST 1990   hack@wookumz
+       * make-gas.com  (Define error as as_fatal when compiling vax.c and vms.c
+                       A two line patch from Eric Youngdale
+                       (YOUNGDALE@v6550c.nrl.navy.mil)
+
+Tue Mar  6 16:01:09 EST 1990   hack@wookumz
+
+       * Makefile  Include ns32k options in makefile.  A small patch from
+       David Taylor (taylor@think.com).
+
+       * as.c read.c write.c Makefile  #ifdef DONTDEF out all the gdb
+       symbol stuff, since it isn't used anymore and it doesn't work.
+
+Mon Mar  5 14:51:04 EST 1990   hack@wookumz
+
+       * i386.c (md_assemble) Replace memchr() with index().
+
+       * as.c  Trap signals 1 through NSIG, print an error msg, and don't
+       produce an object file.
+
+       * m68k.c Added a hack so that fsincosx fpx,fpy:fpz works.
+
+       * messages.c New function: as_bad  This is like as_warn, except
+       -W doesn't disable it, and calling it inhibits production of an
+       object file and causes a non-zero exit code.
+
+Tue Feb 13 14:25:53 EST 1990   hack@wookumz
+       * Makefile  Include G0 and LOADLIBES for Sequent Symmetry.
+       Based on a small patch from Johan Widen (jw@sics.se)
+
+Thu Feb  1 14:08:58 EST 1990   hack@wookumz
+       * m68k.c  Replace 'abort' with 'abort()' which will work.
+
+Wed Jan 24 17:15:08 EST 1990   hack@ai.mit.edu
+
+       * read.c  (ignore_rest_of_line)  Have it print the first junk char
+       in both decimal and %c form.
+
+       (read_a_source_file)  On bad pseudo-op, print out the unknown
+       pseudo-op's name.
+
+Tue Jan 23 13:12:48 EST 1990   hack@ai.mit.edu
+
+       * read.c (pseudo_set)   If the symbol is external, have it remain
+       external.
+
+       * i386-opcode.h  Allow jc as a synonym for jb and jnc as a syn for jnb.
+
+
+Wed Jan  3 09:35:31 EST 1990   hack@ai.mit.edu
+
+       * ns32k.c [cpureg_032]  Change register id of psr from 0x0b to 0x0d
+       * ns32k-opcode.h        Change shift-counts for lsh and lshd
+       to one byte instead of 2 and 4.
+       A Trivial patch from John F. Peters (think!ames!practic.com!jfp@eddie)
+
+Tue Dec  5 16:37:44 EST 1989   hack@ai.mit.edu
+
+       * ns32k.c (md_create_{long,short}_jump)  Six line patch from
+       John F Peters (think!ames!vine!practice.com!jfp) to use the
+       correct addressing mode and byte-order for broken-word stuff.
+
+       * write.c (write_object_file)  One line patch to call fix_new_ns32k
+       with the correct # of args.
+
+Fri Dec  1 16:44:21 EST 1989   hack@ai.mit.edu
+
+       * atof-generic.c, flonum-mult.c  A real fix for the trailing-zeroes
+       problem from Georg Feil (ghfeil@white.toronto.edu)  (two line change)
+
+Mon Nov 27 15:30:46 EST 1989   hack@ai.mit.edu
+
+       * i386-opcode.h  Fixed opcode-table entry for ljmp.  A one char
+       patch from eliot@mgm.mit.edu
+
+Mon Nov 20 12:41:28 EST 1989   hack@ai.mit.edu
+
+       * expr.c  Replace the generic_buffer hack with a more portable one */
+
+       * atof-generic.c (atof_generic)  Ignore trailing zeroes after a decimal
+       point.  For some reason trailing zeroes (but not trailing nonzeroes) were
+       causing loss of precision.  I don't know why. . .
+
+       * vms.c Change copyright notice.  Install changes from Kenneth Adelman
+       (adelman@tgv.com) for c++?  (A dozen lines or so)
+
+Mon Nov 13 11:48:44 EST 1989   hack@ai.mit.edu
+
+       * Makefile  Add BINDIR and use it to control where the executable is
+       installed.
+
+       * i386.c Use __builtin_alloca if possible (trivial patch from
+       Marco S. Hyman pacbell!dumbcat!marc)
+
+Mon Nov  6 18:24:47 EST 1989   hack@ai.mit.edu
+
+       * version.c  New version: 1.35 will be distributed with the
+       1.36 gcc release.
+
+Mon Oct 30 10:38:11 EST 1989   hack@ai.mit.edu
+
+       * atof-m68k.c (atof_m68k)  Don't put the bits[] array on the stack,
+       since it may be pointed to after atof-m68k exits.
+
+Tue Oct 24 11:15:57 EDT 1989   hack@ai.mit.edu
+
+       * atof-m68k.c  Added #define for bcopy on USG systems.
+       #ifdef TEST the print_gen() function.
+
+       * a.out.h  if USE_HP_INC_HDR then use ../binutils/hp-include/a.out.h
+
+Fri Oct 13 14:36:48 EDT 1989   hack@ai.mit.edu
+
+       * vax.c (all)  Ran vax through indent -gnu to make it readable.
+
+       vax.c (vip_op)  Correctly assemble code like jmp $*0x11223344
+       by setting vip_nbytes to 4 when using an immediate address.
+       I hope this works!
+
+       m68k.c (s_proc (new))  Added s_proc no-op pseudo-op.
+
+       Makefile  Added instructions for compiling on Sequent Symmetry
+       and HP 9000/300.
+
+       a.out.h Modified to compile on Sequent and HP above.  (HP port
+       based on a msg from asjl@comp.vuw.ac.nz (real name unknown)).
+
+Tue Oct 10 14:39:44 EDT 1989   hack@ai.mit.edu
+       * vax.c (vip_op)        Fixed a typo in an error msg and cleaned
+       up some spacing stuff.
+
+Wed Sep 27 19:07:12 EDT 1989   hack@ai.mit.edu
+
+       * app.c (do_scrub_next_char)    Fixed parsing of
+               # <line> "file" garbage
+       text so that it'll work again?  (8 line patch from Mike Hibler
+       (mike@cs.utah.edu))
+
+Mon Sep 18 16:26:01 EDT 1989   hack@ai.mit.edu
+
+       * app.c (do_scrub_next_char): Modify parsing of /* ... */ to work
+       on the text /* ****/
+
+       * sparc.c (sparc_ip):  Don't abort on insns that use the Alternate
+       Spaces.  Try to assemble them correctly.
+
+Thu Sep 14 11:42:44 EDT 1989   hack@ai.mit.edu
+
+       * sparc.c (md_number_to_imm)  Dozen line patch from jkp@sauna.hut.fi
+       (Jyrki Kuoppala) so that gas output will work with shared libraries.
+
+       * ns32k.c Include <string.h> instead of <strings.h> if USG defined.
+
+       (md_end)  free(freeptr_static) instead of free(freeptr) .
+
+       * atof-ns32k.c  Include as.h so that sysV stuff (bzero) will be
+       defined if needed.  These ns32k changes from
+       nixbur!mollers.pad@seismo.css.gov (Josef Moellers)
+
+Fri Sep  1 11:39:52 EDT 1989   hack@ai.mit.edu
+
+       * atof-m68k.c (gen_to_words)  Get the sign right on negative
+       floating-point numbers.
+
+Wed Aug 30 13:59:57 EDT 1989   hack@ai.mit.edu
+
+       * Makefile  Remove the rest of the $< entries that kill sun make
+
+Fri Aug 25 15:00:30 EDT 1989   Nobody You Know (hack@ai.mit.edu)
+
+       * atof-m68k.c (gen_to_words) deal with denormalized floating-point
+       numbers.
+
+Tue Aug 22 02:03:05 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * Makefile (gas-dist.tar): Put ChangeLog in the tar file.
+
+       * version.c: Added comment telling Jay Fenl--I mean people--not to put
+       changes in version.c, but to use ChangeLog instead.
+
+       * version.c (version_string): Put "GNU" in all-caps.
+
+       * version.c: Moved all comments about changes to ChangeLog (this file).
+       Many anonymous entries have been attributed to Jay Fenlason (hack).
+
+Thu Aug 17 15:53:57 1989  Jay Fenlason  (hack at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Removed $< references that seem
+       to choke some versions of make.
+
+       * frags.c (frag_grow): Fixed to deal with requests for very
+       large frags (larger than frags.chunk_size).
+
+       * app.c (do_scrub_next_char): Have it ignore any characters
+       after the filename in a # line "filename".
+
+       * sparc.c (s_common): On an error, don't print out
+       input_line_pointer past the end of the line where the error is.
+
+       * atof-generic.c (atof_generic): Accept any case for
+       inf and nan.
+
+       * m68k.c (m68_ip): Don't use PC-relative mode for alterable
+       addressing modes.
+
+Tue Aug 15 04:58:36 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * sparc.c (md_begin): Rewrote this function to perform consistency
+       checks with the new opcode table.
+
+Fri Aug 11 16:01:16 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * sparc-opcode.h (struct sparc_opcode): Replaced `mask' field with
+       `lose'; removed `last' field.  Updated all opcodes accordingly.
+       Fixed several opcodes that generated the wrong instructions.
+       sparc.c (md_begin, sparc_ip): Changed to use new struct sparc_opcode.
+
+Thu Aug  3 14:44:24 1989  Jay Fenlason  (hack at apple-gunkies.ai.mit.edu)
+
+       * Makefile (a32k): Use read- and write-ns32k.o
+       * ns32k.c (encode_operand): Make sure pcrel_adjust starts out zeroed.
+       * read.c (cons): Call fix_new_ns32k() if NS32K is defined.
+       * write.c (write_object_file): Ditto.
+       These so that .word sym-sym (etc) will produce values with
+       the proper byte-order.
+
+Wed Aug 2 12:55:?? 1989  Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
+
+       * sparc.c (comment_chars[]): Removed '|' because it was causing
+       problems.  Probably not the best fix, since I suspect other
+       assemblers (68020) may get | in .stabs also, and the 68020 needs
+       the '|' comment character.
+
+Mon Jul 31 09:22:28 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * sparc.c (sparc_ip): Allow the characters [0123] in opcodes.
+
+Tue Jul 25 16:32:12 1989  Jay Fenlason  (hack)
+
+       * atof-generic.c (atof_generic): Tried to keep
+       size_of_digits_in_littlenum from going negative.
+
+       * sparc-opcode.h: Added duplicate [i+1] entries to go with
+       the [1+i] entries already there.  A kludgy fix, but it works.
+
+Mon Jul 24 17:20:03 1989  Jay Fenlason  (hack)
+
+       * write.c (relax_segment): Modified rs_org code so it won't
+       occasionally dump core.
+
+       * write.c (pseudo_set): Modified SEG_DIFFERENCE to (perhaps)
+       allow one to set a symbol to the difference of two other symbols.
+
+       * ns32k.c (convert_iif): Moved size_so_far+=size and size=0 inside
+        the check for a valid type.
+
+       * sparc-opcode.h: Modified the entries for std "q,[1+i]", "D,[1+i]",
+       and "Q,[1+i]".
+
+(In version 1.34)  Jay Fenlason  (hack)
+
+       * Makefile: Reorganized, added stuff to make asparc.
+
+       * sparc.c, sparc-opcode.h, sparc.h: Sparc port.
+
+       * write.c: Set the size of text and bss segments to a multiple of eight
+       bytes.
+
+       * m68k.c: Moved .single pseudo-op to machine independent part.
+
+       * atof-generic.c: Fixed type in #ifdef __GNUC__.
+
+       * sparc-opcode.h: Handle "mov REG, %y".
+
+       * make-gas.com: Know that error.c no longer exists.
+
+       * sparc.c: Handle [expr+reg].
+       Don't call getExpression when looking for an immediate and getting
+       something that starts with % and isn't %hi or %lo.
+
+       * Teach the 68k about long conditional branches.
+
+(In version 1.33)  Jay Fenlason  (hack)
+
+       * Use __builtin_alloca if available.
+
+       * README: Added more instructions for reporting bugs.
+
+       * ns32k-opcode.h: Changed the acbb, acbw, and acbd insns.
+
+       * vax.c: Replaced instances of LENGTH[STRING] with STRING[LENGTH].
+
+       * ns32k.c (encode_operand): Increased max size of bit field for exts
+       and inss instructions from 31 to 32 bits.
+
+       * flonum-mult.c (flonum_multip): Fixed typo.
+
+       * m68kc.: Allow #32 to be the same as #0 for bit-field ops.
+
+       * make-gas.com, version.c, hex-value.c, flonum-const.c: VMS fixes.
+
+       * ns32k.c, ns32k-opcode.h: More fixes from taylor@think.com.
+       Mostly typos in comments, etc.
+
+       * ns32k-opcode.h: Fixed size of immediate operands to andw and andd
+       instructions.
+
+(In version 1.32)  Jay Fenlason  (hack)
+
+       * read.c (s_set): Fixed misnamed variable.
+
+       * as.c: Don't hang if given an invalid option.
+
+       * m68k.c: Fixed bug in creating absolute long addresses for branches.
+
+       * ns3k*: Some small ns32k patches.
+
+       * m68k.c: Recognize 0rnan, 0rinf, 0r-inf.
+
+       * app.c: Don't dump core on unterminated strings.
+
+       * symbols.c: Give reasonable error messages.
+
+       * ns32k*: Allow -m32032 and -m32532 options.
+
+       * atof-*.c: Added support for NaN, Inf, and -Inf in atof_generic and
+       the various descriptions.
+
+       * m68k.c (add_fix): Replace occurrences of "width==" with
+       "(width)==".  This correct a precedence problem.
+
+       * write.c, struc-symbol.h, m68k-opcode.h, m-hpux.h, Makefile: Changes
+       for HP-UX from Chris Hanson (cph@kleph.ai.mit.edu).
+
+       * m68k-opcode.h: Reorder movem insns so gdb will see the ones using the
+       register list syntax first.
+
+       * symbols.c (colon): Give more useful error messages when something was
+       defined as a .comm and is now trying to be defined locally.
+       Also, redefining a symbol is a fatal, not a warning.
+
+       * m68k.c: Fixed a bug in using bignums as literal bit patterns for
+       floating-point numbers.
+
+(In version 1.31)  Jay Fenlason  (hack)
+
+       * i386*: More patches.
+
+       * Moved machine-dependent option parsing into the machine-dependent
+       source files.
+
+(In version 1.30)  Jay Fenlason  (hack)
+
+       * i386*: New new version.
+
+       * atof-m68k.c: Changed to be smaller, with somewhat better modularity.
+       Also fixed an obscure bug wherein next_bits would return random bits.
+
+       * m68k.c: Be more careful about creating PC-relative addressing modes
+       on the 68000 and 68010.
+
+       * frags.c (frag_new): Zero out the new frag.
+
+       * Don't choke on "foo= bar" or on formfeeds.
+
+       * read.c: Allow Sun-syntax local labels #ifdef SUN_ASM_SYNTAX.
+       * m-sun3.h: Defined SUN_ASM_SYNTAX.
+
+(In version 1.29)  Jay Fenlason  (hack)
+
+       * i386.c: Newer version that fixes a bug wherein a jump instruction
+       would be split between two frags.
+
+       * i386*: New version.
+
+       * m68k.c: #ifdef M_SUN and -m68010, produce Sun-2 executables.
+
+(In version 1.28)  Jay Fenlason  (hack)
+
+       * m68k.c: Added .single pseudo-op.
+
+       * Made ". = X" and ".set .,X" equivalent to ".org X".
+       The pseudo-symbol "." has the value of the location the assembler is
+       currently assembling to.
+
+(In version 1.27)  Jay Fenlason  (hack)
+
+       * Merged ns32k and i386 support.
+
+(In version 1.26)  Jay Fenlason  (hack)
+
+       * Added partial ns32k support.
+
+       * Added RMS's evil .word misfeature.  Invented the -k (kludge) option
+       to warn that this misfeature was used.
+
+       * Modified some files to get rid of warnings from GCC.
+
+       * Added fix so that / can also be a comment character by itself.
+
+(In version 1.25)  Jay Fenlason  (hack)
+
+       * Installed patches for VMS.
+
+       * as.h (SIZEOF_STRUCT_FRAG): Added space before backslash-newline.
+
+       * messages.c: Fixed typo.
+
+       * app.c: Handle : correctly.
+
+       * error.c: Removed; no longer used.
+
+       * m68k-opcode.h: Added fnop.
+       Fixed to correctly handle fmovem with a register list and
+       non-predecriment addressing mode.
+
+       * m68k-opcode.h: Fixed to know about long form of FBcc insns.
+
+       * write.c: Warn if a fixup ended up being wider than its field width.
+
+(In version 1.24)  Jay Fenlason  (hack)
+
+       * Accept and ignore -mc68010 and -m68010 switches.
+
+       * Correctly assemble long subroutine calls on the 68000 without using a
+       68020-specific instruction.
+
+       * When calling with no filenames, read stdin.
+
+(In version 1.23)  Jay Fenlason (hack)
+
+       * app.c: Rewritten.
+
+       * xmalloc.c, xrealloc.c: Replaced to work with GCC.
+
+(In version 1.22)  Jay Fenlason  (hack)
+
+       * write.c: Fixed a VMS bug.
+
+       * m68k.c: Fixed a bug having to do with turning absolute into
+       PC-relative.
+
+       * atof-m68k.c (atof_m68k, gen_to_words): Try to avoid a problem with
+       running off the end of the LITTLENUMS.
+
+       * vax.c: Fixed so parenthesized expressions work.
+
+       * atof-generic.c: Added a cast that fixes problems with some C
+       compilers.
+
+(In version 1.21)
+
+       * Changes for VMS support and correct bitfield order for
+       cross-assembly.
+
+(In version 1.20)
+
+       * m68k*: Fixed "fmovel #N, fpcr".  Added fpcr and fpsr to the list of
+       registers.
+
+(In version 1.19)
+
+       * m68k.c? (md_convert_frag): Don't put the fixups for absolute long to
+       PC-relative in the data segment.
+
+       * atof-generic.c: #include <alloca.h> #ifdef sparc.
+
+(In version 1.18)
+
+       * Re-fixed _vfprintf stuff (?).
+
+       * Made "movem REG, ADDR" work.
+
+       * Improved preprocessing, without temporary files.
+
+(In version 1.17)
+
+       * Don't produce an undefined empty symbol for ".globl foo," (a line
+       ending with a comma).
+
+       * Fixed a bug wherein ".long X" became ".long 0" on the Sparc.
+
+       * Fixed a bug which caused many "#APP" "#NO_APP" pairs to dump core.
+
+       * Fixed calls to _doprnt to call _vfprintf #ifndef NO_VARARGS.
+
+(In version 1.16)
+
+       * Merged HP-UX changes from Chris Hanson (cph@zurich.ai.mit.edu).
+
+       * flonum-multip.c: Renamed to flonum-mult.c.
+
+       * m-hpux.h: Created.
+
+       * m68k.c (bcopy): Fixed.
+
+(In version 1.15)
+
+       * struct-symbol.h: Renamed to struc-symbol.h.
+
+(In version 1.14)
+
+       * vax.c: Added a quick fix for the offset of fixed-width branches not
+       fitting in the field given.
+
+       * gdb-lines.c, read.c: Added support for .gdline and .gdbline
+       pseudo-ops.
+
+(In version 1.13)
+
+       * read.c, atof-generic.c: Fixed bugs in reading in floating-point
+       numbers.
+
+       * m68k-opcode.h: Made "fmovep a0@, fp0" work.
+
+(In version 1.12)
+
+       * write.c: Fixed an obscure bug in relaction that would occasionally
+       cause the assembler to stop relaxing when it really had at least one
+       more pass to do.
+
+(In version 1.11)
+
+       * m68k*: Allow register lists in fmovem.
+
+       * Added more floating-point exponents.
+
+       * Print an error message on exponent overflow.
+
+(In version 1.10)
+
+       * Fixed floating point bugs that made it generate incorrect numbers for
+       values over 10^16 or so.
+
+(In version 1.09)
+
+       * Fixed bug wherein you couldn't forward reference local label 0.
+
+(In version 1.08)
+
+       * m68k.c, m68k-opcode.h: Added support for fmovem with register lists.
+
+       * Fixed an obscure bug having to do with generating PC-relative
+       addressing mode for things in the middle of the instruction instead of
+       at the end.
+
+Wed Mar  1 15:29:24 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * *.*: Modified copyright notices to reflect new General Public
+       License. 
+
+       * Makefile: Added copyright notice.
+
+Fri Feb 17 09:42:01 1989  Jay Fenlason  (hack at spiff)
+
+       * Patched frags.c so that new frags start out bzero()ed.
+
+Thu Jan 26 14:23:44 1989  Jay Fenlason  (hack at apple-gunkies.ai.mit.edu)
+
+       * Added patches from pace to files as.h i386.c i386-opcode.h
+         imull foo,%eax no longer gets assembled into the 32-64 bit
+         multiply, which clobbers %edx behind gcc's back
+
+         jcxz/jecxz were backwards
+
+         There was a bug when using %ebp as a base register with no
+         displacement
+
+         Instructions like andb $0xffffff, %al used to put out too many
+         immediate bytes
+
+         The splitting jump instructions across frags could happen when
+         obstack_room()==6 too.
+\f
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/gas/Makefile-intel b/gas/Makefile-intel
new file mode 100755 (executable)
index 0000000..54487c2
--- /dev/null
@@ -0,0 +1,146 @@
+#-----------------------------------------------------------------------------
+#              Makefile for gas960
+#
+# $Id$
+#-----------------------------------------------------------------------------
+
+# The following two lines should be uncommented for system V (i386v).
+#__i386v__#USG = -DUSG
+#__i386v__#LIBS = -lmalloc -lPW
+
+# The following two lines should be uncommented for HP-UX
+#__hp9000__#USG = -DUSG
+
+# The following line should be uncommented for Macintosh A/UX.
+#__mac-aux__#USG = -DUSG
+
+#Always build with static libraries on Sun systems
+#__sun3__#LDFLAGS = -Bstatic
+#__sun386i__#LDFLAGS = -Bstatic
+#__sun4__#LDFLAGS = -Bstatic
+
+# Essential under System V, harmless elsewhere
+SHELL = /bin/sh
+
+TARG   = gas960
+OPT    = -g
+IPATH  = ../../include
+CFLAGS = ${OPT} ${USG} -DI80960 -I${IPATH}
+
+
+OBJS = app.o append.o as.o atof-generic.o bignum-copy.o expr.o \
+       flonum-const.o flonum-copy.o flonum-mult.o frags.o gdb-blocks.o \
+       gdb-file.o gdb-lines.o gdb-symbols.o gdb.o hash.o hex-value.o \
+       input-file.o input-scrub.o messages.o obstack.o output-file.o read.o \
+       strstr.o subsegs.o symbols.o version.o write.o xmalloc.o xrealloc.o
+
+# Note that we use the 386 floating-point support for the i80960
+I960OBJ        = i960.o i960-opcode.o atof-i386.o
+
+gas960:        ${OBJS} ${I960OBJ} VERSION
+       make ver960.o
+       ${CC} -o gas960 ${LDFLAGS} ${OBJS} ${I960OBJ} ver960.o ${LIBS}
+
+hash.o:        hash.c
+       ${CC} -c ${CFLAGS} -Derror=as_fatal hash.c
+
+xmalloc.o:     xmalloc.c
+       ${CC} -c ${CFLAGS} -Derror=as_fatal xmalloc.c
+
+xrealloc.o:    xrealloc.c
+       ${CC} -c ${CFLAGS} -Derror=as_fatal xrealloc.c
+
+app.o:         as.h
+
+as.o:          ${IPATH}/b.out.h as.h read.h struc-symbol.h write.h
+atof-generic.o:        flonum.h
+bignum-copy.o: bignum.h
+expr.o:                ${IPATH}/b.out.h as.h expr.h flonum.h obstack.h read.h
+expr.o:                struc-symbol.h symbols.h
+flonum-const.o:        flonum.h
+flonum-copy.o: flonum.h
+flonum-mult.o: flonum.h
+flonum-normal.o:flonum.h
+flonum-print.o:        flonum.h
+frags.o:       ${IPATH}/b.out.h as.h frags.h obstack.h struc-symbol.h subsegs.h
+gdb.o:         as.h
+gdb-blocks.o:  as.h
+gdb-lines.o:   as.h frags.h obstack.h
+gdb-symbols.o: ${IPATH}/b.out.h as.h struc-symbol.h
+hash.o:                hash.h
+i960.o:                as.h ${IPATH}/b.out.h expr.h flonum.h frags.h hash.h
+i960.o:                i960-opcode.h md.h obstack.h struc-symbol.h write.h
+i960-opcode.o: i960-opcode.h
+input-file.o:  input-file.h
+input-scrub.o: as.h input-file.h read.h
+messages.o:    as.h
+obstack.o:     obstack.h
+read.o:                ${IPATH}/b.out.h as.h expr.h flonum.h frags.h hash.h md.h
+read.o:                obstack.h read.h struc-symbol.h symbols.h
+subsegs.o:     ${IPATH}/b.out.h as.h frags.h obstack.h struc-symbol.h subsegs.h
+subsegs.o:     write.h
+symbols.o:     ${IPATH}/b.out.h as.h frags.h hash.h obstack.h struc-symbol.h
+symbols.o:     symbols.h
+write.o:       ${IPATH}/b.out.h as.h md.h obstack.h struc-symbol.h subsegs.h
+write.o:       symbols.h write.h
+
+flonum.h:      bignum.h
+
+#-----------------------------------------------------------------------------
+#              'STANDARD' GNU/960 TARGETS BELOW THIS POINT
+#
+# 'VERSION' file must be present and contain a string of the form "x.y"
+#-----------------------------------------------------------------------------
+
+ver960.c: FORCE
+       rm -f ver960.c
+       echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c
+
+
+# This target should be invoked before building a new release.
+# 'VERSION' file must be present and contain a string of the form "x.y"
+#
+roll:
+       @V=`cat VERSION`                ; \
+       MAJ=`sed 's/\..*//' VERSION`    ; \
+       MIN=`sed 's/.*\.//' VERSION`    ; \
+       V=$$MAJ.`expr $$MIN + 1`        ; \
+       rm -f VERSION                   ; \
+       echo $$V >VERSION               ; \
+       echo Version $$V
+
+# Dummy target to force execution of dependent targets.
+#
+FORCE:
+
+# 'G960BASE' will be defined at invocation
+install:
+       make ${TARG} OPT=-O
+       strip ${TARG}
+       rm -f ${G960BASE}/bin/${TARG}
+       mv ${TARG} ${G960BASE}/bin/${TARG}
+
+clean:
+       rm -f ${TARG} *.o core
+
+# Target to uncomment host-specific lines in this makefile.  Such lines must
+# have the following string beginning in column 1: #__<hostname>__#
+# Original Makefile is backed up as 'Makefile.old'.
+#
+# Invoke with:  make make HOST=xxx
+#
+make:
+       -@if test $(HOST)x = x ; then \
+               echo '\aSpecify "make make HOST=???"'; \
+               exit 1; \
+       fi ; \
+       grep -s "^#The next line was generated by 'make make'" Makefile; \
+       if test $$? = 0 ; then  \
+               echo "\aMakefile has already been processed with 'make make'";\
+               exit 1; \
+       fi ; \
+       mv -f Makefile Makefile.old; \
+       echo "#The next line was generated by 'make make'"       >Makefile ; \
+       echo "HOST=$(HOST)"                                     >>Makefile ; \
+       echo                                                    >>Makefile ; \
+       sed "s/^#__$(HOST)__#//" < Makefile.old                 >>Makefile
diff --git a/gas/Makefile.generic b/gas/Makefile.generic
new file mode 100755 (executable)
index 0000000..1bf57a3
--- /dev/null
@@ -0,0 +1,586 @@
+host = generic
+target = generic
+# Makefile for GNU Assembler
+#   Copyright (C) 1987, 1988, 1990, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# $Id$
+
+# 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.
+# See below for how to change them for certain systems.
+
+ALLOCA =
+CFLAGS = -g $(XCFLAGS) # -I$(srcdir)/../include
+INTERNAL_CFLAGS = $(CROSS)
+OLDCC = cc
+BISON = bison
+BISONFLAGS = -v
+AR = ar
+OLDAR_FLAGS = qc
+AR_FLAGS = rc
+SHELL = /bin/sh
+# on sysV, define this as cp.
+INSTALL = install -c
+# These permit overriding just for certain files.
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_FILE = $(INSTALL)
+
+# Define this as & to perform parallel make on a Sequent.
+# Note that this has some bugs, and it seems currently necessary 
+# to compile all the gen* files first by hand to avoid erroneous results.
+P =
+
+# How to invoke ranlib.
+RANLIB = ranlib
+# Test to use to see whether ranlib exists on the system.
+RANLIB_TEST = [ -f /usr/bin/ranlib -o -f /bin/ranlib ]
+
+# CFLAGS for use with OLDCC, for compiling gnulib.
+# NOTE: -O does not work on some Unix systems!
+CCLIBFLAGS = -O
+
+# Version of ar to use when compiling gnulib. 
+OLDAR = ar
+
+version=`./gcc -dumpversion`
+
+# Directory where sources are, from where we are.
+srcdir = .
+# Common prefix for installation directories.
+# NOTE: This directory must exist when you start installation.
+prefix = /usr/local
+# Directory in which to put the executable for the command `gcc'
+bindir = $(prefix)/bin
+# Directory in which to put the directories used by the compiler.
+libdir = $(prefix)/lib
+# Directory in which the compiler finds executables, libraries, etc.
+libsubdir = $(libdir)/gcc/$(target)/$(version)
+# Number to put in man-page filename.
+manext = 1
+# Directory in which to put man pages.
+mandir = $(prefix)/man/man$(manext)
+
+# Additional system libraries to link with.
+CLIB=
+
+# Change this to a null string if obstacks are installed in the
+# system library.
+OBSTACK=obstack.o
+
+# Specify the rule for actually making gnulib.
+GNULIB = gnulib.portable
+
+# Specify the rule for actually making gnulib2.
+GNULIB2 = gnulib2.portable
+
+# List of extra C and assembler files to add to gnulib.
+# Assembler files should have names ending in `.asm'.
+LIBFUNCS_EXTRA = 
+
+# Program to convert libraries.
+LIBCONVERT = 
+
+# Control whether header files are installed.
+INSTALL_HEADERS=install-headers
+
+# Change this to empty to prevent installing limits.h
+LIMITS_H = limits.h
+
+# Directory to link to, when using the target `maketest'.
+DIR = ../gcc
+
+# For better debugging under COFF, define SEPARATE_AUX_OUTPUT in config.h
+# and define the following variable as `aux-output2.c' in make-...
+AUX_OUTPUT2 =
+
+# Flags to use when cross-building GCC.
+# Prefix to apply to names of object files when using them
+# to run on the machine we are compiling on.
+HOST_PREFIX=
+# Prefix to apply to names of object files when compiling them
+# to run on the machine we are compiling on.
+# The default for this variable is chosen to keep these rules 
+# out of the way of the other rules for compiling the same source files.
+HOST_PREFIX_1=loser-
+HOST_CC=$(CC)
+HOST_CFLAGS=$(ALL_CFLAGS)
+HOST_LDFLAGS=$(LDFLAGS)
+HOST_CPPFLAGS=$(CPPFLAGS)
+
+# Choose the real default target.
+ALL=bootstrap
+
+# End of variables for you to override.
+
+# Lists of files for various purposes.
+
+REAL_SOURCES = \
+       $(srcdir)/app.c \
+       $(srcdir)/as.c \
+       $(srcdir)/atof-generic.c \
+       $(srcdir)/bignum-copy.c \
+       $(srcdir)/cond.c \
+       $(srcdir)/expr.c \
+       $(srcdir)/flonum-const.c \
+       $(srcdir)/flonum-copy.c \
+       $(srcdir)/flonum-mult.c \
+       $(srcdir)/frags.c \
+       $(srcdir)/hash.c \
+       $(srcdir)/hex-value.c \
+       $(srcdir)/input-file.c \
+       $(srcdir)/input-scrub.c \
+       $(srcdir)/messages.c \
+       $(srcdir)/output-file.c \
+       $(srcdir)/read.c \
+       $(srcdir)/strstr.c \
+       $(srcdir)/subsegs.c \
+       $(srcdir)/symbols.c \
+       $(srcdir)/version.c \
+       $(srcdir)/write.c \
+       $(srcdir)/xmalloc.c \
+       $(srcdir)/xrealloc.c
+
+# in an expedient order
+LINKED_SOURCES = \
+       targ-cpu.c \
+       obj-format.c \
+       atof-targ.c
+
+SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES)
+
+REAL_HEADERS = \
+       $(srcdir)/as.h \
+       $(srcdir)/bignum.h \
+       $(srcdir)/expr.h \
+       $(srcdir)/flonum.h \
+       $(srcdir)/frags.h \
+       $(srcdir)/hash.h \
+       $(srcdir)/input-file.h \
+       $(srcdir)/tc.h \
+       $(srcdir)/obj.h \
+       $(srcdir)/read.h \
+       $(srcdir)/reloc.h \
+       $(srcdir)/struc-symbol.h \
+       $(srcdir)/subsegs.h \
+       $(srcdir)/symbols.h \
+       $(srcdir)/syscalls.h \
+       $(srcdir)/write.h
+
+LINKED_HEADERS = \
+       a.out.gnu.h \
+       a.out.h \
+       host.h \
+       targ-env.h \
+       targ-cpu.h \
+       obj-format.h \
+       atof-targ.h
+
+HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
+
+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-const.o \
+       flonum-copy.o \
+       flonum-mult.o \
+       frags.o \
+       hash.o \
+       hex-value.o \
+       input-file.o \
+       input-scrub.o \
+       messages.o \
+       output-file.o \
+       read.o \
+       strstr.o \
+       subsegs.o \
+       symbols.o \
+       version.o \
+       write.o \
+       xmalloc.o \
+       xrealloc.o
+
+# Definition of `all' is here so that new rules inserted by sed
+# do not specify the default target.
+# The real definition is under `all.internal'.
+
+all: $(ALL)
+
+# sed inserts variable overrides after the following line.
+####
+
+# Now figure out from those variables how to compile and link.
+
+# This is the variable actually used when we compile.
+ALL_CFLAGS = $(INTERNAL_CFLAGS) $(CFLAGS)
+
+# Even if ALLOCA is set, don't use it if compiling with GCC.
+USE_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${ALLOCA}; else true; fi`
+USE_HOST_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${HOST_PREFIX}${ALLOCA}; else true; fi`
+
+# Dependency on obstack, alloca, malloc or whatever library facilities
+# are not installed in the system libraries.
+# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
+LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC)
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
+HOST_LIBDEPS= $(HOST_PREFIX)$(OBSTACK) $(HOST_PREFIX)$(ALLOCA) $(HOST_PREFIX)$(MALLOC)
+
+# How to link with both our special library facilities
+# and the system's installed libraries.
+LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(CLIB)
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+HOST_LIBS = $(HOST_PREFIX)$(OBSTACK) $(USE_HOST_ALLOCA) $(HOST_PREFIX)$(MALLOC) $(CLIB)
+
+# 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$(srcdir)/config
+SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../$(srcdir)/config
+
+# 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.
+STAGE_GCC=gcc
+STAGESTUFF = *.o gas 
+
+# The files that "belong" in CONFIG_H are deliberately omitted
+# because having them there would not be useful in actual practice.
+# All they would do is cause complete recompilation every time
+# one of the machine description files is edited.
+# That may or may not be what one wants to do.
+# If it is, rm *.o is an easy way to do it.
+# CONFIG_H = config.h tm.h
+CONFIG_H =
+
+gas: $(OBJS) $(LIBDEPS)
+       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gas $(OBJS) $(LIBS)
+
+all.internal: native
+# This is what is made with the host's compiler if making a cross assembler.
+native: config.status gas
+
+config.status:
+       @echo You must configure gas.  Look at the INSTALL file for details.
+       @false
+
+compilations: ${OBJS}
+
+# Compiling object files from source files.
+
+# Note that dependencies on obstack.h are not written
+# because that file is not part of GAS.
+
+app.o : app.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+as.o : as.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+bignum-copy.o : bignum-copy.c as.h host.h \
+  targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+cond.o : cond.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+debug.o : debug.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h 
+expr.o : expr.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+flonum-const.o : flonum-const.c flonum.h bignum.h 
+flonum-copy.o : flonum-copy.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+flonum-mult.o : flonum-mult.c flonum.h bignum.h 
+frags.o : frags.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h 
+hash.o : hash.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+hex-value.o : hex-value.c 
+input-file.o : input-file.c as.h host.h \
+   targ-env.h obj-format.h targ-cpu.h \
+   struc-symbol.h reloc.h write.h flonum.h bignum.h expr.h \
+  frags.h hash.h read.h symbols.h tc.h obj.h input-file.h 
+input-scrub.o : input-scrub.c /usr/include/errno.h /usr/include/sys/errno.h \
+  as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  input-file.h 
+messages.o : messages.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+obstack.o : obstack.c obstack.h 
+output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  output-file.h 
+read.o : read.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+strstr.o : strstr.c   
+subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h 
+symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h subsegs.h 
+version.o : version.c 
+write.o : write.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h output-file.h 
+xmalloc.o : xmalloc.c
+xrealloc.o : xrealloc.c 
+atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h 
+obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h obstack.h 
+targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h obstack.h
+
+# Normally this target is not used; but it is used if you
+# define ALLOCA=alloca.o.  In that case, you must get a suitable alloca.c
+# from the GNU Emacs distribution.
+# Note some machines won't allow $(CC) without -S on this source file.
+alloca.o:      alloca.c
+       $(CC) $(ALL_CFLAGS) $(CPPFLAGS) -S `echo $(srcdir)/alloca.c | sed 's,^\./,,'`
+       as alloca.s -o alloca.o
+
+# Compile the libraries to be used by gen*.
+# If we are not cross-building, gen* use the same .o's that cc1 will use,
+# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict
+# with the rules for rtl.o, alloca.o, etc.
+$(HOST_PREFIX_1)alloca.o: alloca.c
+       rm -f $(HOST_PREFIX)alloca.c
+       cp $(srcdir)/alloca.c $(HOST_PREFIX)alloca.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c
+
+$(HOST_PREFIX_1)obstack.o: obstack.c
+       rm -f $(HOST_PREFIX)obstack.c
+       cp $(srcdir)/obstack.c $(HOST_PREFIX)obstack.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
+
+$(HOST_PREFIX_1)malloc.o: malloc.c
+       rm -f $(HOST_PREFIX)malloc.c
+       cp $(srcdir)/malloc.c $(HOST_PREFIX)malloc.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c
+
+# Remake the info files.
+
+doc: $(srcdir)/gas.info
+
+$(srcdir)/gas.info: $(srcdir)/gas.texinfo
+       makeinfo `echo $(srcdir)/gas.texinfo | sed 's,^\./,,'`
+
+
+# Deletion of files made during compilation.
+# There are three levels of this: `clean', `cleanconfig' and `realclean'.
+# `clean' deletes what you want to delete ordinarily to save space.
+# This is most, but not all, of the files made by compilation.
+# `cleanconfig' also deletes everything depending
+# on the choice of config files.
+# `realclean' also deletes everything that could be regenerated automatically.
+
+clean:
+       -rm -f $(STAGESTUFF)
+# Delete the temporary source copies for cross compilation.
+       -rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c
+       -rm -f $(HOST_PREFIX_1)obstack.c 
+# Delete the stamp files except stamp-gnulib2.
+       -rm -f core
+
+# Like clean but also delete the links made to configure gas.
+cleanconfig: clean
+       -rm -f config.status Makefile host.h targ-env.h
+       -rm -f targ-cpu.h targ-cpu.c
+       -rm -f obj-format.h obj-format.c
+       -rm -f atof-targ.c
+
+# Get rid of every file that's generated from some other file (except INSTALL).
+realclean: cleanconfig
+       -rm -f gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs gas.tps gas.vrs
+       -rm -f TAGS 
+       -rm -f gas.info* gas.?? gas.??s gas.log gas.toc gas.*aux
+       -rm -f *.dvi
+
+# Entry points `install', `includes' and `uninstall'.
+
+# Copy the files into directories where they will be run.
+install:
+       $(INSTALL_PROGRAM) gas $(bindir)/as
+
+# Create the installation directory.
+install-dir:
+       -mkdir $(libdir)
+       -mkdir $(libdir)/gcc
+       -mkdir $(libdir)/gcc/$(target)
+       -mkdir $(libdir)/gcc/$(target)/$(version)
+
+# Install the compiler executables built during cross compilation.
+install-cross: native install-dir
+       -if [ -f cc1 ] ; then $(INSTALL_PROGRAM) cc1 $(libsubdir)/cc1; else true; fi
+       -if [ -f cc1plus ] ; then $(INSTALL_PROGRAM) cc1plus $(libsubdir)/cc1plus; else true; fi
+       $(INSTALL_PROGRAM) cpp $(libsubdir)/cpp
+       ./gcc -dumpspecs > $(libsubdir)/specs
+       $(INSTALL_PROGRAM) gcc $(bindir)/gcc
+
+# Install the man pages.
+install-man: install-dir $(srcdir)/gcc.1 protoize.1 unprotoize.1
+       $(INSTALL_FILE) $(srcdir)/gcc.1 $(mandir)/gcc.$(manext)
+       chmod a-x $(mandir)/gcc.$(manext)
+       $(INSTALL_FILE) $(srcdir)/protoize.1 $(mandir)/protoize.$(manext)
+       chmod a-x $(mandir)/protoize.$(manext)
+       $(INSTALL_FILE) $(srcdir)/unprotoize.1 $(mandir)/unprotoize.$(manext)
+       chmod a-x $(mandir)/unprotoize.$(manext)
+
+# Cancel installation by deleting the installed files.
+uninstall:
+       -rm -rf $(libsubdir)
+       -rm -rf $(bindir)/gas
+       -rm -rf $(mandir)/gas.$(manext)
+
+
+# These exist for maintenance purposes.
+
+tags TAGS: force
+       etags $(REAL_SOURCES) $(REAL_HEADERS) README Makefile config/*.[hc]
+       
+bootstrap: gas force
+       $(MAKE) stage1
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       $(MAKE) stage2
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+bootstrap2: force
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       $(MAKE) stage2
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+bootstrap3: force
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+       -mkdir stage1
+       -mv $(STAGESTUFF) stage1
+       -(cd stage1 ; ln -s gas as)
+
+stage2: force
+       -mkdir stage2
+       -mv $(STAGESTUFF) stage2
+       -(cd stage2 ; ln -s gas as)
+
+
+stage3: force
+       -mkdir stage3
+       -mv $(STAGESTUFF) $(STAGE_GCC) stage3
+       -rm -f stage3/gnulib
+       -cp gnulib stage3
+       -if $(RANLIB_TEST) ; then $(RANLIB) stage3/gnulib; else true; fi
+
+stage4: force
+       -mkdir stage4
+       -mv $(STAGESTUFF) $(STAGE_GCC) stage4
+       -rm -f stage4/gnulib
+       -cp gnulib stage4
+       -if $(RANLIB_TEST) ; then $(RANLIB) stage4/gnulib; else true; fi
+
+# Copy just the executable files from a particular stage into a subdirectory,
+# and delete the object files.  Use this if you're just verifying a version
+# that is pretty sure to work, and you are short of disk space.
+risky-stage1: force
+       -mkdir stage1
+       -mv cc1 cpp cccp gcc stage1
+       -rm -f stage1/gnulib
+       -cp gnulib stage1 && $(RANLIB) stage1/gnulib
+       -make clean
+
+risky-stage2: force
+       -mkdir stage2
+       -mv cc1 cpp cccp gcc stage2
+       -rm -f stage2/gnulib
+       -cp gnulib stage2 && $(RANLIB) stage2/gnulib
+       -make clean
+
+risky-stage3: force
+       -mkdir stage3
+       -mv cc1 cpp cccp gcc stage3
+       -rm -f stage3/gnulib
+       -cp gnulib stage3 && $(RANLIB) stage3/gnulib
+       -make clean
+
+risky-stage4: force
+       -mkdir stage4
+       -mv cc1 cpp cccp gcc stage4
+       -rm -f stage4/gnulib
+       -cp gnulib stage4 && $(RANLIB) stage4/gnulib
+       -make clean
+
+#In GNU Make, ignore whether `stage*' exists.
+.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap
+.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(srcdir)/configure
+       $(srcdir)/configure.was -srcdir=$(srcdir) -host=$(host) $(target)
diff --git a/gas/Makefile.in b/gas/Makefile.in
new file mode 100644 (file)
index 0000000..3f263d1
--- /dev/null
@@ -0,0 +1,584 @@
+# Makefile for GNU Assembler
+#   Copyright (C) 1987, 1988, 1990, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# $Id$
+
+# 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.
+# See below for how to change them for certain systems.
+
+ALLOCA =
+CFLAGS = -g $(XCFLAGS) # -I$(srcdir)/../include
+INTERNAL_CFLAGS = $(CROSS)
+OLDCC = cc
+BISON = bison
+BISONFLAGS = -v
+AR = ar
+OLDAR_FLAGS = qc
+AR_FLAGS = rc
+SHELL = /bin/sh
+# on sysV, define this as cp.
+INSTALL = install -c
+# These permit overriding just for certain files.
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_FILE = $(INSTALL)
+
+# Define this as & to perform parallel make on a Sequent.
+# Note that this has some bugs, and it seems currently necessary 
+# to compile all the gen* files first by hand to avoid erroneous results.
+P =
+
+# How to invoke ranlib.
+RANLIB = ranlib
+# Test to use to see whether ranlib exists on the system.
+RANLIB_TEST = [ -f /usr/bin/ranlib -o -f /bin/ranlib ]
+
+# CFLAGS for use with OLDCC, for compiling gnulib.
+# NOTE: -O does not work on some Unix systems!
+CCLIBFLAGS = -O
+
+# Version of ar to use when compiling gnulib. 
+OLDAR = ar
+
+version=`./gcc -dumpversion`
+
+# Directory where sources are, from where we are.
+srcdir = .
+# Common prefix for installation directories.
+# NOTE: This directory must exist when you start installation.
+prefix = /usr/local
+# Directory in which to put the executable for the command `gcc'
+bindir = $(prefix)/bin
+# Directory in which to put the directories used by the compiler.
+libdir = $(prefix)/lib
+# Directory in which the compiler finds executables, libraries, etc.
+libsubdir = $(libdir)/gcc/$(target)/$(version)
+# Number to put in man-page filename.
+manext = 1
+# Directory in which to put man pages.
+mandir = $(prefix)/man/man$(manext)
+
+# Additional system libraries to link with.
+CLIB=
+
+# Change this to a null string if obstacks are installed in the
+# system library.
+OBSTACK=obstack.o
+
+# Specify the rule for actually making gnulib.
+GNULIB = gnulib.portable
+
+# Specify the rule for actually making gnulib2.
+GNULIB2 = gnulib2.portable
+
+# List of extra C and assembler files to add to gnulib.
+# Assembler files should have names ending in `.asm'.
+LIBFUNCS_EXTRA = 
+
+# Program to convert libraries.
+LIBCONVERT = 
+
+# Control whether header files are installed.
+INSTALL_HEADERS=install-headers
+
+# Change this to empty to prevent installing limits.h
+LIMITS_H = limits.h
+
+# Directory to link to, when using the target `maketest'.
+DIR = ../gcc
+
+# For better debugging under COFF, define SEPARATE_AUX_OUTPUT in config.h
+# and define the following variable as `aux-output2.c' in make-...
+AUX_OUTPUT2 =
+
+# Flags to use when cross-building GCC.
+# Prefix to apply to names of object files when using them
+# to run on the machine we are compiling on.
+HOST_PREFIX=
+# Prefix to apply to names of object files when compiling them
+# to run on the machine we are compiling on.
+# The default for this variable is chosen to keep these rules 
+# out of the way of the other rules for compiling the same source files.
+HOST_PREFIX_1=loser-
+HOST_CC=$(CC)
+HOST_CFLAGS=$(ALL_CFLAGS)
+HOST_LDFLAGS=$(LDFLAGS)
+HOST_CPPFLAGS=$(CPPFLAGS)
+
+# Choose the real default target.
+ALL=gas
+
+# End of variables for you to override.
+
+# Lists of files for various purposes.
+
+REAL_SOURCES = \
+       $(srcdir)/app.c \
+       $(srcdir)/as.c \
+       $(srcdir)/atof-generic.c \
+       $(srcdir)/bignum-copy.c \
+       $(srcdir)/cond.c \
+       $(srcdir)/expr.c \
+       $(srcdir)/flonum-const.c \
+       $(srcdir)/flonum-copy.c \
+       $(srcdir)/flonum-mult.c \
+       $(srcdir)/frags.c \
+       $(srcdir)/hash.c \
+       $(srcdir)/hex-value.c \
+       $(srcdir)/input-file.c \
+       $(srcdir)/input-scrub.c \
+       $(srcdir)/messages.c \
+       $(srcdir)/output-file.c \
+       $(srcdir)/read.c \
+       $(srcdir)/strstr.c \
+       $(srcdir)/subsegs.c \
+       $(srcdir)/symbols.c \
+       $(srcdir)/version.c \
+       $(srcdir)/write.c \
+       $(srcdir)/xmalloc.c \
+       $(srcdir)/xrealloc.c
+
+# in an expedient order
+LINKED_SOURCES = \
+       targ-cpu.c \
+       obj-format.c \
+       atof-targ.c
+
+SOURCES = $(LINKED_SOURCES) $(REAL_SOURCES)
+
+REAL_HEADERS = \
+       $(srcdir)/as.h \
+       $(srcdir)/bignum.h \
+       $(srcdir)/expr.h \
+       $(srcdir)/flonum.h \
+       $(srcdir)/frags.h \
+       $(srcdir)/hash.h \
+       $(srcdir)/input-file.h \
+       $(srcdir)/tc.h \
+       $(srcdir)/obj.h \
+       $(srcdir)/read.h \
+       $(srcdir)/reloc.h \
+       $(srcdir)/struc-symbol.h \
+       $(srcdir)/subsegs.h \
+       $(srcdir)/symbols.h \
+       $(srcdir)/syscalls.h \
+       $(srcdir)/write.h
+
+LINKED_HEADERS = \
+       a.out.gnu.h \
+       a.out.h \
+       host.h \
+       targ-env.h \
+       targ-cpu.h \
+       obj-format.h \
+       atof-targ.h
+
+HEADERS = $(LINKED_HEADERS) $(REAL_HEADERS)
+
+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-const.o \
+       flonum-copy.o \
+       flonum-mult.o \
+       frags.o \
+       hash.o \
+       hex-value.o \
+       input-file.o \
+       input-scrub.o \
+       messages.o \
+       output-file.o \
+       read.o \
+       strstr.o \
+       subsegs.o \
+       symbols.o \
+       version.o \
+       write.o \
+       xmalloc.o \
+       xrealloc.o
+
+# Definition of `all' is here so that new rules inserted by sed
+# do not specify the default target.
+# The real definition is under `all.internal'.
+
+all: $(ALL)
+
+# sed inserts variable overrides after the following line.
+####
+\f
+# Now figure out from those variables how to compile and link.
+
+# This is the variable actually used when we compile.
+ALL_CFLAGS = $(INTERNAL_CFLAGS) $(CFLAGS)
+
+# Even if ALLOCA is set, don't use it if compiling with GCC.
+USE_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${ALLOCA}; else true; fi`
+USE_HOST_ALLOCA= `if [ x"${CC}" = x"${OLDCC}" ] ; then echo ${HOST_PREFIX}${ALLOCA}; else true; fi`
+
+# Dependency on obstack, alloca, malloc or whatever library facilities
+# are not installed in the system libraries.
+# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
+LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC)
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
+HOST_LIBDEPS= $(HOST_PREFIX)$(OBSTACK) $(HOST_PREFIX)$(ALLOCA) $(HOST_PREFIX)$(MALLOC)
+
+# How to link with both our special library facilities
+# and the system's installed libraries.
+LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(CLIB)
+
+# Likewise, for use in the tools that must run on this machine
+# even if we are cross-building GCC.
+HOST_LIBS = $(HOST_PREFIX)$(OBSTACK) $(USE_HOST_ALLOCA) $(HOST_PREFIX)$(MALLOC) $(CLIB)
+
+# 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$(srcdir)/config
+SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../$(srcdir)/config
+
+# 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:
+\f
+# Files to be copied away after each stage in building.
+STAGE_GCC=gcc
+STAGESTUFF = *.o gas 
+
+# The files that "belong" in CONFIG_H are deliberately omitted
+# because having them there would not be useful in actual practice.
+# All they would do is cause complete recompilation every time
+# one of the machine description files is edited.
+# That may or may not be what one wants to do.
+# If it is, rm *.o is an easy way to do it.
+# CONFIG_H = config.h tm.h
+CONFIG_H =
+\f
+gas: $(OBJS) $(LIBDEPS)
+       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o gas $(OBJS) $(LIBS)
+
+all.internal: native
+# This is what is made with the host's compiler if making a cross assembler.
+native: config.status gas
+
+config.status:
+       @echo You must configure gas.  Look at the INSTALL file for details.
+       @false
+
+compilations: ${OBJS}
+
+# Compiling object files from source files.
+
+# Note that dependencies on obstack.h are not written
+# because that file is not part of GAS.
+
+app.o : app.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+as.o : as.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+atof-generic.o : atof-generic.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+bignum-copy.o : bignum-copy.c as.h host.h \
+  targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+cond.o : cond.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+debug.o : debug.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h 
+expr.o : expr.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+flonum-const.o : flonum-const.c flonum.h bignum.h 
+flonum-copy.o : flonum-copy.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+flonum-mult.o : flonum-mult.c flonum.h bignum.h 
+frags.o : frags.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h 
+hash.o : hash.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h 
+hex-value.o : hex-value.c 
+input-file.o : input-file.c as.h host.h \
+   targ-env.h obj-format.h targ-cpu.h \
+   struc-symbol.h reloc.h write.h flonum.h bignum.h expr.h \
+  frags.h hash.h read.h symbols.h tc.h obj.h input-file.h 
+input-scrub.o : input-scrub.c /usr/include/errno.h /usr/include/sys/errno.h \
+  as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  input-file.h 
+messages.o : messages.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h
+obstack.o : obstack.c obstack.h 
+output-file.o : output-file.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  output-file.h 
+read.o : read.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h 
+strstr.o : strstr.c   
+subsegs.o : subsegs.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h 
+symbols.o : symbols.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  obstack.h subsegs.h 
+version.o : version.c 
+write.o : write.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h  struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h symbols.h tc.h obj.h \
+  subsegs.h obstack.h output-file.h 
+xmalloc.o : xmalloc.c
+xrealloc.o : xrealloc.c 
+atof-targ.o : atof-targ.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h 
+obj-format.o : obj-format.c as.h host.h targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h obstack.h 
+targ-cpu.o : targ-cpu.c targ-env.h obj-format.h \
+  targ-cpu.h struc-symbol.h reloc.h \
+  write.h flonum.h bignum.h expr.h frags.h hash.h read.h \
+  symbols.h tc.h obj.h obstack.h
+
+# Normally this target is not used; but it is used if you
+# define ALLOCA=alloca.o.  In that case, you must get a suitable alloca.c
+# from the GNU Emacs distribution.
+# Note some machines won't allow $(CC) without -S on this source file.
+alloca.o:      alloca.c
+       $(CC) $(ALL_CFLAGS) $(CPPFLAGS) -S `echo $(srcdir)/alloca.c | sed 's,^\./,,'`
+       as alloca.s -o alloca.o
+\f
+# Compile the libraries to be used by gen*.
+# If we are not cross-building, gen* use the same .o's that cc1 will use,
+# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict
+# with the rules for rtl.o, alloca.o, etc.
+$(HOST_PREFIX_1)alloca.o: alloca.c
+       rm -f $(HOST_PREFIX)alloca.c
+       cp $(srcdir)/alloca.c $(HOST_PREFIX)alloca.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)alloca.c
+
+$(HOST_PREFIX_1)obstack.o: obstack.c
+       rm -f $(HOST_PREFIX)obstack.c
+       cp $(srcdir)/obstack.c $(HOST_PREFIX)obstack.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
+
+$(HOST_PREFIX_1)malloc.o: malloc.c
+       rm -f $(HOST_PREFIX)malloc.c
+       cp $(srcdir)/malloc.c $(HOST_PREFIX)malloc.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)malloc.c
+\f
+# Remake the info files.
+
+doc: $(srcdir)/gas.info
+
+$(srcdir)/gas.info: $(srcdir)/gas.texinfo
+       makeinfo `echo $(srcdir)/gas.texinfo | sed 's,^\./,,'`
+
+\f
+# Deletion of files made during compilation.
+# There are three levels of this: `clean', `cleanconfig' and `realclean'.
+# `clean' deletes what you want to delete ordinarily to save space.
+# This is most, but not all, of the files made by compilation.
+# `cleanconfig' also deletes everything depending
+# on the choice of config files.
+# `realclean' also deletes everything that could be regenerated automatically.
+
+clean:
+       -rm -f $(STAGESTUFF)
+# Delete the temporary source copies for cross compilation.
+       -rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c
+       -rm -f $(HOST_PREFIX_1)obstack.c 
+# Delete the stamp files except stamp-gnulib2.
+       -rm -f core
+
+# Like clean but also delete the links made to configure gas.
+cleanconfig: clean
+       -rm -f config.status Makefile host.h targ-env.h
+       -rm -f targ-cpu.h targ-cpu.c
+       -rm -f obj-format.h obj-format.c
+       -rm -f atof-targ.c
+
+# Get rid of every file that's generated from some other file (except INSTALL).
+realclean: cleanconfig
+       -rm -f gas.aux gas.cps gas.fns gas.info gas.kys gas.pgs gas.tps gas.vrs
+       -rm -f TAGS 
+       -rm -f gas.info* gas.?? gas.??s gas.log gas.toc gas.*aux
+       -rm -f *.dvi
+\f
+# Entry points `install', `includes' and `uninstall'.
+
+# Copy the files into directories where they will be run.
+install:
+       $(INSTALL_PROGRAM) gas $(bindir)/as
+
+# Create the installation directory.
+install-dir:
+       -mkdir $(libdir)
+       -mkdir $(libdir)/gcc
+       -mkdir $(libdir)/gcc/$(target)
+       -mkdir $(libdir)/gcc/$(target)/$(version)
+
+# Install the compiler executables built during cross compilation.
+install-cross: native install-dir
+       -if [ -f cc1 ] ; then $(INSTALL_PROGRAM) cc1 $(libsubdir)/cc1; else true; fi
+       -if [ -f cc1plus ] ; then $(INSTALL_PROGRAM) cc1plus $(libsubdir)/cc1plus; else true; fi
+       $(INSTALL_PROGRAM) cpp $(libsubdir)/cpp
+       ./gcc -dumpspecs > $(libsubdir)/specs
+       $(INSTALL_PROGRAM) gcc $(bindir)/gcc
+
+# Install the man pages.
+install-man: install-dir $(srcdir)/gcc.1 protoize.1 unprotoize.1
+       $(INSTALL_FILE) $(srcdir)/gcc.1 $(mandir)/gcc.$(manext)
+       chmod a-x $(mandir)/gcc.$(manext)
+       $(INSTALL_FILE) $(srcdir)/protoize.1 $(mandir)/protoize.$(manext)
+       chmod a-x $(mandir)/protoize.$(manext)
+       $(INSTALL_FILE) $(srcdir)/unprotoize.1 $(mandir)/unprotoize.$(manext)
+       chmod a-x $(mandir)/unprotoize.$(manext)
+
+# Cancel installation by deleting the installed files.
+uninstall:
+       -rm -rf $(libsubdir)
+       -rm -rf $(bindir)/gas
+       -rm -rf $(mandir)/gas.$(manext)
+
+\f
+# These exist for maintenance purposes.
+
+tags TAGS: force
+       etags $(REAL_SOURCES) $(REAL_HEADERS) README Makefile config/*.[hc]
+       
+bootstrap: gas force
+       $(MAKE) stage1
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       $(MAKE) stage2
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+bootstrap2: force
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage1/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       $(MAKE) stage2
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+bootstrap3: force
+       $(MAKE) CC="$(CC)" CFLAGS="-O -Bstage2/ $(CFLAGS)" libdir=$(libdir) ALLOCA= gas
+       for i in *.o; do cmp $$i stage2/$$i; done
+
+# Copy the object files from a particular stage into a subdirectory.
+stage1: force
+       -mkdir stage1
+       -mv $(STAGESTUFF) stage1
+       -(cd stage1 ; ln -s gas as)
+
+stage2: force
+       -mkdir stage2
+       -mv $(STAGESTUFF) stage2
+       -(cd stage2 ; ln -s gas as)
+
+
+stage3: force
+       -mkdir stage3
+       -mv $(STAGESTUFF) $(STAGE_GCC) stage3
+       -rm -f stage3/gnulib
+       -cp gnulib stage3
+       -if $(RANLIB_TEST) ; then $(RANLIB) stage3/gnulib; else true; fi
+
+stage4: force
+       -mkdir stage4
+       -mv $(STAGESTUFF) $(STAGE_GCC) stage4
+       -rm -f stage4/gnulib
+       -cp gnulib stage4
+       -if $(RANLIB_TEST) ; then $(RANLIB) stage4/gnulib; else true; fi
+
+# Copy just the executable files from a particular stage into a subdirectory,
+# and delete the object files.  Use this if you're just verifying a version
+# that is pretty sure to work, and you are short of disk space.
+risky-stage1: force
+       -mkdir stage1
+       -mv cc1 cpp cccp gcc stage1
+       -rm -f stage1/gnulib
+       -cp gnulib stage1 && $(RANLIB) stage1/gnulib
+       -make clean
+
+risky-stage2: force
+       -mkdir stage2
+       -mv cc1 cpp cccp gcc stage2
+       -rm -f stage2/gnulib
+       -cp gnulib stage2 && $(RANLIB) stage2/gnulib
+       -make clean
+
+risky-stage3: force
+       -mkdir stage3
+       -mv cc1 cpp cccp gcc stage3
+       -rm -f stage3/gnulib
+       -cp gnulib stage3 && $(RANLIB) stage3/gnulib
+       -make clean
+
+risky-stage4: force
+       -mkdir stage4
+       -mv cc1 cpp cccp gcc stage4
+       -rm -f stage4/gnulib
+       -cp gnulib stage4 && $(RANLIB) stage4/gnulib
+       -make clean
+
+#In GNU Make, ignore whether `stage*' exists.
+.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap
+.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4
+
+force:
+
+Makefile: $(srcdir)/Makefile.in $(srcdir)/configure
+       (cd $(srcdir) ; configure -host=$(host) $(target))
diff --git a/gas/README b/gas/README
new file mode 100644 (file)
index 0000000..2042639
--- /dev/null
@@ -0,0 +1,139 @@
+This is the beta-test version of the GNU assembler.  (Probably
+around Version 1.38, but check version.c which gets updated more
+often than this readme.)
+
+These files are currently set up to allow you to compile all of the
+versions of the assembler on the same machine.  'make all' compiles
+all of them.  The resulting executable names are:
+
+       68020           a68
+       Vax             avax
+       NS 32xxx        a32k
+       Intel 80386     a386
+       SPARC           asparc
+       AMD 29000       asm29k
+
+The Makefile contains instructions on how to make one of the
+assemblers compile as the default.
+
+Before you can compile the 68020 version of the assembler, you must
+make m68k.h be a link to m-sun3.h , m-hpux.h or m-generic.h .  If
+you are on a SUN-3 (or other machine that uses a magic number of
+(2 << 16) | OMAGIC type 'ln -s m-sun3.h m68k.h' else if you are on a
+machine running HP-UX, type 'ln m-hpux.h m689k.h' else type
+'ln -s m-generic.h m68k.h' If your machine does not support symbolic
+links, omit the '-s'.
+
+See the instructions in the Makefile for compiling gas for the Sequent
+Symmetry (dynix 3.0.12 + others?) or for the HP 9000/300
+
+If your machine does not have both varargs.h and vfprintf(), but does have
+_doprnt() add -DNO_VARARGS to the CFLAGS line in the makefile.  If your
+machine has neither vfprintf() or _doprnt(), you will have to change
+messages.c in order to get readable error messages from the assembler.
+
+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  If you can't
+get through to prep, try hack@gnu.ai.mit.edu or hack@media-lab.media.mit.edu
+
+If you report a bug in GAS, please remember to include:
+
+A description of exactly what went wrong.
+
+The type of machine GAS was running on (VAX, 68020, etc),
+
+The Operating System GAS was running under.
+
+The options given to GAS.
+
+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.
+
+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.
+
+------------------------------ README.APOLLO ---------------------------------
+
+The changes required to get the GNU C compiler running on
+Apollo 68K platforms are available via anonymous ftp from
+labrea.stanford.edu (36.8.0.47) in the form of a compressed
+tar file named "/pub/gnu/apollo-gcc-1.37.tar.Z".
+The size of the file is 84145 bytes.
+
+To build GCC for the Apollo you'll need the virgin FSF
+distributions of bison-1.03, gas-1.34, and gcc-1.37. They
+are also on labrea.stanford.edu as well as prep.ai.mit.edu.
+My changes are to enable gas to produce Apollo COFF object
+files and allow gcc to parse some of the syntax extensions
+which appear in Apollo C header files. Note that the
+COFF encapsulation technique cannot be used on the Apollo.
+                                                             
+The tar file should be unpacked in the directory containing
+the gas-1.34 and gcc-1.37 directories; a few files will be overlaid,
+and an APOLLO-GCC-README file will appear in the top directory.
+This file contains detailed instructions on how to proceed.
+
+These changes will only work for SR10.1 or later systems, using
+the 6.6 or later version of the Apollo C compiler.
+
+If you do not have ftp access, I can mail you the changes in the
+form of diffs; they are approximately 40K in length. If you request
+them, be sure to give me a voice phone number so I can contact you
+in case I can't send you mail; I've had several requests in the
+past from people I can't contact.
+
+By the way, I'm working on getting the GNU C++ compiler running;
+there are a couple problems to solve. I hope to be able to announce
+the Apollo version shortly after the 1.37 version is released.
+
+John Vasta                Hewlett-Packard Apollo Systems Division
+vasta@apollo.hp.com       M.S. CHA-01-LT
+(508) 256-6600 x6362      300 Apollo Drive, Chelmsford, MA 01824
+UUCP: {decwrl!decvax, mit-eddie, attunix}!apollo!vasta
+
+------------------------------------
+
+You might refer others who are interested in a similar thing.
+
+Kevin Buchs    buchs@mayo.edu
+
+
+------------------------------ README.COFF -----------------------------------
+
+If you have a COFF system, you may wish to aquire
+
+       UUCP: osu-cis!~/gnu/coff/gnu-coff.tar.Z
+       or
+       FTP:  tut.cis.ohio-state.edu:/pub/gnu/coff/gnu-coff.tar.Z
+
+These contain patches for gas that will make it produce COFF output.
+I have never seen these patches, so I don't know how well they work.
diff --git a/gas/app.c b/gas/app.c
new file mode 100644 (file)
index 0000000..c806cb7
--- /dev/null
+++ b/gas/app.c
@@ -0,0 +1,508 @@
+/* Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
+
+Modified by Allen Wirfs-Brock, Instantiations Inc 2/90
+*/
+/* This is the Assembler Pre-Processor
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* 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.app-file <filename> pair.
+   This needs better error-handling.
+ */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include <stdio.h>
+#include "as.h"                /* For BAD_CASE() only */
+
+#if !defined(__STDC__) && !defined(const)
+#define const /* Nothing */
+#endif
+
+static char    lex [256];
+static char    symbol_chars[] = 
+       "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+/* These will go in BSS if not defined elsewhere, producing empty strings. */
+extern const char comment_chars[];
+extern const char line_comment_chars[];
+extern const char line_separator_chars[];
+
+#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_TWOCHAR_COMMENT_2ND      7
+#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)
+
+void do_scrub_begin() {
+       const char *p;
+
+       lex [' ']               = LEX_IS_WHITESPACE;
+       lex ['\t']              = LEX_IS_WHITESPACE;
+       lex ['\n']              = LEX_IS_NEWLINE;
+       lex [';']               = LEX_IS_LINE_SEPARATOR;
+       lex ['"']               = LEX_IS_STRINGQUOTE;
+       lex ['\'']              = LEX_IS_ONECHAR_QUOTE;
+       lex [':']               = LEX_IS_COLON;
+
+       /* 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[*p] = LEX_IS_SYMBOL_COMPONENT;
+       for (p=comment_chars;*p;p++)
+               lex[*p] = LEX_IS_COMMENT_START;
+       for (p=line_comment_chars;*p;p++)
+               lex[*p] = LEX_IS_LINE_COMMENT_START;
+       for (p=line_separator_chars;*p;p++)
+               lex[*p] = LEX_IS_LINE_SEPARATOR;
+
+       /* Only allow slash-star comments if slash is not in use */
+       if (lex['/'] == 0) {
+               lex ['/']       = LEX_IS_TWOCHAR_COMMENT_1ST;
+               lex ['*']       = LEX_IS_TWOCHAR_COMMENT_2ND;
+       }
+}
+
+FILE *scrub_file;
+
+int scrub_from_file() {
+       return getc(scrub_file);
+}
+
+void scrub_to_file(ch)
+int ch;
+{
+       ungetc(ch,scrub_file);
+} /* scrub_to_file() */
+
+char *scrub_string;
+char *scrub_last_string;
+
+int scrub_from_string() {
+       return scrub_string == scrub_last_string ? EOF : *scrub_string++;
+} /* scrub_from_string() */
+
+void scrub_to_string(ch)
+int ch;
+{
+       *--scrub_string=ch;
+} /* scrub_to_string() */
+
+/* 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 = 0;
+
+/* 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 *scrub_string;
+  char *scrub_last_string;
+  FILE *scrub_file;
+};
+
+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;
+  bcopy(saved->out_buf, out_buf, sizeof(out_buf));
+  saved->add_newlines  = add_newlines;
+  saved->scrub_string  = scrub_string;
+  saved->scrub_last_string = scrub_last_string;
+  saved->scrub_file    = scrub_file;
+
+  /* do_scrub_begin() is not useful, just wastes time. */
+  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;
+  bcopy (out_buf,  saved->out_buf, sizeof (out_buf));
+  add_newlines = saved->add_newlines;
+  scrub_string = saved->scrub_string;
+  scrub_last_string = saved->scrub_last_string;
+  scrub_file   = saved->scrub_file;
+
+  free (arg);
+} /* app_pop() */
+
+int do_scrub_next_char(get,unget)
+int (*get)();
+void (*unget)();
+{
+       /*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 .app-file, put out string.
+               8: After putting out a .app-file string, flush until newline.
+               -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
+       */
+
+       register int ch, ch2;
+
+       switch (state) {
+       case -1: 
+               ch= *out_string++;
+               if(*out_string==0) {
+                       state=old_state;
+                       old_state=3;
+               }
+               return ch;
+       
+       case -2:
+               for(;;) {
+                       do {
+                               ch=(*get)();
+                       } while(ch!=EOF && ch!='\n' && ch!='*');
+                       if(ch=='\n' || ch==EOF)
+                               return ch;
+
+                       /* At this point, ch must be a '*' */
+                       while ( (ch=(*get)()) == '*' ){
+                               ;
+                       }
+                       if(ch==EOF || ch=='/')
+                               break;
+                       (*unget)(ch);
+               }
+               state=old_state;
+               return ' ';
+
+       case 4:
+               ch=(*get)();
+               if(ch==EOF || (ch>='0' && ch<='9'))
+                       return ch;
+               else {
+                       while(ch!=EOF && IS_WHITESPACE(ch))
+                               ch=(*get)();
+                       if(ch=='"') {
+                               (*unget)(ch);
+                               out_string="\n.app-file ";
+                               old_state=7;
+                               state= -1;
+                               return *out_string++;
+                       } else {
+                               while(ch!=EOF && ch!='\n')
+                                       ch=(*get)();
+                               return ch;
+                       }
+               }
+
+       case 5:
+               ch=(*get)();
+               if(ch=='"') {
+                       state=old_state;
+                       return '"';
+               } else if(ch=='\\') {
+                       state=6;
+                       return ch;
+               } else if(ch==EOF) {
+                       as_warn("End of file in string: inserted '\"'");
+                       state=old_state;
+                       (*unget)('\n');
+                       return '"';
+               } else {
+                       return ch;
+               }
+       
+       case 6:
+               state=5;
+               ch=(*get)();
+               switch(ch) {
+                       /* This is neet.  Turn "string
+                          more string" into "string\n  more string"
+                        */
+               case '\n':
+                       (*unget)('n');
+                       add_newlines++;
+                       return '\\';
+
+               case '"':
+               case '\\':
+               case 'b':
+               case 'f':
+               case 'n':
+               case 'r':
+               case 't':
+#ifdef BACKSLASH_V
+               case 'v':
+#endif /* BACKSLASH_V */
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+                       break;
+
+#ifdef 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");
+                       return '"';
+               }
+               return ch;
+
+       case 7:
+               ch=(*get)();
+               state=5;
+               old_state=8;
+               return ch;
+
+       case 8:
+               do ch= (*get)();
+               while(ch!='\n');
+               state=0;
+               return ch;
+       }
+
+       /* OK, we are somewhere in states 0 through 4 */
+
+/* flushchar: */
+       ch=(*get)();
+ recycle:
+       if (ch == EOF) {
+               if (state != 0)
+                       as_warn("End of file not at end of a line: Newline inserted.");
+               return ch;
+       }
+
+       switch (lex[ch]) {
+       case LEX_IS_WHITESPACE:
+               do ch=(*get)();
+               while(ch!=EOF && IS_WHITESPACE(ch));
+               if(ch==EOF)
+                       return ch;
+               if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPARATOR(ch)) {
+                       goto recycle;
+               }
+               switch (state) {
+               case 0: state++; goto recycle;  /* Punted leading sp */
+               case 1:          BAD_CASE(state); /* We can't get here */
+               case 2: state++; (*unget)(ch); return ' ';  /* Sp after opco */
+               case 3:          goto recycle;  /* Sp in operands */
+               default:        BAD_CASE(state);
+               }
+               break;
+
+       case LEX_IS_TWOCHAR_COMMENT_1ST:
+               ch2=(*get)();
+               if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND) {
+                       for(;;) {
+                               do {
+                                       ch2=(*get)();
+                                       if(ch2 != EOF && IS_NEWLINE(ch2))
+                                               add_newlines++;
+                               } while(ch2!=EOF &&
+                                    (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND));
+
+                               while (ch2!=EOF &&
+                                    (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)){
+                                       ch2=(*get)();
+                               }
+
+                               if(ch2==EOF 
+                                 || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST)
+                                       break;
+                               (*unget)(ch);
+                       }
+                       if(ch2==EOF)
+                               as_warn("End of file in multiline comment");
+
+                       ch = ' ';
+                       goto recycle;
+               } else {
+                       if(ch2!=EOF)
+                               (*unget)(ch2);
+                       return ch;
+               }
+               break;
+
+       case LEX_IS_STRINGQUOTE:
+               old_state=state;
+               state=5;
+               return ch;
+
+       case LEX_IS_ONECHAR_QUOTE:
+               ch=(*get)();
+               if(ch==EOF) {
+                       as_warn("End-of-file after a one-character quote; \000 inserted");
+                       ch=0;
+               }
+               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
+                       (*unget)(ch);
+#endif
+               }
+
+               old_state=state;
+               state= -1;
+               out_string=out_buf;
+               return *out_string++;
+
+       case LEX_IS_COLON:
+               if(state!=3)
+                       state=0;
+               return ch;
+
+       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;
+               return ch;
+
+       case LEX_IS_LINE_COMMENT_START:
+               if (state != 0)         /* Not at start of line, act normal */
+                       goto de_fault;
+               do ch=(*get)();
+               while(ch!=EOF && IS_WHITESPACE(ch));
+               if(ch==EOF) {
+                       as_warn("EOF in comment:  Newline inserted");
+                       return '\n';
+               }
+               if(ch<'0' || ch>'9') {
+                       /* Non-numerics:  Eat whole comment line */
+                       while(ch!=EOF && !IS_NEWLINE(ch))
+                               ch=(*get)();
+                       if(ch==EOF)
+                               as_warn("EOF in Comment: Newline inserted");
+                       state=0;
+                       return '\n';
+               }
+               /* Numerics begin comment.  Perhaps CPP `# 123 "filename"' */
+               (*unget)(ch);
+               old_state=4;
+               state= -1;
+               out_string=".line ";
+               return *out_string++;
+
+       case LEX_IS_COMMENT_START:
+               do ch=(*get)();
+               while(ch!=EOF && !IS_NEWLINE(ch));
+               if(ch==EOF)
+                       as_warn("EOF in comment:  Newline inserted");
+               state=0;
+               return '\n';
+
+       default:
+       de_fault:
+               /* Some relatively `normal' character.  */
+               if(state==0) {
+                       state=2;        /* Now seeing opcode */
+                       return ch;
+               } else if(state==1) {
+                       state=2;        /* Ditto */
+                       return ch;
+               } else {
+                       return ch;      /* Opcode or operands already */
+               }
+       }
+       return -1;
+}
+
+#ifdef TEST
+
+char comment_chars[] = "|";
+char line_comment_chars[] = "#";
+
+main()
+{
+       int     ch;
+
+       app_begin();
+       while((ch=do_scrub_next_char(stdin))!=EOF)
+               putc(ch,stdout);
+}
+
+as_warn(str)
+char *str;
+{
+       fputs(str,stderr);
+       putc('\n',stderr);
+}
+#endif
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of app.c */
diff --git a/gas/as.c b/gas/as.c
new file mode 100644 (file)
index 0000000..a885f0d
--- /dev/null
+++ b/gas/as.c
@@ -0,0 +1,361 @@
+/* as.c - GAS main program.
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * 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 <stdio.h>
+#include <string.h>
+
+#ifdef _POSIX_SOURCE
+#include <sys/types.h> /* For pid_t in signal.h */
+#endif
+#include <signal.h>
+
+#define COMMON
+
+#include "as.h"
+
+#ifdef __STDC__
+
+ /* This prototype for got_sig() is ansi.  If you want
+    anything else, then your compiler is lying to you when
+    it says that it is __STDC__.  If you want to change it,
+    #ifdef protect it from those of us with real ansi
+    compilers. */
+
+#define SIGTY void
+
+static void got_sig(int sig);
+static char *stralloc(char *str);
+static void perform_an_assembly_pass(int argc, char **argv);
+
+#else /* __STDC__ */
+
+#ifndef SIGTY
+#define SIGTY int
+#endif
+
+static SIGTY got_sig();
+static char *stralloc();       /* Make a (safe) copy of a string. */
+static void perform_an_assembly_pass();
+
+#endif /* __STDC__ */
+
+#ifdef DONTDEF
+static char * gdb_symbol_file_name;
+long gdb_begin();
+#endif
+
+char *myname;          /* argv[0] */
+extern char version_string[];
+\f
+int main(argc,argv)
+int argc;
+char **argv;
+{
+       int work_argc;  /* variable copy of argc */
+       char **work_argv;       /* variable copy of argv */
+       char *arg;              /* an arg to program */
+       char a;         /* an arg flag (after -) */
+       static const int sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, 0};
+
+       for(a=0;sig[a]!=0;a++)
+               if(signal(sig[a], SIG_IGN) != SIG_IGN)
+                       signal(sig[a], got_sig);
+
+       myname=argv[0];
+       bzero (flagseen, sizeof(flagseen)); /* aint seen nothing yet */
+#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME
+#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out"
+#endif /* OBJ_DEFAULT_OUTPUT_FILE_NAME */
+       out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME;
+
+       symbol_begin();         /* symbols.c */
+       subsegs_begin();                /* subsegs.c */
+       read_begin();                   /* read.c */
+       md_begin();                     /* MACHINE.c */
+       input_scrub_begin();            /* input_scrub.c */
+#ifdef DONTDEF
+       gdb_symbol_file_name = 0;
+#endif
+       /*
+        * Parse arguments, but we are only interested in flags.
+        * When we find a flag, we process it then make it's argv[] NULL.
+        * This helps any future argv[] scanners avoid what we processed.
+        * 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.
+        */
+ /* FIXME-SOMEDAY this should use getopt. */
+       work_argc = argc-1;             /* don't count argv[0] */
+       work_argv = argv+1;             /* skip argv[0] */
+       for (;work_argc--;work_argv++) {
+               arg = * work_argv;      /* work_argv points to this argument */
+
+               if (*arg!='-')          /* Filename. We need it later. */
+                       continue;       /* Keep scanning args looking for flags. */
+               if (arg[1] == '-' && arg[2] == 0) {
+                       /* "--" as an argument means read STDIN */
+                       /* on this scan, we don't want to think about filenames */
+                       * work_argv = "";       /* Code that means 'use stdin'. */
+                       continue;
+               }
+                               /* This better be a switch. */
+               arg ++;         /*->letter. */
+
+               while ((a = * arg) != '\0')  {/* scan all the 1-char flags */
+                       arg ++; /* arg->after letter. */
+                       a &= 0x7F;      /* ascii only please */
+                       if (flagseen[a])
+                               as_tsktsk("%s: Flag option - %c has already been seen.", myname, a);
+                       flagseen[a] = 1;
+                       switch (a) {
+                       case 'f':
+                               break;  /* -f means fast - no need for "app" preprocessor. */
+
+                       case 'D':
+                               /* DEBUG is implemented: it debugs different */
+                               /* things to other people's assemblers. */
+                               break;
+
+#ifdef DONTDEF
+                       case 'G':       /* GNU AS switch: include gdbsyms. */
+                               if (*arg)       /* Rest of argument is file-name. */
+                                       gdb_symbol_file_name = stralloc (arg);
+                               else if (work_argc) {   /* Next argument is file-name. */
+                                       work_argc --;
+                                       * work_argv = NULL; /* Not a source file-name. */
+                                       gdb_symbol_file_name = * ++ work_argv;
+                               } else
+                                       as_warn("%s: I expected a filename after -G", myname);
+                               arg = "";       /* Finished with this arg. */
+                               break;
+#endif
+
+                       case 'I': { /* Include file directory */
+                               
+                               char *temp;
+                               if (*arg)
+                                   temp = stralloc (arg);
+                               else if (work_argc) {
+                                       * work_argv = NULL;
+                                       work_argc--;
+                                       temp = * ++ work_argv;
+                               } else
+                                   as_warn("%s: I expected a filename after -I", myname);
+                               add_include_dir (temp);
+                               arg = "";       /* Finished with this arg. */
+                               break;
+                       }
+
+#ifndef WORKING_DOT_WORD
+                       case 'k':
+                               break;
+#endif
+
+                       case 'L': /* -L means keep L* symbols */
+                               break;
+
+                       case 'o':
+                               if (*arg)       /* Rest of argument is object file-name. */
+                                       out_file_name = stralloc (arg);
+                               else if (work_argc) {   /* Want next arg for a file-name. */
+                                       * work_argv = NULL; /* This is not a file-name. */
+                                       work_argc--;
+                                       out_file_name = * ++ work_argv;
+                               } else
+                                       as_warn("%s: I expected a filename after -o. \"%s\" assumed.", myname, out_file_name);
+                               arg = "";       /* Finished with this arg. */
+                               break;
+
+                       case 'R':
+                               /* -R means put data into text segment */
+                               break;
+
+                       case 'v':
+#ifdef VMS
+                               {
+                               extern char *compiler_version_string;
+                               compiler_version_string = arg;
+                               }
+#else /* not VMS */
+                               fprintf(stderr,version_string);
+                               if(*arg && strcmp(arg,"ersion"))
+                                       as_warn("Unknown -v option ignored");
+#endif
+                               while(*arg) arg++;      /* Skip the rest */
+                               break;
+
+                       case 'W':
+                               /* -W means don't warn about things */
+                       case 'X':
+                               /* -X means treat warnings as errors */
+                       case 'Z':
+                               /* -Z means attempt to generate object file even after errors. */
+                               break;
+
+                       default:
+                               --arg;
+                               if(md_parse_option(&arg,&work_argc,&work_argv)==0)
+                                       as_warn("%s: I don't understand '%c' flag.", myname, a);
+                               if(arg && *arg)
+                                       arg++;
+                               break;
+                       }
+               }
+               /*
+                * We have just processed a "-..." arg, which was not a
+                * file-name. Smash it so the
+                * things that look for filenames won't ever see it.
+                *
+                * Whatever work_argv points to, it has already been used
+                * as part of a flag, so DON'T re-use it as a filename.
+                */
+               *work_argv = NULL; /* NULL means 'not a file-name' */
+       }
+#ifdef DONTDEF
+       if (gdb_begin(gdb_symbol_file_name) == 0)
+               flagseen ['G'] = 0;     /* Don't do any gdbsym stuff. */
+#endif
+       /* Here with flags set up in flagseen[]. */
+       perform_an_assembly_pass(argc,argv); /* Assemble it. */
+#ifdef TC_I960
+       brtab_emit();
+#endif
+       if (seen_at_least_1_file()
+           && !((had_warnings() && flagseen['Z'])
+                || had_errors() > 0)) { 
+               write_object_file(); /* relax() addresses then emit object file */
+       } /* we also check in write_object_file() just before emit. */
+
+       input_scrub_end();
+       md_end();                       /* MACHINE.c */
+
+#ifndef        VMS
+       return((had_warnings() && flagseen['Z'])
+              || had_errors() > 0);                    /* WIN */
+#else  /* VMS */
+       return(!((had_warnings() && flagseen['Z'])
+                || had_errors() > 0));                 /* WIN */
+#endif /* VMS */
+
+} /* main() */
+
+\f
+/*                     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;
+
+       text_fix_root           = NULL;
+       data_fix_root           = NULL;
+       need_pass_2             = 0;
+
+       subseg_new (SEG_TEXT, 0);
+
+       argv++;                 /* skip argv[0] */
+       argc--;                 /* skip argv[0] */
+       while (argc--) {
+               if (*argv) {            /* Is it a file-name argument? */
+                       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() */
+\f
+/*
+ *                     stralloc()
+ *
+ * Allocate memory for a new copy of a string. Copy the string.
+ * Return the address of the new string. Die if there is any error.
+ */
+
+static char *
+stralloc (str)
+char * str;
+{
+       register char * retval;
+       register long len;
+
+       len = strlen (str) + 1;
+       retval = xmalloc (len);
+       (void) strcpy(retval, str);
+       return(retval);
+}
+\f
+#ifdef comment
+static void lose() {
+       as_fatal("%s: 2nd pass not implemented - get your code from random(3)", myname);
+       return;
+} /* lose() */
+#endif /* comment */
+
+static SIGTY
+got_sig(sig)
+int sig;
+{
+       static here_before = 0;
+
+       as_bad("Interrupted by signal %d", sig);
+       if(here_before++)
+               exit(1);
+       return((SIGTY) 0);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: as.c */
diff --git a/gas/as.h b/gas/as.h
new file mode 100644 (file)
index 0000000..f956893
--- /dev/null
+++ b/gas/as.h
@@ -0,0 +1,397 @@
+/* as.h - global header file
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#define GAS 1
+
+#include "host.h"
+#include "flonum.h"
+
+#ifndef __STDC__
+#define        volatile        /**/
+#ifndef const
+#define        const           /**/
+#endif /* const */
+#endif /* __STDC__ */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#define register
+#endif /* __GNUC__ */
+
+#ifndef __LINE__
+#define __LINE__ "unknown"
+#endif /* __LINE__ */
+
+#ifndef __FILE__
+#define __FILE__ "unknown"
+#endif /* __FILE__ */
+
+/*
+ * 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.
+ * #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 "".
+ */
+
+/* These #defines are for parameters of entire assembler. */
+
+/* #define SUSPECT JF remove for speed testing */
+/* These #includes are for type definitions etc. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#define obstack_chunk_alloc    xmalloc
+#define obstack_chunk_free     xfree
+
+#define BAD_CASE(value)                                                        \
+{                                                                      \
+  as_fatal("Case value %d unexpected at line %d of file \"%s\"\n",     \
+          value, __LINE__, __FILE__);                                  \
+}
+
+\f
+/* These are assembler-wide concepts */
+
+
+#ifndef COMMON
+#ifdef TEST
+#define COMMON                 /* declare our COMMONs storage here. */
+#else
+#define COMMON extern          /* our commons live elswhere */
+#endif
+#endif
+                               /* COMMON now defined */
+#define DEBUG /* temporary */
+
+#ifdef DEBUG
+#undef NDEBUG
+#define know(p) assert(p)      /* Verify our assumptions! */
+#else
+#define know(p)                        /* know() checks are no-op.ed */
+#endif
+
+
+#define xfree free
+\f
+/* input_scrub.c */
+
+/*
+ * Supplies sanitised buffers to read.c.
+ * Also understands printing line-number part of error messages.
+ */
+
+\f
+/* subsegs.c     Sub-segments. Also, segment(=expression type)s.*/
+
+/*
+ * This table describes the use of segments as EXPRESSION types.
+ *
+ *     X_seg   X_add_symbol  X_subtract_symbol X_add_number
+ * SEG_ABSENT                                          no (legal) expression
+ * SEG_PASS1                                           no (defined) "
+ * SEG_BIG                                     *       > 32 bits const.
+ * SEG_ABSOLUTE                                        0
+ * SEG_DATA            *                       0
+ * SEG_TEXT            *                       0
+ * SEG_BSS             *                       0
+ * SEG_UNKNOWN         *                       0
+ * SEG_DIFFERENCE      0               *       0
+ * SEG_REGISTER                                        *
+ *
+ * The blank fields MUST be 0, and are nugatory.
+ * The '0' fields MAY be 0. The '*' fields MAY NOT be 0.
+ *
+ * SEG_BIG: X_add_number is < 0 if the result is in
+ *     generic_floating_point_number.  The value is -'c' where c is the
+ *     character that introduced the constant.  e.g. "0f6.9" will have  -'f'
+ *     as a X_add_number value.
+ *     X_add_number > 0 is a count of how many littlenums it took to
+ *     represent a bignum.
+ * SEG_DIFFERENCE:
+ * If segments of both symbols are known, they are the same segment.
+ * X_add_symbol != X_sub_symbol (then we just cancel them, => SEG_ABSOLUTE).
+ */
+
+typedef enum {
+       SEG_ABSOLUTE = 0,
+       SEG_TEXT,
+       SEG_DATA,
+       SEG_BSS,
+       SEG_UNKNOWN,
+       SEG_ABSENT,             /* Mythical Segment (absent): NO expression seen. */
+       SEG_PASS1,              /* Mythical Segment: Need another pass. */
+       SEG_GOOF,               /* Only happens if AS has a logic error. */
+                               /* Invented so we don't crash printing */
+                               /* error message involving weird segment. */
+       SEG_BIG,                /* Bigger than 32 bits constant. */
+       SEG_DIFFERENCE,         /* Mythical Segment: absolute difference. */
+       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)
+
+typedef int subsegT;
+
+COMMON subsegT                 now_subseg;
+                               /* What subseg we are accreting now? */
+
+
+COMMON segT                    now_seg;
+                               /* Segment our instructions emit to. */
+                               /* Only OK values are SEG_TEXT or SEG_DATA. */
+
+
+extern char *const seg_name[];
+extern int section_alignment[];
+
+
+/* relax() */
+
+typedef enum
+{
+       rs_fill,                /* Variable chars to be repeated fr_offset */
+                               /* times. Fr_symbol unused. */
+                               /* Used with fr_offset == 0 for a constant */
+                               /* length frag. */
+
+       rs_align,               /* Align: Fr_offset: power of 2. */
+                               /* 1 variable char: fill character. */
+       rs_org,                 /* Org: Fr_offset, fr_symbol: address. */
+                               /* 1 variable char: fill character. */
+
+       rs_machine_dependent,
+#ifndef WORKING_DOT_WORD
+       rs_broken_word,         /* JF: gunpoint */
+#endif
+}
+relax_stateT;
+
+/* typedef unsigned char relax_substateT; */
+/* JF this is more likely to leave the end of a struct frag on an align
+   boundry.  Be very careful with this.  */
+typedef unsigned long relax_substateT;
+
+typedef unsigned long relax_addressT;/* Enough bits for address. */
+                               /* Still an integer type. */
+
+\f
+/* 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                    /* a code fragment */
+{
+       unsigned long fr_address; /* Object file address. */
+       struct frag *fr_next;   /* Chain forward; ascending address order. */
+                               /* Rooted in frch_root. */
+
+       long fr_fix;    /* (Fixed) number of chars we know we have. */
+                               /* May be 0. */
+       long fr_var;    /* (Variable) number of chars after above. */
+                               /* May be 0. */
+       struct symbol *fr_symbol; /* For variable-length tail. */
+       long fr_offset; /* For variable-length tail. */
+       char    *fr_opcode;     /*->opcode low addr byte,for relax()ation*/
+       relax_stateT fr_type;   /* What state is my tail in? */
+       relax_substateT fr_subtype;
+               /* These are needed only on the NS32K machines */
+       char    fr_pcrel_adjust;
+       char    fr_bsr;
+       char    fr_literal [1]; /* Chars begin here. */
+                               /* One day we will compile fr_literal[0]. */
+};
+#define SIZEOF_STRUCT_FRAG \
+ ((int)zero_address_frag.fr_literal-(int)&zero_address_frag)
+                               /* We want to say fr_literal[0] above. */
+
+typedef struct frag fragS;
+
+COMMON fragS * frag_now;       /* -> current frag we are building. */
+                               /* This frag is incomplete. */
+                               /* It is, however, included in frchain_now. */
+                               /* Frag_now->fr_fix is bogus. Use: */
+/* Virtual frag_now->fr_fix==obstack_next_free(&frags)-frag_now->fr_literal.*/
+
+COMMON fragS zero_address_frag;        /* For foreign-segment symbol fixups. */
+COMMON fragS  bss_address_frag;        /* For local common (N_BSS segment) fixups. */
+
+/* main program "as.c" (command arguments etc) */
+
+COMMON char
+flagseen[128];                 /* ['x'] TRUE if "-x" seen. */
+
+COMMON char *
+out_file_name;                 /* name of emitted object file */
+
+COMMON int     need_pass_2;    /* TRUE if we need a second pass. */
+
+typedef struct {
+  char *       poc_name;       /* assembler mnemonic, lower case, no '.' */
+  void         (*poc_handler)();       /* Do the work */
+  int          poc_val;        /* Value to pass to handler */
+} pseudo_typeS;
+
+#if defined(__STDC__) & !defined(NO_STDARG)
+
+int had_errors(void);
+int had_warnings(void);
+void as_bad(const char *Format, ...);
+void as_fatal(const char *Format, ...);
+void as_tsktsk(const char *Format, ...);
+void as_warn(const char *Format, ...);
+
+#else
+
+int had_errors();
+int had_warnings();
+void as_bad();
+void as_fatal();
+void as_tsktsk();
+void as_warn();
+
+#endif /* __STDC__ & !NO_STDARG */
+
+#ifdef __STDC__
+
+char *app_push(void);
+char *atof_ieee(char *str, int what_kind, LITTLENUM_TYPE *words);
+char *input_scrub_include_file(char *filename, char *position);
+char *input_scrub_new_file(char *filename);
+char *input_scrub_next_buffer(char **bufp);
+char *strstr(const char *s, const char *wanted);
+char *xmalloc(int size);
+char *xrealloc(char *ptr, long n);
+int do_scrub_next_char(int (*get)(), void (*unget)());
+int gen_to_words(LITTLENUM_TYPE *words, int precision, long exponent_bits);
+int had_err(void);
+int had_errors(void);
+int had_warnings(void);
+int ignore_input(void);
+int scrub_from_file(void);
+int scrub_from_file(void);
+int scrub_from_string(void);
+int seen_at_least_1_file(void);
+void app_pop(char *arg);
+void as_howmuch(FILE *stream);
+void as_perror(char *gripe, char *filename);
+void as_where(void);
+void bump_line_counters(void);
+void do_scrub_begin(void);
+void input_scrub_begin(void);
+void input_scrub_close(void);
+void input_scrub_end(void);
+void int_to_gen(long x);
+void new_logical_line(char *fname, int line_number);
+void scrub_to_file(int ch);
+void scrub_to_string(int ch);
+void subseg_change(segT seg, int subseg);
+void subseg_new(segT seg, subsegT subseg);
+void subsegs_begin(void);
+
+#else /* __STDC__ */
+
+char *app_push();
+char *atof_ieee();
+char *input_scrub_include_file();
+char *input_scrub_new_file();
+char *input_scrub_next_buffer();
+char *strstr();
+char *xmalloc();
+char *xrealloc();
+int do_scrub_next_char();
+int gen_to_words();
+int had_err();
+int had_errors();
+int had_warnings();
+int ignore_input();
+int scrub_from_file();
+int scrub_from_file();
+int scrub_from_string();
+int seen_at_least_1_file();
+void app_pop();
+void as_howmuch();
+void as_perror();
+void as_where();
+void bump_line_counters();
+void do_scrub_begin();
+void input_scrub_begin();
+void input_scrub_close();
+void input_scrub_end();
+void int_to_gen();
+void new_logical_line();
+void scrub_to_file();
+void scrub_to_string();
+void subseg_change();
+void subseg_new();
+void subsegs_begin();
+
+#endif /* __STDC__ */
+
+ /* this one starts the chain of target dependant headers */
+#include "targ-env.h"
+
+ /* these define types needed by the interfaces */
+#include "struc-symbol.h"
+#include "reloc.h"
+#include "write.h"
+#include "expr.h"
+#include "frags.h"
+#include "hash.h"
+#include "read.h"
+#include "symbols.h"
+
+#include "tc.h"
+#include "obj.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: as.h */
diff --git a/gas/atof-generic.c b/gas/atof-generic.c
new file mode 100644 (file)
index 0000000..7d2d8f4
--- /dev/null
@@ -0,0 +1,549 @@
+/* atof_generic.c - turn a string of digits into a Flonum
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "as.h"
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#endif
+#endif
+
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#endif
+
+/* #define     FALSE (0) */
+/* #define TRUE  (1) */
+
+/***********************************************************************\
+*                                                                      *
+*      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"}
+
+*/
+\f
+int                            /* 0 if OK */
+atof_generic (
+       address_of_string_pointer, /* return pointer to just AFTER number we read. */
+       string_of_decimal_marks, /* At most one per number. */
+       string_of_decimal_exponent_marks,
+       address_of_generic_floating_point_number)
+
+     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;
+
+{
+
+  int                  return_value; /* 0 means OK. */
+  char *               first_digit;
+  /* char *            last_digit; JF unused */
+  int                  number_of_digits_before_decimal;
+  int                  number_of_digits_after_decimal;
+  long         decimal_exponent;
+  int                  number_of_digits_available;
+  char                 digits_sign_char;
+\f
+  {
+    /*
+     * 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;
+
+    first_digit = * address_of_string_pointer;
+    c= *first_digit;
+    if (c=='-' || c=='+')
+      {
+       digits_sign_char = c;
+        first_digit ++;
+      }
+    else
+       digits_sign_char = '+';
+
+    if(   (first_digit[0]=='n' || first_digit[0]=='N')
+       && (first_digit[1]=='a' || first_digit[1]=='A')
+       && (first_digit[2]=='n' || first_digit[2]=='N')) {
+      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;
+    }
+    if(   (first_digit[0]=='i' || first_digit[0]=='I') 
+       && (first_digit[1]=='n' || first_digit[1]=='N')
+       && (first_digit[2]=='f' || first_digit[2]=='F')) {
+      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;
+      if(   (first_digit[3]=='i' || first_digit[3]=='I')
+         && (first_digit[4]=='n' || first_digit[4]=='N')
+        && (first_digit[5]=='i' || first_digit[5]=='I')
+        && (first_digit[6]=='t' || first_digit[6]=='T')
+        && (first_digit[7]=='y' || first_digit[7]=='Y'))
+         (*address_of_string_pointer)=first_digit+8;
+      else
+         (*address_of_string_pointer)=first_digit+3;
+      return 0;
+    }
+
+    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 || ! strchr (string_of_decimal_marks,          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 && strchr(string_of_decimal_marks,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 && strchr (string_of_decimal_marks, c))
+      {
+       for (p ++;
+            ((c = * p) != '\0')
+            && (!c || ! strchr (string_of_decimal_exponent_marks, c) );
+            p ++)
+         {
+           if (isdigit(c))
+             {
+               number_of_digits_after_decimal ++; /* This may be retracted below. */
+               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;
+/*    last_digit = p; JF unused */
+#endif
+    
+    if (c && strchr (string_of_decimal_exponent_marks, c) )
+      {
+       char            digits_exponent_sign_char;
+       
+       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;
+  }
+\f
+  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
+    {
+      LITTLENUM_TYPE * digits_binary_low;
+      int              precision;
+      int              maximum_useful_digits;
+      int              number_of_digits_to_use;
+      int              more_than_enough_bits_for_digits;
+      int              more_than_enough_littlenums_for_digits;
+      int              size_of_digits_in_littlenums;
+      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) */
+      maximum_useful_digits = (  ((double) (precision - 2))
+                              * ((double) (LITTLENUM_NUMBER_OF_BITS))
+                              / (LOG_TO_BASE_2_OF_10)
+                              )
+       + 2;                    /* 2 :: guard digits. */
+      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;
+       }
+      decimal_exponent += number_of_digits_before_decimal - number_of_digits_to_use;
+
+      more_than_enough_bits_for_digits
+       = ((((double)number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1);
+      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);
+      bzero ((char *)digits_binary_low, 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
+        */
+
+       char *          p;
+       char            c;
+       int             count;  /* Number of useful digits left to scan. */
+
+       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.
+                    */
+                   abort();    /* RMS prefers abort() to any message. */
+                 }
+             }
+           else
+             {
+               ++ count;       /* '.' doesn't alter digits used count. */
+             }         /* if valid digit */
+         }                     /* for each digit */
+      }
+
+      /*
+       * 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;
+       int             size_of_power_in_littlenums;
+       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 seperate. */
+       
+       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 );
+       bzero ((char *)power_binary_low, 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
+                     flonum_multip(multiplicand + place_number, &power_of_10_flonum, &temporary_flonum);
+                     flonum_copy (& temporary_flonum, & power_of_10_flonum);
+                   }           /* 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: " );
+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;
+
+    }                          /* If we had any significant digits. */
+  return (return_value);
+}                              /* atof_generic () */
+
+/* end: atof_generic.c */
diff --git a/gas/bignum-copy.c b/gas/bignum-copy.c
new file mode 100644 (file)
index 0000000..0dd5f9c
--- /dev/null
@@ -0,0 +1,77 @@
+/* bignum_copy.c - copy a bignum
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include "as.h"
+
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#define bcopy(from,to,n) memcpy(to,from,n)
+#endif
+
+/*
+ *                     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 bcopy() 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 */
+{
+  register int significant_littlenums_dropped;
+
+  if (out_length < in_length)
+    {
+      register LITTLENUM_TYPE *        p; /* -> most significant (non-zero) input littlenum. */
+
+      bcopy ((char *)in, (char *)out, 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
+    {
+      bcopy ((char *)in, (char *)out, in_length << LITTLENUM_SHIFT);
+      if (out_length > in_length)
+       {
+         bzero ((char *)(out + out_length), (out_length - in_length) << LITTLENUM_SHIFT);
+       }
+      significant_littlenums_dropped = 0;
+    }
+  return (significant_littlenums_dropped);
+}
+
+/* end: bignum_copy.c */
diff --git a/gas/bignum.h b/gas/bignum.h
new file mode 100644 (file)
index 0000000..9b1b8e8
--- /dev/null
@@ -0,0 +1,47 @@
+/* bignum.h-arbitrary precision integers
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, 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! */
+
+/* end: bignum.h */
diff --git a/gas/cond.c b/gas/cond.c
new file mode 100644 (file)
index 0000000..38aec6f
--- /dev/null
@@ -0,0 +1,128 @@
+/* cond.c - conditional assembly pseudo-ops, and .include
+   Copyright (C) 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include "as.h"
+
+#include "obstack.h"
+
+void s_ifdef(arg)
+int arg;
+{
+/*     register char c; */
+       register char *name;    /* points to name of symbol */
+       register struct symbol *        symbolP; /* Points to symbol */
+       
+       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);
+       } else {
+               get_symbol_end();
+               ++input_line_pointer;
+               symbolP = symbol_find(name);
+               
+               /* ??? Should we try to optimize such that if we hit a .endif
+                  before a .else, we don't need to push state?  */
+               obstack_1grow(&cond_obstack, (symbolP != 0) ^ arg);
+       }
+} /* s_ifdef() */
+
+/* This is allocated to grow and shrink as .ifdef/.endif pairs
+   are scanned.  When the top element is nonzero, it means
+   we should accept input.  Otherwise, we should ignore input.  */
+struct obstack cond_obstack;
+
+void s_if(arg)
+int arg;
+{
+       expressionS operand;
+       
+       SKIP_WHITESPACE();              /* Leading whitespace is part of operand. */
+       expr(0, &operand);
+       
+       if (operand.X_add_symbol != NULL
+           || operand.X_subtract_symbol != NULL)
+           as_bad("non-constant expression in .if statement");
+       
+       /* If the above error is signaled, this will dispatch
+          using an undefined result.  No big deal.  */
+       obstack_1grow(&cond_obstack, (operand.X_add_number != 0) ^ arg);
+} /* s_if() */
+
+void s_endif(arg)
+int arg;
+{
+       char *base = obstack_base(&cond_obstack);
+       char *ptr = obstack_next_free(&cond_obstack);
+       
+       if (ptr-1 == base) {
+               as_bad("unbalanced .endif");
+       } else {
+               obstack_free(&cond_obstack, ptr-1);
+               cond_obstack.object_base = base;
+       }
+} /* s_endif() */
+
+void s_else(arg)
+int arg;
+{
+       char *ptr = obstack_next_free(&cond_obstack);
+       if (ptr-1 == obstack_base(&cond_obstack)) {
+               as_bad(".else without matching .if");
+       } else {
+               ptr[-1] = !ptr[-1];
+       }
+} /* s_else() */
+
+void s_ifeqs(arg)
+int arg;
+{
+       as_bad("ifeqs not implemented.");
+} /* s_ifeqs() */
+
+void s_end(arg)
+int arg;
+{
+       ;
+} /* s_end() */
+
+int ignore_input() {
+  char *ptr = obstack_next_free (&cond_obstack);
+
+  /* We cannot ignore certain pseudo ops.  */
+  if (input_line_pointer[-1] == '.')
+    {
+      if (input_line_pointer[0] == 'i'
+         && (!strncmp (input_line_pointer, "if", 2)
+             || !strncmp (input_line_pointer, "ifdef", 5)
+             || !strncmp (input_line_pointer, "ifndef", 6)))
+       return 0;
+      if (input_line_pointer[0] == 'e'
+         && (!strncmp (input_line_pointer, "else", 4)
+             || !strncmp (input_line_pointer, "endif", 5)))
+       return 0;
+    }
+
+  return (ptr[-1] == 0);
+} /* ignore_input() */
+
+/* end of cond.c */
diff --git a/gas/config/a.out.h b/gas/config/a.out.h
new file mode 100755 (executable)
index 0000000..5043249
--- /dev/null
@@ -0,0 +1,150 @@
+/* This file describes the a.out file format
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#ifdef USE_HP_INC_HDR
+#include "../binutils/hp-include/a.out.h"
+#else
+
+#ifdef USE_SYSTEM_HDR
+#include "/usr/include/a.out.h"
+#else
+
+#ifdef USE_HP_HDR
+/* The `exec' structure and overall layout must be close to HP's when
+   we are running on an HP system, otherwise we will not be able to
+   execute the resulting file. */
+
+struct exec
+{
+  unsigned short a_machtype;   /* machine type */
+  unsigned short a_magic;      /* magic number */
+  unsigned long a_spare1;
+  unsigned long a_spare2;
+  unsigned long a_text;                /* length of text, in bytes */
+  unsigned long a_data;                /* length of data, in bytes */
+  unsigned long a_bss;         /* length of uninitialized data area for file, in bytes */
+  unsigned long a_trsize;      /* length of relocation info for text, in bytes */
+  unsigned long a_drsize;      /* length of relocation info for data, in bytes */
+  unsigned long a_spare3;      /* HP = pascal interface size */
+  unsigned long a_spare4;      /* HP = symbol table size */
+  unsigned long a_spare5;      /* HP = debug name table size */
+  unsigned long a_entry;       /* start address */
+  unsigned long a_spare6;      /* HP = source line table size */
+  unsigned long a_spare7;      /* HP = value table size */
+  unsigned long a_syms;                /* length of symbol table data in file, in bytes */
+  unsigned long a_spare8;
+};
+
+#define N_MAGIC(exec) ((exec) . a_magic)
+#define N_MACHTYPE(exec) ((exec) . a_machtype)
+#define N_SET_MAGIC(exec, magic) (((exec) . a_magic) = (magic))
+#define N_SET_MACHTYPE(exec, machtype) (((exec) . a_machtype) = (machtype))
+
+#define N_BADMAG(x) ((_N_BADMAG (x)) || (_N_BADMACH (x)))
+
+#define _N_BADMACH(x)                                                  \
+(((N_MACHTYPE (x)) != HP9000S200_ID) &&                                        \
+ ((N_MACHTYPE (x)) != HP98x6_ID))
+
+#define _N_BADMAG(x) \
+ (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
+
+#define HP98x6_ID 0x20A
+#define HP9000S200_ID 0x20C
+
+#else
+
+       /* A Generic machine. . . */
+
+/* JF I'm not sure where this file came from.  I put the permit.text message in
+   it anyway.  This file came to me as part of the original VAX assembler, but had
+   no copyright notices in it. */
+
+struct exec {
+       long    a_magic;                        /* number identifies as .o file and gives type of such. */
+       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 */
+};
+
+#define N_BADMAG(x) \
+ (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
+
+#endif
+
+       /* From here down is common to both the HP and the generic machine */
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+
+
+#define N_TXTOFF(x) \
+ ((x).a_magic == ZMAGIC ? 1024 : sizeof(struct exec))
+
+#define N_SYMOFF(x) \
+ (N_TXTOFF(x) + (x).a_text + (x).a_data + (x).a_trsize + (x).a_drsize)
+
+#define N_STROFF(x) \
+ (N_SYMOFF(x) + (x).a_syms)
+
+struct nlist {
+       union {
+               char    *n_name;
+               struct nlist *n_next;
+               long    n_strx;
+       } n_un;
+       char    n_type;
+       char    n_other;
+       short   n_desc;
+       unsigned n_value;
+};
+
+#define N_UNDF 0
+#define N_ABS  2
+#define N_TEXT 4
+#define N_DATA 6
+#define N_BSS  8
+#define N_FN   31              /* JF: Someone claims this should be 31 instead of
+                          15.  I just inherited this file; I didn't write
+                          it.  Who is right? */
+
+
+#define N_EXT 1
+#define N_TYPE 036
+#define N_STAB 0340
+
+struct relocation_info {
+       int      r_address;
+       unsigned r_symbolnum:24,
+                r_pcrel:1,
+                r_length:2,
+                r_extern:1,
+                r_bsr:1, /* OVE: used on ns32k based systems, if you want */
+                r_disp:1, /* OVE: used on ns32k based systems, if you want */
+                nuthin:2;
+};
+
+#endif
+#endif
diff --git a/gas/config/atof-ieee.c b/gas/config/atof-ieee.c
new file mode 100644 (file)
index 0000000..323d4e1
--- /dev/null
@@ -0,0 +1,511 @@
+/* atof_ieee.c - turn a Flonum into an IEEE floating point number
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "as.h"
+
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#define bcopy(from,to,n) memcpy((to),(from),(n))
+#endif
+
+extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+extern char EXP_CHARS[];
+                               /* Precision in LittleNums. */
+#define MAX_PRECISION (6)
+#define F_PRECISION (2)
+#define D_PRECISION (4)
+#define X_PRECISION (6)
+#define P_PRECISION (6)
+
+                               /* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+static 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
+  };
+\f
+
+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]= ((unsigned)-1)>>1;    /* Zero the leftmost bit */
+       words[1]= -1;
+       words[2]= -1;
+       words[3]= -1;
+       words[4]= -1;
+       words[5]= -1;
+}
+\f
+/***********************************************************************\
+*      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.  */
+
+char *                         /* Return pointer past text consumed. */
+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. */
+{
+       static LITTLENUM_TYPE   bits [MAX_PRECISION + MAX_PRECISION + GUARD];
+                               /* Extra bits for zeroed low-order bits. */
+                               /* The 1st MAX_PRECISION are zeroed, */
+                               /* the last contain flonum bits. */
+       char *          return_value;
+       int             precision; /* Number of 16-bit words in the format. */
+       long    exponent_bits;
+
+       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  = NULL;
+       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. */
+
+       bzero (bits, 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)) {
+               /* as_bad("Error converting floating point number (Exponent overflow?)"); */
+               make_invalid_floating_point_number (words);
+               return NULL;
+       }
+       gen_to_words(words, precision, exponent_bits);
+       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;
+
+       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;
+               bzero (&words[1], sizeof(LITTLENUM_TYPE) * (precision-1));
+               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 {
+                       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 {
+                       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 {
+                       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<1 && exponent_4>=-62) {
+               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);
+               if(precision==X_PRECISION && exponent_bits==15)
+                       prec_bits-=LITTLENUM_NUMBER_OF_BITS+1;
+
+               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;
+                       }
+                       if(precision==X_PRECISION && exponent_bits==15) {
+                               *lp++=0;
+                               *lp++=0;
+                               num_bits-=LITTLENUM_NUMBER_OF_BITS-1;
+                       }
+                       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;
+                               *lp++=0;
+                               if(num_bits==LITTLENUM_NUMBER_OF_BITS) {
+                                       *lp++=0;
+                                       *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS-1);
+                               } else if(num_bits==LITTLENUM_NUMBER_OF_BITS-1)
+                                       *lp++=0;
+                               else
+                                       *lp++=next_bits(LITTLENUM_NUMBER_OF_BITS-1-num_bits);
+                               num_bits=0;
+                       } else {
+                               word1|= next_bits ((LITTLENUM_NUMBER_OF_BITS-1) - (exponent_bits+num_bits));
+                               *lp++=word1;
+                       }
+               }
+               while(lp<words+precision)
+                       *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++;
+               }
+
+               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: it has 16 bits of zero in the middle,
+          followed by a 1 bit. */
+       if(exponent_bits==15 && precision==X_PRECISION) {
+               *lp++=0;
+               *lp++= 1<<(LITTLENUM_NUMBER_OF_BITS)|next_bits(LITTLENUM_NUMBER_OF_BITS-1);
+       }
+
+       /* The rest of the words are just mantissa bits. */
+       while(lp < words + precision)
+               *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 ( (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);
+}
+
+/* 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)
+ */
+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?)");
+}
+
+#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);
+       bcopy(&arr[0],&dv,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);
+       bcopy(&arr[0],&fv,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
diff --git a/gas/config/atof-vax.c b/gas/config/atof-vax.c
new file mode 100644 (file)
index 0000000..43c81d6
--- /dev/null
@@ -0,0 +1,509 @@
+/* atof_vax.c - turn a Flonum into a VAX floating point number
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+       /* JF added these two for md_atof() */
+#include "as.h"
+
+#include "flonum.h"
+
+
+                               /* Precision in LittleNums. */
+#define MAX_PRECISION (8)
+#define H_PRECISION (8)
+#define G_PRECISION (4)
+#define D_PRECISION (4)
+#define F_PRECISION (2)
+
+                               /* Length in LittleNums of guard bits. */
+#define GUARD (2)
+
+int                            /* Number of chars in flonum type 'letter'. */
+atof_vax_sizeof (letter)
+     char letter;
+{
+  int  return_value;
+
+  /*
+   * Permitting uppercase letters is probably a bad idea.
+   * Please use only lower-cased letters in case the upper-cased
+   * ones become unsupported!
+   */
+  switch (letter)
+    {
+    case 'f':
+    case 'F':
+      return_value = 4;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'g':
+    case 'G':
+      return_value = 8;
+      break;
+
+    case 'h':
+    case 'H':
+      return_value = 16;
+      break;
+
+    default:
+      return_value = 0;
+      break;
+    }
+  return (return_value);
+}                              /* atof_vax_sizeof */
+
+static const 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
+  };
+\f
+
+/* Shared between flonum_gen2vax and next_bits */
+static int             bits_left_in_littlenum;
+static LITTLENUM_TYPE *        littlenum_pointer;
+static LITTLENUM_TYPE * littlenum_end;
+
+static int
+next_bits (number_of_bits)
+     int               number_of_bits;
+{
+  int                  return_value;
+
+  if(littlenum_pointer<littlenum_end)
+       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;
+      bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
+      littlenum_pointer --;
+      if(littlenum_pointer>=littlenum_end)
+             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);
+}
+
+static void
+make_invalid_floating_point_number (words)
+     LITTLENUM_TYPE *  words;
+{
+  * words = 0x8000;            /* Floating Reserved Operand Code */
+}
+\f
+static int                     /* 0 means letter is OK. */
+what_kind_of_float (letter, precisionP, exponent_bitsP)
+     char              letter; /* In: lowercase please. What kind of float? */
+     int *             precisionP; /* Number of 16-bit words in the float. */
+     long *            exponent_bitsP; /* Number of exponent bits. */
+{
+  int  retval;                 /* 0: OK. */
+
+  retval = 0;
+  switch (letter)
+    {
+    case 'f':
+      * precisionP = F_PRECISION;
+      * exponent_bitsP = 8;
+      break;
+
+    case 'd':
+      * precisionP = D_PRECISION;
+      * exponent_bitsP = 8;
+      break;
+
+    case 'g':
+      * precisionP = G_PRECISION;
+      * exponent_bitsP = 11;
+      break;
+
+    case 'h':
+      * precisionP = H_PRECISION;
+      * exponent_bitsP = 15;
+      break;
+
+    default:
+      retval = 69;
+      break;
+    }
+  return (retval);
+}
+\f
+/***********************************************************************\
+*                                                                      *
+*      Warning: this returns 16-bit LITTLENUMs, because that is        *
+*      what the VAX thinks in. 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!            *
+*                                                                      *
+\***********************************************************************/
+
+char *                         /* Return pointer past text consumed. */
+atof_vax (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. */
+{
+  FLONUM_TYPE          f;
+  LITTLENUM_TYPE       bits [MAX_PRECISION + MAX_PRECISION + GUARD];
+                               /* Extra bits for zeroed low-order bits. */
+                               /* The 1st MAX_PRECISION are zeroed, */
+                               /* the last contain flonum bits. */
+  char *               return_value;
+  int                  precision; /* Number of 16-bit words in the format. */
+  long         exponent_bits;
+
+  return_value = str;
+  f . low      = bits + MAX_PRECISION;
+  f . high     = NULL;
+  f . leader   = NULL;
+  f . exponent = NULL;
+  f . sign     = '\0';
+
+  if (what_kind_of_float (what_kind, & precision, & exponent_bits))
+    {
+      return_value = NULL;     /* We lost. */
+      make_invalid_floating_point_number (words);
+    }
+  if (return_value)
+    {
+      bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION);
+
+                               /* Use more LittleNums than seems */
+                               /* necessary: the highest flonum may have */
+                               /* 15 leading 0 bits, so could be useless. */
+      f . high = f . low + precision - 1 + GUARD;
+
+      if (atof_generic (& return_value, ".", "eE", & f))
+       {
+         make_invalid_floating_point_number (words);
+         return_value = NULL;  /* we lost */
+       }
+      else
+       {
+         if (flonum_gen2vax (what_kind, & f, words))
+           {
+             return_value = NULL;
+           }
+       }
+    }
+  return (return_value);
+}
+\f
+/*
+ * In: a flonum, a vax floating point format.
+ * Out: a vax floating-point bit pattern.
+ */
+
+int                            /* 0: OK. */
+flonum_gen2vax (format_letter, f, words)
+     char              format_letter; /* One of 'd' 'f' 'g' 'h'. */
+     FLONUM_TYPE *     f;
+     LITTLENUM_TYPE *  words;  /* Deliver answer here. */
+{
+  LITTLENUM_TYPE *     lp;
+  int                  precision;
+  long         exponent_bits;
+  int                  return_value; /* 0 == OK. */
+
+  return_value = what_kind_of_float (format_letter, & precision, & exponent_bits);
+  if (return_value != 0)
+    {
+      make_invalid_floating_point_number (words);
+    }
+  else
+    {
+      if (f -> low > f -> leader)
+       {
+         /* 0.0e0 seen. */
+         bzero (words, sizeof(LITTLENUM_TYPE) * precision);
+       }
+      else
+       {
+         long          exponent_1;
+         long          exponent_2;
+         long          exponent_3;
+         long          exponent_4;
+         int           exponent_skippage;
+         LITTLENUM_TYPE        word1;
+
+               /* JF: Deal with new Nan, +Inf and -Inf codes */
+         if(f->sign!='-' && f->sign!='+') {
+           make_invalid_floating_point_number(words);
+           return return_value;
+         }
+         /*
+          * All vaxen floating_point formats (so far) 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 are the next most significant bits.
+          * And so on for each other word.
+          *
+          * All this to be compatible with a KF11?? (Which is still faster
+          * than lots of vaxen I can think of, but it also has higher
+          * maintenance costs ... sigh).
+          *
+          * So we need: number of bits of exponent, number of bits of
+          * mantissa.
+          */
+         
+#ifdef NEVER  /******* This zeroing seems redundant - Dean 3may86 **********/
+         /*
+          * No matter how few bits we got back from the atof()
+          * routine, add enough zero littlenums so the rest of the
+          * code won't run out of "significant" bits in the mantissa.
+          */
+         {
+           LITTLENUM_TYPE * ltp;
+           for (ltp = f -> leader + 1;
+                ltp <= f -> low + precision;
+                ltp ++)
+             {
+               * ltp = 0;
+             }
+         }
+#endif
+         
+         bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
+         littlenum_pointer = f -> leader;
+         littlenum_end = f->low;
+         /* Seek (and forget) 1st significant bit */
+         for (exponent_skippage = 0;
+              ! next_bits(1);
+              exponent_skippage ++)
+           {
+           }
+         exponent_1 = f -> exponent + f -> leader + 1 - f -> low;
+         /* Radix LITTLENUM_RADIX, point just higher than f -> 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));
+         /* Offset exponent. */
+         
+         if (exponent_4 & ~ mask [exponent_bits])
+           {
+             /*
+              * Exponent overflow. Lose immediately.
+              */
+             
+             make_invalid_floating_point_number (words);
+             
+             /*
+              * We leave return_value alone: admit we read the
+              * number, but return a floating exception
+              * because we can't encode the number.
+              */
+           }
+         else
+           {
+             lp = words;
+             
+             /* Word 1. Sign, exponent and perhaps high bits. */
+             /* Assume 2's complement integers. */
+             word1 = ((exponent_4 & mask [exponent_bits]) << (15 - exponent_bits))
+               |       ((f -> sign == '+') ? 0 : 0x8000)
+                 |     next_bits (15 - exponent_bits);
+             * lp ++ = word1;
+             
+             /* The rest of the words are just mantissa bits. */
+             for (; lp < words + precision; lp++)
+               {
+                 * lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
+               }
+             
+             if (next_bits (1))
+               {
+                 /*
+                  * 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?
+                  */
+                 
+                 unsigned long carry;
+                 
+                 /*
+                   #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 ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) )
+                   {
+                     make_invalid_floating_point_number (words);
+                     /*
+                      * We leave return_value alone: admit we read the
+                      * number, but return a floating exception
+                      * because we can't encode the number.
+                      */
+                   }
+               }               /* if (we needed to round up) */
+           }                   /* if (exponent overflow) */
+       }                       /* if (0.0e0) */
+    }                          /* if (float_type was OK) */
+  return (return_value);
+}
+
+
+/* JF this used to be in vax.c but this looks like a better place for it */
+
+/*
+ *             md_atof()
+ *
+ * In: input_line_pointer -> the 1st character of a floating-point
+ *             number.
+ *     1 letter denoting the type of statement that wants a
+ *             binary floating point number returned.
+ *     Address of where to build floating point literal.
+ *             Assumed to be 'big enough'.
+ *     Address of where to return size of literal (in chars).
+ *
+ * Out:        Input_line_pointer -> of next char after floating number.
+ *     Error message, or "".
+ *     Floating point literal.
+ *     Number of chars we used for the literal.
+ */
+
+#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */
+
+char *
+md_atof (what_statement_type, literalP, sizeP)
+     char      what_statement_type;
+     char *    literalP;
+     int *     sizeP;
+{
+  LITTLENUM_TYPE       words [MAXIMUM_NUMBER_OF_LITTLENUMS];
+  register char                kind_of_float;
+  register int         number_of_chars;
+  register LITTLENUM_TYPE * littlenum_pointer;
+
+  switch (what_statement_type)
+    {
+    case 'F':                  /* .float */
+    case 'f':                  /* .ffloat */
+      kind_of_float = 'f';
+      break;
+
+    case 'D':                  /* .double */
+    case 'd':                  /* .dfloat */
+      kind_of_float = 'd';
+      break;
+
+    case 'g':                  /* .gfloat */
+      kind_of_float = 'g';
+      break;
+
+    case 'h':                  /* .hfloat */
+      kind_of_float = 'h';
+      break;
+
+    default:
+      kind_of_float = 0;
+      break;
+    };
+
+  if (kind_of_float)
+    {
+      register LITTLENUM_TYPE * limit;
+
+      input_line_pointer = atof_vax (input_line_pointer,
+                                    kind_of_float,
+                                    words);
+      /*
+       * The atof_vax() builds up 16-bit numbers.
+       * Since the assembler may not be running on
+       * a little-endian machine, be very careful about
+       * converting words to chars.
+       */
+      number_of_chars = atof_vax_sizeof (kind_of_float);
+      know( number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof(LITTLENUM_TYPE) );
+      limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE));
+      for (littlenum_pointer = words;
+          littlenum_pointer < limit;
+          littlenum_pointer ++)
+       {
+         md_number_to_chars (literalP, * littlenum_pointer, sizeof(LITTLENUM_TYPE));
+         literalP += sizeof(LITTLENUM_TYPE);
+       };
+    }
+  else
+    {
+      number_of_chars = 0;
+    };
+
+  * sizeP = number_of_chars;
+  return (kind_of_float ? "" : "Bad call to md_atof()");
+}                              /* md_atof() */
+
+/* atof_vax.c */
diff --git a/gas/config/coff.gnu.h b/gas/config/coff.gnu.h
new file mode 100755 (executable)
index 0000000..281ac17
--- /dev/null
@@ -0,0 +1,568 @@
+/*** coff information for 80960.  Origins: Intel, AMD, etc., natch. */
+
+/*
+ * At this point I'm sure this file is right for i960 and I'm pretty sure it's
+ * right for a29k, although it hasn't been tested rigorously.  Please feel free
+ * to add your own machine's description here.  Without that info, it isn't
+ * possible to build cross development tools from elsewhere nor is it easy to
+ * continue to support your machines format.
+ *
+ * The TC_foo ifdef's are mine.  They are what gas uses.  The other ifdef's
+ * remain for documentation from other scavenged files.   xoxorich.
+ */
+
+/* $Id$ */
+
+/********************** FILE HEADER **********************/
+
+struct filehdr {
+       unsigned short  f_magic;        /* magic number                 */
+       unsigned short  f_nscns;        /* number of sections           */
+       long            f_timdat;       /* time & date stamp            */
+       long            f_symptr;       /* file pointer to symtab       */
+       long            f_nsyms;        /* number of symtab entries     */
+       unsigned short  f_opthdr;       /* sizeof(optional hdr)         */
+       unsigned short  f_flags;        /* flags                        */
+};
+
+/* Bits for f_flags:
+ *     F_RELFLG        relocation info stripped from file
+ *     F_EXEC          file is executable (no unresolved externel references)
+ *     F_LNNO          line nunbers stripped from file
+ *     F_LSYMS         local symbols stripped from file
+ *     F_AR32WR        file has byte ordering of an AR32WR machine (e.g. vax)
+ */
+#define F_RELFLG       (0x0001)
+#define F_EXEC         (0x0002)
+#define F_LNNO         (0x0004)
+#define F_LSYMS                (0x0008)
+
+#ifdef TC_I960
+#define F_AR32WR       (0x0010) /* File has 32 bits per word, least
+                                   significant byte first. */
+#else /* TC_I960 */
+#define F_AR32WR       (0x0100)
+#endif /* TC_I960 */
+
+#define F_MINMAL       (0x0010) /* ??? */
+#define F_UPDATE       (0x0020) /* ??? */
+#define F_SWABD                (0x0040) /* ??? */
+#define F_AR16WR       (0x0080) /* File has the byte ordering used by
+                                   the PDP*-11/70 processor. */
+#define F_AR32W                (0x0200) /* File has 32 bits per word, most
+                                   significant byte first. */
+
+/*
+ *     Intel 80960 (I960) processor flags.
+ *     F_I960TYPE == mask for processor type field. 
+ */
+
+#define        F_I960TYPE      (0xf000)
+#define        F_I960CORE      (0x1000)
+#define        F_I960KB        (0x2000)
+#define        F_I960SB        (0x2000)
+#define        F_I960MC        (0x3000)
+#define        F_I960XA        (0x4000)
+#define        F_I960CA        (0x5000)
+#define        F_I960KA        (0x6000)
+#define        F_I960SA        (0x6000)
+
+/*
+ * i80960 Magic Numbers
+ */
+
+#define I960ROMAGIC    (0x160) /* read-only text segments */
+#define I960RWMAGIC    (0x161) /* read-write text segments */
+
+#define I960BADMAG(x) (((x).f_magic != I960ROMAGIC) && ((x).f_magic != I960RWMAGIC))
+
+#define        SIPFBOMAGIC     (0x17a) /* Am29000 (Byte 0 is MSB - Big Endian) */
+#define        SIPRBOMAGIC     (0x17b) /* Am29000 (Byte 0 is LSB - Little Endian) */
+
+#define A29KBADMAG(x)  (((x).f_magic != SIPFBOMAGIC) && ((x).f_magic != SIPRBOMAGIC))
+
+#define        FILHDR  struct filehdr
+#define        FILHSZ  sizeof(FILHDR)
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+typedef struct {
+       unsigned long   phys_addr;
+       unsigned long   bitarray;
+} TAGBITS;
+
+/*  These appear to be used only by exec(2).  I don't know who cares
+    about them in a cross development environment.  In any case, this
+    is my collection after researching the issue for a few hours.
+    Apparently, most have these have remained essentially unchanged
+    since v7 days, although a few new ones have been added.  xoxorich. */
+
+#define BAD0MAGIC      (0401) /* (?) "lpd (UNIX/RT)" */
+#define BAD1MAGIC      (0405) /* (?) overlay */
+#define        OMAGIC          (0407) /* old impure format. data immediately
+                                 follows text. both sections are rw. */
+#define        NMAGIC          (0410) /* split i&d, read-only text */
+#define A_MAGIC3       (0411) /* (?) "separated I&D" */
+#define        ZMAGIC          (0413) /* like NMAGIC, but demand loaded */
+#define PAGEMAGIC2     (0414) /* (?) like ZMAGIC, but address zero
+                                 explicitly unmapped. */
+#define REGMAGIC       (0414) /* (?) a PAGEMAGIC2 alias? */
+#define PAGEMAGIC3     (0415) /* (?) like ZMAGIC, but address zero mapped. */
+#define A_MAGIC5       (0437) /* (?) "system overlay, separated I&D" */
+ /* intended for non-unix cross development */
+#define SASMAGIC       (010000) /* Single Address Space */    
+#define MASMAGIC       (020000) /* (?) "Multiple (separate I & D) Address Spaces" */
+
+typedef        struct aouthdr {
+       short           magic;  /* type of file                         */
+       short           vstamp; /* version stamp                        */
+       unsigned long   tsize;  /* text size in bytes, padded to FW bdry*/
+       unsigned long   dsize;  /* initialized data "  "                */
+       unsigned long   bsize;  /* uninitialized data "   "             */
+#if U3B
+       unsigned long   dum1;
+       unsigned long   dum2;   /* pad to entry point   */
+#endif
+       unsigned long   entry;  /* entry pt.                            */
+       unsigned long   text_start;     /* base of text used for this file */
+       unsigned long   data_start;     /* base of data used for this file */
+ /* CAREFUL: some formats omit the tagentries member. */
+       unsigned long   tagentries;     /* number of tag entries to
+                                          follow (always zero for i960) */
+} AOUTHDR;
+
+/* return a pointer to the tag bits array */
+
+#define TAGPTR(aout) ((TAGBITS *) (&(aout.tagentries)+1))
+
+/* compute size of a header */
+
+/*#define AOUTSZ(aout) (sizeof(AOUTHDR)+(aout.tagentries*sizeof(TAGBITS)))*/
+#define AOUTSZ (sizeof(AOUTHDR))
+
+
+/********************** STORAGE CLASSES **********************/
+
+#define C_EFCN         -1      /* physical end of function */
+#define C_NULL         0
+#define C_AUTO         1       /* automatic variable */
+#define C_EXT          2       /* external symbol */
+#define C_STAT         3       /* static */
+#define C_REG          4       /* register variable */
+#define C_EXTDEF       5       /* external definition */
+#define C_LABEL                6       /* label */
+#define C_ULABEL       7       /* undefined label */
+#define C_MOS          8       /* member of structure */
+#define C_ARG          9       /* function argument */
+#define C_STRTAG       10      /* structure tag */
+#define C_MOU          11      /* member of union */
+#define C_UNTAG                12      /* union tag */
+#define C_TPDEF                13      /* type definition */
+#define C_USTATIC      14      /* undefined static */
+#define C_ENTAG                15      /* enumeration tag */
+#define C_MOE          16      /* member of enumeration */
+#define C_REGPARM      17      /* register parameter */
+#define C_FIELD                18      /* bit field */
+
+#ifdef TC_I960
+#define C_AUTOARG      19      /* auto argument */
+#define C_LASTENT      20      /* dummy entry (end of block) */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+#define C_GLBLREG      19              /* global register */
+#define C_EXTREG       20              /* external global register */
+#define        C_DEFREG        21              /* ext. def. of global register */
+#define C_STARTOF      22              /* as29 $SIZEOF and $STARTOF symbols */
+#endif /* TC_A29K */
+
+#define C_BLOCK                100     /* ".bb" or ".eb" */
+#define C_FCN          101     /* ".bf" or ".ef" */
+#define C_EOS          102     /* end of structure */
+#define C_FILE         103     /* file name */
+#define C_LINE         104     /* line # reformatted as symbol table entry */
+#define C_ALIAS                105     /* duplicate tag */
+#define C_HIDDEN       106     /* ext symbol in dmert public lib. like static,
+                                  used to avoid name conflicts. */
+
+#ifdef TC_I960
+       /* New storage classes for 80960 */
+#define C_SCALL                107     /* Procedure reachable via system call  */
+ /* C_LEAFPROC is obsolete.  Use C_LEAFEXT or C_LEAFSTAT */
+#define C_LEAFPROC     108     /* Leaf procedure, "call" via BAL */
+#define C_LEAFEXT       108
+#define C_OPTVAR       109     /* Optimized variable */
+#define C_DEFINE       110     /* Preprocessor #define */
+#define C_PRAGMA       111     /* Advice to compiler or linker */
+#define C_SEGMENT      112     /* 80960 segment name */
+#define C_LEAFSTAT      113     /* Static leaf */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+#define C_SHADOW       107 /* shadow symbol */
+#endif /* TC_A29K */
+
+/********************** SECTION HEADER **********************/
+
+struct scnhdr {
+       char            s_name[8];      /* section name */
+       long            s_paddr;        /* physical address, aliased s_nlib */
+       long            s_vaddr;        /* virtual address */
+       long            s_size;         /* section size */
+       long            s_scnptr;       /* file ptr to raw data for section */
+       long            s_relptr;       /* file ptr to relocation */
+       long            s_lnnoptr;      /* file ptr to line numbers */
+       unsigned short  s_nreloc;       /* number of relocation entries */
+       unsigned short  s_nlnno;        /* number of line number entries */
+       long            s_flags;        /* flags */
+
+#ifdef TC_I960
+       unsigned long   s_align;        /* section alignment */
+#endif /* TC_I960 */
+};
+
+#define        SCNHDR  struct scnhdr
+#define        SCNHSZ  sizeof(SCNHDR)
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT  ".text"
+#define _DATA  ".data"
+#define _BSS   ".bss"
+
+/*
+ * s_flags "type"
+ */
+
+/*
+ * In instances where it is necessary for a linker to
+ * produce an output file which contains text or data not
+ * based at virtual address 0, e.g. for a ROM, then the
+ * linker should accept address base information as command
+ * input and use PAD sections to skip over unused addresses.
+ * (at least for a29k.  Maybe others.)
+ */
+
+#define STYP_REG        (0x0000) /* "regular" section: allocated, relocated, loaded */
+#define STYP_DSECT      (0x0001) /* "dummy" section: not allocated, relocated, not loaded */
+#define STYP_NOLOAD     (0x0002) /* "noload" section: allocated, relocated, not loaded */
+#define STYP_GROUP      (0x0004) /* "grouped" section: formed of input sections */
+#define STYP_PAD        (0x0008) /* "padding" section: not allocated, not relocated, loaded */
+#define STYP_COPY       (0x0010) /* "copy" section: for decision function used by field update;  not allocated, not relocated,
+                                    loaded; reloc & lineno entries processed normally */
+#define STYP_TEXT       (0x0020) /* section contains text only */
+#define S_SHRSEG        (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile
+                                    will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will
+                                    update all process invocations. */
+#define STYP_DATA       (0x0040) /* section contains data only */
+#define STYP_BSS        (0x0080) /* section contains bss only */
+#define S_NEWFCN        (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */
+#define STYP_INFO       (0x0200) /* comment section : not allocated not relocated, not loaded */
+#define STYP_OVER       (0x0400) /* overlay section : relocated not allocated or loaded */
+#define STYP_LIB        (0x0800) /* for .lib section : same as INFO */
+#define STYP_MERGE      (0x2000) /* merge section -- combines with text, data or bss sections only */
+#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions wherever padding is necessary and there is a
+                                    word of contiguous bytes beginning on a word boundary. */
+
+#ifdef TC_A29K
+/* NOTE:  The use of STYP_BSSREG for relocation is not yet defined. */
+#define        STYP_BSSREG     0x1200  /* Global register area (like STYP_INFO) */
+#define STYP_ENVIR     0x2200  /* Environment (like STYP_INFO) */
+#define STYP_ABS       0x4000  /* Absolute (allocated, not reloc, loaded) */
+#define STYP_LIT       0x8020  /* Literal data (like STYP_TEXT) */
+#endif /* TC_A29K */
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct lineno {
+       union {
+               long l_symndx;  /* symbol index of function name, iff l_lnno == 0*/
+               long l_paddr;   /* (physical) address of line number */
+       } l_addr;
+       unsigned short  l_lnno; /* line number */
+#ifdef TC_I960
+ /* not used on a29k */
+       char padding[2];        /* force alignment */
+#endif /* TC_I960 */
+};
+
+#define        LINENO  struct lineno
+#define        LINESZ  sizeof(LINENO) 
+
+
+/********************** SYMBOLS **********************/
+
+#define SYMNMLEN       8       /* # characters in a symbol name        */
+#define FILNMLEN       14      /* # characters in a file name          */
+#define DIMNUM         4       /* # array dimensions in auxiliary entry */
+
+struct syment {
+       union {
+               char    _n_name[SYMNMLEN];      /* old COFF version     */
+               struct {
+                       long    _n_zeroes;      /* new == 0             */
+                       long    _n_offset;      /* offset into string table */
+               } _n_n;
+               char    *_n_nptr[2];    /* allows for overlaying        */
+       } _n;
+       long            n_value;        /* value of symbol              */
+       short           n_scnum;        /* section number               */
+
+#ifdef TC_I960
+ /* This isn't yet used on the i960.  In some formats this
+    is two bytes of padding.  In others, it is missing entirely. */
+       unsigned short  n_flags;        /* copy of flags from filhdr    */
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+       unsigned short  n_type;         /* type and derived type        */
+#else /* TC_A29K */
+ /* at least i960 uses long */
+       unsigned long   n_type;         /* type and derived type        */
+#endif /* TC_A29K */
+
+       char            n_sclass;       /* storage class                */
+       char            n_numaux;       /* number of aux. entries       */
+
+#ifndef TC_A29K
+       char            pad2[2];        /* force alignment              */
+#endif /* TC_A29K */
+};
+
+#define        SYMENT  struct syment
+#define        SYMESZ  sizeof(SYMENT) /* This had better also be sizeof(AUXENT) */
+
+#define n_name         _n._n_name
+#define n_ptr          _n._n_nptr[1]
+#define n_zeroes       _n._n_n._n_zeroes
+#define n_offset       _n._n_n._n_offset
+
+/*
+ * Relocatable symbols have number of the section in which they are defined,
+ * or one of the following:
+ */
+
+#define N_SCNUM        ((short) 1-65535) /* section num where symbol defined */
+#define N_UNDEF        ((short)0)  /* undefined symbol */
+#define N_ABS  ((short)-1) /* value of symbol is absolute */
+#define N_DEBUG        ((short)-2) /* debugging symbol -- symbol value is meaningless */
+#define N_TV   ((short)-3) /* indicates symbol needs preload transfer vector */
+#define P_TV   ((short)-4) /* indicates symbol needs transfer vector (postload) */
+
+/*
+ * Type of a symbol, in low 4 bits of the word
+ */
+#define T_NULL         0 /* type not assigned */
+#define T_VOID         1 /* function argument (only used by compiler) (but now
+                            real void). */
+#define T_CHAR         2 /* character */
+#define T_SHORT                3 /* short integer */
+#define T_INT          4 /* integer */
+#define T_LONG         5 /* long integer */
+#define T_FLOAT                6 /* floating point */
+#define T_DOUBLE       7 /* double word */
+#define T_STRUCT       8 /* structure */
+#define T_UNION                9 /* union */
+#define T_ENUM         10 /* enumeration */
+#define T_MOE          11 /* member of enumeration */
+#define T_UCHAR                12 /* unsigned character */
+#define T_USHORT       13 /* unsigned short */
+#define T_UINT         14 /* unsigned integer */
+#define T_ULONG                15 /* unsigned long */
+
+#ifdef TC_I960
+#define T_LNGDBL       16      /* long double */
+#endif /* TC_I960 */
+
+/*
+ * derived types, in n_type
+ */
+#define DT_NON         (0)     /* no derived type */
+#define DT_PTR         (1)     /* pointer */
+#define DT_FCN         (2)     /* function */
+#define DT_ARY         (3)     /* array */
+
+#ifndef TC_I960
+
+#define N_BTMASK       (0x0f)
+#define N_TMASK                (0x30)
+#define N_BTSHFT       (4)
+#define N_TSHIFT       (2)
+
+#else /* TC_I960 */
+
+#define N_BTMASK       (0x1f)
+#define N_TMASK                (0x60)
+#define N_BTSHFT       (5)
+#define N_TSHIFT       (2)
+
+#endif /* TC_I960 */
+
+#define BTYPE(x)       ((x) & N_BTMASK)
+
+#define ISPTR(x)       (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
+#define ISFCN(x)       (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
+#define ISARY(x)       (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
+
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+
+union auxent {
+       struct {
+               long x_tagndx;  /* str, un, or enum tag indx */
+               union {
+                       struct {
+                           unsigned short x_lnno; /* declaration line number */
+                           unsigned short x_size; /* str/union/array size */
+                       } x_lnsz;
+                       long x_fsize;   /* size of function */
+               } x_misc;
+               union {
+                       struct {                /* if ISFCN, tag, or .bb */
+                           long x_lnnoptr;     /* ptr to fcn line # */
+                           long x_endndx;      /* entry ndx past block end */
+                       } x_fcn;
+                       struct {                /* if ISARY, up to 4 dimen. */
+                           unsigned short x_dimen[DIMNUM];
+                       } x_ary;
+               } x_fcnary;
+               unsigned short x_tvndx;         /* tv index */
+       } x_sym;
+
+ /* This was just a struct x_file with x_fname only in a29k.  xoxorich. */
+       union {
+               char x_fname[FILNMLEN];
+               struct {
+                       long x_zeroes;
+                       long x_offset;
+               } x_n;
+       } x_file;
+
+       struct {
+               long x_scnlen;                  /* section length */
+               unsigned short x_nreloc;        /* # relocation entries */
+               unsigned short x_nlinno;        /* # line numbers */
+       } x_scn;
+
+       struct {
+               long            x_tvfill;       /* tv fill value */
+               unsigned short  x_tvlen;        /* length of .tv */
+
+ /* This field was typo'd x_tvrna on a29k. xoxorich. */
+               unsigned short  x_tvran[2];     /* tv range */
+       } x_tv;         /* info about .tv section (in auxent of symbol .tv)) */
+
+#ifdef TC_I960
+       /******************************************
+        *  I960-specific *2nd* aux. entry formats
+        ******************************************/
+       struct {
+ /* This is a very old typo that keeps getting propogated. */
+#define x_stdindx x_stindx
+               long x_stindx;  /* sys. table entry */
+       } x_sc; /* system call entry */
+
+       struct {
+               unsigned long x_balntry; /* BAL entry point */
+       } x_bal; /* BAL-callable function */
+
+       struct {
+               unsigned long   x_timestamp;            /* time stamp */
+               char    x_idstring[20];         /* producer identity string */
+       } x_ident;                              /* Producer ident info */
+
+       char a[sizeof(struct syment)];  /* force auxent/syment sizes to match */
+#endif /* TC_I960 */
+};
+
+#define        AUXENT  union auxent
+#define        AUXESZ  sizeof(AUXENT) /* This had better also be sizeof(SYMENT) */
+
+#if VAX || I960
+#      define _ETEXT   "_etext"
+#else
+#      define _ETEXT   "etext"
+#endif
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct reloc {
+       long r_vaddr;           /* Virtual address of reference */
+       long r_symndx;          /* Index into symbol table */
+       unsigned short r_type;  /* Relocation type */
+#ifdef TC_I960
+ /* not used for a29k */
+       char pad[2];            /* Unused */
+#endif /* TC_I960 */
+};
+
+#define RELOC struct reloc
+#define RELSZ sizeof(RELOC)
+
+#ifdef TC_I960
+#define R_RELLONG      (0x11)  /* Direct 32-bit relocation */
+#define R_IPRSHORT     (0x18)
+#define R_IPRMED       (0x19)  /* 24-bit ip-relative relocation */
+#define R_IPRLONG      (0x1a)
+#define R_OPTCALL      (0x1b)  /* 32-bit optimizable call (leafproc/sysproc) */
+#define R_OPTCALLX     (0x1c)  /* 64-bit optimizable call (leafproc/sysproc) */
+#define R_GETSEG       (0x1d)
+#define R_GETPA                (0x1e)
+#define R_TAGWORD      (0x1f)
+#endif /* TC_I960 */
+
+#ifdef TC_A29K
+/*
+ * NOTE: All the "I" forms refer to Am29000 instruction
+ * formats.  The linker is expected to know how the numeric
+ * information is split and/or aligned within the
+ * instruction word(s).  R_BYTE works for instructions, too.
+ *
+ * If the parameter to a CONSTH instruction is a relocatable
+ * type, two relocation records are written.  The first has
+ * an r_type of R_IHIHALF (33 octal) and a normal r_vaddr
+ * and r_symndx.  The second relocation record has an r_type
+ * of R_IHCONST (34 octal), a normal r_vaddr (which is
+ * redundant), and an r_symndx containing the 32-bit
+ * constant offset to the relocation instead of the actual
+ * symbol table index.  This second record is always
+ * written, even if the constant offset is zero.  The
+ * constant fields of the instruction are set to zero.
+ */
+
+#define        R_ABS           (0x00) /* reference is absolute */
+#define        R_IREL          (0x18) /* instruction relative (jmp/call) */
+#define        R_IABS          (0x19) /* instruction absolute (jmp/call) */
+#define        R_ILOHALF       (0x1a) /* instruction low half  (const)  */
+#define        R_IHIHALF       (0x1b) /* instruction high half (consth) part 1 */
+#define        R_IHCONST       (0x1c) /* instruction high half (consth) part 2
+                                 constant offset of R_IHIHALF relocation */
+#define        R_BYTE          (0x1d) /* relocatable byte value */
+#define R_HWORD                (0x1e) /* relocatable halfword value */
+#define R_WORD         (0x1f) /* relocatable word value */
+#define        R_IGLBLRC       (0x20) /* instruction global register RC */
+#define        R_IGLBLRA       (0x21) /* instruction global register RA */
+#define        R_IGLBLRB       (0x22) /* instruction global register RB */
+#endif /* TC_A29K */
+
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 16
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of coff.gnu.h */
diff --git a/gas/config/ho-ansi.h b/gas/config/ho-ansi.h
new file mode 100644 (file)
index 0000000..b7fc587
--- /dev/null
@@ -0,0 +1,40 @@
+/* ho-ansi.h  Host-specific header file for generic ansi environments.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define M_ANSI 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#define sys_nerr       _sys_nerr
+#define sys_errlist    _sys_errlist
+#define bzero(b,l)     (memset((b),0,(l)))
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:15:38  rich
+ * Initial revision
+ *
+ *
+ */
+
+/* end of ho-ansi.h */
diff --git a/gas/config/ho-cygnus.h b/gas/config/ho-cygnus.h
new file mode 100755 (executable)
index 0000000..9b39153
--- /dev/null
@@ -0,0 +1,41 @@
+/* ho-ansi.h  Host-specific header file for generic ansi environments.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define M_ANSI 1
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define sys_nerr       _sys_nerr
+#define sys_errlist    _sys_errlist
+#define bzero(s,l)     (memset((s),0,(l)))
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:15:40  rich
+ * Initial revision
+ *
+ *
+ */
+
+/* end of ho-ansi.h */
diff --git a/gas/config/ho-generic.h b/gas/config/ho-generic.h
new file mode 100644 (file)
index 0000000..40c49e9
--- /dev/null
@@ -0,0 +1,32 @@
+/* ho-generic.h  Generic host-specific header file.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define M_GENERIC 1
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:15:42  rich
+ * Initial revision
+ *
+ *
+ */
+
+/* end of ho-generic.h */
diff --git a/gas/config/ho-hpux.h b/gas/config/ho-hpux.h
new file mode 100644 (file)
index 0000000..751b4ee
--- /dev/null
@@ -0,0 +1,34 @@
+/* ho-hpux.h -- Header to compile the assembler under HP-UX
+   Copyright (C) 1988, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#include "ho-sysv.h"
+
+/* This header file contains the #defines specific
+   to HPUX changes sent me by cph@zurich.ai.mit.edu */
+#ifndef hpux
+#define hpux
+#endif
+
+#ifdef setbuffer
+#undef setbuffer
+#endif /* setbuffer */
+
+#define setbuffer(stream, buf, size)
diff --git a/gas/config/ho-i386.h b/gas/config/ho-i386.h
new file mode 100644 (file)
index 0000000..94dd8c2
--- /dev/null
@@ -0,0 +1,28 @@
+/* ho-i386.h  i386 specific header file.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define HO_I386 1
+
+#define NO_STDARG
+
+#include "ho-sysv.h"
+
+/* end of ho-i386.h */
diff --git a/gas/config/ho-sun3.h b/gas/config/ho-sun3.h
new file mode 100644 (file)
index 0000000..33b74c3
--- /dev/null
@@ -0,0 +1,7 @@
+/* $Id$ */
+
+#include <ho-sunos.h>
+
+extern int sprintf();
+
+/* end of ho-sun3.h */
diff --git a/gas/config/ho-sun386.h b/gas/config/ho-sun386.h
new file mode 100644 (file)
index 0000000..00eacad
--- /dev/null
@@ -0,0 +1,7 @@
+/* $Id$ */
+
+#include <ho-sunos.h>
+
+extern int sprintf();
+
+/* end of ho-sun386.h */
diff --git a/gas/config/ho-sun4.h b/gas/config/ho-sun4.h
new file mode 100644 (file)
index 0000000..6cfd6b4
--- /dev/null
@@ -0,0 +1,5 @@
+/* $Id$ */
+
+#include <ho-sunos.h>
+
+/* end of ho-sun4.h */
diff --git a/gas/config/ho-sunos.h b/gas/config/ho-sunos.h
new file mode 100644 (file)
index 0000000..13d5c3d
--- /dev/null
@@ -0,0 +1,56 @@
+/* $Id$ */
+
+#ifndef __STDC__
+#define NO_STDARG
+#include <memory.h>
+#endif /* not __STDC__ */
+
+#include <ctype.h>
+#include <string.h>
+
+/* externs for system libraries. */
+
+extern char *strchr();
+extern char *malloc();
+extern char *realloc();
+extern char *strrchr();
+extern int _filbuf();
+extern int _flsbuf();
+extern int abort();
+extern int bcopy();
+extern int bzero();
+extern int bzero();
+extern int exit();
+extern int fclose();
+extern int fprintf();
+extern int fread();
+extern int free();
+extern int perror();
+extern int printf();
+extern int setvbuf();
+extern int sscanf();
+extern int strcmp();
+extern int strlen();
+extern int strncmp();
+extern int time();
+extern int ungetc();
+extern int vfprintf();
+extern int vprintf();
+extern long atol();
+
+#ifndef tolower
+extern int tolower();
+#endif /* tolower */
+
+#ifndef toupper
+extern int toupper();
+#endif /* toupper */
+
+/*
+ * Local Variables:
+ * fill-column: 80
+ * comment-column: 0
+ * End:
+ */
+
+/* end of ho-sun4.h */
diff --git a/gas/config/ho-sysv.h b/gas/config/ho-sysv.h
new file mode 100644 (file)
index 0000000..af8dd6e
--- /dev/null
@@ -0,0 +1,31 @@
+/* ho-sysv.h  System V specific header file.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define HO_USG
+
+#define bcopy(from,to,n) memcpy((to),(from),(n))
+#define bzero(s,n) memset((s),0,(n))
+#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOLBF, (size))
+
+extern int free();
+extern char *malloc();
+
+/* end of ho-sysv.h */
diff --git a/gas/config/obj-aout.c b/gas/config/obj-aout.c
new file mode 100644 (file)
index 0000000..6c1e100
--- /dev/null
@@ -0,0 +1,500 @@
+/* a.out object file format
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+#include "as.h"
+
+#include "obstack.h"
+
+ /* in: segT   out: N_TYPE bits */
+const short seg_N_TYPE[] = {
+  N_ABS,
+  N_TEXT,
+  N_DATA,
+  N_BSS,
+  N_UNDF, /* unknown */
+  N_UNDF, /* absent */
+  N_UNDF, /* pass1 */
+  N_UNDF, /* error */
+  N_UNDF, /* bignum/flonum */
+  N_UNDF, /* difference */
+  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,
+};
+
+#ifdef __STDC__
+static void obj_aout_stab(int what);
+static void obj_aout_line(void);
+static void obj_aout_desc(void);
+#else /* __STDC__ */
+static void obj_aout_desc();
+static void obj_aout_stab();
+static void obj_aout_line();
+#endif /* __STDC__ */
+
+const pseudo_typeS obj_pseudo_table[] = {
+       { "line",       obj_aout_line,          0       }, /* source code line number */
+       { "ln",         obj_aout_line,          0       }, /* source code line number */
+       { "desc",       obj_aout_desc,          0       }, /* def */
+       { "stabd",      obj_aout_stab,          'd'     }, /* stabs */
+       { "stabn",      obj_aout_stab,          'n'     }, /* stabs */
+       { "stabs",      obj_aout_stab,          's'     }, /* stabs */
+
+       { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+
+/* Relocation. */
+
+/*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+static unsigned char
+nbytes_r_length [] = {
+  42, 0, 1, 42, 2
+  };
+
+/*
+ *             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;
+{
+       struct reloc_info_generic ri;
+       register symbolS *symbolP;
+
+       /* If a machine dependent emitter is needed, call it instead. */
+       if (md_emit_relocations) {
+               (*md_emit_relocations) (fixP, segment_address_in_file);
+               return;
+       }
+
+       /* JF this is for paranoia */
+       bzero((char *)&ri,sizeof(ri));
+       for (;  fixP;  fixP = fixP->fx_next) {
+               if ((symbolP = fixP->fx_addsy) != 0) {
+                       ri.r_bsr                = fixP->fx_bsr;
+                       ri.r_disp               = fixP->fx_im_disp;
+                       ri.r_callj              = fixP->fx_callj;
+                       ri.r_length             = nbytes_r_length [fixP->fx_size];
+                       ri.r_pcrel              = fixP->fx_pcrel;
+                       ri.r_address    = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
+
+                       if (S_GET_TYPE(symbolP) == N_UNDF) {
+                               ri.r_extern     = 1;
+                               ri.r_symbolnum  = symbolP->sy_number;
+                       } else {
+                               ri.r_extern     = 0;
+                               ri.r_symbolnum  = S_GET_TYPE(symbolP);
+                       }
+
+                       /* Output the relocation information in machine-dependent form. */
+                       md_ri_to_chars(*where, &ri);
+                       *where += md_reloc_size;
+               } /* if there is an add symbol */
+       } /* for each fix */
+
+       return;
+} /* emit_relocations() */
+
+/* Aout file generation & utilities */
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+       tc_headers_hook(headers);
+
+#ifdef CROSS_ASSEMBLE
+       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);
+#ifdef EXEC_MACHINE_TYPE
+       md_number_to_chars(*where, headers->header.a_machtype, sizeof(headers->header.a_machtype));
+       *where += sizeof(headers->header.a_machtype);
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+       md_number_to_chars(*where, headers->header.a_version, sizeof(headers->header.a_version));
+       *where += sizeof(headers->header.a_version);
+#endif /* EXEC_VERSION */
+
+#else /* CROSS_ASSEMBLE */
+
+       append(where, (char *) &headers->header, sizeof(headers->header));
+#endif /* CROSS_ASSEMBLE */
+
+       return;
+} /* obj_append_header() */
+
+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 *)&(S_GET_VALUE(symbolP)), S_GET_VALUE(symbolP), sizeof(S_GET_VALUE(symbolP)));
+
+       append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
+} /* obj_symbol_to_chars() */
+
+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);
+
+       obj_symbol_to_chars(where, symbolP);
+       S_SET_NAME(symbolP,temp);
+    }
+} /* emit_symbols() */
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+       S_SET_OTHER(symbolP, 0);
+       S_SET_DESC(symbolP, 0);
+       return;
+} /* obj_symbol_new_hook() */
+
+static void obj_aout_line() {
+       /* 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() */
+
+/*
+ *                     stab()
+ *
+ * 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.
+ *
+ * .stabX directives always make a symbol table entry. It may be junk if
+ * the rest of your .stabX directive is malformed.
+ */
+static void obj_aout_stab(what)
+int what;
+{
+  register symbolS *   symbolP = 0;
+  register char *      string;
+          int saved_type = 0;
+          int length;
+          int goof;    /* TRUE if we have aborted. */
+          long longint;
+
+/*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+       goof = 0; /* JF who forgot this?? */
+       if (what == 's') {
+               string = demand_copy_C_string(& length);
+               SKIP_WHITESPACE();
+               if (* input_line_pointer == ',')
+                       input_line_pointer ++;
+               else {
+                       as_bad("I need a comma after symbol's name");
+                       goof = 1;
+               }
+       } else
+               string = "";
+
+/*
+ * Input_line_pointer->after ','.  String->symbol name.
+ */
+       if (! goof) {
+               symbolP = symbol_new(string,
+                                    SEG_UNKNOWN,
+                                    0,
+                                    (struct frag *)0);
+               switch (what) {
+               case 'd':
+                       S_SET_NAME(symbolP, NULL); /* .stabd feature. */
+                       S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
+                       symbolP->sy_frag = frag_now;
+                       break;
+
+               case 'n':
+                       symbolP->sy_frag = &zero_address_frag;
+                       break;
+
+               case 's':
+                       symbolP->sy_frag = & zero_address_frag;
+                       break;
+
+               default:
+                       BAD_CASE(what);
+                       break;
+               }
+
+               if (get_absolute_expression_and_terminator(&longint) == ',')
+                       symbolP->sy_symbol.n_type = saved_type = longint;
+               else {
+                       as_bad("I want a comma after the n_type expression");
+                       goof = 1;
+                       input_line_pointer --; /* Backup over a non-',' char. */
+               }
+       }
+
+       if (!goof) {
+               if (get_absolute_expression_and_terminator(&longint) == ',')
+                       S_SET_OTHER(symbolP, longint);
+               else {
+                       as_bad("I want a comma after the n_other expression");
+                       goof = 1;
+                       input_line_pointer--; /* Backup over a non-',' char. */
+               }
+       }
+
+       if (!goof) {
+               S_SET_DESC(symbolP, get_absolute_expression());
+               if (what == 's' || what == 'n') {
+                       if (*input_line_pointer != ',') {
+                               as_bad("I want a comma after the n_desc expression");
+                               goof = 1;
+                       } else {
+                               input_line_pointer++;
+                       }
+               }
+       }
+
+       if ((!goof) && (what=='s' || what=='n')) {
+               pseudo_set(symbolP);
+               symbolP->sy_symbol.n_type = saved_type;
+       }
+
+       if (goof)
+               ignore_rest_of_line();
+       else
+               demand_empty_rest_of_line ();
+} /* obj_aout_stab() */
+
+static void obj_aout_desc() {
+       register char *name;
+       register char c;
+       register char *p;
+       register symbolS *symbolP;
+       register int temp;
+
+       /*
+        * Frob invented at RMS' request. Set the n_desc of a symbol.
+ */
+       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();
+} /* obj_aout_desc() */
+
+void obj_read_begin_hook() {
+       return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+       symbolS *symbolP;
+       symbolS **symbolPP;
+       int symbol_number = 0;
+
+       /* JF deal with forward references first... */
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if (symbolP->sy_forward) {
+                       S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
+                                   + S_GET_VALUE(symbolP->sy_forward)
+                                   + symbolP->sy_forward->sy_frag->fr_address);
+
+                       symbolP->sy_forward=0;
+               } /* if it has a forward reference */
+       } /* walk the symbol chain */
+
+       tc_crawl_symbol_chain(headers);
+
+       symbolPP = &symbol_rootP;       /*->last symbol chain link. */
+       while ((symbolP  = *symbolPP) != NULL) {
+               if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+                       S_SET_SEGMENT(symbolP, SEG_TEXT);
+               } /* if pusing data into text */
+
+               S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+               /* 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)
+#ifdef TC_I960
+                       /* FIXME-SOON this ifdef seems highly dubious to me.  xoxorich. */
+                       || !S_IS_DEFINED(symbolP)
+                       || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+                       || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! 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)) {
+                               as_bad("Local symbol %s never defined", 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);
+
+       return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+       symbolS *symbolP;
+
+#ifdef CROSS_ASSEMBLE
+       /* 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_ASSEMBLE */
+       append (where, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count));
+#endif /* CROSS_ASSEMBLE */
+
+       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 */
+
+       return;
+} /* obj_emit_strings() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-aout.c */
diff --git a/gas/config/obj-aout.h b/gas/config/obj-aout.h
new file mode 100644 (file)
index 0000000..602d760
--- /dev/null
@@ -0,0 +1,187 @@
+/* a.out object file format
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+/* Tag to validate a.out object file format processing */
+#define OBJ_AOUT 1
+
+#include "targ-cpu.h"
+
+#ifndef                VMS
+#include "a.out.gnu.h"         /* Needed to define struct nlist. Sigh. */
+#else
+#include "a_out.h"
+#endif
+
+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 */
+
+/* SYMBOL TABLE */
+/* Symbol table entry data type */
+
+typedef struct nlist obj_symbol_type; /* Symbol table entry */
+
+/* If compiler generate leading underscores, remove them. */
+
+#ifndef STRIP_UNDERSCORE
+#define STRIP_UNDERSCORE 0
+#endif /* STRIP_UNDERSCORE */
+
+/* Symbol table macros and constants */
+
+/*
+ *  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_OTHER(s) != 0) || (S_GET_DESC(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 */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
+   nameless symbols come from .stab directives. */
+#define S_IS_LOCAL(s)          (S_GET_NAME(s) && \
+                                !S_IS_DEBUG(s) && \
+                                (S_GET_NAME(s)[0] == '\001' || \
+                                 (S_LOCAL_NAME(s) && !flagseen['L'])))
+/* 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 value of the symbol */
+#define S_GET_VALUE(s)         (((s)->sy_symbol.n_value))
+/* 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)
+
+/* Modifiers */
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v)       ((s)->sy_symbol.n_value = (unsigned long) (v))
+/* 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_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))
+
+/* File header macro and type definition */
+
+#define H_GET_FILE_SIZE(h)     (sizeof(struct exec) + \
+                                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)->string_table_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_MAGIC_NUMBER(h)          ((h)->header.a_info)
+#define H_GET_ENTRY_POINT(h)           ((h)->header.a_entry)
+#define H_GET_STRING_SIZE(h)           ((h)->string_table_size)
+#ifdef EXEC_MACHINE_TYPE
+#define H_GET_MACHINE_TYPE(h)          ((h)->header.a_machtype)
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_GET_VERSION(h)               ((h)->header.a_version)
+#endif /* EXEC_VERSION */
+
+#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) * \
+                                        sizeof(struct nlist))
+
+#define H_SET_MAGIC_NUMBER(h,v)                ((h)->header.a_info = (v))
+
+#define H_SET_ENTRY_POINT(h,v)         ((h)->header.a_entry = (v))
+#define H_SET_STRING_SIZE(h,v)         ((h)->string_table_size = (v))
+#ifdef EXEC_MACHINE_TYPE
+#define H_SET_MACHINE_TYPE(h,v)                ((h)->header.a_machtype = (v))
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_SET_VERSION(h,v)             ((h)->header.a_version = (v))
+#endif /* EXEC_VERSION */
+
+/* 
+ * Current means for getting the name of a segment.
+ * This will change for infinite-segments support (e.g. COFF).
+ */
+#define        segment_name(seg)  ( seg_name[(int)(seg)] )
+extern char *const seg_name[];
+
+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)       ;
+#define obj_pre_write_hook(a)          ;
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-aout.h */
diff --git a/gas/config/obj-bout.c b/gas/config/obj-bout.c
new file mode 100644 (file)
index 0000000..abfdaa8
--- /dev/null
@@ -0,0 +1,485 @@
+/* b.out object file format
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+#include "as.h"
+#include "obstack.h"
+
+const short /* in: segT   out: N_TYPE bits */
+seg_N_TYPE[] = {
+  N_ABS,
+  N_TEXT,
+  N_DATA,
+  N_BSS,
+  N_UNDF, /* unknown */
+  N_UNDF, /* absent */
+  N_UNDF, /* pass1 */
+  N_UNDF, /* error */
+  N_UNDF, /* bignum/flonum */
+  N_UNDF, /* difference */
+  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,
+};
+
+#ifdef __STDC__
+static void obj_bout_stab(int what);
+static void obj_bout_line(void);
+static void obj_bout_desc(void);
+#else /* __STDC__ */
+static void obj_bout_desc();
+static void obj_bout_stab();
+static void obj_bout_line();
+#endif /* __STDC__ */
+
+const pseudo_typeS obj_pseudo_table[] = {
+ /* stabs (aka a.out aka b.out directives for debug symbols) */
+       { "desc",       obj_bout_desc,          0       }, /* def */
+       { "line",       obj_bout_line,          0       }, /* source code line number */
+       { "stabd",      obj_bout_stab,          'd'     }, /* stabs */
+       { "stabn",      obj_bout_stab,          'n'     }, /* stabs */
+       { "stabs",      obj_bout_stab,          's'     }, /* stabs */
+
+ /* coff debugging directives.  Currently ignored silently */
+       { "def",        s_ignore,               0 },
+       { "dim",        s_ignore,               0 },
+       { "endef",      s_ignore,               0 },
+       { "ln",         s_ignore,               0 },
+       { "scl",        s_ignore,               0 },
+       { "size",       s_ignore,               0 },
+       { "tag",        s_ignore,               0 },
+       { "type",       s_ignore,               0 },
+       { "val",        s_ignore,               0 },
+
+ /* other stuff we don't handle */
+       { "ABORT",      s_ignore,               0 },
+       { "ident",      s_ignore,               0 },
+
+       { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+/* Relocation. */
+
+/*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+static unsigned char
+nbytes_r_length [] = {
+  42, 0, 1, 42, 2
+  };
+
+/*
+ *             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;
+{
+       struct reloc_info_generic       ri;
+       register symbolS *              symbolP;
+       
+       /* If a machine dependent emitter is needed, call it instead. */
+       if (md_emit_relocations) {
+               (*md_emit_relocations) (fixP, segment_address_in_file);
+               return;
+       }
+       
+       
+       /* JF this is for paranoia */
+       bzero((char *)&ri,sizeof(ri));
+       for (;  fixP;  fixP = fixP->fx_next) {
+               if ((symbolP = fixP->fx_addsy) != 0) {
+                       ri . r_bsr              = fixP->fx_bsr;
+                       ri . r_disp             = fixP->fx_im_disp;
+                       ri . r_callj            = fixP->fx_callj;
+                       ri . r_length           = nbytes_r_length [fixP->fx_size];
+                       ri . r_pcrel            = fixP->fx_pcrel;
+                       ri . r_address  = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file;
+                       
+                       if (S_GET_TYPE(symbolP) == N_UNDF) {
+                               ri . r_extern   = 1;
+                               ri . r_symbolnum        = symbolP->sy_number;
+                       } else {
+                               ri . r_extern   = 0;
+                               ri . r_symbolnum        = S_GET_TYPE(symbolP);
+                       }
+                       
+                       /* Output the relocation information in machine-dependent form. */
+                       md_ri_to_chars(*where, &ri);
+                       *where += md_reloc_size;
+               }
+       }
+} /* emit_relocations() */
+
+/* Aout file generation & utilities */
+
+/* Convert a lvalue to machine dependent data */
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+       /* Always leave in host byte order */
+
+       headers->header.a_talign = section_alignment[SEG_TEXT];
+
+       if (headers->header.a_talign < 2){
+               headers->header.a_talign = 2;
+       } /* force to at least 2 */
+
+       headers->header.a_dalign = section_alignment[SEG_DATA];
+       headers->header.a_balign = section_alignment[SEG_BSS];
+
+       headers->header.a_tload = 0;
+       headers->header.a_dload = md_section_align(SEG_DATA, headers->header.a_text);
+
+       append(where, (char *) &headers->header, sizeof(headers->header));
+} /* a_header_append() */
+
+void obj_symbol_to_chars(where, symbolP)
+char **where;
+symbolS *symbolP;
+{
+ /* leave in host byte order */
+       append(where, (char *)&symbolP->sy_symbol, sizeof(obj_symbol_type));
+} /* obj_symbol_to_chars() */
+
+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. */
+       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);
+
+       obj_symbol_to_chars(where, symbolP);
+       S_SET_NAME(symbolP,temp);
+    }
+} /* emit_symbols() */
+
+void obj_symbol_new_hook(symbolP)
+symbolS *symbolP;
+{
+       S_SET_OTHER(symbolP, 0);
+       S_SET_DESC(symbolP, 0);
+       return;
+} /* obj_symbol_new_hook() */
+
+static void obj_bout_line() {
+       /* 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_bout_line() */
+
+/*
+ *                     stab()
+ *
+ * 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.
+ *
+ * .stabX directives always make a symbol table entry. It may be junk if
+ * the rest of your .stabX directive is malformed.
+ */
+static void obj_bout_stab(what)
+int what;
+{
+  register symbolS *   symbolP = 0;
+  register char *      string;
+          int saved_type = 0;
+          int length;
+          int goof;    /* TRUE if we have aborted. */
+          long longint;
+
+/*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+       goof = 0; /* JF who forgot this?? */
+       if (what == 's') {
+               string = demand_copy_C_string(& length);
+               SKIP_WHITESPACE();
+               if (*input_line_pointer == ',')
+                       input_line_pointer ++;
+               else {
+                       as_bad("I need a comma after symbol's name");
+                       goof = 1;
+               }
+       } else
+               string = "";
+
+/*
+ * Input_line_pointer->after ','.  String->symbol name.
+ */
+       if (!goof) {
+               symbolP = symbol_new(string,
+                                    SEG_UNKNOWN,
+                                    0,
+                                    (struct frag *)0);
+               switch (what) {
+               case 'd':
+                       S_SET_NAME(symbolP,NULL); /* .stabd feature. */
+                       S_SET_VALUE(symbolP,obstack_next_free(&frags) -
+                                   frag_now->fr_literal);
+                       symbolP->sy_frag = frag_now;
+                       break;
+
+               case 'n':
+                       symbolP->sy_frag = &zero_address_frag;
+                       break;
+
+               case 's':
+                       symbolP->sy_frag = & zero_address_frag;
+                       break;
+
+               default:
+                       BAD_CASE(what);
+                       break;
+               }
+               if (get_absolute_expression_and_terminator(& longint) == ',')
+                       symbolP->sy_symbol.n_type = saved_type = longint;
+               else {
+                       as_bad("I want a comma after the n_type expression");
+                       goof = 1;
+                       input_line_pointer--; /* Backup over a non-',' char. */
+               }
+       }
+       if (! goof) {
+               if (get_absolute_expression_and_terminator (& longint) == ',')
+                       S_SET_OTHER(symbolP,longint);
+               else {
+                       as_bad("I want a comma after the n_other expression");
+                       goof = 1;
+                       input_line_pointer--; /* Backup over a non-',' char. */
+               }
+       }
+       if (! goof) {
+               S_SET_DESC(symbolP, get_absolute_expression ());
+               if (what == 's' || what == 'n') {
+                       if (* input_line_pointer != ',') {
+                               as_bad("I want a comma after the n_desc expression");
+                               goof = 1;
+                       } else {
+                               input_line_pointer ++;
+                       }
+               }
+       }
+       if ((! goof) && (what=='s' || what=='n')) {
+               pseudo_set(symbolP);
+               symbolP->sy_symbol.n_type = saved_type;
+       }
+       if (goof)
+               ignore_rest_of_line ();
+       else
+               demand_empty_rest_of_line ();
+} /* obj_bout_stab() */
+
+static void obj_bout_desc() {
+       register char *name;
+       register char c;
+       register char *p;
+       register symbolS *      symbolP;
+       register int temp;
+
+       /*
+        * Frob invented at RMS' request. Set the n_desc of a symbol.
+        */
+       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();
+} /* obj_bout_desc() */
+
+void obj_read_begin_hook() {
+       return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+       symbolS **symbolPP;
+       symbolS *symbolP;
+       int symbol_number = 0;
+
+       /* JF deal with forward references first... */
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if (symbolP->sy_forward) {
+                       S_SET_VALUE(symbolP, S_GET_VALUE(symbolP)
+                                   + S_GET_VALUE(symbolP->sy_forward)
+                                   + symbolP->sy_forward->sy_frag->fr_address);
+
+                       symbolP->sy_forward=0;
+               } /* if it has a forward reference */
+       } /* walk the symbol chain */
+
+       tc_crawl_symbol_chain(headers);
+
+       symbolPP = & symbol_rootP;      /*->last symbol chain link. */
+       while ((symbolP  = *symbolPP) != NULL) {
+               if (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+                       S_SET_SEGMENT(symbolP, SEG_TEXT);
+               } /* if pusing data into text */
+
+               S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+               /* 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 (1
+                   && !S_IS_REGISTER(symbolP)
+                   && (!S_GET_NAME(symbolP)
+                       || S_IS_DEBUG(symbolP)
+#ifdef TC_I960
+                       /* FIXME-SOON this ifdef seems highly dubious to me.  xoxorich. */
+                       || !S_IS_DEFINED(symbolP)
+                       || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+                       || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! 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)) {
+                               as_bad("Local symbol %s never defined", 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);
+
+       return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+       symbolS *symbolP;
+
+#ifdef CROSS_ASSEMBLE
+       /* 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_ASSEMBLE */
+       append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count));
+#endif /* CROSS_ASSEMBLE */
+
+       for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if(S_GET_NAME(symbolP))
+                   append(where, S_GET_NAME(symbolP), (unsigned long)(strlen (S_GET_NAME(symbolP)) + 1));
+       } /* walk symbol chain */
+
+       return;
+} /* obj_emit_strings() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bout.c */
diff --git a/gas/config/obj-bout.h b/gas/config/obj-bout.h
new file mode 100644 (file)
index 0000000..fc95a35
--- /dev/null
@@ -0,0 +1,312 @@
+/* b.out object file format
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA
+02139, USA. */
+
+/* $Id$ */
+
+/*
+ * This file is a modified version of 'a.out.h'.  It is to be used in all GNU
+ * tools modified to support the i80960 b.out format (or tools that operate on
+ * object files created by such tools).
+ *
+ * All i80960 development is done in a CROSS-DEVELOPMENT environment.  I.e.,
+ * object code is generated on, and executed under the direction of a symbolic
+ * debugger running on, a host system.  We do not want to be subject to the
+ * vagaries of which host it is or whether it supports COFF or a.out format, or
+ * anything else.  We DO want to:
+ *
+ *     o always generate the same format object files, regardless of host.
+ *
+ *     o have an 'a.out' header that we can modify for our own purposes
+ *       (the 80960 is typically an embedded processor and may require
+ *       enhanced linker support that the normal a.out.h header can't
+ *       accommodate).
+ *
+ * As for byte-ordering, the following rules apply:
+ *
+ *     o Text and data that is actually downloaded to the target is always
+ *       in i80960 (little-endian) order.
+ *
+ *     o All other numbers (in the header, symbols, relocation directives)
+ *       are in host byte-order:  object files CANNOT be lifted from a
+ *       little-end host and used on a big-endian (or vice versa) without
+ *       modification.
+ *
+ *     o The downloader ('comm960') takes care to generate a pseudo-header
+ *       with correct (i80960) byte-ordering before shipping text and data
+ *       off to the NINDY monitor in the target systems.  Symbols and
+ *       relocation info are never sent to the target.
+ */
+
+
+#define OBJ_BOUT 1
+
+#include "targ-cpu.h"
+
+ /* bout uses host byte order for headers */
+#ifdef CROSS_ASSEMBLE
+#undef CROSS_ASSEMBLE
+#endif /* CROSS_ASSEMBLE */
+
+ /* We want \v. */
+#define BACKSLASH_V 1
+
+#define OBJ_DEFAULT_OUTPUT_FILE_NAME   "b.out"
+
+extern const short seg_N_TYPE[];
+extern const segT  N_TYPE_seg[];
+
+#define BMAGIC 0415
+/* We don't accept the following (see N_BADMAG macro).
+ * They're just here so GNU code will compile.
+ */
+#define        OMAGIC  0407            /* old impure format */
+#define        NMAGIC  0410            /* read-only text */
+#define        ZMAGIC  0413            /* demand load format */
+
+#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE   (BMAGIC)
+#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */
+
+/* FILE HEADER
+ *     All 'lengths' are given as a number of bytes.
+ *     All 'alignments' are for relinkable files only;  an alignment of
+ *             'n' indicates the corresponding segment must begin at an
+ *             address that is a multiple of (2**n).
+ */
+struct exec {
+       /* Standard stuff */
+       unsigned long a_magic;  /* Identifies this as a b.out file      */
+       unsigned long a_text;   /* Length of text                       */
+       unsigned long a_data;   /* Length of data                       */
+       unsigned long a_bss;    /* Length of runtime uninitialized data area */
+       unsigned long a_syms;   /* Length of symbol table               */
+       unsigned long a_entry;  /* Runtime start address                */
+       unsigned long a_trsize; /* Length of text relocation info       */
+       unsigned long a_drsize; /* Length of data relocation info       */
+
+       /* Added for i960 */
+       unsigned long a_tload;  /* Text runtime load address            */
+       unsigned long a_dload;  /* Data runtime load address            */
+       unsigned char a_talign; /* Alignment of text segment            */
+       unsigned char a_dalign; /* Alignment of data segment            */
+       unsigned char a_balign; /* Alignment of bss segment             */
+       unsigned char unused;   /* (Just to make struct size a multiple of 4) */
+};
+
+#define N_BADMAG(x)    (((x).a_magic)!=BMAGIC)
+#define N_TXTOFF(x)    ( sizeof(struct exec) )
+#define N_DATOFF(x)    ( N_TXTOFF(x) + (x).a_text )
+#define N_TROFF(x)     ( N_DATOFF(x) + (x).a_data )
+#define N_DROFF(x)     ( N_TROFF(x) + (x).a_trsize )
+#define N_SYMOFF(x)    ( N_DROFF(x) + (x).a_drsize )
+#define N_STROFF(x)    ( N_SYMOFF(x) + (x).a_syms )
+
+/* A single entry in the symbol table
+ */
+struct nlist {
+       union {
+               char    *n_name;
+               struct nlist *n_next;
+               long    n_strx;         /* Index into string table      */
+       } n_un;
+       unsigned char n_type;   /* See below                            */
+       char    n_other;        /* Used in i80960 support -- see below  */
+       short   n_desc;
+       unsigned long n_value;
+};
+
+typedef struct nlist obj_symbol_type;
+
+/* Legal values of n_type
+ */
+#define N_UNDF 0       /* Undefined symbol     */
+#define N_ABS  2       /* Absolute symbol      */
+#define N_TEXT 4       /* Text symbol          */
+#define N_DATA 6       /* Data symbol          */
+#define N_BSS  8       /* BSS symbol           */
+#define N_FN   31      /* Filename symbol      */
+
+#define N_EXT  1       /* External symbol (OR'd in with one of above)  */
+#define N_TYPE 036     /* Mask for all the type bits                   */
+#define N_STAB 0340    /* Mask for all bits used for SDB entries       */
+
+#ifndef CUSTOM_RELOC_FORMAT
+struct relocation_info {
+       int      r_address;     /* File address of item to be relocated */
+       unsigned
+               r_index:24,/* Index of symbol on which relocation is based*/
+               r_pcrel:1,      /* 1 => relocate PC-relative; else absolute
+                                *      On i960, pc-relative implies 24-bit
+                                *      address, absolute implies 32-bit.
+                                */
+               r_length:2,     /* Number of bytes to relocate:
+                                *      0 => 1 byte
+                                *      1 => 2 bytes
+                                *      2 => 4 bytes -- only value used for i960
+                                */
+               r_extern:1,
+               r_bsr:1,        /* Something for the GNU NS32K assembler */
+               r_disp:1,       /* Something for the GNU NS32K assembler */
+               r_callj:1,      /* 1 if relocation target is an i960 'callj' */
+               nuthin:1;       /* Unused                               */
+};
+#endif /* CUSTOM_RELOC_FORMAT */
+
+/* If compiler generate leading underscores, remove them. */
+
+#ifndef STRIP_UNDERSCORE
+#define STRIP_UNDERSCORE 0
+#endif /* STRIP_UNDERSCORE */
+
+/*
+ *  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.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_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 */
+/* A symbol name whose name begin with ^A is a gas internal pseudo symbol
+   nameless symbols come from .stab directives. */
+#define S_IS_LOCAL(s)          (S_GET_NAME(s) && \
+                                !S_IS_DEBUG(s) && \
+                                (S_GET_NAME(s)[0] == '\001' || \
+                                 (S_LOCAL_NAME(s) && !flagseen['L'])))
+/* 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) == NULL)
+
+/* Accessors */
+/* The value of the symbol */
+#define S_GET_VALUE(s)         ((long) ((s)->sy_symbol.n_value))
+/* 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)
+
+/* Modifiers */
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v)       ((s)->sy_symbol.n_value = (unsigned long) (v))
+/* 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_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))
+
+/* File header macro and type definition */
+
+#define H_GET_FILE_SIZE(h)     (sizeof(struct exec) + \
+                                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)->string_table_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_MAGIC_NUMBER(h)          ((h)->header.a_info)
+#define H_GET_ENTRY_POINT(h)           ((h)->header.a_entry)
+#define H_GET_STRING_SIZE(h)           ((h)->string_table_size)
+#ifdef EXEC_MACHINE_TYPE
+#define H_GET_MACHINE_TYPE(h)          ((h)->header.a_machtype)
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_GET_VERSION(h)               ((h)->header.a_version)
+#endif /* EXEC_VERSION */
+
+#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) * \
+                                        sizeof(struct nlist))
+
+#define H_SET_MAGIC_NUMBER(h,v)                ((h)->header.a_magic = (v))
+
+#define H_SET_ENTRY_POINT(h,v)         ((h)->header.a_entry = (v))
+#define H_SET_STRING_SIZE(h,v)         ((h)->string_table_size = (v))
+#ifdef EXEC_MACHINE_TYPE
+#define H_SET_MACHINE_TYPE(h,v)                ((h)->header.a_machtype = (v))
+#endif /* EXEC_MACHINE_TYPE */
+#ifdef EXEC_VERSION
+#define H_SET_VERSION(h,v)             ((h)->header.a_version = (v))
+#endif /* EXEC_VERSION */
+
+/* 
+ * Current means for getting the name of a segment.
+ * This will change for infinite-segments support (e.g. COFF).
+ */
+#define        segment_name(seg)  ( seg_name[(int)(seg)] )
+extern char *const seg_name[];
+
+typedef struct {
+    struct exec        header;                 /* a.out header */
+    long       string_table_size;      /* names + '\0' + sizeof(int) */
+} object_headers;
+
+/* unused hooks. */
+#define OBJ_EMIT_LINENO(a, b, c)       ;
+#define obj_pre_write_hook(a)          ;
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-bout.h */
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
new file mode 100644 (file)
index 0000000..ef48334
--- /dev/null
@@ -0,0 +1,1772 @@
+/* coff object file format
+   Copyright (C) 1989, 1990, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#include "as.h"
+
+#include "obstack.h"
+
+lineno* lineno_rootP;
+
+const short seg_N_TYPE[] = { /* in: segT   out: N_TYPE bits */
+       C_ABS_SECTION,
+       C_TEXT_SECTION,
+       C_DATA_SECTION,
+       C_BSS_SECTION,
+       C_UNDEF_SECTION,                /* SEG_UNKNOWN */
+       C_UNDEF_SECTION,                /* SEG_ABSENT */
+       C_UNDEF_SECTION,                /* SEG_PASS1 */
+       C_UNDEF_SECTION,                /* SEG_GOOF */
+       C_UNDEF_SECTION,                /* SEG_BIG */
+       C_UNDEF_SECTION,                /* SEG_DIFFERENCE */
+       C_DEBUG_SECTION,                /* SEG_DEBUG */
+       C_NTV_SECTION,          /* SEG_NTV */
+       C_PTV_SECTION,          /* SEG_PTV */
+};
+
+
+/* Add 4 to the real value to get the index and compensate the negatives */
+
+const segT N_TYPE_seg [32] =
+{
+  SEG_PTV,                     /* C_PTV_SECTION        == -4 */
+  SEG_NTV,                     /* C_NTV_SECTION        == -3 */
+  SEG_DEBUG,                   /* C_DEBUG_SECTION      == -2 */
+  SEG_ABSOLUTE,                        /* C_ABS_SECTION        == -1 */
+  SEG_UNKNOWN,                 /* C_UNDEF_SECTION      == 0 */
+  SEG_TEXT,                    /* C_TEXT_SECTION       == 1 */
+  SEG_DATA,                    /* C_DATA_SECTION       == 2 */
+  SEG_BSS,                     /* C_BSS_SECTION        == 3 */
+  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_GOOF,SEG_GOOF,SEG_GOOF
+};
+
+#ifdef __STDC__
+
+char *s_get_name(symbolS *s);
+static symbolS *tag_find_or_make(char *name);
+static symbolS* tag_find(char *name);
+static void c_section_header_append(char **where, SCNHDR *header);
+static void obj_coff_def(int what);
+static void obj_coff_dim(void);
+static void obj_coff_endef(void);
+static void obj_coff_line(void);
+static void obj_coff_ln(void);
+static void obj_coff_scl(void);
+static void obj_coff_size(void);
+static void obj_coff_stab(int what);
+static void obj_coff_tag(void);
+static void obj_coff_type(void);
+static void obj_coff_val(void);
+static void tag_init(void);
+static void tag_insert(char *name, symbolS *symbolP);
+
+#else
+
+char *s_get_name();
+static symbolS *tag_find();
+static symbolS *tag_find_or_make();
+static void c_section_header_append();
+static void obj_coff_def();
+static void obj_coff_dim();
+static void obj_coff_endef();
+static void obj_coff_line();
+static void obj_coff_ln();
+static void obj_coff_scl();
+static void obj_coff_size();
+static void obj_coff_stab();
+static void obj_coff_tag();
+static void obj_coff_type();
+static void obj_coff_val();
+static void tag_init();
+static void tag_insert();
+
+#endif /* __STDC__ */
+
+static struct hash_control *tag_hash;
+static symbolS *def_symbol_in_progress = NULL;
+
+const pseudo_typeS obj_pseudo_table[] = {
+#ifndef IGNORE_DEBUG
+       { "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       },
+       { "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       },
+#else
+       { "def",        s_ignore,               0       },
+       { "dim",        s_ignore,               0       },
+       { "endef",      s_ignore,               0       },
+       { "line",       s_ignore,               0       },
+       { "ln",         s_ignore,               0       },
+       { "scl",        s_ignore,               0       },
+       { "size",       s_ignore,               0       },
+       { "tag",        s_ignore,               0       },
+       { "type",       s_ignore,               0       },
+       { "val",        s_ignore,               0       },
+#endif /* ignore debug */
+
+ /* stabs aka a.out aka b.out directives for debug symbols.
+    Currently ignored silently.  Except for .line which we
+    guess at from context. */
+       { "desc",       s_ignore,               0       }, /* def */
+/*     { "line",       s_ignore,               0       }, */ /* source code line number */
+       { "stabd",      obj_coff_stab,          'd'     }, /* stabs */
+       { "stabn",      obj_coff_stab,          'n'     }, /* stabs */
+       { "stabs",      obj_coff_stab,          's'     }, /* stabs */
+
+ /* other stuff */
+       { "ABORT",      s_abort,                0 },
+       { "ident",      s_ignore,               0 },
+
+       { NULL} /* end sentinel */
+}; /* obj_pseudo_table */
+
+
+ /* obj dependant output values */
+static SCNHDR bss_section_header;
+static SCNHDR data_section_header;
+static SCNHDR text_section_header;
+
+/* 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;
+{
+       RELOC ri;
+       symbolS *symbolP;
+
+       bzero((char *)&ri,sizeof(ri));
+       for (;  fixP;  fixP = fixP->fx_next) {
+               if (symbolP = fixP->fx_addsy) {
+#if defined(TC_M68K)
+                       ri.r_type = (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_RELLONG));
+#elif defined(TC_I386)
+                       /* FIXME-SOON R_OFF8 & R_DIR16 are a vague guess, completly untested. */
+                       ri.r_type = (fixP->fx_pcrel ?
+                                    (fixP->fx_size == 1 ? R_PCRBYTE :
+                                     fixP->fx_size == 2 ? R_PCRWORD :
+                                     R_PCRLONG):
+                                    (fixP->fx_size == 1 ? R_OFF8 :
+                                     fixP->fx_size == 2 ? R_DIR16 :
+                                     R_DIR32));
+#elif defined(TC_I960)
+                       ri.r_type = (fixP->fx_pcrel
+                                    ? R_IPRMED
+                                    : R_RELLONG);
+#elif defined(TC_A29K)
+                       ri.r_type = tc_coff_fix2rtype(fixP);
+#else
+                       you lose
+#endif /* TC_M68K || TC_I386 */
+                           ri.r_vaddr = fixP->fx_frag->fr_address + fixP->fx_where;
+                       /* If symbol associated to relocation entry is a bss symbol
+                          or undefined symbol just remember the index of the symbol.
+                          Otherwise store the index of the symbol describing the
+                          section the symbol belong to. This heuristic speeds up ld.
+                          */
+                       /* Local symbols can generate relocation information. In case
+                          of structure return for instance. But they have no symbol
+                          number because they won't be emitted in the final object.
+                          In the case where they are in the BSS section, this leads
+                          to an incorrect r_symndx.
+                          Under bsd the loader do not care if the symbol reference is
+                          incorrect. But the SYS V ld complains about this. To avoid
+                          this we associate the symbol to the associated section,
+                          *even* if it is the BSS section. */
+                       /* If someone can tell me why the other symbols of the bss
+                          section are not associated with the .bss section entry,
+                          I'd be gratefull. I guess that it has to do with the special
+                          nature of the .bss section. Or maybe this is because the
+                          bss symbols are declared in the common section and can
+                          be resized later. Can it break code some where ? */
+                       ri.r_symndx = (S_GET_SEGMENT(symbolP) == SEG_TEXT
+                                      ? dot_text_symbol->sy_number
+                                      : (S_GET_SEGMENT(symbolP) == SEG_DATA
+                                         ? dot_data_symbol->sy_number
+                                         : ((SF_GET_LOCAL(symbolP)
+                                             ? dot_bss_symbol->sy_number
+                                             : symbolP->sy_number)))); /* bss or undefined */
+
+                       /* md_ri_to_chars((char *) &ri, ri); */  /* Last step : write md f */
+                       append(where, (char *) &ri, sizeof(ri));
+
+#ifdef TC_I960
+                       if (fixP->fx_callj) {
+                               ri.r_type = R_OPTCALL;
+                               append(where, (char *) &ri, sizeof(ri));
+                       } /* if it's a callj, do it again for the opcode */
+#endif /* TC_I960 */
+
+               } /* if there's a symbol */
+       } /* for each fixP */
+
+       return;
+} /* obj_emit_relocations() */
+
+/* Coff file generation & utilities */
+
+void obj_header_append(where, headers)
+char **where;
+object_headers *headers;
+{
+       tc_headers_hook(headers);
+
+#ifdef CROSS_ASSEMBLE
+       /* Eventually swap bytes for cross compilation for file header */
+       md_number_to_chars(*where, headers->filehdr.f_magic, sizeof(headers->filehdr.f_magic));
+       *where += sizeof(headers->filehdr.f_magic);
+       md_number_to_chars(*where, headers->filehdr.f_nscns, sizeof(headers->filehdr.f_nscns));
+       *where += sizeof(headers->filehdr.f_nscns);
+       md_number_to_chars(*where, headers->filehdr.f_timdat, sizeof(headers->filehdr.f_timdat));
+       *where += sizeof(headers->filehdr.f_timdat);
+       md_number_to_chars(*where, headers->filehdr.f_symptr, sizeof(headers->filehdr.f_symptr));
+       *where += sizeof(headers->filehdr.f_symptr);
+       md_number_to_chars(*where, headers->filehdr.f_nsyms, sizeof(headers->filehdr.f_nsyms));
+       *where += sizeof(headers->filehdr.f_nsyms);
+       md_number_to_chars(*where, headers->filehdr.f_opthdr, sizeof(headers->filehdr.f_opthdr));
+       *where += sizeof(headers->filehdr.f_opthdr);
+       md_number_to_chars(*where, headers->filehdr.f_flags, sizeof(headers->filehdr.f_flags));
+       *where += sizeof(headers->filehdr.f_flags);
+
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+       /* Eventually swap bytes for cross compilation for a.out header */
+       md_number_to_chars(*where, headers->aouthdr.magic, sizeof(headers->aouthdr.magic));
+       *where += sizeof(headers->aouthdr.magic);
+       md_number_to_chars(*where, headers->aouthdr.vstamp, sizeof(headers->aouthdr.vstamp));
+       *where += sizeof(headers->aouthdr.vstamp);
+       md_number_to_chars(*where, headers->aouthdr.tsize, sizeof(headers->aouthdr.tsize));
+       *where += sizeof(headers->aouthdr.tsize);
+       md_number_to_chars(*where, headers->aouthdr.dsize, sizeof(headers->aouthdr.dsize));
+       *where += sizeof(headers->aouthdr.dsize);
+       md_number_to_chars(*where, headers->aouthdr.bsize, sizeof(headers->aouthdr.bsize));
+       *where += sizeof(headers->aouthdr.bsize);
+       md_number_to_chars(*where, headers->aouthdr.entry, sizeof(headers->aouthdr.entry));
+       *where += sizeof(headers->aouthdr.entry);
+       md_number_to_chars(*where, headers->aouthdr.text_start, sizeof(headers->aouthdr.text_start));
+       *where += sizeof(headers->aouthdr.text_start);
+       md_number_to_chars(*where, headers->aouthdr.data_start, sizeof(headers->aouthdr.data_start));
+       *where += sizeof(headers->aouthdr.data_start);
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#else /* CROSS_ASSEMBLE */
+
+       append(where, (char *) &headers->filehdr, sizeof(headers->filehdr));
+#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER
+       append(where, (char *) &headers->aouthdr, sizeof(headers->aouthdr));
+#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */
+
+#endif /* CROSS_ASSEMBLE */
+
+       /* Output the section headers */
+       c_section_header_append(where, &text_section_header);
+       c_section_header_append(where, &data_section_header);
+       c_section_header_append(where, &bss_section_header);
+
+       return;
+} /* obj_header_append() */
+
+void obj_symbol_to_chars(where, symbolP)
+char **where;
+symbolS *symbolP;
+{
+       SYMENT *syment = &symbolP->sy_symbol.ost_entry;
+       int i;
+       char numaux = syment->n_numaux;
+       unsigned short type = S_GET_DATA_TYPE(symbolP);
+
+#ifdef CROSS_ASSEMBLE
+       md_number_to_chars(*where, syment->n_value, sizeof(syment->n_value));
+       *where += sizeof(syment->n_value);
+       md_number_to_chars(*where, syment->n_scnum, sizeof(syment->n_scnum));
+       *where += sizeof(syment->n_scnum);
+       md_number_to_chars(*where, syment->n_type, sizeof(syment->n_type));
+       *where += sizeof(syment->n_type);
+       md_number_to_chars(*where, syment->n_sclass, sizeof(syment->n_sclass));
+       *where += sizeof(syment->n_sclass);
+       md_number_to_chars(*where, syment->n_numaux, sizeof(syment->n_numaux));
+       *where += sizeof(syment->n_numaux);
+#else /* CROSS_ASSEMBLE */
+       append(where, (char *) syment, sizeof(*syment));
+#endif /* CROSS_ASSEMBLE */
+
+       /* Should do the following : if (.file entry) MD(..)... else if (static entry) MD(..) */
+       if (numaux > OBJ_COFF_MAX_AUXENTRIES) {
+               as_bad("Internal error? too many auxents for symbol");
+       } /* too many auxents */
+
+       for (i = 0; i < numaux; ++i) {
+#ifdef CROSS_ASSEMBLE
+#if 0 /* This code has never been tested */
+               /* The most common case, x_sym entry. */
+               if ((SF_GET(symbolP) & (SF_FILE | SF_STATICS)) == 0) {
+                       md_number_to_chars(*where, auxP->x_sym.x_tagndx, sizeof(auxP->x_sym.x_tagndx));
+                       *where += sizeof(auxP->x_sym.x_tagndx);
+                       if (ISFCN(type)) {
+                               md_number_to_chars(*where, auxP->x_sym.x_misc.x_fsize, sizeof(auxP->x_sym.x_misc.x_fsize));
+                               *where += sizeof(auxP->x_sym.x_misc.x_fsize);
+                       } else {
+                               md_number_to_chars(*where, auxP->x_sym.x_misc.x_lnno, sizeof(auxP->x_sym.x_misc.x_lnno));
+                               *where += sizeof(auxP->x_sym.x_misc.x_lnno);
+                               md_number_to_chars(*where, auxP->x_sym.x_misc.x_size, sizeof(auxP->x_sym.x_misc.x_size));
+                               *where += sizeof(auxP->x_sym.x_misc.x_size);
+                       }
+                       if (ISARY(type)) {
+                               register int index;
+                               for (index = 0; index < DIMNUM; index++)
+                                   md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_ary.x_dimen[index], sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index]));
+                               *where += sizeof(auxP->x_sym.x_fcnary.x_ary.x_dimen[index]);
+                       } else {
+                               md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr));
+                               *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_lnnoptr);
+                               md_number_to_chars(*where, auxP->x_sym.x_fcnary.x_fcn.x_endndx, sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx));
+                               *where += sizeof(auxP->x_sym.x_fcnary.x_fcn.x_endndx);
+                       }
+                       md_number_to_chars(*where, auxP->x_sym.x_tvndx, sizeof(auxP->x_sym.x_tvndx));
+                       *where += sizeof(auxP->x_sym.x_tvndx);
+               } else if (SF_GET_FILE(symbolP)) {      /* .file */
+                       ;
+               } else if (SF_GET_STATICS(symbolP)) { /* .text, .data, .bss symbols */
+                       md_number_to_chars(*where, auxP->x_scn.x_scnlen, sizeof(auxP->x_scn.x_scnlen));
+                       *where += sizeof(auxP->x_scn.x_scnlen);
+                       md_number_to_chars(*where, auxP->x_scn.x_nreloc, sizeof(auxP->x_scn.x_nreloc));
+                       *where += sizeof(auxP->x_scn.x_nreloc);
+                       md_number_to_chars(*where, auxP->x_scn.x_nlinno, sizeof(auxP->x_scn.x_nlinno));
+                       *where += sizeof(auxP->x_scn.x_nlinno);
+               }
+#endif /* 0 */
+#else /* CROSS_ASSEMBLE */
+               append(where, (char *) &symbolP->sy_symbol.ost_auxent[i], sizeof(symbolP->sy_symbol.ost_auxent[i]));
+#endif /* CROSS_ASSEMBLE */
+
+       }; /* for each aux in use */
+
+       return;
+} /* obj_symbol_to_chars() */
+
+static void c_section_header_append(where, header)
+char **where;
+SCNHDR *header;
+{
+#ifdef CROSS_ASSEMBLE
+    md_number_to_chars(*where, header->s_paddr, sizeof(header->s_paddr));
+    *where += sizeof(header->s_paddr);
+
+    md_number_to_chars(*where, header->s_vaddr, sizeof(header->s_vaddr));
+    *where += sizeof(header->s_vaddr);
+
+    md_number_to_chars(*where, header->s_size, sizeof(header->s_size));
+    *where += sizeof(header->s_size);
+
+    md_number_to_chars(*where, header->s_scnptr, sizeof(header->s_scnptr));
+    *where += sizeof(header->s_scnptr);
+
+    md_number_to_chars(*where, header->s_relptr, sizeof(header->s_relptr));
+    *where += sizeof(header->s_relptr);
+
+    md_number_to_chars(*where, header->s_lnnoptr, sizeof(header->s_lnnoptr));
+    *where += sizeof(header->s_lnnoptr);
+
+    md_number_to_chars(*where, header->s_nreloc, sizeof(header->s_nreloc));
+    *where += sizeof(header->s_nreloc);
+
+    md_number_to_chars(*where, header->s_nlnno, sizeof(header->s_nlnno));
+    *where += sizeof(header->s_nlnno);
+
+    md_number_to_chars(*where, header->s_flags, sizeof(header->s_flags));
+    *where += sizeof(header->s_flags);
+
+#else /* CROSS_ASSEMBLE */
+
+    append(where, (char *) header, sizeof(*header));
+
+#endif /* CROSS_ASSEMBLE */
+
+    return;
+} /* c_section_header_append() */
+
+
+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;
+
+           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 {
+                   bzero(symbolP->sy_symbol.ost_entry.n_name, SYMNMLEN);
+                   strncpy(symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN);
+           }
+           obj_symbol_to_chars(where, symbolP);
+           S_SET_NAME(symbolP,temp);
+    }
+} /* obj_emit_symbols() */
+
+/* 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)) {
+               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], 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 symbolS *previous_file_symbol = NULL;
+
+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);
+    SA_SET_FILE_FNAME(symbolP, filename);
+    SF_SET_DEBUG(symbolP);
+    S_SET_VALUE(symbolP, (long) previous_file_symbol);
+
+    previous_file_symbol = symbolP;
+
+    /* Make sure that the symbol is first on the symbol chain */
+    if (symbol_rootP != symbolP) {
+           if (symbolP == symbol_lastP) {
+                   symbol_lastP = symbol_lastP->sy_previous;
+           } /* if it was the last thing on the list */
+
+           symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+           symbol_insert(symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
+           symbol_rootP = symbolP;
+    } /* if not first on the list */
+
+} /* c_dot_file_symbol() */
+/*
+ * Build a 'section static' symbol.
+ */
+
+char *c_section_symbol(name, value, length, nreloc, nlnno)
+char *name;
+long value;
+long length;
+unsigned short nreloc;
+unsigned short nlnno;
+{
+    symbolS *symbolP;
+
+    symbolP = symbol_new(name,
+                        (name[1] == 't'
+                         ? SEG_TEXT
+                         : (name[1] == 'd'
+                            ? SEG_DATA
+                            : SEG_BSS)),
+                        value,
+                        &zero_address_frag);
+
+    S_SET_STORAGE_CLASS(symbolP, C_STAT);
+    S_SET_NUMBER_AUXILIARY(symbolP, 1);
+
+    SA_SET_SCN_SCNLEN(symbolP, length);
+    SA_SET_SCN_NRELOC(symbolP, nreloc);
+    SA_SET_SCN_NLINNO(symbolP, nlnno);
+
+    SF_SET_STATICS(symbolP);
+
+    return (char*)symbolP;
+} /* c_section_symbol() */
+
+void c_section_header(header,
+                     name,
+                     core_address,
+                     size,
+                     data_ptr,
+                     reloc_ptr,
+                     lineno_ptr,
+                     reloc_number,
+                     lineno_number,
+                     alignment)
+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;
+{
+       strncpy(header->s_name, name, 8);
+       header->s_paddr = header->s_vaddr = core_address;
+       header->s_scnptr = ((header->s_size = size) != 0) ? data_ptr : 0;
+       header->s_relptr = reloc_ptr;
+       header->s_lnnoptr = lineno_ptr;
+       header->s_nreloc = reloc_number;
+       header->s_nlnno = lineno_number;
+
+#ifdef OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT
+#ifdef OBJ_COFF_BROKEN_ALIGNMENT
+       header->s_align = ((name[1] == 'b' || (size > 0)) ? 16 : 0);
+#else
+       header->s_align = ((alignment == 0)
+                          ? 0
+                          : (1 << alignment));
+#endif /* OBJ_COFF_BROKEN_ALIGNMENT */
+#endif /* OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT */
+
+       header->s_flags = STYP_REG | (name[1] == 't'
+                                     ? STYP_TEXT
+                                     : (name[1] == 'd'
+                                        ? STYP_DATA
+                                        : (name[1] == 'b'
+                                           ? STYP_BSS
+                                           : STYP_INFO)));
+       return;
+} /* c_section_header() */
+
+/* Line number handling */
+
+int function_lineoff = -1;     /* Offset in line#s where the last function
+                                  started (the odd entry for line #0) */
+int text_lineno_number = 0;
+int our_lineno_number = 0;     /* we use this to build pointers from .bf's
+                                  into the linetable.  It should match
+                                  exactly the values that are later
+                                  assigned in text_lineno_number by
+                                  write.c. */
+lineno* lineno_lastP = (lineno*)0;
+
+int
+c_line_new(paddr, line_number, frag)
+long paddr;
+unsigned short line_number;
+fragS* frag;
+{
+    lineno* new_line = (lineno*)xmalloc(sizeof(lineno));
+
+    new_line->line.l_addr.l_paddr = paddr;
+    new_line->line.l_lnno = line_number;
+    new_line->frag = (char*)frag;
+    new_line->next = (lineno*)0;
+
+    if (lineno_rootP == (lineno*)0)
+       lineno_rootP = new_line;
+    else
+       lineno_lastP->next = new_line;
+    lineno_lastP = new_line;
+    return LINESZ * our_lineno_number++;
+}
+
+void obj_emit_lineno(where, line, file_start)
+char **where;
+lineno *line;
+char *file_start;
+{
+       LINENO *line_entry;
+
+       for (; line; line = line->next) {
+               line_entry = &line->line;
+
+ /* FIXME-SOMEDAY Resolving the sy_number of function linno's used to be done in
+    write_object_file() but their symbols need a fileptr to the lnno, so
+    I moved this resolution check here.  xoxorich. */
+
+               if (line_entry->l_lnno == 0) {
+                       /* There is a good chance that the symbol pointed to
+                          is not the one that will be emitted and that the
+                          sy_number is not accurate. */
+/*                     char *name; */
+                       symbolS *symbolP;
+
+                       symbolP = (symbolS *) line_entry->l_addr.l_symndx;
+
+                       line_entry->l_addr.l_symndx = symbolP->sy_number;
+                       symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr = *where - file_start;
+
+               } /* if this is a function linno */
+
+               /* No matter which member of the union we process, they are
+                  both long. */
+#ifdef CROSS_ASSEMBLE
+               md_number_to_chars(*where, line_entry->l_addr.l_paddr, sizeof(line_entry->l_addr.l_paddr));
+               *where += sizeof(line_entry->l_addr.l_paddr);
+
+               md_number_to_chars(*where, line_entry->l_lnno, sizeof(line_entry->l_lnno));
+               *where += sizeof(line_entry->l_lnno);
+#else /* CROSS_ASSEMBLE */
+               append(where, (char *) line_entry, LINESZ);
+#endif /* CROSS_ASSEMBLE */
+
+       } /* for each line number */
+
+       return ;
+} /* obj_emit_lineno() */
+
+void 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 */
+       bzero((char*)&symbolP->sy_symbol.ost_auxent[0], AUXESZ);
+
+#if STRIP_UNDERSCORE
+       /* Remove leading underscore at the beginning of the symbol.
+        * This is to be compatible with the standard librairies.
+        */
+       if (*S_GET_NAME(symbolP) == '_') {
+               underscore = 1;
+               S_SET_NAME(symbolP, S_GET_NAME(symbolP) + 1);
+       } /* strip underscore */
+#endif /* STRIP_UNDERSCORE */
+
+       if (S_IS_STRING(symbolP))
+           SF_SET_STRING(symbolP);
+       if (!underscore && S_IS_LOCAL(symbolP))
+           SF_SET_LOCAL(symbolP);
+
+       return;
+} /* obj_symbol_new_hook() */
+
+ /* stack stuff */
+stack* stack_init(chunk_size, element_size)
+unsigned long chunk_size;
+unsigned long element_size;
+{
+       stack* st;
+
+       if ((st = (stack*)malloc(sizeof(stack))) == (stack*)0)
+           return (stack*)0;
+       if ((st->data = malloc(chunk_size)) == (char*)0) {
+               free(st);
+               return (stack*)0;
+       }
+       st->pointer = 0;
+       st->size = chunk_size;
+       st->chunk_size = chunk_size;
+       st->element_size = element_size;
+       return st;
+} /* stack_init() */
+
+void stack_delete(st)
+stack* st;
+{
+    free(st->data);
+    free(st);
+}
+
+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;
+} /* stack_push() */
+
+char* stack_pop(st)
+stack* st;
+{
+    if ((st->pointer -= st->element_size) < 0) {
+       st->pointer = 0;
+       return (char*)0;
+    }
+    return st->data + st->pointer;
+}
+
+char* stack_top(st)
+stack* st;
+{
+    return st->data + st->pointer - st->element_size;
+}
+
+
+/*
+ * Handle .ln directives.
+ */
+
+static void obj_coff_ln() {
+       if (def_symbol_in_progress != NULL) {
+               as_warn(".ln pseudo-op inside .def/.endef: ignored.");
+               demand_empty_rest_of_line();
+               return;
+       } /* wrong context */
+
+       c_line_new(obstack_next_free(&frags) - frag_now->fr_literal,
+                  get_absolute_expression(),
+                  frag_now);
+
+       demand_empty_rest_of_line();
+       return;
+} /* obj_coff_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;
+    /*$char*   directiveP;$ */         /* Name of the pseudo opcode */
+    /*$char directive[MAX_DIRECTIVE];$ */ /* Backup of the directive */
+    /*$char end = 0;$ */ /* If 1, stop parsing */
+
+    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(&notes, sizeof(*def_symbol_in_progress));
+    bzero(def_symbol_in_progress, 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);
+
+    /* Initialize the new symbol */
+#if 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 = ~0;
+    def_symbol_in_progress->sy_number = ~0;
+    def_symbol_in_progress->sy_frag = &zero_address_frag;
+
+    if (S_IS_STRING(def_symbol_in_progress)) {
+       SF_SET_STRING(def_symbol_in_progress);
+    } /* "long" name */
+
+    *input_line_pointer = name_end;
+
+    demand_empty_rest_of_line();
+    return;
+} /* obj_coff_def() */
+
+unsigned int dim_index;
+static void obj_coff_endef() {
+       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, 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_TEXT);
+
+               if (def_symbol_in_progress->sy_symbol.ost_entry.n_name[1] == 'b') { /* .bf */
+                       if (function_lineoff < 0) {
+                               fprintf(stderr, "`.bf' symbol without preceding function\n");
+                       } /* missing function symbol */
+                       SA_GET_SYM_LNNOPTR(def_symbol_in_progress) = function_lineoff;
+                       SF_SET_PROCESS(def_symbol_in_progress); /* Will need relocating */
+                       function_lineoff = -1;
+               }
+               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, SEG_ABSOLUTE);
+               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
+           || (S_GET_SEGMENT(def_symbol_in_progress) == SEG_DEBUG
+               && !SF_GET_TAG(def_symbol_in_progress))
+           || S_GET_SEGMENT(def_symbol_in_progress) == SEG_ABSOLUTE
+           || (symbolP = symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP)) == NULL) {
+
+               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)) {
+                       /* For functions, and tags, 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)
+           && symbol_find_base(S_GET_NAME(def_symbol_in_progress), DO_NOT_STRIP) == NULL) {
+               tag_insert(S_GET_NAME(def_symbol_in_progress), def_symbol_in_progress);
+       } /* If symbol is a {structure,union} tag, associate symbol to its name. */
+
+       if (SF_GET_FUNCTION(def_symbol_in_progress)) {
+               know(sizeof(def_symbol_in_progress) <= sizeof(long));
+               function_lineoff = c_line_new((long) def_symbol_in_progress, 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();
+       return;
+} /* obj_coff_endef() */
+#if 0
+This code expects all the dims to be after one another, and that is not true
+for gcc960
+sac@cygnus.com
+static void obj_coff_dim() {
+       register 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 ';':
+                       dim_index = DIMNUM;
+                       break;
+               } /* switch on following character */
+       } /* for each dimension */
+
+       demand_empty_rest_of_line();
+       return;
+} /* obj_coff_dim() */
+#else
+
+static void 
+obj_coff_dim() 
+{
+    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);
+
+    /*  Grab as many dims as we can fit, until ; or full */
+    while (dim_index < DIMNUM) 
+       {
+           SKIP_WHITESPACES();
+           SA_SET_SYM_DIMEN(def_symbol_in_progress, dim_index, get_absolute_expression());
+           dim_index++;
+           if (*input_line_pointer == ';') break;
+           if (*input_line_pointer != ',') {
+               as_warn("badly formed .dim directive ignored");
+               break;
+           }
+           input_line_pointer++;
+       }
+    demand_empty_rest_of_line();
+    return;
+} /* obj_coff_dim() */
+#endif
+
+static void obj_coff_line() {
+       if (def_symbol_in_progress == NULL) {
+               obj_coff_ln();
+               return;
+       } /* if it looks like a stabs style line */
+
+       S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+       SA_SET_SYM_LNNO(def_symbol_in_progress, get_absolute_expression());
+
+       demand_empty_rest_of_line();
+       return;
+} /* obj_coff_line() */
+
+static void obj_coff_size() {
+       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();
+       return;
+} /* obj_coff_size() */
+
+static void obj_coff_scl() {
+       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();
+       return;
+} /* obj_coff_scl() */
+
+static void obj_coff_tag() {
+       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;
+       } /* if not inside .def/.endef */
+
+       S_SET_NUMBER_AUXILIARY(def_symbol_in_progress, 1);
+       symbol_name = input_line_pointer;
+       name_end = get_symbol_end();
+
+       /* 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();
+       return;
+} /* obj_coff_tag() */
+
+static void obj_coff_type() {
+       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();
+       return;
+} /* obj_coff_type() */
+
+static void obj_coff_val() {
+       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();
+
+               if (!strcmp(symbol_name, ".")) {
+                       def_symbol_in_progress->sy_frag = frag_now;
+                       S_SET_VALUE(def_symbol_in_progress, obstack_next_free(&frags) - frag_now->fr_literal);
+                       /* 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_forward = symbol_find_or_make(symbol_name);
+
+                       /* If the segment is undefined when the forward
+                          reference is solved, 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();
+       return;
+} /* obj_coff_val() */
+
+/*
+ * Maintain a list of the tagnames of the structres.
+ */
+
+static void tag_init() {
+    tag_hash = hash_new();
+    return ;
+} /* tag_init() */
+
+static void tag_insert(name, symbolP)
+char *name;
+symbolS *symbolP;
+{
+       register 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);
+       }
+       return ;
+} /* tag_insert() */
+
+static symbolS *tag_find_or_make(name)
+char *name;
+{
+       symbolS *symbolP;
+
+       if ((symbolP = tag_find(name)) == NULL) {
+               symbolP = symbol_new(name,
+                                    SEG_UNKNOWN,
+                                    0,
+                                    &zero_address_frag);
+
+               tag_insert(S_GET_NAME(symbolP), symbolP);
+               symbol_table_insert(symbolP);
+       } /* not found */
+
+       return(symbolP);
+} /* tag_find_or_make() */
+
+static symbolS *tag_find(name)
+char *name;
+{
+#if STRIP_UNDERSCORE
+       if (*name == '_') name++;
+#endif /* STRIP_UNDERSCORE */
+       return((symbolS*)hash_find(tag_hash, name));
+} /* tag_find() */
+
+void obj_read_begin_hook() {
+ /* These had better be the same.  Usually 18 bytes. */
+       know(sizeof(SYMENT) == sizeof(AUXENT));
+       know(SYMESZ == AUXESZ);
+
+       tag_init();
+
+       return;
+} /* obj_read_begin_hook() */
+
+void obj_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+       int symbol_number = 0;
+       lineno *lineP;
+       symbolS *last_functionP = NULL;
+       symbolS *last_tagP;
+       symbolS *symbolP;
+       symbolS *symbol_externP = NULL;
+       symbolS *symbol_extern_lastP = NULL;
+
+       /* Initialize the stack used to keep track of the matching .bb .be */
+       stack* block_stack = stack_init(512, sizeof(symbolS*));
+
+       /* JF deal with forward references first... */
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if (symbolP->sy_forward) {
+                       S_SET_VALUE(symbolP, (S_GET_VALUE(symbolP)
+                                             + S_GET_VALUE(symbolP->sy_forward)
+                                             + symbolP->sy_forward->sy_frag->fr_address));
+
+                       if (SF_GET_GET_SEGMENT(symbolP)) {
+                               S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward));
+                       } /* forward segment also */
+
+                       symbolP->sy_forward=0;
+               } /* if it has a forward reference */
+       } /* walk the symbol chain */
+
+       tc_crawl_symbol_chain(headers);
+
+       /* The symbol list should be ordered according to the following sequence
+        * order :
+        * . .file symbol
+        * . debug entries for functions
+        * . fake symbols for .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.
+        */
+
+       if (symbol_rootP == NULL
+           || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) {
+               know(!previous_file_symbol);
+               c_dot_file_symbol("fake");
+       } /* Is there a .file symbol ? If not insert one at the beginning. */
+
+       /*
+        * Build up static symbols for .text, .data and .bss
+        */
+       dot_text_symbol = (symbolS*)
+           c_section_symbol(".text",
+                            0,
+                            H_GET_TEXT_SIZE(headers),
+                            0/*text_relocation_number */,
+                            0/*text_lineno_number */);
+
+       dot_data_symbol = (symbolS*)
+           c_section_symbol(".data",
+                            H_GET_TEXT_SIZE(headers),
+                            H_GET_DATA_SIZE(headers),
+                            0/*data_relocation_number */,
+                            0); /* There are no data lineno entries */
+
+       dot_bss_symbol = (symbolS*)
+           c_section_symbol(".bss",
+                            H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers),
+                            H_GET_BSS_SIZE(headers),
+                            0, /* No relocation for a bss section. */
+                            0); /* There are no bss lineno entries */
+
+#if defined(DEBUG)
+       verify_symbol_chain(symbol_rootP, symbol_lastP);
+#endif /* DEBUG */
+
+       /* Three traversals of symbol chains here.  The
+          first traversal yanks externals into a temporary
+          chain, removing the externals from the global
+          chain, numbers symbols, and does some other guck.
+          The second traversal is on the temporary chain of
+          externals and just appends them to the global
+          chain again, numbering them as we go.  The third
+          traversal patches pointers to symbols (using sym
+          indexes).  The last traversal was once done as
+          part of the first pass, but that fails when a
+          reference preceeds a definition as the definition
+          has no number at the time we process the
+          reference. */
+
+       /* Note that symbolP will be NULL at the end of a loop
+          if an external was at the beginning of the list (it
+          gets moved off the list).  Hence the weird check in
+          the loop control.
+          */
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbolP ? symbol_next(symbolP) : symbol_rootP) {
+
+               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)
+                           && (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 (flagseen['R'] && (S_GET_SEGMENT(symbolP) == SEG_DATA)) {
+                               S_SET_SEGMENT(symbolP, SEG_TEXT);
+                       } /* push data into text */
+
+                       S_SET_VALUE(symbolP, S_GET_VALUE(symbolP) + symbolP->sy_frag->fr_address);
+
+                       if (!S_IS_DEFINED(symbolP) && !SF_GET_LOCAL(symbolP)) {
+                               S_SET_EXTERNAL(symbolP);
+                       } else if (S_GET_STORAGE_CLASS(symbolP) == C_NULL) {
+                               if (S_GET_SEGMENT(symbolP) == SEG_TEXT){
+                                       S_SET_STORAGE_CLASS(symbolP, C_LABEL);
+                               } else {
+                                       S_SET_STORAGE_CLASS(symbolP, C_STAT);
+                               }
+                       } /* no storage class yet */
+
+                       /* 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. */
+                                       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));
+                               }
+                               /* The C_FCN doesn't need any additional information.
+                                  I don't even know if this is needed for sdb. But the
+                                  standard assembler generates it, so...
+                                  */
+                               if (S_GET_STORAGE_CLASS(symbolP) == C_EFCN) {
+                                       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 (S_GET_VALUE(symbolP)) {
+                               S_SET_VALUE((symbolS *) S_GET_VALUE(symbolP), symbol_number);
+                               S_SET_VALUE(symbolP, 0);
+                       } /* no one points at the first .file symbol */
+               } /* if debug or tag or eos or file */
+
+               /* 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 (!S_IS_DEFINED(symbolP) && !S_IS_DEBUG(symbolP) && !SF_GET_STATICS(symbolP)) {
+/* S_GET_STORAGE_CLASS(symbolP) == 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 (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 */
+
+       for (symbolP = symbol_externP; symbol_externP;) {
+               symbolS *tmp = symbol_externP;
+
+               /* append */
+               symbol_remove(tmp, &symbol_externP, &symbol_extern_lastP);
+               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 */
+
+       /* When a tag reference preceeds the tag definition,
+          the definition will not have a number at the time
+          we process the reference during the first
+          traversal.  Thus, a second traversal. */
+
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if (SF_GET_TAGGED(symbolP)) {
+                       SA_SET_SYM_TAGNDX(symbolP, ((symbolS*) SA_GET_SYM_TAGNDX(symbolP))->sy_number);
+               } /* If the symbol has a tagndx entry, resolve it */
+       } /* second traversal */
+
+       know(symbol_externP == NULL);
+       know(symbol_extern_lastP  == NULL);
+
+       /* FIXME-SOMEDAY I'm counting line no's here so we know what to put in the section
+          headers, and I'm resolving the addresses since I'm not sure how to
+          do it later. I am NOT resolving the linno's representing functions.
+          Their symbols need a fileptr pointing to this linno when emitted.
+          Thus, I resolve them on emit.  xoxorich. */
+
+       for (lineP = lineno_rootP; lineP; lineP = lineP->next) {
+               if (lineP->line.l_lnno > 0) {
+                       lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address;
+               } else {
+                       ;
+               }
+               text_lineno_number++;
+       } /* for each line number */
+
+       H_SET_SYMBOL_TABLE_SIZE(headers, symbol_number);
+
+       return;
+} /* obj_crawl_symbol_chain() */
+
+/*
+ * Find strings by crawling along symbol table chain.
+ */
+
+void obj_emit_strings(where)
+char **where;
+{
+       symbolS *symbolP;
+
+#ifdef CROSS_ASSEMBLE
+       /* 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_ASSEMBLE */
+       append(where, (char *) &string_byte_count, (unsigned long) sizeof(string_byte_count));
+#endif /* CROSS_ASSEMBLE */
+
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               if (SF_GET_STRING(symbolP)) {
+                       append(where, S_GET_NAME(symbolP), (unsigned long)(strlen(S_GET_NAME(symbolP)) + 1));
+               } /* if it has a string */
+       } /* walk the symbol chain */
+
+       return;
+} /* obj_emit_strings() */
+
+void obj_pre_write_hook(headers)
+object_headers *headers;
+{
+       register int text_relocation_number = 0;
+       register int data_relocation_number = 0;
+       register fixS *fixP;
+
+       /* FIXME-SOMEDAY this should be done at
+          fixup_segment time but I'm going to wait until I
+          do multiple segments.  xoxorich. */
+       /* Count the number of relocation entries for text and data */
+       for (fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
+               if (fixP->fx_addsy) {
+                       ++text_relocation_number;
+#ifdef TC_I960
+                       /* two relocs per callj under coff. */
+                       if (fixP->fx_callj) {
+                               ++text_relocation_number;
+                       } /* if callj and not already fixed. */
+#endif /* TC_I960 */
+
+               } /* if not yet fixed */
+       } /* for each fix */
+
+       SA_SET_SCN_NRELOC(dot_text_symbol, text_relocation_number);
+       /* Assign the number of line number entries for the text section */
+       SA_SET_SCN_NLINNO(dot_text_symbol, text_lineno_number);
+       /* Assign the size of the section */
+       SA_SET_SCN_SCNLEN(dot_text_symbol, H_GET_TEXT_SIZE(headers));
+
+       for (fixP = data_fix_root; fixP; fixP = fixP->fx_next) {
+               if (fixP->fx_addsy) {
+                       ++data_relocation_number;
+               } /* if still relocatable */
+       } /* for each fix */
+
+       SA_SET_SCN_NRELOC(dot_data_symbol, data_relocation_number);
+       /* Assign the size of the section */
+       SA_SET_SCN_SCNLEN(dot_data_symbol, H_GET_DATA_SIZE(headers));
+
+       /* Assign the size of the section */
+       SA_SET_SCN_SCNLEN(dot_bss_symbol, H_GET_BSS_SIZE(headers));
+
+       /* Fill in extra coff fields */
+
+       /* Initialize general line number information. */
+       H_SET_LINENO_SIZE(headers, text_lineno_number * LINESZ);
+
+       /* filehdr */
+       H_SET_FILE_MAGIC_NUMBER(headers, FILE_HEADER_MAGIC);
+       H_SET_NUMBER_OF_SECTIONS(headers, 3); /* text+data+bss */
+       H_SET_TIME_STAMP(headers, (long)time((long*)0));
+       H_SET_SYMBOL_TABLE_POINTER(headers, H_GET_SYMBOL_TABLE_FILE_OFFSET(headers));
+       /* symbol table size allready set */
+       H_SET_SIZEOF_OPTIONAL_HEADER(headers, OBJ_COFF_AOUTHDRSZ);
+#ifndef OBJ_COFF_IGNORE_EXEC_FLAG
+       H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0)
+                   | ((text_relocation_number + data_relocation_number) ? 0 : F_EXEC)
+                   | BYTE_ORDERING);
+#else /* OBJ_COFF_IGNORE_EXEC_FLAG */
+       H_SET_FLAGS(headers, (text_lineno_number == 0 ? F_LNNO : 0)
+                   | BYTE_ORDERING);
+#endif /* OBJ_COFF_IGNORE_EXEC_FLAG */
+
+       /* aouthdr */
+       /* magic number allready set */
+       H_SET_VERSION_STAMP(headers, 0);
+       /* Text, data, bss size; entry point; text_start and data_start are already set */
+
+       /* Build section headers */
+
+       c_section_header(&text_section_header,
+                        ".text",
+                        0,
+                        H_GET_TEXT_SIZE(headers),
+                        H_GET_TEXT_FILE_OFFSET(headers),
+                        (SA_GET_SCN_NRELOC(dot_text_symbol)
+                         ? H_GET_RELOCATION_FILE_OFFSET(headers)
+                         : 0),
+                        (text_lineno_number
+                         ? H_GET_LINENO_FILE_OFFSET(headers)
+                         : 0),
+                        SA_GET_SCN_NRELOC(dot_text_symbol),
+                        text_lineno_number,
+                        section_alignment[(int) SEG_TEXT]);
+
+       c_section_header(&data_section_header,
+                        ".data",
+                        H_GET_TEXT_SIZE(headers),
+                        H_GET_DATA_SIZE(headers),
+                        (H_GET_DATA_SIZE(headers)
+                         ? H_GET_DATA_FILE_OFFSET(headers)
+                         : 0),
+                        (SA_GET_SCN_NRELOC(dot_data_symbol)
+                         ? (H_GET_RELOCATION_FILE_OFFSET(headers)
+                            + text_section_header.s_nreloc * RELSZ)
+                         : 0),
+                        0, /* No line number information */
+                        SA_GET_SCN_NRELOC(dot_data_symbol),
+                        0,  /* No line number information */
+                        section_alignment[(int) SEG_DATA]);
+
+       c_section_header(&bss_section_header,
+                        ".bss",
+                        H_GET_TEXT_SIZE(headers) + H_GET_DATA_SIZE(headers),
+                        H_GET_BSS_SIZE(headers),
+                        0, /* No file offset */
+                        0, /* No relocation information */
+                        0, /* No line number information */
+                        0, /* No relocation information */
+                        0, /* No line number information */
+                        section_alignment[(int) SEG_BSS]);
+
+       return;
+} /* obj_pre_write_hook() */
+
+/* This is a copy from aout.  All I do is neglect to actually build the symbol. */
+
+static void obj_coff_stab(what)
+int what;
+{
+       char *string;
+       expressionS e;
+       int goof = 0;   /* TRUE if we have aborted. */
+       int length;
+       int saved_type = 0;
+       long longint;
+       symbolS *symbolP = 0;
+
+       if (what == 's') {
+               string = demand_copy_C_string(&length);
+               SKIP_WHITESPACE();
+
+               if (*input_line_pointer == ',') {
+                       input_line_pointer++;
+               } else {
+                       as_bad("I need a comma after symbol's name");
+                       goof = 1;
+               } /* better be a comma */
+       } /* skip the string */
+
+       /*
+        * Input_line_pointer->after ','.  String->symbol name.
+        */
+       if (!goof) {
+               if (get_absolute_expression_and_terminator(&longint) != ',') {
+                       as_bad("I want a comma after the n_type expression");
+                       goof = 1;
+                       input_line_pointer--; /* Backup over a non-',' char. */
+               } /* on error */
+       } /* no error */
+
+       if (!goof) {
+               if (get_absolute_expression_and_terminator(&longint) != ',') {
+                       as_bad("I want a comma after the n_other expression");
+                       goof = 1;
+                       input_line_pointer--; /* Backup over a non-',' char. */
+               } /* on error */
+       } /* no error */
+
+       if (!goof) {
+               get_absolute_expression();
+
+               if (what == 's' || what == 'n') {
+                       if (*input_line_pointer != ',') {
+                               as_bad("I want a comma after the n_desc expression");
+                               goof = 1;
+                       } else {
+                               input_line_pointer++;
+                       } /* on goof */
+               } /* not stabd */
+       } /* no error */
+
+       expression(&e);
+
+       if (goof) {
+               ignore_rest_of_line();
+       } else {
+               demand_empty_rest_of_line();
+       } /* on error */
+} /* obj_coff_stab() */
+
+#ifdef DEBUG
+ /* for debugging */
+char *s_get_name(s)
+symbolS *s;
+{
+       return((s == NULL) ? "(NULL)" : S_GET_NAME(s));
+} /* s_get_name() */
+
+void symbol_dump() {
+       symbolS *symbolP;
+
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+               printf("%3ld: 0x%lx \"%s\" type = %ld, class = %d, segment = %d\n",
+                      symbolP->sy_number,
+                      (unsigned long) symbolP,
+                      S_GET_NAME(symbolP),
+                      (long) S_GET_DATA_TYPE(symbolP),
+                      S_GET_STORAGE_CLASS(symbolP),
+                      (int) S_GET_SEGMENT(symbolP));
+       } /* traverse symbols */
+
+       return;
+} /* symbol_dump() */
+#endif /* DEBUG */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coff.c */
diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h
new file mode 100644 (file)
index 0000000..6ed5c84
--- /dev/null
@@ -0,0 +1,494 @@
+/* coff object file format
+   Copyright (C) 1989, 1990, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define OBJ_COFF 1
+
+#include "targ-cpu.h"
+
+#include "coff.gnu.h"
+
+#ifdef USE_NATIVE_HEADERS
+#include <filehdr.h>
+#include <aouthdr.h>
+#include <scnhdr.h>
+#include <storclass.h>
+#include <linenum.h>
+#include <syms.h>
+#include <reloc.h>
+#include <sys/types.h>
+#endif /* USE_NATIVE_HEADERS */
+
+/* Define some processor dependent values according to the processor we are
+   on. */
+#ifdef TC_M68K
+
+#define BYTE_ORDERING          F_AR32W    /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC      MC68MAGIC  /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I386)
+
+#define BYTE_ORDERING          F_AR32WR   /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC      I386MAGIC  /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_I960)
+
+#define BYTE_ORDERING          F_AR32WR   /* See filehdr.h for more info. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC      I960ROMAGIC  /* ... */
+#endif /* FILE_HEADER_MAGIC */
+
+#elif defined(TC_A29K)
+
+#define BYTE_ORDERING          F_AR32W /* big endian. */
+#ifndef FILE_HEADER_MAGIC
+#define FILE_HEADER_MAGIC      SIPFBOMAGIC
+#endif /* FILE_HEADER_MAGIC */
+
+#else
+you lose
+#endif 
+
+#ifndef OBJ_COFF_MAX_AUXENTRIES
+#define OBJ_COFF_MAX_AUXENTRIES 1
+#endif /* OBJ_COFF_MAX_AUXENTRIES */
+
+extern const short seg_N_TYPE[];
+extern const segT  N_TYPE_seg[];
+
+/* Magic number of paged executable. */
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE   (OMAGIC)
+
+/* Add these definitions to have a consistent convention for all the
+   types used in COFF format. */
+#define AOUTHDR                        struct aouthdr
+#define AOUTHDRSZ              sizeof(AOUTHDR)
+
+/* SYMBOL TABLE */
+
+ /* targets may also set this */
+#ifndef SYMBOLS_NEED_BACKPOINTERS
+#define SYMBOLS_NEED_BACKPOINTERS 1
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+/* Symbol table entry data type */
+
+typedef struct {
+       SYMENT ost_entry;       /* Basic symbol */
+       AUXENT ost_auxent[OBJ_COFF_MAX_AUXENTRIES];      /* Auxiliary entry. */
+       unsigned int ost_flags; /* obj_coff internal use only flags */
+} obj_symbol_type;
+
+/* If compiler generate leading underscores, remove them. */
+
+#ifndef STRIP_UNDERSCORE
+#define STRIP_UNDERSCORE 0
+#endif /* STRIP_UNDERSCORE */
+#define DO_NOT_STRIP   0
+#define DO_STRIP       1
+
+/* 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_TEXT_SECTION         ((short)1)
+#define C_DATA_SECTION         ((short)2)
+#define C_BSS_SECTION          ((short)3)
+#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
+
+/*
+ *  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)->sy_symbol.ost_entry.n_value > 0))
+/* 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 begin with ^A is a gas internal pseudo symbol */
+#define S_IS_LOCAL(s)          (S_GET_NAME(s)[0] == '\001' || \
+                                (S_LOCAL_NAME(s) && !flagseen['L']))
+/* True if a symbol is not defined in this file */
+#define S_IS_EXTERN(s)         ((s)->sy_symbol.ost_entry.n_scnum == 0 && (s)->sy_symbol.ost_entry.n_value == 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)->sy_symbol.ost_entry.n_value != 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 zeroes if symbol name is longer than 8 chars */
+#define S_GET_ZEROES(s)                ((s)->sy_symbol.ost_entry.n_zeroes)
+/* The value of the symbol */
+#define S_GET_VALUE(s)         ((s)->sy_symbol.ost_entry.n_value)
+/* The numeric value of the segment */
+#define S_GET_SEGMENT(s)        (N_TYPE_seg[(s)->sy_symbol.ost_entry.n_scnum+4])
+/* 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 zeroes if symbol name is longer than 8 chars */
+#define S_SET_ZEROES(s,v)              ((s)->sy_symbol.ost_entry.n_zeroes = (v))
+/* Set the value of the symbol */
+#define S_SET_VALUE(s,v)       ((s)->sy_symbol.ost_entry.n_value = (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 SA_GET_SYM_TAGNDX(s)   ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx)
+#define SA_GET_SYM_LNNO(s)     ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno)
+#define SA_GET_SYM_SIZE(s)     ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size)
+#define SA_GET_SYM_FSIZE(s)    ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize)
+#define SA_GET_SYM_LNNOPTR(s)  ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr)
+#define SA_GET_SYM_ENDNDX(s)   ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx)
+#define SA_GET_SYM_DIMEN(s,i)  ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)])
+#define SA_GET_FILE_FNAME(s)   ((s)->sy_symbol.ost_auxent[0].x_file.x_fname)
+#define SA_GET_SCN_SCNLEN(s)   ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen)
+#define SA_GET_SCN_NRELOC(s)   ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc)
+#define SA_GET_SCN_NLINNO(s)   ((s)->sy_symbol.ost_auxent[0].x_scn.x_nlinno)
+
+/* Modifiers */
+#define SA_SET_SYM_TAGNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_tagndx=(v))
+#define SA_SET_SYM_LNNO(s,v)   ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_lnno=(v))
+#define SA_SET_SYM_SIZE(s,v)   ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_lnsz.x_size=(v))
+#define SA_SET_SYM_FSIZE(s,v)  ((s)->sy_symbol.ost_auxent[0].x_sym.x_misc.x_fsize=(v))
+#define SA_SET_SYM_LNNOPTR(s,v)        ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_lnnoptr=(v))
+#define SA_SET_SYM_ENDNDX(s,v) ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_fcn.x_endndx=(v))
+#define SA_SET_SYM_DIMEN(s,i,v)        ((s)->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v))
+#define SA_SET_FILE_FNAME(s,v) strncpy((s)->sy_symbol.ost_auxent[0].x_file.x_fname,(v),FILNMLEN)
+#define SA_SET_SCN_SCNLEN(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_scnlen=(v))
+#define SA_SET_SCN_NRELOC(s,v) ((s)->sy_symbol.ost_auxent[0].x_scn.x_nreloc=(v))
+#define SA_SET_SCN_NLINNO(s,v) ((s)->sy_symbol.ost_auxent[0].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_symbol.ost_flags)
+#define SF_GET_NORMAL_FIELD(s) ((s)->sy_symbol.ost_flags & SF_NORMAL_MASK)
+#define SF_GET_DEBUG_FIELD(s)  ((s)->sy_symbol.ost_flags & SF_DEBUG_MASK)
+#define SF_GET_FILE(s)         ((s)->sy_symbol.ost_flags & SF_FILE)
+#define SF_GET_STATICS(s)      ((s)->sy_symbol.ost_flags & SF_STATICS)
+#define SF_GET_DEFINED(s)      ((s)->sy_symbol.ost_flags & SF_DEFINED)
+#define SF_GET_STRING(s)       ((s)->sy_symbol.ost_flags & SF_STRING)
+#define SF_GET_LOCAL(s)                ((s)->sy_symbol.ost_flags & SF_LOCAL)
+#define SF_GET_FUNCTION(s)      ((s)->sy_symbol.ost_flags & SF_FUNCTION)
+#define SF_GET_PROCESS(s)      ((s)->sy_symbol.ost_flags & SF_PROCESS)
+#define SF_GET_DEBUG(s)                ((s)->sy_symbol.ost_flags & SF_DEBUG)
+#define SF_GET_TAGGED(s)       ((s)->sy_symbol.ost_flags & SF_TAGGED)
+#define SF_GET_TAG(s)          ((s)->sy_symbol.ost_flags & SF_TAG)
+#define SF_GET_GET_SEGMENT(s)  ((s)->sy_symbol.ost_flags & SF_GET_SEGMENT)
+#define SF_GET_I960(s)         ((s)->sy_symbol.ost_flags & SF_I960_MASK) /* used by i960 */
+#define SF_GET_BALNAME(s)      ((s)->sy_symbol.ost_flags & SF_BALNAME) /* used by i960 */
+#define SF_GET_CALLNAME(s)     ((s)->sy_symbol.ost_flags & SF_CALLNAME) /* used by i960 */
+#define SF_GET_IS_SYSPROC(s)   ((s)->sy_symbol.ost_flags & SF_IS_SYSPROC) /* used by i960 */
+#define SF_GET_SYSPROC(s)      ((s)->sy_symbol.ost_flags & SF_SYSPROC) /* used by i960 */
+
+/* Modifiers */
+#define SF_SET(s,v)            ((s)->sy_symbol.ost_flags = (v))
+#define SF_SET_NORMAL_FIELD(s,v)((s)->sy_symbol.ost_flags |= ((v) & SF_NORMAL_MASK))
+#define SF_SET_DEBUG_FIELD(s,v)        ((s)->sy_symbol.ost_flags |= ((v) & SF_DEBUG_MASK))
+#define SF_SET_FILE(s)         ((s)->sy_symbol.ost_flags |= SF_FILE)
+#define SF_SET_STATICS(s)      ((s)->sy_symbol.ost_flags |= SF_STATICS)
+#define SF_SET_DEFINED(s)      ((s)->sy_symbol.ost_flags |= SF_DEFINED)
+#define SF_SET_STRING(s)       ((s)->sy_symbol.ost_flags |= SF_STRING)
+#define SF_SET_LOCAL(s)                ((s)->sy_symbol.ost_flags |= SF_LOCAL)
+#define SF_CLEAR_LOCAL(s)      ((s)->sy_symbol.ost_flags &= ~SF_LOCAL)
+#define SF_SET_FUNCTION(s)      ((s)->sy_symbol.ost_flags |= SF_FUNCTION)
+#define SF_SET_PROCESS(s)      ((s)->sy_symbol.ost_flags |= SF_PROCESS)
+#define SF_SET_DEBUG(s)                ((s)->sy_symbol.ost_flags |= SF_DEBUG)
+#define SF_SET_TAGGED(s)       ((s)->sy_symbol.ost_flags |= SF_TAGGED)
+#define SF_SET_TAG(s)          ((s)->sy_symbol.ost_flags |= SF_TAG)
+#define SF_SET_GET_SEGMENT(s)  ((s)->sy_symbol.ost_flags |= SF_GET_SEGMENT)
+#define SF_SET_I960(s,v)       ((s)->sy_symbol.ost_flags |= ((v) & SF_I960_MASK)) /* used by i960 */
+#define SF_SET_BALNAME(s)      ((s)->sy_symbol.ost_flags |= SF_BALNAME) /* used by i960 */
+#define SF_SET_CALLNAME(s)     ((s)->sy_symbol.ost_flags |= SF_CALLNAME) /* used by i960 */
+#define SF_SET_IS_SYSPROC(s)   ((s)->sy_symbol.ost_flags |= SF_IS_SYSPROC) /* used by i960 */
+#define SF_SET_SYSPROC(s,v)    ((s)->sy_symbol.ost_flags |= ((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) * SYMESZ + \
+          (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_TABLE_SIZE(h)     ((h)->filehdr.f_nsyms)
+#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)
+
+/* 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 */
+#define segment_name(v)        (seg_name[(int) (v)])
+
+typedef struct {
+    AOUTHDR       aouthdr;             /* a.out header */
+    FILHDR        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;
+
+/* --------------  Line number handling ------- */
+extern int             text_lineno_number;
+
+/* line numbering stuff. */
+
+typedef struct internal_lineno {
+    LINENO line;                       /* The lineno structure itself */
+    char* frag;                                /* Frag to which the line number is related */
+    struct internal_lineno* next;      /* Forward chain pointer */
+} lineno;
+
+extern lineno *lineno_lastP;
+extern lineno *lineno_rootP;
+#define OBJ_EMIT_LINENO(a, b, c)       obj_emit_lineno((a),(b),(c))
+
+#ifdef __STDC__
+void obj_emit_lineno(char **where, lineno *line, char *file_start);
+#else /* __STDC__ */
+void obj_emit_lineno();
+#endif /* __STDC__ */
+
+ /* stack stuff */
+typedef struct {
+    unsigned long chunk_size;
+    unsigned long element_size;
+    unsigned long size;
+    char*        data;
+    unsigned long pointer;
+} stack;
+
+#ifdef __STDC__
+
+char *stack_pop(stack *st);
+char *stack_push(stack *st, char *element);
+char *stack_top(stack *st);
+stack *stack_init(unsigned long chunk_size, unsigned long element_size);
+void c_dot_file_symbol(char *filename);
+void obj_extra_stuff(object_headers *headers);
+void stack_delete(stack *st);
+
+#ifndef tc_headers_hook
+void tc_headers_hook(object_headers *headers);
+#endif /* tc_headers_hook */
+
+#ifndef tc_coff_symbol_emit_hook
+void tc_coff_symbol_emit_hook(); /* really tc_coff_symbol_emit_hook(symbolS *symbolP) */
+#endif /* tc_coff_symbol_emit_hook */
+
+void c_section_header(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);
+
+#else /* __STDC__ */
+
+char *stack_pop();
+char *stack_push();
+char *stack_top();
+stack *stack_init();
+void c_dot_file_symbol();
+void c_section_header();
+void obj_extra_stuff();
+void stack_delete();
+void tc_headers_hook();
+void tc_coff_symbol_emit_hook();
+
+#endif /* __STDC__ */
+
+
+ /* 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 */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj-coff.h */
diff --git a/gas/config/tc-a29k.c b/gas/config/tc-a29k.c
new file mode 100644 (file)
index 0000000..8bb6d2a
--- /dev/null
@@ -0,0 +1,1157 @@
+/* tc-a29k.c -- Assemble for the AMD 29000.
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/* John Gilmore has reorganized this module somewhat, to make it easier
+   to convert it to new machines' assemblers as desired.  There was too
+   much bloody rewriting required before.  There still probably is.  */
+#include "as.h"
+
+#include "a29k-opcode.h"
+
+/* Make it easier to clone this machine desc into another one.  */
+#define        machine_opcode  a29k_opcode
+#define        machine_opcodes a29k_opcodes
+#define        machine_ip      a29k_ip
+#define        machine_it      a29k_it
+
+const relax_typeS md_relax_table[] = { 0 };
+
+#define        IMMEDIATE_BIT   0x01000000      /* Turns RB into Immediate */
+#define        ABSOLUTE_BIT    0x01000000      /* Turns PC-relative to Absolute */
+#define        CE_BIT          0x00800000      /* Coprocessor enable in LOAD */
+#define        UI_BIT          0x00000080      /* Unsigned integer in CONVERT */
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+struct machine_it {
+    char    *error;
+    unsigned long opcode;
+    struct nlist *nlistp;
+    expressionS exp;
+    int pcrel;
+    int  reloc_offset;         /* Offset of reloc within insn */
+    enum reloc_type reloc;
+} the_insn;
+
+#ifdef __STDC__
+
+/* static int getExpression(char *str); */
+static void machine_ip(char *str);
+/* static void print_insn(struct machine_it *insn); */
+static void s_data1(void);
+static void s_use(void);
+
+#else /* __STDC__ */
+
+/* static int getExpression(); */
+static void machine_ip();
+/* static void print_insn(); */
+static void s_data1();
+static void s_use();
+
+#endif /* __STDC__ */
+
+const pseudo_typeS
+md_pseudo_table[] = {
+  { "align",   s_align_bytes,  4 },
+  { "block",   s_space,        0 },
+  { "cputype", s_ignore,       0 },    /* CPU as 29000 or 29050 */
+  { "file",    s_ignore,       0 },    /* COFF File name for debug info? */
+  { "line",    s_ignore,       0 },    /* Line number of coff symbol */
+  { "reg",     s_lsym,         0 },    /* Register equate, same as equ */
+  { "space",   s_ignore,       0 },    /* Listing control */
+  { "sect",    s_ignore,       0 },    /* Creation of coff sections */
+  { "use",     s_use,          0 },
+  { "word",    cons,           4 },
+  { NULL,      0,              0 },
+};
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+int md_reloc_size = 12;
+
+/* This array holds the chars that always start a comment.  If the
+    pre-processor is disabled, these aren't very useful */
+char comment_chars[] = ";";
+
+/* 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 like this one will always work */
+char line_comment_chars[] = "#";
+
+/* We needed an unused char for line separation to work around the
+   lack of macros, using sed and such.  */
+char line_separator_chars[] = "@";
+
+/* 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";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+ */
+
+static unsigned char octal[256];
+#define isoctal(c)  octal[c]
+static unsigned char toHex[256];
+
+/*
+ *  anull bit - causes the branch delay slot instructions to not be executed 
+ */
+#define ANNUL       (1 << 29)
+
+static void
+s_use()
+{
+
+    if (strncmp(input_line_pointer, ".text", 5) == 0) {
+       input_line_pointer += 5;
+       s_text();
+       return;
+    }
+    if (strncmp(input_line_pointer, ".data", 5) == 0) {
+       input_line_pointer += 5;
+       s_data();
+       return;
+    }
+    if (strncmp(input_line_pointer, ".data1", 6) == 0) {
+       input_line_pointer += 6;
+       s_data1();
+       return;
+    }
+    /* Literals can't go in the text segment because you can't read
+       from instruction memory on some 29k's.  So, into initialized data. */
+    if (strncmp(input_line_pointer, ".lit", 4) == 0) {
+       input_line_pointer += 4;
+       subseg_new(SEG_DATA, 200);
+       demand_empty_rest_of_line();
+       return;
+    }
+
+    as_bad("Unknown segment type");
+    demand_empty_rest_of_line();
+    return;
+}
+
+static void
+s_data1()
+{
+    subseg_new(SEG_DATA, 1);
+    demand_empty_rest_of_line();
+    return;
+}
+
+/* Install symbol definition that maps REGNAME to REGNO.
+   FIXME-SOON:  These are not recognized in mixed case.  */
+
+static void
+insert_sreg (regname, regnum)
+     char *regname;
+     int regnum;
+{
+       /* FIXME-SOON, put something in these syms so they won't be output to the symbol
+          table of the resulting object file.  */
+       
+       /* Must be large enough to hold the names of the special registers.  */
+       char buf[80];
+       int i;
+       
+       symbol_table_insert(symbol_new(regname, SEG_REGISTER, regnum, &zero_address_frag));
+       for (i = 0; regname[i]; i++)
+           buf[i] = islower (regname[i]) ? toupper (regname[i]) : regname[i];
+       buf[i] = '\0';
+       
+       symbol_table_insert(symbol_new(buf, SEG_REGISTER, regnum, &zero_address_frag));
+} /* insert_sreg() */
+
+/* Install symbol definitions for assorted special registers.
+   See ASM29K Ref page 2-9.  */
+
+void define_some_regs() {
+#define SREG   256
+       
+       /* Protected special-purpose register names */
+       insert_sreg ("vab", SREG+0);
+       insert_sreg ("ops", SREG+1);
+       insert_sreg ("cps", SREG+2);
+       insert_sreg ("cfg", SREG+3);
+       insert_sreg ("cha", SREG+4);
+       insert_sreg ("chd", SREG+5);
+       insert_sreg ("chc", SREG+6);
+       insert_sreg ("rbp", SREG+7);
+       insert_sreg ("tmc", SREG+8);
+       insert_sreg ("tmr", SREG+9);
+       insert_sreg ("pc0", SREG+10);
+       insert_sreg ("pc1", SREG+11);
+       insert_sreg ("pc2", SREG+12);
+       insert_sreg ("mmu", SREG+13);
+       insert_sreg ("lru", SREG+14);
+       
+       /* Unprotected special-purpose register names */
+       insert_sreg ("ipc", SREG+128);
+       insert_sreg ("ipa", SREG+129);
+       insert_sreg ("ipb", SREG+130);
+       insert_sreg ("q",   SREG+131);
+       insert_sreg ("alu", SREG+132);
+       insert_sreg ("bp",  SREG+133);
+       insert_sreg ("fc",  SREG+134);
+       insert_sreg ("cr",  SREG+135);
+       insert_sreg ("fpe", SREG+160);
+       insert_sreg ("inte",SREG+161);
+       insert_sreg ("fps", SREG+162);
+       /*  "",    SREG+163);     Reserved */
+       insert_sreg ("exop",SREG+164);
+} /* define_some_regs() */
+
+/* This function is called once, at assembler startup time.  It should
+   set up all the tables, etc. that the MD part of the assembler will need.  */
+void
+md_begin()
+{
+  register char *retval = NULL;
+  int lose = 0;
+  register int skipnext = 0;
+  register unsigned int i;
+  register char *strend, *strend2;
+
+  /* Hash up all the opcodes for fast use later.  */
+
+  op_hash = hash_new();
+  if (op_hash == NULL)
+    as_fatal("Virtual memory exhausted");
+
+  for (i = 0; i < num_opcodes; i++)
+    {
+      const char *name = machine_opcodes[i].name;
+
+      if (skipnext) {
+       skipnext = 0;
+       continue;
+      }
+
+      /* Hack to avoid multiple opcode entries.  We pre-locate all the
+        variations (b/i field and P/A field) and handle them. */
+
+      if (!strcmp (name, machine_opcodes[i+1].name)) {
+       if ((machine_opcodes[i].opcode ^ machine_opcodes[i+1].opcode)
+            != 0x01000000)
+         goto bad_table;
+       strend =  machine_opcodes[i  ].args+strlen(machine_opcodes[i  ].args)-1;
+       strend2 = machine_opcodes[i+1].args+strlen(machine_opcodes[i+1].args)-1;
+       switch (*strend) {
+         case 'b':
+           if (*strend2 != 'i')  goto bad_table;
+           break;
+         case 'i':
+           if (*strend2 != 'b')  goto bad_table;
+           break;
+         case 'P':
+           if (*strend2 != 'A')  goto bad_table;
+           break;
+         case 'A':
+           if (*strend2 != 'P')  goto bad_table;
+           break;
+          default:
+         bad_table:
+           fprintf (stderr, "internal error: can't handle opcode %s\n", name);
+           lose = 1;
+       }
+
+       /* OK, this is an i/b or A/P pair.  We skip the higher-valued one,
+          and let the code for operand checking handle OR-ing in the bit.  */
+       if (machine_opcodes[i].opcode & 1)
+         continue;
+       else
+         skipnext = 1;
+      }
+
+      retval = hash_insert (op_hash, name, &machine_opcodes[i]);
+      if (retval != NULL && *retval != '\0')
+       {
+         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                  machine_opcodes[i].name, retval);
+         lose = 1;
+       }
+    }
+
+  if (lose)
+    as_fatal("Broken assembler.  No assembly attempted.");
+
+  for (i = '0'; i < '8'; ++i)
+    octal[i] = 1;
+  for (i = '0'; i <= '9'; ++i)
+    toHex[i] = i - '0';
+  for (i = 'a'; i <= 'f'; ++i)
+    toHex[i] = i + 10 - 'a';
+  for (i = 'A'; i <= 'F'; ++i)
+    toHex[i] = i + 10 - 'A';
+
+  define_some_regs ();
+}
+
+void md_end() {
+    return;
+}
+
+/* Assemble a single instruction.  Its label has already been handled
+   by the generic front end.  We just parse opcode and operands, and
+   produce the bytes of data and relocation.  */
+
+void md_assemble(str)
+    char *str;
+{
+    char *toP;
+/* !!!!    int rsd; */
+
+    know(str);
+    machine_ip(str);
+    toP = frag_more(4);
+    /* put out the opcode */
+    md_number_to_chars(toP, the_insn.opcode, 4);
+
+    /* put out the symbol-dependent stuff */
+    if (the_insn.reloc != NO_RELOC) {
+       fix_new(
+           frag_now,                           /* which frag */
+           (toP - frag_now->fr_literal + the_insn.reloc_offset), /* where */
+           4,                                  /* size */
+           the_insn.exp.X_add_symbol,
+           the_insn.exp.X_subtract_symbol,
+           the_insn.exp.X_add_number,
+           the_insn.pcrel,
+           the_insn.reloc
+       );
+    }
+}
+
+char *
+parse_operand (s, operandp)
+     char *s;
+     expressionS *operandp;
+{
+    char *save = input_line_pointer;
+    char *new;
+    segT seg;
+
+    input_line_pointer = s;
+    seg = expr (0, operandp);
+    new = input_line_pointer;
+    input_line_pointer = save;
+
+    switch (seg) {
+    case SEG_ABSOLUTE:
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_REGISTER:
+       return new;
+
+    case SEG_ABSENT:
+       as_bad("Missing operand");
+       return new;
+
+    default:
+       as_bad("Don't understand operand of type %s", segment_name (seg));
+       return new;
+    }
+}
+
+/* Instruction parsing.  Takes a string containing the opcode.  
+   Operands are at input_line_pointer.  Output is in the_insn.
+   Warnings or errors are generated.  */
+static void
+machine_ip(str)
+    char *str;
+{
+    char *s;
+    const char *args;
+/* !!!!    char c; */
+/* !!!!    unsigned long i; */
+    struct machine_opcode *insn;
+    char *argsStart;
+    unsigned long   opcode;
+/* !!!!    unsigned int mask; */
+    expressionS the_operand;
+    expressionS *operand = &the_operand;
+    unsigned int reg;
+
+    /* Must handle `div0' opcode.  */
+    s = str;
+    if (isalpha(*s))
+      for (; isalnum(*s); ++s)
+       if (isupper (*s))
+         *s = tolower (*s);
+
+    switch (*s) {
+    case '\0':
+       break;
+
+    case ' ':          /* FIXME-SOMEDAY more whitespace */
+       *s++ = '\0';
+       break;
+
+    default:
+       as_bad("Unknown opcode: `%s'", str);
+       return;
+    }
+    if ((insn = (struct machine_opcode *) hash_find(op_hash, str)) == NULL) {
+       as_bad("Unknown opcode `%s'.", str);
+       return;
+    }
+    argsStart = s;
+    opcode = insn->opcode;
+    bzero(&the_insn, sizeof(the_insn));
+    the_insn.reloc = NO_RELOC;
+
+    /*
+     * Build the opcode, checking as we go to make
+     * sure that the operands match.
+     *
+     * If an operand matches, we modify the_insn or opcode appropriately,
+     * and do a "continue".  If an operand fails to match, we "break".
+     */
+    if (insn->args[0] != '\0')
+       s = parse_operand (s, operand); /* Prime the pump */
+
+    for (args = insn->args; ; ++args) {
+       switch (*args) {
+
+       case '\0':  /* end of args */
+           if (*s == '\0') {
+               /* We are truly done. */
+               the_insn.opcode = opcode;
+               return;
+           }
+           as_bad("Too many operands: %s", s);
+           break;
+
+       case ',':       /* Must match a comma */
+           if (*s++ == ',') {
+               s = parse_operand (s, operand); /* Parse next opnd */
+               continue;
+           }
+           break;
+
+       case 'v':               /* Trap numbers (immediate field) */
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               if (operand->X_add_number < 256) {
+                   opcode |= (operand->X_add_number << 16);
+                   continue;
+               } else {
+                   as_bad("Immediate value of %d is too large", 
+                           operand->X_add_number);
+                   continue;
+               }
+           }
+           the_insn.reloc = RELOC_8;
+           the_insn.reloc_offset = 1;  /* BIG-ENDIAN Byte 1 of insn */
+           the_insn.exp = *operand;
+           continue;
+           
+       case 'b':       /* A general register or 8-bit immediate */
+       case 'i':
+           /* We treat the two cases identically since we mashed
+              them together in the opcode table.  */
+           if (operand->X_seg == SEG_REGISTER)
+               goto general_reg;
+
+           opcode |= IMMEDIATE_BIT;
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               if (operand->X_add_number < 256) {
+                   opcode |= operand->X_add_number;
+                   continue;
+               } else {
+                   as_bad("Immediate value of %d is too large", 
+                           operand->X_add_number);
+                   continue;
+               }
+           }
+           the_insn.reloc = RELOC_8;
+           the_insn.reloc_offset = 3;  /* BIG-ENDIAN Byte 3 of insn */
+           the_insn.exp = *operand;
+           continue;
+           
+       case 'a':   /* next operand must be a register */
+       case 'c':
+       general_reg:
+           /* lrNNN or grNNN or %%expr or a user-def register name */
+           if (operand->X_seg != SEG_REGISTER)
+               break;          /* Only registers */
+           know (operand->X_add_symbol == 0);
+           know (operand->X_subtract_symbol == 0);
+           reg = operand->X_add_number;
+           if (reg >= SREG)
+               break;          /* No special registers */
+
+           /*
+            * Got the register, now figure out where
+            * it goes in the opcode.
+            */
+           switch (*args) {
+           case 'a':
+               opcode |= reg << 8;
+               continue;
+
+           case 'b':
+           case 'i':
+               opcode |= reg;
+               continue;
+
+           case 'c':
+               opcode |= reg << 16;
+               continue;
+           }
+           abort();
+           break;
+
+       case 'x':               /* 16 bit constant, zero-extended */
+       case 'X':               /* 16 bit constant, one-extended */
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               opcode |=  (operand->X_add_number & 0xFF)   << 0 |
+                         ((operand->X_add_number & 0xFF00) << 8);
+               continue;
+           }
+           the_insn.reloc = RELOC_CONST;
+           the_insn.exp = *operand;
+           continue;
+
+       case 'h':
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               opcode |=  (operand->X_add_number & 0x00FF0000) >> 16 |
+                         (((unsigned long)operand->X_add_number
+                         /* avoid sign ext */    & 0xFF000000) >> 8);
+               continue;
+           }
+           the_insn.reloc = RELOC_CONSTH;
+           the_insn.exp = *operand;
+           continue;
+
+       case 'P':               /* PC-relative jump address */
+       case 'A':               /* Absolute jump address */
+           /* These two are treated together since we folded the
+              opcode table entries together.  */
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               opcode |= ABSOLUTE_BIT |
+                         (operand->X_add_number & 0x0003FC00) << 6 |
+                        ((operand->X_add_number & 0x000003FC) >> 2);
+               continue;
+           }
+           the_insn.reloc = RELOC_JUMPTARG;
+           the_insn.exp = *operand;
+           the_insn.pcrel = 1;         /* Assume PC-relative jump */
+           /* FIXME-SOON, Do we figure out whether abs later, after know sym val? */
+           continue;
+
+       case 'e':               /* Coprocessor enable bit for LOAD/STORE insn */
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               if (operand->X_add_number == 0)
+                   continue;
+               if (operand->X_add_number == 1) {
+                   opcode |= CE_BIT;
+                   continue;
+               }
+           }
+           break;
+
+       case 'n':               /* Control bits for LOAD/STORE instructions */
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 128) {
+               opcode |= (operand->X_add_number << 16);
+               continue;
+           }
+           break;
+           
+       case 's':               /* Special register number */
+           if (operand->X_seg != SEG_REGISTER)
+               break;          /* Only registers */
+           if (operand->X_add_number < SREG)
+               break;          /* Not a special register */
+           opcode |= (operand->X_add_number & 0xFF) << 8;
+           continue;
+
+       case 'u':               /* UI bit of CONVERT */
+           if (operand->X_seg == SEG_ABSOLUTE) {
+               if (operand->X_add_number == 0)
+                   continue;
+               if (operand->X_add_number == 1) {
+                   opcode |= UI_BIT;
+                   continue;
+               }
+           }
+           break;
+
+       case 'r':               /* RND bits of CONVERT */
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 8) {
+               opcode |= operand->X_add_number << 4;
+               continue;
+           }
+           break;
+
+       case 'd':               /* FD bits of CONVERT */
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 4) {
+               opcode |= operand->X_add_number << 2;
+               continue;
+           }
+           break;
+
+
+       case 'f':               /* FS bits of CONVERT */
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 4) {
+               opcode |= operand->X_add_number << 0;
+               continue;
+           }
+           break;
+
+         case 'C':
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 4) {
+               opcode |= operand->X_add_number << 16;
+               continue;
+           }
+           break;
+
+         case 'F':
+           if (operand->X_seg == SEG_ABSOLUTE &&
+               operand->X_add_number < 16) {
+               opcode |= operand->X_add_number << 18;
+               continue;
+           }
+           break;
+
+       default:
+           BAD_CASE (*args);
+       }
+       /* Types or values of args don't match.  */
+       as_bad("Invalid operands");
+       return;
+    }
+}
+
+/*
+    This is identical to the md_atof in m68k.c.  I think this is right,
+    but I'm not sure.
+
+   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
+
+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':
+    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 ""; /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+md_number_to_chars(buf,val,n)
+    char *buf;
+    long val;
+    int n;
+{
+
+    switch(n) {
+
+    case 4:
+       *buf++ = val >> 24;
+       *buf++ = val >> 16;
+    case 2:
+       *buf++ = val >> 8;
+    case 1:
+       *buf = val;
+       break;
+
+    default:
+       abort();
+    }
+    return;
+}
+
+void md_apply_fix(fixP, val)
+    fixS *fixP;
+    long val;
+{
+    char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+    fixP->fx_addnumber = val;  /* Remember value for emit_reloc */
+
+    if (fixP->fx_r_type == NO_RELOC) {
+       abort();                /* FIXME-SOON, if this is never used, remove */
+       switch (fixP->fx_size) {
+       case 1:
+               *buf = val;
+               break;
+       case 2:
+               *buf++ = (val>>8);
+               *buf = val;
+               break;
+       case 4:
+               *buf++ = (val>>24);
+               *buf++ = (val>>16);
+               *buf++ = (val>>8);
+               *buf = val;
+               break;
+       default:
+               abort();
+       }
+       return;
+    }
+
+    know(fixP->fx_size == 4);
+    know(fixP->fx_r_type < NO_RELOC);
+
+    /*
+     * This is a hack.  There should be a better way to
+     * handle this.
+     */
+    if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) {
+           val += fixP->fx_where + fixP->fx_frag->fr_address;
+    }
+
+    switch (fixP->fx_r_type) {
+
+    case RELOC_32:
+       buf[0] = val >> 24;
+       buf[1] = val >> 16;
+       buf[2] = val >> 8;
+       buf[3] = val;
+       break;
+
+    case RELOC_8:
+       buf[0] = val;
+       break;
+
+    case RELOC_WDISP30:
+       val = (val >>= 2) + 1;
+       buf[0] |= (val >> 24) & 0x3f;
+       buf[1]= (val >> 16);
+       buf[2] = val >> 8;
+       buf[3] = val;
+       break;
+
+    case RELOC_HI22:
+       buf[1] |= (val >> 26) & 0x3f;
+       buf[2] = val >> 18;
+       buf[3] = val >> 10;
+       break;
+
+    case RELOC_LO10:
+       buf[2] |= (val >> 8) & 0x03;
+       buf[3] = val;
+       break;
+
+    case RELOC_BASE13:
+       buf[2] |= (val >> 8) & 0x1f;
+       buf[3] = val;
+       break;
+
+    case RELOC_WDISP22:
+       val = (val >>= 2) + 1;
+       /* FALLTHROUGH */
+    case RELOC_BASE22:
+       buf[1] |= (val >> 16) & 0x3f;
+       buf[2] = val >> 8;
+       buf[3] = val;
+       break;
+
+#if 0
+    case RELOC_PC10: 
+    case RELOC_PC22: 
+    case RELOC_JMP_TBL:
+    case RELOC_SEGOFF16:
+    case RELOC_GLOB_DAT:
+    case RELOC_JMP_SLOT: 
+    case RELOC_RELATIVE:
+#endif
+    case RELOC_JUMPTARG:       /* 00XX00XX pattern in a word */
+       buf[1] = val >> 10;     /* Holds bits 0003FFFC of address */
+       buf[3] = val >> 2;
+       break;
+
+    case RELOC_CONST:          /* 00XX00XX pattern in a word */
+       buf[1] = val >> 8;      /* Holds bits 0000XXXX */
+       buf[3] = val;
+       break;
+
+    case RELOC_CONSTH:         /* 00XX00XX pattern in a word */
+       buf[1] = val >> 24;     /* Holds bits XXXX0000 */
+       buf[3] = val >> 16;
+       break;
+
+    case NO_RELOC:
+    default:
+       as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
+       break;
+    }
+    return;
+}
+
+#ifdef OBJ_COFF
+short tc_coff_fix2rtype(fixP)
+fixS *fixP;
+{
+
+       /* FIXME-NOW: relocation type handling is not yet written for
+          a29k. */
+
+       know(0);
+       switch (fixP->fx_r_type) {
+       case RELOC_32:  return(R_WORD);
+       case RELOC_8:   return(R_BYTE);
+       default:        know(0);
+       } /* switch on type */
+
+       return(0);
+} /* tc_coff_fix2rtype() */
+#endif /* OBJ_COFF */
+
+/* should never be called for sparc */
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char *ptr;
+    long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+    fprintf(stderr, "a29k_create_short_jmp\n");
+    abort();
+}
+
+/* Translate internal representation of relocation info to target format.
+
+   On sparc/29k: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as external, bits 6 & 5 unused, and the lower
+   five bits as relocation type.  Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void
+md_ri_to_chars(the_bytes, ri)
+     char *the_bytes;
+     struct reloc_info_generic *ri;
+{
+  /* this is easy */
+  md_number_to_chars(the_bytes, ri->r_address, 4);
+  /* now the fun stuff */
+  the_bytes[4] = (ri->r_index >> 16) & 0x0ff;
+  the_bytes[5] = (ri->r_index >> 8) & 0x0ff;
+  the_bytes[6] = ri->r_index & 0x0ff;
+  the_bytes[7] = ((ri->r_extern << 7)  & 0x80) | (0 & 0x60) | (ri->r_type & 0x1F);
+  /* Also easy */
+  md_number_to_chars(&the_bytes[8], ri->r_addend, 4);
+}
+
+/* should never be called for 29k */
+void md_convert_frag(fragP)
+    register fragS *fragP;
+{
+    fprintf(stderr, "sparc_convert_frag\n");
+    abort();
+}
+
+/* should never be called for 29k */
+void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char       *ptr;
+    long       from_addr,
+               to_addr;
+    fragS      *frag;
+    symbolS    *to_symbol;
+{
+    fprintf(stderr, "sparc_create_long_jump\n");
+    abort();
+}
+
+/* should never be called for sparc */
+int md_estimate_size_before_relax(fragP, segtype)
+    register fragS *fragP;
+segT segtype;
+{
+    fprintf(stderr, "sparc_estimate_size_before_relax\n");
+    abort();
+    return 0;
+}
+
+#if 0
+/* for debugging only */
+static void
+print_insn(insn)
+    struct machine_it *insn;
+{
+    char *Reloc[] = {
+    "RELOC_8",
+    "RELOC_16",
+    "RELOC_32",
+    "RELOC_DISP8",
+    "RELOC_DISP16",
+    "RELOC_DISP32",
+    "RELOC_WDISP30",
+    "RELOC_WDISP22",
+    "RELOC_HI22",
+    "RELOC_22",
+    "RELOC_13",
+    "RELOC_LO10",
+    "RELOC_SFA_BASE",
+    "RELOC_SFA_OFF13",
+    "RELOC_BASE10",
+    "RELOC_BASE13",
+    "RELOC_BASE22",
+    "RELOC_PC10",
+    "RELOC_PC22",
+    "RELOC_JMP_TBL",
+    "RELOC_SEGOFF16",
+    "RELOC_GLOB_DAT",
+    "RELOC_JMP_SLOT",
+    "RELOC_RELATIVE",
+    "NO_RELOC"
+    };
+
+    if (insn->error) {
+       fprintf(stderr, "ERROR: %s\n");
+    }
+    fprintf(stderr, "opcode=0x%08x\n", insn->opcode);
+    fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]);
+    fprintf(stderr, "exp =  {\n");
+    fprintf(stderr, "\t\tX_add_symbol = %s\n",
+       insn->exp.X_add_symbol ?
+       (S_GET_NAME(insn->exp.X_add_symbol) ? 
+       S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
+    fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+       insn->exp.X_subtract_symbol ?
+           (S_GET_NAME(insn->exp.X_subtract_symbol) ? 
+               S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
+    fprintf(stderr, "\t\tX_add_number = %d\n",
+       insn->exp.X_add_number);
+    fprintf(stderr, "}\n");
+    return;
+}
+#endif
+
+/*
+ * Sparc/A29K relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+#ifdef OBJ_AOUT
+static void emit_machine_reloc(fixP, segment_address_in_file)
+register fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+    struct reloc_info_generic ri;
+    register symbolS *symbolP;
+    extern char *next_object_file_charP;
+/* !!!!    long add_number; */
+
+    bzero((char *) &ri, sizeof(ri));
+    for (; fixP; fixP = fixP->fx_next) {
+
+       if (fixP->fx_r_type >= NO_RELOC) {
+           fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
+           abort();
+       }
+
+       if ((symbolP = fixP->fx_addsy) != NULL) {
+           ri.r_address = fixP->fx_frag->fr_address +
+               fixP->fx_where - segment_address_in_file;
+           ri.r_addend = fixP->fx_addnumber;
+           if (!S_IS_DEFINED(symbolP)) {
+               ri.r_extern = 1;
+               ri.r_index = symbolP->sy_number;
+           } else {
+               ri.r_extern = 0;
+               ri.r_index = S_GET_TYPE(symbolP);
+           }
+           ri.r_type = fixP->fx_r_type;
+
+           md_ri_to_chars (next_object_file_charP, &ri);
+           next_object_file_charP += md_reloc_size;
+       }
+    }
+} /* emit_machine_reloc() */
+
+void (*md_emit_relocations)() = emit_machine_reloc;
+
+#endif /* OBJ_AOUT */
+
+int
+md_parse_option(argP,cntP,vecP)
+    char **argP;
+    int *cntP;
+    char ***vecP;
+{
+    return 1;
+}
+
+
+/* Default the values of symbols known that should be "predefined".  We
+   don't bother to predefine them unless you actually use one, since there
+   are a lot of them.  */
+
+symbolS *md_undefined_symbol (name)
+     char *name;
+{
+  long regnum;
+  char testbuf[5+ /*SLOP*/ 5];
+
+  if (name[0] == 'g' || name[0] == 'G' || name[0] == 'l' || name[0] == 'L')
+    {
+      /* Perhaps a global or local register name */
+      if (name[1] == 'r' || name[1] == 'R')
+       {
+         /* Parse the number, make sure it has no extra zeroes or trailing
+            chars */
+         regnum = atol(&name[2]);
+         if (regnum > 127)
+           return 0;
+         sprintf(testbuf, "%ld", regnum);
+         if (strcmp (testbuf, &name[2]) != 0)
+           return 0;   /* gr007 or lr7foo or whatever */
+
+         /* We have a wiener!  Define and return a new symbol for it.  */
+         if (name[0] == 'l' || name[0] == 'L')
+           regnum += 128;
+         return(symbol_new(name, SEG_REGISTER, regnum, &zero_address_frag));
+       }
+    }
+
+  return 0;
+}
+
+/* Parse an operand that is machine-specific.  */
+
+void md_operand(expressionP)
+     expressionS *expressionP;
+{
+
+  if (input_line_pointer[0] == '%' && input_line_pointer[1] == '%')
+    {
+      /* We have a numeric register expression.  No biggy.  */
+      input_line_pointer += 2; /* Skip %% */
+      (void)expression (expressionP);
+      if (expressionP->X_seg != SEG_ABSOLUTE
+         || expressionP->X_add_number > 255)
+       as_bad("Invalid expression after %%%%\n");
+      expressionP->X_seg = SEG_REGISTER;
+    }
+  else if (input_line_pointer[0] == '&')
+    {
+      /* We are taking the 'address' of a register...this one is not
+         in the manual, but it *is* in traps/fpsymbol.h!  What they
+        seem to want is the register number, as an absolute number.  */
+      input_line_pointer++;            /* Skip & */
+      (void)expression (expressionP);
+      if (expressionP->X_seg != SEG_REGISTER)
+       as_bad("Invalid register in & expression");
+      else
+        expressionP->X_seg = SEG_ABSOLUTE;
+    }
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the 29000, they're relative to the address of the instruction,
+   which we have set up as the address of the fixup too.  */
+long md_pcrel_from (fixP)
+     fixS *fixP;
+{
+  return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-a29k.c */
diff --git a/gas/config/tc-a29k.h b/gas/config/tc-a29k.h
new file mode 100644 (file)
index 0000000..e689cfc
--- /dev/null
@@ -0,0 +1,29 @@
+/* tc-a29k.h -- Assemble for the AMD 29000.
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#define TC_A29K
+
+#define tc_headers_hook(a)             ; /* not used */
+#define tc_headers_hook(a)             ; /* not used */
+#define tc_crawl_symbol_chain(a)       ; /* not used */
+#define tc_coff_symbol_emit_hook(a)    ; /* not used */
+
+/* end of tc-a29k.h */
diff --git a/gas/config/tc-generic.c b/gas/config/tc-generic.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gas/config/tc-generic.h b/gas/config/tc-generic.h
new file mode 100644 (file)
index 0000000..aa63410
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * This file is tc-generic.h and is intended to be a template for
+ * target cpu specific header files. 
+ */
+
+#define TC_GENERIC 1
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-generic.h */
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
new file mode 100644 (file)
index 0000000..cff66a4
--- /dev/null
@@ -0,0 +1,1983 @@
+/* i386.c -- Assemble code for the Intel 80386
+   Copyright (C) 1989, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/*
+  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 "as.h"
+
+#include "obstack.h"
+#include "i386-opcode.h"
+
+/* 'md_assemble ()' gathers together information and puts it into a
+   i386_insn. */
+
+typedef struct {
+  /* 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];
+
+  /* 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. */
+  seg_entry         * seg;     /* segment for memory operands (if given) */
+
+  /* PREFIX holds all the given prefix opcodes (usually null).
+     PREFIXES is the size of PREFIX. */
+  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;
+} i386_insn;
+
+char FLT_CHARS[] = "fFdDxX";
+char EXP_CHARS[] = "eE";
+char line_comment_chars[] = "#";
+char comment_chars[] = "#/";
+
+/* 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 */
+
+/*
+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
+
+#define ENCODE_RELAX_STATE(type,size) ((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},
+
+};
+
+#ifdef __STDC__
+
+static char *output_invalid(int c);
+static int i386_operand(char *operand_string);
+static reg_entry *parse_register(char *reg_string);
+
+#else /* __STDC__ */
+
+static char *output_invalid();
+static int i386_operand();
+static reg_entry *parse_register();
+
+#endif /* __STDC__ */
+
+
+/* Ignore certain directives generated by gcc. This probably should
+   not be here. */
+void dummy ()
+{
+  while (*input_line_pointer && *input_line_pointer != '\n')
+    input_line_pointer++;
+}
+
+const pseudo_typeS md_pseudo_table[] = {
+       { "ffloat",     float_cons,     'f' },
+       { "dfloat",     float_cons,     'd' },
+       { "tfloat",     float_cons,     'x' },
+       { "value",      cons,           2 },
+       { "ident",      dummy,          0   }, /* ignore these directives */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+       { "def",        dummy,          0   },
+#endif                         /* OBJ_AOUT or OBJ_BOUT */
+       { "def",        dummy,          0   },
+       { "optim",      dummy,          0   }, /* For sun386i cc */
+       { "version",    dummy,          0   },
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+       { "ln",    dummy,          0   },
+#endif                         /* OBJ_AOUT or OBJ_BOUT */
+       { "ln",    dummy,          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 = (struct hash_control *) 0;
+/* hash table for register lookup */
+static struct hash_control *reg_hash = (struct hash_control *) 0;
+/* hash table for prefix lookup */
+static struct hash_control *prefix_hash = (struct hash_control *) 0;
+
+\f
+void md_begin ()
+{
+  char * hash_err;
+
+  obstack_begin (&o,4096);
+
+  /* initialize op_hash hash table */
+  op_hash = hash_new();                /* xmalloc handles error */
+
+  {
+    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_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, regtab);
+      if (hash_err && *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, prefixtab);
+      if (hash_err && *hash_err) goto hash_error;
+    }
+  }
+
+  /* fill in lexical tables:  opcode_chars, operand_chars, space_chars */
+  {  
+    register unsigned int c;
+    
+    bzero (opcode_chars, sizeof(opcode_chars));
+    bzero (operand_chars, sizeof(operand_chars));
+    bzero (space_chars, sizeof(space_chars));
+    bzero (identifier_chars, sizeof(identifier_chars));
+    bzero (digit_chars, sizeof(digit_chars));
+
+    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;
+      else if (c && strchr(operand_special_chars, c))
+         operand_chars[c] = c;
+      
+      if (isdigit(c) || c == '-') digit_chars[c] = c;
+
+      if (isalpha(c) || c == '_' || c == '.' || isdigit(c))
+       identifier_chars[c] = c;
+
+      if (c == ' ' || c == '\t') space_chars[c] = c;
+    }
+  }
+}
+
+void md_end() {}               /* not much to do here. */
+
+\f
+#ifdef DEBUG386
+
+/* debugging routines for md_assemble */
+/* static void pi (), pte (), pt (), pe (), ps (); */
+
+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) 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, "    segment       %s\n", segment_name (e->X_seg));
+  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_subtract_symbol) {
+    fprintf (stdout, "    sub_symbol    ");
+    ps (e->X_subtract_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"},
+  { 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 */
+\f
+/*
+  This is the guts of the machine-dependent assembler.  LINE points to a
+  machine dependent instruction.  This funciton is supposed to emit
+  the frags/bytes it assembles to.
+ */
+void md_assemble (line)
+     char *line;
+{
+  /* Holds temlate once we've found it. */
+  register template * t;
+
+  /* Possible templates for current insn */
+  templates *current_templates = (templates *) 0;
+
+  /* Initialize globals. */
+  bzero (&i, sizeof(i));
+  bzero (disp_expressions, sizeof(disp_expressions));
+  bzero (im_expressions, 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. */
+  {
+    register char *l = line;           /* Fast place to put 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 balenced. */
+    unsigned int paren_not_balenced;
+    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 */
+       register unsigned int q;
+       register 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_balenced = 0;
+       while (paren_not_balenced || *l != ',') {
+         if (*l == END_OF_INSN) {
+           if (paren_not_balenced) {
+             as_bad("unbalenced parenthesis in %s operand.",
+                      ordinal_names[i.operands]);
+             return;
+           } else break;               /* we are done */
+         } else if (! is_operand_char(*l)) {
+           as_bad("invalid character %s in %s operand",
+                    output_invalid(*l),
+                    ordinal_names[i.operands]);
+           return;
+         }
+         if (*l == '(') ++paren_not_balenced;
+         if (*l == ')') --paren_not_balenced;
+         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)))
+  
+    /* 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!). */
+    bcopy (t, &i.tm, sizeof (template));
+    t = &i.tm;                 /* alter new copy of template */
+
+    /* 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 o;
+      for (o = 0; o < MAX_OPERANDS; o++)
+       if (i.types[o] & Reg) {
+         i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX :
+           (i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX :
+             DWORD_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) {
+       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) {
+      /* 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) {
+         i.regs[2] = i.regs[1]; /* Pretend we saw the 3 operand case. */
+         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 o = (i.types[0] & (Reg|FloatReg)) ? 0 : 1;
+       /* Register goes in low 3 bits of opcode. */
+       t->base_opcode |= i.regs[o]->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->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)) ? 0 : 1;
+         dest = source + 1;
+         i.rm.mode = 3;
+         /* We must be careful to make sure that all segment/control/test/
+            debug 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)) {
+           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 o = (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[o]);
+             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[o] & 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[o] |= Disp8;
+             }
+             i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
+             i.rm.regmem = EBP_REG_NUM;
+           } else if (! i.base_reg && (i.types[o] & 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[o] &= ~Disp;
+             i.types[o] |= 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[o] &= ~Disp;
+             i.types[o] |= 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[o]);
+             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[o] |= Disp8;
+                 i.rm.mode = MODE_FROM_DISP_SIZE (i.types[o]);
+               }
+             }
+           }
+           if (fake_zero_displacement) {
+             /* Fakes a zero displacement assuming that i.types[o] holds
+                the correct displacement size. */
+             exp = &disp_expressions[i.disp_operands++];
+             i.disps[o] = exp;
+             exp->X_seg = SEG_ABSOLUTE;
+             exp->X_add_number = 0;
+             exp->X_add_symbol = (symbolS *) 0;
+             exp->X_subtract_symbol = (symbolS *) 0;
+           }
+
+           /* Select the correct segment for the memory operand. */
+           if (i.seg) {
+             const unsigned int seg_index;
+             const seg_entry * default_seg;
+
+             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];
+             }
+             /* If the specified segment is not the default, use an
+                opcode prefix to select it */
+             if (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;
+             }
+           }
+         }
+
+         /* 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 registers are coded
+            into the i.rm.reg field. */
+         if (i.reg_operands) {
+           unsigned int o =
+             (i.types[0] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 0 :
+               (i.types[1] & (Reg|SReg2|SReg3|Control|Debug|Test)) ? 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[o]->reg_num;
+           else i.rm.reg = i.regs[o]->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;
+       }
+      }
+    }
+  }
+
+  /* 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) {
+      int n = i.disps[0]->X_add_number;
+      
+      switch (i.disps[0]->X_seg) {
+      case SEG_ABSOLUTE:
+       if (FITS_IN_SIGNED_BYTE (n)) {
+         p = frag_more (2);
+         p[0] = t->base_opcode;
+         p[1] = n;
+#if 0 /* leave out 16 bit jumps - pace */
+       } else if (FITS_IN_SIGNED_WORD (n)) {
+         p = frag_more (4);
+         p[0] = WORD_PREFIX_OPCODE;
+         p[1] = t->base_opcode;
+         md_number_to_chars (&p[2], n, 2);
+#endif
+       } else {                /* It's an absolute dword displacement. */
+         if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */
+           /* unconditional jump */
+           p = frag_more (5);
+           p[0] = 0xe9;
+           md_number_to_chars (&p[1], n, 4);
+         } else {
+           /* conditional jump */
+           p = frag_more (6);
+           p[0] = TWO_BYTE_OPCODE_ESCAPE;
+           p[1] = t->base_opcode + 0x10;
+           md_number_to_chars (&p[2], n, 4);
+         }
+       }
+       break;
+      default:
+       /* It's a symbol; end frag & setup for relax.
+          Make sure there are 6 chars left in the current frag; if not
+          we'll have to start a new one. */
+       /* I caught it failing with obstack_room == 6,
+          so I changed to <=   pace */
+       if (obstack_room (&frags) <= 6) {
+               frag_wane(frag_now);
+               frag_new (0);
+       }
+       p = frag_more (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,
+                 n, p);
+       break;
+      }
+    } else if (t->opcode_modifier & (JumpByte|JumpDword)) {
+      int size = (t->opcode_modifier & JumpByte) ? 1 : 4;
+      int n = i.disps[0]->X_add_number;
+      
+      if (FITS_IN_UNSIGNED_BYTE(t->base_opcode)) {
+       FRAG_APPEND_1_CHAR (t->base_opcode);
+      } else {
+       p = frag_more (2);      /* opcode can be at most two bytes */
+       /* 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);
+      switch (i.disps[0]->X_seg) {
+      case SEG_ABSOLUTE:
+       md_number_to_chars (p, n, size);
+       if (size == 1 && ! FITS_IN_SIGNED_BYTE (n)) {
+         as_bad("loop/jecx only takes byte displacement; %d shortened to %d",
+                  n, *p);
+       }
+       break;
+      default:
+       fix_new (frag_now, p - frag_now->fr_literal, size,
+                i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
+                i.disps[0]->X_add_number, 1, NO_RELOC);
+       break;
+      }
+    } else if (t->opcode_modifier & JumpInterSegment) {
+      p =  frag_more (1 + 2 + 4);      /* 1 opcode; 2 segment; 4 offset */
+      p[0] = t->base_opcode;
+      if (i.imms[1]->X_seg == SEG_ABSOLUTE)
+       md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4);
+      else
+       fix_new (frag_now, p + 1 -  frag_now->fr_literal, 4,
+                i.imms[1]->X_add_symbol,
+                i.imms[1]->X_subtract_symbol,
+                i.imms[1]->X_add_number, 0, NO_RELOC);
+      if (i.imms[0]->X_seg != SEG_ABSOLUTE)
+       as_bad("can't handle non absolute segment in long call/jmp");
+      md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2);
+    } else {
+      /* Output normal instructions here. */
+      register char *q;
+      
+      /* First the prefix bytes. */
+      for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
+       p =  frag_more (1);
+       md_number_to_chars (p, (unsigned int) *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);
+      } else if (FITS_IN_UNSIGNED_WORD(t->base_opcode)) {
+       p =  frag_more (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);
+         *p++ = (t->base_opcode >> 24) & 0xff;
+       } else p = frag_more (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);
+       /* md_number_to_chars (p, i.rm, 1); */
+       md_number_to_chars (p, (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);
+         /* md_number_to_chars (p, i.bi, 1); */
+         md_number_to_chars (p,(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_seg == SEG_ABSOLUTE) {
+             if (i.types[n] & (Disp8|Abs8)) {
+               p =  frag_more (1);
+               md_number_to_chars (p, i.disps[n]->X_add_number, 1);
+             } else if (i.types[n] & (Disp16|Abs16)) {
+               p =  frag_more (2);
+               md_number_to_chars (p, i.disps[n]->X_add_number, 2);
+             } else {          /* Disp32|Abs32 */
+               p =  frag_more (4);
+               md_number_to_chars (p, i.disps[n]->X_add_number, 4);
+             }
+           } else {                    /* not SEG_ABSOLUTE */
+             /* need a 32-bit fixup (don't support 8bit non-absolute disps) */
+             p =  frag_more (4);
+             fix_new (frag_now, p -  frag_now->fr_literal, 4,
+                      i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol,
+                      i.disps[n]->X_add_number, 0, NO_RELOC);
+           }
+         }
+       }
+      }                                /* 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_seg == SEG_ABSOLUTE) {
+             if (i.types[n] & (Imm8|Imm8S)) {
+               p =  frag_more (1);
+               md_number_to_chars (p, i.imms[n]->X_add_number, 1);
+             } else if (i.types[n] & Imm16) {
+               p =  frag_more (2);
+               md_number_to_chars (p, i.imms[n]->X_add_number, 2);
+             } else {
+               p =  frag_more (4);
+               md_number_to_chars (p, i.imms[n]->X_add_number, 4);
+             }
+           } else {                    /* not SEG_ABSOLUTE */
+             /* need a 32-bit fixup (don't support 8bit non-absolute ims) */
+             /* try to support other sizes ... */
+             int size;
+             if (i.types[n] & (Imm8|Imm8S))
+               size = 1;
+             else if (i.types[n] & Imm16)
+               size = 2;
+             else
+               size = 4;
+             p = frag_more (size);
+             fix_new (frag_now, p - frag_now->fr_literal, size,
+                      i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol,
+                      i.imms[n]->X_add_number, 0, NO_RELOC);
+           }
+         }
+       }
+      }                                /* end immediate output */
+    }
+
+#ifdef DEBUG386
+    if (flagseen ['D']) {
+      pi (line, &i);
+    }
+#endif /* DEBUG386 */
+
+  }
+  return;
+}
+\f
+/* 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 = 0;
+  char * displacement_string_end;
+
+  /* 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 = &es; break;
+      case 1:
+       i.seg = &cs; break;
+      case 2:
+       i.seg = &ss; break;
+      case 3:
+       i.seg = &ds; break;
+      case 4:
+       i.seg = &fs; break;
+      case 5:
+       i.seg = &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;
+    register expressionS *exp;
+    segT exp_seg;
+    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! */
+    exp_seg = expression (exp);
+    input_line_pointer = save_input_line_pointer;
+    switch (exp_seg) {
+    case SEG_ABSENT:    /* missing or bad expr becomes absolute 0 */
+      as_bad("missing or invalid immediate expression '%s' taken as 0",
+              operand_string);
+      exp->X_seg = SEG_ABSOLUTE;
+      exp->X_add_number = 0;
+      exp->X_add_symbol = (symbolS *) 0;
+      exp->X_subtract_symbol = (symbolS *) 0;
+      i.types[this_operand] |= Imm;
+      break;
+    case SEG_ABSOLUTE:
+      i.types[this_operand] |= SMALLEST_IMM_TYPE (exp->X_add_number);
+      break;
+    case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN:
+      i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */
+      break;
+    default:
+seg_unimplemented:
+      as_bad("Unimplemented segment type %d in parse_operand", exp_seg);
+      return 0;
+    }
+    /* 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_balenced = 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_balenced++;
+       if (*base_string == '(') parens_balenced--;
+      } while (parens_balenced);
+      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;
+      char * save_input_line_pointer;
+      exp = &disp_expressions[i.disp_operands];
+      i.disps [this_operand] = exp;
+      i.disp_operands++;
+      save_input_line_pointer = input_line_pointer;
+      input_line_pointer = displacement_string_start;
+      END_STRING_AND_SAVE (displacement_string_end);
+      exp_seg = expression (exp);
+      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;
+      switch (exp_seg) {
+      case SEG_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_seg = SEG_ABSOLUTE;
+       exp->X_add_number = 0;
+       exp->X_add_symbol = (symbolS *) 0;
+       exp->X_subtract_symbol = (symbolS *) 0;
+       break;
+      case SEG_ABSOLUTE:
+       i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
+       break;
+      case SEG_TEXT: case SEG_DATA: case SEG_BSS:
+      case SEG_UNKNOWN:        /* must be 32 bit displacement (i.e. address) */
+       i.types[this_operand] |= Disp32;
+       break;
+      default:
+       goto seg_unimplemented;
+      }
+    }
+
+    /* 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;
+    }
+    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 */
+}
+\f
+/*
+ *                     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,
+              (symbolS *) 0,
+              fragP -> fr_offset, 1, NO_RELOC);
+      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,
+              (symbolS *) 0,
+              fragP -> fr_offset, 1, NO_RELOC);
+      break;
+    }
+    frag_wane (fragP);
+  }
+  return (fragP -> fr_var + fragP -> fr_fix - old_fr_fix);
+}                              /* md_estimate_size_before_relax() */
+\f
+/*
+ *                     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".
+ */
+void
+md_convert_frag (fragP)
+     register fragS *  fragP;
+{
+  register unsigned char * opcode;
+  unsigned char * where_to_put_displacement;
+  unsigned int target_address, opcode_address;
+  unsigned int extension;
+  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;
+
+  /* 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 (where_to_put_displacement,
+                     displacement_from_opcode_start - extension,
+                     SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
+  fragP -> fr_fix += extension;
+}
+
+\f
+int md_short_jump_size = 2;    /* size of byte displacement jmp */
+int md_long_jump_size  = 5;    /* size of dword displacement jmp */
+int md_reloc_size = 8;         /* Size of relocation record */
+
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+     char      *ptr;
+     long      from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+  long offset;
+
+  offset = to_addr - (from_addr + 2);
+  md_number_to_chars (ptr, (long) 0xeb, 1); /* opcode for byte-disp jump */
+  md_number_to_chars (ptr + 1, offset, 1);
+}
+
+void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char      *ptr;
+     long      from_addr, to_addr;
+     fragS     *frag;
+     symbolS   *to_symbol;
+{
+  long offset;
+
+  if (flagseen['m']) {
+    offset = to_addr - S_GET_VALUE(to_symbol);
+    md_number_to_chars (ptr, 0xe9, 1); /* opcode for long jmp */
+    md_number_to_chars (ptr + 1, offset, 4);
+    fix_new (frag, (ptr+1) - frag->fr_literal, 4,
+            to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC);
+  } else {
+    offset = to_addr - (from_addr + 5);
+    md_number_to_chars(ptr, (long) 0xe9, 1);
+    md_number_to_chars(ptr + 1, offset, 4);
+  }
+}
+\f
+int
+md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+       return 1;
+}
+\f
+void                           /* Knows about order of bytes in address. */
+md_number_to_chars (con, value, nbytes)
+     char      con []; /* Return 'nbytes' of chars here. */
+     long      value;          /* The value of the bits. */
+     int       nbytes;         /* Number of bytes in the output. */
+{
+  register char * p = con;
+
+  switch (nbytes) {
+  case 1:
+    p[0] = value & 0xff;
+    break;
+  case 2:
+    p[0] = value & 0xff;
+    p[1] = (value >> 8) & 0xff;
+    break;
+  case 4:
+    p[0] = value & 0xff;
+    p[1] = (value>>8) & 0xff;
+    p[2] = (value>>16) & 0xff;
+    p[3] = (value>>24) & 0xff;
+    break;
+  default:
+    BAD_CASE (nbytes);
+  }
+}
+
+
+/* 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.  */
+
+void
+md_apply_fix (fixP, value)
+     fixS * fixP;              /* The fix we're to put in */
+     long      value;          /* The value of the bits. */
+{
+  register char * p = fixP->fx_where + fixP->fx_frag->fr_literal;
+  switch (fixP->fx_size) {
+  case 1:
+    *p = value;
+    break;
+  case 2:
+    *p++ = value;
+    *p = (value>>8);
+    break;
+  case 4:
+    *p++ = value;
+    *p++ = (value>>8);
+    *p++ = (value>>16);
+    *p = (value>>24);
+    break;
+  default:
+    BAD_CASE (fixP->fx_size);
+  }
+}
+
+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;
+}
+
+/* Not needed for coff since relocation structure does not 
+   contain bitfields. */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+/* Output relocation information in the target's format.  */
+void
+md_ri_to_chars(the_bytes, ri)
+     char *the_bytes;
+     struct reloc_info_generic *ri;
+{
+  /* this is easy */
+  md_number_to_chars(the_bytes, ri->r_address, 4);
+  /* now the fun stuff */
+  the_bytes[6] = (ri->r_symbolnum >> 16) & 0x0ff;
+  the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+  the_bytes[4] = ri->r_symbolnum & 0x0ff;
+  the_bytes[7] = (((ri->r_extern << 3)  & 0x08) | ((ri->r_length << 1) & 0x06) | 
+    ((ri->r_pcrel << 0)  & 0x01)) & 0x0F; 
+}
+#endif                         /* OBJ_AOUT or OBJ_BOUT */
+
+\f
+#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, (long) (*wordP--), sizeof(LITTLENUM_TYPE));
+    litP += sizeof(LITTLENUM_TYPE);
+  }
+  return "";   /* Someone should teach Dean about null pointers */
+}
+\f
+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;
+}
+
+static reg_entry *parse_register (reg_string)
+    char *reg_string;          /* reg_string starts *before* REGISTER_PREFIX */
+{
+  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 [*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);
+}
+
+
+/* We have no need to default values of symbols.  */
+
+/* ARGSUSED */
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}
+
+/* Parse an operand that is machine-specific.  
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* 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;
+}
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:16:41  rich
+ * Initial revision
+ *
+ * Revision 1.2  1991/03/30  17:11:30  rich
+ * Updated md_create_short_jump calling protocol.
+ *
+ *
+ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-i386.c */
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
new file mode 100644 (file)
index 0000000..a2b853e
--- /dev/null
@@ -0,0 +1,247 @@
+/* i386.h -- Header file for i386.c
+   Copyright (C) 1989, 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+#define TC_I386 1
+
+#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 4         /* 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
+
+/* 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 MODE_FROM_DISP_SIZE(t) \
+      ((t&(Disp8)) ? 1 : \
+       ((t&(Disp32)) ? 2 : 0))
+
+#define Byte (Reg8|Imm8|Imm8S)
+#define Word (Reg16|Imm16)
+#define DWord (Reg32|Imm32)
+
+/* convert opcode suffix ('b' 'w' 'l' typically) into type specifyer */
+#define OPCODE_SUFFIX_TO_TYPE(s)                 \
+  (s == BYTE_OPCODE_SUFFIX ? Byte : \
+   (s == WORD_OPCODE_SUFFIX ? Word : DWord))
+
+#define FITS_IN_SIGNED_BYTE(num) ((num) >= -128 && (num) <= 127)
+#define FITS_IN_UNSIGNED_BYTE(num) ((num) >= 0 && (num) <= 255)
+#define FITS_IN_UNSIGNED_WORD(num) ((num) >= 0 && (num) <= 65535)
+#define FITS_IN_SIGNED_WORD(num) ((num) >= -32768 && (num) <= 32767)
+
+#define SMALLEST_DISP_TYPE(num) \
+  FITS_IN_SIGNED_BYTE(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32)
+
+#define SMALLEST_IMM_TYPE(num) \
+  (num == 1) ? (Imm1|Imm8|Imm8S|Imm16|Imm32): \
+  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)
+
+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
+
+  /* (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;
+
+/* end of tc-i386.h */
diff --git a/gas/config/tc-i860.c b/gas/config/tc-i860.c
new file mode 100644 (file)
index 0000000..d9dd84c
--- /dev/null
@@ -0,0 +1,1255 @@
+/* i860.c -- Assemble for the I860
+   Copyright (C) 1989 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+#include "as.h"
+
+#include "i860-opcode.h"
+
+/* incorporated from i860.h */
+enum reloc_type /* NOTE: three bits max, see struct reloc_info_i860.r_type */
+{
+    NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32,
+};
+      
+enum highlow_type       /* NOTE: two bits max, see reloc_info_i860.r_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;
+};
+
+#define relocation_info reloc_info_i860
+
+
+void md_begin();
+void md_end();
+void md_number_to_chars();
+void md_assemble();
+char *md_atof();
+void md_convert_frag();
+void md_create_short_jump();
+void md_create_long_jump();
+int  md_estimate_size_before_relax();
+void md_number_to_imm();
+void md_number_to_disp();
+void md_number_to_field();
+void md_ri_to_chars();
+static void i860_ip();
+void emit_machine_reloc();
+
+int md_reloc_size = sizeof(struct relocation_info);
+
+void (*md_emit_relocations)() = emit_machine_reloc;
+
+const relax_typeS md_relax_table[] = { 0 };
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+static void s_dual(), s_enddual();
+static void s_atmp();
+
+const pseudo_typeS
+md_pseudo_table[] = {
+    { "dual",       s_dual,     4 },
+    { "enddual",    s_enddual,  4 },
+    { "atmp",      s_atmp,     4 },
+    { NULL,         0,          0 },
+};
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+
+/* This array holds the chars that always start a comment.  If the
+    pre-processor is disabled, these aren't very useful */
+char comment_chars[] = "!/";   /* JF removed '|' from comment_chars */
+
+/* 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 like this one will always work. */
+char line_comment_chars[] = "#/";
+
+/* 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";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+ */
+int size_reloc_info = sizeof(struct relocation_info);
+
+static unsigned char octal[256];
+#define isoctal(c)  octal[c]
+static unsigned char toHex[256];
+
+struct i860_it {
+    char    *error;
+    unsigned long opcode;
+    struct nlist *nlistp;
+    expressionS exp;
+    int pcrel;
+    enum expand_type expand;
+    enum highlow_type highlow;
+    enum reloc_type reloc;
+} the_insn;
+
+#ifdef __STDC__
+static void print_insn(struct i860_it *insn);
+static int getExpression(char *str);
+#else
+static void print_insn();
+static int getExpression();
+#endif
+static char *expr_end;
+static char last_expand;       /* error if expansion after branch */
+
+enum dual
+{
+    DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT,
+};
+static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */
+
+static void
+s_dual()       /* floating point instructions have dual set */
+{
+    dual_mode = DUAL_ON;
+}
+
+static void
+s_enddual()    /* floating point instructions have dual set */
+{
+    dual_mode = DUAL_OFF;
+}
+
+static int atmp = 31; /* temporary register for pseudo's */
+
+static void
+s_atmp()
+{
+    register int temp;
+    if (strncmp(input_line_pointer, "sp", 2) == 0) {
+      input_line_pointer += 2;
+      atmp = 2;
+    }
+    else if (strncmp(input_line_pointer, "fp", 2) == 0) {
+      input_line_pointer += 2;
+      atmp = 3;
+    }
+    else if (strncmp(input_line_pointer, "r", 1) == 0) {
+      input_line_pointer += 1;
+      temp = get_absolute_expression();
+      if (temp >= 0 && temp <= 31)
+          atmp = temp;
+        else
+            as_bad("Unknown temporary pseudo register");
+    }
+    else {
+        as_bad("Unknown temporary pseudo register");
+    }
+    demand_empty_rest_of_line();
+    return;
+}
+
+/* This function is called once, at assembler startup time.  It should
+   set up all the tables, etc. that the MD part of the assembler will need.  */
+void
+md_begin()
+{
+  register char *retval = NULL;
+  int lose = 0;
+  register unsigned int i = 0;
+
+  op_hash = hash_new();
+  if (op_hash == NULL)
+    as_fatal("Virtual memory exhausted");
+
+  while (i < NUMOPCODES)
+    {
+      const char *name = i860_opcodes[i].name;
+      retval = hash_insert(op_hash, name, &i860_opcodes[i]);
+      if(retval != NULL && *retval != '\0')
+       {
+         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                  i860_opcodes[i].name, retval);
+         lose = 1;
+       }
+      do
+       {
+         if (i860_opcodes[i].match & i860_opcodes[i].lose)
+           {
+             fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+                      i860_opcodes[i].name, i860_opcodes[i].args);
+             lose = 1;
+           }
+         ++i;
+       } while (i < NUMOPCODES
+                && !strcmp(i860_opcodes[i].name, name));
+    }
+
+  if (lose)
+    as_fatal("Broken assembler.  No assembly attempted.");
+
+  for (i = '0'; i < '8'; ++i)
+    octal[i] = 1;
+  for (i = '0'; i <= '9'; ++i)
+    toHex[i] = i - '0';
+  for (i = 'a'; i <= 'f'; ++i)
+    toHex[i] = i + 10 - 'a';
+  for (i = 'A'; i <= 'F'; ++i)
+    toHex[i] = i + 10 - 'A';
+}
+
+void
+md_end()
+{
+    return;
+}
+
+void
+md_assemble(str)
+    char *str;
+{
+    char *toP;
+    int rsd;
+    int no_opcodes = 1;
+    int i;
+    struct i860_it pseudo[3];
+
+    assert(str);
+    i860_ip(str);
+
+    /* check for expandable flag to produce pseudo-instructions */
+    if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) {
+       for (i = 0; i < 3; i++)
+           pseudo[i] = the_insn;
+
+       switch (the_insn.expand) {
+
+       case E_DELAY:
+               no_opcodes = 1;
+               break;
+
+       case E_MOV:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 15) &&
+                the_insn.exp.X_add_number >= -(1 << 15)))
+               break;
+           /* or l%const,r0,ireg_dest */
+           pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000;
+           pseudo[0].highlow = PAIR;
+           /* orh h%const,ireg_dest,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 |
+               ((the_insn.opcode & 0x001f0000) << 5);
+           pseudo[1].highlow = HIGH;
+           no_opcodes = 2;
+           break;
+
+       case E_ADDR:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL)
+               break;
+           /* orh ha%addr_expr,r0,r31 */
+           pseudo[0].opcode = 0xec000000 | (atmp<<16);
+           pseudo[0].highlow = HIGHADJ;
+           pseudo[0].reloc = LOW0;     /* must overwrite */
+           /* l%addr_expr(r31),ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           no_opcodes = 2;
+           break;
+
+       case E_U32:     /* 2nd version emulates Intel as, not doc. */
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 16) &&
+                the_insn.exp.X_add_number >= 0))
+               break;
+           /* $(opcode)h h%const,ireg_src2,ireg_dest
+           pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */
+           /* $(opcode)h h%const,ireg_src2,r31 */
+           pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 |
+               (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           /* $(opcode) l%const,ireg_dest,ireg_dest
+           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+               ((the_insn.opcode & 0x001f0000) << 5); */
+           /* $(opcode) l%const,r31,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 |
+               (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           no_opcodes = 2;
+           break;
+
+       case E_AND:     /* 2nd version emulates Intel as, not doc. */
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 16) &&
+                the_insn.exp.X_add_number >= 0))
+               break;
+           /* andnot h%const,ireg_src2,ireg_dest
+           pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */
+           /* andnot h%const,ireg_src2,r31 */
+           pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 |
+               (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+           /* andnot l%const,ireg_dest,ireg_dest
+           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+               ((the_insn.opcode & 0x001f0000) << 5); */
+           /* andnot l%const,r31,ireg_dest */
+           pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 |
+               (atmp << 21);
+           pseudo[1].highlow = PAIR;
+           pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number;
+           no_opcodes = 2;
+           break;
+
+       case E_S32:
+           if (the_insn.exp.X_add_symbol == NULL &&
+               the_insn.exp.X_subtract_symbol == NULL &&
+               (the_insn.exp.X_add_number < (1 << 15) &&
+                the_insn.exp.X_add_number >= -(1 << 15)))
+               break;
+           /* orh h%const,r0,r31 */
+           pseudo[0].opcode = 0xec000000 | (atmp << 16);
+           pseudo[0].highlow = HIGH;
+           /* or l%const,r31,r31 */
+           pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16);
+           pseudo[1].highlow = PAIR;
+           /* r31,ireg_src2,ireg_dest */
+           pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11);
+           pseudo[2].reloc = NO_RELOC;
+           no_opcodes = 3;
+           break;
+
+       default:
+           abort();
+       }
+
+        the_insn = pseudo[0];
+       /* check for expanded opcode after branch or in dual */
+       if (no_opcodes > 1 && last_expand == 1)
+           as_warn("Expanded opcode after delayed branch: `%s'", str);
+       if (no_opcodes > 1 && dual_mode != DUAL_OFF)
+           as_warn("Expanded opcode in dual mode: `%s'", str);
+    }
+
+    i = 0;
+    do {       /* always produce at least one opcode */
+        toP = frag_more(4);
+        /* put out the opcode */
+        md_number_to_chars(toP, the_insn.opcode, 4);
+
+       /* check for expanded opcode after branch or in dual */
+       last_expand = the_insn.pcrel;
+
+        /* put out the symbol-dependent stuff */
+        if (the_insn.reloc != NO_RELOC) {
+           fix_new(
+               frag_now,                           /* which frag */
+               (toP - frag_now->fr_literal), /* where */
+               4,                                  /* size */
+               the_insn.exp.X_add_symbol,
+               the_insn.exp.X_subtract_symbol,
+               the_insn.exp.X_add_number,
+               the_insn.pcrel,
+               /* merge bit fields into one argument */
+               (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))
+           );
+        }
+        the_insn = pseudo[++i];
+    } while (--no_opcodes > 0);
+
+}
+
+static void
+i860_ip(str)
+    char *str;
+{
+    char *s;
+    const char *args;
+    char c;
+    unsigned long i;
+    struct i860_opcode *insn;
+    char *argsStart;
+    unsigned long   opcode;
+    unsigned int mask;
+    int match = 0;
+    int comma = 0;
+
+
+    for (s = str; islower(*s) || *s == '.' || *s == '3'; ++s)
+       ;
+    switch (*s) {
+
+    case '\0':
+       break;
+
+    case ',':
+       comma = 1;
+
+       /*FALLTHROUGH*/
+
+    case ' ':
+       *s++ = '\0';
+       break;
+
+    default:
+           as_bad("Unknown opcode: `%s'", str);
+           exit(1);
+    }
+
+    if (strncmp(str, "d.", 2) == 0) {  /* check for d. opcode prefix */
+       if (dual_mode == DUAL_ON)
+           dual_mode = DUAL_ONDDOT;
+       else
+           dual_mode = DUAL_DDOT;
+       str += 2;
+    }
+
+    if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) {
+       if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT)
+           str -= 2;
+       as_bad("Unknown opcode: `%s'", str);
+       return;
+    }
+    if (comma) {
+       *--s = ',';
+    }
+    argsStart = s;
+    for (;;) {
+       opcode = insn->match;
+       bzero(&the_insn, sizeof(the_insn));
+       the_insn.reloc = NO_RELOC;
+
+       /*
+        * Build the opcode, checking as we go to make
+        * sure that the operands match
+        */
+       for (args = insn->args; ; ++args) {
+           switch (*args) {
+
+           case '\0':  /* end of args */
+               if (*s == '\0') {
+                   match = 1;
+               }
+               break;
+
+           case '+':
+           case '(':   /* these must match exactly */
+           case ')':
+           case ',':
+           case ' ':
+               if (*s++ == *args)
+                   continue;
+               break;
+
+           case '#':   /* must be at least one digit */
+               if (isdigit(*s++)) {
+                   while (isdigit(*s)) {
+                       ++s;
+                   }
+                   continue;
+               }
+               break;
+
+           case '1':   /* next operand must be a register */
+           case '2':
+           case 'd':
+               switch (*s) {
+
+               case 'f':   /* frame pointer */
+                   s++;
+                   if (*s++ == 'p') {
+                       mask = 0x3;
+                       break;
+                   }
+                   goto error;
+
+               case 's':   /* stack pointer */
+                   s++;
+                   if (*s++ == 'p') {
+                       mask= 0x2;
+                       break;
+                   }
+                   goto error;
+
+               case 'r': /* any register */
+                   s++;
+                   if (!isdigit(c = *s++)) {
+                       goto error;
+                   }
+                   if (isdigit(*s)) {
+                       if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
+                           goto error;
+                       }
+                   } else {
+                       c -= '0';
+                   }
+                   mask= c;
+                   break;
+
+               default:        /* not this opcode */
+                   goto error;
+               }
+               /*
+                * Got the register, now figure out where
+                * it goes in the opcode.
+                */
+               switch (*args) {
+
+               case '1':
+                   opcode |= mask << 11;
+                   continue;
+
+               case '2':
+                   opcode |= mask << 21;
+                   continue;
+
+               case 'd':
+                   opcode |= mask << 16;
+                   continue;
+
+               }
+               break;
+
+           case 'e':    /* next operand is a floating point register */
+           case 'f':
+           case 'g':
+               if (*s++ == 'f' && isdigit(*s)) {
+                   mask = *s++;
+                   if (isdigit(*s)) {
+                       mask = 10 * (mask - '0') + (*s++ - '0');
+                       if (mask >= 32) {
+                           break;
+                       }
+                   } else {
+                       mask -= '0';
+                   }
+                   switch (*args) {
+
+                   case 'e':
+                       opcode |= mask << 11;
+                       continue;
+
+                   case 'f':
+                       opcode |= mask << 21;
+                       continue;
+
+                   case 'g':
+                       opcode |= mask << 16;
+                       if (dual_mode != DUAL_OFF)
+                           opcode |= (1 << 9); /* dual mode instruction */
+                       if (dual_mode == DUAL_DDOT)
+                           dual_mode = DUAL_OFF;
+                       if (dual_mode == DUAL_ONDDOT)
+                           dual_mode = DUAL_ON;
+                       if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f)))
+                           as_warn("Fsr1 equals fdest with Pipelining");
+                       continue;
+                   }
+               }
+               break;
+
+           case 'c': /* next operand must be a control register */
+               if (strncmp(s, "fir", 3) == 0) {
+                   opcode |= 0x0 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "psr", 3) == 0) {
+                   opcode |= 0x1 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "dirbase", 7) == 0) {
+                   opcode |= 0x2 << 21;
+                   s += 7;
+                   continue;
+               }
+               if (strncmp(s, "db", 2) == 0) {
+                   opcode |= 0x3 << 21;
+                   s += 2;
+                   continue;
+               }
+               if (strncmp(s, "fsr", 3) == 0) {
+                   opcode |= 0x4 << 21;
+                   s += 3;
+                   continue;
+               }
+               if (strncmp(s, "epsr", 4) == 0) {
+                   opcode |= 0x5 << 21;
+                   s += 4;
+                   continue;
+               }
+               break;
+
+           case '5':   /* 5 bit immediate in src1 */
+               bzero(&the_insn, sizeof(the_insn));
+               if ( !getExpression(s)) {
+                   s = expr_end;
+                   if (the_insn.exp.X_add_number & ~0x1f)
+                       as_bad("5-bit immediate too large");
+                   opcode |= (the_insn.exp.X_add_number & 0x1f) << 11;
+                   bzero(&the_insn, sizeof(the_insn));
+                   the_insn.reloc = NO_RELOC;
+                   continue;
+               }
+               break;
+
+           case 'l':   /* 26 bit immediate, relative branch */
+               the_insn.reloc = BRADDR;
+               the_insn.pcrel = 1;
+               goto immediate;
+
+           case 's':   /* 16 bit immediate, split relative branch */
+                       /* upper 5 bits of offset in dest field */
+               the_insn.pcrel = 1;
+               the_insn.reloc = SPLIT0;
+               goto immediate;
+
+           case 'S':   /* 16 bit immediate, split (st), aligned */
+               if (opcode & (1 << 28))
+                   if (opcode & 0x1)
+                       the_insn.reloc = SPLIT2;
+                   else
+                       the_insn.reloc = SPLIT1;
+               else
+                   the_insn.reloc = SPLIT0;
+               goto immediate;
+
+           case 'I':   /* 16 bit immediate, aligned */
+               if (opcode & (1 << 28))
+                   if (opcode & 0x1)
+                       the_insn.reloc = LOW2;
+                   else
+                       the_insn.reloc = LOW1;
+               else
+                   the_insn.reloc = LOW0;
+               goto immediate;
+
+           case 'i':   /* 16 bit immediate */
+               the_insn.reloc = LOW0;
+
+               /*FALLTHROUGH*/
+
+           immediate:
+               if(*s==' ')
+                 s++;
+               if (strncmp(s, "ha%", 3) == 0) {
+                   the_insn.highlow = HIGHADJ;
+                   s += 3;
+               } else if (strncmp(s, "h%", 2) == 0) {
+                   the_insn.highlow = HIGH;
+                   s += 2;
+               } else if (strncmp(s, "l%", 2) == 0) {
+                   the_insn.highlow = PAIR;
+                   s += 2;
+               }
+               the_insn.expand = insn->expand; 
+
+               /* Note that if the getExpression() fails, we will still have
+                  created U entries in the symbol table for the 'symbols'
+                  in the input string.  Try not to create U symbols for
+                  registers, etc. */
+
+               if ( !getExpression(s)) {
+                   s = expr_end;
+                   continue;
+               }
+               break;
+
+           default:
+               abort();
+           }
+           break;
+       }
+       error:
+       if (match == 0)
+         {
+           /* Args don't match.  */
+           if (&insn[1] - i860_opcodes < NUMOPCODES
+               && !strcmp(insn->name, insn[1].name))
+             {
+               ++insn;
+               s = argsStart;
+               continue;
+             }
+           else
+             {
+               as_bad("Illegal operands");
+               return;
+             }
+         }
+       break;
+    }
+
+    the_insn.opcode = opcode;
+    return;
+}
+
+static int
+getExpression(str)
+    char *str;
+{
+    char *save_in;
+    segT seg;
+
+    save_in = input_line_pointer;
+    input_line_pointer = str;
+    switch (seg = expression(&the_insn.exp)) {
+
+    case SEG_ABSOLUTE:
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+    case SEG_DIFFERENCE:
+    case SEG_BIG:
+    case SEG_ABSENT:
+       break;
+
+    default:
+       the_insn.error = "bad segment";
+       expr_end = input_line_pointer;
+       input_line_pointer=save_in;
+       return 1;
+    }
+    expr_end = input_line_pointer;
+    input_line_pointer = save_in;
+    return 0;
+}
+
+
+/*
+    This is identical to the md_atof in m68k.c.  I think this is right,
+    but I'm not sure.
+
+   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
+
+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 ""; /* Someone should teach Dean about null pointers */
+}
+
+/*
+ * Write out big-endian.
+ */
+void
+md_number_to_chars(buf,val,n)
+    char *buf;
+    long val;
+    int n;
+{
+    switch(n) {
+
+    case 4:
+       *buf++ = val >> 24;
+       *buf++ = val >> 16;
+    case 2:
+       *buf++ = val >> 8;
+    case 1:
+       *buf = val;
+       break;
+
+    default:
+       abort();
+    }
+    return;
+}
+
+void md_number_to_imm(buf,val,n, fixP)
+    char *buf;
+    long val;
+    int n;
+    fixS *fixP;
+{
+    enum reloc_type reloc = fixP->fx_r_type & 0xf;
+    enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3;
+
+    assert(buf);
+    assert(n == 4);    /* always on i860 */
+
+    switch(highlow)
+    {
+
+    case HIGHADJ:      /* adjusts the high-order 16-bits */
+       if (val & (1 << 15))
+           val += (1 << 16);
+
+           /*FALLTHROUGH*/
+
+    case HIGH: /* selects the high-order 16-bits */
+       val >>= 16;
+       break;
+
+    case PAIR: /* selects the low-order 16-bits */
+       val = val & 0xffff;
+       break;
+
+    default:
+       break;
+    }
+
+    switch(reloc)
+    {
+
+    case BRADDR:       /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */
+       if (fixP->fx_pcrel != 1)
+           as_bad("26-bit branch w/o pc relative set: 0x%08x", val);
+       val >>= 2;      /* align pcrel offset, see manual */
+
+       if (val >= (1 << 25) || val < -(1 << 25))       /* check for overflow */
+           as_bad("26-bit branch offset overflow: 0x%08x", val);
+       buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3);
+       buf[1] = val >> 16;
+       buf[2] = val >> 8;
+       buf[3] = val;
+       break;
+
+    case SPLIT2:       /* 16 bit immediate, 4-byte aligned */
+       if (val & 0x3)
+           as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
+       val &= ~0x3;    /* 4-byte align value */
+       /*FALLTHROUGH*/
+    case SPLIT1:       /* 16 bit immediate, 2-byte aligned */
+       if (val & 0x1)
+           as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
+       val &= ~0x1;    /* 2-byte align value */
+       /*FALLTHROUGH*/
+    case SPLIT0:       /* st,bla,bte,btne w/16-bit immediate */
+       if (fixP->fx_pcrel == 1)
+           val >>= 2;  /* align pcrel offset, see manual */
+       /* check for bounds */
+       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+           as_bad("16-bit branch offset overflow: 0x%08x", val);
+       buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f);
+       buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7);
+       buf[3] |= val;  /* perserve bottom opcode bits */       
+       break;
+
+    case LOW4: /* fld,pfld,pst,flush 16-byte aligned */
+       if (val & 0xf)
+           as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val);
+       val &= ~0xf;    /* 16-byte align value */
+       /*FALLTHROUGH*/
+    case LOW3: /* fld,pfld,pst,flush 8-byte aligned */
+       if (val & 0x7)
+           as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val);
+       val &= ~0x7;    /* 8-byte align value */
+       /*FALLTHROUGH*/
+    case LOW2: /* 16 bit immediate, 4-byte aligned */
+       if (val & 0x3)
+           as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val);
+       val &= ~0x3;    /* 4-byte align value */
+       /*FALLTHROUGH*/
+    case LOW1: /* 16 bit immediate, 2-byte aligned */
+       if (val & 0x1)
+           as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val);
+       val &= ~0x1;    /* 2-byte align value */
+       /*FALLTHROUGH*/
+    case LOW0: /* 16 bit immediate, byte aligned */
+       /* check for bounds */
+       if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15)))
+           as_bad("16-bit immediate overflow: 0x%08x", val);
+       buf[2] = val >> 8;
+       buf[3] |= val;  /* perserve bottom opcode bits */       
+       break;
+
+    case NO_RELOC:
+    default:
+       as_bad("bad relocation type: 0x%02x", reloc);
+       break;
+    }
+    return;
+}
+
+/* should never be called for i860 */
+void
+md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char *ptr;
+    long from_addr, to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+    fprintf(stderr, "i860_create_short_jmp\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_number_to_disp(buf,val,n)
+    char       *buf;
+    long       val;
+{
+    fprintf(stderr, "md_number_to_disp\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_number_to_field(buf,val,fix)
+    char *buf;
+    long val;
+    void *fix;
+{
+    fprintf(stderr, "i860_number_to_field\n");
+    abort();
+}
+
+/* the bit-field entries in the relocation_info struct plays hell 
+   with the byte-order problems of cross-assembly.  So as a hack,
+   I added this mach. dependent ri twiddler.  Ugly, but it gets
+   you there. -KWK */
+/* on i860: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as pcrel, bit 6 as extern, and the lower six bits as
+   relocation type (highlow 5-4).  Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void
+md_ri_to_chars(ri_p, ri)
+     struct relocation_info *ri_p, ri;
+{
+#if 0
+  unsigned char the_bytes[sizeof(*ri_p)];
+  
+  /* this is easy */
+  md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
+  /* now the fun stuff */
+  the_bytes[4] = (ri.r_index >> 16) & 0x0ff;
+  the_bytes[5] = (ri.r_index >> 8) & 0x0ff;
+  the_bytes[6] = ri.r_index & 0x0ff;
+  the_bytes[7] = ((ri.r_extern << 7)  & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F);
+  /* Also easy */
+  md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend));
+  /* now put it back where you found it, Junior... */
+  bcopy (the_bytes, (char *)ri_p, sizeof(*ri_p));
+#endif
+}
+
+/* should never be called for i860 */
+void
+md_convert_frag(fragP)
+    register fragS *fragP;
+{
+    fprintf(stderr, "i860_convert_frag\n");
+    abort();
+}
+
+/* should never be called for i860 */
+void
+md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+    char       *ptr;
+    long       from_addr,
+               to_addr;
+    fragS      *frag;
+    symbolS    *to_symbol;
+{
+    fprintf(stderr, "i860_create_long_jump\n");
+    abort();
+}
+
+/* should never be called for i860 */
+int
+md_estimate_size_before_relax(fragP, segtype)
+    register fragS *fragP;
+segT segtype;
+{
+    fprintf(stderr, "i860_estimate_size_before_relax\n");
+    abort();
+    return 0;
+}
+
+/* for debugging only, must match enum reloc_type */
+static char *Reloc[] = {
+    "NO_RELOC",
+    "BRADDR", 
+    "LOW0", 
+    "LOW1", 
+    "LOW2", 
+    "LOW3", 
+    "LOW4", 
+    "SPLIT0", 
+    "SPLIT1", 
+    "SPLIT2", 
+    "RELOC_32", 
+};
+static char *Highlow[] = {
+    "NO_SPEC",
+    "PAIR", 
+    "HIGH", 
+    "HIGHADJ", 
+};
+static void
+print_insn(insn)
+    struct i860_it *insn;
+{
+    if (insn->error) {
+       fprintf(stderr, "ERROR: %s\n");
+    }
+    fprintf(stderr, "opcode=0x%08x\t", insn->opcode);
+    fprintf(stderr, "expand=0x%08x\t", insn->expand);
+    fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]);
+    fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]);
+    fprintf(stderr, "exp =  {\n");
+    fprintf(stderr, "\t\tX_add_symbol = %s\n",
+       insn->exp.X_add_symbol ?
+       (S_GET_NAME(insn->exp.X_add_symbol) ? 
+       S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0");
+    fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+       insn->exp.X_subtract_symbol ?
+           (S_GET_NAME(insn->exp.X_subtract_symbol) ? 
+               S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0");
+    fprintf(stderr, "\t\tX_add_number = %d\n",
+       insn->exp.X_add_number);
+    fprintf(stderr, "}\n");
+    return;
+}
+
+int
+md_parse_option(argP,cntP,vecP)
+    char **argP;
+    int *cntP;
+    char ***vecP;
+{
+    return 1;
+}
+
+/*
+ * I860 relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+void
+emit_machine_reloc(fixP, segment_address_in_file)
+    register fixS *fixP;
+    relax_addressT segment_address_in_file;
+{
+    struct reloc_info_i860 ri;
+    register symbolS *symbolP;
+    extern char *next_object_file_charP;
+    long add_number;
+
+    bzero((char *) &ri, sizeof(ri));
+    for (; fixP; fixP = fixP->fx_next) {
+
+       if (fixP->fx_r_type & ~0x3f) {
+           fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
+           abort();
+       }
+       ri.r_pcrel = fixP->fx_pcrel;
+       ri.r_type = fixP->fx_r_type;
+
+       if ((symbolP = fixP->fx_addsy) != NULL) {
+           ri.r_address = fixP->fx_frag->fr_address +
+               fixP->fx_where - segment_address_in_file;
+           if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
+               ri.r_extern = 1;
+               ri.r_symbolnum = symbolP->sy_number;
+           } else {
+               ri.r_extern = 0;
+               ri.r_symbolnum = symbolP->sy_type & N_TYPE;
+           }
+           if (symbolP && symbolP->sy_frag) {
+               ri.r_addend = symbolP->sy_frag->fr_address;
+           }
+           ri.r_type = fixP->fx_r_type;
+           if (fixP->fx_pcrel) {
+               /* preserve actual offset vs. pc + 4 */
+               ri.r_addend -= (ri.r_address + 4);
+           } else {
+               ri.r_addend = fixP->fx_addnumber;
+           }
+
+           md_ri_to_chars((char *) &ri, ri);
+           append(&next_object_file_charP, (char *)& ri, sizeof(ri));
+       }
+    }
+    return;
+}
+
+/* Parse an operand that is machine-specific.  
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* We have no need to default values of symbols.  */
+
+/* ARGSUSED */
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the i860, 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;
+}
+
+void
+md_apply_fix(fixP, val)
+    fixS *fixP;
+    long val;
+{
+       char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+       
+       if (!fixP->fx_bit_fixP) {
+               
+               switch (fixP->fx_im_disp) {
+               case 0:
+                       fixP->fx_addnumber = val;
+                       md_number_to_imm(place, val, fixP->fx_size, fixP);
+                       break;
+               case 1:
+                       md_number_to_disp (place,
+                                          fixP->fx_pcrel ? val+fixP->fx_pcrel_adjust:val,
+                                          fixP->fx_size);
+                       break;
+               case 2: /* fix requested for .long .word etc */
+                       md_number_to_chars (place, val, fixP->fx_size);
+                       break;
+               default:
+                       as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
+               } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+       } else {
+               md_number_to_field (place, val, fixP->fx_bit_fixP);
+       }
+       
+       return;
+} /* md_apply_fix() */
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:16:48  rich
+ * Initial revision
+ *
+ * Revision 1.2  1991/03/30  17:11:32  rich
+ * Updated md_create_short_jump calling protocol.
+ *
+ *
+ */
+
+/*
+ * Local Variables:
+ * fill-column: 131
+ * comment-column: 0
+ */
+
+/* end of i860.c */
diff --git a/gas/config/tc-i860.h b/gas/config/tc-i860.h
new file mode 100644 (file)
index 0000000..2fc6514
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * This file is tc-i860.h.
+ */
+
+#define TC_I860 1
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-i860.h */
diff --git a/gas/config/tc-i960.c b/gas/config/tc-i960.c
new file mode 100644 (file)
index 0000000..a32325b
--- /dev/null
@@ -0,0 +1,2800 @@
+/* i960.c - All the i80960-specific stuff
+   Copyright (C) 1989, 1990, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/* See comment on md_parse_option for 80960-specific invocation options. */
+
+/******************************************************************************
+ * i80690 NOTE!!!:
+ *     Header, symbol, and relocation info will be used on the host machine
+ *     only -- only executable code is actually downloaded to the i80960.
+ *     Therefore, leave all such information in host byte order.
+ *
+ *     (That's a slight lie -- we DO download some header information, but
+ *     the downloader converts the file format and corrects the byte-ordering
+ *     of the relevant fields while doing so.)
+ *
+ ***************************************************************************** */
+
+/* There are 4 different lengths of (potentially) symbol-based displacements
+ * in the 80960 instruction set, each of which could require address fix-ups
+ * and (in the case of external symbols) emission of relocation directives:
+ *
+ * 32-bit (MEMB)
+ *     This is a standard length for the base assembler and requires no
+ *     special action.
+ *
+ * 13-bit (COBR)
+ *     This is a non-standard length, but the base assembler has a hook for
+ *     bit field address fixups:  the fixS structure can point to a descriptor
+ *     of the field, in which case our md_number_to_field() routine gets called
+ *     to process it.
+ *
+ *     I made the hook a little cleaner by having fix_new() (in the base
+ *     assembler) return a pointer to the fixS in question.  And I made it a
+ *     little simpler by storing the field size (in this case 13) instead of
+ *     of a pointer to another structure:  80960 displacements are ALWAYS
+ *     stored in the low-order bits of a 4-byte word.
+ *
+ *     Since the target of a COBR cannot be external, no relocation directives
+ *     for this size displacement have to be generated.  But the base assembler
+ *     had to be modified to issue error messages if the symbol did turn out
+ *     to be external.
+ *
+ * 24-bit (CTRL)
+ *     Fixups are handled as for the 13-bit case (except that 24 is stored
+ *     in the fixS).
+ *
+ *     The relocation directive generated is the same as that for the 32-bit
+ *     displacement, except that it's PC-relative (the 32-bit displacement
+ *     never is).   The i80960 version of the linker needs a mod to
+ *     distinguish and handle the 24-bit case.
+ *
+ * 12-bit (MEMA)
+ *     MEMA formats are always promoted to MEMB (32-bit) if the displacement
+ *     is based on a symbol, because it could be relocated at link time.
+ *     The only time we use the 12-bit format is if an absolute value of
+ *     less than 4096 is specified, in which case we need neither a fixup nor
+ *     a relocation directive.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "as.h"
+
+#include "obstack.h"
+
+#include "i960-opcode.h"
+
+extern char *input_line_pointer;
+extern struct hash_control *po_hash;
+extern unsigned char nbytes_r_length[];
+extern char *next_object_file_charP;
+
+#ifdef OBJ_COFF
+int md_reloc_size = sizeof(struct reloc);
+#else /* OBJ_COFF */
+int md_reloc_size = sizeof(struct relocation_info);
+#endif /* OBJ_COFF */
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+#ifdef __STDC__
+
+static void emit_machine_reloc(fixS *fixP, relax_addressT segment_address_in_file);
+
+#else /* __STDC__ */
+
+static void emit_machine_reloc();
+
+#endif /* __STDC__ */
+
+void (*md_emit_relocations)() = emit_machine_reloc;
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+       /***************************
+        *  Local i80960 routines  *
+        ************************** */
+
+static void    brcnt_emit();   /* Emit branch-prediction instrumentation code */
+static char *  brlab_next();   /* Return next branch local label */
+       void    brtab_emit();   /* Emit br-predict instrumentation table */
+static void    cobr_fmt();     /* Generate COBR instruction */
+static void    ctrl_fmt();     /* Generate CTRL instruction */
+static char *  emit();         /* Emit (internally) binary */
+static int get_args(); /* Break arguments out of comma-separated list */
+static void    get_cdisp();    /* Handle COBR or CTRL displacement */
+static char *  get_ispec();    /* Find index specification string */
+static int get_regnum();       /* Translate text to register number */
+static int i_scan();   /* Lexical scan of instruction source */
+static void    mem_fmt();      /* Generate MEMA or MEMB instruction */
+static void    mema_to_memb(); /* Convert MEMA instruction to MEMB format */
+static segT    parse_expr();   /* Parse an expression */
+static int parse_ldconst();/* Parse and replace a 'ldconst' pseudo-op */
+static void    parse_memop();  /* Parse a memory operand */
+static void    parse_po();     /* Parse machine-dependent pseudo-op */
+static void    parse_regop();  /* Parse a register operand */
+static void    reg_fmt();      /* Generate a REG format instruction */
+       void    reloc_callj();  /* Relocate a 'callj' instruction */
+static void    relax_cobr();   /* "De-optimize" cobr into compare/branch */
+static void    s_leafproc();   /* Process '.leafproc' pseudo-op */
+static void    s_sysproc();    /* Process '.sysproc' pseudo-op */
+static int shift_ok(); /* Will a 'shlo' substiture for a 'ldconst'? */
+static void    syntax();       /* Give syntax error */
+static int targ_has_sfr();     /* Target chip supports spec-func register? */
+static int targ_has_iclass();/* Target chip supports instruction set? */
+/* static void unlink_sym(); */        /* Remove a symbol from the symbol list */
+
+/* See md_parse_option() for meanings of these options */
+static char norelax = 0;               /* True if -norelax switch seen */
+static char instrument_branches = 0;   /* True if -b switch seen */
+
+/* Characters that always start a comment.
+ * If the pre-processor is disabled, these aren't very useful.
+ */
+char comment_chars[] = "#";
+
+/* Characters 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. */
+
+char line_comment_chars[] = "";
+
+/* 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[] = "fFdDtT";
+
+
+/* Table used by base assembler to relax addresses based on varying length
+ * instructions.  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.
+ *
+ * For i80960, the only application is the (de-)optimization of cobr
+ * instructions into separate compare and branch instructions when a 13-bit
+ * displacement won't hack it.
+ */
+const relax_typeS
+md_relax_table[] = {
+       {0,         0,        0,0}, /* State 0 => no more relaxation possible */
+       {4088,      -4096,    0,2}, /* State 1: conditional branch (cobr) */
+       {0x800000-8,-0x800000,4,0}, /* State 2: compare (reg) & branch (ctrl) */
+};
+
+
+/* These are the machine dependent pseudo-ops.
+ *
+ * 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
+ */
+#define S_LEAFPROC     1
+#define S_SYSPROC      2
+
+const pseudo_typeS
+md_pseudo_table[] = {
+
+       { "bss",        s_lcomm,        1 },
+       { "extended",   float_cons,     't' },
+       { "leafproc",   parse_po,       S_LEAFPROC },
+       { "sysproc",    parse_po,       S_SYSPROC },
+
+       { "word",       cons,           4 },
+       { "quad",       big_cons,       16 },
+
+       { 0,            0,              0 }
+};
+\f
+/* Macros to extract info from an 'expressionS' structure 'e' */
+#define adds(e)        e.X_add_symbol
+#define subs(e)        e.X_subtract_symbol
+#define offs(e)        e.X_add_number
+#define segs(e)        e.X_seg
+
+
+/* Branch-prediction bits for CTRL/COBR format opcodes */
+#define BP_MASK                0x00000002  /* Mask for branch-prediction bit */
+#define BP_TAKEN       0x00000000  /* Value to OR in to predict branch */
+#define BP_NOT_TAKEN   0x00000002  /* Value to OR in to predict no branch */
+
+
+/* Some instruction opcodes that we need explicitly */
+#define BE     0x12000000
+#define BG     0x11000000
+#define BGE    0x13000000
+#define BL     0x14000000
+#define BLE    0x16000000
+#define BNE    0x15000000
+#define BNO    0x10000000
+#define BO     0x17000000
+#define CHKBIT 0x5a002700
+#define CMPI   0x5a002080
+#define CMPO   0x5a002000
+
+#define B      0x08000000
+#define BAL    0x0b000000
+#define CALL   0x09000000
+#define CALLS  0x66003800
+#define RET    0x0a000000
+
+
+/* These masks are used to build up a set of MEMB mode bits. */
+#define        A_BIT           0x0400
+#define        I_BIT           0x0800
+#define MEMB_BIT       0x1000
+#define        D_BIT           0x2000
+
+
+/* Mask for the only mode bit in a MEMA instruction (if set, abase reg is used) */
+#define MEMA_ABASE     0x2000
+
+/* Info from which a MEMA or MEMB format instruction can be generated */
+typedef struct {
+       long opcode;    /* (First) 32 bits of instruction */
+       int disp;       /* 0-(none), 12- or, 32-bit displacement needed */
+       char *e;        /* The expression in the source instruction from
+                        *      which the displacement should be determined
+                        */
+} memS;
+
+
+/* The two pieces of info we need to generate a register operand */
+struct regop {
+       int mode;       /* 0 =>local/global/spec reg; 1=> literal or fp reg */
+       int special;    /* 0 =>not a sfr;  1=> is a sfr (not valid w/mode=0) */
+       int n;          /* Register number or literal value */
+};
+
+
+/* Number and assembler mnemonic for all registers that can appear in operands */
+static struct {
+       char *reg_name;
+       int reg_num;
+} regnames[] = {
+       { "pfp",  0 }, { "sp",   1 }, { "rip",  2 }, { "r3",   3 },
+       { "r4",   4 }, { "r5",   5 }, { "r6",   6 }, { "r7",   7 },
+       { "r8",   8 }, { "r9",   9 }, { "r10", 10 }, { "r11", 11 },
+       { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 },
+       { "g0",  16 }, { "g1",  17 }, { "g2",  18 }, { "g3",  19 },
+       { "g4",  20 }, { "g5",  21 }, { "g6",  22 }, { "g7",  23 },
+       { "g8",  24 }, { "g9",  25 }, { "g10", 26 }, { "g11", 27 },
+       { "g12", 28 }, { "g13", 29 }, { "g14", 30 }, { "fp",  31 },
+
+       /* Numbers for special-function registers are for assembler internal
+        * use only: they are scaled back to range [0-31] for binary output.
+        */
+#      define SF0      32
+
+       { "sf0", 32 }, { "sf1", 33 }, { "sf2", 34 }, { "sf3", 35 },
+       { "sf4", 36 }, { "sf5", 37 }, { "sf6", 38 }, { "sf7", 39 },
+       { "sf8", 40 }, { "sf9", 41 }, { "sf10",42 }, { "sf11",43 },
+       { "sf12",44 }, { "sf13",45 }, { "sf14",46 }, { "sf15",47 },
+       { "sf16",48 }, { "sf17",49 }, { "sf18",50 }, { "sf19",51 },
+       { "sf20",52 }, { "sf21",53 }, { "sf22",54 }, { "sf23",55 },
+       { "sf24",56 }, { "sf25",57 }, { "sf26",58 }, { "sf27",59 },
+       { "sf28",60 }, { "sf29",61 }, { "sf30",62 }, { "sf31",63 },
+
+       /* Numbers for floating point registers are for assembler internal use
+        * only: they are scaled back to [0-3] for binary output.
+        */
+#      define FP0      64
+
+       { "fp0", 64 }, { "fp1", 65 }, { "fp2", 66 }, { "fp3", 67 },
+
+       { NULL,  0 },           /* END OF LIST */
+};
+
+#define        IS_RG_REG(n)    ((0 <= (n)) && ((n) < SF0))
+#define        IS_SF_REG(n)    ((SF0 <= (n)) && ((n) < FP0))
+#define        IS_FP_REG(n)    ((n) >= FP0)
+
+/* Number and assembler mnemonic for all registers that can appear as 'abase'
+ * (indirect addressing) registers.
+ */
+static struct {
+       char *areg_name;
+       int areg_num;
+} aregs[] = {
+       { "(pfp)",  0 }, { "(sp)",   1 }, { "(rip)",  2 }, { "(r3)",   3 },
+       { "(r4)",   4 }, { "(r5)",   5 }, { "(r6)",   6 }, { "(r7)",   7 },
+       { "(r8)",   8 }, { "(r9)",   9 }, { "(r10)", 10 }, { "(r11)", 11 },
+       { "(r12)", 12 }, { "(r13)", 13 }, { "(r14)", 14 }, { "(r15)", 15 },
+       { "(g0)",  16 }, { "(g1)",  17 }, { "(g2)",  18 }, { "(g3)",  19 },
+       { "(g4)",  20 }, { "(g5)",  21 }, { "(g6)",  22 }, { "(g7)",  23 },
+       { "(g8)",  24 }, { "(g9)",  25 }, { "(g10)", 26 }, { "(g11)", 27 },
+       { "(g12)", 28 }, { "(g13)", 29 }, { "(g14)", 30 }, { "(fp)",  31 },
+
+#      define IPREL    32
+       /* for assembler internal use only: this number never appears in binary
+        * output.
+        */
+       { "(ip)", IPREL },
+
+       { NULL,  0 },           /* END OF LIST */
+};
+
+
+/* Hash tables */
+static struct hash_control *op_hash = NULL;    /* Opcode mnemonics */
+static struct hash_control *reg_hash = NULL;   /* Register name hash table */
+static struct hash_control *areg_hash = NULL;  /* Abase register hash table */
+
+
+/* Architecture for which we are assembling */
+#define ARCH_ANY       0       /* Default: no architecture checking done */
+#define ARCH_KA                1
+#define ARCH_KB                2
+#define ARCH_MC                3
+#define ARCH_CA                4
+int architecture = ARCH_ANY;   /* Architecture requested on invocation line */
+int iclasses_seen = 0;         /* OR of instruction classes (I_* constants)
+                                *      for which we've actually assembled
+                                *      instructions.
+                                */
+
+
+/* BRANCH-PREDICTION INSTRUMENTATION
+ *
+ *     The following supports generation of branch-prediction instrumentation
+ *     (turned on by -b switch).  The instrumentation collects counts
+ *     of branches taken/not-taken for later input to a utility that will
+ *     set the branch prediction bits of the instructions in accordance with
+ *     the behavior observed.  (Note that the KX series does not have
+ *     brach-prediction.)
+ *
+ *     The instrumentation consists of:
+ *
+ *     (1) before and after each conditional branch, a call to an external
+ *         routine that increments and steps over an inline counter.  The
+ *         counter itself, initialized to 0, immediately follows the call
+ *         instruction.  For each branch, the counter following the branch
+ *         is the number of times the branch was not taken, and the difference
+ *         between the counters is the number of times it was taken.  An
+ *         example of an instrumented conditional branch:
+ *
+ *                             call    BR_CNT_FUNC
+ *                             .word   0
+ *             LBRANCH23:      be      label
+ *                             call    BR_CNT_FUNC
+ *                             .word   0
+ *
+ *     (2) a table of pointers to the instrumented branches, so that an
+ *         external postprocessing routine can locate all of the counters.
+ *         the table begins with a 2-word header: a pointer to the next in
+ *         a linked list of such tables (initialized to 0);  and a count
+ *         of the number of entries in the table (exclusive of the header.
+ *
+ *         Note that input source code is expected to already contain calls
+ *         an external routine that will link the branch local table into a
+ *         list of such tables.
+ */
+
+static int br_cnt = 0;         /* Number of branches instrumented so far.
+                                * Also used to generate unique local labels
+                                * for each instrumented branch
+                                */
+
+#define BR_LABEL_BASE  "LBRANCH"
+                               /* Basename of local labels on instrumented
+                                * branches, to avoid conflict with compiler-
+                                * generated local labels.
+                                */
+
+#define BR_CNT_FUNC    "__inc_branch"
+                               /* Name of the external routine that will
+                                * increment (and step over) an inline counter.
+                                */
+
+#define BR_TAB_NAME    "__BRANCH_TABLE__"
+                               /* Name of the table of pointers to branches.
+                                * A local (i.e., non-external) symbol.
+                                */
+\f
+/*****************************************************************************
+ * md_begin:  One-time initialization.
+ *
+ *     Set up hash tables.
+ *
+ **************************************************************************** */
+void
+md_begin()
+{
+       int i;                          /* Loop counter */
+       const struct i960_opcode *oP; /* Pointer into opcode table */
+       char *retval;                   /* Value returned by hash functions */
+
+       if (((op_hash = hash_new()) == 0)
+           || ((reg_hash = hash_new()) == 0)
+           || ((areg_hash = hash_new()) == 0)) {
+               as_fatal("virtual memory exceeded");
+       }
+
+       retval = "";    /* For some reason, the base assembler uses an empty
+                        * string for "no error message", instead of a NULL
+                        * pointer.
+                        */
+
+       for (oP=i960_opcodes; oP->name && !*retval; oP++) {
+               retval = hash_insert(op_hash, oP->name, oP);
+       }
+
+       for (i=0; regnames[i].reg_name && !*retval; i++) {
+               retval = hash_insert(reg_hash, regnames[i].reg_name,
+                                    &regnames[i].reg_num);
+       }
+
+       for (i=0; aregs[i].areg_name && !*retval; i++){
+               retval = hash_insert(areg_hash, aregs[i].areg_name,
+                                    &aregs[i].areg_num);
+       }
+
+       if (*retval) {
+               as_fatal("Hashing returned \"%s\".", retval);
+       }
+} /* md_begin() */
+
+/*****************************************************************************
+ * md_end:  One-time final cleanup
+ *
+ *     None necessary
+ *
+ **************************************************************************** */
+void
+md_end()
+{
+}
+
+/*****************************************************************************
+ * md_assemble:  Assemble an instruction
+ *
+ * Assumptions about the passed-in text:
+ *     - all comments, labels removed
+ *     - text is an instruction
+ *     - all white space compressed to single blanks
+ *     - all character constants have been replaced with decimal
+ *
+ **************************************************************************** */
+void
+md_assemble(textP)
+    char *textP;       /* Source text of instruction */
+{
+       char *args[4];  /* Parsed instruction text, containing NO whitespace:
+                        *      arg[0]->opcode mnemonic
+                        *      arg[1-3]->operands, with char constants
+                        *                      replaced by decimal numbers
+                        */
+       int n_ops;      /* Number of instruction operands */
+
+       struct i960_opcode *oP;
+                       /* Pointer to instruction description */
+       int branch_predict;
+                       /* TRUE iff opcode mnemonic included branch-prediction
+                        *      suffix (".f" or ".t")
+                        */
+       long bp_bits;   /* Setting of branch-prediction bit(s) to be OR'd
+                        *      into instruction opcode of CTRL/COBR format
+                        *      instructions.
+                        */
+       int n;          /* Offset of last character in opcode mnemonic */
+
+       static const char bp_error_msg[] = "branch prediction invalid on this opcode";
+
+
+       /* Parse instruction into opcode and operands */
+       bzero(args, sizeof(args));
+       n_ops = i_scan(textP, args);
+       if (n_ops == -1){
+               return;         /* Error message already issued */
+       }
+
+       /* Do "macro substitution" (sort of) on 'ldconst' pseudo-instruction */
+       if (!strcmp(args[0],"ldconst")){
+               n_ops = parse_ldconst(args);
+               if (n_ops == -1){
+                       return;
+               }
+       }
+
+       /* Check for branch-prediction suffix on opcode mnemonic, strip it off */
+       n = strlen(args[0]) - 1;
+       branch_predict = 0;
+       bp_bits = 0;
+       if (args[0][n-1] == '.' && (args[0][n] == 't' || args[0][n] == 'f')){
+               /* We could check here to see if the target architecture
+                * supports branch prediction, but why bother?  The bit
+                * will just be ignored by processors that don't use it.
+                */
+               branch_predict = 1;
+               bp_bits = (args[0][n] == 't') ? BP_TAKEN : BP_NOT_TAKEN;
+               args[0][n-1] = '\0';    /* Strip suffix from opcode mnemonic */
+       }
+
+       /* Look up opcode mnemonic in table and check number of operands.
+        * Check that opcode is legal for the target architecture.
+        * If all looks good, assemble instruction.
+        */
+       oP = (struct i960_opcode *) hash_find(op_hash, args[0]);
+       if (!oP || !targ_has_iclass(oP->iclass)) {
+               as_bad("invalid opcode, \"%s\".", args[0]);
+
+       } else if (n_ops != oP->num_ops) {
+               as_bad("improper number of operands.  expecting %d, got %d", oP->num_ops, n_ops);
+
+       } else {
+               switch (oP->format){
+               case FBRA:
+               case CTRL:
+                       ctrl_fmt(args[1], oP->opcode | bp_bits, oP->num_ops);
+                       if (oP->format == FBRA){
+                               /* Now generate a 'bno' to same arg */
+                               ctrl_fmt(args[1], BNO | bp_bits, 1);
+                       }
+                       break;
+               case COBR:
+               case COJ:
+                       cobr_fmt(args, oP->opcode | bp_bits, oP);
+                       break;
+               case REG:
+                       if (branch_predict){
+                               as_warn(bp_error_msg);
+                       }
+                       reg_fmt(args, oP);
+                       break;
+               case MEM1:
+               case MEM2:
+               case MEM4:
+               case MEM8:
+               case MEM12:
+               case MEM16:
+                       if (branch_predict){
+                               as_warn(bp_error_msg);
+                       }
+                       mem_fmt(args, oP);
+                       break;
+               case CALLJ:
+                       if (branch_predict){
+                               as_warn(bp_error_msg);
+                       }
+                       /* Output opcode & set up "fixup" (relocation);
+                        * flag relocation as 'callj' type.
+                        */
+                       know(oP->num_ops == 1);
+                       get_cdisp(args[1], "CTRL", oP->opcode, 24, 0, 1);
+                       break;
+               default:
+                       BAD_CASE(oP->format);
+                       break;
+               }
+       }
+} /* md_assemble() */
+
+/*****************************************************************************
+ * md_number_to_chars:  convert a number to target byte order
+ *
+ **************************************************************************** */
+void
+md_number_to_chars(buf, value, n)
+    char *buf;         /* Put output here */
+    long value;                /* The integer to be converted */
+    int n;             /* Number of bytes to output (significant bytes
+                        *      in 'value')
+                        */
+{
+       while (n--){
+               *buf++ = value;
+               value >>= 8;
+       }
+
+       /* XXX line number probably botched for this warning message. */
+       if (value != 0 && value != -1){
+               as_bad("Displacement too long for instruction field length.");
+       }
+} /* md_number_to_chars() */
+
+/*****************************************************************************
+ * md_chars_to_number:  convert from target byte order to host byte order.
+ *
+ **************************************************************************** */
+int
+md_chars_to_number(val, n)
+    unsigned char *val;        /* Value in target byte order */
+    int n;             /* Number of bytes in the input */
+{
+       int retval;
+
+       for (retval=0; n--;){
+               retval <<= 8;
+               retval |= val[n];
+       }
+       return retval;
+}
+
+
+#define MAX_LITTLENUMS 6
+#define LNUM_SIZE      sizeof(LITTLENUM_TYPE)
+
+/*****************************************************************************
+ * md_atof:    convert ascii to floating point
+ *
+ * Turn a string at input_line_pointer into a floating point constant of type
+ * 'type', and store the appropriate bytes at *litP.  The number of LITTLENUMS
+ * emitted is returned at 'sizeP'.  An error message is returned, or a pointer
+ * to an empty message if OK.
+ *
+ * Note we call the i386 floating point routine, rather than complicating
+ * things with more files or symbolic links.
+ *
+ **************************************************************************** */
+char * md_atof(type, litP, sizeP)
+int type;
+char *litP;
+int *sizeP;
+{
+       LITTLENUM_TYPE words[MAX_LITTLENUMS];
+       LITTLENUM_TYPE *wordP;
+       int prec;
+       char *t;
+       char *atof_ieee();
+
+       switch(type) {
+       case 'f':
+       case 'F':
+               prec = 2;
+               break;
+
+       case 'd':
+       case 'D':
+               prec = 4;
+               break;
+
+       case 't':
+       case 'T':
+               prec = 5;
+               type = 'x';     /* That's what atof_ieee() understands */
+               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 * LNUM_SIZE;
+
+       /* Output the LITTLENUMs in REVERSE order in accord with i80960
+        * word-order.  (Dunno why atof_ieee doesn't do it in the right
+        * order in the first place -- probably because it's a hack of
+        * atof_m68k.)
+        */
+
+       for(wordP = words + prec - 1; prec--;){
+               md_number_to_chars(litP, (long) (*wordP--), LNUM_SIZE);
+               litP += sizeof(LITTLENUM_TYPE);
+       }
+
+       return "";      /* Someone should teach Dean about null pointers */
+}
+
+
+/*****************************************************************************
+ * md_number_to_imm
+ *
+ **************************************************************************** */
+void
+md_number_to_imm(buf, val, n)
+    char *buf;
+    long val;
+    int n;
+{
+       md_number_to_chars(buf, val, n);
+}
+
+
+/*****************************************************************************
+ * md_number_to_disp
+ *
+ **************************************************************************** */
+void
+md_number_to_disp(buf, val, n)
+    char *buf;
+    long val;
+    int n;
+{
+       md_number_to_chars(buf, val, n);
+}
+
+/*****************************************************************************
+ * md_number_to_field:
+ *
+ *     Stick a value (an address fixup) into a bit field of
+ *     previously-generated instruction.
+ *
+ **************************************************************************** */
+void
+md_number_to_field(instrP, val, bfixP)
+     char *instrP;     /* Pointer to instruction to be fixed */
+     long val;         /* Address fixup value */
+     bit_fixS *bfixP;  /* Description of bit field to be fixed up */
+{
+       int numbits;    /* Length of bit field to be fixed */
+       long instr;     /* 32-bit instruction to be fixed-up */
+       long sign;      /* 0 or -1, according to sign bit of 'val' */
+
+       /* Convert instruction back to host byte order
+        */
+       instr = md_chars_to_number(instrP, 4);
+
+       /* Surprise! -- we stored the number of bits
+        * to be modified rather than a pointer to a structure.
+        */
+       numbits = (int)bfixP;
+       if (numbits == 1){
+               /* This is a no-op, stuck here by reloc_callj() */
+               return;
+       }
+
+       know ((numbits==13) || (numbits==24));
+
+       /* Propagate sign bit of 'val' for the given number of bits.
+        * Result should be all 0 or all 1
+        */
+       sign = val >> ((int)numbits - 1);
+       if (((val < 0) && (sign != -1))
+       ||   ((val > 0) && (sign != 0))){
+                 as_bad("Fixup of %d too large for field width of %d",
+                                                       val, numbits);
+       } else {
+               /* Put bit field into instruction and write back in target
+                * byte order.
+                */
+               val &= ~(-1 << (int)numbits);   /* Clear unused sign bits */
+               instr |= val;
+               md_number_to_chars(instrP, instr, 4);
+       }
+} /* md_number_to_field() */
+
+
+/*****************************************************************************
+ * md_parse_option
+ *     Invocation line includes a switch not recognized by the base assembler.
+ *     See if it's a processor-specific option.  For the 960, these are:
+ *
+ *     -norelax:
+ *             Conditional branch instructions that require displacements
+ *             greater than 13 bits (or that have external targets) should
+ *             generate errors.  The default is to replace each such
+ *             instruction with the corresponding compare (or chkbit) and
+ *             branch instructions.  Note that the Intel "j" cobr directives
+ *             are ALWAYS "de-optimized" in this way when necessary,
+ *             regardless of the setting of this option.
+ *
+ *     -b:
+ *             Add code to collect information about branches taken, for
+ *             later optimization of branch prediction bits by a separate
+ *             tool.  COBR and CNTL format instructions have branch
+ *             prediction bits (in the CX architecture);  if "BR" represents
+ *             an instruction in one of these classes, the following rep-
+ *             resents the code generated by the assembler:
+ *
+ *                     call    <increment routine>
+ *                     .word   0       # pre-counter
+ *             Label:  BR
+ *                     call    <increment routine>
+ *                     .word   0       # post-counter
+ *
+ *             A table of all such "Labels" is also generated.
+ *
+ *
+ *     -AKA, -AKB, -AKC, -ASA, -ASB, -AMC, -ACA:
+ *             Select the 80960 architecture.  Instructions or features not
+ *             supported by the selected architecture cause fatal errors.
+ *             The default is to generate code for any instruction or feature
+ *             that is supported by SOME version of the 960 (even if this
+ *             means mixing architectures!).
+ *
+ **************************************************************************** */
+int
+md_parse_option(argP, cntP, vecP)
+    char **argP;
+    int *cntP;
+    char ***vecP;
+{
+       char *p;
+       struct tabentry { char *flag; int arch; };
+       static struct tabentry arch_tab[] = {
+               "KA", ARCH_KA,
+               "KB", ARCH_KB,
+               "SA", ARCH_KA,  /* Synonym for KA */
+               "SB", ARCH_KB,  /* Synonym for KB */
+               "KC", ARCH_MC,  /* Synonym for MC */
+               "MC", ARCH_MC,
+               "CA", ARCH_CA,
+               NULL, 0
+       };
+       struct tabentry *tp;
+
+       if (!strcmp(*argP,"norelax")){
+               norelax = 1;
+
+       } else if (**argP == 'b'){
+               instrument_branches = 1;
+
+       } else if (**argP == 'A'){
+               p = (*argP) + 1;
+
+               for (tp = arch_tab; tp->flag != NULL; tp++){
+                       if (!strcmp(p,tp->flag)){
+                               break;
+                       }
+               }
+
+               if (tp->flag == NULL){
+                       as_bad("unknown architecture: %s", p);
+               } else {
+                       architecture = tp->arch;
+               }
+       } else {
+               /* Unknown option */
+               (*argP)++;
+               return 0;
+       }
+       **argP = '\0';  /* Done parsing this switch */
+       return 1;
+}
+
+/*****************************************************************************
+ * md_convert_frag:
+ *     Called by base assembler after address relaxation is finished:  modify
+ *     variable fragments according to how much relaxation was done.
+ *
+ *     If the fragment substate is still 1, a 13-bit displacement was enough
+ *     to reach the symbol in question.  Set up an address fixup, but otherwise
+ *     leave the cobr instruction alone.
+ *
+ *     If the fragment substate is 2, a 13-bit displacement was not enough.
+ *     Replace the cobr with a two instructions (a compare and a branch).
+ *
+ **************************************************************************** */
+void
+md_convert_frag(fragP)
+    fragS * fragP;
+{
+       fixS *fixP;     /* Structure describing needed address fix */
+
+       switch (fragP->fr_subtype){
+       case 1:
+               /* LEAVE SINGLE COBR INSTRUCTION */
+               fixP = fix_new(fragP,
+                              fragP->fr_opcode-fragP->fr_literal,
+                              4,
+                              fragP->fr_symbol,
+                              0,
+                              fragP->fr_offset,
+                              1,
+                              0);
+
+               fixP->fx_bit_fixP = (bit_fixS *) 13;    /* size of bit field */
+               break;
+       case 2:
+               /* REPLACE COBR WITH COMPARE/BRANCH INSTRUCTIONS */
+               relax_cobr(fragP);
+               break;
+       default:
+               BAD_CASE(fragP->fr_subtype);
+               break;
+       }
+}
+
+/*****************************************************************************
+ * md_estimate_size_before_relax:  How much does it look like *fragP will grow?
+ *
+ *     Called by base assembler just before address relaxation.
+ *     Return the amount by which the fragment will grow.
+ *
+ *     Any symbol that is now undefined will not become defined; cobr's
+ *     based on undefined symbols will have to be replaced with a compare
+ *     instruction and a branch instruction, and the code fragment will grow
+ *     by 4 bytes.
+ *
+ **************************************************************************** */
+int
+md_estimate_size_before_relax(fragP, segment_type)
+     register fragS *fragP;
+     register segT segment_type;
+{
+       /* If symbol is undefined in this segment, go to "relaxed" state
+        * (compare and branch instructions instead of cobr) right now.
+        */
+       if (S_GET_SEGMENT(fragP->fr_symbol) != segment_type) {
+               relax_cobr(fragP);
+               return 4;
+       }
+       return 0;
+} /* md_estimate_size_before_relax() */
+
+
+/*****************************************************************************
+ * md_ri_to_chars:
+ *     This routine exists in order to overcome machine byte-order problems
+ *     when dealing with bit-field entries in the relocation_info struct.
+ *
+ *     But relocation info will be used on the host machine only (only
+ *     executable code is actually downloaded to the i80960).  Therefore,
+ *     we leave it in host byte order.
+ *
+ **************************************************************************** */
+void md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
+{
+       struct relocation_info br;
+
+       (void) bzero(&br, sizeof(br));
+
+       br.r_address = ri->r_address;
+       br.r_index = ri->r_index;
+       br.r_pcrel = ri->r_pcrel;
+       br.r_length = ri->r_length;
+       br.r_extern = ri->r_extern;
+       br.r_bsr = ri->r_bsr;
+       br.r_disp = ri->r_disp;
+       br.r_callj = ri->r_callj;
+
+       *((struct relocation_info *) the_bytes) = br;
+} /* md_ri_to_chars() */
+
+
+#ifndef WORKING_DOT_WORD
+
+int md_short_jump_size = 0;
+int md_long_jump_size = 0;
+
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+       abort();
+}
+
+void
+md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+    char *ptr;
+    long from_addr, to_addr;
+    fragS *frag;
+    symbolS *to_symbol;
+{
+       abort();
+}
+#endif
+\f
+       /*************************************************************
+        *                                                           *
+        *  FOLLOWING ARE THE LOCAL ROUTINES, IN ALPHABETICAL ORDER  *
+        *                                                           *
+        ************************************************************ */
+
+
+
+/*****************************************************************************
+ * brcnt_emit: Emit code to increment inline branch counter.
+ *
+ *     See the comments above the declaration of 'br_cnt' for details on
+ *     branch-prediction instrumentation.
+ **************************************************************************** */
+static void
+brcnt_emit()
+{
+       ctrl_fmt(BR_CNT_FUNC,CALL,1);/* Emit call to "increment" routine */
+       emit(0);                /* Emit inline counter to be incremented */
+}
+
+/*****************************************************************************
+ * brlab_next: generate the next branch local label
+ *
+ *     See the comments above the declaration of 'br_cnt' for details on
+ *     branch-prediction instrumentation.
+ **************************************************************************** */
+static char *
+brlab_next()
+{
+       static char buf[20];
+
+       sprintf(buf, "%s%d", BR_LABEL_BASE, br_cnt++);
+       return buf;
+}
+
+/*****************************************************************************
+ * brtab_emit: generate the fetch-prediction branch table.
+ *
+ *     See the comments above the declaration of 'br_cnt' for details on
+ *     branch-prediction instrumentation.
+ *
+ *     The code emitted here would be functionally equivalent to the following
+ *     example assembler source.
+ *
+ *                     .data
+ *                     .align  2
+ *        BR_TAB_NAME:
+ *                     .word   0               # link to next table
+ *                     .word   3               # length of table
+ *                     .word   LBRANCH0        # 1st entry in table proper
+ *                     .word   LBRANCH1
+ *                     .word   LBRANCH2
+ ***************************************************************************** */
+void
+brtab_emit()
+{
+       int i;
+       char buf[20];
+       char *p;                /* Where the binary was output to */
+       fixS *fixP;             /*->description of deferred address fixup */
+
+       if (!instrument_branches){
+               return;
+       }
+
+       subseg_new(SEG_DATA,0);         /*      .data */
+       frag_align(2,0);                /*      .align 2 */
+       record_alignment(now_seg,2);
+       colon(BR_TAB_NAME);             /* BR_TAB_NAME: */
+       emit(0);                        /*      .word 0 #link to next table */
+       emit(br_cnt);                   /*      .word n #length of table */
+
+       for (i=0; i<br_cnt; i++){
+               sprintf(buf, "%s%d", BR_LABEL_BASE, i);
+               p = emit(0);
+               fixP = fix_new(frag_now,
+                              p - frag_now->fr_literal,
+                              4,
+                              symbol_find(buf),
+                              0,
+                              0,
+                              0,
+                              0);
+               fixP->fx_im_disp = 2;           /* 32-bit displacement fix */
+       }
+}
+
+/*****************************************************************************
+ * cobr_fmt:   generate a COBR-format instruction
+ *
+ **************************************************************************** */
+static
+void
+cobr_fmt(arg, opcode, oP)
+    char *arg[];       /* arg[0]->opcode mnemonic, arg[1-3]->operands (ascii) */
+    long opcode;       /* Opcode, with branch-prediction bits already set
+                        *      if necessary.
+                        */
+    struct i960_opcode *oP;
+                       /*->description of instruction */
+{
+       long instr;             /* 32-bit instruction */
+       struct regop regop;     /* Description of register operand */
+       int n;                  /* Number of operands */
+       int var_frag;           /* 1 if varying length code fragment should
+                                *      be emitted;  0 if an address fix
+                                *      should be emitted.
+                                */
+
+       instr = opcode;
+       n = oP->num_ops;
+
+       if (n >= 1) {
+               /* First operand (if any) of a COBR is always a register
+                * operand.  Parse it.
+                */
+               parse_regop(&regop, arg[1], oP->operand[0]);
+               instr |= (regop.n << 19) | (regop.mode << 13);
+       }
+       if (n >= 2) {
+               /* Second operand (if any) of a COBR is always a register
+                * operand.  Parse it.
+                */
+               parse_regop(&regop, arg[2], oP->operand[1]);
+               instr |= (regop.n << 14) | regop.special;
+       }
+
+
+       if (n < 3){
+               emit(instr);
+
+       } else {
+               if (instrument_branches){
+                       brcnt_emit();
+                       colon(brlab_next());
+               }
+
+               /* A third operand to a COBR is always a displacement.
+                * Parse it; if it's relaxable (a cobr "j" directive, or any
+                * cobr other than bbs/bbc when the "-norelax" option is not in
+                * use) set up a variable code fragment;  otherwise set up an
+                * address fix.
+                */
+               var_frag = !norelax || (oP->format == COJ); /* TRUE or FALSE */
+               get_cdisp(arg[3], "COBR", instr, 13, var_frag, 0);
+
+               if (instrument_branches){
+                       brcnt_emit();
+               }
+       }
+} /* cobr_fmt() */
+
+
+/*****************************************************************************
+ * ctrl_fmt:   generate a CTRL-format instruction
+ *
+ **************************************************************************** */
+static
+void
+ctrl_fmt(targP, opcode, num_ops)
+    char *targP;       /* Pointer to text of lone operand (if any) */
+    long opcode;       /* Template of instruction */
+    int num_ops;       /* Number of operands */
+{
+       int instrument; /* TRUE iff we should add instrumentation to track
+                        * how often the branch is taken
+                        */
+
+
+       if (num_ops == 0){
+               emit(opcode);           /* Output opcode */
+       } else {
+
+               instrument = instrument_branches && (opcode!=CALL)
+                       && (opcode!=B) && (opcode!=RET) && (opcode!=BAL);
+
+               if (instrument){
+                       brcnt_emit();
+                       colon(brlab_next());
+               }
+
+               /* The operand MUST be an ip-relative displacment. Parse it
+                * and set up address fix for the instruction we just output.
+                */
+               get_cdisp(targP, "CTRL", opcode, 24, 0, 0);
+
+               if (instrument){
+                       brcnt_emit();
+               }
+       }
+
+}
+
+
+/*****************************************************************************
+ * emit:       output instruction binary
+ *
+ *     Output instruction binary, in target byte order, 4 bytes at a time.
+ *     Return pointer to where it was placed.
+ *
+ **************************************************************************** */
+static
+char *
+emit(instr)
+    long instr;                /* Word to be output, host byte order */
+{
+       char *toP;      /* Where to output it */
+
+       toP = frag_more(4);                     /* Allocate storage */
+       md_number_to_chars(toP, instr, 4);  /* Convert to target byte order */
+       return toP;
+}
+
+
+/*****************************************************************************
+ * get_args:   break individual arguments out of comma-separated list
+ *
+ * Input assumptions:
+ *     - all comments and labels have been removed
+ *     - all strings of whitespace have been collapsed to a single blank.
+ *     - all character constants ('x') have been replaced with decimal
+ *
+ * Output:
+ *     args[0] is untouched. args[1] points to first operand, etc. All args:
+ *     - are NULL-terminated
+ *     - contain no whitespace
+ *
+ * Return value:
+ *     Number of operands (0,1,2, or 3) or -1 on error.
+ *
+ **************************************************************************** */
+static int get_args(p, args)
+    register char *p;  /* Pointer to comma-separated operands; MUCKED BY US */
+    char *args[];      /* Output arg: pointers to operands placed in args[1-3].
+                        * MUST ACCOMMODATE 4 ENTRIES (args[0-3]).
+                        */
+{
+       register int n;         /* Number of operands */
+       register char *to;
+/*     char buf[4]; */
+/*     int len; */
+
+
+       /* Skip lead white space */
+       while (*p == ' '){
+               p++;
+       }
+
+       if (*p == '\0'){
+               return 0;
+       }
+
+       n = 1;
+       args[1] = p;
+
+       /* Squeze blanks out by moving non-blanks toward start of string.
+        * Isolate operands, whenever comma is found.
+        */
+       to = p;
+       while (*p != '\0'){
+
+               if (*p == ' '){
+                       p++;
+
+               } else if (*p == ','){
+
+                       /* Start of operand */
+                       if (n == 3){
+                               as_bad("too many operands");
+                               return -1;
+                       }
+                       *to++ = '\0';   /* Terminate argument */
+                       args[++n] = to; /* Start next argument */
+                       p++;
+
+               } else {
+                       *to++ = *p++;
+               }
+       }
+       *to = '\0';
+       return n;
+}
+
+
+/*****************************************************************************
+ * get_cdisp:  handle displacement for a COBR or CTRL instruction.
+ *
+ *     Parse displacement for a COBR or CTRL instruction.
+ *
+ *     If successful, output the instruction opcode and set up for it,
+ *     depending on the arg 'var_frag', either:
+ *         o an address fixup to be done when all symbol values are known, or
+ *         o a varying length code fragment, with address fixup info.  This
+ *             will be done for cobr instructions that may have to be relaxed
+ *             in to compare/branch instructions (8 bytes) if the final address
+ *             displacement is greater than 13 bits.
+ *
+ **************************************************************************** */
+static
+void
+get_cdisp(dispP, ifmtP, instr, numbits, var_frag, callj)
+    char *dispP;       /*->displacement as specified in source instruction */
+    char *ifmtP;       /*->"COBR" or "CTRL" (for use in error message) */
+    long instr;                /* Instruction needing the displacement */
+    int numbits;       /* # bits of displacement (13 for COBR, 24 for CTRL) */
+    int var_frag;      /* 1 if varying length code fragment should be emitted;
+                        *      0 if an address fix should be emitted.
+                        */
+    int callj;         /* 1 if callj relocation should be done; else 0 */
+{
+       expressionS e;  /* Parsed expression */
+       fixS *fixP;     /* Structure describing needed address fix */
+       char *outP;     /* Where instruction binary is output to */
+
+       fixP = NULL;
+
+       switch (parse_expr(dispP,&e)) {
+
+       case SEG_GOOF:
+               as_bad("expression syntax error");
+               break;
+
+       case SEG_TEXT:
+       case SEG_UNKNOWN:
+               if (var_frag) {
+                       outP = frag_more(8);    /* Allocate worst-case storage */
+                       md_number_to_chars(outP, instr, 4);
+                       frag_variant(rs_machine_dependent, 4, 4, 1,
+                                               adds(e), offs(e), outP, 0, 0);
+               } else {
+                       /* Set up a new fix structure, so address can be updated
+                        * when all symbol values are known.
+                        */
+                       outP = emit(instr);
+                       fixP = fix_new(frag_now,
+                                      outP - frag_now->fr_literal,
+                                      4,
+                                      adds(e),
+                                      0,
+                                      offs(e),
+                                      1,
+                                      0);
+
+                       fixP->fx_callj = callj;
+
+                       /* We want to modify a bit field when the address is
+                        * known.  But we don't need all the garbage in the
+                        * bit_fix structure.  So we're going to lie and store
+                        * the number of bits affected instead of a pointer.
+                        */
+                       fixP->fx_bit_fixP = (bit_fixS *) numbits;
+               }
+               break;
+
+       case SEG_DATA:
+       case SEG_BSS:
+               as_bad("attempt to branch into different segment");
+               break;
+
+       default:
+               as_bad("target of %s instruction must be a label", ifmtP);
+               break;
+       }
+}
+
+
+/*****************************************************************************
+ * get_ispec:  parse a memory operand for an index specification
+ *
+ *     Here, an "index specification" is taken to be anything surrounded
+ *     by square brackets and NOT followed by anything else.
+ *
+ *     If it's found, detach it from the input string, remove the surrounding
+ *     square brackets, and return a pointer to it.  Otherwise, return NULL.
+ *
+ **************************************************************************** */
+static
+char *
+get_ispec(textP)
+    char *textP; /*->memory operand from source instruction, no white space */
+{
+       char *start;    /*->start of index specification */
+       char *end;      /*->end of index specification */
+
+       /* Find opening square bracket, if any
+        */
+       start = index(textP, '[');
+
+       if (start != NULL){
+
+               /* Eliminate '[', detach from rest of operand */
+               *start++ = '\0';
+
+               end = index(start, ']');
+
+               if (end == NULL){
+                       as_bad("unmatched '['");
+
+               } else {
+                       /* Eliminate ']' and make sure it was the last thing
+                        * in the string.
+                        */
+                       *end = '\0';
+                       if (*(end+1) != '\0'){
+                               as_bad("garbage after index spec ignored");
+                       }
+               }
+       }
+       return start;
+}
+
+/*****************************************************************************
+ * get_regnum:
+ *
+ *     Look up a (suspected) register name in the register table and return the
+ *     associated register number (or -1 if not found).
+ *
+ **************************************************************************** */
+static
+int
+get_regnum(regname)
+    char *regname;     /* Suspected register name */
+{
+       int *rP;
+
+       rP = (int *) hash_find(reg_hash, regname);
+       return (rP == NULL) ? -1 : *rP;
+}
+
+
+/*****************************************************************************
+ * i_scan:     perform lexical scan of ascii assembler instruction.
+ *
+ * Input assumptions:
+ *     - input string is an i80960 instruction (not a pseudo-op)
+ *     - all comments and labels have been removed
+ *     - all strings of whitespace have been collapsed to a single blank.
+ *
+ * Output:
+ *     args[0] points to opcode, other entries point to operands. All strings:
+ *     - are NULL-terminated
+ *     - contain no whitespace
+ *     - have character constants ('x') replaced with a decimal number
+ *
+ * Return value:
+ *     Number of operands (0,1,2, or 3) or -1 on error.
+ *
+ **************************************************************************** */
+static int i_scan(iP, args)
+    register char *iP; /* Pointer to ascii instruction;  MUCKED BY US. */
+    char *args[];      /* Output arg: pointers to opcode and operands placed
+                        *      here.  MUST ACCOMMODATE 4 ENTRIES.
+                        */
+{
+
+       /* Isolate opcode */
+       if (*(iP) == ' ') {
+               iP++;
+       } /* Skip lead space, if any */
+       args[0] = iP;
+       for (; *iP != ' '; iP++) {
+               if (*iP == '\0') {
+                       /* There are no operands */
+                       if (args[0] == iP) {
+                               /* We never moved: there was no opcode either! */
+                               as_bad("missing opcode");
+                               return -1;
+                       }
+                       return 0;
+               }
+       }
+       *iP++ = '\0';   /* Terminate opcode */
+       return(get_args(iP, args));
+} /* i_scan() */
+
+
+/*****************************************************************************
+ * mem_fmt:    generate a MEMA- or MEMB-format instruction
+ *
+ **************************************************************************** */
+static void mem_fmt(args, oP)
+    char *args[];      /* args[0]->opcode mnemonic, args[1-3]->operands */
+    struct i960_opcode *oP; /* Pointer to description of instruction */
+{
+       int i;                  /* Loop counter */
+       struct regop regop;     /* Description of register operand */
+       char opdesc;            /* Operand descriptor byte */
+       memS instr;             /* Description of binary to be output */
+       char *outP;             /* Where the binary was output to */
+       expressionS expr;       /* Parsed expression */
+       fixS *fixP;             /*->description of deferred address fixup */
+
+       bzero(&instr, sizeof(memS));
+       instr.opcode = oP->opcode;
+
+       /* Process operands. */
+       for (i = 1; i <= oP->num_ops; i++){
+               opdesc = oP->operand[i-1];
+
+               if (MEMOP(opdesc)){
+                       parse_memop(&instr, args[i], oP->format);
+               } else {
+                       parse_regop(&regop, args[i], opdesc);
+                       instr.opcode |= regop.n << 19;
+               }
+       }
+
+       /* Output opcode */
+       outP = emit(instr.opcode);
+
+       if (instr.disp == 0){
+               return;
+       }
+
+       /* Parse and process the displacement */
+       switch (parse_expr(instr.e,&expr)){
+
+       case SEG_GOOF:
+               as_bad("expression syntax error");
+               break;
+
+       case SEG_ABSOLUTE:
+               if (instr.disp == 32){
+                       (void) emit(offs(expr));        /* Output displacement */
+               } else {
+                       /* 12-bit displacement */
+                       if (offs(expr) & ~0xfff){
+                               /* Won't fit in 12 bits: convert already-output
+                                * instruction to MEMB format, output
+                                * displacement.
+                                */
+                               mema_to_memb(outP);
+                               (void) emit(offs(expr));
+                       } else {
+                               /* WILL fit in 12 bits:  OR into opcode and
+                                * overwrite the binary we already put out
+                                */
+                               instr.opcode |= offs(expr);
+                               md_number_to_chars(outP, instr.opcode, 4);
+                       }
+               }
+               break;
+
+       case SEG_DIFFERENCE:
+       case SEG_TEXT:
+       case SEG_DATA:
+       case SEG_BSS:
+       case SEG_UNKNOWN:
+               if (instr.disp == 12){
+                       /* Displacement is dependent on a symbol, whose value
+                        * may change at link time.  We HAVE to reserve 32 bits.
+                        * Convert already-output opcode to MEMB format.
+                        */
+                       mema_to_memb(outP);
+               }
+
+               /* Output 0 displacement and set up address fixup for when
+                * this symbol's value becomes known.
+                */
+               outP = emit((long) 0);
+               fixP = fix_new(frag_now,
+                              outP - frag_now->fr_literal,
+                              4,
+                              adds(expr),
+                              subs(expr),
+                              offs(expr),
+                              0,
+                              0);
+               fixP->fx_im_disp = 2;           /* 32-bit displacement fix */
+               break;
+
+       default:
+               BAD_CASE(segs(expr));
+               break;
+       }
+} /* memfmt() */
+
+
+/*****************************************************************************
+ * mema_to_memb:       convert a MEMA-format opcode to a MEMB-format opcode.
+ *
+ * There are 2 possible MEMA formats:
+ *     - displacement only
+ *     - displacement + abase
+ *
+ * They are distinguished by the setting of the MEMA_ABASE bit.
+ *
+ **************************************************************************** */
+static void mema_to_memb(opcodeP)
+    char *opcodeP;     /* Where to find the opcode, in target byte order */
+{
+       long opcode;    /* Opcode in host byte order */
+       long mode;      /* Mode bits for MEMB instruction */
+
+       opcode = md_chars_to_number(opcodeP, 4);
+       know(!(opcode & MEMB_BIT));
+
+       mode = MEMB_BIT | D_BIT;
+       if (opcode & MEMA_ABASE){
+               mode |= A_BIT;
+       }
+
+       opcode &= 0xffffc000;   /* Clear MEMA offset and mode bits */
+       opcode |= mode;         /* Set MEMB mode bits */
+
+       md_number_to_chars(opcodeP, opcode, 4);
+} /* mema_to_memb() */
+
+
+/*****************************************************************************
+ * parse_expr:         parse an expression
+ *
+ *     Use base assembler's expression parser to parse an expression.
+ *     It, unfortunately, runs off a global which we have to save/restore
+ *     in order to make it work for us.
+ *
+ *     An empty expression string is treated as an absolute 0.
+ *
+ *     Return "segment" to which the expression evaluates.
+ *     Return SEG_GOOF regardless of expression evaluation if entire input
+ *     string is not consumed in the evaluation -- tolerate no dangling junk!
+ *
+ **************************************************************************** */
+static
+segT
+parse_expr(textP, expP)
+    char *textP;       /* Text of expression to be parsed */
+    expressionS *expP; /* Where to put the results of parsing */
+{
+       char *save_in;  /* Save global here */
+       segT seg;       /* Segment to which expression evaluates */
+       symbolS *symP;
+
+       know(textP);
+
+       if (*textP == '\0') {
+               /* Treat empty string as absolute 0 */
+               expP->X_add_symbol = expP->X_subtract_symbol = NULL;
+               expP->X_add_number = 0;
+               seg = expP->X_seg = SEG_ABSOLUTE;
+
+       } else {
+               save_in = input_line_pointer;   /* Save global */
+               input_line_pointer = textP;     /* Make parser work for us */
+
+               seg = expression(expP);
+               if (input_line_pointer - textP != strlen(textP)) {
+                       /* Did not consume all of the input */
+                       seg = SEG_GOOF;
+               }
+               symP = expP->X_add_symbol;
+               if (symP && (hash_find(reg_hash, S_GET_NAME(symP)))) {
+                       /* Register name in an expression */
+                       seg = SEG_GOOF;
+               }
+
+               input_line_pointer = save_in;   /* Restore global */
+       }
+       return seg;
+}
+
+
+/*****************************************************************************
+ * parse_ldcont:
+ *     Parse and replace a 'ldconst' pseudo-instruction with an appropriate
+ *     i80960 instruction.
+ *
+ *     Assumes the input consists of:
+ *             arg[0]  opcode mnemonic ('ldconst')
+ *             arg[1]  first operand (constant)
+ *             arg[2]  name of register to be loaded
+ *
+ *     Replaces opcode and/or operands as appropriate.
+ *
+ *     Returns the new number of arguments, or -1 on failure.
+ *
+ **************************************************************************** */
+static
+int
+parse_ldconst(arg)
+    char *arg[];       /* See above */
+{
+       int n;                  /* Constant to be loaded */
+       int shift;              /* Shift count for "shlo" instruction */
+       static char buf[5];     /* Literal for first operand */
+       static char buf2[5];    /* Literal for second operand */
+       expressionS e;          /* Parsed expression */
+
+
+       arg[3] = NULL;  /* So we can tell at the end if it got used or not */
+
+       switch(parse_expr(arg[1],&e)){
+
+       case SEG_TEXT:
+       case SEG_DATA:
+       case SEG_BSS:
+       case SEG_UNKNOWN:
+       case SEG_DIFFERENCE:
+               /* We're dependent on one or more symbols -- use "lda" */
+               arg[0] = "lda";
+               break;
+
+       case SEG_ABSOLUTE:
+               /* Try the following mappings:
+                *      ldconst 0,<reg>  ->mov  0,<reg>
+                *      ldconst 31,<reg> ->mov  31,<reg>
+                *      ldconst 32,<reg> ->addo 1,31,<reg>
+                *      ldconst 62,<reg> ->addo 31,31,<reg>
+                *      ldconst 64,<reg> ->shlo 8,3,<reg>
+                *      ldconst -1,<reg> ->subo 1,0,<reg>
+                *      ldconst -31,<reg>->subo 31,0,<reg>
+                *
+                * anthing else becomes:
+                *      lda xxx,<reg>
+                */
+               n = offs(e);
+               if ((0 <= n) && (n <= 31)){
+                       arg[0] = "mov";
+
+               } else if ((-31 <= n) && (n <= -1)){
+                       arg[0] = "subo";
+                       arg[3] = arg[2];
+                       sprintf(buf, "%d", -n);
+                       arg[1] = buf;
+                       arg[2] = "0";
+
+               } else if ((32 <= n) && (n <= 62)){
+                       arg[0] = "addo";
+                       arg[3] = arg[2];
+                       arg[1] = "31";
+                       sprintf(buf, "%d", n-31);
+                       arg[2] = buf;
+
+               } else if ((shift = shift_ok(n)) != 0){
+                       arg[0] = "shlo";
+                       arg[3] = arg[2];
+                       sprintf(buf, "%d", shift);
+                       arg[1] = buf;
+                       sprintf(buf2, "%d", n >> shift);
+                       arg[2] = buf2;
+
+               } else {
+                       arg[0] = "lda";
+               }
+               break;
+
+       default:
+               as_bad("invalid constant");
+               return -1;
+               break;
+       }
+       return (arg[3] == 0) ? 2: 3;
+}
+
+/*****************************************************************************
+ * parse_memop:        parse a memory operand
+ *
+ *     This routine is based on the observation that the 4 mode bits of the
+ *     MEMB format, taken individually, have fairly consistent meaning:
+ *
+ *              M3 (bit 13): 1 if displacement is present (D_BIT)
+ *              M2 (bit 12): 1 for MEMB instructions (MEMB_BIT)
+ *              M1 (bit 11): 1 if index is present (I_BIT)
+ *              M0 (bit 10): 1 if abase is present (A_BIT)
+ *
+ *     So we parse the memory operand and set bits in the mode as we find
+ *     things.  Then at the end, if we go to MEMB format, we need only set
+ *     the MEMB bit (M2) and our mode is built for us.
+ *
+ *     Unfortunately, I said "fairly consistent".  The exceptions:
+ *
+ *              DBIA
+ *              0100   Would seem illegal, but means "abase-only".
+ *
+ *              0101   Would seem to mean "abase-only" -- it means IP-relative.
+ *                     Must be converted to 0100.
+ *
+ *              0110   Would seem to mean "index-only", but is reserved.
+ *                     We turn on the D bit and provide a 0 displacement.
+ *
+ *     The other thing to observe is that we parse from the right, peeling
+ *     things * off as we go:  first any index spec, then any abase, then
+ *     the displacement.
+ *
+ **************************************************************************** */
+static
+void
+parse_memop(memP, argP, optype)
+    memS *memP;        /* Where to put the results */
+    char *argP;        /* Text of the operand to be parsed */
+    int optype;        /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16 */
+{
+       char *indexP;   /* Pointer to index specification with "[]" removed */
+       char *p;        /* Temp char pointer */
+       char iprel_flag;/* True if this is an IP-relative operand */
+       int regnum;     /* Register number */
+       int scale;      /* Scale factor: 1,2,4,8, or 16.  Later converted
+                        *      to internal format (0,1,2,3,4 respectively).
+                        */
+       int mode;       /* MEMB mode bits */
+       int *intP;      /* Pointer to register number */
+
+       /* The following table contains the default scale factors for each
+        * type of memory instruction.  It is accessed using (optype-MEM1)
+        * as an index -- thus it assumes the 'optype' constants are assigned
+        * consecutive values, in the order they appear in this table
+        */
+       static int def_scale[] = {
+               1,      /* MEM1 */
+               2,      /* MEM2 */
+               4,      /* MEM4 */
+               8,      /* MEM8 */
+               -1,     /* MEM12 -- no valid default */
+               16      /* MEM16 */
+       };
+
+
+       iprel_flag = mode = 0;
+
+       /* Any index present? */
+       indexP = get_ispec(argP);
+       if (indexP) {
+               p = strchr(indexP, '*');
+               if (p == NULL) {
+                       /* No explicit scale -- use default for this
+                        *instruction type.
+                        */
+                       scale = def_scale[ optype - MEM1 ];
+               } else {
+                       *p++ = '\0';    /* Eliminate '*' */
+
+                       /* Now indexP->a '\0'-terminated register name,
+                        * and p->a scale factor.
+                        */
+
+                       if (!strcmp(p,"16")){
+                               scale = 16;
+                       } else if (strchr("1248",*p) && (p[1] == '\0')){
+                               scale = *p - '0';
+                       } else {
+                               scale = -1;
+                       }
+               }
+
+               regnum = get_regnum(indexP);            /* Get index reg. # */
+               if (!IS_RG_REG(regnum)){
+                       as_bad("invalid index register");
+                       return;
+               }
+
+               /* Convert scale to its binary encoding */
+               switch (scale){
+               case  1: scale = 0 << 7; break;
+               case  2: scale = 1 << 7; break;
+               case  4: scale = 2 << 7; break;
+               case  8: scale = 3 << 7; break;
+               case 16: scale = 4 << 7; break;
+               default: as_bad("invalid scale factor"); return;
+               };
+
+               memP->opcode |= scale | regnum;  /* Set index bits in opcode */
+               mode |= I_BIT;                  /* Found a valid index spec */
+       }
+
+       /* Any abase (Register Indirect) specification present? */
+       if ((p = strrchr(argP,'(')) != NULL) {
+               /* "(" is there -- does it start a legal abase spec?
+                * (If not it could be part of a displacement expression.)
+                */
+               intP = (int *) hash_find(areg_hash, p);
+               if (intP != NULL){
+                       /* Got an abase here */
+                       regnum = *intP;
+                       *p = '\0';      /* discard register spec */
+                       if (regnum == IPREL){
+                               /* We have to specialcase ip-rel mode */
+                               iprel_flag = 1;
+                       } else {
+                               memP->opcode |= regnum << 14;
+                               mode |= A_BIT;
+                       }
+               }
+       }
+
+       /* Any expression present? */
+       memP->e = argP;
+       if (*argP != '\0'){
+               mode |= D_BIT;
+       }
+
+       /* Special-case ip-relative addressing */
+       if (iprel_flag){
+               if (mode & I_BIT){
+                       syntax();
+               } else {
+                       memP->opcode |= 5 << 10;        /* IP-relative mode */
+                       memP->disp = 32;
+               }
+               return;
+       }
+
+       /* Handle all other modes */
+       switch (mode){
+       case D_BIT | A_BIT:
+               /* Go with MEMA instruction format for now (grow to MEMB later
+                *      if 12 bits is not enough for the displacement).
+                * MEMA format has a single mode bit: set it to indicate
+                *      that abase is present.
+                */
+               memP->opcode |= MEMA_ABASE;
+               memP->disp = 12;
+               break;
+
+       case D_BIT:
+               /* Go with MEMA instruction format for now (grow to MEMB later
+                *      if 12 bits is not enough for the displacement).
+                */
+               memP->disp = 12;
+               break;
+
+       case A_BIT:
+               /* For some reason, the bit string for this mode is not
+                * consistent:  it should be 0 (exclusive of the MEMB bit),
+                * so we set it "by hand" here.
+                */
+               memP->opcode |= MEMB_BIT;
+               break;
+
+       case A_BIT | I_BIT:
+               /* set MEMB bit in mode, and OR in mode bits */
+               memP->opcode |= mode | MEMB_BIT;
+               break;
+
+       case I_BIT:
+               /* Treat missing displacement as displacement of 0 */
+               mode |= D_BIT;
+               /***********************
+                * Fall into next case *
+                ********************** */
+       case D_BIT | A_BIT | I_BIT:
+       case D_BIT | I_BIT:
+               /* set MEMB bit in mode, and OR in mode bits */
+               memP->opcode |= mode | MEMB_BIT;
+               memP->disp = 32;
+               break;
+
+       default:
+               syntax();
+               break;
+       }
+}
+
+/*****************************************************************************
+ * parse_po:   parse machine-dependent pseudo-op
+ *
+ *     This is a top-level routine for machine-dependent pseudo-ops.  It slurps
+ *     up the rest of the input line, breaks out the individual arguments,
+ *     and dispatches them to the correct handler.
+ **************************************************************************** */
+static
+void
+parse_po(po_num)
+    int po_num;         /* Pseudo-op number:  currently S_LEAFPROC or S_SYSPROC */
+{
+       char *args[4];  /* Pointers operands, with no embedded whitespace.
+                        *      arg[0] unused.
+                        *      arg[1-3]->operands
+                        */
+       int n_ops;      /* Number of operands */
+       char *p;        /* Pointer to beginning of unparsed argument string */
+       char eol;       /* Character that indicated end of line */
+
+       extern char is_end_of_line[];
+
+       /* Advance input pointer to end of line. */
+       p = input_line_pointer;
+       while (!is_end_of_line[ *input_line_pointer ]){
+               input_line_pointer++;
+       }
+       eol = *input_line_pointer;      /* Save end-of-line char */
+       *input_line_pointer = '\0';     /* Terminate argument list */
+
+       /* Parse out operands */
+       n_ops = get_args(p, args);
+       if (n_ops == -1){
+               return;
+       }
+
+       /* Dispatch to correct handler */
+       switch(po_num){
+       case S_SYSPROC:         s_sysproc(n_ops, args); break;
+       case S_LEAFPROC:        s_leafproc(n_ops, args);        break;
+       default:                BAD_CASE(po_num);               break;
+       }
+
+       /* Restore eol, so line numbers get updated correctly.  Base assembler
+        * assumes we leave input pointer pointing at char following the eol.
+        */
+       *input_line_pointer++ = eol;
+}
+
+/*****************************************************************************
+ * parse_regop: parse a register operand.
+ *
+ *     In case of illegal operand, issue a message and return some valid
+ *     information so instruction processing can continue.
+ **************************************************************************** */
+static
+void
+parse_regop(regopP, optext, opdesc)
+    struct regop *regopP; /* Where to put description of register operand */
+    char *optext;      /* Text of operand */
+    char opdesc;       /* Descriptor byte:  what's legal for this operand */
+{
+       int n;          /* Register number */
+       expressionS e;  /* Parsed expression */
+
+       /* See if operand is a register */
+       n = get_regnum(optext);
+       if (n >= 0){
+               if (IS_RG_REG(n)){
+                       /* global or local register */
+                       if (!REG_ALIGN(opdesc,n)){
+                               as_bad("unaligned register");
+                       }
+                       regopP->n = n;
+                       regopP->mode = 0;
+                       regopP->special = 0;
+                       return;
+               } else if (IS_FP_REG(n) && FP_OK(opdesc)){
+                       /* Floating point register, and it's allowed */
+                       regopP->n = n - FP0;
+                       regopP->mode = 1;
+                       regopP->special = 0;
+                       return;
+               } else if (IS_SF_REG(n) && SFR_OK(opdesc)){
+                       /* Special-function register, and it's allowed */
+                       regopP->n = n - SF0;
+                       regopP->mode = 0;
+                       regopP->special = 1;
+                       if (!targ_has_sfr(regopP->n)){
+                               as_bad("no such sfr in this architecture");
+                       }
+                       return;
+               }
+       } else if (LIT_OK(opdesc)){
+               /*
+                * How about a literal?
+                */
+               regopP->mode = 1;
+               regopP->special = 0;
+               if (FP_OK(opdesc)){     /* floating point literal acceptable */
+                        /* Skip over 0f, 0d, or 0e prefix */
+                        if ( (optext[0] == '0')
+                             && (optext[1] >= 'd')
+                             && (optext[1] <= 'f') ){
+                                optext += 2;
+                        }
+
+                        if (!strcmp(optext,"0.0") || !strcmp(optext,"0") ){
+                                regopP->n = 0x10;
+                                return;
+                        }
+                        if (!strcmp(optext,"1.0") || !strcmp(optext,"1") ){
+                                regopP->n = 0x16;
+                                return;
+                        }
+
+               } else {                /* fixed point literal acceptable */
+                       if ((parse_expr(optext,&e) != SEG_ABSOLUTE)
+                       ||   (offs(e) < 0) || (offs(e) > 31)){
+                               as_bad("illegal literal");
+                               offs(e) = 0;
+                       }
+                       regopP->n = offs(e);
+                       return;
+               }
+       }
+
+       /* Nothing worked */
+       syntax();
+       regopP->mode = 0;       /* Register r0 is always a good one */
+       regopP->n = 0;
+       regopP->special = 0;
+} /* parse_regop() */
+
+/*****************************************************************************
+ * reg_fmt:    generate a REG-format instruction
+ *
+ **************************************************************************** */
+static void reg_fmt(args, oP)
+    char *args[];      /* args[0]->opcode mnemonic, args[1-3]->operands */
+    struct i960_opcode *oP; /* Pointer to description of instruction */
+{
+       long instr;             /* Binary to be output */
+       struct regop regop;     /* Description of register operand */
+       int n_ops;              /* Number of operands */
+
+
+       instr = oP->opcode;
+       n_ops = oP->num_ops;
+
+       if (n_ops >= 1){
+               parse_regop(&regop, args[1], oP->operand[0]);
+
+               if ((n_ops == 1) && !(instr & M3)){
+                       /* 1-operand instruction in which the dst field should
+                        * be used (instead of src1).
+                        */
+                       regop.n       <<= 19;
+                       if (regop.special){
+                               regop.mode = regop.special;
+                       }
+                       regop.mode    <<= 13;
+                       regop.special = 0;
+               } else {
+                       /* regop.n goes in bit 0, needs no shifting */
+                       regop.mode    <<= 11;
+                       regop.special <<= 5;
+               }
+               instr |= regop.n | regop.mode | regop.special;
+       }
+
+       if (n_ops >= 2) {
+               parse_regop(&regop, args[2], oP->operand[1]);
+
+               if ((n_ops == 2) && !(instr & M3)){
+                       /* 2-operand instruction in which the dst field should
+                        * be used instead of src2).
+                        */
+                       regop.n       <<= 19;
+                       if (regop.special){
+                               regop.mode = regop.special;
+                       }
+                       regop.mode    <<= 13;
+                       regop.special = 0;
+               } else {
+                       regop.n       <<= 14;
+                       regop.mode    <<= 12;
+                       regop.special <<= 6;
+               }
+               instr |= regop.n | regop.mode | regop.special;
+       }
+       if (n_ops == 3){
+               parse_regop(&regop, args[3], oP->operand[2]);
+               if (regop.special){
+                       regop.mode = regop.special;
+               }
+               instr |= (regop.n <<= 19) | (regop.mode <<= 13);
+       }
+       emit(instr);
+}
+
+
+/*****************************************************************************
+ * relax_cobr:
+ *     Replace cobr instruction in a code fragment with equivalent branch and
+ *     compare instructions, so it can reach beyond a 13-bit displacement.
+ *     Set up an address fix/relocation for the new branch instruction.
+ *
+ **************************************************************************** */
+
+/* This "conditional jump" table maps cobr instructions into equivalent
+ * compare and branch opcodes.
+ */
+static
+struct {
+       long compare;
+       long branch;
+} coj[] = {            /* COBR OPCODE: */
+       CHKBIT, BNO,    /*      0x30 - bbc */
+       CMPO,   BG,     /*      0x31 - cmpobg */
+       CMPO,   BE,     /*      0x32 - cmpobe */
+       CMPO,   BGE,    /*      0x33 - cmpobge */
+       CMPO,   BL,     /*      0x34 - cmpobl */
+       CMPO,   BNE,    /*      0x35 - cmpobne */
+       CMPO,   BLE,    /*      0x36 - cmpoble */
+       CHKBIT, BO,     /*      0x37 - bbs */
+       CMPI,   BNO,    /*      0x38 - cmpibno */
+       CMPI,   BG,     /*      0x39 - cmpibg */
+       CMPI,   BE,     /*      0x3a - cmpibe */
+       CMPI,   BGE,    /*      0x3b - cmpibge */
+       CMPI,   BL,     /*      0x3c - cmpibl */
+       CMPI,   BNE,    /*      0x3d - cmpibne */
+       CMPI,   BLE,    /*      0x3e - cmpible */
+       CMPI,   BO,     /*      0x3f - cmpibo */
+};
+
+static
+void
+relax_cobr(fragP)
+    register fragS *fragP;     /* fragP->fr_opcode is assumed to point to
+                                * the cobr instruction, which comes at the
+                                * end of the code fragment.
+                                */
+{
+       int opcode, src1, src2, m1, s2;
+                       /* Bit fields from cobr instruction */
+       long bp_bits;   /* Branch prediction bits from cobr instruction */
+       long instr;     /* A single i960 instruction */
+       char *iP;       /*->instruction to be replaced */
+       fixS *fixP;     /* Relocation that can be done at assembly time */
+
+       /* PICK UP & PARSE COBR INSTRUCTION */
+       iP = fragP->fr_opcode;
+       instr  = md_chars_to_number(iP, 4);
+       opcode = ((instr >> 24) & 0xff) - 0x30; /* "-0x30" for table index */
+       src1   = (instr >> 19) & 0x1f;
+       m1     = (instr >> 13) & 1;
+       s2     = instr & 1;
+       src2   = (instr >> 14) & 0x1f;
+       bp_bits= instr & BP_MASK;
+
+       /* GENERATE AND OUTPUT COMPARE INSTRUCTION */
+       instr = coj[opcode].compare
+                       | src1 | (m1 << 11) | (s2 << 6) | (src2 << 14);
+       md_number_to_chars(iP, instr, 4);
+
+       /* OUTPUT BRANCH INSTRUCTION */
+       md_number_to_chars(iP+4, coj[opcode].branch | bp_bits, 4);
+
+       /* SET UP ADDRESS FIXUP/RELOCATION */
+       fixP = fix_new(fragP,
+                      iP+4 - fragP->fr_literal,
+                      4,
+                      fragP->fr_symbol,
+                      0,
+                      fragP->fr_offset,
+                      1,
+                      0);
+
+       fixP->fx_bit_fixP = (bit_fixS *) 24;    /* Store size of bit field */
+
+       fragP->fr_fix += 4;
+       frag_wane(fragP);
+}
+
+
+/*****************************************************************************
+ * reloc_callj:        Relocate a 'callj' instruction
+ *
+ *     This is a "non-(GNU)-standard" machine-dependent hook.  The base
+ *     assembler calls it when it decides it can relocate an address at
+ *     assembly time instead of emitting a relocation directive.
+ *
+ *     Check to see if the relocation involves a 'callj' instruction to a:
+ *         sysproc:    Replace the default 'call' instruction with a 'calls'
+ *         leafproc:   Replace the default 'call' instruction with a 'bal'.
+ *         other proc: Do nothing.
+ *
+ *     See b.out.h for details on the 'n_other' field in a symbol structure.
+ *
+ * IMPORTANT!:
+ *     Assumes the caller has already figured out, in the case of a leafproc,
+ *     to use the 'bal' entry point, and has substituted that symbol into the
+ *     passed fixup structure.
+ *
+ **************************************************************************** */
+void reloc_callj(fixP)
+fixS *fixP;            /* Relocation that can be done at assembly time */
+{
+       char *where;    /*->the binary for the instruction being relocated */
+
+       if (!fixP->fx_callj) {
+               return;
+       } /* This wasn't a callj instruction in the first place */
+
+       where = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+       if (TC_S_IS_SYSPROC(fixP->fx_addsy)) {
+               /* Symbol is a .sysproc: replace 'call' with 'calls'.
+                * System procedure number is (other-1).
+                */
+               md_number_to_chars(where, CALLS|TC_S_GET_SYSPROC(fixP->fx_addsy), 4);
+
+               /* Nothing else needs to be done for this instruction.
+                * Make sure 'md_number_to_field()' will perform a no-op.
+                */
+               fixP->fx_bit_fixP = (bit_fixS *) 1;
+
+       } else if (TC_S_IS_CALLNAME(fixP->fx_addsy)) {
+               /* Should not happen: see block comment above */
+               as_fatal("Trying to 'bal' to %s", S_GET_NAME(fixP->fx_addsy));
+
+       } else if (TC_S_IS_BALNAME(fixP->fx_addsy)) {
+               /* Replace 'call' with 'bal';  both instructions have
+                * the same format, so calling code should complete
+                * relocation as if nothing happened here.
+                */
+               md_number_to_chars(where, BAL, 4);
+       } else if (TC_S_IS_BADPROC(fixP->fx_addsy)) {
+               as_bad("Looks like a proc, but can't tell what kind.\n");
+       } /* switch on proc type */
+       
+       /* else Symbol is neither a sysproc nor a leafproc */
+       
+       return;
+} /* reloc_callj() */
+
+
+/*****************************************************************************
+ * s_leafproc: process .leafproc pseudo-op
+ *
+ *     .leafproc takes two arguments, the second one is optional:
+ *             arg[1]: name of 'call' entry point to leaf procedure
+ *             arg[2]: name of 'bal' entry point to leaf procedure
+ *
+ *     If the two arguments are identical, or if the second one is missing,
+ *     the first argument is taken to be the 'bal' entry point.
+ *
+ *     If there are 2 distinct arguments, we must make sure that the 'bal'
+ *     entry point immediately follows the 'call' entry point in the linked
+ *     list of symbols.
+ *
+ **************************************************************************** */
+static void s_leafproc(n_ops, args)
+int n_ops;             /* Number of operands */
+char *args[];  /* args[1]->1st operand, args[2]->2nd operand */
+{
+       symbolS *callP; /* Pointer to leafproc 'call' entry point symbol */
+       symbolS *balP;  /* Pointer to leafproc 'bal' entry point symbol */
+
+       if ((n_ops != 1) && (n_ops != 2)) {
+               as_bad("should have 1 or 2 operands");
+               return;
+       } /* Check number of arguments */
+
+       /* Find or create symbol for 'call' entry point. */
+       callP = symbol_find_or_make(args[1]);
+
+       if (TC_S_IS_CALLNAME(callP)) {
+               as_warn("Redefining leafproc %s", S_GET_NAME(callP));
+       } /* is leafproc */
+
+       /* If that was the only argument, use it as the 'bal' entry point.
+        * Otherwise, mark it as the 'call' entry point and find or create
+        * another symbol for the 'bal' entry point.
+        */
+       if ((n_ops == 1) || !strcmp(args[1],args[2])) {
+               TC_S_FORCE_TO_BALNAME(callP);
+
+       } else {
+               TC_S_FORCE_TO_CALLNAME(callP);
+
+               balP = symbol_find_or_make(args[2]);
+               if (TC_S_IS_CALLNAME(balP)) {
+                       as_warn("Redefining leafproc %s", S_GET_NAME(balP));
+               }
+               TC_S_FORCE_TO_BALNAME(balP);
+
+               tc_set_bal_of_call(callP, balP);
+       } /* if only one arg, or the args are the same */
+
+       return;
+} /* s_leafproc() */
+
+
+/*
+ * s_sysproc:  process .sysproc pseudo-op
+ *
+ *     .sysproc takes two arguments:
+ *             arg[1]: name of entry point to system procedure
+ *             arg[2]: 'entry_num' (index) of system procedure in the range
+ *                     [0,31] inclusive.
+ *
+ *     For [ab].out, we store the 'entrynum' in the 'n_other' field of
+ *     the symbol.  Since that entry is normally 0, we bias 'entrynum'
+ *     by adding 1 to it.  It must be unbiased before it is used.
+ */
+static void s_sysproc(n_ops, args)
+int n_ops; /* Number of operands */
+char *args[]; /* args[1]->1st operand, args[2]->2nd operand */
+{
+       expressionS exp;
+       symbolS *symP;
+
+       if (n_ops != 2) {
+               as_bad("should have two operands");
+               return;
+       } /* bad arg count */
+
+       /* Parse "entry_num" argument and check it for validity. */
+       if ((parse_expr(args[2],&exp) != SEG_ABSOLUTE)
+           || (offs(exp) < 0)
+           || (offs(exp) > 31)) {
+               as_bad("'entry_num' must be absolute number in [0,31]");
+               return;
+       }
+
+       /* Find/make symbol and stick entry number (biased by +1) into it */
+       symP = symbol_find_or_make(args[1]);
+
+       if (TC_S_IS_SYSPROC(symP)) {
+               as_warn("Redefining entrynum for sysproc %s", S_GET_NAME(symP));
+       } /* redefining */
+
+       TC_S_SET_SYSPROC(symP, offs(exp)); /* encode entry number */
+       TC_S_FORCE_TO_SYSPROC(symP);
+
+       return;
+} /* s_sysproc() */
+
+
+/*****************************************************************************
+ * shift_ok:
+ *     Determine if a "shlo" instruction can be used to implement a "ldconst".
+ *     This means that some number X < 32 can be shifted left to produce the
+ *     constant of interest.
+ *
+ *     Return the shift count, or 0 if we can't do it.
+ *     Caller calculates X by shifting original constant right 'shift' places.
+ *
+ **************************************************************************** */
+static
+int
+shift_ok(n)
+    int n;             /* The constant of interest */
+{
+       int shift;      /* The shift count */
+
+       if (n <= 0){
+               /* Can't do it for negative numbers */
+               return 0;
+       }
+
+       /* Shift 'n' right until a 1 is about to be lost */
+       for (shift = 0; (n & 1) == 0; shift++){
+               n >>= 1;
+       }
+
+       if (n >= 32){
+               return 0;
+       }
+       return shift;
+}
+
+
+/*****************************************************************************
+ * syntax:     issue syntax error
+ *
+ **************************************************************************** */
+static void syntax() {
+       as_bad("syntax error");
+} /* syntax() */
+
+
+/*****************************************************************************
+ * targ_has_sfr:
+ *     Return TRUE iff the target architecture supports the specified
+ *     special-function register (sfr).
+ *
+ **************************************************************************** */
+static
+int
+targ_has_sfr(n)
+    int n;     /* Number (0-31) of sfr */
+{
+       switch (architecture){
+       case ARCH_KA:
+       case ARCH_KB:
+       case ARCH_MC:
+               return 0;
+       case ARCH_CA:
+       default:
+               return ((0<=n) && (n<=2));
+       }
+}
+
+
+/*****************************************************************************
+ * targ_has_iclass:
+ *     Return TRUE iff the target architecture supports the indicated
+ *     class of instructions.
+ *
+ **************************************************************************** */
+static
+int
+targ_has_iclass(ic)
+    int ic;    /* Instruction class;  one of:
+                *      I_BASE, I_CX, I_DEC, I_KX, I_FP, I_MIL, I_CASIM
+                */
+{
+       iclasses_seen |= ic;
+       switch (architecture){
+       case ARCH_KA:   return ic & (I_BASE | I_KX);
+       case ARCH_KB:   return ic & (I_BASE | I_KX | I_FP | I_DEC);
+       case ARCH_MC:   return ic & (I_BASE | I_KX | I_FP | I_DEC | I_MIL);
+       case ARCH_CA:   return ic & (I_BASE | I_CX | I_CASIM);
+       default:
+               if ((iclasses_seen & (I_KX|I_FP|I_DEC|I_MIL))
+               &&   (iclasses_seen & I_CX)){
+                       as_warn("architecture of opcode conflicts with that of earlier instruction(s)");
+                       iclasses_seen &= ~ic;
+               }
+               return 1;
+       }
+}
+
+
+/* Parse an operand that is machine-specific.
+   We just return without modifying the expression if we have nothing
+   to do. */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+       return 0;
+} /* md_undefined_symbol() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the i960, they're relative to the address of the instruction,
+   which we have set up as the address of the fixup too. */
+long
+md_pcrel_from (fixP)
+     fixS *fixP;
+{
+  return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+void
+md_apply_fix(fixP, val)
+    fixS *fixP;
+    long val;
+{
+       char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+       if (!fixP->fx_bit_fixP) {
+
+               switch (fixP->fx_im_disp) {
+               case 0:
+                       fixP->fx_addnumber = val;
+                       md_number_to_imm(place, val, fixP->fx_size, fixP);
+                       break;
+               case 1:
+                       md_number_to_disp(place,
+                                          fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val,
+                                          fixP->fx_size);
+                       break;
+               case 2: /* fix requested for .long .word etc */
+                       md_number_to_chars(place, val, fixP->fx_size);
+                       break;
+               default:
+                       as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__);
+               } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+       } else {
+               md_number_to_field(place, val, fixP->fx_bit_fixP);
+       }
+
+       return;
+} /* md_apply_fix() */
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+/*
+ *             emit_relocations()
+ *
+ * Crawl along a fixS chain. Emit the segment's relocations.
+ */
+static void
+emit_machine_reloc (fixP, segment_address_in_file)
+     register fixS *   fixP;   /* Fixup chain for this segment. */
+     relax_addressT    segment_address_in_file;
+{
+  struct reloc_info_generic    ri;
+  register symbolS *           symbolP;
+
+       /* JF this is for paranoia */
+  bzero((char *)&ri,sizeof(ri));
+  for (;  fixP;  fixP = fixP->fx_next)
+    {
+      if ((symbolP = fixP->fx_addsy) != 0)
+       {
+         /* These two 'cuz of NS32K */
+         ri . r_bsr            = fixP->fx_bsr;
+         ri . r_disp           = fixP->fx_im_disp;
+
+         ri . r_callj          = fixP->fx_callj;
+
+         ri . r_length         = nbytes_r_length [fixP->fx_size];
+         ri . r_pcrel          = fixP->fx_pcrel;
+         ri . r_address        = fixP->fx_frag->fr_address
+           +   fixP->fx_where
+             - segment_address_in_file;
+         if (!S_IS_DEFINED(symbolP))
+           {
+             ri . r_extern     = 1;
+             ri . r_symbolnum  = symbolP->sy_number;
+           }
+         else
+           {
+             ri . r_extern     = 0;
+             ri . r_symbolnum  = S_GET_TYPE(symbolP);
+           }
+
+         /* Output the relocation information in machine-dependent form. */
+         md_ri_to_chars(next_object_file_charP, &ri);
+         next_object_file_charP += sizeof(struct relocation_info);
+       }
+    }
+
+} /* emit_machine_reloc() */
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+/* Align an address by rounding it up to the specified boundary.
+ */
+long md_section_align(seg, addr)
+segT seg;
+long addr;             /* Address to be rounded up */
+{
+       return((addr + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));
+} /* md_section_align() */
+
+#ifdef OBJ_COFF
+void tc_headers_hook(headers)
+object_headers *headers;
+{
+       unsigned short arch_flag = 0;
+
+       if (iclasses_seen == I_BASE){
+               headers->filehdr.f_flags |= F_I960CORE;
+       } else if (iclasses_seen & I_CX){
+               headers->filehdr.f_flags |= F_I960CA;
+       } else if (iclasses_seen & I_MIL){
+               headers->filehdr.f_flags |= F_I960MC;
+       } else if (iclasses_seen & (I_DEC|I_FP)){
+               headers->filehdr.f_flags |= F_I960KB;
+       } else {
+               headers->filehdr.f_flags |= F_I960KA;
+       } /* set arch flag */
+
+       if (flagseen['R']) {
+               headers->filehdr.f_magic = I960RWMAGIC;
+               headers->aouthdr.magic = OMAGIC;
+       } else {
+               headers->filehdr.f_magic = I960ROMAGIC;
+               headers->aouthdr.magic = NMAGIC;
+       } /* set magic numbers */
+       
+       return;
+} /* tc_headers_hook() */
+#endif /* OBJ_COFF */
+
+/*
+ * Things going on here:
+ *
+ * For bout, We need to assure a couple of simplifying
+ * assumptions about leafprocs for the linker: the leafproc
+ * entry symbols will be defined in the same assembly in
+ * which they're declared with the '.leafproc' directive;
+ * and if a leafproc has both 'call' and 'bal' entry points
+ * they are both global or both local.
+ *
+ * For coff, the call symbol has a second aux entry that
+ * contains the bal entry point.  The bal symbol becomes a
+ * label.
+ *
+ * For coff representation, the call symbol has a second aux entry that
+ * contains the bal entry point.  The bal symbol becomes a label.
+ *
+ */
+
+void tc_crawl_symbol_chain(headers)
+object_headers *headers;
+{
+       symbolS *symbolP;
+
+       for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+#ifdef OBJ_COFF
+               if (TC_S_IS_SYSPROC(symbolP)) {
+                       /* second aux entry already contains the sysproc number */
+                       S_SET_NUMBER_AUXILIARY(symbolP, 2);
+                       S_SET_STORAGE_CLASS(symbolP, C_SCALL);
+                       S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT));
+                       continue;
+               } /* rewrite sysproc */
+#endif /* OBJ_COFF */
+
+               if (!TC_S_IS_BALNAME(symbolP) && !TC_S_IS_CALLNAME(symbolP)) {
+                       continue;
+               }  /* Not a leafproc symbol */
+
+               if (!S_IS_DEFINED(symbolP)) {
+                       as_bad("leafproc symbol '%s' undefined", S_GET_NAME(symbolP));
+               } /* undefined leaf */
+
+               if (TC_S_IS_CALLNAME(symbolP)) {
+                       symbolS *balP = tc_get_bal_of_call(symbolP);
+                       if (S_IS_EXTERNAL(symbolP) != S_IS_EXTERNAL(balP)) {
+                               S_SET_EXTERNAL(symbolP);
+                               S_SET_EXTERNAL(balP);
+                               as_warn("Warning: making leafproc entries %s and %s both global\n",
+                                       S_GET_NAME(symbolP), S_GET_NAME(balP));
+                       } /* externality mismatch */
+               } /* if callname */
+       } /* walk the symbol chain */
+
+       return;
+} /* tc_crawl_symbol_chain() */
+
+/*
+ * For aout or bout, the bal immediately follows the call.
+ *
+ * For coff, we cheat and store a pointer to the bal symbol
+ * in the second aux entry of the call.
+ */
+
+void tc_set_bal_of_call(callP, balP)
+symbolS *callP;
+symbolS *balP;
+{
+       know(TC_S_IS_CALLNAME(callP));
+       know(TC_S_IS_BALNAME(balP));
+       
+#ifdef OBJ_COFF
+
+       callP->sy_symbol.ost_auxent[1].x_bal.x_balntry = (int) balP;
+       S_SET_NUMBER_AUXILIARY(callP,2);
+
+#elif defined(OBJ_AOUT) || defined(OBJ_BOUT)
+
+       /* If the 'bal' entry doesn't immediately follow the 'call'
+        * symbol, unlink it from the symbol list and re-insert it.
+        */
+       if (symbol_next(callP) != balP) {
+               symbol_remove(balP, &symbol_rootP, &symbol_lastP);
+               symbol_append(balP, callP, &symbol_rootP, &symbol_lastP);
+       } /* if not in order */
+
+#else
+       (as yet unwritten.);
+#endif /* switch on OBJ_FORMAT */
+       
+       return;
+} /* tc_set_bal_of_call() */
+
+char *_tc_get_bal_of_call(callP)
+symbolS *callP;
+{
+       symbolS *retval;
+
+       know(TC_S_IS_CALLNAME(callP));
+
+#ifdef OBJ_COFF
+       retval = (symbolS *) (callP->sy_symbol.ost_auxent[1].x_bal.x_balntry);
+#elif defined(OBJ_AOUT) || defined(OBJ_BOUT)
+       retval = symbol_next(callP);
+#else
+       (as yet unwritten.);
+#endif /* switch on OBJ_FORMAT */
+
+       know(TC_S_IS_BALNAME(retval));
+       return((char *) retval);
+} /* _tc_get_bal_of_call() */
+
+void tc_coff_symbol_emit_hook(symbolP)
+symbolS *symbolP;
+{
+       if (TC_S_IS_CALLNAME(symbolP)) {
+#ifdef OBJ_COFF
+               symbolS *balP = tc_get_bal_of_call(symbolP);
+               
+               /* second aux entry contains the bal entry point */
+/*             S_SET_NUMBER_AUXILIARY(symbolP, 2); */
+               symbolP->sy_symbol.ost_auxent[1].x_bal.x_balntry = S_GET_VALUE(balP);
+               S_SET_STORAGE_CLASS(symbolP, (!SF_GET_LOCAL(symbolP) ? C_LEAFEXT : C_LEAFSTAT));
+               S_SET_DATA_TYPE(symbolP, S_GET_DATA_TYPE(symbolP) | (DT_FCN << N_BTSHFT));
+               /* fix up the bal symbol */
+               S_SET_STORAGE_CLASS(balP, C_LABEL);
+#endif /* OBJ_COFF */
+       } /* only on calls */
+       
+       return;
+} /* tc_coff_symbol_emit_hook() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of i960.c */
diff --git a/gas/config/tc-i960.h b/gas/config/tc-i960.h
new file mode 100644 (file)
index 0000000..2b05340
--- /dev/null
@@ -0,0 +1,279 @@
+/* tc-i960.h - Basic 80960 instruction formats.
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+/*
+ * The 'COJ' instructions are actually COBR instructions with the 'b' in
+ * the mnemonic replaced by a 'j';  they are ALWAYS "de-optimized" if necessary:
+ * if the displacement will not fit in 13 bits, the assembler will replace them
+ * with the corresponding compare and branch instructions.
+ *
+ * All of the 'MEMn' instructions are the same format; the 'n' in the name
+ * indicates the default index scale factor (the size of the datum operated on).
+ *
+ * The FBRA formats are not actually an instruction format.  They are the
+ * "convenience directives" for branching on floating-point comparisons,
+ * each of which generates 2 instructions (a 'bno' and one other branch).
+ *
+ * The CALLJ format is not actually an instruction format.  It indicates that
+ * the instruction generated (a CTRL-format 'call') should have its relocation
+ * specially flagged for link-time replacement with a 'bal' or 'calls' if
+ * appropriate.
+ */ 
+
+#define TC_I960 1
+
+ /* tailor gas */
+#define SYMBOLS_NEED_BACKPOINTERS
+#define LOCAL_LABELS_FB
+#define WANT_BITFIELDS
+
+ /* tailor the coff format */
+#define OBJ_COFF_SECTION_HEADER_HAS_ALIGNMENT
+#define OBJ_COFF_MAX_AUXENTRIES        (2)
+
+ /* other */
+#define CTRL   0
+#define COBR   1
+#define COJ    2
+#define REG    3
+#define MEM1   4
+#define MEM2   5
+#define MEM4   6
+#define MEM8   7
+#define MEM12  8
+#define MEM16  9
+#define FBRA   10
+#define CALLJ  11
+
+/* Masks for the mode bits in REG format instructions */
+#define M1             0x0800
+#define M2             0x1000
+#define M3             0x2000
+
+/* Generate the 12-bit opcode for a REG format instruction by placing the 
+ * high 8 bits in instruction bits 24-31, the low 4 bits in instruction bits
+ * 7-10.
+ */
+
+#define REG_OPC(opc)   ((opc & 0xff0) << 20) | ((opc & 0xf) << 7)
+
+/* Generate a template for a REG format instruction:  place the opcode bits
+ * in the appropriate fields and OR in mode bits for the operands that will not
+ * be used.  I.e.,
+ *             set m1=1, if src1 will not be used
+ *             set m2=1, if src2 will not be used
+ *             set m3=1, if dst  will not be used
+ *
+ * Setting the "unused" mode bits to 1 speeds up instruction execution(!).
+ * The information is also useful to us because some 1-operand REG instructions
+ * use the src1 field, others the dst field; and some 2-operand REG instructions
+ * use src1/src2, others src1/dst.  The set mode bits enable us to distinguish.
+ */
+#define R_0(opc)       ( REG_OPC(opc) | M1 | M2 | M3 ) /* No operands      */
+#define R_1(opc)       ( REG_OPC(opc) | M2 | M3 )      /* 1 operand: src1  */
+#define R_1D(opc)      ( REG_OPC(opc) | M1 | M2 )      /* 1 operand: dst   */
+#define R_2(opc)       ( REG_OPC(opc) | M3 )           /* 2 ops: src1/src2 */
+#define R_2D(opc)      ( REG_OPC(opc) | M2 )           /* 2 ops: src1/dst  */
+#define R_3(opc)       ( REG_OPC(opc) )                /* 3 operands       */
+
+/* DESCRIPTOR BYTES FOR REGISTER OPERANDS
+ *
+ * Interpret names as follows:
+ *     R:   global or local register only
+ *     RS:  global, local, or (if target allows) special-function register only
+ *     RL:  global or local register, or integer literal
+ *     RSL: global, local, or (if target allows) special-function register;
+ *             or integer literal
+ *     F:   global, local, or floating-point register
+ *     FL:  global, local, or floating-point register; or literal (including
+ *             floating point)
+ *
+ * A number appended to a name indicates that registers must be aligned,
+ * as follows:
+ *     2: register number must be multiple of 2
+ *     4: register number must be multiple of 4
+ */
+
+#define SFR    0x10            /* Mask for the "sfr-OK" bit */
+#define LIT    0x08            /* Mask for the "literal-OK" bit */
+#define FP     0x04            /* Mask for "floating-point-OK" bit */
+
+/* This macro ors the bits together.  Note that 'align' is a mask
+ * for the low 0, 1, or 2 bits of the register number, as appropriate.
+ */
+#define OP(align,lit,fp,sfr)   ( align | lit | fp | sfr )
+
+#define R      OP( 0, 0,   0,  0   )
+#define RS     OP( 0, 0,   0,  SFR )
+#define RL     OP( 0, LIT, 0,  0   )
+#define RSL    OP( 0, LIT, 0,  SFR )
+#define F      OP( 0, 0,   FP, 0   )
+#define FL     OP( 0, LIT, FP, 0   )
+#define R2     OP( 1, 0,   0,  0   )
+#define RL2    OP( 1, LIT, 0,  0   )
+#define F2     OP( 1, 0,   FP, 0   )
+#define FL2    OP( 1, LIT, FP, 0   )
+#define R4     OP( 3, 0,   0,  0   )
+#define RL4    OP( 3, LIT, 0,  0   )
+#define F4     OP( 3, 0,   FP, 0   )
+#define FL4    OP( 3, LIT, FP, 0   )
+
+#define M      0x7f    /* Memory operand (MEMA & MEMB format instructions) */
+
+/* Macros to extract info from the register operand descriptor byte 'od'.
+ */
+#define SFR_OK(od)     (od & SFR)      /* TRUE if sfr operand allowed */
+#define LIT_OK(od)     (od & LIT)      /* TRUE if literal operand allowed */
+#define FP_OK(od)      (od & FP)       /* TRUE if floating-point op allowed */
+#define REG_ALIGN(od,n)        ((od & 0x3 & n) == 0)
+                                       /* TRUE if reg #n is properly aligned */
+#define MEMOP(od)      (od == M)       /* TRUE if operand is a memory operand*/
+
+/* Classes of 960 intructions:
+ *     - each instruction falls into one class.
+ *     - each target architecture supports one or more classes.
+ *
+ * EACH CONSTANT MUST CONTAIN 1 AND ONLY 1 SET BIT!:  see targ_has_iclass().
+ */
+#define I_BASE 0x01    /* 80960 base instruction set   */
+#define I_CX   0x02    /* 80960Cx instruction          */
+#define I_DEC  0x04    /* Decimal instruction          */
+#define I_FP   0x08    /* Floating point instruction   */
+#define I_KX   0x10    /* 80960Kx instruction          */
+#define I_MIL  0x20    /* Military instruction         */
+
+/* MEANING OF 'n_other' in the symbol record.
+ *
+ * If non-zero, the 'n_other' fields indicates either a leaf procedure or
+ * a system procedure, as follows:
+ *
+ *     1 <= n_other <= 32 :
+ *             The symbol is the entry point to a system procedure.
+ *             'n_value' is the address of the entry, as for any other
+ *             procedure.  The system procedure number (which can be used in
+ *             a 'calls' instruction) is (n_other-1).  These entries come from
+ *             '.sysproc' directives.
+ *
+ *     n_other == N_CALLNAME
+ *             the symbol is the 'call' entry point to a leaf procedure.
+ *             The *next* symbol in the symbol table must be the corresponding
+ *             'bal' entry point to the procedure (see following).  These
+ *             entries come from '.leafproc' directives in which two different
+ *             symbols are specified (the first one is represented here).
+ *     
+ *
+ *     n_other == N_BALNAME
+ *             the symbol is the 'bal' entry point to a leaf procedure.
+ *             These entries result from '.leafproc' directives in which only
+ *             one symbol is specified, or in which the same symbol is
+ *             specified twice.
+ *
+ * Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry,
+ * but not every N_BALNAME entry must have an N_CALLNAME entry.
+ */
+#define        N_CALLNAME      (-1)
+#define        N_BALNAME       (-2)
+
+
+ /* i960 uses a custom relocation record. */
+
+ /* let obj-aout.h know */
+#define CUSTOM_RELOC_FORMAT 1
+ /* let a.out.gnu.h know */
+#define N_RELOCATION_INFO_DECLARED 1
+struct relocation_info {
+       int      r_address;     /* File address of item to be relocated */
+       unsigned
+               r_index:24,/* Index of symbol on which relocation is based*/
+               r_pcrel:1,      /* 1 => relocate PC-relative; else absolute
+                                *      On i960, pc-relative implies 24-bit
+                                *      address, absolute implies 32-bit.
+                                */
+               r_length:2,     /* Number of bytes to relocate:
+                                *      0 => 1 byte
+                                *      1 => 2 bytes
+                                *      2 => 4 bytes -- only value used for i960
+                                */
+               r_extern:1,
+               r_bsr:1,        /* Something for the GNU NS32K assembler */
+               r_disp:1,       /* Something for the GNU NS32K assembler */
+               r_callj:1,      /* 1 if relocation target is an i960 'callj' */
+               nuthin:1;       /* Unused                               */
+};
+
+ /* hacks for tracking callj's */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+
+#define TC_S_IS_SYSPROC(s)     ((1<=S_GET_OTHER(s)) && (S_GET_OTHER(s)<=32))
+#define TC_S_IS_BALNAME(s)     (S_GET_OTHER(s) == N_BALNAME)
+#define TC_S_IS_CALLNAME(s)    (S_GET_OTHER(s) == N_CALLNAME)
+#define TC_S_IS_BADPROC(s)     ((S_GET_OTHER(s) != 0) && !TC_S_IS_CALLNAME(s) && !TC_S_IS_BALNAME(s) && !TC_S_IS_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) (S_SET_OTHER((s), (p)+1))
+#define TC_S_GET_SYSPROC(s)    (S_GET_OTHER(s)-1)
+
+#define TC_S_FORCE_TO_BALNAME(s)       (S_SET_OTHER((s), N_BALNAME))
+#define TC_S_FORCE_TO_CALLNAME(s)      (S_SET_OTHER((s), N_CALLNAME))
+#define TC_S_FORCE_TO_SYSPROC(s)       {;}
+
+#elif defined(OBJ_COFF)
+
+#define TC_S_IS_SYSPROC(s)     (S_GET_STORAGE_CLASS(s) == C_SCALL)
+#define TC_S_IS_BALNAME(s)     (SF_GET_BALNAME(s))
+#define TC_S_IS_CALLNAME(s)    (SF_GET_CALLNAME(s))
+#define TC_S_IS_BADPROC(s)     (TC_S_IS_SYSPROC(s) && TC_S_GET_SYSPROC(s) < 0 && 31 < TC_S_GET_SYSPROC(s))
+
+#define TC_S_SET_SYSPROC(s, p) ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx = (p))
+#define TC_S_GET_SYSPROC(s)    ((s)->sy_symbol.ost_auxent[1].x_sc.x_stindx)
+
+#define TC_S_FORCE_TO_BALNAME(s)       (SF_SET_BALNAME(s))
+#define TC_S_FORCE_TO_CALLNAME(s)      (SF_SET_CALLNAME(s))
+#define TC_S_FORCE_TO_SYSPROC(s)       (S_SET_STORAGE_CLASS((s), C_SCALL))
+
+#else /* switch on OBJ */
+you lose
+#endif /* witch on OBJ */
+
+#ifdef __STDC__
+
+void brtab_emit(void);
+void reloc_callj(); /* this is really reloc_callj(fixS *fixP) but I don't want to change header inclusion order. */
+void tc_set_bal_of_call(); /* this is really tc_set_bal_of_call(symbolS *callP, symbolS *balP) */
+
+#else /* __STDC__ */
+
+void brtab_emit();
+void reloc_callj();
+void tc_set_bal_of_call();
+
+#endif /* __STDC__ */
+
+char *_tc_get_bal_of_call(); /* this is really symbolS *tc_get_bal_of_call(symbolS *callP). */
+#define tc_get_bal_of_call(c)  ((symbolS *) _tc_get_bal_of_call(c))
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tp-i960.h */
diff --git a/gas/config/tc-m68851.h b/gas/config/tc-m68851.h
new file mode 100644 (file)
index 0000000..ff984fe
--- /dev/null
@@ -0,0 +1,284 @@
+
+/*
+ * 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 pmmu.h */
diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
new file mode 100644 (file)
index 0000000..c2ba228
--- /dev/null
@@ -0,0 +1,3808 @@
+/* m68k.c  All the m68020 specific stuff in one convenient, huge,
+   slow to compile, easy to find file.
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <ctype.h>
+
+#include "as.h"
+
+#include "obstack.h"
+
+ /* note that this file includes real declarations and thus can only be included by one source file per executable. */
+#include "m68k-opcode.h"
+
+/* This array holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = "|";
+
+/* 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 like this one will always work. */
+const char line_comment_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[] = "rRsSfFdDxXeEpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+ */
+
+int md_reloc_size = 8;         /* Size of relocation record */
+
+/* Its an arbitrary name:  This means I don't approve of it */
+/* See flames below */
+static struct obstack robyn;
+
+#define TAB(x,y)       (((x)<<2)+(y))
+#define TABTYPE(xy)     ((xy) >> 2)
+#define BYTE           0
+#define SHORT          1
+#define LONG           2
+#define SZ_UNDEF       3
+
+#define BRANCH         1
+#define FBRANCH                2
+#define PCREL          3
+#define BCC68000        4
+#define DBCC            5
+#define PCLEA          6
+
+struct m68k_exp {
+       char    *e_beg;
+       char    *e_end;
+       expressionS e_exp;
+       short   e_siz;          /* 0== default 1==short/byte 2==word 3==long */
+};
+
+/* Internal form of an operand.  */
+struct m68k_op {
+       char    *error;         /* Couldn't parse it */
+       int     mode;           /* What mode this instruction is in.  */
+       unsigned long   reg;            /* Base register */
+       struct m68k_exp *con1;
+       int     ireg;           /* Index register */
+       int     isiz;           /* 0==unspec  1==byte(?)  2==short  3==long  */
+       int     imul;           /* Multipy ireg by this (1,2,4,or 8) */
+       struct  m68k_exp *con2;
+};
+
+/* internal form of a 68020 instruction */
+struct m68_it {
+       char    *error;
+       char    *args;          /* list of opcode info */
+       int     numargs;
+
+       int     numo;           /* Number of shorts in opcode */
+       short   opcode[11];
+
+       struct m68k_op operands[6];
+
+       int     nexp;           /* number of exprs in use */
+       struct m68k_exp exprs[4];
+
+       int     nfrag;          /* Number of frags we have to produce */
+       struct {
+               int fragoff;    /* Where in the current opcode[] the frag ends */
+               symbolS *fadd;
+               long foff;
+               int fragty;
+       } fragb[4];
+
+       int     nrel;           /* Num of reloc strucs in use */
+       struct  {
+               int     n;
+               symbolS *add,
+                       *sub;
+               long off;
+               char    wid;
+               char    pcrel;
+       } reloc[5];             /* Five is enough??? */
+};
+
+struct m68_it the_ins;         /* the instruction being assembled */
+
+
+/* Macros for adding things to the m68_it struct */
+
+#define addword(w)     the_ins.opcode[the_ins.numo++]=(w)
+
+/* Like addword, but goes BEFORE general operands */
+#define insop(w)       {int z;\
+ for(z=the_ins.numo;z>opcode->m_codenum;--z)\
+   the_ins.opcode[z]=the_ins.opcode[z-1];\
+ for(z=0;z<the_ins.nrel;z++)\
+   the_ins.reloc[z].n+=2;\
+ the_ins.opcode[opcode->m_codenum]=w;\
+ the_ins.numo++;\
+}
+
+
+#define add_exp(beg,end) (\
+       the_ins.exprs[the_ins.nexp].e_beg=beg,\
+       the_ins.exprs[the_ins.nexp].e_end=end,\
+       &the_ins.exprs[the_ins.nexp++]\
+)
+
+
+/* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/
+#define add_fix(width,exp,pc_rel) {\
+       the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
+               (((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\
+       the_ins.reloc[the_ins.nrel].add=adds((exp));\
+       the_ins.reloc[the_ins.nrel].sub=subs((exp));\
+       the_ins.reloc[the_ins.nrel].off=offs((exp));\
+       the_ins.reloc[the_ins.nrel].wid=width;\
+       the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\
+}
+
+#define add_frag(add,off,type)  {\
+       the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
+       the_ins.fragb[the_ins.nfrag].fadd=add;\
+       the_ins.fragb[the_ins.nfrag].foff=off;\
+       the_ins.fragb[the_ins.nfrag++].fragty=type;\
+}
+
+#define isvar(exp)     ((exp) && (adds(exp) || subs(exp)))
+
+#define seg(exp)       ((exp)->e_exp.X_seg)
+#define adds(exp)      ((exp)->e_exp.X_add_symbol)
+#define subs(exp)      ((exp)->e_exp.X_subtract_symbol)
+#define offs(exp)      ((exp)->e_exp.X_add_number)
+
+
+struct m68_incant {
+       char *m_operands;
+       unsigned long m_opcode;
+       short m_opnum;
+       short m_codenum;
+       struct m68_incant *m_next;
+};
+
+#define getone(x)      ((((x)->m_opcode)>>16)&0xffff)
+#define gettwo(x)      (((x)->m_opcode)&0xffff)
+
+
+#ifdef __STDC__
+
+static char *crack_operand(char *str, struct m68k_op *opP);
+static int get_num(struct m68k_exp *exp, int ok);
+static int get_regs(int i, char *str, struct m68k_op *opP);
+static int reverse_16_bits(int in);
+static int reverse_8_bits(int in);
+static int try_index(char **s, struct m68k_op *opP);
+static void install_gen_operand(int mode, int val);
+static void install_operand(int mode, int val);
+static void s_bss(void);
+static void s_data1(void);
+static void s_data2(void);
+static void s_even(void);
+static void s_proc(void);
+
+#else /* __STDC__ */
+
+static char *crack_operand();
+static int get_num();
+static int get_regs();
+static int reverse_16_bits();
+static int reverse_8_bits();
+static int try_index();
+static void install_gen_operand();
+static void install_operand();
+static void s_bss();
+static void s_data1();
+static void s_data2();
+static void s_even();
+static void s_proc();
+
+#endif /* __STDC__ */
+
+/* BCC68000 is for patching in an extra jmp instruction for long offsets
+   on the 68000.  The 68000 doesn't support long branches with branchs */
+
+/* This table desribes how you change sizes for the various types of variable
+   size expressions.  This version only supports two kinds. */
+
+/* Note that calls to frag_var need to specify the maximum expansion needed */
+/* This is currently 10 bytes for DBCC */
+
+/* The fields are:
+       How far Forward this mode will reach:
+       How far Backward this mode will reach:
+       How many bytes this mode will add to the size of the frag
+       Which mode to go to if the offset won't fit in this one
+ */
+const relax_typeS
+md_relax_table[] = {
+{ 1,           1,              0,      0 },    /* First entries aren't used */
+{ 1,           1,              0,      0 },    /* For no good reason except */
+{ 1,           1,              0,      0 },    /* that the VAX doesn't either */
+{ 1,           1,              0,      0 },
+
+{ (127),       (-128),         0,      TAB(BRANCH,SHORT)},
+{ (32767),     (-32768),       2,      TAB(BRANCH,LONG) },
+{ 0,           0,              4,      0 },
+{ 1,           1,              0,      0 },
+
+{ 1,           1,              0,      0 },    /* FBRANCH doesn't come BYTE */
+{ (32767),     (-32768),       2,      TAB(FBRANCH,LONG)},
+{ 0,           0,              4,      0 },
+{ 1,           1,              0,      0 },
+
+{ 1,           1,              0,      0 },    /* PCREL doesn't come BYTE */
+{ (32767),     (-32768),       2,      TAB(PCREL,LONG)},
+{ 0,           0,              4,      0 },
+{ 1,           1,              0,      0 },
+
+{ (127),       (-128),         0,      TAB(BCC68000,SHORT)},
+{ (32767),     (-32768),       2,      TAB(BCC68000,LONG) },
+{ 0,           0,              6,      0 },    /* jmp long space */
+{ 1,           1,              0,      0 },
+
+{ 1,           1,              0,      0 },    /* DBCC doesn't come BYTE */
+{ (32767),     (-32768),       2,      TAB(DBCC,LONG) },
+{ 0,           0,              10,     0 },    /* bra/jmp long space */
+{ 1,           1,              0,      0 },
+
+{ 1,           1,              0,      0 },    /* PCLEA doesn't come BYTE */
+{ 32767,       -32768,         2,      TAB(PCLEA,LONG) },
+{ 0,           0,              6,      0 },
+{ 1,           1,              0,      0 },
+
+};
+
+/* These are the machine dependent pseudo-ops.  These are included so
+   the assembler can work on the output from the SUN C compiler, which
+   generates these.
+ */
+
+/* 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
+ */
+const pseudo_typeS md_pseudo_table[] = {
+       { "data1",      s_data1,        0       },
+       { "data2",      s_data2,        0       },
+       { "bss",        s_bss,          0       },
+       { "even",       s_even,         0       },
+       { "skip",       s_space,        0       },
+       { "proc",       s_proc,         0       },
+       { 0,            0,              0       }
+};
+
+
+/* #define isbyte(x)   ((x)>=-128 && (x)<=127) */
+/* #define isword(x)   ((x)>=-32768 && (x)<=32767) */
+
+#define issbyte(x)     ((x)>=-128 && (x)<=127)
+#define isubyte(x)     ((x)>=0 && (x)<=255)
+#define issword(x)     ((x)>=-32768 && (x)<=32767)
+#define isuword(x)     ((x)>=0 && (x)<=65535)
+
+#define isbyte(x)      ((x)>=-128 && (x)<=255)
+#define isword(x)      ((x)>=-32768 && (x)<=65535)
+#define islong(x)      (1)
+
+extern char *input_line_pointer;
+
+/* Operands we can parse:  (And associated modes)
+
+numb:  8 bit num
+numw:  16 bit num
+numl:  32 bit num
+dreg:  data reg 0-7
+reg:   address or data register
+areg:  address register
+apc:   address register, PC, ZPC or empty string
+num:   16 or 32 bit num
+num2:  like num
+sz:    w or l          if omitted, l assumed
+scale: 1 2 4 or 8      if omitted, 1 assumed
+
+7.4 IMMED #num                         --> NUM
+0.? DREG  dreg                         --> dreg
+1.? AREG  areg                         --> areg
+2.? AINDR areg@                                --> *(areg)
+3.? AINC  areg@+                       --> *(areg++)
+4.? ADEC  areg@-                       --> *(--areg)
+5.? AOFF  apc@(numw)                   --> *(apc+numw) -- empty string and ZPC not allowed here
+6.? AINDX apc@(num,reg:sz:scale)       --> *(apc+num+reg*scale)
+6.? AINDX apc@(reg:sz:scale)           --> same, with num=0
+6.? APODX apc@(num)@(num2,reg:sz:scale)        --> *(*(apc+num)+num2+reg*scale)
+6.? APODX apc@(num)@(reg:sz:scale)     --> same, with num2=0
+6.? AMIND apc@(num)@(num2)             --> *(*(apc+num)+num2) (previous mode without an index reg)
+6.? APRDX apc@(num,reg:sz:scale)@(num2)        --> *(*(apc+num+reg*scale)+num2)
+6.? APRDX apc@(reg:sz:scale)@(num2)    --> same, with num=0
+7.0 ABSL  num:sz                       --> *(num)
+          num                          --> *(num) (sz L assumed)
+*** MSCR  otherreg                     --> Magic
+With -l option
+5.? AOFF  apc@(num)                    --> *(apc+num) -- empty string and ZPC not allowed here still
+
+examples:
+       #foo    #0x35   #12
+       d2
+       a4
+       a3@
+       a5@+
+       a6@-
+       a2@(12) pc@(14)
+       a1@(5,d2:w:1)   @(45,d6:l:4)
+       pc@(a2)         @(d4)
+       etc . . .
+
+
+#name@(numw)   -->turn into PC rel mode
+apc@(num8,reg:sz:scale)                --> *(apc+num8+reg*scale)
+
+*/
+
+#define IMMED  1
+#define DREG   2
+#define AREG   3
+#define AINDR  4
+#define ADEC   5
+#define AINC   6
+#define AOFF   7
+#define AINDX  8
+#define APODX  9
+#define AMIND  10
+#define APRDX  11
+#define ABSL   12
+#define MSCR   13
+#define REGLST 14
+
+#define FAIL   0
+#define OK     1
+
+/* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg,
+   8-15==addr reg for operands that take both types */
+#define DATA   1               /*   1- 8 == data registers 0-7 */
+#define ADDR   (DATA+8)        /*   9-16 == address regs 0-7 */
+#define FPREG  (ADDR+8)        /*  17-24 Eight FP registers */
+#define COPNUM (FPREG+8)       /*  25-32 Co-processor #1-#8 */
+
+#define PC     (COPNUM+8)      /*  33 Program counter */
+#define ZPC    (PC+1)          /*  34 Hack for Program space, but 0 addressing */
+#define SR     (ZPC+1)         /*  35 Status Reg */
+#define CCR    (SR+1)          /*  36 Condition code Reg */
+
+/* These have to be in order for the movec instruction to work. */
+#define USP    (CCR+1)         /*  37 User Stack Pointer */
+#define ISP    (USP+1)         /*  38 Interrupt stack pointer */
+#define SFC    (ISP+1)         /*  39 */
+#define DFC    (SFC+1)         /*  40 */
+#define CACR   (DFC+1)         /*  41 */
+#define VBR    (CACR+1)        /*  42 */
+#define CAAR   (VBR+1)         /*  43 */
+#define MSP    (CAAR+1)        /*  44 */
+
+#define FPI    (MSP+1)         /* 45 */
+#define FPS    (FPI+1)         /* 46 */
+#define FPC    (FPS+1)         /* 47 */
+/*
+ * 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     (FPC+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 */
+
+
+/* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */
+/* I think. . .  */
+
+#define        SP      ADDR+7
+
+/* JF these tables here are for speed at the expense of size */
+/* You can replace them with the #if 0 versions if you really
+   need space and don't mind it running a bit slower */
+
+static char mklower_table[256];
+#define mklower(c) (mklower_table[(unsigned char)(c)])
+static char notend_table[256];
+static char alt_notend_table[256];
+#define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\
+ alt_notend_table[(unsigned char)(s[1])])))
+
+#if 0
+#define mklower(c)     (isupper(c) ? tolower(c) : c)
+#endif
+
+
+/* JF modified this to handle cases where the first part of a symbol name
+   looks like a register */
+
+int
+m68k_reg_parse(ccp)
+register char **ccp;
+{
+       register char c1,
+               c2,
+               c3,
+               c4;
+       register int n = 0,
+               ret = FAIL;
+
+       c1=mklower(ccp[0][0]);
+#ifdef REGISTER_PREFIX
+       if(c1!=REGISTER_PREFIX)
+               return FAIL;
+       c1=mklower(ccp[0][1]);
+       c2=mklower(ccp[0][2]);
+       c3=mklower(ccp[0][3]);
+       c4=mklower(ccp[0][4]);
+#else
+       c2=mklower(ccp[0][1]);
+       c3=mklower(ccp[0][2]);
+       c4=mklower(ccp[0][3]);
+#endif
+       switch(c1) {
+       case 'a':
+               if(c2>='0' && c2<='7') {
+                       n=2;
+                       ret=ADDR+c2-'0';
+               }
+#ifdef m68851
+               else if (c2 == 'c') {
+                       n = 2;
+                       ret = AC;
+               }
+#endif
+               break;
+#ifdef m68851
+       case 'b':
+               if (c2 == 'a') {
+                       if (c3 == 'd') {
+                               if (c4 >= '0' && c4 <= '7') {
+                                       n = 4;
+                                       ret = BAD + c4 - '0';
+                               }
+                       }
+                       if (c3 == 'c') {
+                               if (c4 >= '0' && c4 <= '7') {
+                                       n = 4;
+                                       ret = BAC + c4 - '0';
+                               }
+                       }
+               }
+               break;
+#endif
+       case 'c':
+#ifdef m68851
+               if (c2 == 'a' && c3 == 'l') {
+                       n = 3;
+                       ret = CAL;
+               } else
+#endif
+                       /* This supports both CCR and CC as the ccr reg. */
+               if(c2=='c' && c3=='r') {
+                       n=3;
+                       ret = CCR;
+               } else if(c2=='c') {
+                       n=2;
+                       ret = CCR;
+               } else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') {
+                       n=4;
+                       ret = c3=='a' ? CAAR : CACR;
+               }
+#ifdef m68851
+               else if (c2 == 'r' && c3 == 'p') {
+                       n = 3;
+                       ret = (CRP);
+               }
+#endif
+               break;
+       case 'd':
+               if(c2>='0' && c2<='7') {
+                       n=2;
+                       ret = DATA+c2-'0';
+               } else if(c2=='f' && c3=='c') {
+                       n=3;
+                       ret = DFC;
+               }
+#ifdef m68851
+               else if (c2 == 'r' && c3 == 'p') {
+                       n = 3;
+                       ret = (DRP);
+               }
+#endif
+               break;
+       case 'f':
+               if(c2=='p') {
+                       if(c3>='0' && c3<='7') {
+                               n=3;
+                               ret = FPREG+c3-'0';
+                               if(c4==':')
+                                       ccp[0][3]=',';
+                       } else if(c3=='i') {
+                               n=3;
+                               ret = FPI;
+                       } else if(c3=='s') {
+                               n= (c4 == 'r' ? 4 : 3);
+                               ret = FPS;
+                       } else if(c3=='c') {
+                               n= (c4 == 'r' ? 4 : 3);
+                               ret = FPC;
+                       }
+               }
+               break;
+       case 'i':
+               if(c2=='s' && c3=='p') {
+                       n=3;
+                       ret = ISP;
+               }
+               break;
+       case 'm':
+               if(c2=='s' && c3=='p') {
+                       n=3;
+                       ret = MSP;
+               }
+               break;
+       case 'p':
+               if(c2=='c') {
+#ifdef m68851
+                       if(c3 == 's' && c4=='r') {
+                               n=4;
+                               ret = (PCSR);
+                       } else
+#endif
+                       {
+                               n=2;
+                               ret = PC;
+                       }
+               }
+#ifdef m68851
+               else if (c2 == 's' && c3 == 'r') {
+                       n = 3;
+                       ret = (PSR);
+               }
+#endif
+               break;
+       case 's':
+#ifdef m68851
+               if (c2 == 'c' && c3 == 'c') {
+                       n = 3;
+                       ret = (SCC);
+               } else if (c2 == 'r' && c3 == 'p') {
+                       n = 3;
+                       ret = (SRP);
+               } else
+#endif
+               if(c2=='r') {
+                       n=2;
+                       ret = SR;
+               } else if(c2=='p') {
+                       n=2;
+                       ret = ADDR+7;
+               } else if(c2=='f' && c3=='c') {
+                       n=3;
+                       ret = SFC;
+               }
+               break;
+#ifdef m68851
+       case 't':
+               if(c2 == 'c') {
+                       n=2;
+                       ret=TC;
+               }
+               break;
+#endif
+       case 'u':
+               if(c2=='s' && c3=='p') {
+                       n=3;
+                       ret = USP;
+               }
+               break;
+       case 'v':
+#ifdef m68851
+               if (c2 == 'a' && c3 == 'l') {
+                       n = 3;
+                       ret = (VAL);
+               } else
+#endif
+               if(c2=='b' && c3=='r') {
+                       n=3;
+                       ret = VBR;
+               }
+               break;
+       case 'z':
+               if(c2=='p' && c3=='c') {
+                       n=3;
+                       ret = ZPC;
+               }
+               break;
+       default:
+               break;
+       }
+       if(n) {
+#ifdef REGISTER_PREFIX
+               n++;
+#endif
+               if(isalnum(ccp[0][n]) || ccp[0][n]=='_')
+                       ret=FAIL;
+               else
+                       ccp[0]+=n;
+       } else
+               ret = FAIL;
+       return ret;
+}
+
+#define SKIP_WHITE()   { str++; if(*str==' ') str++;}
+
+int
+m68k_ip_op(str,opP)
+char *str;
+register struct m68k_op *opP;
+{
+       char    *strend;
+       long    i;
+
+       if(*str==' ')
+               str++;
+               /* Find the end of the string */
+       if(!*str) {
+               /* Out of gas */
+               opP->error="Missing operand";
+               return FAIL;
+       }
+       for(strend=str;*strend;strend++)
+               ;
+       --strend;
+
+               /* Guess what:  A constant.  Shar and enjoy */
+       if(*str=='#') {
+               str++;
+               opP->con1=add_exp(str,strend);
+               opP->mode=IMMED;
+               return OK;
+       }
+       i=m68k_reg_parse(&str);
+       if((i==FAIL || *str!='\0') && *str!='@') {
+               char *stmp;
+
+               if(i!=FAIL && (*str=='/' || *str=='-')) {
+                       opP->mode=REGLST;
+                       return get_regs(i,str,opP);
+               }
+               if((stmp=strchr(str,'@')) != '\0') {
+                       opP->con1=add_exp(str,stmp-1);
+                       if(stmp==strend) {
+                               opP->mode=AINDX;
+                               return OK;
+                       }
+                       stmp++;
+                       if(*stmp++!='(' || *strend--!=')') {
+                               opP->error="Malformed operand";
+                               return FAIL;
+                       }
+                       i=try_index(&stmp,opP);
+                       opP->con2=add_exp(stmp,strend);
+                       if(i==FAIL) opP->mode=AMIND;
+                       else opP->mode=APODX;
+                       return OK;
+               }
+               opP->mode=ABSL;
+               opP->con1=add_exp(str,strend);
+               return OK;
+       }
+       opP->reg=i;
+       if(*str=='\0') {
+               if(i>=DATA+0 && i<=DATA+7)
+                       opP->mode=DREG;
+               else if(i>=ADDR+0 && i<=ADDR+7)
+                       opP->mode=AREG;
+               else
+                       opP->mode=MSCR;
+               return OK;
+       }
+       if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) {      /* Can't indirect off non address regs */
+               opP->error="Invalid indirect register";
+               return FAIL;
+       }
+       if(*str!='@')
+               abort();
+       str++;
+       switch(*str) {
+       case '\0':
+               opP->mode=AINDR;
+               return OK;
+       case '-':
+               opP->mode=ADEC;
+               return OK;
+       case '+':
+               opP->mode=AINC;
+               return OK;
+       case '(':
+               str++;
+               break;
+       default:
+               opP->error="Junk after indirect";
+               return FAIL;
+       }
+               /* Some kind of indexing involved.  Lets find out how bad it is */
+       i=try_index(&str,opP);
+               /* Didn't start with an index reg, maybe its offset or offset,reg */
+       if(i==FAIL) {
+               char *beg_str;
+
+               beg_str=str;
+               for(i=1;i;) {
+                       switch(*str++) {
+                       case '\0':
+                               opP->error="Missing )";
+                               return FAIL;
+                       case ',': i=0; break;
+                       case '(': i++; break;
+                       case ')': --i; break;
+                       }
+               }
+               /* if(str[-3]==':') {
+                       int siz;
+
+                       switch(str[-2]) {
+                       case 'b':
+                       case 'B':
+                               siz=1;
+                               break;
+                       case 'w':
+                       case 'W':
+                               siz=2;
+                               break;
+                       case 'l':
+                       case 'L':
+                               siz=3;
+                               break;
+                       default:
+                               opP->error="Specified size isn't :w or :l";
+                               return FAIL;
+                       }
+                       opP->con1=add_exp(beg_str,str-4);
+                       opP->con1->e_siz=siz;
+               } else */
+                       opP->con1=add_exp(beg_str,str-2);
+                       /* Should be offset,reg */
+               if(str[-1]==',') {
+                       i=try_index(&str,opP);
+                       if(i==FAIL) {
+                               opP->error="Malformed index reg";
+                               return FAIL;
+                       }
+               }
+       }
+               /* We've now got offset)   offset,reg)   or    reg) */
+
+       if(*str=='\0') {
+               /* Th-the-thats all folks */
+               if(opP->reg==FAIL) opP->mode=AINDX;     /* Other form of indirect */
+               else if(opP->ireg==FAIL) opP->mode=AOFF;
+               else opP->mode=AINDX;
+               return OK;
+       }
+               /* Next thing had better be another @ */
+       if(*str!='@' || str[1]!='(') {
+               opP->error="junk after indirect";
+               return FAIL;
+       }
+       str+=2;
+       if(opP->ireg!=FAIL) {
+               opP->mode=APRDX;
+               i=try_index(&str,opP);
+               if(i!=FAIL) {
+                       opP->error="Two index registers!  not allowed!";
+                       return FAIL;
+               }
+       } else
+               i=try_index(&str,opP);
+       if(i==FAIL) {
+               char *beg_str;
+
+               beg_str=str;
+               for(i=1;i;) {
+                       switch(*str++) {
+                       case '\0':
+                               opP->error="Missing )";
+                               return FAIL;
+                       case ',': i=0; break;
+                       case '(': i++; break;
+                       case ')': --i; break;
+                       }
+               }
+               opP->con2=add_exp(beg_str,str-2);
+               if(str[-1]==',') {
+                       if(opP->ireg!=FAIL) {
+                               opP->error="Can't have two index regs";
+                               return FAIL;
+                       }
+                       i=try_index(&str,opP);
+                       if(i==FAIL) {
+                               opP->error="malformed index reg";
+                               return FAIL;
+                       }
+                       opP->mode=APODX;
+               } else if(opP->ireg!=FAIL)
+                       opP->mode=APRDX;
+               else
+                       opP->mode=AMIND;
+       } else
+               opP->mode=APODX;
+       if(*str!='\0') {
+               opP->error="Junk after indirect";
+               return FAIL;
+       }
+       return OK;
+}
+
+static int try_index(s,opP)
+char **s;
+struct m68k_op *opP;
+{
+       register int    i;
+       char    *ss;
+#define SKIP_W()       { ss++; if(*ss==' ') ss++;}
+
+       ss= *s;
+       /* SKIP_W(); */
+       i=m68k_reg_parse(&ss);
+       if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
+               *s=ss;
+               return FAIL;
+       }
+       opP->ireg=i;
+       /* SKIP_W(); */
+       if(*ss==')') {
+               opP->isiz=0;
+               opP->imul=1;
+               SKIP_W();
+               *s=ss;
+               return OK;
+       }
+       if(*ss!=':') {
+               opP->error="Missing : in index register";
+               *s=ss;
+               return FAIL;
+       }
+       SKIP_W();
+       switch(*ss) {
+       case 'w':
+       case 'W':
+               opP->isiz=2;
+               break;
+       case 'l':
+       case 'L':
+               opP->isiz=3;
+               break;
+       default:
+               opP->error="Index register size spec not :w or :l";
+               *s=ss;
+               return FAIL;
+       }
+       SKIP_W();
+       if(*ss==':') {
+               SKIP_W();
+               switch(*ss) {
+               case '1':
+               case '2':
+               case '4':
+               case '8':
+                       opP->imul= *ss-'0';
+                       break;
+               default:
+                       opP->error="index multiplier not 1, 2, 4 or 8";
+                       *s=ss;
+                       return FAIL;
+               }
+               SKIP_W();
+       } else opP->imul=1;
+       if(*ss!=')') {
+               opP->error="Missing )";
+               *s=ss;
+               return FAIL;
+       }
+       SKIP_W();
+       *s=ss;
+       return OK;
+} /* try_index() */
+
+#ifdef TEST1   /* TEST1 tests m68k_ip_op(), which parses operands */
+main()
+{
+       char buf[128];
+       struct m68k_op thark;
+
+       for(;;) {
+               if(!gets(buf))
+                       break;
+               bzero(&thark,sizeof(thark));
+               if(!m68k_ip_op(buf,&thark)) printf("FAIL:");
+               if(thark.error)
+                       printf("op1 error %s in %s\n",thark.error,buf);
+               printf("mode %d, reg %d, ",thark.mode,thark.reg);
+               if(thark.b_const)
+                       printf("Constant: '%.*s',",1+thark.e_const-thark.b_const,thark.b_const);
+               printf("ireg %d, isiz %d, imul %d ",thark.ireg,thark.isiz,thark.imul);
+               if(thark.b_iadd)
+                       printf("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd);
+               printf("\n");
+       }
+       exit(0);
+}
+
+#endif
+
+
+static struct hash_control*   op_hash = NULL;  /* handle of the OPCODE hash table
+                                  NULL means any use before m68_ip_begin()
+                                  will crash */
+
+\f
+/*
+ *             m 6 8 _ i p ( )
+ *
+ * This converts a string into a 68k instruction.
+ * The string must be a bare single instruction in sun format
+ * with RMS-style 68020 indirects
+ *  (example:  )
+ *
+ * It provides some error messages: at most one fatal error message (which
+ * stops the scan) and at most one warning message for each operand.
+ * The 68k instruction is returned in exploded form, since we have no
+ * knowledge of how you parse (or evaluate) your expressions.
+ * We do however strip off and decode addressing modes and operation
+ * mnemonic.
+ *
+ * This function's value is a string. If it is not "" then an internal
+ * logic error was found: read this code to assign meaning to the string.
+ * No argument string should generate such an error string:
+ * it means a bug in our code, not in the user's text.
+ *
+ * You MUST have called m86_ip_begin() once and m86_ip_end() never before using
+ * this function.
+ */
+
+/* JF this function no longer returns a useful value.  Sorry */
+void
+m68_ip (instring)
+char   *instring;
+{
+       register char *p;
+       register struct m68k_op *opP;
+       register struct m68_incant *opcode;
+       register char *s;
+       register int tmpreg,
+               baseo,
+               outro,
+               nextword;
+       int     siz1,
+               siz2;
+       char    c;
+       int     losing;
+       int     opsfound;
+       LITTLENUM_TYPE words[6];
+       LITTLENUM_TYPE *wordp;
+
+       if (*instring == ' ')
+               instring++;                     /* skip leading whitespace */
+
+  /* Scan up to end of operation-code, which MUST end in end-of-string
+     or exactly 1 space. */
+       for (p = instring; *p != '\0'; p++)
+               if (*p == ' ')
+                       break;
+
+
+       if (p == instring) {
+               the_ins.error = "No operator";
+               the_ins.opcode[0] = (short) NULL;
+               /* the_ins.numo=1; */
+               return;
+       }
+
+  /* p now points to the end of the opcode name, probably whitespace.
+     make sure the name is null terminated by clobbering the whitespace,
+     look it up in the hash table, then fix it back. */   
+       c = *p;
+       *p = '\0';
+       opcode = (struct m68_incant *)hash_find (op_hash, instring);
+       *p = c;
+
+       if (opcode == NULL) {
+               the_ins.error = "Unknown operator";
+               the_ins.opcode[0] = (short) NULL;
+               /* the_ins.numo=1; */
+               return;
+       }
+
+  /* found a legitimate opcode, start matching operands */
+       for(opP= &the_ins.operands[0];*p;opP++) {
+               p = crack_operand (p, opP);
+               if(opP->error) {
+                       the_ins.error=opP->error;
+                       return;
+               }
+       }
+
+       opsfound=opP- &the_ins.operands[0];
+       /* This ugly hack is to support the floating pt opcodes in their standard form */
+       /* Essentially, we fake a first enty of type COP#1 */
+       if(opcode->m_operands[0]=='I') {
+               int     n;
+
+               for(n=opsfound;n>0;--n)
+                       the_ins.operands[n]=the_ins.operands[n-1];
+
+               /* bcopy((char *)(&the_ins.operands[0]),(char *)(&the_ins.operands[1]),opsfound*sizeof(the_ins.operands[0])); */
+               bzero((char *)(&the_ins.operands[0]),sizeof(the_ins.operands[0]));
+               the_ins.operands[0].mode=MSCR;
+               the_ins.operands[0].reg=COPNUM;         /* COP #1 */
+               opsfound++;
+       }
+               /* We've got the operands.  Find an opcode that'll
+                  accept them */
+       for(losing=0;;) {
+               if(opsfound!=opcode->m_opnum)
+                       losing++;
+               else for(s=opcode->m_operands,opP= &the_ins.operands[0];*s && !losing;s+=2,opP++) {
+                               /* Warning: this switch is huge! */
+                               /* I've tried to organize the cases into  this order:
+                                  non-alpha first, then alpha by letter.  lower-case goes directly
+                                  before uppercase counterpart. */
+                               /* Code with multiple case ...: gets sorted by the lowest case ...
+                                  it belongs to.  I hope this makes sense. */
+                       switch(*s) {
+                       case '!':
+                               if(opP->mode==MSCR || opP->mode==IMMED ||
+ opP->mode==DREG || opP->mode==AREG || opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '#':
+                               if(opP->mode!=IMMED)
+                                       losing++;
+                               else {
+                                       long t;
+
+                                       t=get_num(opP->con1,80);
+                                       if(s[1]=='b' && !isbyte(t))
+                                               losing++;
+                                       else if(s[1]=='w' && !isword(t))
+                                               losing++;
+                               }
+                               break;
+
+                       case '^':
+                       case 'T':
+                               if(opP->mode!=IMMED)
+                                       losing++;
+                               break;
+
+                       case '$':
+                               if(opP->mode==MSCR || opP->mode==AREG ||
+ opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '%':
+                               if(opP->mode==MSCR || opP->reg==PC ||
+ opP->reg==ZPC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+
+                       case '&':
+                               if(opP->mode==MSCR || opP->mode==DREG ||
+ opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC ||
+ opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '*':
+                               if(opP->mode==MSCR || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '+':
+                               if(opP->mode!=AINC)
+                                       losing++;
+                               break;
+
+                       case '-':
+                               if(opP->mode!=ADEC)
+                                       losing++;
+                               break;
+
+                       case '/':
+                               if(opP->mode==MSCR || opP->mode==AREG ||
+ opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case ';':
+                               if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '?':
+                               if(opP->mode==MSCR || opP->mode==AREG ||
+ opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->reg==PC ||
+ opP->reg==ZPC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '@':
+                               if(opP->mode==MSCR || opP->mode==AREG ||
+ opP->mode==IMMED || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case '~':               /* For now! (JF FOO is this right?) */
+                               if(opP->mode==MSCR || opP->mode==DREG ||
+ opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case 'A':
+                               if(opP->mode!=AREG)
+                                       losing++;
+                               break;
+
+                       case 'B':       /* FOO */
+                               if(opP->mode!=ABSL)
+                                       losing++;
+                               break;
+
+                       case 'C':
+                               if(opP->mode!=MSCR || opP->reg!=CCR)
+                                       losing++;
+                               break;
+
+                       case 'd':       /* FOO This mode is a KLUDGE!! */
+                               if(opP->mode!=AOFF && (opP->mode!=ABSL ||
+ opP->con1->e_beg[0]!='(' || opP->con1->e_end[0]!=')'))
+                                       losing++;
+                               break;
+
+                       case 'D':
+                               if(opP->mode!=DREG)
+                                       losing++;
+                               break;
+
+                       case 'F':
+                               if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
+                                       losing++;
+                               break;
+
+                       case 'I':
+                               if(opP->mode!=MSCR || opP->reg<COPNUM ||
+ opP->reg>=COPNUM+7)
+                                       losing++;
+                               break;
+
+                       case 'J':
+                               if(opP->mode!=MSCR || opP->reg<USP || opP->reg>MSP)
+                                       losing++;
+                               break;
+
+                       case 'k':
+                               if(opP->mode!=IMMED)
+                                       losing++;
+                               break;
+
+                       case 'l':
+                       case 'L':
+                               if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
+                                       if(s[1]=='8')
+                                               losing++;
+                                       else {
+                                               opP->mode=REGLST;
+                                               opP->reg=1<<(opP->reg-DATA);
+                                       }
+                               } else if(opP->mode!=REGLST) {
+                                       losing++;
+                               } else if(s[1]=='8' && opP->reg&0x0FFffFF)
+                                       losing++;
+                               else if(s[1]=='3' && opP->reg&0x7000000)
+                                       losing++;
+                               break;
+
+                       case 'M':
+                               if(opP->mode!=IMMED)
+                                       losing++;
+                               else {
+                                       long t;
+
+                                       t=get_num(opP->con1,80);
+                                       if(!issbyte(t) || isvar(opP->con1))
+                                               losing++;
+                               }
+                               break;
+
+                       case 'O':
+                               if(opP->mode!=DREG && opP->mode!=IMMED)
+                                       losing++;
+                               break;
+
+                       case 'Q':
+                               if(opP->mode!=IMMED)
+                                       losing++;
+                               else {
+                                       long t;
+
+                                       t=get_num(opP->con1,80);
+                                       if(t<1 || t>8 || isvar(opP->con1))
+                                               losing++;
+                               }
+                               break;
+
+                       case 'R':
+                               if(opP->mode!=DREG && opP->mode!=AREG)
+                                       losing++;
+                               break;
+
+                       case 's':
+                               if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
+                                       losing++;
+                               break;
+
+                       case 'S':
+                               if(opP->mode!=MSCR || opP->reg!=SR)
+                                       losing++;
+                               break;
+
+                       case 'U':
+                               if(opP->mode!=MSCR || opP->reg!=USP)
+                                       losing++;
+                               break;
+
+                       /* JF these are out of order.  We could put them
+                          in order if we were willing to put up with
+                          bunches of #ifdef m68851s in the code */
+#ifdef m68851
+                       /* Memory addressing mode used by pflushr */
+                       case '|':
+                               if(opP->mode==MSCR || opP->mode==DREG ||
+ opP->mode==AREG || opP->mode==REGLST)
+                                       losing++;
+                               break;
+
+                       case 'f':
+                               if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
+                                       losing++;
+                               break;
+
+                       case 'P':
+                               if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
+                                   opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
+                                       losing++;
+                               break;
+
+                       case 'V':
+                               if (opP->reg != VAL)
+                                       losing++;
+                               break;
+
+                       case 'W':
+                               if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
+                                   opP->reg != CRP))
+                                       losing++;
+                               break;
+
+                       case 'X':
+                               if (opP->mode != MSCR ||
+                                   (!(opP->reg >= BAD && opP->reg <= BAD+7) &&
+                                    !(opP->reg >= BAC && opP->reg <= BAC+7)))
+                                       losing++;
+                               break;
+
+                       case 'Y':
+                               if (opP->reg != PSR)
+                                       losing++;
+                               break;
+
+                       case 'Z':
+                               if (opP->reg != PCSR)
+                                       losing++;
+                               break;
+#endif
+                       default:
+                               as_fatal("Internal error:  Operand mode %c unknown in line %s of file \"%s\"",
+                                        *s, __LINE__, __FILE__);
+                       }
+               }
+               if(!losing)
+                       break;
+               opcode=opcode->m_next;
+               if(!opcode) {           /* Fell off the end */
+                       the_ins.error="instruction/operands mismatch";
+                       return;
+               }
+               losing=0;
+       }
+       the_ins.args=opcode->m_operands;
+       the_ins.numargs=opcode->m_opnum;
+       the_ins.numo=opcode->m_codenum;
+       the_ins.opcode[0]=getone(opcode);
+       the_ins.opcode[1]=gettwo(opcode);
+
+       for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) {
+                       /* This switch is a doozy.
+                          What the first step; its a big one! */
+               switch(s[0]) {
+
+               case '*':
+               case '~':
+               case '%':
+               case ';':
+               case '@':
+               case '!':
+               case '&':
+               case '$':
+               case '?':
+               case '/':
+#ifdef m68851
+               case '|':
+#endif
+                       switch(opP->mode) {
+                       case IMMED:
+                               tmpreg=0x3c;    /* 7.4 */
+                               if(strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
+                               else nextword=nextword=get_num(opP->con1,0);
+                               if(isvar(opP->con1))
+                                       add_fix(s[1],opP->con1,0);
+                               switch(s[1]) {
+                               case 'b':
+                                       if(!isbyte(nextword))
+                                               opP->error="operand out of range";
+                                       addword(nextword);
+                                       baseo=0;
+                                       break;
+                               case 'w':
+                                       if(!isword(nextword))
+                                               opP->error="operand out of range";
+                                       addword(nextword);
+                                       baseo=0;
+                                       break;
+                               case 'l':
+                                       addword(nextword>>16);
+                                       addword(nextword);
+                                       baseo=0;
+                                       break;
+
+                               case 'f':
+                                       baseo=2;
+                                       outro=8;
+                                       break;
+                               case 'F':
+                                       baseo=4;
+                                       outro=11;
+                                       break;
+                               case 'x':
+                                       baseo=6;
+                                       outro=15;
+                                       break;
+                               case 'p':
+                                       baseo=6;
+                                       outro= -1;
+                                       break;
+                               default:
+                                       as_fatal("Internal error:  Can't decode %c%c in line %s of file \"%s\"",
+                                                *s, s[1], __LINE__, __FILE__);
+                               }
+                               if(!baseo)
+                                       break;
+
+                               /* We gotta put out some float */
+                               if(seg(opP->con1)!=SEG_BIG) {
+                                       int_to_gen(nextword);
+                                       gen_to_words(words,baseo,(long)outro);
+                                       for(wordp=words;baseo--;wordp++)
+                                               addword(*wordp);
+                                       break;
+                               }               /* Its BIG */
+                               if(offs(opP->con1)>0) {
+                                       as_warn("Bignum assumed to be binary bit-pattern");
+                                       if(offs(opP->con1)>baseo) {
+                                               as_bad("Bignum too big for %c format; truncated",s[1]);
+                                               offs(opP->con1)=baseo;
+                                       }
+                                       baseo-=offs(opP->con1);
+                                       for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
+                                               addword(*wordp);
+                                       while(baseo--)
+                                               addword(0);
+                                       break;
+                               }
+                               gen_to_words(words,baseo,(long)outro);
+                               for(wordp=words;baseo--;wordp++)
+                                       addword(*wordp);
+                               break;
+                       case DREG:
+                               tmpreg=opP->reg-DATA; /* 0.dreg */
+                               break;
+                       case AREG:
+                               tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
+                               break;
+                       case AINDR:
+                               tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
+                               break;
+                       case ADEC:
+                               tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
+                               break;
+                       case AINC:
+                               tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
+                               break;
+                       case AOFF:
+
+                               nextword=get_num(opP->con1,80);
+                               /* Force into index mode.  Hope this works */
+
+                               /* We do the first bit for 32-bit displacements,
+                                  and the second bit for 16 bit ones.  It is
+                                  possible that we should make the default be
+                                  WORD instead of LONG, but I think that'd
+                                  break GCC, so we put up with a little
+                                  inefficiency for the sake of working output.
+                                */
+
+                               if(   !issword(nextword)
+                                  || (   isvar(opP->con1)
+                                      && (  (   opP->con1->e_siz==0
+                                             && flagseen['l']==0)
+                                          || opP->con1->e_siz==3))) {
+
+                                       if(opP->reg==PC)
+                                               tmpreg=0x3B;    /* 7.3 */
+                                       else
+                                               tmpreg=0x30+opP->reg-ADDR;      /* 6.areg */
+                                       if(isvar(opP->con1)) {
+                                               if(opP->reg==PC) {
+                                                      add_frag(adds(opP->con1),
+                                                        offs(opP->con1),
+                                                        TAB(PCLEA,SZ_UNDEF));
+                                                       break;
+                                               } else {
+                                                       addword(0x0170);
+                                                       add_fix('l',opP->con1,1);
+                                               }
+                                       } else
+                                               addword(0x0170);
+                                       addword(nextword>>16);
+                               } else {
+                                       if(opP->reg==PC)
+                                               tmpreg=0x3A; /* 7.2 */
+                                       else
+                                               tmpreg=0x28+opP->reg-ADDR; /* 5.areg */
+
+                                       if(isvar(opP->con1)) {
+                                               if(opP->reg==PC) {
+                                                       add_fix('w',opP->con1,1);
+                                               } else
+                                                       add_fix('w',opP->con1,0);
+                                               }
+                               }
+                               addword(nextword);
+                               break;
+                       case AINDX:
+                       case APODX:
+                       case AMIND:
+                       case APRDX:
+                               nextword=0;
+                               baseo=get_num(opP->con1,80);
+                               outro=get_num(opP->con2,80);
+                                       /* Figure out the 'addressing mode' */
+                                       /* Also turn on the BASE_DISABLE bit, if needed */
+                               if(opP->reg==PC || opP->reg==ZPC) {
+                                       tmpreg=0x3b; /* 7.3 */
+                                       if(opP->reg==ZPC)
+                                               nextword|=0x80;
+                               } else if(opP->reg==FAIL) {
+                                       nextword|=0x80;
+                                       tmpreg=0x30;    /* 6.garbage */
+                               } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
+
+                               siz1= (opP->con1) ? opP->con1->e_siz : 0;
+                               siz2= (opP->con2) ? opP->con2->e_siz : 0;
+
+                                       /* Index register stuff */
+                               if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
+                                       nextword|=(opP->ireg-DATA)<<12;
+
+                                       if(opP->isiz==0 || opP->isiz==3)
+                                               nextword|=0x800;
+                                       switch(opP->imul) {
+                                       case 1: break;
+                                       case 2: nextword|=0x200; break;
+                                       case 4: nextword|=0x400; break;
+                                       case 8: nextword|=0x600; break;
+                                       default: abort();
+                                       }
+                                               /* IF its simple,
+                                                  GET US OUT OF HERE! */
+
+                                               /* Must be INDEX, with an index
+                                                  register.  Address register
+                                                  cannot be ZERO-PC, and either
+                                                  :b was forced, or we know
+                                                  it will fit */
+                                       if(   opP->mode==AINDX
+                                          && opP->reg!=FAIL
+                                          && opP->reg!=ZPC
+                                          && (   siz1==1
+                                              || (   issbyte(baseo)
+                                                  && !isvar(opP->con1)))) {
+                                               nextword +=baseo&0xff;
+                                               addword(nextword);
+                                               if(isvar(opP->con1))
+                                                       add_fix('B',opP->con1,0);
+                                               break;
+                                       }
+                               } else
+                                       nextword|=0x40; /* No index reg */
+
+                                       /* It aint simple */
+                               nextword|=0x100;
+                                       /* If the guy specified a width, we assume that
+                                          it is wide enough.  Maybe it isn't.  Ifso, we lose
+                                        */
+                               switch(siz1) {
+                               case 0:
+                                       if(isvar(opP->con1) || !issword(baseo)) {
+                                               siz1=3;
+                                               nextword|=0x30;
+                                       } else if(baseo==0)
+                                               nextword|=0x10;
+                                       else {  
+                                               nextword|=0x20;
+                                               siz1=2;
+                                       }
+                                       break;
+                               case 1:
+                                       as_warn("Byte dispacement won't work.  Defaulting to :w");
+                               case 2:
+                                       nextword|=0x20;
+                                       break;
+                               case 3:
+                                       nextword|=0x30;
+                                       break;
+                               }
+
+                                       /* Figure out innner displacement stuff */
+                               if(opP->mode!=AINDX) {
+                                       switch(siz2) {
+                                       case 0:
+                                               if(isvar(opP->con2) || !issword(outro)) {
+                                                       siz2=3;
+                                                       nextword|=0x3;
+                                               } else if(outro==0)
+                                                       nextword|=0x1;
+                                               else {  
+                                                       nextword|=0x2;
+                                                       siz2=2;
+                                               }
+                                               break;
+                                       case 1:
+                                               as_warn("Byte dispacement won't work.  Defaulting to :w");
+                                       case 2:
+                                               nextword|=0x2;
+                                               break;
+                                       case 3:
+                                               nextword|=0x3;
+                                               break;
+                                       }
+                                       if(opP->mode==APODX) nextword|=0x04;
+                                       else if(opP->mode==AMIND) nextword|=0x40;
+                               }
+                               addword(nextword);
+
+                               if(isvar(opP->con1)) {
+                                       if(opP->reg==PC || opP->reg==ZPC) {
+                                               add_fix(siz1==3 ? 'l' : 'w',opP->con1,1);
+                                               opP->con1->e_exp.X_add_number+=6;
+                                       } else
+                                               add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
+                               }
+                               if(siz1==3)
+                                       addword(baseo>>16);
+                               if(siz1)
+                                       addword(baseo);
+
+                               if(isvar(opP->con2)) {
+                                       if(opP->reg==PC || opP->reg==ZPC) {
+                                               add_fix(siz2==3 ? 'l' : 'w',opP->con2,1);
+                                               opP->con1->e_exp.X_add_number+=6;
+                                       } else
+                                               add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
+                               }
+                               if(siz2==3)
+                                       addword(outro>>16);
+                               if(siz2)
+                                       addword(outro);
+
+                               break;
+
+                       case ABSL:
+                               nextword=get_num(opP->con1,80);
+                               switch(opP->con1->e_siz) {
+                               default:
+                                       as_bad("Unknown size for absolute reference");
+                               case 0:
+                                       if(!isvar(opP->con1) && issword(offs(opP->con1))) {
+                                               tmpreg=0x38; /* 7.0 */
+                                               addword(nextword);
+                                               break;
+                                       }
+                                       if(isvar(opP->con1) &&
+                                          !subs(opP->con1) &&
+                                          !strchr("~%&$?", s[0])) {
+                                               tmpreg=0x3A; /* 7.2 */
+                                               add_frag(adds(opP->con1),
+                                                        offs(opP->con1),
+                                                        TAB(PCREL,SZ_UNDEF));
+                                               break;
+                                       }
+                               case 3:         /* Fall through into long */
+                                       if(isvar(opP->con1))
+                                               add_fix('l',opP->con1,0);
+
+                                       tmpreg=0x39;    /* 7.1 mode */
+                                       addword(nextword>>16);
+                                       addword(nextword);
+                                       break;
+
+                               case 2:         /* Word */
+                                       if(isvar(opP->con1))
+                                               add_fix('w',opP->con1,0);
+
+                                       tmpreg=0x38;    /* 7.0 mode */
+                                       addword(nextword);
+                                       break;
+                               }
+                               break;
+                       case MSCR:
+                       default:
+                               as_bad("unknown/incorrect operand");
+                               /* abort(); */
+                       }
+                       install_gen_operand(s[1],tmpreg);
+                       break;
+
+               case '#':
+               case '^':
+                       switch(s[1]) {  /* JF: I hate floating point! */
+                       case 'j':
+                               tmpreg=70;
+                               break;
+                       case '8':
+                               tmpreg=20;
+                               break;
+                       case 'C':
+                               tmpreg=50;
+                               break;
+                       case '3':
+                       default:
+                               tmpreg=80;
+                               break;
+                       }
+                       tmpreg=get_num(opP->con1,tmpreg);
+                       if(isvar(opP->con1))
+                               add_fix(s[1],opP->con1,0);
+                       switch(s[1]) {
+                       case 'b':       /* Danger:  These do no check for
+                                          certain types of overflow.
+                                          user beware! */
+                               if(!isbyte(tmpreg))
+                                       opP->error="out of range";
+                               insop(tmpreg);
+                               if(isvar(opP->con1))
+                                       the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+                               break;
+                       case 'w':
+                               if(!isword(tmpreg))
+                                       opP->error="out of range";
+                               insop(tmpreg);
+                               if(isvar(opP->con1))
+                                       the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+                               break;
+                       case 'l':
+                               insop(tmpreg);          /* Because of the way insop works, we put these two out backwards */
+                               insop(tmpreg>>16);
+                               if(isvar(opP->con1))
+                                       the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+                               break;
+                       case '3':
+                               tmpreg&=0xFF;
+                       case '8':
+                       case 'C':
+                               install_operand(s[1],tmpreg);
+                               break;
+                       default:
+                               as_fatal("Internal error:  Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__);
+                       }
+                       break;
+
+               case '+':
+               case '-':
+               case 'A':
+                       install_operand(s[1],opP->reg-ADDR);
+                       break;
+
+               case 'B':
+                       tmpreg=get_num(opP->con1,80);
+                       switch(s[1]) {
+                       case 'g':
+                               if(opP->con1->e_siz) {  /* Deal with fixed size stuff by hand */
+                                       switch(opP->con1->e_siz) {
+                                       case 1:
+                                               add_fix('b',opP->con1,1);
+                                               break;
+                                       case 2:
+                                               add_fix('w',opP->con1,1);
+                                               addword(0);
+                                               break;
+                                       case 3:
+                                               add_fix('l',opP->con1,1);
+                                               addword(0);
+                                               addword(0);
+                                               break;
+                                       default:
+                                               as_bad("Bad size for expression %d", opP->con1->e_siz);
+                                       }
+                               } else if(subs(opP->con1)) {
+                                               /* We can't relax it */
+                                       the_ins.opcode[the_ins.numo-1]|=0xff;
+                                       add_fix('l',opP->con1,1);
+                                       addword(0);
+                                       addword(0);
+                               } else if(adds(opP->con1)) {
+                                       if (flagseen['m'] && 
+                                           (the_ins.opcode[0] >= 0x6200) &&
+                                           (the_ins.opcode[0] <= 0x6f00)) {
+                                         add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
+                                       } else {
+                                               add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
+                                       }
+                               } else {
+                                       /* JF:  This is the WRONG thing to do
+                                       add_frag((symbolS *)0,offs(opP->con1),TAB(BRANCH,BYTE)); */
+                                       the_ins.opcode[the_ins.numo-1]|=0xff;
+                                       offs(opP->con1)+=4;
+                                       add_fix('l',opP->con1,1);
+                                       addword(0);
+                                       addword(0);
+                               }
+                               break;
+                       case 'w':
+                               if(isvar(opP->con1)) {
+                                   /* check for DBcc instruction */
+                                       if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8) {
+                                           /* size varies if patch */
+                                           /* needed for long form */
+                                               add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
+                                               break;
+                                       }
+
+                                               /* Don't ask! */
+                                       opP->con1->e_exp.X_add_number+=2;
+                                       add_fix('w',opP->con1,1);
+                               }
+                               addword(0);
+                               break;
+                       case 'c':
+                               if(opP->con1->e_siz) {
+                                       switch(opP->con1->e_siz) {
+                                       case 2:
+                                               add_fix('w',opP->con1,1)
+                                               addword(0);
+                                               break;
+                                       case 3:
+                                               the_ins.opcode[the_ins.numo-1]|=0x40;
+                                               add_fix('l',opP->con1,1);
+                                               addword(0);
+                                               addword(0);
+                                               break;
+                                       default:
+                                               as_bad("Bad size for offset, must be word or long");
+                                               break;
+                                       }
+                               } else if(subs(opP->con1)) {
+                                       add_fix('l',opP->con1,1);
+                                       add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
+                               } else if(adds(opP->con1)) {
+                                       add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF));
+                               } else {
+                                       /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
+                                       the_ins.opcode[the_ins.numo-1]|=0x40;
+                                       add_fix('l',opP->con1,1);
+                                       addword(0);
+                                       addword(4);
+                               }
+                               break;
+                       default:
+                               as_fatal("Internal error:  operand type B%c unknown in line %s of file \"%s\"",
+                                        s[1], __LINE__, __FILE__);
+                       }
+                       break;
+
+               case 'C':               /* Ignore it */
+                       break;
+
+               case 'd':               /* JF this is a kludge */
+                       if(opP->mode==AOFF) {
+                               install_operand('s',opP->reg-ADDR);
+                       } else {
+                               char *tmpP;
+
+                               tmpP=opP->con1->e_end-2;
+                               opP->con1->e_beg++;
+                               opP->con1->e_end-=4;    /* point to the , */
+                               baseo=m68k_reg_parse(&tmpP);
+                               if(baseo<ADDR+0 || baseo>ADDR+7) {
+                                       as_bad("Unknown address reg, using A0");
+                                       baseo=0;
+                               } else baseo-=ADDR;
+                               install_operand('s',baseo);
+                       }
+                       tmpreg=get_num(opP->con1,80);
+                       if(!issword(tmpreg)) {
+                               as_bad("Expression out of range, using 0");
+                               tmpreg=0;
+                       }
+                       addword(tmpreg);
+                       break;
+
+               case 'D':
+                       install_operand(s[1],opP->reg-DATA);
+                       break;
+
+               case 'F':
+                       install_operand(s[1],opP->reg-FPREG);
+                       break;
+
+               case 'I':
+                       tmpreg=1+opP->reg-COPNUM;
+                       if(tmpreg==8)
+                               tmpreg=0;
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'J':               /* JF foo */
+                       switch(opP->reg) {
+                       case SFC:
+                               tmpreg=0;
+                               break;
+                       case DFC:
+                               tmpreg=0x001;
+                               break;
+                       case CACR:
+                               tmpreg=0x002;
+                               break;
+                       case USP:
+                               tmpreg=0x800;
+                               break;
+                       case VBR:
+                               tmpreg=0x801;
+                               break;
+                       case CAAR:
+                               tmpreg=0x802;
+                               break;
+                       case MSP:
+                               tmpreg=0x803;
+                               break;
+                       case ISP:
+                               tmpreg=0x804;
+                               break;
+                       default:
+                               abort();
+                       }
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'k':
+                       tmpreg=get_num(opP->con1,55);
+                       install_operand(s[1],tmpreg&0x7f);
+                       break;
+
+               case 'l':
+                       tmpreg=opP->reg;
+                       if(s[1]=='w') {
+                               if(tmpreg&0x7FF0000)
+                                       as_bad("Floating point register in register list");
+                               insop(reverse_16_bits(tmpreg));
+                       } else {
+                               if(tmpreg&0x700FFFF)
+                                       as_bad("Wrong register in floating-point reglist");
+                               install_operand(s[1],reverse_8_bits(tmpreg>>16));
+                       }
+                       break;
+
+               case 'L':
+                       tmpreg=opP->reg;
+                       if(s[1]=='w') {
+                               if(tmpreg&0x7FF0000)
+                                       as_bad("Floating point register in register list");
+                               insop(tmpreg);
+                       } else if(s[1]=='8') {
+                               if(tmpreg&0x0FFFFFF)
+                                       as_bad("incorrect register in reglist");
+                               install_operand(s[1],tmpreg>>24);
+                       } else {
+                               if(tmpreg&0x700FFFF)
+                                       as_bad("wrong register in floating-point reglist");
+                               else
+                                       install_operand(s[1],tmpreg>>16);
+                       }
+                       break;
+
+               case 'M':
+                       install_operand(s[1],get_num(opP->con1,60));
+                       break;
+
+               case 'O':
+                       tmpreg= (opP->mode==DREG)
+                               ? 0x20+opP->reg-DATA
+                               : (get_num(opP->con1,40)&0x1F);
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'Q':
+                       tmpreg=get_num(opP->con1,10);
+                       if(tmpreg==8)
+                               tmpreg=0;
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'R':
+                       /* This depends on the fact that ADDR registers are
+                          eight more than their corresponding DATA regs, so
+                          the result will have the ADDR_REG bit set */
+                       install_operand(s[1],opP->reg-DATA);
+                       break;
+
+               case 's':
+                       if(opP->reg==FPI) tmpreg=0x1;
+                       else if(opP->reg==FPS) tmpreg=0x2;
+                       else if(opP->reg==FPC) tmpreg=0x4;
+                       else abort();
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'S':       /* Ignore it */
+                       break;
+
+               case 'T':
+                       install_operand(s[1],get_num(opP->con1,30));
+                       break;
+
+               case 'U':       /* Ignore it */
+                       break;
+
+#ifdef m68851
+                       /* JF: These are out of order, I fear. */
+               case 'f':
+                       switch (opP->reg) {
+                       case SFC:
+                               tmpreg=0;
+                               break;
+                       case DFC:
+                               tmpreg=1;
+                               break;
+                       default:
+                               abort();
+                       }
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'P':
+                       switch(opP->reg) {
+                       case TC:
+                               tmpreg=0;
+                               break;
+                       case CAL:
+                               tmpreg=4;
+                               break;
+                       case VAL:
+                               tmpreg=5;
+                               break;
+                       case SCC:
+                               tmpreg=6;
+                               break;
+                       case AC:
+                               tmpreg=7;
+                               break;
+                       default:
+                               abort();
+                       }
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'V':
+                       if (opP->reg == VAL)
+                               break;
+                       abort();
+
+               case 'W':
+                       switch(opP->reg) {
+
+                       case DRP:
+                               tmpreg=1;
+                               break;
+                       case SRP:
+                               tmpreg=2;
+                               break;
+                       case CRP:
+                               tmpreg=3;
+                               break;
+                       default:
+                               abort();
+                       }
+                       install_operand(s[1],tmpreg);
+                       break;
+
+               case 'X':
+                       switch (opP->reg) {
+                       case BAD: case BAD+1: case BAD+2: case BAD+3:
+                       case BAD+4: case BAD+5: case BAD+6: case BAD+7:
+                               tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
+                               break;
+
+                       case BAC: case BAC+1: case BAC+2: case BAC+3:
+                       case BAC+4: case BAC+5: case BAC+6: case BAC+7:
+                               tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
+                               break;
+
+                       default:
+                               abort();
+                       }
+                       install_operand(s[1], tmpreg);
+                       break;
+               case 'Y':
+                       if (opP->reg == PSR)
+                               break;
+                       abort();
+
+               case 'Z':
+                       if (opP->reg == PCSR)
+                               break;
+                       abort();
+#endif /* m68851 */
+               default:
+                       as_fatal("Internal error:  Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__);
+               }
+       }
+       /* By the time whe get here (FINALLY) the_ins contains the complete
+          instruction, ready to be emitted. . . */
+}
+
+static int get_regs(i,str,opP)
+int i;
+struct m68k_op *opP;
+char *str;
+{
+       /*                           26, 25, 24, 23-16,  15-8, 0-7 */
+       /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
+       unsigned long cur_regs = 0;
+       int     reg1,
+               reg2;
+
+#define ADD_REG(x)     {     if(x==FPI) cur_regs|=(1<<24);\
+                        else if(x==FPS) cur_regs|=(1<<25);\
+                        else if(x==FPC) cur_regs|=(1<<26);\
+                        else cur_regs|=(1<<(x-1));  }
+
+       reg1=i;
+       for(;;) {
+               if(*str=='/') {
+                       ADD_REG(reg1);
+                       str++;
+               } else if(*str=='-') {
+                       str++;
+                       reg2=m68k_reg_parse(&str);
+                       if(reg2<DATA || reg2>=FPREG+8 || reg1==FPI || reg1==FPS || reg1==FPC) {
+                               opP->error="unknown register in register list";
+                               return FAIL;
+                       }
+                       while(reg1<=reg2) {
+                               ADD_REG(reg1);
+                               reg1++;
+                       }
+                       if(*str=='\0')
+                               break;
+               } else if(*str=='\0') {
+                       ADD_REG(reg1);
+                       break;
+               } else {
+                       opP->error="unknow character in register list";
+                       return FAIL;
+               }
+/* DJA -- Bug Fix.  Did't handle d1-d2/a1 until the following instruction was added */
+               if (*str=='/')
+                 str ++;
+               reg1=m68k_reg_parse(&str);
+               if((reg1<DATA || reg1>=FPREG+8) && !(reg1==FPI || reg1==FPS || reg1==FPC)) {
+                       opP->error="unknown register in register list";
+                       return FAIL;
+               }
+       }
+       opP->reg=cur_regs;
+       return OK;
+} /* get_regs() */
+
+static int reverse_16_bits(in)
+int in;
+{
+       int out=0;
+       int n;
+
+       static int mask[16] = {
+0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
+       };
+       for(n=0;n<16;n++) {
+               if(in&mask[n])
+                       out|=mask[15-n];
+       }
+       return out;
+} /* reverse_16_bits() */
+
+static int reverse_8_bits(in)
+int in;
+{
+       int out=0;
+       int n;
+
+       static int mask[8] = {
+0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+       };
+
+       for(n=0;n<8;n++) {
+               if(in&mask[n])
+                       out|=mask[7-n];
+       }
+       return out;
+} /* reverse_8_bits() */
+
+static void install_operand(mode,val)
+int mode;
+int val;
+{
+       switch(mode) {
+       case 's':
+               the_ins.opcode[0]|=val & 0xFF;  /* JF FF is for M kludge */
+               break;
+       case 'd':
+               the_ins.opcode[0]|=val<<9;
+               break;
+       case '1':
+               the_ins.opcode[1]|=val<<12;
+               break;
+       case '2':
+               the_ins.opcode[1]|=val<<6;
+               break;
+       case '3':
+               the_ins.opcode[1]|=val;
+               break;
+       case '4':
+               the_ins.opcode[2]|=val<<12;
+               break;
+       case '5':
+               the_ins.opcode[2]|=val<<6;
+               break;
+       case '6':
+                       /* DANGER!  This is a hack to force cas2l and cas2w cmds
+                          to be three words long! */
+               the_ins.numo++;
+               the_ins.opcode[2]|=val;
+               break;
+       case '7':
+               the_ins.opcode[1]|=val<<7;
+               break;
+       case '8':
+               the_ins.opcode[1]|=val<<10;
+               break;
+#ifdef m68851
+       case '9':
+               the_ins.opcode[1]|=val<<5;
+               break;
+#endif
+
+       case 't':
+               the_ins.opcode[1]|=(val<<10)|(val<<7);
+               break;
+       case 'D':
+               the_ins.opcode[1]|=(val<<12)|val;
+               break;
+       case 'g':
+               the_ins.opcode[0]|=val=0xff;
+               break;
+       case 'i':
+               the_ins.opcode[0]|=val<<9;
+               break;
+       case 'C':
+               the_ins.opcode[1]|=val;
+               break;
+       case 'j':
+               the_ins.opcode[1]|=val;
+               the_ins.numo++;         /* What a hack */
+               break;
+       case 'k':
+               the_ins.opcode[1]|=val<<4;
+               break;
+       case 'b':
+       case 'w':
+       case 'l':
+               break;
+       case 'c':
+       default:
+               abort();
+       }
+} /* install_operand() */
+
+static void install_gen_operand(mode,val)
+int mode;
+int val;
+{
+       switch(mode) {
+       case 's':
+               the_ins.opcode[0]|=val;
+               break;
+       case 'd':
+                       /* This is a kludge!!! */
+               the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
+               break;
+       case 'b':
+       case 'w':
+       case 'l':
+       case 'f':
+       case 'F':
+       case 'x':
+       case 'p':
+               the_ins.opcode[0]|=val;
+               break;
+               /* more stuff goes here */
+       default:
+               abort();
+       }
+} /* install_gen_operand() */
+
+static char *crack_operand(str,opP)
+register char *str;
+register struct m68k_op *opP;
+{
+       register int parens;
+       register int c;
+       register char *beg_str;
+
+       if(!str) {
+               return str;
+       }
+       beg_str=str;
+       for(parens=0;*str && (parens>0 || notend(str));str++) {
+               if(*str=='(') parens++;
+               else if(*str==')') {
+                       if(!parens) {           /* ERROR */
+                               opP->error="Extra )";
+                               return str;
+                       }
+                       --parens;
+               }
+       }
+       if(!*str && parens) {           /* ERROR */
+               opP->error="Missing )";
+               return str;
+       }
+       c= *str;
+       *str='\0';
+       if(m68k_ip_op(beg_str,opP)==FAIL) {
+               *str=c;
+               return str;
+       }
+       *str=c;
+       if(c=='}')
+               c= *++str;              /* JF bitfield hack */
+       if(c) {
+               c= *++str;
+               if(!c)
+                       as_bad("Missing operand");
+       }
+       return str;
+}
+
+/* See the comment up above where the #define notend(... is */
+#if 0
+notend(s)
+char *s;
+{
+       if(*s==',') return 0;
+       if(*s=='{' || *s=='}')
+               return 0;
+       if(*s!=':') return 1;
+               /* This kludge here is for the division cmd, which is a kludge */
+       if(strchr("aAdD#",s[1])) return 0;
+       return 1;
+}
+#endif
+
+/* 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
+md_assemble(str)
+char *str;
+{
+       char *er;
+       short   *fromP;
+       char    *toP;
+       int     m,n;
+       char    *to_beg_P;
+       int     shorts_this_frag;
+
+       bzero((char *)(&the_ins),sizeof(the_ins));      /* JF for paranoia sake */
+       m68_ip(str);
+       er=the_ins.error;
+       if(!er) {
+               for(n=the_ins.numargs;n;--n)
+                       if(the_ins.operands[n].error) {
+                               er=the_ins.operands[n].error;
+                               break;
+                       }
+       }
+       if(er) {
+               as_bad("\"%s\" -- Statement '%s' ignored",er,str);
+               return;
+       }
+
+       if(the_ins.nfrag==0) {  /* No frag hacking involved; just put it out */
+               toP=frag_more(2*the_ins.numo);
+               fromP= &the_ins.opcode[0];
+               for(m=the_ins.numo;m;--m) {
+                       md_number_to_chars(toP,(long)(*fromP),2);
+                       toP+=2;
+                       fromP++;
+               }
+                       /* put out symbol-dependent info */
+               for(m=0;m<the_ins.nrel;m++) {
+                       switch(the_ins.reloc[m].wid) {
+                       case 'B':
+                               n=1;
+                               break;
+                       case 'b':
+                               n=1;
+                               break;
+                       case '3':
+                               n=2;
+                               break;
+                       case 'w':
+                               n=2;
+                               break;
+                       case 'l':
+                               n=4;
+                               break;
+                       default:
+                               as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid);
+                       }
+
+                       fix_new(frag_now,
+                               (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
+                               n,
+                               the_ins.reloc[m].add,
+                               the_ins.reloc[m].sub,
+                               the_ins.reloc[m].off,
+                               the_ins.reloc[m].pcrel,
+                               NO_RELOC);
+               }
+               return;
+       }
+
+               /* There's some frag hacking */
+       for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) {
+               int wid;
+
+               if(n==0) wid=2*the_ins.fragb[n].fragoff;
+               else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff);
+               toP=frag_more(wid);
+               to_beg_P=toP;
+               shorts_this_frag=0;
+               for(m=wid/2;m;--m) {
+                       md_number_to_chars(toP,(long)(*fromP),2);
+                       toP+=2;
+                       fromP++;
+                       shorts_this_frag++;
+               }
+               for(m=0;m<the_ins.nrel;m++) {
+                       if((the_ins.reloc[m].n)>= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) {
+                               the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */;
+                               break;
+                       }
+                       wid=the_ins.reloc[m].wid;
+                       if(wid==0)
+                               continue;
+                       the_ins.reloc[m].wid=0;
+                       wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
+
+                       fix_new(frag_now,
+                           (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
+                           wid,
+                           the_ins.reloc[m].add,
+                           the_ins.reloc[m].sub,
+                           the_ins.reloc[m].off,
+                           the_ins.reloc[m].pcrel,
+                               NO_RELOC);
+               }
+               know(the_ins.fragb[n].fadd);
+               (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
+ the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
+       }
+       n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
+       shorts_this_frag=0;
+       if(n) {
+               toP=frag_more(n*sizeof(short));
+               while(n--) {
+                       md_number_to_chars(toP,(long)(*fromP),2);
+                       toP+=2;
+                       fromP++;
+                       shorts_this_frag++;
+               }
+       }
+       for(m=0;m<the_ins.nrel;m++) {
+               int wid;
+
+               wid=the_ins.reloc[m].wid;
+               if(wid==0)
+                       continue;
+               the_ins.reloc[m].wid=0;
+               wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
+
+               fix_new(frag_now,
+                   (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2,
+                   wid,
+                   the_ins.reloc[m].add,
+                   the_ins.reloc[m].sub,
+                   the_ins.reloc[m].off,
+                   the_ins.reloc[m].pcrel,
+                               NO_RELOC);
+       }
+}
+
+/* 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()
+{
+/*
+ * md_begin -- set up hash tables with 68000 instructions.
+ * similar to what the vax assembler does.  ---phr
+ */
+       /* RMS claims the thing to do is take the m68k-opcode.h table, and make
+          a copy of it at runtime, adding in the information we want but isn't
+          there.  I think it'd be better to have an awk script hack the table
+          at compile time.  Or even just xstr the table and use it as-is.  But
+          my lord ghod hath spoken, so we do it this way.  Excuse the ugly var
+          names.  */
+
+       register const struct m68k_opcode *ins;
+       register struct m68_incant *hack,
+               *slak;
+       register char *retval = 0;              /* empty string, or error msg text */
+       register unsigned int i;
+       register char c;
+
+       if ((op_hash = hash_new()) == NULL)
+               as_fatal("Virtual memory exhausted");
+
+       obstack_begin(&robyn,4000);
+       for (ins = m68k_opcodes; ins < endop; ins++) {
+               hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant));
+               do {
+                       slak->m_operands=ins->args;
+                       slak->m_opnum=strlen(slak->m_operands)/2;
+                       slak->m_opcode=ins->opcode;
+                               /* This is kludgey */
+                       slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
+                       if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) {
+                               slak->m_next=(struct m68_incant *)
+obstack_alloc(&robyn,sizeof(struct m68_incant));
+                               ins++;
+                       } else
+                               slak->m_next=0;
+                       slak=slak->m_next;
+               } while(slak);
+
+               retval = hash_insert (op_hash, ins->name,(char *)hack);
+                       /* Didn't his mommy tell him about null pointers? */
+               if(retval && *retval)
+                       as_fatal("Internal Error:  Can't hash %s: %s", ins->name,retval);
+       }
+
+       for (i = 0; i < sizeof(mklower_table) ; i++)
+               mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
+
+       for (i = 0 ; i < sizeof(notend_table) ; i++) {
+               notend_table[i] = 0;
+               alt_notend_table[i] = 0;
+       }
+       notend_table[','] = 1;
+       notend_table['{'] = 1;
+       notend_table['}'] = 1;
+       alt_notend_table['a'] = 1;
+       alt_notend_table['A'] = 1;
+       alt_notend_table['d'] = 1;
+       alt_notend_table['D'] = 1;
+       alt_notend_table['#'] = 1;
+       alt_notend_table['f'] = 1;
+       alt_notend_table['F'] = 1;
+#ifdef REGISTER_PREFIX
+       alt_notend_table[REGISTER_PREFIX] = 1;
+#endif
+}
+
+#if 0
+#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
+                   || (*s == ':' && strchr("aAdD#", s[1]))) \
+               ? 0 : 1)
+#endif
+
+/* This funciton is called once, before the assembler exits.  It is
+   supposed to do any final cleanup for this part of the assembler.
+ */
+void
+md_end()
+{
+}
+
+/* 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;
+
+       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 "";      /* Someone should teach Dean about null pointers */
+}
+
+/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
+   for use in the a.out file, and stores them in the array pointed to by buf.
+   This knows about the endian-ness of the target machine and does
+   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
+   2 (short) and 4 (long)  Floating numbers are put out as a series of
+   LITTLENUMS (shorts, here at least)
+ */
+void
+md_number_to_chars(buf,val,n)
+char   *buf;
+long   val;
+int n;
+{
+       switch(n) {
+       case 1:
+               *buf++=val;
+               break;
+       case 2:
+               *buf++=(val>>8);
+               *buf++=val;
+               break;
+       case 4:
+               *buf++=(val>>24);
+               *buf++=(val>>16);
+               *buf++=(val>>8);
+               *buf++=val;
+               break;
+       default:
+               abort();
+       }
+}
+
+void
+md_apply_fix(fixP, val)
+       fixS *fixP;
+       long val;
+{
+       char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+       switch(fixP->fx_size) {
+       case 1:
+               *buf++=val;
+               break;
+       case 2:
+               *buf++=(val>>8);
+               *buf++=val;
+               break;
+       case 4:
+               *buf++=(val>>24);
+               *buf++=(val>>16);
+               *buf++=(val>>8);
+               *buf++=val;
+               break;
+       default:
+               BAD_CASE (fixP->fx_size);
+       }
+}
+
+
+/* *fragP has been relaxed to its final size, and now needs to have
+   the bytes inside it modified to conform to the new size  There is UGLY
+   MAGIC here. ..
+ */
+void
+md_convert_frag(fragP)
+register fragS *fragP;
+{
+  long disp;
+  long ext;
+
+  /* Address in gas core of the place to store the displacement.  */
+  register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
+  /* Address in object code of the displacement.  */
+  register int object_address = fragP -> fr_fix + fragP -> fr_address;
+
+  know(fragP->fr_symbol);
+
+  /* The displacement of the address, from current location.  */
+  disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address;
+
+  switch(fragP->fr_subtype) {
+  case TAB(BCC68000,BYTE):
+  case TAB(BRANCH,BYTE):
+    know(issbyte(disp));
+    if(disp==0)
+      as_bad("short branch with zero offset: use :w");
+    fragP->fr_opcode[1]=disp;
+    ext=0;
+    break;
+  case TAB(DBCC,SHORT):
+    know(issword(disp));
+    ext=2;
+    break;
+  case TAB(BCC68000,SHORT):
+  case TAB(BRANCH,SHORT):
+    know(issword(disp));
+    fragP->fr_opcode[1]=0x00;
+    ext=2;
+    break;
+  case TAB(BRANCH,LONG):
+    if(flagseen['m']) {
+      if(fragP->fr_opcode[0]==0x61) {
+       fragP->fr_opcode[0]= 0x4E;
+       fragP->fr_opcode[1]= 0xB9;      /* JSR with ABSL LONG offset */
+       subseg_change(SEG_TEXT, 0);
+
+       fix_new(fragP,
+               fragP->fr_fix,
+               4,
+               fragP->fr_symbol,
+               0,
+               fragP->fr_offset,
+               0,
+               NO_RELOC);
+
+       fragP->fr_fix+=4;
+       ext=0;
+      } else if(fragP->fr_opcode[0]==0x60) {
+        fragP->fr_opcode[0]= 0x4E;
+        fragP->fr_opcode[1]= 0xF9;      /* JMP  with ABSL LONG offset */
+        subseg_change(SEG_TEXT, 0);
+        fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0,
+                               NO_RELOC);
+        fragP->fr_fix+=4;
+        ext=0;
+      }else {
+        as_bad("Long branch offset not supported.");
+      }
+    } else {
+      fragP->fr_opcode[1]=0xff;
+      ext=4;
+    }
+    break;
+  case TAB(BCC68000,LONG):
+       /* only Bcc 68000 instructions can come here */
+        /* change bcc into b!cc/jmp absl long */
+       fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
+        fragP->fr_opcode[1] = 0x6;   /* branch offset = 6 */
+
+       /* JF: these used to be fr_opcode[2,3], but they may be in a
+          different frag, in which case refering to them is a no-no.
+          Only fr_opcode[0,1] are guaranteed to work. */
+        *buffer_address++ = 0x4e;  /* put in jmp long (0x4ef9) */ 
+        *buffer_address++ = 0xf9;  
+        fragP->fr_fix += 2;         /* account for jmp instruction */
+        subseg_change(SEG_TEXT,0);
+        fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 
+                                        fragP->fr_offset,0,
+                               NO_RELOC);
+        fragP->fr_fix += 4;
+        ext=0;
+       break;
+  case TAB(DBCC,LONG):
+        /* only DBcc 68000 instructions can come here */
+        /* change dbcc into dbcc/jmp absl long */
+       /* JF: these used to be fr_opcode[2-7], but that's wrong */
+        *buffer_address++ = 0x00;  /* branch offset = 4 */
+        *buffer_address++ = 0x04;  
+        *buffer_address++ = 0x60;  /* put in bra pc+6 */ 
+        *buffer_address++ = 0x06;  
+        *buffer_address++ = 0x4e;  /* put in jmp long (0x4ef9) */ 
+        *buffer_address++ = 0xf9;  
+
+        fragP->fr_fix += 6;         /* account for bra/jmp instructions */
+        subseg_change(SEG_TEXT,0);
+        fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 
+                                        fragP->fr_offset,0,
+                               NO_RELOC);
+        fragP->fr_fix += 4;
+        ext=0;
+    break;
+  case TAB(FBRANCH,SHORT):
+    know((fragP->fr_opcode[1]&0x40)==0);
+    ext=2;
+    break;
+  case TAB(FBRANCH,LONG):
+    fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */
+    ext=4;
+    break;
+  case TAB(PCREL,SHORT):
+    ext=2;
+    break;
+  case TAB(PCREL,LONG):
+    /* FIXME-SOMEDAY, this should allow pcrel-long to be generated if -pic is on.
+       Else we can't handle position independent code.  Pcrel-long costs an
+       extra index word though.  Doing it requires more relax tables and
+       stuff elsewhere in this module though. */
+    /* The thing to do here is force it to ABSOLUTE LONG, since
+       PCREL is really trying to shorten an ABSOLUTE address anyway */
+    subseg_change(SEG_TEXT,0);
+    fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0,
+                               NO_RELOC);
+    if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
+       as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
+               fragP->fr_opcode[0],fragP->fr_address);
+    fragP->fr_opcode[1]&= ~0x3F;
+    fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
+    fragP->fr_fix+=4;
+    ext=0;
+    break;
+  case TAB(PCLEA,SHORT):
+    subseg_change(SEG_TEXT,0);
+    fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1,
+                               NO_RELOC);
+    fragP->fr_opcode[1] &= ~0x3F;
+    fragP->fr_opcode[1] |= 0x3A;
+    ext=2;
+    break;
+  case TAB(PCLEA,LONG):
+    subseg_change(SEG_TEXT,0);
+    fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1,
+                               NO_RELOC);
+    *buffer_address++ = 0x01;
+    *buffer_address++ = 0x70;
+    fragP->fr_fix+=2;
+    /* buffer_address+=2; */
+    ext=4;
+    break;
+
+  }
+  if(ext) {
+    md_number_to_chars(buffer_address,(long)disp,(int)ext);
+    fragP->fr_fix+=ext;
+  }
+}
+
+/* Force truly undefined symbols to their maximum size, and generally set up
+   the frag list to be relaxed
+ */
+int md_estimate_size_before_relax(fragP, segment)
+register fragS *fragP;
+segT segment;
+{
+       int     old_fix;
+       register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
+
+       old_fix=fragP->fr_fix;
+
+       /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
+       switch(fragP->fr_subtype) {
+       case TAB(BRANCH,SZ_UNDEF):
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+                       /* Symbol now defined; start at byte-size.  */
+                       fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
+                       break;
+               } else if(!flagseen['p'] || (!flagseen['l'] && flagseen['m'])) {
+                       /* Symbol in another segment, or undef.
+                          If we don't care about position independent code,
+                          or if we're using long displacements on a 68000,
+                          rewrite to short or long absolute. */
+                       if(fragP->fr_opcode[0]==0x61) {
+                               if(flagseen['l']) {
+                                       fragP->fr_opcode[0]= 0x4E;
+                                       fragP->fr_opcode[1]= 0xB9;      /* JBSR with ABSL WORD offset */
+                                       subseg_change(SEG_TEXT, 0);
+                                       fix_new(fragP, fragP->fr_fix, 2, 
+                                               fragP->fr_symbol, 0, fragP->fr_offset, 0,
+                               NO_RELOC);
+                                       fragP->fr_fix+=2;
+                               } else {
+                                       fragP->fr_opcode[0]= 0x4E;
+                                       fragP->fr_opcode[1]= 0xB9;      /* JBSR with ABSL LONG offset */
+                                       subseg_change(SEG_TEXT, 0);
+                                       fix_new(fragP, fragP->fr_fix, 4, 
+                                               fragP->fr_symbol, 0, fragP->fr_offset, 0,
+                               NO_RELOC);
+                                       fragP->fr_fix+=4;
+                               }
+                               frag_wane(fragP);
+                       } else if(fragP->fr_opcode[0]==0x60) {
+                               if(flagseen['l']) {
+                                       fragP->fr_opcode[0]= 0x4E;
+                                       fragP->fr_opcode[1]= 0xF8;      /* JMP  with ABSL WORD offset */
+                                       subseg_change(SEG_TEXT, 0);
+                                       fix_new(fragP, fragP->fr_fix, 2, 
+                                               fragP->fr_symbol, 0, fragP->fr_offset, 0,
+                               NO_RELOC);
+                                       fragP->fr_fix+=2;
+                               } else {
+                                       fragP->fr_opcode[0]= 0x4E;
+                                       fragP->fr_opcode[1]= 0xF9;      /* JMP  with ABSL LONG offset */
+                                       subseg_change(SEG_TEXT, 0);
+                                       fix_new(fragP, fragP->fr_fix, 4, 
+                                               fragP->fr_symbol, 0, fragP->fr_offset, 0,
+                               NO_RELOC);
+                                       fragP->fr_fix+=4;
+                               }
+                               frag_wane(fragP);
+                       } else {
+                               as_bad("Long branch offset to extern symbol not supported.");
+                       }
+               } else if(flagseen['l']) {
+                       /* Symbol in other seg or undefined, and user
+                          wants short pcrel offsets (-l).  Set size to 2, fix
+                          pcrel displacement after relax.  */
+                       fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,
+                               (symbolS *)0,fragP->fr_offset+2,1,
+                               NO_RELOC);
+                       fragP->fr_fix+=2;
+                       fragP->fr_opcode[1]=0x00;
+                       frag_wane(fragP);
+               } else {
+                       /* Symbol in other seg or undefined, and user
+                          wants long pcrel offsets.  Set size to 4, and fix
+                          pcrel displacement after relax.  */
+                       fix_new(fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol,
+                               (symbolS *)0,fragP->fr_offset + 4,1,
+                               NO_RELOC);
+                       fragP->fr_fix+=4;
+                       fragP->fr_opcode[1]=0xff;
+                       frag_wane(fragP);
+                       break;
+               }
+               break;
+
+       case TAB(FBRANCH,SZ_UNDEF):
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment
+                  || flagseen['l']) {
+                       fragP->fr_subtype=TAB(FBRANCH,SHORT);
+                       fragP->fr_var+=2;
+               } else {
+                       fragP->fr_subtype=TAB(FBRANCH,LONG);
+                       fragP->fr_var+=4;
+               }
+               break;
+
+       case TAB(PCREL,SZ_UNDEF):
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment
+                  || flagseen['l']) {
+                       fragP->fr_subtype=TAB(PCREL,SHORT);
+                       fragP->fr_var+=2;
+               } else {
+                       fragP->fr_subtype=TAB(PCREL,LONG);
+                       fragP->fr_var+=4;
+               }
+               break;
+
+       case TAB(BCC68000,SZ_UNDEF):
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+                       fragP->fr_subtype=TAB(BCC68000,BYTE);
+                       break;
+               }
+               /* only Bcc 68000 instructions can come here */
+               /* change bcc into b!cc/jmp absl long */
+               fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
+               if(flagseen['l']) {
+                       fragP->fr_opcode[1] = 0x04;   /* branch offset = 6 */
+                       /* JF: these were fr_opcode[2,3] */
+                       buffer_address[0] = 0x4e;  /* put in jmp long (0x4ef9) */ 
+                       buffer_address[1] = 0xf8;
+                       fragP->fr_fix += 2;          /* account for jmp instruction */
+                       subseg_change(SEG_TEXT,0);
+                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, 
+                                                        fragP->fr_offset,0,
+                               NO_RELOC);
+                       fragP->fr_fix += 2;
+               } else {
+                       fragP->fr_opcode[1] = 0x06;   /* branch offset = 6 */
+                       /* JF: these were fr_opcode[2,3] */
+                       buffer_address[2] = 0x4e;  /* put in jmp long (0x4ef9) */ 
+                       buffer_address[3] = 0xf9;
+                       fragP->fr_fix += 2;          /* account for jmp instruction */
+                       subseg_change(SEG_TEXT,0);
+                       fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 
+                                                        fragP->fr_offset,0,
+                               NO_RELOC);
+                       fragP->fr_fix += 4;
+               }
+               frag_wane(fragP);
+               break;
+
+       case TAB(DBCC,SZ_UNDEF):
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+                       fragP->fr_subtype=TAB(DBCC,SHORT);
+                       fragP->fr_var+=2;
+                       break;
+               }
+               /* only DBcc 68000 instructions can come here */
+               /* change dbcc into dbcc/jmp absl long */
+               /* JF: these used to be fr_opcode[2-4], which is wrong. */
+               buffer_address[0] = 0x00;  /* branch offset = 4 */
+               buffer_address[1] = 0x04;  
+               buffer_address[2] = 0x60;  /* put in bra pc + ... */ 
+               if(flagseen['l']) {
+                       /* JF: these were fr_opcode[5-7] */
+                       buffer_address[3] = 0x04; /* plus 4 */
+                       buffer_address[4] = 0x4e;/* Put in Jump Word */
+                       buffer_address[5] = 0xf8;
+                       fragP->fr_fix += 6;       /* account for bra/jmp instruction */
+                       subseg_change(SEG_TEXT,0);
+                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, 
+                                                        fragP->fr_offset,0,
+                               NO_RELOC);
+                       fragP->fr_fix+=2;
+               } else {
+                       /* JF: these were fr_opcode[5-7] */
+                       buffer_address[3] = 0x06;  /* Plus 6 */
+                       buffer_address[4] = 0x4e;  /* put in jmp long (0x4ef9) */ 
+                       buffer_address[5] = 0xf9;  
+                       fragP->fr_fix += 6;       /* account for bra/jmp instruction */
+                       subseg_change(SEG_TEXT,0);
+                       fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 
+                                                        fragP->fr_offset,0,
+                               NO_RELOC);
+                       fragP->fr_fix += 4;
+               }
+               frag_wane(fragP);
+               break;
+
+       case TAB(PCLEA,SZ_UNDEF):
+               if((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) {
+                       fragP->fr_subtype=TAB(PCLEA,SHORT);
+                       fragP->fr_var+=2;
+               } else {
+                       fragP->fr_subtype=TAB(PCLEA,LONG);
+                       fragP->fr_var+=6;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       /* now that SZ_UNDEF are taken care of, check others */
+       switch(fragP->fr_subtype) {
+       case TAB(BCC68000,BYTE):
+       case TAB(BRANCH,BYTE):
+                       /* We can't do a short jump to the next instruction,
+                          so we force word mode.  */
+               if(fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol)==0 &&
+ fragP->fr_symbol->sy_frag==fragP->fr_next) {
+                       fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
+                       fragP->fr_var+=2;
+               }
+               break;
+       default:
+               break;
+       }
+       return fragP->fr_var + fragP->fr_fix - old_fix;
+}
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+/* the bit-field entries in the relocation_info struct plays hell 
+   with the byte-order problems of cross-assembly.  So as a hack,
+   I added this mach. dependent ri twiddler.  Ugly, but it gets
+   you there. -KWK */
+/* on m68k: first 4 bytes are normal unsigned long, next three bytes
+are symbolnum, most sig. byte first.  Last byte is broken up with
+bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
+nibble as nuthin. (on Sun 3 at least) */
+/* Translate the internal relocation information into target-specific
+   format. */
+void
+md_ri_to_chars(the_bytes, ri)
+     char *the_bytes;
+     struct reloc_info_generic *ri;
+{
+  /* this is easy */
+  md_number_to_chars(the_bytes, ri->r_address, 4);
+  /* now the fun stuff */
+  the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
+  the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+  the_bytes[6] = ri->r_symbolnum & 0x0ff;
+  the_bytes[7] = (((ri->r_pcrel << 7)  & 0x80) | ((ri->r_length << 5) & 0x60) | 
+    ((ri->r_extern << 4)  & 0x10)); 
+}
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+#ifndef WORKING_DOT_WORD
+const int md_short_jump_size = 4;
+const int md_long_jump_size = 6;
+
+void
+md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       offset = to_addr - (from_addr+2);
+
+       md_number_to_chars(ptr  ,(long)0x6000,2);
+       md_number_to_chars(ptr+2,(long)offset,2);
+}
+
+void
+md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       if(flagseen['m']) {
+               offset=to_addr-S_GET_VALUE(to_symbol);
+               md_number_to_chars(ptr  ,(long)0x4EF9,2);
+               md_number_to_chars(ptr+2,(long)offset,4);
+               fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long)0,0,
+                               NO_RELOC);
+       } else {
+               offset=to_addr - (from_addr+2);
+               md_number_to_chars(ptr  ,(long)0x60ff,2);
+               md_number_to_chars(ptr+2,(long)offset,4);
+       }
+}
+
+#endif
+/* Different values of OK tell what its OK to return.  Things that aren't OK are an error (what a shock, no?)
+
+       0:  Everything is OK
+       10:  Absolute 1:8       only
+       20:  Absolute 0:7       only
+       30:  absolute 0:15      only
+       40:  Absolute 0:31      only
+       50:  absolute 0:127     only
+       55:  absolute -64:63    only
+       60:  absolute -128:127  only
+       70:  absolute 0:4095    only
+       80:  No bignums
+
+*/
+
+static int get_num(exp,ok)
+struct m68k_exp *exp;
+int ok;
+{
+#ifdef TEST2
+       long    l = 0;
+
+       if(!exp->e_beg)
+               return 0;
+       if(*exp->e_beg=='0') {
+               if(exp->e_beg[1]=='x')
+                       sscanf(exp->e_beg+2,"%x",&l);
+               else
+                       sscanf(exp->e_beg+1,"%O",&l);
+               return l;
+       }
+       return atol(exp->e_beg);
+#else
+       char    *save_in;
+       char    c_save;
+
+       if(!exp) {
+               /* Can't do anything */
+               return 0;
+       }
+       if(!exp->e_beg || !exp->e_end) {
+               seg(exp)=SEG_ABSOLUTE;
+               adds(exp)=0;
+               subs(exp)=0;
+               offs(exp)= (ok==10) ? 1 : 0;
+               as_bad("Null expression defaults to %ld", offs(exp));
+               return 0;
+       }
+
+       exp->e_siz=0;
+       if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) {
+               switch(exp->e_end[0]) {
+               case 's':
+               case 'S':
+               case 'b':
+               case 'B':
+                       exp->e_siz=1;
+                       break;
+               case 'w':
+               case 'W':
+                       exp->e_siz=2;
+                       break;
+               case 'l':
+               case 'L':
+                       exp->e_siz=3;
+                       break;
+               default:
+                       as_bad("Unknown size for expression \"%c\"", exp->e_end[0]);
+               }
+               exp->e_end-=2;
+       }
+       c_save=exp->e_end[1];
+       exp->e_end[1]='\0';
+       save_in=input_line_pointer;
+       input_line_pointer=exp->e_beg;
+       switch(expression(&(exp->e_exp))) {
+       case SEG_PASS1:
+               seg(exp)=SEG_ABSOLUTE;
+               adds(exp)=0;
+               subs(exp)=0;
+               offs(exp)= (ok==10) ? 1 : 0;
+               as_bad("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp));
+               break;
+
+       case SEG_ABSENT:
+               /* Do the same thing the VAX asm does */
+               seg(exp)=SEG_ABSOLUTE;
+               adds(exp)=0;
+               subs(exp)=0;
+               offs(exp)=0;
+               if(ok==10) {
+                       as_bad("expression out of range: defaulting to 1");
+                       offs(exp)=1;
+               }
+               break;
+       case SEG_ABSOLUTE:
+               switch(ok) {
+               case 10:
+                       if(offs(exp)<1 || offs(exp)>8) {
+                               as_bad("expression out of range: defaulting to 1");
+                               offs(exp)=1;
+                       }
+                       break;
+               case 20:
+                       if(offs(exp)<0 || offs(exp)>7)
+                               goto outrange;
+                       break;
+               case 30:
+                       if(offs(exp)<0 || offs(exp)>15)
+                               goto outrange;
+                       break;
+               case 40:
+                       if(offs(exp)<0 || offs(exp)>32)
+                               goto outrange;
+                       break;
+               case 50:
+                       if(offs(exp)<0 || offs(exp)>127)
+                               goto outrange;
+                       break;
+               case 55:
+                       if(offs(exp)<-64 || offs(exp)>63)
+                               goto outrange;
+                       break;
+               case 60:
+                       if(offs(exp)<-128 || offs(exp)>127)
+                               goto outrange;
+                       break;
+               case 70:
+                       if(offs(exp)<0 || offs(exp)>4095) {
+                       outrange:
+                               as_bad("expression out of range: defaulting to 0");
+                               offs(exp)=0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case SEG_TEXT:
+       case SEG_DATA:
+       case SEG_BSS:
+       case SEG_UNKNOWN:
+       case SEG_DIFFERENCE:
+               if(ok>=10 && ok<=70) {
+                       seg(exp)=SEG_ABSOLUTE;
+                       adds(exp)=0;
+                       subs(exp)=0;
+                       offs(exp)= (ok==10) ? 1 : 0;
+                       as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
+               }
+               break;
+       case SEG_BIG:
+               if(ok==80 && offs(exp)<0) {     /* HACK! Turn it into a long */
+                       LITTLENUM_TYPE words[6];
+
+                       gen_to_words(words,2,8L);/* These numbers are magic! */
+                       seg(exp)=SEG_ABSOLUTE;
+                       adds(exp)=0;
+                       subs(exp)=0;
+                       offs(exp)=words[1]|(words[0]<<16);
+               } else if(ok!=0) {
+                       seg(exp)=SEG_ABSOLUTE;
+                       adds(exp)=0;
+                       subs(exp)=0;
+                       offs(exp)= (ok==10) ? 1 : 0;
+                       as_bad("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
+               }
+               break;
+       default:
+               abort();
+       }
+       if(input_line_pointer!=exp->e_end+1)
+               as_bad("Ignoring junk after expression");
+       exp->e_end[1]=c_save;
+       input_line_pointer=save_in;
+       if(exp->e_siz) {
+               switch(exp->e_siz) {
+               case 1:
+                       if(!isbyte(offs(exp)))
+                               as_bad("expression doesn't fit in BYTE");
+                       break;
+               case 2:
+                       if(!isword(offs(exp)))
+                               as_bad("expression doesn't fit in WORD");
+                       break;
+               }
+       }
+       return offs(exp);
+#endif
+} /* get_num() */
+
+/* These are the back-ends for the various machine dependent pseudo-ops.  */
+
+static void s_data1() {
+       subseg_new(SEG_DATA,1);
+       demand_empty_rest_of_line();
+} /* s_data1() */
+
+static void s_data2() {
+       subseg_new(SEG_DATA,2);
+       demand_empty_rest_of_line();
+} /* s_data2() */
+
+static void s_bss() {
+       /* We don't support putting frags in the BSS segment, but we
+          can put them into initialized data for now... */
+       subseg_new(SEG_DATA,255);       /* FIXME-SOON */
+       demand_empty_rest_of_line();
+} /* s_bss() */
+
+static void s_even() {
+       register int temp;
+       register long temp_fill;
+
+       temp = 1;               /* JF should be 2? */
+       temp_fill = get_absolute_expression ();
+       if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */
+               frag_align (temp, (int)temp_fill);
+       demand_empty_rest_of_line();
+} /* s_even() */
+
+static void s_proc() {
+       demand_empty_rest_of_line();
+} /* s_proc() */
+
+/* s_space is defined in read.c .skip is simply an alias to it. */
+
+int
+md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+       switch(**argP) {
+       case 'l':       /* -l means keep externals to 2 byte branch offsets
+                          rather than 4 byte branch offsets */
+               break;
+
+       case 'm':
+               /* Gas almost ignores this option! */
+               (*argP)++;
+               if(**argP=='c')
+                       (*argP)++;
+               if(!strcmp(*argP,"68000"))
+                       flagseen['m']=2;
+               else if(!strcmp(*argP,"68010")) {
+#ifdef TE_SUN
+                       magic_number_for_object_file = 1<<16|OMAGIC;
+#endif
+                       flagseen['m']=1;
+               } else if(!strcmp(*argP,"68020"))
+                       flagseen['m']=0;
+               else
+                       as_warn("Unknown -m option ignored");
+               while(**argP)
+                       (*argP)++;
+               break;
+
+       case 'p':
+               if (!strcmp(*argP,"pic")) {
+                       (*argP) += 3;
+                       break;          /* -pic, Position Independent Code */
+               }
+               else
+                       return 0;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+
+#ifdef TEST2
+
+/* TEST2:  Test md_assemble() */
+/* Warning, this routine probably doesn't work anymore */
+
+main()
+{
+       struct m68_it the_ins;
+       char buf[120];
+       char *cp;
+       int     n;
+
+       m68_ip_begin();
+       for(;;) {
+               if(!gets(buf) || !*buf)
+                       break;
+               if(buf[0]=='|' || buf[1]=='.')
+                       continue;
+               for(cp=buf;*cp;cp++)
+                       if(*cp=='\t')
+                               *cp=' ';
+               if(is_label(buf))
+                       continue;
+               bzero(&the_ins,sizeof(the_ins));
+               m68_ip(&the_ins,buf);
+               if(the_ins.error) {
+                       printf("Error %s in %s\n",the_ins.error,buf);
+               } else {
+                       printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args);
+                       for(n=0;n<the_ins.numo;n++)
+                               printf(" 0x%x",the_ins.opcode[n]&0xffff);
+                       printf("    ");
+                       print_the_insn(&the_ins.opcode[0],stdout);
+                       (void)putchar('\n');
+               }
+               for(n=0;n<strlen(the_ins.args)/2;n++) {
+                       if(the_ins.operands[n].error) {
+                               printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf);
+                               continue;
+                       }
+                       printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg);
+                       if(the_ins.operands[n].b_const)
+                               printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
+                       printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul);
+                       if(the_ins.operands[n].b_iadd)
+                               printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
+                       (void)putchar('\n');
+               }
+       }
+       m68_ip_end();
+       return 0;
+}
+
+is_label(str)
+char *str;
+{
+       while(*str==' ')
+               str++;
+       while(*str && *str!=' ')
+               str++;
+       if(str[-1]==':' || str[1]=='=')
+               return 1;
+       return 0;
+}
+
+#endif
+
+/* Possible states for relaxation:
+
+0 0    branch offset   byte    (bra, etc)
+0 1                    word
+0 2                    long
+
+1 0    indexed offsets byte    a0@(32,d4:w:1) etc
+1 1                    word
+1 2                    long
+
+2 0    two-offset index word-word a0@(32,d4)@(45) etc
+2 1                    word-long
+2 2                    long-word
+2 3                    long-long
+
+*/
+
+
+
+#ifdef DONTDEF
+abort()
+{
+       printf("ABORT!\n");
+       exit(12);
+}
+
+char *index(s,c)
+char *s;
+{
+       while(*s!=c) {
+               if(!*s) return 0;
+               s++;
+       }
+       return s;
+}
+
+bzero(s,n)
+char *s;
+{
+       while(n--)
+               *s++=0;
+}
+
+print_frags()
+{
+       fragS *fragP;
+       extern fragS *text_frag_root;
+
+       for(fragP=text_frag_root;fragP;fragP=fragP->fr_next) {
+               printf("addr %lu  next 0x%x  fix %ld  var %ld  symbol 0x%x  offset %ld\n",
+ fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
+               printf("opcode 0x%x  type %d  subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype);
+       }
+       fflush(stdout);
+       return 0;
+}
+#endif
+
+#ifdef DONTDEF
+/*VARARGS1*/
+panic(format,args)
+char *format;
+{
+       fputs("Internal error:",stderr);
+       _doprnt(format,&args,stderr);
+       (void)putc('\n',stderr);
+       as_where();
+       abort();
+}
+#endif
+
+/* We have no need to default values of symbols.  */
+
+/* ARGSUSED */
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}
+
+/* Parse an operand that is machine-specific.  
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the 68k, 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;
+}
+
+/* Opcode table for m68000/m68020 and m68881.
+   Copyright (C) 1989, Free Software Foundation.
+
+This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.
+
+Both GDB and GAS are free software; you can redistribute 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.
+
+GDB and GAS are 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 GDB or GAS; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+/* We store four bytes of opcode for all opcodes because that
+   is the most any of them need.  The actual length of an instruction
+   is always at least 2 bytes, and is as much longer as necessary to
+   hold the operands it has.
+
+   The match component is a mask saying which bits must match
+   particular opcode in order for an instruction to be an instance
+   of that opcode.
+
+   The args component is a string containing two characters
+   for each operand of the instruction.  The first specifies
+   the kind of operand; the second, the place it is stored.  */
+
+/* Kinds of operands:
+   D  data register only.  Stored as 3 bits.
+   A  address register only.  Stored as 3 bits.
+   R  either kind of register.  Stored as 4 bits.
+   F  floating point coprocessor register only.   Stored as 3 bits.
+   O  an offset (or width): immediate data 0-31 or data register.
+      Stored as 6 bits in special format for BF... insns.
+   +  autoincrement only.  Stored as 3 bits (number of the address register).
+   -  autodecrement only.  Stored as 3 bits (number of the address register).
+   Q  quick immediate data.  Stored as 3 bits.
+      This matches an immediate operand only when value is in range 1 .. 8.
+   M  moveq immediate data.  Stored as 8 bits.
+      This matches an immediate operand only when value is in range -128..127
+   T  trap vector immediate data.  Stored as 4 bits.
+
+   k  K-factor for fmove.p instruction.   Stored as a 7-bit constant or
+      a three bit register offset, depending on the field type.
+
+   #  immediate data.  Stored in special places (b, w or l)
+      which say how many bits to store.
+   ^  immediate data for floating point instructions.   Special places
+      are offset by 2 bytes from '#'...
+   B  pc-relative address, converted to an offset
+      that is treated as immediate data.
+   d  displacement and register.  Stores the register as 3 bits
+      and stores the displacement in the entire second word.
+
+   C  the CCR.  No need to store it; this is just for filtering validity.
+   S  the SR.  No need to store, just as with CCR.
+   U  the USP.  No need to store, just as with CCR.
+
+   I  Coprocessor ID.   Not printed if 1.   The Coprocessor ID is always
+      extracted from the 'd' field of word one, which means that an extended
+      coprocessor opcode can be skipped using the 'i' place, if needed.
+
+   s  System Control register for the floating point coprocessor.
+   S  List of system control registers for floating point coprocessor.
+
+   J  Misc register for movec instruction, stored in 'j' format.
+       Possible values:
+       000     SFC     Source Function Code reg
+       001     DFC     Data Function Code reg
+       002     CACR    Cache Control Register
+       800     USP     User Stack Pointer
+       801     VBR     Vector Base reg
+       802     CAAR    Cache Address Register
+       803     MSP     Master Stack Pointer
+       804     ISP     Interrupt Stack Pointer
+
+    L  Register list of the type d0-d7/a0-a7 etc.
+       (New!  Improved!  Can also hold fp0-fp7, as well!)
+       The assembler tries to see if the registers match the insn by
+       looking at where the insn wants them stored.
+
+    l  Register list like L, but with all the bits reversed.
+       Used for going the other way. . .
+
+ They are all stored as 6 bits using an address mode and a register number;
+ they differ in which addressing modes they match.
+
+   *  all                                      (modes 0-6,7.*)
+   ~  alterable memory                         (modes 2-6,7.0,7.1)(not 0,1,7.~)
+   %  alterable                                        (modes 0-6,7.0,7.1)(not 7.~)
+   ;  data                                     (modes 0,2-6,7.*)(not 1)
+   @  data, but not immediate                  (modes 0,2-6,7.? ? ?)(not 1,7.?)  This may really be ;, the 68020 book says it is
+   !  control                                  (modes 2,5,6,7.*-)(not 0,1,3,4,7.4)
+   &  alterable control                                (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?)
+   $  alterable data                           (modes 0,2-6,7.0,7.1)(not 1,7.~)
+   ?  alterable control, or data register      (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~)
+   /  control, or data register                        (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4)
+*/
+
+/* JF: for the 68851 */
+/*
+   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.*)
+
+*/
+
+/* Places to put an operand, for non-general operands:
+   s  source, low bits of first word.
+   d  dest, shifted 9 in first word
+   1  second word, shifted 12
+   2  second word, shifted 6
+   3  second word, shifted 0
+   4  third word, shifted 12
+   5  third word, shifted 6
+   6  third word, shifted 0
+   7  second word, shifted 7
+   8  second word, shifted 10
+   D  store in both place 1 and place 3; for divul and divsl.
+   b  second word, low byte
+   w  second word (entire)
+   l  second and third word (entire)
+   g  branch offset for bra and similar instructions.
+      The place to store depends on the magnitude of offset.
+   t  store in both place 7 and place 8; for floating point operations
+   c  branch offset for cpBcc operations.
+      The place to store is word two if bit six of word one is zero,
+      and words two and three if bit six of word one is one.
+   i  Increment by two, to skip over coprocessor extended operands.   Only
+      works with the 'I' format.
+   k  Dynamic K-factor field.   Bits 6-4 of word 2, used as a register number.
+      Also used for dynamic fmovem instruction.
+   C  floating point coprocessor constant - 7 bits.  Also used for static
+      K-factors...
+   j  Movec register #, stored in 12 low bits of second word.
+
+ Places to put operand, for general operands:
+   d  destination, shifted 6 bits in first word
+   b  source, at low bit of first word, and immediate uses one byte
+   w  source, at low bit of first word, and immediate uses two bytes
+   l  source, at low bit of first word, and immediate uses four bytes
+   s  source, at low bit of first word.
+      Used sometimes in contexts where immediate is not allowed anyway.
+   f  single precision float, low bit of 1st word, immediate uses 4 bytes
+   F  double precision float, low bit of 1st word, immediate uses 8 bytes
+   x  extended precision float, low bit of 1st word, immediate uses 12 bytes
+   p  packed float, low bit of 1st word, immediate uses 12 bytes
+*/
+
+#define one(x) ((x) << 16)
+#define two(x, y) (((x) << 16) + y)
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-m68k.c */
diff --git a/gas/config/tc-m68k.h b/gas/config/tc-m68k.h
new file mode 100644 (file)
index 0000000..4fa516c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * This file is tp-generic.h and is intended to be a template for
+ * target processor specific header files. 
+ */
+
+#define TC_M68K 1
+
+#ifdef TE_SUN3
+/* This variable contains the value to write out at the beginning of
+   the a.out file.  The 2<<16 means that this is a 68020 file instead
+   of an old-style 68000 file */
+
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (2<<16|OMAGIC);   /* Magic byte for file header */
+#endif /* TE_SUN3 */
+
+#define tc_crawl_symbol_chain(a)       ; /* not used */
+#define tc_headers_hook(a)             ; /* not used */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-m68k.h */
diff --git a/gas/config/tc-ns32k.c b/gas/config/tc-ns32k.c
new file mode 100644 (file)
index 0000000..f4fd883
--- /dev/null
@@ -0,0 +1,1867 @@
+/* ns32k.c  -- Assemble on the National Semiconductor 32k series
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*#define SHOW_NUM 1*/ /* uncomment for debugging */
+
+#include <stdio.h>
+#include <ctype.h>
+#ifdef USG
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "ns32k-opcode.h"
+
+#include "as.h"
+
+#include "obstack.h"
+
+/* Macros */
+#define IIF_ENTRIES 13                         /* number of entries in iif */ 
+#define PRIVATE_SIZE 256                       /* size of my garbage memory */
+#define MAX_ARGS 4
+#define DEFAULT        -1              /* addr_mode returns this value when plain constant or label is encountered */
+
+#define IIF(ptr,a1,c1,e1,g1,i1,k1,m1,o1,q1,s1,u1) \
+  iif.iifP[ptr].type= a1; \
+  iif.iifP[ptr].size= c1; \
+  iif.iifP[ptr].object= e1; \
+  iif.iifP[ptr].object_adjust= g1; \
+  iif.iifP[ptr].pcrel= i1; \
+  iif.iifP[ptr].pcrel_adjust= k1; \
+  iif.iifP[ptr].im_disp= m1; \
+  iif.iifP[ptr].relax_substate= o1; \
+  iif.iifP[ptr].bit_fixP= q1; \
+  iif.iifP[ptr].addr_mode= s1; \
+  iif.iifP[ptr].bsr= u1;
+
+#ifdef SEQUENT_COMPATABILITY
+#define LINE_COMMENT_CHARS "|"
+#define ABSOLUTE_PREFIX '@'
+#define IMMEDIATE_PREFIX '#'
+#endif
+
+#ifndef LINE_COMMENT_CHARS
+#define LINE_COMMENT_CHARS "#"
+#endif
+
+char comment_chars[] = "#";
+char line_comment_chars[] = LINE_COMMENT_CHARS;
+#if !defined(ABSOLUTE_PREFIX) && !defined(IMMEDIATE_PREFIX)
+#define ABSOLUTE_PREFIX '@'    /* One or the other MUST be defined */
+#endif
+
+struct addr_mode {
+  char mode;                   /* addressing mode of operand (0-31) */
+  char scaled_mode;            /* mode combined with scaled mode */
+  char scaled_reg;             /* register used in scaled+1 (1-8) */
+  char float_flag;             /* set if R0..R7 was F0..F7 ie a floating-point-register */
+  char am_size;                        /* estimated max size of general addr-mode parts*/
+  char im_disp;                        /* if im_disp==1 we have a displacement */
+  char pcrel;                  /* 1 if pcrel, this is really redundant info */
+  char disp_suffix[2];         /* length of displacement(s), 0=undefined */
+  char *disp[2];               /* pointer(s) at displacement(s)
+                                             or immediates(s)     (ascii) */
+  char index_byte;             /* index byte */
+};
+typedef struct addr_mode addr_modeS;
+
+
+char *freeptr,*freeptr_static; /* points at some number of free bytes */
+struct hash_control *inst_hash_handle;
+
+struct ns32k_opcode *desc; /* pointer at description of instruction */
+addr_modeS addr_modeP;
+char EXP_CHARS[] = "eE";
+char FLT_CHARS[] = "fd"; /* we don't want to support lowercase, do we */
+
+/* UPPERCASE denotes live names 
+ * when an instruction is built, IIF is used as an intermidiate form to store
+ * the actual parts of the instruction. A ns32k machine instruction can
+ * be divided into a couple of sub PARTs. When an instruction is assembled
+ * the appropriate PART get an assignment. When an IIF has been completed it's
+ * converted to a FRAGment as specified in AS.H */
+
+/* internal structs */
+struct option {
+  char *pattern;
+  unsigned long or;
+  unsigned long and;
+};
+
+typedef struct {
+  int                  type;           /* how to interpret object */
+  int                  size;           /* Estimated max size of object */
+  unsigned long                object;         /* binary data */
+  int                  object_adjust;  /* number added to object */
+  int                  pcrel;          /* True if object is pcrel */
+  int                  pcrel_adjust;   /* It's value reflects the length in bytes from the instruction start to the displacement */
+  int                  im_disp;        /* True if the object is a displacement */
+  relax_substateT      relax_substate; /* Initial relaxsubstate */
+  bit_fixS             *bit_fixP;      /* Pointer at bit_fix struct */ 
+  int                  addr_mode;      /* What addrmode do we associate with this iif-entry */
+  char                 bsr;            /* Sequent hack */
+}iif_entryT;                           /* Internal Instruction Format */
+struct int_ins_form {
+  int          instr_size;             /* Max size of instruction in bytes. */
+  iif_entryT    iifP[IIF_ENTRIES+1];
+};
+struct int_ins_form iif;
+expressionS exprP;
+char *input_line_pointer;
+/* description of the PARTs in IIF 
+ *object[n]:
+ * 0   total length in bytes of entries in iif
+ * 1   opcode
+ * 2   index_byte_a
+ * 3   index_byte_b
+ * 4   disp_a_1
+ * 5   disp_a_2
+ * 6   disp_b_1
+ * 7   disp_b_2
+ * 8   imm_a
+ * 9   imm_b
+ * 10  implied1
+ * 11  implied2
+ * 
+ * For every entry there is a datalength in bytes. This is stored in size[n].
+ *      0,     the objectlength is not explicitly given by the instruction
+ *             and the operand is undefined. This is a case for relaxation.
+ *             Reserve 4 bytes for the final object.
+ *
+ *      1,     the entry contains one byte
+ *      2,     the entry contains two bytes
+ *      3,     the entry contains three bytes
+ *      4,     the entry contains four bytes
+ *     etc
+ *
+ * Furthermore, every entry has a data type identifier in type[n].
+ *
+ *      0,     the entry is void, ignore it.
+ *      1,     the entry is a binary number.
+ *      2,     the entry is a pointer at an expression.
+ *             Where expression may be as simple as a single '1',
+ *             and as complicated as  foo-bar+12,
+ *             foo and bar may be undefined but suffixed by :{b|w|d} to
+ *             control the length of the object.
+ *
+ *      3,     the entry is a pointer at a bignum struct
+ *
+ *
+ * The low-order-byte coresponds to low physical memory.
+ * Obviously a FRAGment must be created for each valid disp in PART whose
+ * datalength is undefined (to bad) .
+ * The case where just the expression is undefined is less severe and is
+ * handled by fix. Here the number of bytes in the objectfile is known.
+ * With this representation we simplify the assembly and separates the
+ * machine dependent/independent parts in a more clean way (said OE)
+ */
+\f
+struct option opt1[]= /* restore, exit */
+{
+  { "r0",      0x80,   0xff    },
+  { "r1",      0x40,   0xff    },
+  { "r2",      0x20,   0xff    },
+  { "r3",      0x10,   0xff    },
+  { "r4",      0x08,   0xff    },
+  { "r5",      0x04,   0xff    },
+  { "r6",      0x02,   0xff    },
+  { "r7",      0x01,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option opt2[]= /* save, enter */
+{
+  { "r0",      0x01,   0xff    },
+  { "r1",      0x02,   0xff    },
+  { "r2",      0x04,   0xff    },
+  { "r3",      0x08,   0xff    },
+  { "r4",      0x10,   0xff    },
+  { "r5",      0x20,   0xff    },
+  { "r6",      0x40,   0xff    },
+  { "r7",      0x80,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option opt3[]= /* setcfg */
+{
+  { "c",       0x8,    0xff    },
+  { "m",       0x4,    0xff    },
+  { "f",       0x2,    0xff    },
+  { "i",       0x1,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt4[]= /* cinv */
+{
+  { "a",       0x4,    0xff    },
+  { "i",       0x2,    0xff    },
+  { "d",       0x1,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt5[]= /* string inst */
+{
+  { "b",       0x2,    0xff    },
+  { "u",       0xc,    0xff    },
+  { "w",       0x4,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option opt6[]= /* plain reg ext,cvtp etc */
+{
+  { "r0",      0x00,   0xff    },
+  { "r1",      0x01,   0xff    },
+  { "r2",      0x02,   0xff    },
+  { "r3",      0x03,   0xff    },
+  { "r4",      0x04,   0xff    },
+  { "r5",      0x05,   0xff    },
+  { "r6",      0x06,   0xff    },
+  { "r7",      0x07,   0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+
+#if !defined(NS32032) && !defined(NS32532)
+#define NS32032
+#endif
+
+struct option cpureg_532[]= /* lpr spr */
+{
+  { "us",      0x0,    0xff    },
+  { "dcr",     0x1,    0xff    },
+  { "bpc",     0x2,    0xff    },
+  { "dsr",     0x3,    0xff    },
+  { "car",     0x4,    0xff    },
+  { "fp",      0x8,    0xff    },
+  { "sp",      0x9,    0xff    },
+  { "sb",      0xa,    0xff    },
+  { "usp",     0xb,    0xff    },
+  { "cfg",     0xc,    0xff    },
+  { "psr",     0xd,    0xff    },
+  { "intbase", 0xe,    0xff    },
+  { "mod",     0xf,    0xff    },
+  {  0 ,       0x00,   0xff    }
+};
+struct option mmureg_532[]= /* lmr smr */
+{
+  { "mcr",     0x9,    0xff    },
+  { "msr",     0xa,    0xff    },
+  { "tear",    0xb,    0xff    },
+  { "ptb0",    0xc,    0xff    },
+  { "ptb1",    0xd,    0xff    },
+  { "ivar0",   0xe,    0xff    },
+  { "ivar1",   0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+
+struct option cpureg_032[]= /* lpr spr */
+{
+  { "upsr",    0x0,    0xff    },
+  { "fp",      0x8,    0xff    },
+  { "sp",      0x9,    0xff    },
+  { "sb",      0xa,    0xff    },
+  { "psr",     0xd,    0xff    },
+  { "intbase", 0xe,    0xff    },
+  { "mod",     0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+struct option mmureg_032[]= /* lmr smr */
+{
+  { "bpr0",    0x0,    0xff    },
+  { "bpr1",    0x1,    0xff    },
+  { "pf0",     0x4,    0xff    },
+  { "pf1",     0x5,    0xff    },
+  { "sc",      0x8,    0xff    },
+  { "msr",     0xa,    0xff    },
+  { "bcnt",    0xb,    0xff    },
+  { "ptb0",    0xc,    0xff    },
+  { "ptb1",    0xd,    0xff    },
+  { "eia",     0xf,    0xff    },
+  {  0 ,       0x0,    0xff    }
+};
+
+#if defined(NS32532)
+struct option *cpureg = cpureg_532;
+struct option *mmureg = mmureg_532;
+#else
+struct option *cpureg = cpureg_032;
+struct option *mmureg = mmureg_032;
+#endif
+\f
+
+const pseudo_typeS md_pseudo_table[]={ /* so far empty */
+  { 0, 0,      0       }
+};
+
+#define IND(x,y)       (((x)<<2)+(y))
+
+/* those are index's to relax groups in md_relax_table 
+   ie it must be multiplied by 4 to point at a group start. Viz IND(x,y)
+   Se function relax_segment in write.c for more info */
+
+#define BRANCH         1
+#define PCREL          2 
+
+/* those are index's to entries in a relax group */
+
+#define BYTE           0
+#define WORD           1
+#define DOUBLE         2
+#define UNDEF           3
+/* Those limits are calculated from the displacement start in memory.
+   The ns32k uses the begining of the instruction as displacement base.
+   This type of displacements could be handled here by moving the limit window
+   up or down. I choose to use an internal displacement base-adjust as there
+   are other routines that must consider this. Also, as we have two various
+   offset-adjusts in the ns32k (acb versus br/brs/jsr/bcond), two set of limits
+   would have had to be used.
+   Now we dont have to think about that. */
+
+
+const relax_typeS md_relax_table[]={
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+  { 1,         1,              0,      0                       },
+
+  { (63),      (-64),          1,      IND(BRANCH,WORD)        },
+  { (8192),    (-8192),        2,      IND(BRANCH,DOUBLE)      },
+  { 0,         0,              4,      0                       },
+  { 1,         1,              0,      0                       }
+};
+
+/* Array used to test if mode contains displacements.
+   Value is true if mode contains displacement. */
+
+char disp_test[]={ 0,0,0,0,0,0,0,0,
+                  1,1,1,1,1,1,1,1,
+                  1,1,1,0,0,1,1,0,
+                  1,1,1,1,1,1,1,1 };
+
+/* Array used to calculate max size of displacements */
+
+char disp_size[]={ 4,1,2,0,4 };
+\f
+
+#ifdef __STDC__
+
+static segT evaluate_expr(expressionS *resultP, char *ptr);
+static void md_number_to_disp(char *buf, long val, int n);
+static void md_number_to_imm(char *buf, long val, int n);
+
+#else /* __STDC__ */
+
+static segT evaluate_expr();
+static void md_number_to_disp();
+static void md_number_to_imm();
+
+#endif /* __STDC__ */
+
+/* Parses a general operand into an addressingmode struct 
+
+   in:  pointer at operand in ascii form
+        pointer at addr_mode struct for result
+       the level of recursion. (always 0 or 1)
+
+   out: data in addr_mode struct
+ */
+int addr_mode(operand,addr_modeP,recursive_level)
+     char *operand;
+     register addr_modeS *addr_modeP;
+int recursive_level;
+{
+  register char *str;
+  register int i;
+  register int strl;
+  register int mode;
+  int j;
+  mode = DEFAULT;                              /* default */
+  addr_modeP->scaled_mode=0;           /* why not */
+  addr_modeP->scaled_reg=0;            /* if 0, not scaled index */
+  addr_modeP->float_flag=0;
+  addr_modeP->am_size=0;
+  addr_modeP->im_disp=0;
+  addr_modeP->pcrel=0;                 /* not set in this function */
+  addr_modeP->disp_suffix[0]=0;
+  addr_modeP->disp_suffix[1]=0;
+  addr_modeP->disp[0]=NULL;
+  addr_modeP->disp[1]=NULL;
+  str=operand;
+  if (str[0]==0) {return (0);}         /* we don't want this */
+  strl=strlen(str);               
+  switch (str[0]) {
+    /* the following three case statements controls the mode-chars
+       this is the place to ed if you want to change them */
+#ifdef ABSOLUTE_PREFIX
+  case ABSOLUTE_PREFIX:
+    if (str[strl-1]==']') break;
+    addr_modeP->mode=21;               /* absolute */
+    addr_modeP->disp[0]=str+1;
+    return (-1);
+#endif
+#ifdef IMMEDIATE_PREFIX
+  case IMMEDIATE_PREFIX:
+    if (str[strl-1]==']') break;
+    addr_modeP->mode=20;               /* immediate */
+    addr_modeP->disp[0]=str+1;
+    return (-1);
+#endif
+  case '.':
+    if (str[strl-1]!=']') {
+      switch (str[1]) {
+      case'-':case'+':
+        if (str[2]!='\000') {
+         addr_modeP->mode=27;          /* pc-relativ */
+         addr_modeP->disp[0]=str+2;
+         return (-1);
+       }
+      default:
+        as_warn("Invalid syntax in PC-relative addressing mode");
+        return(0);
+      }
+    }
+    break;
+  case'e':
+    if (str[strl-1]!=']') {
+      if((!strncmp(str,"ext(",4)) && strl>7) { /* external */
+       addr_modeP->disp[0]=str+4;
+       i=0;
+       j=2;
+       do {                             /* disp[0]'s termination point */
+         j+=1;
+         if (str[j]=='(') i++;
+         if (str[j]==')') i--;
+       } while (j<strl && i!=0);
+       if (i!=0 || !(str[j+1]=='-' || str[j+1]=='+') ) {
+         as_warn("Invalid syntax in External addressing mode");
+         return(0);
+       }
+       str[j]='\000';                  /* null terminate disp[0] */
+       addr_modeP->disp[1]=str+j+2;
+       addr_modeP->mode=22;
+       return (-1);
+      }
+    }
+  break;
+  default:;
+  }
+  strl=strlen(str);               
+  switch(strl) {
+  case 2:
+    switch (str[0]) {
+    case'f':addr_modeP->float_flag=1;
+    case'r':
+      if (str[1]>='0' && str[1]<'8') {
+       addr_modeP->mode=str[1]-'0';
+       return (-1);
+      }
+    }
+  case 3:
+    if (!strncmp(str,"tos",3)) {
+      addr_modeP->mode=23; /* TopOfStack */
+      return (-1);
+    }
+  default:;
+  }
+  if (strl>4) {
+    if (str[strl-1]==')') {
+      if (str[strl-2]==')') {
+       if (!strncmp(&str[strl-5],"(fp",3)) {
+         mode=16; /* Memory Relative */
+       }
+       if (!strncmp(&str[strl-5],"(sp",3)) {
+         mode=17;
+       }
+       if (!strncmp(&str[strl-5],"(sb",3)) {
+         mode=18;
+       }
+       if (mode!=DEFAULT) {          /* memory relative */
+         addr_modeP->mode=mode;
+         j=strl-5; /* temp for end of disp[0] */
+         i=0;
+         do {
+           strl-=1;
+           if (str[strl]==')') i++;
+           if (str[strl]=='(') i--;
+         } while (strl>-1 && i!=0);
+         if (i!=0) {
+           as_warn("Invalid syntax in Memory Relative addressing mode");
+           return(0);
+         }
+         addr_modeP->disp[1]=str;
+         addr_modeP->disp[0]=str+strl+1;
+         str[j]='\000'; /* null terminate disp[0] */
+         str[strl]='\000'; /* null terminate disp[1] */
+         return (-1);
+       }
+      }
+      switch (str[strl-3]) {
+      case'r':case'R':
+        if (str[strl-2]>='0' && str[strl-2]<'8' && str[strl-4]=='(') {
+         addr_modeP->mode=str[strl-2]-'0'+8;
+         addr_modeP->disp[0]=str;
+         str[strl-4]=0;
+         return (-1); /* reg rel */
+       }
+      default:
+        if (!strncmp(&str[strl-4],"(fp",3)) {
+         mode=24;
+       }
+        if (!strncmp(&str[strl-4],"(sp",3)) {
+         mode=25;
+       }
+        if (!strncmp(&str[strl-4],"(sb",3)) {
+         mode=26;
+       }
+       if (!strncmp(&str[strl-4],"(pc",3)) {
+         mode=27;
+       }
+        if (mode!=DEFAULT) {
+         addr_modeP->mode=mode;
+         addr_modeP->disp[0]=str;
+         str[strl-4]='\0';
+         return (-1); /* memory space */
+       }
+      }
+    }
+     /* no trailing ')' do we have a ']' ? */
+    if (str[strl-1]==']') {
+      switch (str[strl-2]) {
+      case'b':mode=28;break;
+      case'w':mode=29;break;
+      case'd':mode=30;break;
+      case'q':mode=31;break;
+      default:;
+        as_warn("Invalid scaled-indexed mode, use (b,w,d,q)");
+        if (str[strl-3]!=':' || str[strl-6]!='[' ||
+           str[strl-5]=='r' || str[strl-4]<'0' || str[strl-4]>'7') {
+         as_warn("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}");
+       }
+      }  /* scaled index */
+      {
+       if (recursive_level>0) {
+         as_warn("Scaled-indexed addressing mode combined with scaled-index");
+         return(0);
+       }
+       addr_modeP->am_size+=1;         /* scaled index byte */
+       j=str[strl-4]-'0';              /* store temporary */
+       str[strl-6]='\000';             /* nullterminate for recursive call */
+       i=addr_mode(str,addr_modeP,1);
+       if (!i || addr_modeP->mode==20) {
+         as_warn("Invalid or illegal addressing mode combined with scaled-index");
+         return(0);
+       }
+       addr_modeP->scaled_mode=addr_modeP->mode; /* store the inferior mode */
+       addr_modeP->mode=mode;
+       addr_modeP->scaled_reg=j+1;
+       return (-1);
+      }
+    }
+  }
+  addr_modeP->mode = DEFAULT;  /* default to whatever */
+  addr_modeP->disp[0]=str;
+  return (-1);
+}
+\f
+/* ptr points at string
+   addr_modeP points at struct with result
+   This routine calls addr_mode to determine the general addr.mode of
+   the operand. When this is ready it parses the displacements for size
+   specifying suffixes and determines size of immediate mode via ns32k-opcode.
+   Also builds index bytes if needed.
+ */
+int get_addr_mode(ptr,addr_modeP)
+     char *ptr;
+     addr_modeS *addr_modeP;
+{
+  int tmp;
+  addr_mode(ptr,addr_modeP,0);
+  if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) {
+                              /* resolve ambigious operands, this shouldn't
+                                 be necessary if one uses standard NSC operand
+                                 syntax. But the sequent compiler doesn't!!!
+                                 This finds a proper addressinging mode if it
+                                 is implicitly stated. See ns32k-opcode.h */
+    (void)evaluate_expr(&exprP,ptr); /* this call takes time Sigh! */
+    if (addr_modeP->mode == DEFAULT) {
+      if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+       addr_modeP->mode=desc->default_model; /* we have a label */
+      } else {
+       addr_modeP->mode=desc->default_modec; /* we have a constant */
+      }
+    } else {
+      if (exprP.X_add_symbol || exprP.X_subtract_symbol) {
+       addr_modeP->scaled_mode=desc->default_model;
+      } else {
+       addr_modeP->scaled_mode=desc->default_modec;
+      }
+    }
+    /* must put this mess down in addr_mode to handle the scaled case better */
+  }
+  /* It appears as the sequent compiler wants an absolute when we have a
+     label without @. Constants becomes immediates besides the addr case.
+     Think it does so with local labels too, not optimum, pcrel is better.
+     When I have time I will make gas check this and select pcrel when possible
+     Actually that is trivial.
+     */
+  if (tmp=addr_modeP->scaled_reg) { /* build indexbyte */
+    tmp--; /* remember regnumber comes incremented for flagpurpose */
+    tmp|=addr_modeP->scaled_mode<<3;
+    addr_modeP->index_byte=(char)tmp;
+    addr_modeP->am_size+=1;
+  }
+  if (disp_test[addr_modeP->mode]) { /* there was a displacement, probe for length specifying suffix*/
+    {
+      register char c;
+      register char suffix;
+      register char suffix_sub;
+      register int i;
+      register char *toP;
+      register char *fromP;
+
+      addr_modeP->pcrel=0;
+      if (disp_test[addr_modeP->mode]) { /* there is a displacement */
+       if (addr_modeP->mode==27 || addr_modeP->scaled_mode==27) { /* do we have pcrel. mode */
+         addr_modeP->pcrel=1;
+       }
+       addr_modeP->im_disp=1;
+       for(i=0;i<2;i++) {
+         suffix_sub=suffix=0;
+         if (toP=addr_modeP->disp[i]) { /* suffix of expression, the largest size rules */
+           fromP=toP;
+           while (c = *fromP++) {
+             *toP++=c;
+             if (c==':') {
+               switch (*fromP) {
+               case '\0':
+                 as_warn("Premature end of suffix--Defaulting to d");
+                 suffix=4;
+                 continue;
+               case 'b':suffix_sub=1;break;
+               case 'w':suffix_sub=2;break;
+               case 'd':suffix_sub=4;break;
+               default:
+                 as_warn("Bad suffix after ':' use {b|w|d} Defaulting to d");
+                 suffix=4;
+               }
+               fromP++;
+               toP--; /* So we write over the ':' */
+               if (suffix<suffix_sub) suffix=suffix_sub;
+             }
+           }
+           *toP='\0'; /* terminate properly */
+           addr_modeP->disp_suffix[i]=suffix;
+           addr_modeP->am_size+=suffix ? suffix : 4;
+         }
+       }
+      }
+    }
+  } else {
+    if (addr_modeP->mode==20) { /* look in ns32k_opcode for size */
+      addr_modeP->disp_suffix[0]=addr_modeP->am_size=desc->im_size;
+      addr_modeP->im_disp=0;
+    }
+  }
+  return addr_modeP->mode;
+}
+
+
+/* read an optionlist */
+void optlist(str,optionP,default_map)
+     char *str;                         /* the string to extract options from */
+     struct option *optionP;    /* how to search the string */
+     unsigned long *default_map; /* default pattern and output */
+{
+  register int i,j,k,strlen1,strlen2;
+  register char *patternP,*strP;
+  strlen1=strlen(str);
+  if (strlen1<1) { 
+    as_fatal("Very short instr to option, ie you can't do it on a NULLstr");
+  }
+  for (i=0;optionP[i].pattern!=0;i++) {
+    strlen2=strlen(optionP[i].pattern);
+    for (j=0;j<strlen1;j++) {
+      patternP=optionP[i].pattern;
+      strP = &str[j];
+      for (k=0;k<strlen2;k++) {
+       if (*(strP++)!=*(patternP++)) break;
+      }
+      if (k==strlen2) { /* match */
+       *default_map|=optionP[i].or;
+       *default_map&=optionP[i].and;
+      }
+    }
+  }
+}
+/* search struct for symbols 
+   This function is used to get the short integer form of reg names
+   in the instructions lmr, smr, lpr, spr
+   return true if str is found in list */
+
+int list_search(str,optionP,default_map)
+     char *str;                         /* the string to match */
+     struct option *optionP;    /* list to search */
+     unsigned long *default_map; /* default pattern and output */
+{
+  register int i;
+  for (i=0;optionP[i].pattern!=0;i++) {
+    if (!strncmp(optionP[i].pattern,str,20)) { /* use strncmp to be safe */
+      *default_map|=optionP[i].or;
+      *default_map&=optionP[i].and;
+      return -1;
+    }
+  }
+  as_warn("No such entry in list. (cpu/mmu register)");
+  return 0;
+}
+static segT evaluate_expr(resultP,ptr)
+expressionS *resultP;
+char *ptr;
+{
+  register char *tmp_line;
+  register segT segment;
+  tmp_line=input_line_pointer;
+  input_line_pointer=ptr;
+  segment=expression(&exprP);
+  input_line_pointer=tmp_line;
+  return (segment);
+}
+\f
+/* Convert operands to iif-format and adds bitfields to the opcode.
+   Operands are parsed in such an order that the opcode is updated from
+   its most significant bit, that is when the operand need to alter the
+   opcode.
+   Be carefull not to put to objects in the same iif-slot.
+   */
+
+void encode_operand(argc,argv,operandsP,suffixP,im_size,opcode_bit_ptr)
+     int argc;
+     char **argv;
+     char *operandsP;
+     char *suffixP;
+     char im_size;
+     char opcode_bit_ptr;
+{
+  register int i,j;
+  int pcrel,tmp,b,loop,pcrel_adjust;
+  for(loop=0;loop<argc;loop++) {
+    i=operandsP[loop<<1]-'1'; /* what operand are we supposed to work on */
+    if (i>3) as_fatal("Internal consistency error.  check ns32k-opcode.h");
+    pcrel=0;
+    pcrel_adjust=0;
+    tmp=0;
+    switch (operandsP[(loop<<1)+1]) {
+    case 'f':  /* operand of sfsr turns out to be a nasty specialcase */
+      opcode_bit_ptr-=5;
+    case 'F':          /* 32 bit float general form */
+    case 'L':          /* 64 bit float */
+    case 'Q':          /* quad-word    */
+    case 'B':          /* byte  */
+    case 'W':          /* word  */
+    case 'D':          /* double-word  */
+    case 'A':          /* double-word  gen-address-form ie no regs allowed */
+      get_addr_mode(argv[i],&addr_modeP);
+      iif.instr_size+=addr_modeP.am_size;
+      if (opcode_bit_ptr==desc->opcode_size) b=4; else b=6;
+      for (j=b;j<(b+2);j++) { 
+       if (addr_modeP.disp[j-b]) { 
+         IIF(j,
+             2,
+             addr_modeP.disp_suffix[j-b],
+             (unsigned long)addr_modeP.disp[j-b],
+             0,
+             addr_modeP.pcrel,
+             iif.instr_size-addr_modeP.am_size, /* this aint used (now) */
+             addr_modeP.im_disp,
+             IND(BRANCH,BYTE),
+             NULL,
+             addr_modeP.scaled_reg ? addr_modeP.scaled_mode:addr_modeP.mode,
+             0);
+       }
+      }
+      opcode_bit_ptr-=5;
+      iif.iifP[1].object|=((long)addr_modeP.mode)<<opcode_bit_ptr;
+      if (addr_modeP.scaled_reg) { 
+       j=b/2;
+       IIF(j,1,1, (unsigned long)addr_modeP.index_byte,0,0,0,0,0, NULL,-1,0);
+      }
+      break;
+    case 'b':          /* multiple instruction disp */
+      freeptr++;       /* OVE:this is an useful hack */
+      tmp=(int)sprintf(freeptr,"((%s-1)*%d)\000",argv[i],desc->im_size);
+      argv[i]=freeptr;
+      freeptr=(char*)tmp;
+      pcrel-=1; /* make pcrel 0 inspite of what case 'p': wants */
+      /* fall thru */
+    case 'p':          /* displacement - pc relative addressing */
+      pcrel+=1;
+      /* fall thru */
+    case 'd':                                  /* displacement */
+      iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+      IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+         pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,0);
+      break;
+    case 'H': /* sequent-hack: the linker wants a bit set when bsr */
+      pcrel=1;
+      iif.instr_size+=suffixP[i] ? suffixP[i] : 4;
+      IIF(12, 2, suffixP[i], (unsigned long)argv[i], 0,
+         pcrel, pcrel_adjust, 1, IND(BRANCH,BYTE), NULL,-1,1);break;
+    case 'q':                                  /* quick */
+      opcode_bit_ptr-=4;
+      IIF(11,2,42,(unsigned long)argv[i],0,0,0,0,0,
+         bit_fix_new(4,opcode_bit_ptr,-8,7,0,1,0),-1,0);
+      break;
+    case 'r':                          /* register number (3 bits) */
+      list_search(argv[i],opt6,&tmp);
+      opcode_bit_ptr-=3;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'O':                          /* setcfg instruction optionslist */
+      optlist(argv[i],opt3,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;
+      break;
+    case 'C':                          /* cinv instruction optionslist */
+      optlist(argv[i],opt4,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;/*insert the regtype in opcode */
+      break;
+    case 'S':                          /* stringinstruction optionslist */
+      optlist(argv[i],opt5,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<15;
+      break;
+    case 'u':case 'U':                         /* registerlist */
+      IIF(10,1,1,0,0,0,0,0,0,NULL,-1,0);
+      switch (operandsP[(i<<1)+1]) {
+      case 'u':                                /* restore, exit */
+       optlist(argv[i],opt1,&iif.iifP[10].object);
+       break;
+      case 'U':                                        /* save,enter */
+       optlist(argv[i],opt2,&iif.iifP[10].object);
+       break;
+      }
+      iif.instr_size+=1;
+      break;
+    case 'M':                                  /* mmu register */
+      list_search(argv[i],mmureg,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'P':                                  /* cpu register  */
+      list_search(argv[i],cpureg,&tmp);
+      opcode_bit_ptr-=4;
+      iif.iifP[1].object|=tmp<<opcode_bit_ptr;
+      break;
+    case 'g': /* inss exts */
+      iif.instr_size+=1; /* 1 byte is allocated after the opcode */
+      IIF(10,2,1,
+         (unsigned long)argv[i], /* i always 2 here */
+         0,0,0,0,0,
+         bit_fix_new(3,5,0,7,0,0,0), /* a bit_fix is targeted to the byte */
+         -1,0);
+    case 'G':
+      IIF(11,2,42,
+         (unsigned long)argv[i], /* i always 3 here */
+         0,0,0,0,0,
+         bit_fix_new(5,0,1,32,-1,0,-1),-1,0);
+      break;
+    case 'i':
+      iif.instr_size+=1;
+      b=2+i;  /* put the extension byte after opcode */
+      IIF(b,2,1,0,0,0,0,0,0,0,-1,0);
+    default:
+      as_fatal("Bad opcode-table-option, check in file ns32k-opcode.h");
+    }
+  }
+}
+\f
+/* in:  instruction line
+   out: internal structure of instruction
+        that has been prepared for direct conversion to fragment(s) and
+       fixes in a systematical fashion
+       Return-value = recursive_level
+*/
+/* build iif of one assembly text line */
+int parse(line,recursive_level)
+     char *line;
+     int recursive_level;
+{
+  register char                        *lineptr,c,suffix_separator;
+  register int                 i;
+  int                          argc,arg_type;
+  char                         sqr,sep;
+  char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */
+  if (recursive_level<=0) { /* called from md_assemble */
+    for (lineptr=line;(*lineptr)!='\0' && (*lineptr)!=' ';lineptr++); 
+    c = *lineptr;
+    *lineptr='\0';
+    if (!(desc=(struct ns32k_opcode*)hash_find(inst_hash_handle,line))) {
+      as_fatal("No such opcode");
+    }
+    *lineptr=c;
+  } else {
+    lineptr=line;
+  }
+  argc=0;
+  if (*desc->operands) {
+    if (*lineptr++!='\0') {
+      sqr='[';
+      sep=',';
+      while (*lineptr!='\0') {
+       if (desc->operands[argc<<1]) {
+         suffix[argc]=0;
+         arg_type=desc->operands[(argc<<1)+1];
+         switch (arg_type) {
+         case 'd': case 'b': case 'p': case 'H':  /* the operand is supposed to be a displacement */
+           /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */
+           suffix_separator=':';
+           break;
+         default:
+           suffix_separator='\255'; /* if this char occurs we loose */
+         }
+         suffix[argc]=0; /* 0 when no ':' is encountered */
+         argv[argc]=freeptr;
+         *freeptr='\0';
+         while ((c = *lineptr)!='\0' && c!=sep) {
+           if (c==sqr) {
+             if (sqr=='[') {
+               sqr=']';sep='\0';
+             } else {
+               sqr='[';sep=',';
+             }
+           }
+           if (c==suffix_separator) { /* ':' - label/suffix separator */
+             switch (lineptr[1]) {
+             case 'b':suffix[argc]=1;break;
+             case 'w':suffix[argc]=2;break;
+             case 'd':suffix[argc]=4;break;
+             default: as_warn("Bad suffix, defaulting to d");
+               suffix[argc]=4;
+               if (lineptr[1]=='\0' || lineptr[1]==sep) {
+                 lineptr+=1;
+                 continue;
+               }
+             }
+             lineptr+=2;
+             continue;
+           }
+           *freeptr++=c;
+           lineptr++;
+         }
+         *freeptr++='\0';
+         argc+=1;
+         if (*lineptr=='\0') continue;
+         lineptr+=1;
+       } else {
+         as_fatal("Too many operands passed to instruction");
+       }
+      }
+    }
+  }
+  if (argc!=strlen(desc->operands)/2) {
+    if (strlen(desc->default_args)) { /* we can apply default, dont goof */
+      if (parse(desc->default_args,1)!=1) { /* check error in default */
+       as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h");
+      }
+    } else {
+      as_fatal("Wrong number of operands");
+    }
+
+  }
+  for (i=0;i<IIF_ENTRIES;i++) {
+    iif.iifP[i].type=0; /* mark all entries as void*/
+  }
+
+    /* build opcode iif-entry */
+  iif.instr_size=desc->opcode_size/8;
+  IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0);
+
+    /* this call encodes operands to iif format */
+  if (argc) {
+    encode_operand(argc,
+                  argv,
+                  &desc->operands[0],
+                  &suffix[0],
+                  desc->im_size,
+                  desc->opcode_size);
+  }
+  return recursive_level;
+}
+
+\f
+  /* Convert iif to fragments.
+     From this point we start to dribble with functions in other files than
+     this one.(Except hash.c) So, if it's possible to make an iif for an other
+     CPU, you don't need to know what frags, relax, obstacks, etc is in order
+     to port this assembler. You only need to know if it's possible to reduce
+     your cpu-instruction to iif-format (takes some work) and adopt the other
+     md_? parts according to given instructions
+     Note that iif was invented for the clean ns32k`s architecure.
+     */
+void convert_iif() {
+  register int                 i,j;
+  fragS                        *inst_frag;
+  char                         *inst_offset,*inst_opcode;
+  char                         *memP;
+  segT                         segment;
+  int                          l,k;
+  register int rem_size; /* count the remaining bytes of instruction */
+  register char type;
+  register char size = 0;
+  int  size_so_far=0; /* used to calculate pcrel_adjust */
+
+    rem_size=iif.instr_size;
+    memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */
+    inst_opcode=memP;
+    inst_offset=(char*)(memP-frag_now->fr_literal);
+    inst_frag=frag_now;
+    for (i=0;i<IIF_ENTRIES;i++) {
+      if (type=iif.iifP[i].type) {                     /* the object exist, so handle it */
+       switch (size=iif.iifP[i].size) {
+       case 42: size=0; /* it's a bitfix that operates on an existing object*/
+         if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */
+           iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode;
+         }
+       case 8: /* bignum or doublefloat */
+         bzero (memP,8);
+       case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */
+         j=(unsigned long)iif.iifP[i].bit_fixP;
+         switch (type) {
+         case 1:                               /* the object is pure binary */
+           if (j || iif.iifP[i].pcrel) {
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           0,
+                           0,
+                           iif.iifP[i].object,
+                           iif.iifP[i].pcrel,
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           iif.iifP[i].im_disp,
+                           j,
+                           iif.iifP[i].bsr); /* sequent hack */
+           } else {                    /* good, just put them bytes out */
+             switch (iif.iifP[i].im_disp) {
+             case 0:
+               md_number_to_chars(memP,iif.iifP[i].object,size);break;
+             case 1:
+               md_number_to_disp(memP,iif.iifP[i].object,size);break;
+             default: as_fatal("iif convert internal pcrel/binary");
+             }
+           }
+           memP+=size;
+           rem_size-=size;
+           break;
+         case 2:       /* the object is a pointer at an expression, so unpack
+                          it, note that bignums may result from the expression
+                        */
+           if ((segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object))==SEG_BIG || size==8) {
+             if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */
+               /* this can only happens in a long suffixed instruction */
+               bzero(memP,size); /* size normally is 8 */
+               if (k*2>size) as_warn("Bignum too big for long");
+               if (k==3) memP+=2;
+               for (l=0;k>0;k--,l+=2) {
+                 md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE));
+               }
+             } else { /* flonum */
+               LITTLENUM_TYPE words[4];
+
+               switch(size) {
+               case 4:
+                 gen_to_words(words,2,8);
+                 md_number_to_imm(memP                       ,(long)words[0],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE));
+                 break;
+               case 8:
+                 gen_to_words(words,4,11);
+                 md_number_to_imm(memP                         ,(long)words[0],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+sizeof(LITTLENUM_TYPE)  ,(long)words[1],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE));
+                 md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE));
+                 break;
+               }
+             }
+           memP+=size;
+           rem_size-=size;
+           break;
+           }
+           if (j ||
+               exprP.X_add_symbol ||
+               exprP.X_subtract_symbol ||
+               iif.iifP[i].pcrel) {            /* fixit */
+             /* the expression was undefined due to an undefined label */
+             /* create a fix so we can fix the object later */
+             exprP.X_add_number+=iif.iifP[i].object_adjust;
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           exprP.X_add_symbol,
+                           exprP.X_subtract_symbol,
+                           exprP.X_add_number,
+                           iif.iifP[i].pcrel,
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           iif.iifP[i].im_disp,
+                           j,
+                           iif.iifP[i].bsr); /* sequent hack */
+             
+           } else {                    /* good, just put them bytes out */
+             switch (iif.iifP[i].im_disp) {
+             case 0:
+               md_number_to_imm(memP,exprP.X_add_number,size);break;
+             case 1:
+               md_number_to_disp(memP,exprP.X_add_number,size);break;
+             default: as_fatal("iif convert internal pcrel/pointer");
+             }
+           }
+           memP+=size;
+           rem_size-=size;
+           break;
+         default: as_fatal("Internal logic error in iif.iifP[n].type");
+         }
+         break;
+       case 0:          /* To bad, the object may be undefined as far as its final
+                           nsize in object memory is concerned. The size of the object
+                           in objectmemory is not explicitly given.
+                           If the object is defined its length can be determined and
+                           a fix can replace the frag.
+                           */
+         {
+           int temp;
+           segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object);
+           if ((exprP.X_add_symbol || exprP.X_subtract_symbol) &&
+               !iif.iifP[i].pcrel) { /* OVE: hack, clamp to 4 bytes */
+             size=4; /* we dont wan't to frag this, use 4 so it reaches */
+             fix_new_ns32k(frag_now,
+                           (long)(memP-frag_now->fr_literal),
+                           size,
+                           exprP.X_add_symbol,
+                           exprP.X_subtract_symbol,
+                           exprP.X_add_number,
+                           0, /* never iif.iifP[i].pcrel, */
+                           (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/
+                           1, /* always iif.iifP[i].im_disp, */
+                           0,0);
+             memP+=size;
+             rem_size-=4;
+             break; /* exit this absolute hack */
+           }
+
+           if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */
+             if (exprP.X_subtract_symbol) { /* We cant relax this case */
+               as_fatal("Can't relax difference");
+             }
+             else {
+               /* at this stage we must undo some of the effect caused
+                  by frag_more, ie we must make sure that frag_var causes
+                  frag_new to creat a valid fix-size in the frag it`s closing
+                  */
+               temp = -(rem_size-4);
+               obstack_blank_fast(&frags,temp);
+                 /* we rewind none, some or all of the requested size we
+                    requested by the first frag_more for this iif chunk.
+                    Note: that we allocate 4 bytes to an object we NOT YET 
+                    know the size of, thus rem_size-4.
+                    */
+               (void)frag_variant(rs_machine_dependent,
+                                  4,
+                                  0,
+                                  IND(BRANCH,UNDEF), /* expecting the worst */
+                                  exprP.X_add_symbol,
+                                  exprP.X_add_number,
+                                  (char*)inst_opcode,
+                                  (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/
+                                  iif.iifP[i].bsr); /* sequent linker hack */
+               rem_size-=4;
+               if (rem_size>0) {
+                 memP=frag_more(rem_size);
+               }
+             }
+           }
+           else {/* Double work, this is done in md_number_to_disp */
+/*           exprP.X_add_number; what was this supposed to be?
+  xoxorich. */
+             if (-64<=exprP.X_add_number && exprP.X_add_number<=63) {
+               size=1;
+             } else {
+               if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) {
+                 size=2;
+               } else {
+                 if (-0x1f000000<=exprP.X_add_number &&
+                     exprP.X_add_number<=0x1fffffff)
+                 /* if (-0x40000000<=exprP.X_add_number &&
+                     exprP.X_add_number<=0x3fffffff) */
+                 {
+                   size=4;
+                 } else {
+                   as_warn("Displacement to large for :d");
+                   size=4;
+                 }
+               }
+             }
+             /* rewind the bytes not used */
+             temp = -(4-size);
+             md_number_to_disp(memP,exprP.X_add_number,size);
+             obstack_blank_fast(&frags,temp);
+             memP+=size;
+             rem_size-=4; /* we allocated this amount */
+           }
+         }
+         break;
+       default:
+         as_fatal("Internal logic error in iif.iifP[].type");
+       }
+       size_so_far+=size;
+       size=0;
+      }
+    }
+}
+\f
+void md_assemble(line)
+char *line;
+{
+  freeptr=freeptr_static;
+  parse(line,0); /* explode line to more fix form in iif */
+  convert_iif(); /* convert iif to frags, fix's etc */
+#ifdef SHOW_NUM
+  printf(" \t\t\t%s\n",line);
+#endif
+}
+
+
+void md_begin() {
+  /* build a hashtable of the instructions */
+  register const struct ns32k_opcode *ptr;
+  register char *stat;
+  inst_hash_handle=hash_new();
+  for (ptr=ns32k_opcodes;ptr<endop;ptr++) {
+    if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) {
+       as_fatal("Can't hash %s: %s", ptr->name,stat); /*fatal*/
+      exit(0);
+    }
+  }
+  freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */
+}
+
+
+void
+md_end() {
+  free(freeptr_static);
+}
+
+/* Must be equal to MAX_PRECISON in atof-ieee.c */
+#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':
+               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 * sizeof(LITTLENUM_TYPE);
+       for(wordP=words+prec;prec--;) {
+               md_number_to_chars(litP,(long)(*--wordP),sizeof(LITTLENUM_TYPE));
+               litP+=sizeof(LITTLENUM_TYPE);
+       }
+       return "";      /* Someone should teach Dean about null pointers */
+}
+\f
+/* Convert number to chars in correct order */
+
+void
+md_number_to_chars (buf, value, nbytes)
+     char      *buf;
+     long      value;
+     int       nbytes;
+{
+  while (nbytes--)
+    {
+#ifdef SHOW_NUM
+      printf("%x ",value & 0xff);
+#endif
+      *buf++ = value;          /* Lint wants & MASK_CHAR. */
+      value >>= BITS_PER_CHAR;
+    }
+}
+/* Convert number to chars in correct order */
+
+
+
+/* This is a variant of md_numbers_to_chars. The reason for its' existence
+   is the fact that ns32k uses Huffman coded displacements. This implies
+   that the bit order is reversed in displacements and that they are prefixed
+   with a size-tag.
+
+   binary: msb -> lsb  0xxxxxxx                                byte
+                       10xxxxxx xxxxxxxx                       word
+                       11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx     double word
+          
+   This must be taken care of and we do it here!                 
+ */
+static void md_number_to_disp(buf,val,n)
+     char      *buf;
+     long      val;
+     char       n;
+{ 
+  switch(n) {
+  case 1:
+    if (val < -64 || val > 63)
+      as_warn("Byte displacement out of range.  line number not valid");
+    val&=0x7f;
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 2:
+    if (val < -8192 || val > 8191)
+      as_warn("Word displacement out of range.  line number not valid");
+    val&=0x3fff;
+    val|=0x8000;
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 4:
+    if (val < -0x1f000000 || val >= 0x20000000)
+    /* if (val < -0x20000000 || val >= 0x20000000) */
+      as_warn("Double word displacement out of range");
+    val|=0xc0000000;
+#ifdef SHOW_NUM
+               printf("%x ",val>>24 & 0xff);
+#endif
+    *buf++=(val>>24);
+#ifdef SHOW_NUM
+               printf("%x ",val>>16 & 0xff);
+#endif
+    *buf++=(val>>16);
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  default:
+    as_fatal("Internal logic error.  line %s, file \"%s\"", __LINE__, __FILE__);
+  }
+}
+
+static void md_number_to_imm(buf,val,n)
+     char      *buf;
+     long      val;
+     char       n;
+{ 
+  switch(n) {
+  case 1:
+#ifdef SHOW_NUM
+    printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 2:
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  case 4:
+#ifdef SHOW_NUM
+               printf("%x ",val>>24 & 0xff);
+#endif
+    *buf++=(val>>24);
+#ifdef SHOW_NUM
+               printf("%x ",val>>16 & 0xff);
+#endif
+    *buf++=(val>>16);
+#ifdef SHOW_NUM
+               printf("%x ",val>>8 & 0xff);
+#endif
+    *buf++=(val>>8);
+#ifdef SHOW_NUM
+               printf("%x ",val & 0xff);
+#endif
+    *buf++=val;
+    break;
+  default:
+    as_fatal("Internal logic error. line %s, file \"%s\"", __LINE__, __FILE__);
+  }
+}
+
+/* Translate internal representation of relocation info into target format.
+
+   OVE: on a ns32k the twiddling continues at an even deeper level
+   here we have to distinguish between displacements and immediates.
+
+   The sequent has a bit for this. It also has a bit for relocobjects that
+   points at the target for a bsr (BranchSubRoutine) !?!?!?!
+
+   This md_ri.... is tailored for sequent.
+   */
+
+void
+md_ri_to_chars(the_bytes, ri)
+     char *the_bytes;
+     struct reloc_info_generic *ri;
+{      
+  if (ri->r_bsr) {ri->r_pcrel=0;} /* sequent seems to want this */
+  md_number_to_chars(the_bytes, ri->r_address, sizeof(ri->r_address));
+  md_number_to_chars(the_bytes+4,
+                    (long)(ri->r_symbolnum       ) |
+                    (long)(ri->r_pcrel     << 24 ) |
+                    (long)(ri->r_length           << 25 ) |
+                    (long)(ri->r_extern           << 27 ) |
+                    (long)(ri->r_bsr      << 28 ) |
+                    (long)(ri->r_disp     << 29 ),
+                    4);
+  /* the first and second md_number_to_chars never overlaps (32bit cpu case) */
+}
+\f
+/* fast bitfiddling support */
+/* mask used to zero bitfield before oring in the true field */
+
+static unsigned long l_mask[]={        0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+                               0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+                               0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+                               0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+                               0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+                               0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+                               0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+                               0xf0000000, 0xe0000000, 0xc0000000, 0x80000000,
+                               };
+static unsigned long r_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,
+                               };
+#define MASK_BITS 31
+/* Insert bitfield described by field_ptr and val at buf
+   This routine is written for modification of the first 4 bytes pointed
+   to by buf, to yield speed.
+   The ifdef stuff is for selection between a ns32k-dependent routine
+   and a general version. (My advice: use the general version!)
+ */
+
+static void
+md_number_to_field(buf,val,field_ptr)
+     register char     *buf;
+     register long     val;
+     register bit_fixS  *field_ptr;
+{ 
+  register unsigned long object;
+  register unsigned long mask;
+/* define ENDIAN on a ns32k machine */
+#ifdef ENDIAN
+  register unsigned long *mem_ptr;
+#else
+  register char *mem_ptr;
+#endif
+  if (field_ptr->fx_bit_min<=val && val<=field_ptr->fx_bit_max) {
+#ifdef ENDIAN
+    if (field_ptr->fx_bit_base) { /* override buf */
+      mem_ptr=(unsigned long*)field_ptr->fx_bit_base;
+    } else {
+      mem_ptr=(unsigned long*)buf;
+    }
+#else
+    if (field_ptr->fx_bit_base) { /* override buf */
+      mem_ptr=(char*)field_ptr->fx_bit_base;
+    } else {
+      mem_ptr=buf;
+    }
+#endif
+    mem_ptr+=field_ptr->fx_bit_base_adj;
+#ifdef ENDIAN  /* we have a nice ns32k machine with lowbyte at low-physical mem */
+    object = *mem_ptr; /* get some bytes */
+#else /* OVE Goof! the machine is a m68k or dito */
+      /* That takes more byte fiddling */
+    object=0;
+    object|=mem_ptr[3] & 0xff;
+    object<<=8;
+    object|=mem_ptr[2] & 0xff;
+    object<<=8;
+    object|=mem_ptr[1] & 0xff;
+    object<<=8;
+    object|=mem_ptr[0] & 0xff;
+#endif
+    mask=0;
+    mask|=(r_mask[field_ptr->fx_bit_offset]);
+    mask|=(l_mask[field_ptr->fx_bit_offset+field_ptr->fx_bit_size]);
+    object&=mask;
+    val+=field_ptr->fx_bit_add;
+    object|=((val<<field_ptr->fx_bit_offset) & (mask ^ 0xffffffff));
+#ifdef ENDIAN
+    *mem_ptr=object;
+#else
+    mem_ptr[0]=(char)object;
+    object>>=8;
+    mem_ptr[1]=(char)object;
+    object>>=8;
+    mem_ptr[2]=(char)object;
+    object>>=8;
+    mem_ptr[3]=(char)object;
+#endif
+  } else {
+    as_warn("Bit field out of range");
+  }
+}
+
+/* Apply a fixS (fixup of an instruction or data that we didn't have
+   enough info to complete immediately) to the data in a frag.
+
+   On the ns32k, everything is in a different format, so we have broken
+   out separate functions for each kind of thing we could be fixing.  
+   They all get called from here.  */
+
+void
+md_apply_fix(fixP, val)
+    fixS *fixP;
+    long val;
+{
+    char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+    if (fixP->fx_bit_fixP) {   /* Bitfields to fix, sigh */
+       md_number_to_field (buf, val, fixP->fx_bit_fixP);
+    } else switch (fixP->fx_im_disp) {
+
+    case 0:                    /* Immediate field */
+       md_number_to_imm (buf, val, fixP->fx_size);
+       break;
+
+    case 1:                    /* Displacement field */
+       md_number_to_disp (buf, 
+           fixP->fx_pcrel? val + fixP->fx_pcrel_adjust: val,
+           fixP->fx_size);
+       break;
+
+    case 2:                    /* Pointer in a data object */
+       md_number_to_chars (buf, val, fixP->fx_size);
+       break;
+    }
+}
+\f
+/* Convert a relaxed displacement to ditto in final output */
+
+void
+md_convert_frag(fragP)
+register fragS *fragP;
+{
+  long disp;
+  long ext;
+
+  /* Address in gas core of the place to store the displacement.  */
+  register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
+  /* Address in object code of the displacement.  */
+  register int object_address = fragP -> fr_fix + fragP -> fr_address;
+
+  know(fragP->fr_symbol);
+
+  /* The displacement of the address, from current location.  */
+  disp = (S_GET_VALUE(fragP->fr_symbol) + fragP->fr_offset) - object_address;
+  disp+= fragP->fr_pcrel_adjust;
+
+  switch(fragP->fr_subtype) {
+  case IND(BRANCH,BYTE):
+    ext=1;
+    break;
+  case IND(BRANCH,WORD):
+    ext=2;
+    break;
+  case IND(BRANCH,DOUBLE):
+    ext=4;
+    break;
+  }
+  if(ext) {
+    md_number_to_disp(buffer_address,(long)disp,(int)ext);
+    fragP->fr_fix+=ext;
+  }
+}
+
+
+
+/* This function returns the estimated size a variable object will occupy,
+   one can say that we tries to guess the size of the objects before we
+   actually know it */
+   
+int md_estimate_size_before_relax(fragP, segment)
+     register fragS *fragP;
+     segT segment;
+{
+  int  old_fix;
+  old_fix=fragP->fr_fix;
+  switch(fragP->fr_subtype) {
+  case IND(BRANCH,UNDEF):
+    if(S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+      /* the symbol has been assigned a value */
+      fragP->fr_subtype=IND(BRANCH,BYTE);
+    } else {
+      /* we don't relax symbols defined in an other segment
+         the thing to do is to assume the object will occupy 4 bytes */
+      fix_new_ns32k(fragP,
+                   (int)(fragP->fr_fix),
+                   4,
+                   fragP->fr_symbol,
+                   (symbolS *)0,
+                   fragP->fr_offset,
+                   1,
+                   fragP->fr_pcrel_adjust,
+                   1,
+                   0,
+                   fragP->fr_bsr); /*sequent hack */
+      fragP->fr_fix+=4;
+      /* fragP->fr_opcode[1]=0xff; */
+      frag_wane(fragP);
+      break;
+    }
+  case IND(BRANCH,BYTE):
+    fragP->fr_var+=1;
+    break;
+  default:
+    break;
+  }
+  return fragP->fr_var + fragP->fr_fix - old_fix;
+}
+
+int md_short_jump_size = 3;
+int md_long_jump_size  = 5;
+int md_reloc_size = 8;         /* Size of relocation record */
+
+void
+md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       offset = to_addr - from_addr;
+       md_number_to_chars(ptr, (long)0xEA  ,1);
+       md_number_to_disp(ptr+1,(long)offset,2);
+}
+
+void
+md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+char   *ptr;
+long   from_addr,
+       to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       long offset;
+
+       offset= to_addr - from_addr;
+       md_number_to_chars(ptr, (long)0xEA,  2);
+       md_number_to_disp(ptr+2,(long)offset,4);
+}
+\f
+/* JF this is a new function to parse machine-dep options */
+int
+md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+       switch(**argP) {
+       case 'm':
+         (*argP)++;
+
+         if(!strcmp(*argP,"32032")) {
+           cpureg = cpureg_032;
+           mmureg = mmureg_032;
+         } else if(!strcmp(*argP, "32532")) {
+           cpureg = cpureg_532;
+           mmureg = mmureg_532;
+         } else
+           as_warn("Unknown -m option ignored");
+
+         while(**argP)
+           (*argP)++;
+         break;
+
+       default:
+         return 0;
+       }
+       return 1;
+}
+\f
+/*
+ *                     bit_fix_new()
+ *
+ * Create a bit_fixS in obstack 'notes'.
+ * This struct is used to profile the normal fix. If the bit_fixP is a
+ * valid pointer (not NULL) the bit_fix data will be used to format the fix.
+ */
+bit_fixS *bit_fix_new (size,offset,min,max,add,base_type,base_adj)
+     char      size;           /* Length of bitfield           */
+     char      offset;         /* Bit offset to bitfield       */
+     long      base_type;      /* 0 or 1, if 1 it's exploded to opcode ptr */
+     long      base_adj;
+     long      min;            /* Signextended min for bitfield */
+     long      max;            /* Signextended max for bitfield */
+     long      add;            /* Add mask, used for huffman prefix */
+{
+  register bit_fixS *  bit_fixP;
+
+  bit_fixP = (bit_fixS *)obstack_alloc(&notes,sizeof(bit_fixS));
+
+  bit_fixP -> fx_bit_size      = size;
+  bit_fixP -> fx_bit_offset    = offset;
+  bit_fixP -> fx_bit_base      = base_type;
+  bit_fixP -> fx_bit_base_adj  = base_adj;
+  bit_fixP -> fx_bit_max       = max;
+  bit_fixP -> fx_bit_min       = min;
+  bit_fixP -> fx_bit_add       = add;
+
+  return bit_fixP;
+}
+
+void
+fix_new_ns32k (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+        pcrel_adjust, im_disp, bit_fixP, bsr)
+     fragS *   frag;           /* Which frag? */
+     int       where;          /* Where in that frag? */
+     short int size;           /* 1, 2  or 4 usually. */
+     symbolS * add_symbol;     /* X_add_symbol. */
+     symbolS * sub_symbol;     /* X_subtract_symbol. */
+     long      offset;         /* X_add_number. */
+     int       pcrel;          /* TRUE if PC-relative relocation. */
+     char      pcrel_adjust;   /* not zero if adjustment of pcrel offset is needed */
+     char      im_disp;        /* true if the value to write is a displacement */
+     bit_fixS *bit_fixP;       /* pointer at struct of bit_fix's, ignored if NULL */
+     char      bsr;            /* sequent-linker-hack: 1 when relocobject is a bsr */
+     
+{
+  register fixS *      fixP;
+
+  fixP = (fixS *)obstack_alloc(&notes,sizeof(fixS));
+  fixP -> fx_frag              = frag;
+  fixP -> fx_where             = where;
+  fixP -> fx_size              = size;
+  fixP -> fx_addsy             = add_symbol;
+  fixP -> fx_subsy             = sub_symbol;
+  fixP -> fx_offset            = offset;
+  fixP -> fx_pcrel             = pcrel;
+  fixP -> fx_pcrel_adjust      = pcrel_adjust;
+  fixP -> fx_im_disp           = im_disp;
+  fixP -> fx_bit_fixP          = bit_fixP;
+  fixP -> fx_bsr               = bsr;
+  fixP -> fx_next              = * seg_fix_rootP;
+
+  * seg_fix_rootP = fixP;
+}
+
+/* We have no need to default values of symbols.  */
+
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}
+
+/* Parse an operand that is machine-specific.  
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the National warts, they're relative to the address of the offset,
+   with some funny adjustments in some circumstances during blue moons.
+   (??? Is this right?  FIXME-SOON) */
+long
+md_pcrel_from (fixP)
+     fixS *fixP;
+{
+  long res;
+  res = fixP->fx_where + fixP->fx_frag->fr_address;
+#ifdef SEQUENT_COMPATABILITY
+  if (fixP->fx_frag->fr_bsr)
+    res += 0x12                /* FOO Kludge alert! */
+#endif
+  return res;
+}
+
+/*
+ * $Log$
+ * Revision 1.1  1991/04/04 18:17:05  rich
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * End:
+ */
+
+/* end of tc-ns32k.c */
diff --git a/gas/config/tc-ns32k.h b/gas/config/tc-ns32k.h
new file mode 100644 (file)
index 0000000..b96b650
--- /dev/null
@@ -0,0 +1,57 @@
+/* ns32k-opcode.h -- Opcode table for National Semi 32k processor
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef SEQUENT_COMPATABILITY
+#define DEF_MODEC 20
+#define DEF_MODEL 21
+#endif
+
+#ifndef DEF_MODEC
+#define DEF_MODEC 20
+#endif
+
+#ifndef DEF_MODEL
+#define DEF_MODEL 20
+#endif
+
+#define MAX_ARGS 4
+#define ARG_LEN 50
+
+#ifdef __STDC__
+
+void fix_new_ns32k(fragS *frag,
+                  int where,
+                  void *add_symbol, /* really symbolS */
+                  void *sub_symbol, /* really symbolS */
+                  long offset,
+                  int pcrel,
+                  int pcrel_adjust,
+                  int im_disp,
+                  void *bit_fixP, /* really bit_fixS */
+                  int bsr);
+
+#else /* __STDC__ */
+
+void fix_new_ns32k();
+
+#endif /* __STDC__ */
+
+
+/* end of tc-ns32k.h */
diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c
new file mode 100644 (file)
index 0000000..bd71fa8
--- /dev/null
@@ -0,0 +1,1297 @@
+/* tc-sparc.c -- Assemble for the SPARC
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "as.h"
+
+/* careful, this file includes data *declarations* */
+#include "sparc-opcode.h"
+
+void md_begin();
+void md_end();
+void md_number_to_chars();
+void md_assemble();
+char *md_atof();
+void md_convert_frag();
+void md_create_short_jump();
+void md_create_long_jump();
+int md_estimate_size_before_relax();
+void md_ri_to_chars();
+symbolS *md_undefined_symbol();
+static void sparc_ip();
+
+const relax_typeS md_relax_table[] = {
+       0 };
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+static void s_seg(), s_proc(), s_data1(), s_reserve(), s_common();
+extern void s_globl(), s_long(), s_short(), s_space(), cons();
+extern void s_align_bytes(), s_ignore();
+
+const pseudo_typeS md_pseudo_table[] = {
+       { "align",      s_align_bytes,  0       },    /* Defaulting is invalid (0) */
+       { "common",     s_common,       0       },
+       { "global",     s_globl,        0       },
+       { "half",       cons,           2       },
+       { "optim",      s_ignore,       0       },
+       { "proc",       s_proc,         0       },
+       { "reserve",    s_reserve,      0       },
+       { "seg",        s_seg,          0       },
+       { "skip",       s_space,        0       },
+       { "word",       cons,           4       },
+       { NULL, 0,              0       },
+};
+
+int md_short_jump_size = 4;
+int md_long_jump_size = 4;
+int md_reloc_size = 12;                        /* Size of relocation record */
+
+/* This array holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful */
+char comment_chars[] = "!";    /* JF removed '|' from comment_chars */
+
+/* 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 */
+char line_comment_chars[] = "#";
+
+/* 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";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+   */
+
+static unsigned char octal[256];
+#define isoctal(c)  octal[c]
+static unsigned char toHex[256];
+
+/*
+ *  anull bit - causes the branch delay slot instructions to not be executed
+ */
+#define ANNUL       (1 << 29)
+
+struct sparc_it {
+       char *error;
+       unsigned long opcode;
+       struct nlist *nlistp;
+       expressionS exp;
+       int pcrel;
+       enum reloc_type reloc;
+} the_insn, set_insn;
+
+#ifdef __STDC__
+#if 0
+static void print_insn(struct sparc_it *insn);
+#endif
+static int getExpression(char *str);
+#else
+#if 0
+static void print_insn();
+#endif
+static int getExpression();
+#endif
+static char *expr_end;
+static int special_case;
+
+/*
+ * Instructions that require wierd handling because they're longer than
+ * 4 bytes.
+ */
+#define        SPECIAL_CASE_SET        1
+#define        SPECIAL_CASE_FDIV       2
+
+/*
+ * sort of like s_lcomm
+ *
+ */
+static void s_reserve() {
+       char *name;
+       char c;
+       char *p;
+       int temp;
+       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;
+       }
+       input_line_pointer ++;
+       if ((temp = get_absolute_expression()) < 0) {
+               as_bad("BSS length (%d.) <0! Ignored.", temp);
+               ignore_rest_of_line();
+               return;
+       }
+       *p = 0;
+       symbolP = symbol_find_or_make(name);
+       *p = c;
+       if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0) {
+               as_bad("bad .reserve segment: `%s'", input_line_pointer);
+               return;
+       }
+       input_line_pointer += 6;
+       if (S_GET_OTHER(symbolP) == 0
+           && S_GET_DESC(symbolP) == 0
+           && ((S_GET_TYPE(symbolP) == N_BSS
+                && S_GET_VALUE(symbolP) == local_bss_counter)
+               || !S_IS_DEFINED(symbolP))) {
+               S_SET_VALUE(symbolP, local_bss_counter);
+               S_SET_SEGMENT(symbolP, SEG_BSS);
+               symbolP->sy_frag  = & bss_address_frag;
+               local_bss_counter += temp;
+       } else {
+               as_warn("Ignoring attempt to re-define symbol from %d. to %d.",
+                       S_GET_VALUE(symbolP), local_bss_counter);
+       }
+       demand_empty_rest_of_line();
+       return;
+} /* s_reserve() */
+
+static void s_common() {
+       register char *name;
+       register char c;
+       register char *p;
+       register int 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();
+       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;
+       }
+       *p = 0;
+       symbolP = symbol_find_or_make(name);
+       *p = c;
+       if (S_IS_DEFINED(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) != temp) {
+                       as_warn("Length of .comm \"%s\" is already %d. Not changed to %d.",
+                               S_GET_NAME(symbolP), S_GET_VALUE(symbolP), temp);
+               }
+       } else {
+               S_SET_VALUE(symbolP, temp);
+               S_SET_EXTERNAL(symbolP);
+       }
+       know(symbolP->sy_frag == &zero_address_frag);
+       if (strncmp(input_line_pointer, ",\"bss\"", 6) != 0
+           && strncmp(input_line_pointer, ",\"data\"", 7) != 0) {
+               p=input_line_pointer;
+               while(*p && *p!='\n')
+                   p++;
+               c= *p;
+               *p='\0';
+               as_bad("bad .common segment: `%s'", input_line_pointer);
+               *p=c;
+               return;
+       }
+       input_line_pointer += 6 + (input_line_pointer[2] == 'd'); /* Skip either */
+       demand_empty_rest_of_line();
+       return;
+} /* s_common() */
+
+static void s_seg() {
+       
+       if (strncmp(input_line_pointer, "\"text\"", 6) == 0) {
+               input_line_pointer += 6;
+               s_text();
+               return;
+       }
+       if (strncmp(input_line_pointer, "\"data\"", 6) == 0) {
+               input_line_pointer += 6;
+               s_data();
+               return;
+       }
+       if (strncmp(input_line_pointer, "\"data1\"", 7) == 0) {
+               input_line_pointer += 7;
+               s_data1();
+               return;
+       }
+       if (strncmp(input_line_pointer, "\"bss\"", 5) == 0) {
+               input_line_pointer += 5;
+               /* We only support 2 segments -- text and data -- for now, so
+                  things in the "bss segment" will have to go into data for now.
+                  You can still allocate SEG_BSS stuff with .lcomm or .reserve. */
+               subseg_new(SEG_DATA, 255);      /* FIXME-SOMEDAY */
+               return;
+       }
+       as_bad("Unknown segment type");
+       demand_empty_rest_of_line();
+       return;
+} /* s_seg() */
+
+static void s_data1() {
+       subseg_new(SEG_DATA, 1);
+       demand_empty_rest_of_line();
+       return;
+} /* s_data1() */
+
+static void s_proc() {
+       extern char is_end_of_line[];
+       
+       while (!is_end_of_line[*input_line_pointer]) {
+               ++input_line_pointer;
+       }
+       ++input_line_pointer;
+       return;
+} /* s_proc() */
+
+/* This function is called once, at assembler startup time.  It should
+   set up all the tables, etc. that the MD part of the assembler will need. */
+void md_begin() {
+       register char *retval = NULL;
+       int lose = 0;
+       register unsigned int i = 0;
+       
+       op_hash = hash_new();
+       if (op_hash == NULL)
+           as_fatal("Virtual memory exhausted");
+       
+       while (i < NUMOPCODES) {
+               const char *name = sparc_opcodes[i].name;
+               retval = hash_insert(op_hash, name, &sparc_opcodes[i]);
+               if(retval != NULL && *retval != '\0') {
+                       fprintf (stderr, "internal error: can't hash `%s': %s\n",
+                                sparc_opcodes[i].name, retval);
+                       lose = 1;
+               }
+               do
+                   {
+                           if (sparc_opcodes[i].match & sparc_opcodes[i].lose) {
+                                   fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
+                                            sparc_opcodes[i].name, sparc_opcodes[i].args);
+                                   lose = 1;
+                           }
+                           ++i;
+                   } while (i < NUMOPCODES
+                            && !strcmp(sparc_opcodes[i].name, name));
+       }
+       
+       if (lose)
+           as_fatal("Broken assembler.  No assembly attempted.");
+       
+       for (i = '0'; i < '8'; ++i)
+           octal[i] = 1;
+       for (i = '0'; i <= '9'; ++i)
+           toHex[i] = i - '0';
+       for (i = 'a'; i <= 'f'; ++i)
+           toHex[i] = i + 10 - 'a';
+       for (i = 'A'; i <= 'F'; ++i)
+           toHex[i] = i + 10 - 'A';
+} /* md_begin() */
+
+void md_end() {
+       return;
+} /* md_end() */
+
+void md_assemble(str)
+char *str;
+{
+       char *toP;
+       int rsd;
+       
+       know(str);
+       sparc_ip(str);
+       
+       /* See if "set" operand is absolute and small; skip sethi if so. */
+       if (special_case == SPECIAL_CASE_SET && the_insn.exp.X_seg == SEG_ABSOLUTE) {
+               if (the_insn.exp.X_add_number >= -(1<<12)
+                   && the_insn.exp.X_add_number <   (1<<12)) {
+                       the_insn.opcode = 0x80102000            /* or %g0,imm,... */
+                           | (the_insn.opcode & 0x3E000000)    /* dest reg */
+                               | (the_insn.exp.X_add_number & 0x1FFF); /* imm */
+                       special_case = 0;               /* No longer special */
+                       the_insn.reloc = NO_RELOC;      /* No longer relocated */
+               }
+       }
+       
+       toP = frag_more(4);
+       /* put out the opcode */
+       md_number_to_chars(toP, the_insn.opcode, 4);
+       
+       /* put out the symbol-dependent stuff */
+       if (the_insn.reloc != NO_RELOC) {
+               fix_new(frag_now,                           /* which frag */
+                       (toP - frag_now->fr_literal), /* where */
+                       4,                                  /* size */
+                       the_insn.exp.X_add_symbol,
+                       the_insn.exp.X_subtract_symbol,
+                       the_insn.exp.X_add_number,
+                       the_insn.pcrel,
+                       the_insn.reloc);
+       }
+       switch (special_case) {
+               
+       case SPECIAL_CASE_SET:
+               special_case = 0;
+               assert(the_insn.reloc == RELOC_HI22);
+               /* See if "set" operand has no low-order bits; skip OR if so. */
+               if (the_insn.exp.X_seg == SEG_ABSOLUTE
+                   && ((the_insn.exp.X_add_number & 0x3FF) == 0))
+                   return;
+               toP = frag_more(4);
+               rsd = (the_insn.opcode >> 25) & 0x1f;
+               the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
+               md_number_to_chars(toP, the_insn.opcode, 4);
+               fix_new(frag_now,                           /* which frag */
+                       (toP - frag_now->fr_literal),       /* where */
+                       4,                                  /* size */
+                       the_insn.exp.X_add_symbol,
+                       the_insn.exp.X_subtract_symbol,
+                       the_insn.exp.X_add_number,
+                       the_insn.pcrel,
+                       RELOC_LO10);
+               return;
+               
+       case SPECIAL_CASE_FDIV:
+               /* According to information leaked from Sun, the "fdiv" instructions
+                  on early SPARC machines would produce incorrect results sometimes.
+                  The workaround is to add an fmovs of the destination register to
+                  itself just after the instruction.  This was true on machines
+                  with Weitek 1165 float chips, such as the Sun-4/260 and /280. */
+               special_case = 0;
+               assert(the_insn.reloc == NO_RELOC);
+               toP = frag_more(4);
+               rsd = (the_insn.opcode >> 25) & 0x1f;
+               the_insn.opcode = 0x81A00020 | (rsd << 25) | rsd;  /* fmovs dest,dest */
+               md_number_to_chars(toP, the_insn.opcode, 4);
+               return;
+               
+       case 0:
+               return;
+               
+       default:
+               abort();
+       }
+} /* md_assemble() */
+
+static void sparc_ip(str)
+char *str;
+{
+       char *s;
+       const char *args;
+       char c;
+       struct sparc_opcode *insn;
+       char *argsStart;
+       unsigned long opcode;
+       unsigned int mask;
+       int match = 0;
+       int comma = 0;
+       
+       for (s = str; islower(*s) || (*s >= '0' && *s <= '3'); ++s)
+           ;
+       switch (*s) {
+               
+       case '\0':
+               break;
+               
+       case ',':
+               comma = 1;
+               
+               /*FALLTHROUGH */
+               
+       case ' ':
+               *s++ = '\0';
+               break;
+               
+       default:
+               as_bad("Unknown opcode: `%s'", str);
+               exit(1);
+       }
+       if ((insn = (struct sparc_opcode *) hash_find(op_hash, str)) == NULL) {
+               as_bad("Unknown opcode: `%s'", str);
+               return;
+       }
+       if (comma) {
+               *--s = ',';
+       }
+       argsStart = s;
+       for (;;) {
+               opcode = insn->match;
+               bzero(&the_insn, sizeof(the_insn));
+               the_insn.reloc = NO_RELOC;
+               
+               /*
+                * Build the opcode, checking as we go to make
+                * sure that the operands match
+                */
+               for (args = insn->args; ; ++args) {
+                       switch (*args) {
+                               
+                       case '\0':  /* end of args */
+                               if (*s == '\0') {
+                                       match = 1;
+                               }
+                               break;
+                               
+                       case '+':
+                               if (*s == '+') {
+                                       ++s;
+                                       continue;
+                               }
+                               if (*s == '-') {
+                                       continue;
+                               }
+                               break;
+                               
+                       case '[':   /* these must match exactly */
+                       case ']':
+                       case ',':
+                       case ' ':
+                               if (*s++ == *args)
+                                   continue;
+                               break;
+                               
+                       case '#':   /* must be at least one digit */
+                               if (isdigit(*s++)) {
+                                       while (isdigit(*s)) {
+                                               ++s;
+                                       }
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'C':   /* coprocessor state register */
+                               if (strncmp(s, "%csr", 4) == 0) {
+                                       s += 4;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'b':    /* next operand is a coprocessor register */
+                       case 'c':
+                       case 'D':
+                               if (*s++ == '%' && *s++ == 'c' && isdigit(*s)) {
+                                       mask = *s++;
+                                       if (isdigit(*s)) {
+                                               mask = 10 * (mask - '0') + (*s++ - '0');
+                                               if (mask >= 32) {
+                                                       break;
+                                               }
+                                       } else {
+                                               mask -= '0';
+                                       }
+                                       switch (*args) {
+                                               
+                                       case 'b':
+                                               opcode |= mask << 14;
+                                               continue;
+                                               
+                                       case 'c':
+                                               opcode |= mask;
+                                               continue;
+                                               
+                                       case 'D':
+                                               opcode |= mask << 25;
+                                               continue;
+                                       }
+                               }
+                               break;
+                               
+                       case 'r':   /* next operand must be a register */
+                       case '1':
+                       case '2':
+                       case 'd':
+                               if (*s++ == '%') {
+                                       switch (c = *s++) {
+                                               
+                                       case 'f':   /* frame pointer */
+                                               if (*s++ == 'p') {
+                                                       mask = 0x1e;
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 'g':   /* global register */
+                                               if (isoctal(c = *s++)) {
+                                                       mask = c - '0';
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 'i':   /* in register */
+                                               if (isoctal(c = *s++)) {
+                                                       mask = c - '0' + 24;
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 'l':   /* local register */
+                                               if (isoctal(c = *s++)) {
+                                                       mask= (c - '0' + 16) ;
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 'o':   /* out register */
+                                               if (isoctal(c = *s++)) {
+                                                       mask= (c - '0' + 8) ;
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 's':   /* stack pointer */
+                                               if (*s++ == 'p') {
+                                                       mask= 0xe;
+                                                       break;
+                                               }
+                                               goto error;
+                                               
+                                       case 'r': /* any register */
+                                               if (!isdigit(c = *s++)) {
+                                                       goto error;
+                                               }
+                                               /* FALLTHROUGH */
+                                       case '0': case '1': case '2': case '3': case '4':
+                                       case '5': case '6': case '7': case '8': case '9':
+                                               if (isdigit(*s)) {
+                                                       if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) {
+                                                               goto error;
+                                                       }
+                                               } else {
+                                                       c -= '0';
+                                               }
+                                               mask= c;
+                                               break;
+                                               
+                                       default:
+                                               goto error;
+                                       }
+                                       /*
+                                        * Got the register, now figure out where
+                                        * it goes in the opcode.
+                                        */
+                                       switch (*args) {
+                                               
+                                       case '1':
+                                               opcode |= mask << 14;
+                                               continue;
+                                               
+                                       case '2':
+                                               opcode |= mask;
+                                               continue;
+                                               
+                                       case 'd':
+                                               opcode |= mask << 25;
+                                               continue;
+                                               
+                                       case 'r':
+                                               opcode |= (mask << 25) | (mask << 14);
+                                               continue;
+                                       }
+                               }
+                               break;
+                               
+                       case 'e':    /* next operand is a floating point register */
+                       case 'f':
+                       case 'g':
+                               if (*s++ == '%' && *s++ == 'f' && isdigit(*s)) {
+                                       mask = *s++;
+                                       if (isdigit(*s)) {
+                                               mask = 10 * (mask - '0') + (*s++ - '0');
+                                               if (mask >= 32) {
+                                                       break;
+                                               }
+                                       } else {
+                                               mask -= '0';
+                                       }
+                                       switch (*args) {
+                                               
+                                       case 'e':
+                                               opcode |= mask << 14;
+                                               continue;
+                                               
+                                       case 'f':
+                                               opcode |= mask;
+                                               continue;
+                                               
+                                       case 'g':
+                                               opcode |= mask << 25;
+                                               continue;
+                                       }
+                               }
+                               break;
+                               
+                       case 'F':
+                               if (strncmp(s, "%fsr", 4) == 0) {
+                                       s += 4;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'h':       /* high 22 bits */
+                               the_insn.reloc = RELOC_HI22;
+                               goto immediate;
+                               
+                       case 'l':   /* 22 bit PC relative immediate */
+                               the_insn.reloc = RELOC_WDISP22;
+                               the_insn.pcrel = 1;
+                               goto immediate;
+                               
+                       case 'L':   /* 30 bit immediate */
+                               the_insn.reloc = RELOC_WDISP30;
+                               the_insn.pcrel = 1;
+                               goto immediate;
+                               
+                       case 'i':   /* 13 bit immediate */
+                               the_insn.reloc = RELOC_BASE13;
+                               
+                               /*FALLTHROUGH */
+                               
+                       immediate:
+                               if(*s==' ')
+                                   s++;
+                               if (*s == '%') {
+                                       if ((c = s[1]) == 'h' && s[2] == 'i') {
+                                               the_insn.reloc = RELOC_HI22;
+                                               s+=3;
+                                       } else if (c == 'l' && s[2] == 'o') {
+                                               the_insn.reloc = RELOC_LO10;
+                                               s+=3;
+                                       } else
+                                           break;
+                               }
+                               /* Note that if the getExpression() fails, we will still have
+                                  created U entries in the symbol table for the 'symbols'
+                                  in the input string.  Try not to create U symbols for
+                                  registers, etc. */
+                               {
+                                       /* This stuff checks to see if the expression ends
+                                          in +%reg If it does, it removes the register from
+                                          the expression, and re-sets 's' to point to the
+                                          right place */
+                                       
+                                       char *s1;
+                                       
+                                       for(s1=s;*s1 && *s1!=','&& *s1!=']';s1++)
+                                           ;
+                                       
+                                       if(s1!=s && isdigit(s1[-1])) {
+                                               if(s1[-2]=='%' && s1[-3]=='+') {
+                                                       s1-=3;
+                                                       *s1='\0';
+                                                       (void)getExpression(s);
+                                                       *s1='+';
+                                                       s=s1;
+                                                       continue;
+                                               } else if(strchr("goli0123456789",s1[-2]) && s1[-3]=='%' && s1[-4]=='+') {
+                                                       s1-=4;
+                                                       *s1='\0';
+                                                       (void)getExpression(s);
+                                                       *s1='+';
+                                                       s=s1;
+                                                       continue;
+                                               }
+                                       }
+                               }
+                               (void)getExpression(s);
+                               s = expr_end;
+                               continue;
+                               
+                       case 'a':
+                               if (*s++ == 'a') {
+                                       opcode |= ANNUL;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'A':       /* alternate space */
+                               if (isdigit(*s)) {
+                                       long num;
+                                       
+                                       num=0;
+                                       while (isdigit(*s)) {
+                                               num= num*10 + *s-'0';
+                                               ++s;
+                                       }
+                                       opcode |= num<<5;
+                                       continue;
+                               }
+                               break;
+                               /* abort(); */
+                               
+                       case 'p':
+                               if (strncmp(s, "%psr", 4) == 0) {
+                                       s += 4;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'q':   /* floating point queue */
+                               if (strncmp(s, "%fq", 3) == 0) {
+                                       s += 3;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'Q':   /* coprocessor queue */
+                               if (strncmp(s, "%cq", 3) == 0) {
+                                       s += 3;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 'S':
+                               if (strcmp(str, "set") == 0) {
+                                       special_case = SPECIAL_CASE_SET;
+                                       continue;
+                               } else if (strncmp(str, "fdiv", 4) == 0) {
+                                       special_case = SPECIAL_CASE_FDIV;
+                                       continue;
+                               }
+                               break;
+                               
+                       case 't':
+                               if (strncmp(s, "%tbr", 4) != 0)
+                                   break;
+                               s += 4;
+                               continue;
+                               
+                       case 'w':
+                               if (strncmp(s, "%wim", 4) != 0)
+                                   break;
+                               s += 4;
+                               continue;
+                               
+                       case 'y':
+                               if (strncmp(s, "%y", 2) != 0)
+                                   break;
+                               s += 2;
+                               continue;
+                               
+                       default:
+                               abort();
+                       }
+                       break;
+               }
+       error:
+               if (match == 0) {
+                       /* Args don't match. */
+                       if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES
+                           && !strcmp(insn->name, insn[1].name)) {
+                               ++insn;
+                               s = argsStart;
+                               continue;
+                       }
+                       else
+                           {
+                                   as_bad("Illegal operands");
+                                   return;
+                           }
+               }
+               break;
+       }
+       
+       the_insn.opcode = opcode;
+       return;
+} /* sparc_ip() */
+
+static int getExpression(str)
+char *str;
+{
+       char *save_in;
+       segT seg;
+       
+       save_in = input_line_pointer;
+       input_line_pointer = str;
+       switch (seg = expression(&the_insn.exp)) {
+               
+       case SEG_ABSOLUTE:
+       case SEG_TEXT:
+       case SEG_DATA:
+       case SEG_BSS:
+       case SEG_UNKNOWN:
+       case SEG_DIFFERENCE:
+       case SEG_BIG:
+       case SEG_ABSENT:
+               break;
+               
+       default:
+               the_insn.error = "bad segment";
+               expr_end = input_line_pointer;
+               input_line_pointer=save_in;
+               return 1;
+       }
+       expr_end = input_line_pointer;
+       input_line_pointer = save_in;
+       return 0;
+} /* getExpression() */
+
+
+/*
+  This is identical to the md_atof in m68k.c.  I think this is right,
+  but I'm not sure.
+  
+  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
+
+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 "";      /* Someone should teach Dean about null pointers */
+} /* md_atof() */
+
+/*
+ * Write out big-endian.
+ */
+void md_number_to_chars(buf,val,n)
+char *buf;
+long val;
+int n;
+{
+       
+       switch(n) {
+               
+       case 4:
+               *buf++ = val >> 24;
+               *buf++ = val >> 16;
+       case 2:
+               *buf++ = val >> 8;
+       case 1:
+               *buf = val;
+               break;
+               
+       default:
+               abort();
+       }
+       return;
+} /* md_number_to_chars() */
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+   hold. */
+
+void md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
+{
+       char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+       
+       assert(fixP->fx_size == 4);
+       assert(fixP->fx_r_type < NO_RELOC);
+       
+       fixP->fx_addnumber = val;       /* Remember value for emit_reloc */
+       
+       /*
+        * This is a hack.  There should be a better way to
+        * handle this.
+        */
+       if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) {
+               val += fixP->fx_where + fixP->fx_frag->fr_address;
+       }
+       
+       switch (fixP->fx_r_type) {
+               
+       case RELOC_32:
+               buf[0] = 0; /* val >> 24; */
+               buf[1] = 0; /* val >> 16; */
+               buf[2] = 0; /* val >> 8; */
+               buf[3] = 0; /* val; */
+               break;
+               
+#if 0
+       case RELOC_8:         /* These don't seem to ever be needed. */
+       case RELOC_16:
+       case RELOC_DISP8:
+       case RELOC_DISP16:
+       case RELOC_DISP32:
+#endif
+       case RELOC_WDISP30:
+               val = (val >>= 2) + 1;
+               buf[0] |= (val >> 24) & 0x3f;
+               buf[1]= (val >> 16);
+               buf[2] = val >> 8;
+               buf[3] = val;
+               break;
+               
+       case RELOC_HI22:
+               if(!fixP->fx_addsy) {
+                       buf[1] |= (val >> 26) & 0x3f;
+                       buf[2] = val >> 18;
+                       buf[3] = val >> 10;
+               } else {
+                       buf[2]=0;
+                       buf[3]=0;
+               }
+               break;
+#if 0
+       case RELOC_22:
+       case RELOC_13:
+#endif
+       case RELOC_LO10:
+               if(!fixP->fx_addsy) {
+                       buf[2] |= (val >> 8) & 0x03;
+                       buf[3] = val;
+               } else
+                   buf[3]=0;
+               break;
+#if 0
+       case RELOC_SFA_BASE:
+       case RELOC_SFA_OFF13:
+       case RELOC_BASE10:
+#endif
+       case RELOC_BASE13:
+               buf[2] |= (val >> 8) & 0x1f;
+               buf[3] = val;
+               break;
+               
+       case RELOC_WDISP22:
+               val = (val >>= 2) + 1;
+               /* FALLTHROUGH */
+       case RELOC_BASE22:
+               buf[1] |= (val >> 16) & 0x3f;
+               buf[2] = val >> 8;
+               buf[3] = val;
+               break;
+               
+#if 0
+       case RELOC_PC10:
+       case RELOC_PC22:
+       case RELOC_JMP_TBL:
+       case RELOC_SEGOFF16:
+       case RELOC_GLOB_DAT:
+       case RELOC_JMP_SLOT:
+       case RELOC_RELATIVE:
+#endif
+               
+       case NO_RELOC:
+       default:
+               as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
+               break;
+       }
+} /* md_apply_fix() */
+
+/* should never be called for sparc */
+void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr;
+long to_addr;
+fragS *frag;
+symbolS *to_symbol;
+{
+       fprintf(stderr, "sparc_create_short_jmp\n");
+       abort();
+} /* md_create_short_jump() */
+
+/* Translate internal representation of relocation info to target format.
+   
+   On sparc: first 4 bytes are normal unsigned long address, next three
+   bytes are index, most sig. byte first.  Byte 7 is broken up with
+   bit 7 as external, bits 6 & 5 unused, and the lower
+   five bits as relocation type.  Next 4 bytes are long addend. */
+/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */
+void md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
+{
+       /* this is easy */
+       md_number_to_chars(the_bytes, ri->r_address, 4);
+       /* now the fun stuff */
+       the_bytes[4] = (ri->r_index >> 16) & 0x0ff;
+       the_bytes[5] = (ri->r_index >> 8) & 0x0ff;
+       the_bytes[6] = ri->r_index & 0x0ff;
+       the_bytes[7] = ((ri->r_extern << 7)  & 0x80) | (0 & 0x60) | (ri->r_type & 0x1F);
+       /* Also easy */
+       md_number_to_chars(&the_bytes[8], ri->r_addend, 4);
+} /* md_ri_to_chars() */
+
+/* should never be called for sparc */
+void md_convert_frag(fragP)
+register fragS *fragP;
+{
+       fprintf(stderr, "sparc_convert_frag\n");
+       abort();
+} /* md_convert_frag() */
+
+/* should never be called for sparc */
+void md_create_long_jump(ptr, from_addr, to_addr, frag, to_symbol)
+char *ptr;
+long from_addr, to_addr;
+fragS  *frag;
+symbolS        *to_symbol;
+{
+       fprintf(stderr, "sparc_create_long_jump\n");
+       abort();
+} /* md_create_long_jump() */
+
+/* should never be called for sparc */
+int md_estimate_size_before_relax(fragP, segtype)
+fragS *fragP;
+segT segtype;
+{
+       fprintf(stderr, "sparc_estimate_size_before_relax\n");
+       abort();
+       return 0;
+} /* md_estimate_size_before_relax() */
+
+#if 0
+/* for debugging only */
+static void print_insn(insn)
+struct sparc_it *insn;
+{
+       char *Reloc[] = {
+               "RELOC_8",
+               "RELOC_16",
+               "RELOC_32",
+               "RELOC_DISP8",
+               "RELOC_DISP16",
+               "RELOC_DISP32",
+               "RELOC_WDISP30",
+               "RELOC_WDISP22",
+               "RELOC_HI22",
+               "RELOC_22",
+               "RELOC_13",
+               "RELOC_LO10",
+               "RELOC_SFA_BASE",
+               "RELOC_SFA_OFF13",
+               "RELOC_BASE10",
+               "RELOC_BASE13",
+               "RELOC_BASE22",
+               "RELOC_PC10",
+               "RELOC_PC22",
+               "RELOC_JMP_TBL",
+               "RELOC_SEGOFF16",
+               "RELOC_GLOB_DAT",
+               "RELOC_JMP_SLOT",
+               "RELOC_RELATIVE",
+               "NO_RELOC"
+           };
+       
+       if (insn->error) {
+               fprintf(stderr, "ERROR: %s\n");
+       }
+       fprintf(stderr, "opcode=0x%08x\n", insn->opcode);
+       fprintf(stderr, "reloc = %s\n", Reloc[insn->reloc]);
+       fprintf(stderr, "exp = {
+\n");
+       fprintf(stderr, "\t\tX_add_symbol = %s\n",
+               ((insn->exp.X_add_symbol != NULL)
+                ? ((S_GET_NAME(insn->exp.X_add_symbol) != NULL)
+                   ? S_GET_NAME(insn->exp.X_add_symbol)
+                   : "???")
+                : "0"));
+       fprintf(stderr, "\t\tX_sub_symbol = %s\n",
+               ((insn->exp.X_subtract_symbol != NULL)
+                ? (S_GET_NAME(insn->exp.X_subtract_symbol)
+                   ? S_GET_NAME(insn->exp.X_subtract_symbol)
+                   : "???")
+                : "0"));
+       fprintf(stderr, "\t\tX_add_number = %d\n",
+               insn->exp.X_add_number);
+       fprintf(stderr, "}\n");
+       return;
+} /* print_insn() */
+#endif
+
+/* Set the hook... */
+
+void emit_sparc_reloc();
+void (*md_emit_relocations)() = emit_sparc_reloc;
+
+/*
+ * Sparc/AM29K relocations are completely different, so it needs
+ * this machine dependent routine to emit them.
+ */
+#if defined(OBJ_AOUT) || defined(OBJ_BOUT)
+void emit_sparc_reloc(fixP, segment_address_in_file)
+register fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+       struct reloc_info_generic ri;
+       register symbolS *symbolP;
+       extern char *next_object_file_charP;
+       /*    long add_number; */
+       
+       bzero((char *) &ri, sizeof(ri));
+       for (; fixP; fixP = fixP->fx_next) {
+               
+               if (fixP->fx_r_type >= NO_RELOC) {
+                       fprintf(stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
+                       abort();
+               }
+               
+               if ((symbolP = fixP->fx_addsy) != NULL) {
+                       ri.r_address = fixP->fx_frag->fr_address +
+                           fixP->fx_where - segment_address_in_file;
+                       if ((S_GET_TYPE(symbolP)) == N_UNDF) {
+                               ri.r_extern = 1;
+                               ri.r_index = symbolP->sy_number;
+                       } else {
+                               ri.r_extern = 0;
+                               ri.r_index = S_GET_TYPE(symbolP);
+                       }
+                       if (symbolP && symbolP->sy_frag) {
+                               ri.r_addend = symbolP->sy_frag->fr_address;
+                       }
+                       ri.r_type = fixP->fx_r_type;
+                       if (fixP->fx_pcrel) {
+                               /*              ri.r_addend -= fixP->fx_where; */
+                               ri.r_addend -= ri.r_address;
+                       } else {
+                               ri.r_addend = fixP->fx_addnumber;
+                       }
+                       
+                       md_ri_to_chars(next_object_file_charP, &ri);
+                       next_object_file_charP += md_reloc_size;
+               }
+       }
+       return;
+} /* emit_sparc_reloc() */
+#endif /* aout or bout */
+
+int md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+       return 1;
+} /* md_parse_option() */
+
+/* We have no need to default values of symbols. */
+
+/* ARGSUSED */
+symbolS *md_undefined_symbol(name)
+char *name;
+{
+       return 0;
+} /* md_undefined_symbol() */
+
+/* Parse an operand that is machine-specific.
+   We just return without modifying the expression if we have nothing
+   to do. */
+
+/* ARGSUSED */
+void md_operand(expressionP)
+expressionS *expressionP;
+{
+} /* md_operand() */
+
+/* Round up a section size to the appropriate boundary. */
+long md_section_align (segment, size)
+segT segment;
+long size;
+{
+       return (size + 7) & ~7; /* Round all sects to multiple of 8 */
+} /* md_section_align() */
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the sparc, they're relative to the address of the offset, plus
+   its size.  This gets us to the following instruction.
+   (??? Is this right?  FIXME-SOON) */
+long md_pcrel_from(fixP)
+fixS *fixP;
+{
+       return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+} /* md_pcrel_from() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tp-sparc.c */
diff --git a/gas/config/tc-sparc.h b/gas/config/tc-sparc.h
new file mode 100644 (file)
index 0000000..dd19fdb
--- /dev/null
@@ -0,0 +1,42 @@
+/* tc-sparc.h - Macros and type defines for the sparc.
+   Copyright (C) 1989, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+#define TC_SPARC 1
+
+#ifdef OBJ_BOUT
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | BMAGIC)  /* Magic number for header */
+#else
+#ifdef OBJ_AOUT
+#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE ((0x103 << 16) | OMAGIC)  /* Magic number for header */
+#endif /* OBJ_AOUT */
+#endif /* OBJ_BOUT */
+
+#define tc_headers_hook(a)             ; /* don't need it. */
+#define tc_crawl_symbol_chain(a)       ; /* don't need it. */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tp-sparc.h */
diff --git a/gas/config/tc-vax.c b/gas/config/tc-vax.c
new file mode 100644 (file)
index 0000000..11095c6
--- /dev/null
@@ -0,0 +1,3337 @@
+/* vax.c - vax-specific -
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/* JF I moved almost all the vax specific stuff into this one file 'cuz RMS
+   seems to think its a good idea.  I hope I managed to get all the VAX-isms */
+
+
+#include "as.h"
+
+#include "read.h"
+#include "flonum.h"
+#include "vax-inst.h"
+#include "obstack.h"           /* For FRAG_APPEND_1_CHAR macro in "frags.h" */
+#include "frags.h"
+#include "expr.h"
+#include "symbols.h"
+
+/* These chars start a comment anywhere in a source file (except inside
+   another comment */
+const char comment_chars[] = "#";
+
+/* These chars only start a comment at the beginning of a line. */
+/* Note that for the VAX the are the same as comment_chars above. */
+const char line_comment_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 0f123.456 */
+/* or    0H1.234E-12 (see exp chars above) */
+const char FLT_CHARS[] = "dDfFgGhH";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c .  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.
+ */
+
+static expressionS             /* Hold details of an operand expression */
+ exp_of_operand[VIT_MAX_OPERANDS];
+
+static struct vit
+ v;                            /* A vax instruction after decoding. */
+
+LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];
+ /* Hold details of big operands. */
+FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];
+ /* Above is made to point into */
+ /* big_operand_bits by md_begin(). */
+\f
+/*
+ * For VAX, relative addresses of "just the right length" are easy.
+ * The branch displacement is always the last operand, even in
+ * synthetic instructions.
+ * For VAX, we encode the relax_substateTs (in e.g. fr_substate) as:
+ *
+ *                 4       3       2       1       0        bit number
+ *     ---/ /--+-------+-------+-------+-------+-------+
+ *             |     what state ?      |  how long ?   |
+ *     ---/ /--+-------+-------+-------+-------+-------+
+ *
+ * The "how long" bits are 00=byte, 01=word, 10=long.
+ * This is a Un*x convention.
+ * Not all lengths are legit for a given value of (what state).
+ * The "how long" refers merely to the displacement length.
+ * The address usually has some constant bytes in it as well.
+ *
+
+groups for VAX address relaxing.
+
+1.     "foo" pc-relative.
+       length of byte, word, long
+
+2a.    J<cond> where <cond> is a simple flag test.
+       length of byte, word, long.
+       VAX opcodes are:        (Hex)
+               bneq/bnequ      12
+               beql/beqlu      13
+               bgtr            14
+               bleq            15
+               bgeq            18
+               blss            19
+               bgtru           1a
+               blequ           1b
+               bvc             1c
+               bvs             1d
+               bgequ/bcc       1e
+               blssu/bcs       1f
+       Always, you complement 0th bit to reverse condition.
+       Always, 1-byte opcode, then 1-byte displacement.
+
+2b.    J<cond> where cond tests a memory bit.
+       length of byte, word, long.
+       Vax opcodes are:        (Hex)
+               bbs             e0
+               bbc             e1
+               bbss            e2
+               bbcs            e3
+               bbsc            e4
+               bbcc            e5
+               bbssi           e6
+               bbcci           e7
+       Always, you complement 0th bit to reverse condition.
+       Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement
+
+2c.    J<cond> where cond tests low-order memory bit
+       length of byte,word,long.
+       Vax opcodes are:        (Hex)
+               blbs            e8
+               blbc            e9
+       Always, you complement 0th bit to reverse condition.
+       Always, 1-byte opcode, longword-address, 1-byte displacement.
+
+3.     Jbs/Jbr.
+       length of byte,word,long.
+       Vax opcodes are:        (Hex)
+               bsbb            10
+               brb             11
+       These are like (2) but there is no condition to reverse.
+       Always, 1 byte opcode, then displacement/absolute.
+
+4a.    JacbX
+       length of word, long.
+       Vax opcodes are:        (Hex)
+               acbw            3d
+               acbf            4f
+               acbd            6f
+               abcb            9d
+               acbl            f1
+               acbg          4ffd
+               acbh          6ffd
+       Always, we cannot reverse the sense of the branch; we have a word
+       displacement.
+       The double-byte op-codes don't hurt: we never want to modify the
+       opcode, so we don't care how many bytes are between the opcode and
+       the operand.
+
+4b.    JXobXXX
+       length of long, long, byte.
+       Vax opcodes are:        (Hex)
+               aoblss          f2
+               aobleq          f3
+               sobgeq          f4
+               sobgtr          f5
+       Always, we cannot reverse the sense of the branch; we have a byte
+       displacement.
+
+The only time we need to modify the opcode is for class 2 instructions.
+After relax() we may complement the lowest order bit of such instruction
+to reverse sense of branch.
+
+For class 2 instructions, we store context of "where is the opcode literal".
+We can change an opcode's lowest order bit without breaking anything else.
+
+We sometimes store context in the operand literal. This way we can figure out
+after relax() what the original addressing mode was.
+*/
+\f
+ /* These displacements are relative to */
+ /* the start address of the displacement. */
+ /* The first letter is Byte, Word. */
+ /* 2nd letter is Forward, Backward. */
+#define BF (1+ 127)
+#define BB (1+-128)
+#define WF (2+ 32767)
+#define WB (2+-32768)
+ /* Dont need LF, LB because they always */
+ /* reach. [They are coded as 0.] */
+
+
+#define C(a,b) ENCODE_RELAX(a,b)
+ /* This macro has no side-effects. */
+#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
+
+const relax_typeS
+md_relax_table[] =
+{
+  {
+    1, 1, 0, 0
+  },                           /* error sentinel   0,0 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           0,1 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           0,2 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           0,3 */
+  {
+    BF + 1, BB + 1, 2, C (1, 1)
+  },                           /* B^"foo"          1,0 */
+  {
+    WF + 1, WB + 1, 3, C (1, 2)
+  },                           /* W^"foo"          1,1 */
+  {
+    0, 0, 5, 0
+  },                           /* L^"foo"          1,2 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           1,3 */
+  {
+    BF, BB, 1, C (2, 1)
+  },                           /* b<cond> B^"foo"  2,0 */
+  {
+    WF + 2, WB + 2, 4, C (2, 2)
+  },                           /* br.+? brw X      2,1 */
+  {
+    0, 0, 7, 0
+  },                           /* br.+? jmp X      2,2 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           2,3 */
+  {
+    BF, BB, 1, C (3, 1)
+  },                           /* brb B^foo        3,0 */
+  {
+    WF, WB, 2, C (3, 2)
+  },                           /* brw W^foo        3,1 */
+  {
+    0, 0, 5, 0
+  },                           /* Jmp L^foo        3,2 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           3,3 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           4,0 */
+  {
+    WF, WB, 2, C (4, 2)
+  },                           /* acb_ ^Wfoo       4,1 */
+  {
+    0, 0, 10, 0
+  },                           /* acb_,br,jmp L^foo4,2 */
+  {
+    1, 1, 0, 0
+  },                           /* unused           4,3 */
+  {
+    BF, BB, 1, C (5, 1)
+  },                           /* Xob___,,foo      5,0 */
+  {
+    WF + 4, WB + 4, 6, C (5, 2)
+  },                           /* Xob.+2,brb.+3,brw5,1 */
+  {
+    0, 0, 9, 0
+  },                           /* Xob.+2,brb.+6,jmp5,2 */
+};
+
+#undef C
+#undef BF
+#undef BB
+#undef WF
+#undef WB
+
+void float_cons ();
+
+const pseudo_typeS md_pseudo_table[] =
+{
+  {"dfloat", float_cons, 'd'},
+  {"ffloat", float_cons, 'f'},
+  {"gfloat", float_cons, 'g'},
+  {"hfloat", float_cons, 'h'},
+  {0}
+};
+
+#define STATE_PC_RELATIVE              (1)
+#define STATE_CONDITIONAL_BRANCH       (2)
+#define STATE_ALWAYS_BRANCH            (3)     /* includes BSB... */
+#define STATE_COMPLEX_BRANCH           (4)
+#define STATE_COMPLEX_HOP              (5)
+
+#define STATE_BYTE                     (0)
+#define STATE_WORD                     (1)
+#define STATE_LONG                     (2)
+#define STATE_UNDF                     (3)     /* Symbol undefined in pass1 */
+
+
+#define min(a, b)      ((a) < (b) ? (a) : (b))
+\f
+
+void
+md_begin ()
+{
+  char *vip_begin ();
+  char *errtxt;
+  FLONUM_TYPE *fP;
+  int i;
+
+  if (*(errtxt = vip_begin (TRUE, "$", "*", "`")))
+    {
+      as_fatal("VIP_BEGIN error:%s", errtxt);
+    }
+
+  for (i = 0, fP = float_operand;
+       fP < float_operand + VIT_MAX_OPERANDS;
+       i++, fP++)
+    {
+      fP->low = &big_operand_bits[i][0];
+      fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1];
+    }
+}
+
+void
+md_end ()
+{
+  vip_end ();
+}
+\f
+void                           /* Knows about order of bytes in address. */
+md_number_to_chars (con, value, nbytes)
+     char con[];               /* Return 'nbytes' of chars here. */
+     long value;               /* The value of the bits. */
+     int nbytes;               /* Number of bytes in the output. */
+{
+  int n;
+  long v;
+
+  n = nbytes;
+  v = value;
+  while (nbytes--)
+    {
+      *con++ = value;          /* Lint wants & MASK_CHAR. */
+      value >>= BITS_PER_CHAR;
+    }
+  /* XXX line number probably botched for this warning message. */
+  if (value != 0 && value != -1)
+    as_bad("Displacement (%ld) long for instruction field length (%d).", v, n);
+}
+
+/* Fix up some data or instructions after we find out the value of a symbol
+   that they reference.  */
+
+void                           /* Knows about order of bytes in address. */
+md_apply_fix(fixP, value)
+     fixS *fixP;               /* Fixup struct pointer */
+     long value;               /* The value of the bits. */
+{
+  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  int nbytes;          /* Number of bytes in the output. */
+
+  nbytes = fixP->fx_size;
+  while (nbytes--)
+    {
+      *buf++ = value;          /* Lint wants & MASK_CHAR. */
+      value >>= BITS_PER_CHAR;
+    }
+}
+
+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;
+}
+\f
+/* vax:md_assemble() emit frags for 1 instruction */
+
+void
+md_assemble (instruction_string)
+     char *instruction_string; /* A string: assemble 1 instruction. */
+{
+  char *p;
+  register struct vop *operandP;/* An operand. Scans all operands. */
+  char *save_input_line_pointer;
+  char c_save;                 /* What used to live after an expression. */
+  struct frag *fragP;          /* Fragment of code we just made. */
+  register int goofed;         /* TRUE: instruction_string bad for all passes. */
+  register struct vop *end_operandP;   /* -> slot just after last operand */
+  /* Limit of the for (each operand). */
+  register expressionS *expP;  /* -> expression values for this operand */
+
+  /* These refer to an instruction operand expression. */
+  segT to_seg;                 /* Target segment of the address.        */
+  register valueT this_add_number;
+  register struct symbol *this_add_symbol;     /* +ve (minuend) symbol. */
+  register struct symbol *this_subtract_symbol;        /* -ve(subtrahend) symbol. */
+
+  long opcode_as_number;       /* As a number. */
+  char *opcode_as_chars;       /* Least significant byte 1st. */
+  /* As an array of characters. */
+  char *opcode_low_byteP;      /* Least significant byte 1st */
+  struct details *detP;                /* The details of an ADxxx frag. */
+  int length;                  /* length (bytes) meant by vop_short. */
+  int at;                      /* 0, or 1 if '@' is in addressing mode. */
+  int nbytes;                  /* From vop_nbytes: vax_operand_width (in bytes) */
+  FLONUM_TYPE *floatP;
+  char *vip ();
+  LITTLENUM_TYPE literal_float[8];
+  /* Big enough for any floating point literal. */
+
+  if (*(p = vip (&v, instruction_string)))
+    {
+      as_fatal("vax_assemble\"%s\" in=\"%s\"", p, instruction_string);
+    }
+  /*
+   * Now we try to find as many as_warn()s as we can. If we do any as_warn()s
+   * then goofed=TRUE. Notice that we don't make any frags yet.
+   * Should goofed be TRUE, then this instruction will wedge in any pass,
+   * and we can safely flush it, without causing interpass symbol phase
+   * errors. That is, without changing label values in different passes.
+   */
+  if (goofed = (*v.vit_error))
+    {
+      as_warn ("Ignoring statement due to \"%s\"", v.vit_error);
+    }
+  /*
+   * We need to use expression() and friends, which require us to diddle
+   * input_line_pointer. So we save it and restore it later.
+   */
+  save_input_line_pointer = input_line_pointer;
+  for (operandP = v.vit_operand,
+       expP = exp_of_operand,
+       floatP = float_operand,
+       end_operandP = v.vit_operand + v.vit_operands;
+
+       operandP < end_operandP;
+
+       operandP++,
+       expP++,
+       floatP++
+    )                          /* for each operand */
+    {
+      if (*(operandP->vop_error))
+       {
+         as_warn ("Ignoring statement because \"%s\"", (operandP->vop_error));
+         goofed = TRUE;
+       }
+      else
+       {                       /* statement has no syntax goofs: lets sniff the expression */
+         int can_be_short;     /* TRUE if a bignum can be reduced to a short literal. */
+
+         input_line_pointer = operandP->vop_expr_begin;
+         c_save = operandP->vop_expr_end[1];
+         operandP->vop_expr_end[1] = '\0';
+         /* If to_seg == SEG_PASS1, expression() will have set need_pass_2 = TRUE. */
+         switch (to_seg = expression (expP))
+           {
+           case SEG_ABSENT:
+             /* for BSD4.2 compatibility, missing expression is absolute 0 */
+             to_seg = expP->X_seg = SEG_ABSOLUTE;
+             expP->X_add_number = 0;
+             /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol, X_add_symbol to any particular value. */
+             /* But, we will program defensively. Since this situation occurs */
+             /* rarely so it costs us little to do, and stops Dean */
+             /* worrying about the origin of random bits in expressionS's. */
+             expP->X_add_symbol = NULL;
+             expP->X_subtract_symbol = NULL;
+           case SEG_TEXT:
+           case SEG_DATA:
+           case SEG_BSS:
+           case SEG_ABSOLUTE:
+           case SEG_UNKNOWN:
+             break;
+
+           case SEG_DIFFERENCE:
+           case SEG_PASS1:
+             /*
+              * Major bug. We can't handle the case of a
+              * SEG_DIFFERENCE expression in a VIT_OPCODE_SYNTHETIC
+              * variable-length instruction.
+              * We don't have a frag type that is smart enough to
+              * relax a SEG_DIFFERENCE, and so we just force all
+              * SEG_DIFFERENCEs to behave like SEG_PASS1s.
+              * Clearly, if there is a demand we can invent a new or
+              * modified frag type and then coding up a frag for this
+              * case will be easy. SEG_DIFFERENCE was invented for the
+              * .words after a CASE opcode, and was never intended for
+              * instruction operands.
+              */
+             need_pass_2 = TRUE;
+             as_warn("Can't relocate expression");
+             break;
+
+           case SEG_BIG:
+             /* Preserve the bits. */
+             if (expP->X_add_number > 0)
+               {
+                 bignum_copy (generic_bignum, expP->X_add_number,
+                              floatP->low, SIZE_OF_LARGE_NUMBER);
+               }
+             else
+               {
+                 know (expP->X_add_number < 0);
+                 flonum_copy (&generic_floating_point_number,
+                              floatP);
+                 if (strchr ("s i", operandP->vop_short))
+                   {           /* Could possibly become S^# */
+                     flonum_gen2vax (-expP->X_add_number, floatP, literal_float);
+                     switch (-expP->X_add_number)
+                       {
+                       case 'f':
+                         can_be_short =
+                           (literal_float[0] & 0xFC0F) == 0x4000
+                           && literal_float[1] == 0;
+                         break;
+
+                       case 'd':
+                         can_be_short =
+                           (literal_float[0] & 0xFC0F) == 0x4000
+                           && literal_float[1] == 0
+                           && literal_float[2] == 0
+                           && literal_float[3] == 0;
+                         break;
+
+                       case 'g':
+                         can_be_short =
+                           (literal_float[0] & 0xFF81) == 0x4000
+                           && literal_float[1] == 0
+                           && literal_float[2] == 0
+                           && literal_float[3] == 0;
+                         break;
+
+                       case 'h':
+                         can_be_short =
+                           (literal_float[0] & 0xFFF8) == 0x4000
+                           && (literal_float[1] & 0xE000) == 0
+                           && literal_float[2] == 0
+                           && literal_float[3] == 0
+                           && literal_float[4] == 0
+                           && literal_float[5] == 0
+                           && literal_float[6] == 0
+                           && literal_float[7] == 0;
+                         break;
+
+                       default:
+                         BAD_CASE (-expP->X_add_number);
+                         break;
+                       }       /* switch (float type) */
+                   }           /* if (could want to become S^#...) */
+               }               /* bignum or flonum ? */
+
+             if (operandP->vop_short == 's'
+                 || operandP->vop_short == 'i'
+                 || (operandP->vop_short == ' '
+                     && operandP->vop_reg == 0xF
+                     && (operandP->vop_mode & 0xE) == 0x8))
+               {
+                 /* Saw a '#'. */
+                 if (operandP->vop_short == ' ')
+                   {           /* We must chose S^ or I^. */
+                     if (expP->X_add_number > 0)
+                       {       /* Bignum: Short literal impossible. */
+                         operandP->vop_short = 'i';
+                         operandP->vop_mode = 8;
+                         operandP->vop_reg = 0xF;      /* VAX PC. */
+                       }
+                     else
+                       {       /* Flonum: Try to do it. */
+                         if (can_be_short)
+                           {
+                             operandP->vop_short = 's';
+                             operandP->vop_mode = 0;
+                             operandP->vop_ndx = -1;
+                             operandP->vop_reg = -1;
+                             /* JF hope this is the right thing */
+                             expP->X_seg = SEG_ABSOLUTE;
+                           }
+                         else
+                           {
+                             operandP->vop_short = 'i';
+                             operandP->vop_mode = 8;
+                             operandP->vop_reg = 0xF;  /* VAX PC */
+                           }
+                       }       /* bignum or flonum ? */
+                   }           /*  if #, but no S^ or I^ seen. */
+                 /* No more ' ' case: either 's' or 'i'. */
+                 if (operandP->vop_short == 's')
+                   {
+                     /* Wants to be a short literal. */
+                     if (expP->X_add_number > 0)
+                       {
+                         as_warn ("Bignum not permitted in short literal. Immediate mode assumed.");
+                         operandP->vop_short = 'i';
+                         operandP->vop_mode = 8;
+                         operandP->vop_reg = 0xF;      /* VAX PC. */
+                       }
+                     else
+                       {
+                         if (!can_be_short)
+                           {
+                             as_warn ("Can't do flonum short literal: immediate mode used.");
+                             operandP->vop_short = 'i';
+                             operandP->vop_mode = 8;
+                             operandP->vop_reg = 0xF;  /* VAX PC. */
+                           }
+                         else
+                           {   /* Encode short literal now. */
+                             register int temp;
+
+                             switch (-expP->X_add_number)
+                               {
+                               case 'f':
+                               case 'd':
+                                 temp = literal_float[0] >> 4;
+                                 break;
+
+                               case 'g':
+                                 temp = literal_float[0] >> 1;
+                                 break;
+
+                               case 'h':
+                                 temp = ((literal_float[0] << 3) & 070)
+                                   | ((literal_float[1] >> 13) & 07);
+                                 break;
+
+                               default:
+                                 BAD_CASE (-expP->X_add_number);
+                                 break;
+                               }
+
+                             floatP->low[0] = temp & 077;
+                             floatP->low[1] = 0;
+                           }   /* if can be short literal float */
+                       }       /* flonum or bignum ? */
+                   }
+                 else
+                   {           /* I^# seen: set it up if float. */
+                     if (expP->X_add_number < 0)
+                       {
+                         bcopy (literal_float, floatP->low, sizeof (literal_float));
+                       }
+                   }           /* if S^# seen. */
+               }
+             else
+               {
+                 as_warn ("A bignum/flonum may not be a displacement: 0x%x used",
+                          expP->X_add_number = 0x80000000);
+                 /* Chosen so luser gets the most offset bits to patch later. */
+               }
+             expP->X_add_number = floatP->low[0]
+               | ((LITTLENUM_MASK & (floatP->low[1])) << LITTLENUM_NUMBER_OF_BITS);
+/*
+ * For the SEG_BIG case we have:
+ * If vop_short == 's' then a short floating literal is in the
+ *     lowest 6 bits of floatP -> low [0], which is
+ *     big_operand_bits [---] [0].
+ * If vop_short == 'i' then the appropriate number of elements
+ *     of big_operand_bits [---] [...] are set up with the correct
+ *     bits.
+ * Also, just in case width is byte word or long, we copy the lowest
+ * 32 bits of the number to X_add_number.
+ */
+             break;
+
+           default:
+             BAD_CASE (to_seg);
+             break;
+           }
+         if (input_line_pointer != operandP->vop_expr_end + 1)
+           {
+             as_warn ("Junk at end of expression \"%s\"", input_line_pointer);
+             goofed = TRUE;
+           }
+         operandP->vop_expr_end[1] = c_save;
+       }
+    }                          /* for(each operand) */
+  input_line_pointer = save_input_line_pointer;
+
+  if (!need_pass_2 && !goofed)
+    {
+      /* We saw no errors in any operands - try to make frag(s) */
+      int is_undefined;                /* True if operand expression's */
+      /* segment not known yet. */
+      int length_code;
+
+      /* Emit op-code. */
+      /* Remember where it is, in case we want to modify the op-code later. */
+      opcode_low_byteP = frag_more (v.vit_opcode_nbytes);
+      bcopy (v.vit_opcode, opcode_low_byteP, v.vit_opcode_nbytes);
+      opcode_as_number = md_chars_to_number (opcode_as_chars = v.vit_opcode, 4);
+      for (operandP = v.vit_operand,
+          expP = exp_of_operand,
+          floatP = float_operand,
+          end_operandP = v.vit_operand + v.vit_operands;
+
+          operandP < end_operandP;
+
+          operandP++,
+          floatP++,
+          expP++
+       )                       /* for each operand */
+       {
+         if (operandP->vop_ndx >= 0)
+           {
+             /* indexed addressing byte */
+             /* Legality of indexed mode already checked: it is OK */
+             FRAG_APPEND_1_CHAR (0x40 + operandP->vop_ndx);
+           }                   /* if(vop_ndx>=0) */
+
+         /* Here to make main operand frag(s). */
+         this_add_number = expP->X_add_number;
+         this_add_symbol = expP->X_add_symbol;
+         this_subtract_symbol = expP->X_subtract_symbol;
+         to_seg = expP->X_seg;
+         is_undefined = (to_seg == SEG_UNKNOWN);
+         know (to_seg == SEG_UNKNOWN
+               ||to_seg == SEG_ABSOLUTE
+               ||to_seg == SEG_DATA
+               ||to_seg == SEG_TEXT
+               ||to_seg == SEG_BSS
+               ||to_seg == SEG_BIG
+           );
+         at = operandP->vop_mode & 1;
+         length = operandP->vop_short == 'b' ? 1 : operandP->vop_short == 'w' ? 2 : operandP->vop_short == 'l' ? 4 : 0;
+         nbytes = operandP->vop_nbytes;
+         if (operandP->vop_access == 'b')
+           {
+             if (to_seg == now_seg || is_undefined)
+               {               /* If is_undefined, then it might BECOME now_seg. */
+                 if (nbytes)
+                   {
+                     p = frag_more (nbytes);
+                     fix_new (frag_now, p - frag_now->fr_literal, nbytes,
+                              this_add_symbol, 0, this_add_number, 1);
+                   }
+                 else
+                   {           /* to_seg==now_seg || to_seg == SEG_UNKNOWN */
+                     /* nbytes==0 */
+                     length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
+                     if (opcode_as_number & VIT_OPCODE_SPECIAL)
+                       {
+                         if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
+                           {
+                             /* br or jsb */
+                             frag_var (rs_machine_dependent, 5, 1,
+                                       ENCODE_RELAX (STATE_ALWAYS_BRANCH, length_code),
+                                       this_add_symbol, this_add_number,
+                                       opcode_low_byteP);
+                           }
+                         else
+                           {
+                             if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
+                               {
+                                 length_code = STATE_WORD;     /* JF: There is no state_byte for this one! */
+                                 frag_var (rs_machine_dependent, 10, 2,
+                                           ENCODE_RELAX (STATE_COMPLEX_BRANCH, length_code),
+                                           this_add_symbol, this_add_number,
+                                           opcode_low_byteP);
+                               }
+                             else
+                               {
+                                 know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+                                 frag_var (rs_machine_dependent, 9, 1,
+                                           ENCODE_RELAX (STATE_COMPLEX_HOP, length_code),
+                                           this_add_symbol, this_add_number,
+                                           opcode_low_byteP);
+                               }
+                           }
+                       }
+                     else
+                       {
+                         know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
+                         frag_var (rs_machine_dependent, 7, 1,
+                                   ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
+                                   this_add_symbol, this_add_number,
+                                   opcode_low_byteP);
+                       }
+                   }
+               }
+             else
+               {               /* to_seg != now_seg && to_seg != SEG_UNKNOWN */
+/*
+ * --- SEG FLOAT MAY APPEAR HERE ----
+ */
+                 if (to_seg == SEG_ABSOLUTE)
+                   {
+                     if (nbytes)
+                       {
+                         know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
+                         p = frag_more (nbytes);
+                         /* Conventional relocation. */
+                         fix_new (frag_now, p - frag_now->fr_literal,
+                               nbytes, &abs_symbol, 0, this_add_number, 1);
+                       }
+                     else
+                       {
+                         know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
+                         if (opcode_as_number & VIT_OPCODE_SPECIAL)
+                           {
+                             if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
+                               {
+                                 /* br or jsb */
+                                 *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
+                                 know (opcode_as_chars[1] == 0);
+                                 p = frag_more (5);
+                                 p[0] = VAX_ABSOLUTE_MODE;     /* @#... */
+                                 md_number_to_chars (p + 1, this_add_number, 4);
+                                 /* Now (eg) JMP @#foo or JSB @#foo. */
+                               }
+                             else
+                               {
+                                 if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
+                                   {
+                                     p = frag_more (10);
+                                     p[0] = 2;
+                                     p[1] = 0;
+                                     p[2] = VAX_BRB;
+                                     p[3] = 6;
+                                     p[4] = VAX_JMP;
+                                     p[5] = VAX_ABSOLUTE_MODE; /* @#... */
+                                     md_number_to_chars (p + 6, this_add_number, 4);
+                                     /*
+                                      * Now (eg)       ACBx    1f
+                                      *                BRB     2f
+                                      *        1:      JMP     @#foo
+                                      *        2:
+                                      */
+                                   }
+                                 else
+                                   {
+                                     know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+                                     p = frag_more (9);
+                                     p[0] = 2;
+                                     p[1] = VAX_BRB;
+                                     p[2] = 6;
+                                     p[3] = VAX_JMP;
+                                     p[4] = VAX_PC_RELATIVE_MODE + 1;  /* @#... */
+                                     md_number_to_chars (p + 5, this_add_number, 4);
+                                     /*
+                                      * Now (eg)       xOBxxx  1f
+                                      *                BRB     2f
+                                      *        1:      JMP     @#foo
+                                      *        2:
+                                      */
+                                   }
+                               }
+                           }
+                         else
+                           {
+                             /* b<cond> */
+                             *opcode_low_byteP ^= 1;   /* To reverse the condition in a VAX branch, complement the lowest order bit. */
+                             p = frag_more (7);
+                             p[0] = 6;
+                             p[1] = VAX_JMP;
+                             p[2] = VAX_ABSOLUTE_MODE; /* @#... */
+                             md_number_to_chars (p + 3, this_add_number, 4);
+                             /*
+                              * Now (eg)       BLEQ    1f
+                              *                JMP     @#foo
+                              *        1:
+                              */
+                           }
+                       }
+                   }
+                 else
+                   {           /* to_seg != now_seg && to_seg != SEG_UNKNOWN && to_Seg != SEG_ABSOLUTE */
+                     if (nbytes > 0)
+                       {
+                         /* Pc-relative. Conventional relocation. */
+                         know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
+                         p = frag_more (nbytes);
+                         fix_new (frag_now, p - frag_now->fr_literal,
+                               nbytes, &abs_symbol, 0, this_add_number, 1);
+                       }
+                     else
+                       {
+                         know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
+                         if (opcode_as_number & VIT_OPCODE_SPECIAL)
+                           {
+                             if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
+                               {
+                                 /* br or jsb */
+                                 know (opcode_as_chars[1] == 0);
+                                 *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
+                                 p = frag_more (5);
+                                 p[0] = VAX_PC_RELATIVE_MODE;
+                                 fix_new (frag_now,
+                                          p + 1 - frag_now->fr_literal, 4,
+                                          this_add_symbol, 0,
+                                          this_add_number, 1);
+                                 /* Now eg JMP foo or JSB foo. */
+                               }
+                             else
+                               {
+                                 if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
+                                   {
+                                     p = frag_more (10);
+                                     p[0] = 0;
+                                     p[1] = 2;
+                                     p[2] = VAX_BRB;
+                                     p[3] = 6;
+                                     p[4] = VAX_JMP;
+                                     p[5] = VAX_PC_RELATIVE_MODE;
+                                     fix_new (frag_now,
+                                           p + 6 - frag_now->fr_literal, 4,
+                                              this_add_symbol, 0,
+                                              this_add_number, 1);
+                                     /*
+                                      * Now (eg)       ACBx    1f
+                                      *                BRB     2f
+                                      *        1:      JMP     foo
+                                      *        2:
+                                      */
+                                   }
+                                 else
+                                   {
+                                     know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
+                                     p = frag_more (10);
+                                     p[0] = 2;
+                                     p[1] = VAX_BRB;
+                                     p[2] = 6;
+                                     p[3] = VAX_JMP;
+                                     p[4] = VAX_PC_RELATIVE_MODE;
+                                     fix_new (frag_now,
+                                              p + 5 - frag_now->fr_literal,
+                                              4, this_add_symbol, 0,
+                                              this_add_number, 1);
+                                     /*
+                                      * Now (eg)       xOBxxx  1f
+                                      *                BRB     2f
+                                      *        1:      JMP     foo
+                                      *        2:
+                                      */
+                                   }
+                               }
+                           }
+                         else
+                           {
+                             know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
+                             *opcode_low_byteP ^= 1;   /* Reverse branch condition. */
+                             p = frag_more (7);
+                             p[0] = 6;
+                             p[1] = VAX_JMP;
+                             p[2] = VAX_PC_RELATIVE_MODE;
+                             fix_new (frag_now, p + 3 - frag_now->fr_literal,
+                                      4, this_add_symbol, 0,
+                                      this_add_number, 1);
+                           }
+                       }
+                   }
+               }
+           }
+         else
+           {
+             know (operandP->vop_access != 'b');       /* So it is ordinary operand. */
+             know (operandP->vop_access != ' ');       /* ' ' target-independent: elsewhere. */
+             know (operandP->vop_access == 'a' || operandP->vop_access == 'm' || operandP->vop_access == 'r' || operandP->vop_access == 'v' || operandP->vop_access == 'w');
+             if (operandP->vop_short == 's')
+               {
+                 if (to_seg == SEG_ABSOLUTE)
+                   {
+                     if (this_add_number < 0 || this_add_number >= 64)
+                       {
+                         as_warn ("Short literal overflow(%d.), immediate mode assumed.", this_add_number);
+                         operandP->vop_short = 'i';
+                         operandP->vop_mode = 8;
+                         operandP->vop_reg = 0xF;
+                       }
+                   }
+                 else
+                   {
+                     as_warn ("Forced short literal to immediate mode. now_seg=%s to_seg=%s", segment_name(now_seg), segment_name(to_seg));
+                     operandP->vop_short = 'i';
+                     operandP->vop_mode = 8;
+                     operandP->vop_reg = 0xF;
+                   }
+               }
+             if (operandP->vop_reg >= 0 && (operandP->vop_mode < 8 || (operandP->vop_reg != 0xF && operandP->vop_mode < 10)))
+               {               /* One byte operand. */
+                 know (operandP->vop_mode > 3);
+                 FRAG_APPEND_1_CHAR (operandP->vop_mode << 4 | operandP->vop_reg);
+                 /* All 1-bytes except S^# happen here. */
+               }
+             else
+               {               /* {@}{q^}foo{(Rn)} or S^#foo */
+                 if (operandP->vop_reg == -1 && operandP->vop_short != 's')
+                   {           /* "{@}{q^}foo" */
+                     if (to_seg == now_seg)
+                       {
+                         if (length == 0)
+                           {
+                             know (operandP->vop_short == ' ');
+                             p = frag_var (rs_machine_dependent, 10, 2,
+                              ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE),
+                                           this_add_symbol, this_add_number,
+                                           opcode_low_byteP);
+                             know (operandP->vop_mode == 10 + at);
+                             *p = at << 4;
+                             /* At is the only context we need to carry to */
+                             /* other side of relax() process. */
+                             /* Must be in the correct bit position of VAX */
+                             /* operand spec. byte. */
+                           }
+                         else
+                           {
+                             know (length);
+                             know (operandP->vop_short != ' ');
+                             p = frag_more (length + 1);
+                             /* JF is this array stuff really going to work? */
+                             p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
+                             fix_new (frag_now, p + 1 - frag_now->fr_literal,
+                                      length, this_add_symbol, 0,
+                                      this_add_number, 1);
+                           }
+                       }
+                     else
+                       {       /* to_seg != now_seg */
+                         if (this_add_symbol == NULL)
+                           {
+                             know (to_seg == SEG_ABSOLUTE);
+                             /* Do @#foo: simpler relocation than foo-.(pc) anyway. */
+                             p = frag_more (5);
+                             p[0] = VAX_ABSOLUTE_MODE; /* @#... */
+                             md_number_to_chars (p + 1, this_add_number, 4);
+                             if (length && length != 4)
+                               {
+                                 as_warn ("Length specification ignored. Address mode 9F used");
+                               }
+                           }
+                         else
+                           {
+                             /* {@}{q^}other_seg */
+                             know ((length == 0 && operandP->vop_short == ' ')
+                                 ||(length > 0 && operandP->vop_short != ' '));
+                             if (is_undefined)
+                               {
+                                 /*
+                                  * We have a SEG_UNKNOWN symbol. It might
+                                  * turn out to be in the same segment as
+                                  * the instruction, permitting relaxation.
+                                  */
+                                 p = frag_var (rs_machine_dependent, 5, 2,
+                                               ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF),
+                                          this_add_symbol, this_add_number,
+                                               0);
+                                 p[0] = at << 4;
+                               }
+                             else
+                               {
+                                 if (length == 0)
+                                   {
+                                     know (operandP->vop_short == ' ');
+                                     length = 4;       /* Longest possible. */
+                                   }
+                                 p = frag_more (length + 1);
+                                 p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
+                                 md_number_to_chars (p + 1, this_add_number, length);
+                                 fix_new (frag_now,
+                                          p + 1 - frag_now->fr_literal,
+                                          length, this_add_symbol, 0,
+                                          this_add_number, 1);
+                               }
+                           }
+                       }
+                   }
+                 else
+                   {           /* {@}{q^}foo(Rn) or S^# or I^# or # */
+                     if (operandP->vop_mode < 0xA)
+                       {       /* # or S^# or I^# */
+                         /* know(   (length == 0 && operandP->vop_short == ' ')
+                              || (length >  0 && operandP->vop_short != ' ')); */
+                         if (length == 0
+                             && to_seg == SEG_ABSOLUTE
+                             && operandP->vop_mode == 8        /* No '@'. */
+                             && this_add_number < 64
+                             && this_add_number >= 0)
+                           {
+                             operandP->vop_short = 's';
+                           }
+                         if (operandP->vop_short == 's')
+                           {
+                             FRAG_APPEND_1_CHAR (this_add_number);
+                           }
+                         else
+                           {   /* I^#... */
+                             know (nbytes);
+                             p = frag_more (nbytes + 1);
+                             know (operandP->vop_reg == 0xF);
+                             p[0] = (operandP->vop_mode << 4) | 0xF;
+                             if (to_seg == SEG_ABSOLUTE)
+                               {
+/*
+ * If nbytes > 4, then we are scrod. We don't know if the
+ * high order bytes are to be 0xFF or 0x00.
+ * BSD4.2 & RMS say use 0x00. OK --- but this
+ * assembler needs ANOTHER rewrite to
+ * cope properly with this bug.
+ */
+                                 md_number_to_chars (p + 1, this_add_number, min (4, nbytes));
+                                 if (nbytes > 4)
+                                   {
+                                     bzero (p + 5, nbytes - 4);
+                                   }
+                               }
+                             else
+                               {
+                                 if (to_seg == SEG_BIG)
+                                   {
+/*
+ * Problem here is to get the bytes in the right order.
+ * We stored our constant as LITTLENUMs, not bytes.
+ */
+                                     LITTLENUM_TYPE *lP;
+
+                                     lP = floatP->low;
+                                     if (nbytes & 1)
+                                       {
+                                         know (nbytes == 1);
+                                         p[1] = *lP;
+                                       }
+                                     else
+                                       {
+                                         for (p++; nbytes; nbytes -= 2, p += 2, lP++)
+                                           {
+                                             md_number_to_chars (p, *lP, 2);
+                                           }
+                                       }
+                                   }
+                                 else
+                                   {
+                                     fix_new (frag_now, p + 1 - frag_now->fr_literal,
+                                              nbytes, this_add_symbol, 0,
+                                              this_add_number, 0);
+                                   }
+                               }
+                           }
+                       }
+                     else
+                       {       /* {@}{q^}foo(Rn) */
+                         know ((length == 0 && operandP->vop_short == ' ')
+                             ||(length > 0 && operandP->vop_short != ' '));
+                         if (length == 0)
+                           {
+                             if (to_seg == SEG_ABSOLUTE)
+                               {
+                                 register long test;
+
+                                 test = this_add_number;
+
+                                 if (test < 0)
+                                   test = ~test;
+
+                                 length = test & 0xffff8000 ? 4
+                                   : test & 0xffffff80 ? 2
+                                   : 1;
+                               }
+                             else
+                               {
+                                 length = 4;
+                               }
+                           }
+                         p = frag_more (1 + length);
+                         know (operandP->vop_reg >= 0);
+                         p[0] = operandP->vop_reg
+                           | ((at | "?\12\14?\16"[length]) << 4);
+                         if (to_seg == SEG_ABSOLUTE)
+                           {
+                             md_number_to_chars (p + 1, this_add_number, length);
+                           }
+                         else
+                           {
+                             fix_new (frag_now, p + 1 - frag_now->fr_literal,
+                                      length, this_add_symbol, 0,
+                                      this_add_number, 0);
+                           }
+                       }
+                   }
+               }               /* if(single-byte-operand) */
+           }
+       }                       /* for(operandP) */
+    }                          /* if(!need_pass_2&&!goofed) */
+}                              /* vax_assemble() */
+\f
+/*
+ *                     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 char *p;
+  register int old_fr_fix;
+
+  old_fr_fix = fragP->fr_fix;
+  switch (fragP->fr_subtype)
+    {
+    case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
+      if (S_GET_SEGMENT(fragP->fr_symbol) == segment)
+       {                       /* A relaxable case. */
+         fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
+       }
+      else
+       {
+         p = fragP->fr_literal + old_fr_fix;
+         p[0] |= VAX_PC_RELATIVE_MODE; /* Preserve @ bit. */
+         fragP->fr_fix += 1 + 4;
+         fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+                  fragP->fr_offset, 1);
+         frag_wane (fragP);
+       }
+      break;
+
+    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
+      if (S_GET_SEGMENT(fragP->fr_symbol) == segment)
+       {
+         fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+       }
+      else
+       {
+         p = fragP->fr_literal + old_fr_fix;
+         *fragP->fr_opcode ^= 1;       /* Reverse sense of branch. */
+         p[0] = 6;
+         p[1] = VAX_JMP;
+         p[2] = VAX_PC_RELATIVE_MODE;  /* ...(PC) */
+         fragP->fr_fix += 1 + 1 + 1 + 4;
+         fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0,
+                  fragP->fr_offset, 1);
+         frag_wane (fragP);
+       }
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_UNDF):
+      if (S_GET_SEGMENT(fragP->fr_symbol) == segment)
+       {
+         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
+       }
+      else
+       {
+         p = fragP->fr_literal + old_fr_fix;
+         p[0] = 2;
+         p[1] = 0;
+         p[2] = VAX_BRB;
+         p[3] = 6;
+         p[4] = VAX_JMP;
+         p[5] = VAX_PC_RELATIVE_MODE;  /* ...(pc) */
+         fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
+         fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0,
+                  fragP->fr_offset, 1);
+         frag_wane (fragP);
+       }
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_UNDF):
+      if (S_GET_SEGMENT(fragP->fr_symbol) == segment)
+       {
+         fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
+       }
+      else
+       {
+         p = fragP->fr_literal + old_fr_fix;
+         p[0] = 2;
+         p[1] = VAX_BRB;
+         p[2] = 6;
+         p[3] = VAX_JMP;
+         p[4] = VAX_PC_RELATIVE_MODE;  /* ...(pc) */
+         fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
+         fix_new (fragP, old_fr_fix + 5, 4, fragP->fr_symbol, 0,
+                  fragP->fr_offset, 1);
+         frag_wane (fragP);
+       }
+      break;
+
+    case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
+      if (S_GET_SEGMENT(fragP->fr_symbol) == segment)
+       {
+         fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
+       }
+      else
+       {
+         p = fragP->fr_literal + old_fr_fix;
+         *fragP->fr_opcode += VAX_WIDEN_LONG;
+         p[0] = VAX_PC_RELATIVE_MODE;  /* ...(PC) */
+         fragP->fr_fix += 1 + 4;
+         fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
+                  fragP->fr_offset, 1);
+         frag_wane (fragP);
+       }
+      break;
+
+    default:
+      break;
+    }
+  return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
+}                              /* md_estimate_size_before_relax() */
+\f
+/*
+ *                     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".
+ */
+void
+md_convert_frag (fragP)
+     register fragS *fragP;
+{
+  register char *addressP;     /* -> _var to change. */
+  register char *opcodeP;      /* -> opcode char(s) to change. */
+  register short int length_code;      /* 2=long 1=word 0=byte */
+  register short int extension;        /* Size of relaxed address. */
+  /* Added to fr_fix: incl. ALL var chars. */
+  register symbolS *symbolP;
+  register long where;
+  register long address_of_var;
+  /* Where, in file space, is _var of *fragP? */
+  register long target_address;
+  /* Where, in file space, does addr point? */
+
+  know (fragP->fr_type == rs_machine_dependent);
+  length_code = fragP->fr_subtype & 3; /* depends on ENCODE_RELAX() */
+  know (length_code >= 0 && length_code < 3);
+  where = fragP->fr_fix;
+  addressP = fragP->fr_literal + where;
+  opcodeP = fragP->fr_opcode;
+  symbolP = fragP->fr_symbol;
+  know (symbolP);
+  target_address = symbolP->sy_value + fragP->fr_offset;
+  address_of_var = fragP->fr_address + where;
+  switch (fragP->fr_subtype)
+    {
+    case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
+      know (*addressP == 0 || *addressP == 0x10);      /* '@' bit. */
+      addressP[0] |= 0xAF;     /* Byte displacement. */
+      addressP[1] = target_address - (address_of_var + 2);
+      extension = 2;
+      break;
+
+    case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
+      know (*addressP == 0 || *addressP == 0x10);      /* '@' bit. */
+      addressP[0] |= 0xCF;     /* Word displacement. */
+      md_number_to_chars (addressP + 1, target_address - (address_of_var + 3), 2);
+      extension = 3;
+      break;
+
+    case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
+      know (*addressP == 0 || *addressP == 0x10);      /* '@' bit. */
+      addressP[0] |= 0xEF;     /* Long word displacement. */
+      md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
+      extension = 5;
+      break;
+
+    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+      addressP[0] = target_address - (address_of_var + 1);
+      extension = 1;
+      break;
+
+    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
+      opcodeP[0] ^= 1;         /* Reverse sense of test. */
+      addressP[0] = 3;
+      addressP[1] = VAX_BRB + VAX_WIDEN_WORD;
+      md_number_to_chars (addressP + 2, target_address - (address_of_var + 4), 2);
+      extension = 4;
+      break;
+
+    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
+      opcodeP[0] ^= 1;         /* Reverse sense of test. */
+      addressP[0] = 6;
+      addressP[1] = VAX_JMP;
+      addressP[2] = VAX_PC_RELATIVE_MODE;
+      md_number_to_chars (addressP + 3, target_address, 4);
+      extension = 7;
+      break;
+
+    case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
+      addressP[0] = target_address - (address_of_var + 1);
+      extension = 1;
+      break;
+
+    case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
+      opcodeP[0] += VAX_WIDEN_WORD;    /* brb -> brw, bsbb -> bsbw */
+      md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+      extension = 2;
+      break;
+
+    case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
+      opcodeP[0] += VAX_WIDEN_LONG;    /* brb -> jmp, bsbb -> jsb */
+      addressP[0] = VAX_PC_RELATIVE_MODE;
+      md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
+      extension = 5;
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD):
+      md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
+      extension = 2;
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_LONG):
+      addressP[0] = 2;
+      addressP[1] = 0;
+      addressP[2] = VAX_BRB;
+      addressP[3] = 6;
+      addressP[4] = VAX_JMP;
+      addressP[5] = VAX_PC_RELATIVE_MODE;
+      md_number_to_chars (addressP + 6, target_address, 4);
+      extension = 10;
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE):
+      addressP[0] = target_address - (address_of_var + 1);
+      extension = 1;
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_WORD):
+      addressP[0] = 2;
+      addressP[1] = VAX_BRB;
+      addressP[2] = 3;
+      addressP[3] = VAX_BRW;
+      md_number_to_chars (addressP + 4, target_address - (address_of_var + 6), 2);
+      extension = 6;
+      break;
+
+    case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_LONG):
+      addressP[0] = 2;
+      addressP[1] = VAX_BRB;
+      addressP[2] = 6;
+      addressP[3] = VAX_JMP;
+      addressP[4] = VAX_PC_RELATIVE_MODE;
+      md_number_to_chars (addressP + 5, target_address, 4);
+      extension = 9;
+      break;
+
+    default:
+      BAD_CASE (fragP->fr_subtype);
+      break;
+    }
+  fragP->fr_fix += extension;
+}
+
+/* Translate internal format of relocation info into target format.
+
+   On vax: first 4 bytes are normal unsigned long, next three bytes
+   are symbolnum, least sig. byte first.  Last byte is broken up with
+   the upper nibble as nuthin, bit 3 as extern, bits 2 & 1 as length, and
+   bit 0 as pcrel. */
+void 
+md_ri_to_chars (the_bytes, ri)
+     char *the_bytes;
+     struct reloc_info_generic ri;
+{
+  /* this is easy */
+  md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address));
+  /* now the fun stuff */
+  the_bytes[6] = (ri.r_symbolnum >> 16) & 0x0ff;
+  the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
+  the_bytes[4] = ri.r_symbolnum & 0x0ff;
+  the_bytes[7] = (((ri.r_extern << 3) & 0x08) | ((ri.r_length << 1) & 0x06) |
+                 ((ri.r_pcrel << 0) & 0x01)) & 0x0F;
+}
+\f
+/*
+ *       BUGS, GRIPES,  APOLOGIA, etc.
+ *
+ * The opcode table 'votstrs' needs to be sorted on opcode frequency.
+ * That is, AFTER we hash it with hash_...(), we want most-used opcodes
+ * to come out of the hash table faster.
+ *
+ * I am sorry to inflict
+ * yet another VAX assembler on the world, but RMS says we must
+ * do everything from scratch, to prevent pin-heads restricting
+ * this software.
+ */
+
+/*
+ * This is a vaguely modular set of routines in C to parse VAX
+ * assembly code using DEC mnemonics. It is NOT un*x specific.
+ *
+ * The idea here is that the assembler has taken care of all:
+ *   labels
+ *   macros
+ *   listing
+ *   pseudo-ops
+ *   line continuation
+ *   comments
+ *   condensing any whitespace down to exactly one space
+ * and all we have to do is parse 1 line into a vax instruction
+ * partially formed. We will accept a line, and deliver:
+ *   an error message (hopefully empty)
+ *   a skeleton VAX instruction (tree structure)
+ *   textual pointers to all the operand expressions
+ *   a warning message that notes a silly operand (hopefully empty)
+ */
+\f
+/*
+ *             E D I T   H I S T O R Y
+ *
+ * 17may86 Dean Elsner. Bug if line ends immediately after opcode.
+ * 30apr86 Dean Elsner. New vip_op() uses arg block so change call.
+ *  6jan86 Dean Elsner. Crock vip_begin() to call vip_op_defaults().
+ *  2jan86 Dean Elsner. Invent synthetic opcodes.
+ *     Widen vax_opcodeT to 32 bits. Use a bit for VIT_OPCODE_SYNTHETIC,
+ *     which means this is not a real opcode, it is like a macro; it will
+ *     be relax()ed into 1 or more instructions.
+ *     Use another bit for VIT_OPCODE_SPECIAL if the op-code is not optimised
+ *     like a regular branch instruction. Option added to vip_begin():
+ *     exclude synthetic opcodes. Invent synthetic_votstrs[].
+ * 31dec85 Dean Elsner. Invent vit_opcode_nbytes.
+ *     Also make vit_opcode into a char[]. We now have n-byte vax opcodes,
+ *     so caller's don't have to know the difference between a 1-byte & a
+ *     2-byte op-code. Still need vax_opcodeT concept, so we know how
+ *     big an object must be to hold an op.code.
+ * 30dec85 Dean Elsner. Widen typedef vax_opcodeT in "vax-inst.h"
+ *     because vax opcodes may be 16 bits. Our crufty C compiler was
+ *     happily initialising 8-bit vot_codes with 16-bit numbers!
+ *     (Wouldn't the 'phone company like to compress data so easily!)
+ * 29dec85 Dean Elsner. New static table vax_operand_width_size[].
+ *     Invented so we know hw many bytes a "I^#42" needs in its immediate
+ *     operand. Revised struct vop in "vax-inst.h": explicitly include
+ *     byte length of each operand, and it's letter-code datum type.
+ * 17nov85 Dean Elsner. Name Change.
+ *     Due to ar(1) truncating names, we learned the hard way that
+ *     "vax-inst-parse.c" -> "vax-inst-parse." dropping the "o" off
+ *     the archived object name. SO... we shortened the name of this
+ *     source file, and changed the makefile.
+ */
+
+static char *op_hash = NULL;   /* handle of the OPCODE hash table */
+ /* NULL means any use before vip_begin() */
+ /* will crash */
+
+/*
+ * In: 1 character, from "bdfghloqpw" being the data-type of an operand
+ *     of a vax instruction.
+ *
+ * Out:        the length of an operand of that type, in bytes.
+ *     Special branch operands types "-?!" have length 0.
+ */
+
+static const short int vax_operand_width_size[256] =
+{
+
+#define _ 0
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16,    /* ..b.d.fgh...l..o */
+  _, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _,      /* .q.....w........ */
+  _, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16,    /* ..b.d.fgh...l..o */
+  _, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _,      /* .q.....w........ */
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+  _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _};
+#undef _
+\f
+/*
+ * This perversion encodes all the vax opcodes as a bunch of strings.
+ * RMS says we should build our hash-table at run-time. Hmm.
+ * Please would someone arrange these in decreasing frequency of opcode?
+ * Because of the way hash_...() works, the most frequently used opcode
+ * should be textually first and so on.
+ *
+ * Input for this table was 'vax.opcodes', awk(1)ed by 'vax.opcodes.c.awk' .
+ * So change 'vax.opcodes', then re-generate this table.
+ */
+
+#include "vax-opcode.h"
+\f
+/*
+ * This is a table of optional op-codes. All of them represent
+ * 'synthetic' instructions that seem popular.
+ *
+ * Here we make some pseudo op-codes. Every code has a bit set to say
+ * it is synthetic. This lets you catch them if you want to
+ * ban these opcodes. They are mnemonics for "elastic" instructions
+ * that are supposed to assemble into the fewest bytes needed to do a
+ * branch, or to do a conditional branch, or whatever.
+ *
+ * The opcode is in the usual place [low-order n*8 bits]. This means
+ * that if you mask off the bucky bits, the usual rules apply about
+ * how long the opcode is.
+ *
+ * All VAX branch displacements come at the end of the instruction.
+ * For simple branches (1-byte opcode + 1-byte displacement) the last
+ * operand is coded 'b?' where the "data type" '?' is a clue that we
+ * may reverse the sense of the branch (complement lowest order bit)
+ * and branch around a jump. This is by far the most common case.
+ * That is why the VIT_OPCODE_SYNTHETIC bit is set: it says this is
+ * a 0-byte op-code followed by 2 or more bytes of operand address.
+ *
+ * If the op-code has VIT_OPCODE_SPECIAL set, then we have a more unusual
+ * case.
+ *
+ * For JBSB & JBR the treatment is the similar, except (1) we have a 'bw'
+ * option before (2) we can directly JSB/JMP because there is no condition.
+ * These operands have 'b-' as their access/data type.
+ *
+ * That leaves a bunch of random opcodes: JACBx, JxOBxxx. In these
+ * cases, we do the same idea. JACBxxx are all marked with a 'b!'
+ * JAOBxxx & JSOBxxx are marked with a 'b:'.
+ *
+ */
+#if (VIT_OPCODE_SYNTHETIC != 0x80000000)
+You have just broken the encoding below, which assumes the sign bit
+ means 'I am an imaginary instruction'.
+#endif
+
+#if (VIT_OPCODE_SPECIAL != 0x40000000)
+ You have just broken the encoding below, which assumes the 0x40 M bit means
+ 'I am not to be "optimised" the way normal branches are'.
+#endif
+
+static const struct vot
+ synthetic_votstrs[] =
+{
+  {"jbsb",
+   {"b-", 0xC0000010}},                /* BSD 4.2 */
+ /* jsb used already */
+  {"jbr",
+   {"b-", 0xC0000011}},                /* BSD 4.2 */
+  {"jr",
+   {"b-", 0xC0000011}},                /* consistent */
+  {"jneq",
+   {"b?", 0x80000012}},
+  {"jnequ",
+   {"b?", 0x80000012}},
+  {"jeql",
+   {"b?", 0x80000013}},
+  {"jeqlu",
+   {"b?", 0x80000013}},
+  {"jgtr",
+   {"b?", 0x80000014}},
+  {"jleq",
+   {"b?", 0x80000015}},
+ /* un-used opcodes here */
+  {"jgeq",
+   {"b?", 0x80000018}},
+  {"jlss",
+   {"b?", 0x80000019}},
+  {"jgtru",
+   {"b?", 0x8000001a}},
+  {"jlequ",
+   {"b?", 0x8000001b}},
+  {"jvc",
+   {"b?", 0x8000001c}},
+  {"jvs",
+   {"b?", 0x8000001d}},
+  {"jgequ",
+   {"b?", 0x8000001e}},
+  {"jcc",
+   {"b?", 0x8000001e}},
+  {"jlssu",
+   {"b?", 0x8000001f}},
+  {"jcs",
+   {"b?", 0x8000001f}},
+
+  {"jacbw",
+   {"rwrwmwb!", 0xC000003d}},
+  {"jacbf",
+   {"rfrfmfb!", 0xC000004f}},
+  {"jacbd",
+   {"rdrdmdb!", 0xC000006f}},
+  {"jacbb",
+   {"rbrbmbb!", 0xC000009d}},
+  {"jacbl",
+   {"rlrlmlb!", 0xC00000f1}},
+  {"jacbg",
+   {"rgrgmgb!", 0xC0004ffd}},
+  {"jacbh",
+   {"rhrhmhb!", 0xC0006ffd}},
+
+  {"jbs",
+   {"rlvbb?", 0x800000e0}},
+  {"jbc",
+   {"rlvbb?", 0x800000e1}},
+  {"jbss",
+   {"rlvbb?", 0x800000e2}},
+  {"jbcs",
+   {"rlvbb?", 0x800000e3}},
+  {"jbsc",
+   {"rlvbb?", 0x800000e4}},
+  {"jbcc",
+   {"rlvbb?", 0x800000e5}},
+  {"jbssi",
+   {"rlvbb?", 0x800000e6}},
+  {"jbcci",
+   {"rlvbb?", 0x800000e7}},
+  {"jlbs",
+   {"rlb?", 0x800000e8}},      /* JF changed from rlvbb? */
+  {"jlbc",
+   {"rlb?", 0x800000e9}},      /* JF changed from rlvbb? */
+
+  {"jaoblss",
+   {"rlmlb:", 0xC00000f2}},
+  {"jaobleq",
+   {"rlmlb:", 0xC00000f3}},
+  {"jsobgeq",
+   {"mlb:", 0xC00000f4}},      /* JF was rlmlb: */
+  {"jsobgtr",
+   {"mlb:", 0xC00000f5}},      /* JF was rlmlb: */
+
+/* CASEx has no branch addresses in our conception of it. */
+/* You should use ".word ..." statements after the "case ...". */
+
+  {"", ""}                     /* empty is end sentinel */
+
+};                             /* synthetic_votstrs */
+\f
+/*
+ *                  v i p _ b e g i n ( )
+ *
+ * Call me once before you decode any lines.
+ * I decode votstrs into a hash table at op_hash (which I create).
+ * I return an error text: hopefully "".
+ * If you want, I will include the 'synthetic' jXXX instructions in the
+ * instruction table.
+ * You must nominate metacharacters for eg DEC's "#", "@", "^".
+ */
+
+char *
+vip_begin (synthetic_too, immediate, indirect, displen)
+     int synthetic_too;                /* TRUE means include jXXX op-codes. */
+     char *immediate, *indirect, *displen;
+{
+  register const struct vot *vP;       /* scan votstrs */
+  register char *retval;       /* error text */
+
+  char *hash_insert ();                /*  */
+  char *hash_new ();           /* lies */
+
+  if ((op_hash = hash_new ()))
+    {
+      retval = "";             /* OK so far */
+      for (vP = votstrs; *vP->vot_name && !*retval; vP++)
+       {
+         retval = hash_insert (op_hash, vP->vot_name, &vP->vot_detail);
+       }
+      if (synthetic_too)
+       {
+         for (vP = synthetic_votstrs; *vP->vot_name && !*retval; vP++)
+           {
+             retval = hash_insert (op_hash, vP->vot_name, &vP->vot_detail);
+           }
+       }
+    }
+  else
+    {
+      retval = "virtual memory exceeded";
+    }
+#ifndef CONST_TABLE
+  vip_op_defaults (immediate, indirect, displen);
+#endif
+
+  return (retval);
+}
+
+
+/*
+ *                  v i p _ e n d ( )
+ *
+ * Call me once after you have decoded all lines.
+ * I do any cleaning-up needed.
+ *
+ * We don't have to do any cleanup ourselves: all of our operand
+ * symbol table is static, and free()ing it is naughty.
+ */
+vip_end ()
+{
+}
+\f
+/*
+ *                  v i p ( )
+ *
+ * This converts a string into a vax instruction.
+ * The string must be a bare single instruction in dec-vax (with BSD4 frobs)
+ * format.
+ * It provides some error messages: at most one fatal error message (which
+ * stops the scan) and at most one warning message for each operand.
+ * The vax instruction is returned in exploded form, since we have no
+ * knowledge of how you parse (or evaluate) your expressions.
+ * We do however strip off and decode addressing modes and operation
+ * mnemonic.
+ *
+ * The exploded instruction is returned to a struct vit of your choice.
+ * #include "vax-inst.h" to know what a struct vit is.
+ *
+ * This function's value is a string. If it is not "" then an internal
+ * logic error was found: read this code to assign meaning to the string.
+ * No argument string should generate such an error string:
+ * it means a bug in our code, not in the user's text.
+ *
+ * You MUST have called vip_begin() once and vip_end() never before using
+ * this function.
+ */
+
+char *                         /* "" or bug string */
+vip (vitP, instring)
+     struct vit *vitP;         /* We build an exploded instruction here. */
+     char *instring;           /* Text of a vax instruction: we modify. */
+{
+  register struct vot_wot *vwP;        /* How to bit-encode this opcode. */
+  register char *p;            /* 1/skip whitespace.2/scan vot_how */
+  register char *q;            /*  */
+  register char *bug;          /* "" or program logic error */
+  register unsigned char count;        /* counts number of operands seen */
+  register struct vop *operandp;/* scan operands in struct vit */
+  register char *alloperr;     /* error over all operands */
+  register char c;             /* Remember char, (we clobber it */
+  /* with '\0' temporarily). */
+  register vax_opcodeT oc;     /* Op-code of this instruction. */
+
+  struct vot_wot *hash_find ();
+  char *vip_op ();
+
+  bug = "";
+  if (*instring == ' ')
+    ++instring;                        /* Skip leading whitespace. */
+  for (p = instring; *p && *p != ' '; p++)
+    ;                          /* MUST end in end-of-string or exactly 1 space. */
+  /* Scanned up to end of operation-code. */
+  /* Operation-code is ended with whitespace. */
+  if (p - instring == 0)
+    {
+      vitP->vit_error = "No operator";
+      count = 0;
+      bzero (vitP->vit_opcode, sizeof (vitP->vit_opcode));
+    }
+  else
+    {
+      c = *p;
+      *p = '\0';
+      /*
+       * Here with instring pointing to what better be an op-name, and p
+       * pointing to character just past that.
+       * We trust instring points to an op-name, with no whitespace.
+       */
+      vwP = hash_find (op_hash, instring);
+      *p = c;                  /* Restore char after op-code. */
+      if (vwP == 0)
+       {
+         vitP->vit_error = "Unknown operator";
+         count = 0;
+         bzero (vitP->vit_opcode, sizeof (vitP->vit_opcode));
+       }
+      else
+       {
+         /*
+          * We found a match! So lets pick up as many operands as the
+          * instruction wants, and even gripe if there are too many.
+          * We expect comma to seperate each operand.
+          * We let instring track the text, while p tracks a part of the
+          * struct vot.
+          */
+         /*
+          * The lines below know about 2-byte opcodes starting FD,FE or FF.
+          * They also understand synthetic opcodes. Note:
+          * we return 32 bits of opcode, including bucky bits, BUT
+          * an opcode length is either 8 or 16 bits for vit_opcode_nbytes.
+          */
+         oc = vwP->vot_code;   /* The op-code. */
+         vitP->vit_opcode_nbytes = (oc & 0xFF) >= 0xFD ? 2 : 1;
+         md_number_to_chars (vitP->vit_opcode, oc, 4);
+         count = 0;            /* no operands seen yet */
+         instring = p;         /* point just past operation code */
+         alloperr = "";
+         for (p = vwP->vot_how, operandp = vitP->vit_operand;
+              !*alloperr && !*bug && *p;
+              operandp++, p += 2
+           )
+           {
+             /*
+              * Here to parse one operand. Leave instring pointing just
+              * past any one ',' that marks the end of this operand.
+              */
+             if (!p[1])
+               bug = "p";      /* ODD(!!) number of bytes in vot_how?? */
+             else if (*instring)
+               {
+                 for (q = instring; (c = *q) && c != ','; q++)
+                   ;
+                 /*
+                  * Q points to ',' or '\0' that ends argument. C is that
+                  * character.
+                  */
+                 *q = 0;
+                 operandp->vop_width = p[1];
+                 operandp->vop_nbytes = vax_operand_width_size[p[1]];
+                 operandp->vop_access = p[0];
+                 bug = vip_op (instring, operandp);
+                 *q = c;       /* Restore input text. */
+                 if (*(operandp->vop_error))
+                   alloperr = "Bad operand";
+                 instring = q + (c ? 1 : 0);   /* next operand (if any) */
+                 count++;      /*  won another argument, may have an operr */
+               }
+             else
+               alloperr = "Not enough operands";
+           }
+         if (!*alloperr)
+           {
+             if (*instring == ' ')
+               instring++;     /* Skip whitespace. */
+             if (*instring)
+               alloperr = "Too many operands";
+           }
+         vitP->vit_error = alloperr;
+       }
+    }
+  vitP->vit_operands = count;
+  return (bug);
+}
+\f
+#ifdef test
+
+/*
+ * Test program for above.
+ */
+
+struct vit myvit;              /* build an exploded vax instruction here */
+char answer[100];              /* human types a line of vax assembler here */
+char *mybug;                   /* "" or an internal logic diagnostic */
+int mycount;                   /* number of operands */
+struct vop *myvop;             /* scan operands from myvit */
+int mysynth;                   /* TRUE means want synthetic opcodes. */
+char my_immediate[200];
+char my_indirect[200];
+char my_displen[200];
+
+char *vip ();
+
+main ()
+{
+  char *p;
+  char *vip_begin ();
+
+  printf ("0 means no synthetic instructions.   ");
+  printf ("Value for vip_begin?  ");
+  gets (answer);
+  sscanf (answer, "%d", &mysynth);
+  printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not");
+  printf ("enter immediate symbols eg enter #   ");
+  gets (my_immediate);
+  printf ("enter indirect symbols  eg enter @   ");
+  gets (my_indirect);
+  printf ("enter displen symbols   eg enter ^   ");
+  gets (my_displen);
+  if (*(p = vip_begin (mysynth, my_immediate, my_indirect, my_displen)))
+    {
+      error ("vip_begin=%s", p);
+    }
+  printf ("An empty input line will quit you from the vax instruction parser\n");
+  for (;;)
+    {
+      printf ("vax instruction: ");
+      fflush (stdout);
+      gets (answer);
+      if (!*answer)
+       {
+         break;                /* out of for each input text loop */
+       }
+      mybug = vip (&myvit, answer);
+      if (*mybug)
+       {
+         printf ("BUG:\"%s\"\n", mybug);
+       }
+      if (*myvit.vit_error)
+       {
+         printf ("ERR:\"%s\"\n", myvit.vit_error);
+       }
+      printf ("opcode=");
+      for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode;
+          mycount;
+          mycount--, p++
+       )
+       {
+         printf ("%02x ", *p & 0xFF);
+       }
+      printf ("   operand count=%d.\n", mycount = myvit.vit_operands);
+      for (myvop = myvit.vit_operand; mycount; mycount--, myvop++)
+       {
+         printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"",
+                 myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx,
+                 myvop->vop_short, myvop->vop_access, myvop->vop_width,
+                 myvop->vop_nbytes);
+         for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++)
+           {
+             putchar (*p);
+           }
+         printf ("\"\n");
+         if (*myvop->vop_error)
+           {
+             printf ("  err:\"%s\"\n", myvop->vop_error);
+           }
+         if (*myvop->vop_warn)
+           {
+             printf ("  wrn:\"%s\"\n", myvop->vop_warn);
+           }
+       }
+    }
+  vip_end ();
+  exit ();
+}
+
+#endif /* #ifdef test */
+
+/* end of vax_ins_parse.c */
+
+ /* JF this used to be a separate file also */
+/* vax_reg_parse.c - convert a VAX register name to a number */
+
+/* Copyright (C) 1987 Free Software Foundation, Inc. A part of GNU. */
+
+/*
+ *          v a x _ r e g _ p a r s e ( )
+ *
+ * Take 3 char.s, the last of which may be `\0` (non-existent)
+ * and return the VAX register number that they represent.
+ *
+ * Return -1 if they don't form a register name. Good names return
+ * a number from 0:15 inclusive.
+ *
+ * Case is not important in a name.
+ *
+ * Register names understood are:
+ *
+ *     R0
+ *     R1
+ *     R2
+ *     R3
+ *     R4
+ *     R5
+ *     R6
+ *     R7
+ *     R8
+ *     R9
+ *     R10
+ *     R11
+ *     R12     AP
+ *     R13     FP
+ *     R14     SP
+ *     R15     PC
+ *
+ */
+
+#include <ctype.h>
+#define AP (12)
+#define FP (13)
+#define SP (14)
+#define PC (15)
+\f
+int                            /* return -1 or 0:15 */
+vax_reg_parse (c1, c2, c3)     /* 3 chars of register name */
+     char c1, c2, c3;          /* c3 == 0 if 2-character reg name */
+{
+  register int retval;         /* return -1:15 */
+
+  retval = -1;
+
+  if (isupper (c1))
+    c1 = tolower (c1);
+  if (isupper (c2))
+    c2 = tolower (c2);
+  if (isdigit (c2) && c1 == 'r')
+    {
+      retval = c2 - '0';
+      if (isdigit (c3))
+       {
+         retval = retval * 10 + c3 - '0';
+         retval = (retval > 15) ? -1 : retval;
+         /* clamp the register value to 1 hex digit */
+       }
+      else if (c3)
+       retval = -1;            /* c3 must be '\0' or a digit */
+    }
+  else if (c3)                 /* There are no three letter regs */
+    retval = -1;
+  else if (c2 == 'p')
+    {
+      switch (c1)
+       {
+       case 's':
+         retval = SP;
+         break;
+       case 'f':
+         retval = FP;
+         break;
+       case 'a':
+         retval = AP;
+         break;
+       default:
+         retval = -1;
+       }
+    }
+  else if (c1 == 'p' && c2 == 'c')
+    retval = PC;
+  else
+    retval = -1;
+  return (retval);
+}
+
+/*
+ *               v i p _ o p ( )
+ *
+ * Parse a vax operand in DEC assembler notation.
+ * For speed, expect a string of whitespace to be reduced to a single ' '.
+ * This is the case for GNU AS, and is easy for other DEC-compatible
+ * assemblers.
+ *
+ * Knowledge about DEC VAX assembler operand notation lives here.
+ * This doesn't even know what a register name is, except it believes
+ * all register names are 2 or 3 characters, and lets vax_reg_parse() say
+ * what number each name represents.
+ * It does, however, know that PC, SP etc are special registers so it can
+ * detect addressing modes that are silly for those registers.
+ *
+ * Where possible, it delivers 1 fatal or 1 warning message if the operand
+ * is suspect. Exactly what we test for is still evolving.
+ */
+
+/*
+ *                     B u g s
+ *
+ *     Arg block.
+ *
+ * There were a number of 'mismatched argument type' bugs to vip_op.
+ * The most general solution is to typedef each (of many) arguments.
+ * We used instead a typedef'd argument block. This is less modular
+ * than using seperate return pointers for each result, but runs faster
+ * on most engines, and seems to keep programmers happy. It will have
+ * to be done properly if we ever want to use vip_op as a general-purpose
+ * module (it was designed to be).
+ *
+ *     G^
+ *
+ * Doesn't support DEC "G^" format operands. These always take 5 bytes
+ * to express, and code as modes 8F or 9F. Reason: "G^" deprives you of
+ * optimising to (say) a "B^" if you are lucky in the way you link.
+ * When someone builds a linker smart enough to convert "G^" to "B^", "W^"
+ * whenever possible, then we should implement it.
+ * If there is some other use for "G^", feel free to code it in!
+ *
+ *
+ *     speed
+ *
+ * If I nested if()s more, I could avoid testing (*err) which would save
+ * time, space and page faults. I didn't nest all those if()s for clarity
+ * and because I think the mode testing can be re-arranged 1st to test the
+ * commoner constructs 1st. Does anybody have statistics on this?
+ *
+ *
+ *
+ *     error messages
+ *
+ * In future, we should be able to 'compose' error messages in a scratch area
+ * and give the user MUCH more informative error messages. Although this takes
+ * a little more code at run-time, it will make this module much more self-
+ * documenting. As an example of what sucks now: most error messages have
+ * hardwired into them the DEC VAX metacharacters "#^@" which are nothing like
+ * the Un*x characters "$`*", that most users will expect from this AS.
+ */
+\f
+/*
+ * The input is a string, ending with '\0'.
+ *
+ * We also require a 'hint' of what kind of operand is expected: so
+ * we can remind caller not to write into literals for instance.
+ *
+ * The output is a skeletal instruction.
+ *
+ * The algorithm has two parts.
+ * 1. extract the syntactic features (parse off all the @^#-()+[] mode crud);
+ * 2. express the @^#-()+[] as some parameters suited to further analysis.
+ *
+ * 2nd step is where we detect the googles of possible invalid combinations
+ * a human (or compiler) might write. Note that if we do a half-way
+ * decent assembler, we don't know how long to make (eg) displacement
+ * fields when we first meet them (because they may not have defined values).
+ * So we must wait until we know how many bits are needed for each address,
+ * then we can know both length and opcodes of instructions.
+ * For reason(s) above, we will pass to our caller a 'broken' instruction
+ * of these major components, from which our caller can generate instructions:
+ *  -  displacement length      I^ S^ L^ B^ W^ unspecified
+ *  -  mode                     (many)
+ *  -  register                 R0-R15 or absent
+ *  -  index register           R0-R15 or absent
+ *  -  expression text          what we don't parse
+ *  -  error text(s)            why we couldn't understand the operand
+ */
+
+/*
+ * To decode output of this, test errtxt. If errtxt[0] == '\0', then
+ * we had no errors that prevented parsing. Also, if we ever report
+ * an internal bug, errtxt[0] is set non-zero. So one test tells you
+ * if the other outputs are to be taken seriously.
+ */
+
+
+ /* vax registers we need to know */
+/* JF #define SP      (14)
+/* JF for one big happy file #define PC      (15) */
+
+ /* useful ideas */
+/* #define TRUE    (1) */
+/* #define FALSE   (0) */
+\f
+/*
+ * Because this module is useful for both VMS and UN*X style assemblers
+ * and because of the variety of UN*X assemblers we must recognise
+ * the different conventions for assembler operand notation. For example
+ * VMS says "#42" for immediate mode, while most UN*X say "$42".
+ * We permit arbitrary sets of (single) characters to represent the
+ * 3 concepts that DEC writes '#', '@', '^'.
+ */
+
+ /* character tests */
+#define VIP_IMMEDIATE 01 /* Character is like DEC # */
+#define VIP_INDIRECT  02 /* Char is like DEC @ */
+#define VIP_DISPLEN   04 /* Char is like DEC ^ */
+
+#define IMMEDIATEP(c)  (vip_metacharacters [(c)&0xff]&VIP_IMMEDIATE)
+#define INDIRECTP(c)   (vip_metacharacters [(c)&0xff]&VIP_INDIRECT)
+#define DISPLENP(c)    (vip_metacharacters [(c)&0xff]&VIP_DISPLEN)
+
+/* We assume 8 bits per byte. Use vip_op_defaults() to set these up BEFORE we
+ * are ever called.
+ */
+
+#if defined(CONST_TABLE)
+#define _ 0,
+#define I VIP_IMMEDIATE,
+#define S VIP_INDIRECT,
+#define D VIP_DISPLEN,
+static const char
+vip_metacharacters[256] = {
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*^@ ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J ^K ^L ^M ^N ^O*/
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y ^Z ^[ ^\ ^] ^^ ^_*/
+_ _ _ _ I _ _ _ _ _ S _ _ _ _ _/*sp !  "  #  $  %  &  '  (  )  *  +  ,  -  .  /*/
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?*/
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*@  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O*/
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*P  Q  R  S  T  U  V  W  X  Y  Z  [  \  ]  ^  _*/
+D _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*`  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o*/
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*p  q  r  s  t  u  v  w  x  y  z  {  |  }  ~  ^?*/
+
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+};
+#undef _
+#undef I
+#undef S
+#undef D
+#else
+static char vip_metacharacters[256];
+
+/* Macro is faster under GCC;  The constant table is faster yet, but only works with ASCII */
+#if 0
+static
+#ifdef __GNUC__
+inline
+#endif
+static void
+vip_op_1(bit,syms)
+int bit;
+char *syms;
+{
+  unsigned char t;
+
+  while(t= *syms++)
+    vip_metacharacters[t]|=bit;
+}
+#else
+#define vip_op_1(bit,syms) {           \
+  unsigned char t;                     \
+  char *table=vip_metacharacters;      \
+  while(t= *syms++)                    \
+    table[t]|=bit;                     \
+ }
+#endif
+
+vip_op_defaults (immediate, indirect, displen) /* can be called any time */
+     char *immediate,          /* Strings of characters for each job. */
+     *indirect, *displen;      /* more arguments may appear in future! */
+{
+  vip_op_1 (VIP_IMMEDIATE, immediate);
+  vip_op_1 (VIP_INDIRECT, indirect);
+  vip_op_1 (VIP_DISPLEN, displen);
+}
+#endif
+
+\f
+/*
+ * Dec defines the semantics of address modes (and values)
+ * by a two-letter code, explained here.
+ *
+ *   letter 1:   access type
+ *
+ *     a         address calculation - no data access, registers forbidden
+ *     b         branch displacement
+ *     m         read - let go of bus - write back    "modify"
+ *     r         read
+ *     v         bit field address: like 'a' but registers are OK
+ *     w         write
+ *     space    no operator (eg ".long foo") [our convention]
+ *
+ *   letter 2:   data type (i.e. width, alignment)
+ *
+ *     b         byte
+ *     d         double precision floating point (D format)
+ *     f         single precision floating point (F format)
+ *     g         G format floating
+ *     h         H format floating
+ *     l         longword
+ *     o         octaword
+ *     q         quadword
+ *     w         word
+ *     ?        simple synthetic branch operand
+ *     -        unconditional synthetic JSB/JSR operand
+ *     !        complex synthetic branch operand
+ *
+ * The '-?!' letter 2's are not for external consumption. They are used
+ * for various assemblers. Generally, all unknown widths are assumed 0.
+ * We don't limit your choice of width character.
+ *
+ * DEC operands are hard work to parse. For example, '@' as the first
+ * character means indirect (deferred) mode but elswhere it is a shift
+ * operator.
+ * The long-winded explanation of how this is supposed to work is
+ * cancelled. Read a DEC vax manual.
+ * We try hard not to parse anything that MIGHT be part of the expression
+ * buried in that syntax. For example if we see @...(Rn) we don't check
+ * for '-' before the '(' because mode @-(Rn) does not exist.
+ *
+ * After parsing we have:
+ *
+ * at                     TRUE if leading '@' (or Un*x '*')
+ * len                    takes one value from " bilsw". eg B^ -> 'b'.
+ * hash                   TRUE if leading '#' (or Un*x '$')
+ * expr_begin, expr_end   the expression we did not parse
+ *                        even though we don't interpret it, we make use
+ *                        of its presence or absence.
+ * sign                   -1: -(Rn)    0: absent    +1: (Rn)+
+ * paren                  TRUE if () are around register
+ * reg                    major register number 0:15    -1 means absent
+ * ndx                    index register number 0:15    -1 means absent
+ *
+ * Again, I dare not explain it: just trace ALL the code!
+ */
+\f
+char *                         /* (code here) bug message, "" = OK */
+ /* our code bug, NOT bad assembly language */
+vip_op (optext, vopP)
+     char *optext;             /* user's input string e.g.: */
+ /* "@B^foo@bar(AP)[FP]:" */
+     struct vop *vopP;         /* In: vop_access, vop_width. */
+ /* Out: _ndx, _reg, _mode, _short, _warn, */
+ /* _error _expr_begin, _expr_end, _nbytes. */
+ /* vop_nbytes : number of bytes in a datum. */
+{
+  char *p;                     /* track operand text forward */
+  char *q;                     /* track operand text backward */
+  int at;                      /* TRUE if leading '@' ('*') seen */
+  char len;                    /* one of " bilsw" */
+  int hash;                    /* TRUE if leading '#' ('$') seen */
+  int sign;                    /* -1, 0 or +1 */
+  int paren;                   /* TRUE if () surround register */
+  int reg;                     /* register number, -1:absent */
+  int ndx;                     /* index register number -1:absent */
+  char *bug;                   /* report any logic error in here, ""==OK */
+  char *err;                   /* report illegal operand, ""==OK */
+  /* " " is a FAKE error: means we won */
+  /* ANY err that begins with ' ' is a fake. */
+  /* " " is converted to "" before return */
+  char *wrn;                   /* warn about weird modes pf address */
+  char *oldq;                  /* preserve q in case we backup */
+  int mode;                    /* build up 4-bit operand mode here */
+  /* note: index mode is in ndx, this is */
+  /* the major mode of operand address */
+/*
+ * Notice how we move wrong-arg-type bugs INSIDE this module: if we
+ * get the types wrong below, we lose at compile time rather than at
+ * lint or run time.
+ */
+  char access;                 /* vop_access. */
+  char width;                  /* vop_width. */
+
+  int vax_reg_parse ();                /* returns 0:15 or -1 if not a register */
+
+  access = vopP->vop_access;
+  width = vopP->vop_width;
+  bug =                                /* none of our code bugs (yet) */
+    err =                      /* no user text errors */
+    wrn = "";                  /* no warnings even */
+
+  p = optext;
+
+  if (*p == ' ')               /* Expect all whitespace reduced to ' '. */
+    p++;                       /* skip over whitespace */
+
+  if (at = INDIRECTP (*p))
+    {                          /* TRUE if *p=='@'(or '*' for Un*x) */
+      p++;                     /* at is determined */
+      if (*p == ' ')           /* Expect all whitespace reduced to ' '. */
+       p++;                    /* skip over whitespace */
+    }
+
+  /*
+   * This code is subtle. It tries to detect all legal (letter)'^'
+   * but it doesn't waste time explicitly testing for premature '\0' because
+   * this case is rejected as a mismatch against either (letter) or '^'.
+   */
+  {
+    register char c;
+
+    c = *p;
+    if (isupper (c))
+      c = tolower (c);
+    if (DISPLENP (p[1]) && strchr ("bilws", len = c))
+      p += 2;                  /* skip (letter) '^' */
+    else                       /* no (letter) '^' seen */
+      len = ' ';               /* len is determined */
+  }
+
+  if (*p == ' ')               /* Expect all whitespace reduced to ' '. */
+    p++;                       /* skip over whitespace */
+
+  if (hash = IMMEDIATEP (*p))  /* TRUE if *p=='#' ('$' for Un*x) */
+    p++;                       /* hash is determined */
+
+  /*
+   * p points to what may be the beginning of an expression.
+   * We have peeled off the front all that is peelable.
+   * We know at, len, hash.
+   *
+   * Lets point q at the end of the text and parse that (backwards).
+   */
+
+  for (q = p; *q; q++)
+    ;
+  q--;                         /* now q points at last char of text */
+\f
+  if (*q == ' ' && q >= p)     /* Expect all whitespace reduced to ' '. */
+    q--;
+  /* reverse over whitespace, but don't */
+  /* run back over *p */
+
+  /*
+   * As a matter of policy here, we look for [Rn], although both Rn and S^#
+   * forbid [Rn]. This is because it is easy, and because only a sick
+   * cyborg would have [...] trailing an expression in a VAX-like assembler.
+   * A meticulous parser would first check for Rn followed by '(' or '['
+   * and not parse a trailing ']' if it found another. We just ban expressions
+   * ending in ']'.
+   */
+  if (*q == ']')
+    {
+      while (q >= p && *q != '[')
+       q--;
+      /* either q<p or we got matching '[' */
+      if (q < p)
+       err = "no '[' to match ']'";
+      else
+       {
+         /*
+          * Confusers like "[]" will eventually lose with a bad register
+          * name error. So again we don't need to check for early '\0'.
+          */
+         if (q[3] == ']')
+           ndx = vax_reg_parse (q[1], q[2], 0);
+         else if (q[4] == ']')
+           ndx = vax_reg_parse (q[1], q[2], q[3]);
+         else
+           ndx = -1;
+         /*
+          * Since we saw a ']' we will demand a register name in the [].
+          * If luser hasn't given us one: be rude.
+          */
+         if (ndx < 0)
+           err = "bad register in []";
+         else if (ndx == PC)
+           err = "[PC] index banned";
+         else
+           q--;                /* point q just before "[...]" */
+       }
+    }
+  else
+    ndx = -1;                  /* no ']', so no iNDeX register */
+
+  /*
+   * If err = "..." then we lost: run away.
+   * Otherwise ndx == -1 if there was no "[...]".
+   * Otherwise, ndx is index register number, and q points before "[...]".
+   */
+\f
+  if (*q == ' ' && q >= p)     /* Expect all whitespace reduced to ' '. */
+    q--;
+  /* reverse over whitespace, but don't */
+  /* run back over *p */
+  if (!*err)
+    {
+      sign = 0;                        /* no ()+ or -() seen yet */
+
+      if (q > p + 3 && *q == '+' && q[-1] == ')')
+       {
+         sign = 1;             /* we saw a ")+" */
+         q--;                  /* q points to ')' */
+       }
+
+      if (*q == ')' && q > p + 2)
+       {
+         paren = TRUE;         /* assume we have "(...)" */
+         while (q >= p && *q != '(')
+           q--;
+         /* either q<p or we got matching '(' */
+         if (q < p)
+           err = "no '(' to match ')'";
+         else
+           {
+             /*
+              * Confusers like "()" will eventually lose with a bad register
+              * name error. So again we don't need to check for early '\0'.
+              */
+             if (q[3] == ')')
+               reg = vax_reg_parse (q[1], q[2], 0);
+             else if (q[4] == ')')
+               reg = vax_reg_parse (q[1], q[2], q[3]);
+             else
+               reg = -1;
+             /*
+              * Since we saw a ')' we will demand a register name in the ')'.
+              * This is nasty: why can't our hypothetical assembler permit
+              * parenthesised expressions? BECAUSE I AM LAZY! That is why.
+              * Abuse luser if we didn't spy a register name.
+              */
+             if (reg < 0)
+               {
+                 /* JF allow parenthasized expressions.  I hope this works */
+                 paren = FALSE;
+                 while (*q != ')')
+                   q++;
+                 /* err = "unknown register in ()"; */
+               }
+             else
+               q--;            /* point just before '(' of "(...)" */
+             /*
+              * If err == "..." then we lost. Run away.
+              * Otherwise if reg >= 0 then we saw (Rn).
+              */
+           }
+         /*
+          * If err == "..." then we lost.
+          * Otherwise paren==TRUE and reg = register in "()".
+          */
+       }
+      else
+       paren = FALSE;
+      /*
+       * If err == "..." then we lost.
+       * Otherwise, q points just before "(Rn)", if any.
+       * If there was a "(...)" then paren==TRUE, and reg is the register.
+       */
+\f
+      /*
+       * We should only seek '-' of "-(...)" if:
+       *   we saw "(...)"                    paren == TRUE
+       *   we have no errors so far          ! *err
+       *   we did not see '+' of "(...)+"    sign < 1
+       * We don't check len. We want a specific error message later if
+       * user tries "x^...-(Rn)". This is a feature not a bug.
+       */
+      if (!*err)
+       {
+         if (paren && sign < 1)/* !sign is adequate test */
+           {
+             if (*q == '-')
+               {
+                 sign = -1;
+                 q--;
+               }
+           }
+         /*
+          * We have back-tracked over most
+          * of the crud at the end of an operand.
+          * Unless err, we know: sign, paren. If paren, we know reg.
+          * The last case is of an expression "Rn".
+          * This is worth hunting for if !err, !paren.
+          * We wouldn't be here if err.
+          * We remember to save q, in case we didn't want "Rn" anyway.
+          */
+         if (!paren)
+           {
+             if (*q == ' ' && q >= p)  /* Expect all whitespace reduced to ' '. */
+               q--;
+             /* reverse over whitespace, but don't */
+             /* run back over *p */
+             if (q > p && q < p + 3)   /* room for Rn or Rnn exactly? */
+               reg = vax_reg_parse (p[0], p[1], q < p + 2 ? 0 : p[2]);
+             else
+               reg = -1;       /* always comes here if no register at all */
+             /*
+              * Here with a definitive reg value.
+              */
+             if (reg >= 0)
+               {
+                 oldq = q;
+                 q = p - 1;
+               }
+           }
+       }
+    }
+  /*
+   * have reg. -1:absent; else 0:15
+   */
+
+  /*
+   * We have:  err, at, len, hash, ndx, sign, paren, reg.
+   * Also, any remaining expression is from *p through *q inclusive.
+   * Should there be no expression, q==p-1. So expression length = q-p+1.
+   * This completes the first part: parsing the operand text.
+   */
+\f
+  /*
+   * We now want to boil the data down, checking consistency on the way.
+   * We want:  len, mode, reg, ndx, err, p, q, wrn, bug.
+   * We will deliver a 4-bit reg, and a 4-bit mode.
+   */
+
+  /*
+   * Case of branch operand. Different. No L^B^W^I^S^ allowed for instance.
+   *
+   * in:  at   ?
+   *      len  ?
+   *      hash ?
+   *      p:q  ?
+   *      sign  ?
+   *      paren        ?
+   *      reg   ?
+   *      ndx   ?
+   *
+   * out: mode  0
+   *      reg   -1
+   *      len  ' '
+   *      p:q  whatever was input
+   *      ndx  -1
+   *      err  " "              or error message, and other outputs trashed
+   */
+  /* branch operands have restricted forms */
+  if (!*err && access == 'b')
+    {
+      if (at || hash || sign || paren || ndx >= 0 || reg >= 0 || len != ' ')
+       err = "invalid branch operand";
+      else
+       err = " ";
+    }
+\f
+/* Since nobody seems to use it: comment this 'feature'(?) out for now. */
+#ifdef NEVER
+  /*
+   * Case of stand-alone operand. e.g. ".long foo"
+   *
+   * in:  at   ?
+   *      len  ?
+   *      hash ?
+   *      p:q  ?
+   *      sign  ?
+   *      paren        ?
+   *      reg   ?
+   *      ndx   ?
+   *
+   * out: mode  0
+   *      reg   -1
+   *      len  ' '
+   *      p:q  whatever was input
+   *      ndx  -1
+   *      err  " "              or error message, and other outputs trashed
+   */
+  if (!*err)
+    {
+      if (access == ' ')
+       {                       /* addresses have restricted forms */
+         if (at)
+           err = "address prohibits @";
+         else
+           {
+             if (hash)
+               err = "address prohibits #";
+             else
+               {
+                 if (sign)
+                   {
+                     if (sign < 0)
+                       err = "address prohibits -()";
+                     else
+                       err = "address prohibits ()+";
+                   }
+                 else
+                   {
+                     if (paren)
+                       err = "address prohibits ()";
+                     else
+                       {
+                         if (ndx >= 0)
+                           err = "address prohibits []";
+                         else
+                           {
+                             if (reg >= 0)
+                               err = "address prohibits register";
+                             else
+                               {
+                                 if (len != ' ')
+                                   err = "address prohibits displacement length specifier";
+                                 else
+                                   {
+                                     err = " ";        /* succeed */
+                                     mode = 0;
+                                   }
+                               }
+                           }
+                       }
+                   }
+               }
+           }
+       }
+    }
+#endif /*#Ifdef NEVER*/
+\f
+  /*
+   * Case of S^#.
+   *
+   * in:  at       FALSE
+   *      len      's'               definition
+   *      hash     TRUE              demand
+   *      p:q                        demand not empty
+   *      sign     0                 by paren==FALSE
+   *      paren    FALSE             by "()" scan logic because "S^" seen
+   *      reg      -1                or nn by mistake
+   *      ndx      -1
+   *
+   * out: mode     0
+   *      reg      -1
+   *      len      's'
+   *      exp
+   *      ndx      -1
+   */
+  if (!*err && len == 's')
+    {
+      if (!hash || paren || at || ndx >= 0)
+       err = "invalid operand of S^#";
+      else
+       {
+         if (reg >= 0)
+           {
+             /*
+              * SHIT! we saw S^#Rnn ! put the Rnn back in
+              * expression. KLUDGE! Use oldq so we don't
+              * need to know exact length of reg name.
+              */
+             q = oldq;
+             reg = 0;
+           }
+         /*
+          * We have all the expression we will ever get.
+          */
+         if (p > q)
+           err = "S^# needs expression";
+         else if (access == 'r')
+           {
+             err = " ";        /* WIN! */
+             mode = 0;
+           }
+         else
+           err = "S^# may only read-access";
+       }
+    }
+\f
+  /*
+   * Case of -(Rn), which is weird case.
+   *
+   * in:  at       FALSE
+   *      len      '
+   *      hash     FALSE
+   *      p:q      q<p
+   *      sign     -1                by definition
+   *      paren    TRUE              by definition
+   *      reg      present           by definition
+   *      ndx      optional
+   *
+   * out: mode     7
+   *      reg      present
+   *      len      ' '
+   *      exp      ""                enforce empty expression
+   *      ndx      optional          warn if same as reg
+   */
+  if (!*err && sign < 0)
+    {
+      if (len != ' ' || hash || at || p <= q)
+       err = "invalid operand of -()";
+      else
+       {
+         err = " ";            /* win */
+         mode = 7;
+         if (reg == PC)
+           wrn = "-(PC) unpredictable";
+         else if (reg == ndx)
+           wrn = "[]index same as -()register: unpredictable";
+       }
+    }
+\f
+  /*
+   * We convert "(Rn)" to "@Rn" for our convenience.
+   * (I hope this is convenient: has someone got a better way to parse this?)
+   * A side-effect of this is that "@Rn" is a valid operand.
+   */
+  if (paren && !sign && !hash && !at && len == ' ' && p > q)
+    {
+      at = TRUE;
+      paren = FALSE;
+    }
+
+  /*
+   * Case of (Rn)+, which is slightly different.
+   *
+   * in:  at
+   *      len      ' '
+   *      hash     FALSE
+   *      p:q      q<p
+   *      sign     +1                by definition
+   *      paren    TRUE              by definition
+   *      reg      present           by definition
+   *      ndx      optional
+   *
+   * out: mode     8+@
+   *      reg      present
+   *      len      ' '
+   *      exp      ""                enforce empty expression
+   *      ndx      optional          warn if same as reg
+   */
+  if (!*err && sign > 0)
+    {
+      if (len != ' ' || hash || p <= q)
+       err = "invalid operand of ()+";
+      else
+       {
+         err = " ";            /* win */
+         mode = 8 + (at ? 1 : 0);
+         if (reg == PC)
+           wrn = "(PC)+ unpredictable";
+         else if (reg == ndx)
+           wrn = "[]index same as ()+register: unpredictable";
+       }
+    }
+\f
+  /*
+   * Case of #, without S^.
+   *
+   * in:  at
+   *      len      ' ' or 'i'
+   *      hash     TRUE              by definition
+   *      p:q
+   *      sign     0
+   *      paren    FALSE
+   *      reg      absent
+   *      ndx      optional
+   *
+   * out: mode     8+@
+   *      reg      PC
+   *      len      ' ' or 'i'
+   *      exp
+   *      ndx      optional
+   */
+  if (!*err && hash)
+    {
+      if (len != 'i' && len != ' ')
+       err = "# conflicts length";
+      else if (paren)
+       err = "# bars register";
+      else
+       {
+         if (reg >= 0)
+           {
+             /*
+             * SHIT! we saw #Rnn! Put the Rnn back into the expression.
+             * By using oldq, we don't need to know how long Rnn was.
+             * KLUDGE!
+             */
+             q = oldq;
+             reg = -1;         /* no register any more */
+           }
+         err = " ";            /* win */
+
+               /* JF a bugfix, I think! */
+         if(at && access=='a')
+           vopP->vop_nbytes=4;
+
+         mode = (at ? 9 : 8);
+         reg = PC;
+         if ((access == 'm' || access == 'w') && !at)
+           wrn = "writing or modifying # is unpredictable";
+       }
+    }
+  /*
+   * If !*err, then        sign == 0
+   *                       hash == FALSE
+   */
+\f
+  /*
+   * Case of Rn. We seperate this one because it has a few special
+   * errors the remaining modes lack.
+   *
+   * in:  at       optional
+   *      len      ' '
+   *      hash     FALSE             by program logic
+   *      p:q      empty
+   *      sign     0                 by program logic
+   *      paren    FALSE             by definition
+   *      reg      present           by definition
+   *      ndx      optional
+   *
+   * out: mode     5+@
+   *      reg      present
+   *      len      ' '               enforce no length
+   *      exp      ""                enforce empty expression
+   *      ndx      optional          warn if same as reg
+   */
+  if (!*err && !paren && reg >= 0)
+    {
+      if (len != ' ')
+       err = "length not needed";
+      else if (at)
+       {
+         err = " ";            /* win */
+         mode = 6;             /* @Rn */
+       }
+      else if (ndx >= 0)
+       err = "can't []index a register, because it has no address";
+      else if (access == 'a')
+       err = "a register has no address";
+      else
+       {
+         /*
+         * Idea here is to detect from length of datum
+         * and from register number if we will touch PC.
+         * Warn if we do.
+         * vop_nbytes is number of bytes in operand.
+         * Compute highest byte affected, compare to PC0.
+         */
+         if ((vopP->vop_nbytes + reg * 4) > 60)
+           wrn = "PC part of operand unpredictable";
+         err = " ";            /* win */
+         mode = 5;             /* Rn */
+       }
+    }
+  /*
+   * If !*err,        sign  == 0
+   *                  hash  == FALSE
+   *                  paren == TRUE  OR reg==-1
+   */
+\f
+  /*
+   * Rest of cases fit into one bunch.
+   *
+   * in:  at       optional
+   *      len      ' ' or 'b' or 'w' or 'l'
+   *      hash     FALSE             by program logic
+   *      p:q      expected          (empty is not an error)
+   *      sign     0                 by program logic
+   *      paren    optional
+   *      reg      optional
+   *      ndx      optional
+   *
+   * out: mode     10 + @ + len
+   *      reg      optional
+   *      len      ' ' or 'b' or 'w' or 'l'
+   *      exp                        maybe empty
+   *      ndx      optional          warn if same as reg
+   */
+  if (!*err)
+    {
+      err = " ";               /* win (always) */
+      mode = 10 + (at ? 1 : 0);
+      switch (len)
+       {
+       case 'l':
+         mode += 2;
+       case 'w':
+         mode += 2;
+       case ' ':               /* assumed B^ until our caller changes it */
+       case 'b':
+         break;
+       }
+    }
+
+  /*
+   * here with completely specified     mode
+   *                                   len
+   *                                   reg
+   *                                   expression   p,q
+   *                                   ndx
+   */
+
+  if (*err == ' ')
+    err = "";                  /* " " is no longer an error */
+
+  vopP->vop_mode = mode;
+  vopP->vop_reg = reg;
+  vopP->vop_short = len;
+  vopP->vop_expr_begin = p;
+  vopP->vop_expr_end = q;
+  vopP->vop_ndx = ndx;
+  vopP->vop_error = err;
+  vopP->vop_warn = wrn;
+  return (bug);
+
+}                              /* vip_op() */
+\f
+/*
+
+Summary of vip_op outputs.
+
+                       mode    reg     len     ndx
+(Rn) => @Rn
+{@}Rn                  5+@     n       ' '     optional
+branch operand         0       -1      ' '     -1
+S^#foo                 0       -1      's'     -1
+-(Rn)                  7       n       ' '     optional
+{@}(Rn)+               8+@     n       ' '     optional
+{@}#foo, no S^         8+@     PC      " i"    optional
+{@}{q^}{(Rn)}          10+@+q  option  " bwl"  optional
+
+*/
+\f
+#ifdef TEST                    /* #Define to use this testbed. */
+
+/*
+ * Follows a test program for this function.
+ * We declare arrays non-local in case some of our tiny-minded machines
+ * default to small stacks. Also, helps with some debuggers.
+ */
+
+#include <stdio.h>
+
+char answer[100];              /* human types into here */
+char *p;                       /*  */
+char *myerr;
+char *mywrn;
+char *mybug;
+char myaccess;
+char mywidth;
+char mymode;
+char myreg;
+char mylen;
+char *myleft;
+char *myright;
+char myndx;
+int my_operand_length;
+char my_immediate[200];
+char my_indirect[200];
+char my_displen[200];
+
+main ()
+{
+  char *vip_op ();             /* make cc happy */
+
+  printf ("enter immediate symbols eg enter #   ");
+  gets (my_immediate);
+  printf ("enter indirect symbols  eg enter @   ");
+  gets (my_indirect);
+  printf ("enter displen symbols   eg enter ^   ");
+  gets (my_displen);
+  vip_op_defaults (my_immediate, my_indirect, my_displen);
+  for (;;)
+    {
+      printf ("access,width (eg 'ab' or 'wh') [empty line to quit] :  ");
+      fflush (stdout);
+      gets (answer);
+      if (!answer[0])
+       exit (0);
+      myaccess = answer[0];
+      mywidth = answer[1];
+      switch (mywidth)
+       {
+       case 'b':
+         my_operand_length = 1;
+         break;
+       case 'd':
+         my_operand_length = 8;
+         break;
+       case 'f':
+         my_operand_length = 4;
+         break;
+       case 'g':
+         my_operand_length = 16;
+         break;
+       case 'h':
+         my_operand_length = 32;
+         break;
+       case 'l':
+         my_operand_length = 4;
+         break;
+       case 'o':
+         my_operand_length = 16;
+         break;
+       case 'q':
+         my_operand_length = 8;
+         break;
+       case 'w':
+         my_operand_length = 2;
+         break;
+       case '!':
+       case '?':
+       case '-':
+         my_operand_length = 0;
+         break;
+
+       default:
+         my_operand_length = 2;
+         printf ("I dn't understand access width %c\n", mywidth);
+         break;
+       }
+      printf ("VAX assembler instruction operand: ");
+      fflush (stdout);
+      gets (answer);
+      mybug = vip_op (answer, myaccess, mywidth, my_operand_length,
+                     &mymode, &myreg, &mylen, &myleft, &myright, &myndx,
+                     &myerr, &mywrn);
+      if (*myerr)
+       {
+         printf ("error: \"%s\"\n", myerr);
+         if (*mybug)
+           printf (" bug: \"%s\"\n", mybug);
+       }
+      else
+       {
+         if (*mywrn)
+           printf ("warning: \"%s\"\n", mywrn);
+         mumble ("mode", mymode);
+         mumble ("register", myreg);
+         mumble ("index", myndx);
+         printf ("width:'%c'  ", mylen);
+         printf ("expression: \"");
+         while (myleft <= myright)
+           putchar (*myleft++);
+         printf ("\"\n");
+       }
+    }
+}
+
+mumble (text, value)
+     char *text;
+     int value;
+{
+  printf ("%s:", text);
+  if (value >= 0)
+    printf ("%xx", value);
+  else
+    printf ("ABSENT");
+  printf ("  ");
+}
+
+#endif /* ifdef TEST */
+
+/* end: vip_op.c */
+
+const int md_short_jump_size = 3;
+const int md_long_jump_size = 6;
+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;
+     long from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  long offset;
+
+  offset = to_addr - (from_addr + 1);
+  *ptr++ = 0x31;
+  md_number_to_chars (ptr, offset, 2);
+}
+
+void
+md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
+     char *ptr;
+     long from_addr, to_addr;
+     fragS *frag;
+     symbolS *to_symbol;
+{
+  long offset;
+
+  offset = to_addr - to_symbol->sy_value;
+  *ptr++ = 0x17;
+  *ptr++ = 0x9F;
+  md_number_to_chars (ptr, offset, 4);
+  fix_new (frag, ptr - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0);
+}
+
+int
+md_parse_option (argP, cntP, vecP)
+     char **argP;
+     int *cntP;
+     char ***vecP;
+{
+  char *temp_name;             /* name for -t or -d options */
+  char opt;
+
+  switch (**argP)
+    {
+    case 'J':
+      /* as_warn ("I can do better than -J!"); */
+      break;
+
+    case 'S':
+      as_warn ("SYMBOL TABLE not implemented");
+      break;                   /* SYMBOL TABLE not implemented */
+
+    case 'T':
+      as_warn ("TOKEN TRACE not implemented");
+      break;                   /* TOKEN TRACE not implemented */
+
+    case 'd':
+    case 't':
+      opt= **argP;
+      if (**argP)
+       {                       /* Rest of argument is filename. */
+         temp_name = *argP;
+         while (**argP)
+           (*argP)++;
+       }
+      else if (*cntP)
+       {
+         while (**argP)
+           (*argP)++;
+         --(*cntP);
+         temp_name = *++(*vecP);
+         **vecP = NULL;        /* Remember this is not a file-name. */
+       }
+      else
+       {
+         as_warn ("I expected a filename after -%c.",opt);
+         temp_name = "{absent}";
+       }
+
+      if(opt=='d')
+       as_warn ("Displacement length %s ignored!", temp_name);
+      else
+       as_warn ("I don't need or use temp. file \"%s\".", temp_name);
+      break;
+
+    case 'V':
+      as_warn ("I don't use an interpass file! -V ignored");
+      break;
+
+#ifdef VMS
+    case '+':  /* For g++ */
+      break;
+
+    case 'h':  /* No hashing of mixed-case names */
+      break;
+
+    case 'H':  /* Show new symbol after hash truncation */
+      break;
+#endif
+
+    default:
+      return 0;
+
+    }
+  return 1;
+}
+
+/* We have no need to default values of symbols.  */
+
+/* ARGSUSED */
+symbolS *
+md_undefined_symbol (name)
+     char *name;
+{
+  return 0;
+}
+
+/* Parse an operand that is machine-specific.  
+   We just return without modifying the expression if we have nothing
+   to do.  */
+
+/* ARGSUSED */
+void
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+}
+
+/* Round up a section size to the appropriate boundary.  */
+long
+md_section_align (segment, size)
+     segT segment;
+     long size;
+{
+  return size;         /* Byte alignment is fine */
+}
+
+/* Exactly what point is a PC-relative offset relative TO?
+   On the vax, 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;
+}
diff --git a/gas/config/tc-vax.h b/gas/config/tc-vax.h
new file mode 100644 (file)
index 0000000..0097782
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * This file is tc-vax.h.
+ */
+
+#define TC_VAX 1
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tc-vax.h */
diff --git a/gas/config/te-generic.h b/gas/config/te-generic.h
new file mode 100644 (file)
index 0000000..4b40d61
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * This file is te-generic.h and is intended to be a template for
+ * target environment specific header files.
+ */
+
+#define TE_GENERIC 1
+
+ /* these define interfaces */
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-generic.h */
diff --git a/gas/config/te-ic960.h b/gas/config/te-ic960.h
new file mode 100644 (file)
index 0000000..15c3064
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is te-ic960.h and is intended to define ic960 environment
+ * specific differences.
+ */
+
+/* $Id$ */
+
+#define TE_IC960 1
+
+ /* intel uses host byte order for headers */
+#ifdef CROSS_ASSEMBLE
+#undef CROSS_ASSEMBLE
+#endif /* CROSS_ASSEMBLE */
+
+#define OBJ_COFF_OMIT_OPTIONAL_HEADER
+#define LOCAL_LABEL(name) ( (name[0] =='L') \
+                         || (name[0] =='.' \
+                            && (name[1]=='C' || name[1]=='I' || name[1]=='.')))
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-ic960.h */
diff --git a/gas/config/te-sun3.h b/gas/config/te-sun3.h
new file mode 100644 (file)
index 0000000..9d1ece4
--- /dev/null
@@ -0,0 +1,48 @@
+/* te-sun3.h -- Sun-3 target environment declarations.
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/* This header file contains the #defines specific
+   to SUN computer SUN 3 series computers.  (The only kind
+   we have around here, unfortunatly.)
+   
+   Rumor has it that this file will work on the Sun-2 if the assembler
+   is called with -m68010  This is not tested.  */
+
+
+#define TE_SUN3        1
+#define SUN_ASM_SYNTAX
+
+/* Could also be :
+#define S_LOCAL_NAME(s)        (S_GET_NAME(s)[0] == '.' &&
+                                S_GET_NAME(s)[1] == 'L' || 
+                                S_GET_NAME(s)[1] == '.')
+*/
+
+#include "obj-format.h"
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of te-sun3.h */
diff --git a/gas/config/vax-inst.h b/gas/config/vax-inst.h
new file mode 100644 (file)
index 0000000..51b7c94
--- /dev/null
@@ -0,0 +1,77 @@
+/* vax-inst.h - GNU - Part of vax.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+ * This is part of vax-ins-parse.c & friends.
+ * We want to parse a vax instruction text into a tree defined here.
+ */
+
+#define VIT_MAX_OPERANDS (6)   /* maximum number of operands in one       */
+                               /* single vax instruction                  */
+
+struct vop                     /* vax instruction operand                 */
+{
+  short int    vop_ndx;        /* -1, or index register. eg 7=[R7]        */
+  short int    vop_reg;        /* -1, or register number. eg @I^#=0xF     */
+                               /* Helps distinguish "abs" from "abs(PC)". */
+  short int    vop_mode;       /* addressing mode 4 bits. eg I^#=0x9      */
+  char         vop_short;      /* operand displacement length as written  */
+                               /* ' '=none, "bilsw"=B^I^L^S^W^.           */
+  char         vop_access;     /* 'b'branch ' 'no-instruction 'amrvw'norm */
+  char         vop_width;      /* Operand width, one of "bdfghloqw"       */
+  char *       vop_warn;       /* warning message of this operand, if any */
+  char *        vop_error;     /* say if operand is inappropriate         */
+  char *       vop_expr_begin; /* Unparsed expression, 1st char ...       */
+  char *       vop_expr_end;   /* ... last char.                          */
+  unsigned char        vop_nbytes;     /* number of bytes in datum                */
+};
+
+
+typedef long vax_opcodeT;      /* For initialising array of opcodes       */
+                               /* Some synthetic opcodes > 16 bits!       */
+
+#define VIT_OPCODE_SYNTHETIC 0x80000000        /* Not real hardware instruction.  */
+#define VIT_OPCODE_SPECIAL   0x40000000        /* Not normal branch optimising.   */
+                                       /* Never set without ..._SYNTHETIC */
+
+#define VAX_WIDTH_UNCONDITIONAL_JUMP '-' /* These are encoded into         */
+#define VAX_WIDTH_CONDITIONAL_JUMP   '?' /* vop_width when vop_access=='b' */
+#define VAX_WIDTH_WORD_JUMP          '!' /* and VIT_OPCODE_SYNTHETIC set.  */
+#define VAX_WIDTH_BYTE_JUMP         ':' /*                                */
+
+#define VAX_JMP (0x17)         /* Useful for branch optimising. Jump instr*/
+#define VAX_PC_RELATIVE_MODE (0xef) /* Use it after VAX_JMP               */
+#define VAX_ABSOLUTE_MODE (0x9F) /* Use as @#...                          */
+#define VAX_BRB (0x11)         /* Canonical branch.                       */
+#define VAX_BRW (0x31)         /* Another canonical branch                */
+#define VAX_WIDEN_WORD (0x20)  /* Add this to byte branch to get word br. */
+#define VAX_WIDEN_LONG (0x6)   /* Add this to byte branch to get long jmp.*/
+                               /* Needs VAX_PC_RELATIVE_MODE byte after it*/
+
+struct vit                     /* vax instruction tree                    */
+{
+                               /* vit_opcode is char[] for portability.   */
+  char            vit_opcode [ sizeof (vax_opcodeT) ];
+  unsigned char    vit_opcode_nbytes; /* How long is _opcode? (chars)     */
+  unsigned char    vit_operands;/*                                        */
+  struct vop       vit_operand[VIT_MAX_OPERANDS];  /* operands             */
+  char *          vit_error;   /* "" or error text */
+};
+
+/* end: vax-inst.h */
diff --git a/gas/configure b/gas/configure
new file mode 100755 (executable)
index 0000000..f6bf811
--- /dev/null
@@ -0,0 +1,876 @@
+#!/bin/sh
+# Do not edit this file.  It is generated automatically from configure.in
+# and a configure template.
+configdirs=
+
+#!/bin/sh
+# Do not edit this file.  It is generated automatically from configure.in
+# and a configure template.
+configdirs=
+
+# Configuration script template
+#   Copyright (C) 1988, 1990, 1991 Free Software Foundation, Inc.
+
+#This file is part of GNU.
+
+#GNU CC 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.
+
+#GNU CC 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 CC; see the file COPYING.  If not, write to
+#the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#
+# Shell script to create proper links to machine-dependent files in
+# preparation for compiling gcc.
+#
+# Usage: configure [+srcdir=DIR] [+host=HOST] [+gas] [+nfp] TARGET
+#
+# If configure succeeds, it leaves its status in config.status.
+# If configure fails after disturbing the status quo, 
+#      config.status is removed.
+#
+
+progname=$0
+
+remove=rm
+hard_link=ln
+symbolic_link='ln -s'
+
+#for Test
+#remove="echo rm"
+#hard_link="echo ln"
+#symbolic_link="echo ln -s"
+
+# clear some things potentially inherited from environment.
+target=
+template=
+removing=
+norecurse=
+ansi=
+
+for arg in $*;
+do
+       case $arg in
+       -ansi | +ansi)
+               ansi=true
+               ;;
+       -template=* | +template=*)
+               template=`echo $arg | sed 's/[+-]template=//'`
+               ;;
+       -norecurse | +norecurse)
+               norecurse=true
+               ;;
+       -rm | +rm)
+               removing=$arg
+               ;;
+       -srcdir=* | +srcdir=* | +srcdi=* | +srcd=* | +src=* | +sr=* | +s=*)
+               srcdir=`echo $arg | sed 's/[+-]s[a-z]*=//'`
+               ;;
+       -host=* | +host=* | +hos=* | +ho=* | +h=*)
+               host=`echo $arg | sed 's/[+-]h[a-z]*=//'`
+               ;; 
+       -languages=* | +languages=* | -languag=* | +languag=* | langua=* \
+               | +langua=* | -langu=* | +langu=* | -lang=* | +lang=* | -lan=* \
+               | +lan=* | -la=* | +la=* | -l=* | +l=*)
+               languages="$languages `echo $arg | sed 's/[+-]l[a-z]*=//'`"
+               ;;
+       -gas | +gas | +ga | +g)
+               gas=yes
+               ;;
+       -nfp | +nfp | +nf | +n)
+               nfp=yes
+               ;;
+       *)
+# Allow configure HOST TARGET
+               if [ x$host = x ] ; then host=$target ; fi
+               target=$arg
+               ;;
+       esac
+done
+
+# process host and target only if not rebuilding configure itself.
+if [ -z "$template" ]
+then
+       # Complain if an arg is missing
+       if [ x$target = x ]
+       then
+               echo "Usage: $progname [+srcdir=DIR] [+host=HOST] [+gas] [+nfp] TARGET"
+               echo -n "Where HOST and TARGET are something like "
+               echo "\`vax', \`sun3', \`encore', etc."
+               if [ -r config.status ]
+               then
+                       cat config.status
+               fi
+               exit 1
+       fi
+
+       # Default other arg
+       if [ x$host = x ]
+       then
+               host=$target
+       fi
+
+       # Decode the host machine, then the target machine.
+       # For the host machine, we save the xm_file variable as host_xm_file;
+       # then we decode the target machine and forget everything else
+       # that came from the host machine.
+       for machine in $host $target; do
+
+               # Separate what the user gave into CPU/company and OS (if any).
+               basic_machine=`echo $machine | sed 's/-[^-]*$//'`
+               if [ $basic_machine != $machine ]
+               then os=`echo $machine | sed 's/[^-]*-/-/'`
+               else os=; fi
+
+               # Decode aliases for certain machine/company combinations.
+               case $basic_machine in
+                       iris | iris4d)
+                               basic_machine=mips/sgi
+                               ;;
+                       news | news800)
+                               basic_machine=m68k/sony
+                               ;;
+                       3b1 | 7300 | 7300/att | att-7300)
+                               basic_machine=m68k/att
+                               ;;
+                       delta | 3300 | motorola-3300 | motorola-delta \
+                             | 3300/motorola | delta/motorola)
+                               basic_machine=m68k/motorola
+                               ;;
+                       vax/dec)
+                               basic_machine=vax
+                               ;;
+                       balance)
+                               basic_machine=ns32k/sequent
+                               ;;
+                       symmetry)
+                               basic_machine=i386/sequent
+                               ;;
+                       sun2)
+                               basic_machine=m68000/sun
+                               ;;
+                       sun3)
+                               basic_machine=m68k/sun
+                               ;;
+                       sun4)
+                               basic_machine=sparc/sun
+                               ;;
+                       sun386 | sun386i)
+                               basic_machine=i386/sun
+                               ;;
+                       ps2)
+                               basic_machine=i386/ibm
+                               ;;
+                       next)
+                               basic_machine=m68k/next
+                               ;;
+                       hp9k3[2-9][0-9])
+                               basic_machine=m68k/hp
+                               ;;
+                       hp9k31[0-9] | hp9k2[0-9][0-9])
+                               basic_machine=m68000/hp
+                               ;;
+                       isi68)
+                               basic_machine=m68k/isi
+                               ;;
+                       apollo68)
+                               basic_machine=m68k/apollo
+                               ;;
+                       altos | altos3068)
+                               basic_machine=m68k/altos
+                               ;;
+                       miniframe)
+                               basic_machine=m68000/convergent
+                               ;;
+                       tower | tower-32)
+                               basic_machine=m68k/ncr
+                               ;;
+                       news-3600 | risc-news)
+                               basic_machine=mips/sony
+                               ;;
+                       decstation | decstation-3100 | pmax)
+                               basic_machine=mips/dec
+                               ;;
+                       gmicro)
+                               basic_machine=tron
+                               ;;
+                       convex-c1)
+                               basic_machine=c1/convex
+                               ;;
+                       convex-c2)
+                               basic_machine=c2/convex
+                               ;;
+               esac
+
+               # Decode manufacturer-specific aliases for certain operating systems.
+
+               case $os in
+                       -newsos*)
+                               os=-bsd
+                               ;;
+                       -ultrix*)
+                               os=-bsd
+                               ;;
+                       -dynix*)
+                               os=-bsd
+                               ;;
+                       -ctix*)
+                               os=-sysv
+                               ;;
+               esac
+
+               machine=$basic_machine$os
+
+               cpu_type=
+               xm_file=
+               tm_file=
+               make_var_file=
+
+               case $machine in
+               vax | vax-bsd*)                 # vaxen running BSD
+                       ;;
+               vax-vms | vms)                  # vaxen running VMS
+                       cpu_type=vax
+                       xm_file=xm-vms.h
+                       tm_file=tm-vms.h
+                       ;;
+               vax-sysv* | vaxv)               # vaxen running system V
+                       cpu_type=vax
+                       xm_file=xm-vaxv.h
+                       tm_file=tm-vaxv.h
+                       ;;
+               tahoe | tahoe-bsd*)             # tahoe running BSD
+                       ;;
+               tahoe/harris*)                  # Harris tahoe, using COFF.
+                       cpu_type=tahoe
+                       ;;
+               i386/sequent* | i386/sequent-bsd*)  # 80386 from Sequent
+                       cpu_type=i386
+                       xm_file=xm-i386.h
+                       tm_file=tm-seq386.h
+                       ;;
+               i386-mach | i386/*-mach)
+                       cpu_type=i386
+                       xm_file=xm-i386.h
+                       tm_file=tm-i386gas.h
+                       ;;
+               i386/sco | i386/sco-sysv* | i386/*-sco) # 80386 running SCO system
+                       cpu_type=i386
+                       xm_file=xm-i386v.h
+                       tm_file=tm-i386sco.h
+                       make_var_file=make-i386sco
+                       ;;
+               i386/isc | i386/isc-sysv* | i386/*-isc) # 80386 running ISC system
+                       cpu_type=i386
+                       xm_file=xm-i386v.h
+                       tm_file=tm-i386isc.h
+                       make_var_file=make-i386isc
+                       ;;
+               i386/ibm | i386-aix | i386/ibm-aix)     # IBM PS/2 running AIX
+                       cpu_type=i386
+                       tm_file=tm-i386v.h
+                       xm_file=xm-i386v.h
+                       make_var_file=make-i386v
+                       ;;
+               i386/sun*)
+                       cpu_type=i386
+                       xm_file=xm-sun386i.h
+                       tm_file=tm-sun386i.h
+                       ;;
+               i386-sysv4 | i386/*-sysv4 | i386v4)  # Intel 80386's running system V.4
+                       cpu_type=i386
+                       xm_file=xm-i386v.h
+                       make_var_file=make-i386v
+                       tm_file=tm-i386v4.h
+                       ;;
+               i386-sysv* | i386/*-sysv* | i386v)  # Intel 80386's running system V
+                       cpu_type=i386
+                       xm_file=xm-i386v.h
+                       make_var_file=make-i386v
+                       if [ x$gas = xyes ]
+                       then
+                               tm_file=tm-i386gas.h
+                       else
+                               tm_file=tm-i386v.h
+                       fi
+                       ;;
+               i860 | i860-sysv* | i860/*-sysv*)
+                       cpu_type=i860
+                       if [ x$gas = xyes ]
+                       then
+                               tm_file=tm-i860g.h
+                       else
+                               tm_file=tm-i860.h
+                       fi
+                       ;;
+               i860-bsd* | i860/*-bsd*)
+                       cpu_type=i860
+                       if [ x$gas = xyes ]
+                       then
+                               tm_file=tm-i860bsdg.h
+                       else
+                               tm_file=tm-i860bsd.h
+                       fi
+                       ;;
+               sparc | sparc/* | sparc-*os4 | sparc/*-*os4)
+                       cpu_type=sparc
+                       tm_file=tm-sparc.h
+                       ;;
+               sparc-*os3 | sparc/*-*os3)
+                       cpu_type=sparc
+                       tm_file=tm-sun4os3.h
+                       ;;
+               m68k/next)
+                       cpu_type=m68k
+                       tm_file=tm-next.h
+                       out_file=out-next.c
+                       xm_file=xm-next.h
+                       ;;
+               m68k/sun-*os3)
+                       cpu_type=m68k
+                       if [ x$nfp = xyes ]
+                       then
+                               tm_file=tm-sun3os3nf.h
+                       else
+                               tm_file=tm-sun3os3.h
+                       fi
+                       ;;
+               m68k/sun-mach)
+                       cpu_type=m68k
+                       tm_file=tm-sun3mach.h
+                       ;;
+               m68k/sun | m68k/sun-*os4)
+                       cpu_type=m68k
+                       if [ x$nfp = xyes ]
+                       then
+                               tm_file=tm-sun3nfp.h
+                       else
+                               tm_file=tm-sun3.h
+                       fi
+                       ;;
+               m68k/hp | m68k/hp-hpux*)        # HP 9000 series 300
+                       cpu_type=m68k
+                       xm_file=xm-hp9k320.h
+                       if [ x$gas = xyes ]
+                       then
+                               make_var_file=make-hp9k320g
+                               tm_file=tm-hp9k320g.h
+                       else
+                               make_var_file=make-hp9k320
+                               tm_file=tm-hp9k320.h
+                       fi
+                       ;;
+               m68k/hp-bsd*)                   # HP 9000/3xx running Berkeley Unix
+                       cpu_type=m68k
+                       tm_file=tm-hp9k3bsd.h
+                       ;;
+               m68k/isi | m68k/isi-bsd*)
+                       cpu_type=m68k
+                       if [ x$nfp = xyes ]
+                       then
+                               tm_file=tm-isi68-nfp.h
+                       else
+                               tm_file=tm-isi68.h
+                       fi
+                       ;;
+               m68k/sony | m68k/sony-bsd*)
+                       xm_file=xm-m68k.h
+                       cpu_type=m68k
+                       if [ x$gas = xyes ]
+                       then
+                               tm_file=tm-newsgas.h
+                       else
+                               tm_file=tm-news.h
+                       fi
+                       ;;
+               m68k/altos | m68k/altos-sysv*)             # Altos 3068
+                       cpu_type=m68k
+                       if [ x$gas = xyes ]
+                       then
+                               xm_file=xm-altos3068.h
+                               tm_file=tm-altos3068.h
+                       else
+                               echo "The Altos is supported only with the GNU assembler" 1>&2
+                               exit 1
+                       fi
+                       ;;
+               m68k/motorola | m68k/motorola-sysv*)
+                       cpu_type=m68k
+                       tm_file=tm-mot3300.h
+                       xm_file=xm-mot3300.h
+                       ;;
+               m68k/crds | m68k/crds-unos | m68k-unos | crds | unos)
+                       cpu_type=m68k
+                       xm_file=xm-crds.h
+                       make_var_file=make-crds
+                       tm_file=tm-crds.h
+                       ;;
+               m68k/apollo)
+                       cpu_type=m68k
+                       make_var_file=make-apollo68
+                       tm_file=tm-apollo68.h
+                       ;;
+               m68k/ncr | m68k/ncr-sysv*)      # NCR Tower 32 SVR3
+                       cpu_type=m68k
+                       tm_file=tm-tower-as.h
+                       xm_file=xm-tower.h
+                       ;;
+               m68000/sun | m68000/sun-*os3)
+                       cpu_type=m68k
+                       tm_file=tm-sun2.h
+                       ;;
+               m68000/sun-*os4)
+                       cpu_type=m68k
+                       tm_file=tm-sun2os4.h
+                       ;;
+               m68000/hp | m68000/hp-hpux*)    # HP 9000 series 300
+                       cpu_type=m68k
+                       xm_file=xm-hp9k310.h
+                       if [ x$gas = xyes ]
+                       then
+                               make_var_file=make-hp9k320g
+                               tm_file=tm-hp9k310g.h
+                       else
+                               make_var_file=make-hp9k320
+                               tm_file=tm-hp9k310.h
+                       fi
+                       ;;
+               m68000/hp-bsd*)                 # HP 9000/200 running BSD
+                       cpu_type=m68k
+                       tm_file=tm-hp9k2bsd.h
+                       make_var_file=make-hp9k2bsd
+                       ;;
+               m68000/att | m68000/att-sysv*)
+                       cpu_type=m68k
+                       xm_file=xm-3b1.h
+                       if [ x$gas = xyes ]
+                       then
+                               tm_file=tm-3b1g.h
+                       else
+                               tm_file=tm-3b1.h
+                       fi
+                       ;;
+               m68000/convergent | m68000/convergent-sysv*)
+                       cpu_type=m68k
+                       xm_file=xm-3b1.h
+                       tm_file=tm-ctix.h
+                       ;;
+               ns32k/sequent | ns32k/sequent-bsd*)
+                       cpu_type=ns32k
+                       tm_file=tm-sequent.h
+                       ;;
+               ns32k/encore | ns32k/encore-bsd* | encore | encore-bsd*)
+                       cpu_type=ns32k
+                       tm_file=tm-encore.h
+                       ;;
+               ns32k-genix* | ns32k/*-genix* | genix)
+                       cpu_type=ns32k
+                       xm_file=xm-genix.h
+                       make_var_file=make-genix
+                       tm_file=tm-genix.h
+                       ;;
+               merlin)
+                       cpu_type=ns32k
+                       ;;
+               m88k/dg | m88k/dg-dgux* | m88k-dgux*)
+                       cpu_type=m88k
+                       xm_file=xm-m88kdgux.h
+                       make_var_file=make-m88kdgux
+                       tm_file=tm-m88kdgux.h
+                       ;;
+               m88k-v88r32 | m88k/*-v88r32)
+                       cpu_type=m88k
+                       tm_file=tm-v88r32.h
+                       xm_file=xm-v88r32.h
+                       ;;
+               m88k-sysv* | m88k/*-sysv*)
+                       cpu_type=m88k
+                       tm_file=tm-m88ksvr4.h
+                       xm_file=xm-m88ksvr4.h
+                       ;;
+               alliant | alliant/alliant)      # Alliant FX/8
+                       cpu_type=alliant
+                       tm_file=tm-alliant.h
+                       ;;
+               c1/convex)                      # Convex C1
+                       if [ -r /usr/include/stdlib.h ]
+                       then
+                               tm_file=tm-convex1.h
+                       else
+                               tm_file=tm-conv1os7.h
+                       fi
+                       cpu_type=convex
+                       ;;
+               c2/convex)                      # Convex C2
+                       if [ -r /usr/include/stdlib.h ]
+                       then
+                               tm_file=tm-convex2.h
+                       else
+                               tm_file=tm-conv2os7.h
+                       fi
+                       cpu_type=convex
+                       ;;
+               mips/sgi | mips/sgi-sysv*)      # Mostly like a MIPS.
+                       cpu_type=mips
+                       tm_file=tm-iris.h
+                       xm_file=xm-iris.h
+                       ;;
+               mips | mips/mips)               # Default MIPS environment.
+                       ;;
+               mips/dec | mips/dec-bsd*)       # Decstation.
+                       cpu_type=mips
+                       tm_file=tm-decstatn.h
+                       ;;
+               mips/sony | mips/sony-bsd*)     # Sony NEWS 3600 or risc/news.
+                       cpu_type=mips
+                       tm_file=tm-mips-news.h
+                       ;;
+               mips/*-sysv* | mips-sysv*)      # SYSV variant of MIPS system.
+                       cpu_type=mips
+                       tm_file=tm-mips-sysv.h
+                       ;;
+               mips/*-bsd* | mips-bsd*)        # BSD 4.3 variant of MIPS system.
+                       cpu_type=mips
+                       tm_file=tm-mips-bsd.h
+                       ;;
+               pyramid | pyramid/* | pyramid-*)
+                       cpu_type=pyr
+                       tm_file=tm-pyr.h
+                       ;;
+               tron | tron/*)
+                       cpu_type=gmicro
+                       tm_file=tm_gmicro.h
+                       ;;
+               a29k-bsd* | a29k/*-bsd*)
+                       cpu_type=a29k
+                       tm_file=tm-a29kunix.h
+                       ;;
+               i960)                           # Default i960 environment.
+                       ;;
+       #       370)
+       #               ;;
+               esac
+               if [ x$pass1done = x ]
+               then
+                       if [ x$cpu_type = x ]; then cpu_type=$host; fi
+                       if [ x$xm_file = x ]; then host_xm_file=xm-$cpu_type.h
+                       else host_xm_file=$xm_file
+                       fi
+                       if [ x$make_var_file = x ]
+                       then make_var_file=make-$cpu_type; fi
+                       host_make_var_file=$make_var_file
+                       pass1done=yes
+               fi
+       done
+
+       # Default the machine-specific variables that were not explicitly set.
+       if [ x$cpu_type = x ]
+       then cpu_type=$target; fi
+
+       if [ x$tm_file = x ]
+       then tm_file=tm-$target.h; fi
+
+       md_file=${cpu_type}.md
+
+       if [ x$out_file = x ]
+       then out_file=out-$cpu_type.c; fi
+fi
+
+#### configure.in files go here.
+# This file is a shell script that supplies the information necessary
+# to tailor a template configure script into the configure script
+# appropriate for this directory.  For more information, check any
+# existing configure script.
+
+srctrigger=as.c
+srcname="gas"
+
+case $target in
+*-coff)
+       obj_format=coff
+       ;;
+*-bout)
+       obj_format=bout
+       ;;
+*)
+       obj_format=aout
+       ;;
+esac
+
+case $target in
+vax)
+       atof=vax
+       ;;
+*)
+       atof=ieee
+       ;;
+esac
+
+files="ho-${host}.h tc-${cpu_type}.c tc-${cpu_type}.h te-generic.h obj-${obj_format}.h obj-${obj_format}.c atof-${atof}.c"
+links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c"
+### end of configure.in
+
+# are we rebuilding config itself?
+if [ -n "$template" ]
+then
+       if [ ! -r $template ]
+       then
+               echo "Can't find template ${template}."
+               exit 1
+       fi
+
+       mv configure configure.old
+       echo "#!/bin/sh" > configure
+       echo "# Do not edit this file.  It is generated automatically from configure.in" >> configure
+       echo "# and a configure template." >> configure
+       echo "configdirs=" >> configure
+       echo >> configure
+
+       if [ -r configure.in ]
+       then
+               sed -e "/^####/  r configure.in" $template >> configure
+       else
+               cat $template >> configure
+       fi
+
+       chmod a+x configure
+       rm configure.old
+#      echo Rebuilt configure in `pwd` from ${template}.
+       echo Rebuilt configure in `pwd`
+
+       if [ x$norecurse = x ]
+       then
+               while [ -n "$configdirs" ]
+               do
+                       # set configdir to car of configdirs, configdirs to cdr of configdirs
+                       set $configdirs; configdir=$1; shift; configdirs=$*
+
+                       if [ "`echo ${configdir}.*`" != "${configdir}.*" ]
+                       then
+                               targetspecificdirs=${configdir}.*
+                       else
+                               targetspecificdirs=
+                       fi
+
+                       for i in ${configdir} ${targetspecificdirs}
+                       do
+                               if [ -r $i/configure ]
+                               then
+                                       (cd $i ;
+                                               configure +template=${template})
+                               else
+                                       echo No configure script in `pwd`/$i
+                               fi
+                       done
+               done
+       fi
+
+       exit 0
+fi
+
+# Temporarily, we support only direct subdir builds.
+hostsubdir=Host-$host
+targetsubdir=Target-$target
+
+if [ -n "$removing" ]
+then
+       rm -rf $hostsubdir/$targetsubdir
+
+       if [ -z "`(ls $hostsubdir) 2>&1 | grep Target-`" ]
+       then
+               rm -rf $hostsubdir
+       fi
+else
+       if [ ! -d $hostsubdir ] ; then mkdir $hostsubdir ; fi
+       cd $hostsubdir
+
+       if [ ! -d $targetsubdir ] ; then mkdir $targetsubdir ; fi
+       cd $targetsubdir
+
+       srcdir=../..
+
+       ## Find the source files, if location was not specified.
+       #if [ x$srcdir = x ]
+       #then
+       #       srcdirdefaulted=1
+       #       srcdir=.
+       #       if [ ! -r ${srctrigger} ]
+       #       then
+       #               srcdir=..
+       #       fi
+       #fi
+       #
+       #if [ ! -r ${srcdir}/${srctrigger} ]
+       #then
+       #       if [ x$srcdirdefaulted = x ]
+       #       then
+       #         echo "$progname: Can't find ${srcname} sources in \`${srcdir}'." 1>&2
+       #       else
+       #         echo "$progname: Can't find ${srcname} sources in \`.' or \`..'." 1>&2
+       #       fi
+       #       exit 1
+       #fi
+
+
+
+       # Set up the list of links to be made.
+       # $links is the list of link names, and $files is the list of names to link to.
+
+       # Make the links.
+       while [ -n "$files" ]
+       do
+               # set file to car of files, files to cdr of files
+               set $files; file=$1; shift; files=$*
+               set $links; link=$1; shift; links=$*
+
+               if [ ! -r ${srcdir}/config/$file ]
+               then
+                       echo "$progname: cannot create a link \`$link'," 1>&2
+                       echo "since the file \`config/$file' does not exist." 1>&2
+                       exit 1
+               fi
+
+               $remove -f $link
+               rm -f config.status
+               # Make a symlink if possible, otherwise try a hard link
+               $symbolic_link ${srcdir}/config/$file $link 2>/dev/null || $hard_link ${srcdir}/config/$file $link
+
+               if [ ! -r $link ]
+               then
+                       echo "$progname: unable to link \`$link' to \`${srcdir}/config/$file'." 1>&2
+                       exit 1
+               fi
+               echo "Linked \`$link' to \`${srcdir}/config/$file'."
+       done
+
+       # Install a makefile, and make it set VPATH
+       # if necessary so that the sources are found.
+       # Also change its value of srcdir.
+       # Also create a .gdbinit file which runs the one in srcdir
+       # and tells GDB to look there for source files.
+       case $srcdir in
+       .)
+               ;;
+       *)
+               echo "VPATH = ${srcdir}" > x
+               cat x ${srcdir}/Makefile.in | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.in
+               rm x
+               echo "dir ." > .gdbinit
+               echo "dir ${srcdir}" >> .gdbinit
+               echo "source ${srcdir}/.gdbinit" >> .gdbinit
+               ;;
+       esac
+
+       host_var_file=hmake-${host}
+       target_var_file=tmake-${target}
+
+       # Conditionalize the makefile for this machine.
+       if [ -f ${srcdir}/config/${host_var_file} ]
+       then
+               sed -e "/^####/  r ${srcdir}/config/${host_var_file}" Makefile.in > Makefile.tem
+       else
+               cp Makefile.in Makefile.tem
+       fi
+
+       if [ -f ${srcdir}/config/${target_var_file} ]
+       then
+               sed -e "/^####/  r ${srcdir}/config/${target_var_file}" Makefile.tem > Makefile.tem1
+               mv Makefile.tem1 Makefile.tem
+       fi
+
+       # Remove all formfeeds, since some Makes get confused by them.
+       sed "s/\f//" Makefile.tem >> Makefile.tem1
+       mv Makefile.tem1 Makefile.tem
+
+       # reset SUBDIRS
+       sed "s:^SUBDIRS =.*$:SUBDIRS = ${configdirs}:" Makefile.tem > Makefile.tem1
+       mv Makefile.tem1 Makefile.tem
+
+       # reset NONSUBDIRS
+       sed "s:^NONSUBDIRS =.*$:NONSUBDIRS = ${noconfigdirs}:" Makefile.tem > Makefile.tem1
+       mv Makefile.tem1 Makefile.tem
+
+       # Delete the intermediate files
+       if [ x$srcdir != x. ] ; then rm Makefile.in ; fi
+
+       rm -f Makefile
+
+       # Define macro CROSS_COMPILE in compilation if this is a cross-compiler.
+       if [ x$host != x$target ]
+       then
+               echo "CROSS=-DCROSS_COMPILE" > Makefile
+               echo "ALL=start.encap" >> Makefile
+       else
+               echo "ALL=all.internal" > Makefile
+       fi
+
+       # set target and host
+       echo "host = $host" >> Makefile
+       echo "target = $target" >> Makefile
+
+       cat Makefile.tem >> Makefile
+       rm Makefile.tem
+
+       using=
+       if [ -f ${srcdir}/config/${host_var_file} ]
+       then
+               using=" using \"${host_var_file}\""
+       fi
+
+       if [ -f ${srcdir}/config/${target_var_file} ]
+       then
+               if [ -z "${using}" ]
+               then
+                       andusing=" using \"${target_var_file}\""
+               else
+                       andusing="${using} and \"${target_var_file}\""
+               fi
+       else
+               andusing=${using}
+       fi
+
+       echo "Created \"Makefile\""${andusing}.
+
+       if [ x$host = x$target ]
+       then
+               echo "Links are now set up for use with a $target." \
+                       | tee ${srcdir}/config.status
+       else
+               echo "Links are now set up for host $host and target $target." \
+                       | tee ${srcdir}/config.status
+       fi
+
+       cd ${srcdir}
+fi
+
+# If there are subdirectories, then recurse. 
+
+if [ x$norecurse != x ] ; then exit 0 ; fi
+
+while [ -n "$configdirs" ]
+do
+       # set configdir to car of configdirs, configdirs to cdr of configdirs
+       set $configdirs; configdir=$1; shift; configdirs=$*
+
+       # check for target override
+       targetspecificdir=${configdir}.${target}
+       if [ -d ${targetspecificdir} ]
+       then
+               configdir=${targetspecificdir}
+       fi
+
+       echo Configuring ${configdir}...
+       (cd ${configdir} ;
+               configure +host=${host} ${target} ${removing}) \
+               | sed 's/^/     /'
+done
+
+exit 0
diff --git a/gas/configure.in b/gas/configure.in
new file mode 100644 (file)
index 0000000..4da7737
--- /dev/null
@@ -0,0 +1,31 @@
+# This file is a shell script that supplies the information necessary
+# to tailor a template configure script into the configure script
+# appropriate for this directory.  For more information, check any
+# existing configure script.
+
+srctrigger=as.c
+srcname="gas"
+
+case $target in
+*-coff)
+       obj_format=coff
+       ;;
+*-bout)
+       obj_format=bout
+       ;;
+*)
+       obj_format=aout
+       ;;
+esac
+
+case $target in
+vax)
+       atof=vax
+       ;;
+*)
+       atof=ieee
+       ;;
+esac
+
+files="ho-${host}.h tc-${cpu_type}.c tc-${cpu_type}.h te-generic.h obj-${obj_format}.h obj-${obj_format}.c atof-${atof}.c"
+links="host.h targ-cpu.c targ-cpu.h targ-env.h obj-format.h obj-format.c atof-targ.c"
diff --git a/gas/configure.was b/gas/configure.was
new file mode 100755 (executable)
index 0000000..2485927
--- /dev/null
@@ -0,0 +1,340 @@
+#!/bin/sh
+# Configuration script for GNU GAS
+#   Copyright (C) 1988, 1990, 1991 Free Software Foundation, Inc.
+
+#This file is not yet 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# $Id$
+
+#
+# Shell script to create proper links to machine-dependent files in
+# preparation for compiling gas.
+#
+# Usage: configure [-srcdir=DIR] [-host=HOST] TARGET
+#
+# If configure succeeds, it leaves its status in config.status.
+# If configure fails after disturbing the status quo, 
+#      config.status is removed.
+#
+
+progname=$0
+
+remove=rm
+hard_link=ln
+symbolic_link='ln -s'
+
+host=
+target=
+
+#for Test
+#remove="echo rm"
+#hard_link="echo ln"
+#symbolic_link="echo ln -s"
+
+for arg in $*;
+do
+  case $arg in
+   -srcdir=* | +srcdir=* | +srcdi=* | +srcd=* | +src=* | +sr=* | +s=*)
+       srcdir=`echo $arg | sed 's/[+-]s[a-z]*=//'`
+       ;;
+   -host=* | +host=* | +hos=* | +ho=* | +h=*)
+       host=`echo $arg | sed 's/[+-]h[a-z]*=//'`
+       ;; 
+   *)
+# Allow configure HOST TARGET
+       if [ x$host = x ]
+       then
+               host=$target
+       fi
+       target=$arg
+       ;;
+  esac
+done
+
+# Complain if an arg is missing
+if [ x$target = x ]
+then
+       echo "Usage: $progname [+srcdir=DIR] [+host=HOST] TARGET"
+       echo -n "Where HOST and TARGET are something like "
+       echo "\`vax', \`sun3', \`encore', etc."
+       if [ -r config.status ]
+       then
+               cat config.status
+       fi
+       exit 1
+fi
+
+# Default other arg
+if [ x$host = x ]
+then
+       host=$target
+fi
+
+# Find the source files, if location was not specified.
+if [ x$srcdir = x ]
+then
+       srcdirdefaulted=1
+       srcdir=.
+       if [ ! -r as.c ]
+       then
+               srcdir=..
+       fi
+fi
+
+if [ ! -r ${srcdir}/as.c ]
+then
+       if [ x$srcdirdefaulted = x ]
+       then
+         echo "$progname: Can't find assembler sources in \`${srcdir}'." 1>&2
+       else
+         echo "$progname: Can't find assembler sources in \`.' or \`..'." 1>&2
+       fi
+       exit 1
+fi
+
+# Decode the host machine, then the target machine.
+# For the host machine, we save the ho variable as host_ho;
+# then we decode the target machine and forget everything else
+# that came from the host machine.
+for machine in $host $target; do
+       tc=
+       obj=
+
+       host_header=
+       obj_header=
+       obj_source=
+       te_header=
+       tc_header=
+       tc_source=
+
+       make_var_file=
+
+       case $machine in
+       generic)
+               ;;
+       i860)
+               tc=i860
+               obj=aout
+               ;;
+       pmax | dec3100)
+               ho=pmax
+               ;;
+       sun386)
+               ho=sun386
+               ;;
+       sun4 | sun4-aout | sun-4 | sun4-os4 | sun-4-os4)
+               ho=sun4
+               tc=sparc
+               obj=aout
+               ;;
+       sun4-bout)
+               tc=sparc
+               obj=bout
+               ;;
+       sun4-bfd-sunos)
+               tc=sparc
+               obj=bfd-sunos
+               ;;
+       i960 | i960-coff)
+               tc=i960
+               obj=coff
+               te=ic960
+               ;;
+       i960-bout)
+               tc=i960
+               obj=bout
+               ;;
+       i960-aout)
+               tc=i960
+               obj=aout
+               ;;
+       sun3 | sun3-aout)
+               ho=sun3
+               tc=m68k
+               obj=aout
+               te=sun3
+               ;;
+       a29k | a29k-aout)
+               tc=a29k
+               obj=aout
+               ;;
+       a29k-coff)
+               tc=a29k
+               obj=coff
+               ;;
+       i386)
+               tc=i386
+               obj=aout
+               ;;
+       ns32k)
+               tc=ns32k
+               obj=aout
+               ;;
+       vax)
+               tc=vax
+               obj=aout
+               ;;
+       rs6000)
+               ;;
+       esac
+       if [ x$pass1done = x ]
+       then
+               if [ x$ho = x ]; then ho=$host; fi
+               if [ x$ho_header = x ]; then ho_ho_header=ho-$ho.h
+               else ho_ho_header=$ho_header
+               fi
+               if [ x$make_var_file = x ]
+               then make_var_file=make-$ho; fi
+               ho_make_var_file=$make_var_file
+               pass1done=yes
+       else
+               host_make_var_file=$ho_make_var_file
+               ho_header=$ho_ho_header
+       fi
+done
+
+
+# Default the machine-specific variables that were not explicitly set.
+if [ x$te = x ]
+then te=generic; fi
+
+if [ x$te_header = x ]
+then te_header=te-$te.h; fi
+
+
+if [ x$tc = x ]
+then tc=generic; fi
+
+if [ x$tc_header = x ]
+then tc_header=tc-$tc.h; fi
+
+if [ x$tc_source = x ]
+then tc_source=tc-$tc.c; fi
+
+
+if [ x$obj = x ]
+then obj=generic; fi
+
+if [ x$obj_header = x ]
+then obj_header=obj-$obj.h; fi
+
+if [ x$obj_source = x ]
+then obj_source=obj-$obj.c; fi
+
+
+if [ x$atof_source = x ]
+then atof_source=atof-ieee.c; fi
+
+# Set up the list of links to be made.
+# $links is the list of link names, and $files is the list of names to link to.
+files="$ho_header $te_header $tc_header $tc_source $obj_header $obj_source $atof_source"
+links="host.h targ-env.h targ-cpu.h targ-cpu.c obj-format.h obj-format.c atof-targ.c"
+
+# Make the links.
+while [ -n "$files" ]
+do
+       # set file to car of files, files to cdr of files
+       set $files; file=$1; shift; files=$*
+       set $links; link=$1; shift; links=$*
+
+       if [ ! -r ${srcdir}/config/$file ]
+       then
+               echo "$progname: cannot create a link \`$link'," 1>&2
+               echo "since the file \`config/$file' does not exist." 1>&2
+               exit 1
+       fi
+
+       $remove -f $link
+       rm -f config.status
+       # Make a symlink if possible, otherwise try a hard link
+       $symbolic_link ${srcdir}/config/$file $link 2>/dev/null || $hard_link ${srcdir}/config/$file $link
+
+       if [ ! -r $link ]
+       then
+               echo "$progname: unable to link \`$link' to \`${srcdir}/config/$file'." 1>&2
+               exit 1
+       fi
+       echo "Linked \`$link' to \`${srcdir}/config/$file'."
+done
+
+# Build a Makefile
+
+# Install a makefile, and make it set srcdir
+# if necessary so that the sources are found.
+# Also change its value of srcdir.
+# Also create a .gdbinit file which runs the one in srcdir
+# and tells GDB to look there for source files.
+case $srcdir in
+.)
+       ;;
+*)
+       echo "VPATH = ${srcdir}" > x
+       cat x ${srcdir}/Makefile.in | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.in
+       rm x
+       echo "dir ." > .gdbinit
+       echo "dir ${srcdir}" >> .gdbinit
+       echo "source ${srcdir}/.gdbinit" >> .gdbinit
+       ;;
+esac
+
+# Conditionalize the makefile for this machine.
+if [ -f ${srcdir}/config/${host_make_var_file} ]
+then
+       sed -e "/####/  r ${srcdir}/config/${host_make_var_file}" Makefile.in > Makefile.tem
+else
+       cp Makefile.in Makefile.tem
+fi
+
+# Remove all formfeeds, since some Makes get confused by them.
+sed "s/\f//" Makefile.tem > Makefile.tem1
+
+# Delete the intermediate files
+rm Makefile.tem
+if [ x$srcdir != x. ]
+then
+       rm Makefile.in
+fi
+
+
+# actual Makefile starts here.
+
+echo "host = $host" > Makefile
+echo "target = $target" >> Makefile
+
+# Define macro CROSS_ASSEMBLE in compilation if this is a cross-assembler.
+if [ x$host = x$target ]
+then
+       sed "/^ALL=gas/s//ALL=bootstrap/" < Makefile.tem1 >> Makefile
+else
+       echo "CROSS=-DCROSS_ASSEMBLE" >> Makefile
+       cat Makefile.tem1 >> Makefile
+fi
+
+rm Makefile.tem1
+
+echo "Edited the makefile"
+
+if [ x$host = x$target ]
+then
+       echo "Links are now set up for use with a $target." \
+               | tee config.status
+else
+       echo "Links are now set up for host $host and target $target." \
+               | tee config.status
+fi
+
+exit 0
diff --git a/gas/debug.c b/gas/debug.c
new file mode 100644 (file)
index 0000000..c1e1dbe
--- /dev/null
@@ -0,0 +1,79 @@
+/* Routines for debug use only.  Don't link into product.
+ */
+
+#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 );
+       }
+}
diff --git a/gas/expr.c b/gas/expr.c
new file mode 100644 (file)
index 0000000..c62e39c
--- /dev/null
@@ -0,0 +1,966 @@
+/* expr.c -operands, expressions-
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * 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"
+
+#ifdef __STDC__
+static void clean_up_expression(expressionS *expressionP);
+#else /* __STDC__ */
+static void clean_up_expression();     /* Internal. */
+#endif /* __STDC__ */
+extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */
+extern const char FLT_CHARS[];
+
+#ifdef LOCAL_LABELS_DOLLAR
+extern int local_label_defined[];
+#endif
+
+/*
+ * Build any floating-point literal here.
+ * Also build any bignum literal here.
+ */
+
+/* LITTLENUM_TYPE      generic_buffer [6]; */  /* JF this is a hack */
+/* 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;
+\f
+/*
+ * Summary of operand().
+ *
+ * in: Input_line_pointer points to 1st char of operand, which may
+ *     be a space.
+ *
+ * out:        A expressionS. X_seg determines how to understand the rest of the
+ *     expressionS.
+ *     The operand may have been empty: in this case X_seg == SEG_ABSENT.
+ *     Input_line_pointer->(next non-blank) char after operand.
+ *
+ */
+\f
+static segT
+operand (expressionP)
+     register expressionS *    expressionP;
+{
+  register char c;
+  register char *name; /* points to name of symbol */
+  register symbolS *   symbolP; /* Points to symbol */
+
+  extern  char hex_value[];    /* In hex_value.c */
+
+  SKIP_WHITESPACE();           /* Leading whitespace is part of operand. */
+  c = * input_line_pointer ++; /* Input_line_pointer->past char in c. */
+  if (isdigit(c))
+    {
+      register valueT  number; /* offset or (absolute) value */
+      register short int digit;        /* value of next digit in current radix */
+                               /* invented for humans only, hope */
+                               /* optimising compiler flushes it! */
+      register short int radix;        /* 2, 8, 10 or 16 */
+                               /* 0 means we saw start of a floating- */
+                               /* point constant. */
+      register short int maxdig = 0;/* Highest permitted digit value. */
+      register int too_many_digits = 0; /* If we see >= this number of */
+                               /* digits, assume it is a bignum. */
+      register char *  digit_2; /*->2nd digit of number. */
+               int small;      /* TRUE if fits in 32 bits. */
+
+      if (c == '0') {                  /* non-decimal radix */
+             if ((c = *input_line_pointer ++)=='x' || c=='X') {
+                     c = *input_line_pointer ++; /* read past "0x" or "0X" */
+                     maxdig = radix = 16;
+                     too_many_digits = 9;
+             } else {
+                     /* If it says '0f' and the line ends or it DOESN'T look like
+                        a floating point #, its a local label ref.  DTRT */
+                     /* likewise for the b's.  xoxorich. */
+                     if ((c == 'f' || c == 'b' || c == 'B')
+                         && (!*input_line_pointer ||
+                             (!strchr("+-.0123456789",*input_line_pointer) &&
+                              !strchr(EXP_CHARS,*input_line_pointer)))) {
+                             maxdig = radix = 10;
+                             too_many_digits = 11;
+                             c = '0';
+                             input_line_pointer -= 2;
+
+                     } else if (c == 'b' || c == 'B') {
+                             c = *input_line_pointer++;
+                             maxdig = radix = 2;
+                             too_many_digits = 33;
+
+                     } else if (c && strchr(FLT_CHARS,c)) {
+                             radix = 0;        /* Start of floating-point constant. */
+                             /* input_line_pointer->1st char of number. */
+                             expressionP->X_add_number =  -(isupper(c) ? tolower(c) : c);
+
+                     } else {          /* By elimination, assume octal radix. */
+                             radix = maxdig = 8;
+                             too_many_digits = 11;
+                     }
+             } /* c == char after "0" or "0x" or "0X" or "0e" etc. */
+      } else {
+             maxdig = radix = 10;
+             too_many_digits = 11;
+      } /* if operand starts with a zero */
+
+      if (radix) {                     /* Fixed-point integer constant. */
+                               /* 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.
+ */
+         digit_2 = 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 - digit_2 < 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;
+                               /* We could just use digit_2, but lets be mnemonic. */
+             input_line_pointer = -- digit_2; /*->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(sizeof (int) * 8 == 32);
+             know(LITTLENUM_NUMBER_OF_BITS == 16);
+             /* Hence the constant "2" in the next line. */
+             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 (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 (number<10)
+               {
+                 if (0
+#ifdef LOCAL_LABELS_FB
+                      || c=='b'
+#endif
+#ifdef LOCAL_LABELS_DOLLAR
+                      || (c=='$' && local_label_defined[number])
+#endif
+                     )
+                   {
+                     /*
+                      * Backward ref to local label.
+                      * Because it is backward, expect it to be DEFINED.
+                      */
+                     /*
+                      * Construct a local label.
+                      */
+                     name = local_label_name ((int)number, 0);
+                     if (((symbolP = symbol_find(name)) != NULL) /* seen before */
+                         && (S_IS_DEFINED(symbolP))) /* symbol is defined: OK */
+                       {               /* Expected path: symbol defined. */
+                         /* Local labels are never absolute. Don't waste time checking absoluteness. */
+                         know((S_GET_SEGMENT(symbolP) == SEG_DATA) || (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+                         expressionP->X_add_symbol = symbolP;
+                         expressionP->X_add_number = 0;
+                         expressionP->X_seg = S_GET_SEGMENT(symbolP);
+                       }
+                     else
+                       {               /* Either not seen or not defined. */
+                         as_bad("Backw. ref to unknown label \"%d:\", 0 assumed.",
+                                 number);
+                         expressionP->X_add_number = 0;
+                         expressionP->X_seg        = SEG_ABSOLUTE;
+                       }
+                   }
+                 else
+                   {
+                     if (0
+#ifdef LOCAL_LABELS_FB
+                         || c == 'f'
+#endif
+#ifdef LOCAL_LABELS_DOLLAR
+                         || (c=='$' && !local_label_defined[number])
+#endif
+                         )
+                       {
+                         /*
+                          * Forward reference. Expect symbol to be undefined or
+                          * unknown. Undefined: seen it before. Unknown: never seen
+                          * it in this pass.
+                          * 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 = local_label_name((int)number, 1);
+                         symbolP = symbol_find_or_make(name);
+                         /* We have no need to check symbol properties. */
+                         know(S_GET_SEGMENT(symbolP) == SEG_UNKNOWN
+                              || S_GET_SEGMENT(symbolP) == SEG_TEXT
+                              || S_GET_SEGMENT(symbolP) == SEG_DATA);
+                         expressionP->X_add_symbol      = symbolP;
+                         expressionP->X_seg             = SEG_UNKNOWN;
+                         expressionP->X_subtract_symbol = NULL;
+                         expressionP->X_add_number      = 0;
+                       }
+                     else
+                       {               /* Really a number, not a local label. */
+                         expressionP->X_add_number = number;
+                         expressionP->X_seg        = SEG_ABSOLUTE;
+                         input_line_pointer --; /* Restore following character. */
+                       }               /* if (c=='f') */
+                   }                   /* if (c=='b') */
+               }
+             else
+               {                       /* Really a number. */
+                 expressionP->X_add_number = number;
+                 expressionP->X_seg        = SEG_ABSOLUTE;
+                 input_line_pointer --; /* Restore following character. */
+               }                       /* if (number<10) */
+           }
+         else
+           {
+             expressionP->X_add_number = number;
+             expressionP->X_seg = SEG_BIG;
+             input_line_pointer --; /*->char following number. */
+           }                   /* if (small) */
+       }                       /* (If integer constant) */
+      else
+       {                       /* 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_seg = SEG_BIG;
+                               /* input_line_pointer->just after constant, */
+                               /* which may point to whitespace. */
+         know(expressionP->X_add_number < 0); /* < 0 means "floating point". */
+       }                       /* if (not floating-point constant) */
+    }
+  else if(c=='.' && !is_part_of_name(*input_line_pointer)) {
+    extern struct obstack frags;
+
+    /*
+       JF:  '.' is pseudo symbol with value of current location in current
+       segment. . .
+ */
+    symbolP = symbol_new("L0\001",
+                        now_seg,
+                        (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
+                        frag_now);
+
+    expressionP->X_add_number=0;
+    expressionP->X_add_symbol=symbolP;
+    expressionP->X_seg = now_seg;
+
+  } else 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.
+       */
+      name =  -- input_line_pointer;
+      c = get_symbol_end();
+      symbolP = symbol_find_or_make(name);
+      /*
+       * If we have an absolute symbol or a reg, then we know its value now.
+       */
+      expressionP->X_seg = S_GET_SEGMENT(symbolP);
+      switch (expressionP->X_seg)
+       {
+       case SEG_ABSOLUTE:
+       case SEG_REGISTER:
+         expressionP->X_add_number = S_GET_VALUE(symbolP);
+         break;
+
+        default:
+         expressionP->X_add_number  = 0;
+         expressionP->X_add_symbol  = symbolP;
+       }
+      * input_line_pointer = c;
+      expressionP->X_subtract_symbol = NULL;
+    }
+  else if (c=='(')/* didn't begin with digit & not a name */
+    {
+      (void)expression(expressionP);
+      /* Expression() will pass trailing whitespace */
+      if (* input_line_pointer ++ != ')')
+       {
+         as_bad("Missing ')' assumed");
+         input_line_pointer --;
+       }
+      /* here with input_line_pointer->char after "(...)" */
+    }
+  else if (c == '~' || c == '-' || c == '+') {
+         /* unary operator: hope for SEG_ABSOLUTE */
+      switch (operand (expressionP)) {
+      case SEG_ABSOLUTE:
+             /* 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.
+                      */
+             } else if (c == '~') {
+                     expressionP->X_add_number = ~ expressionP->X_add_number;
+             } else if (c != '+') {
+                     know(0);
+             } /* switch on unary operator */
+             break;
+
+      case SEG_TEXT:
+      case SEG_DATA:
+      case SEG_BSS:
+      case SEG_PASS1:
+      case SEG_UNKNOWN:
+       if(c=='-') {            /* JF I hope this hack works */
+         expressionP->X_subtract_symbol=expressionP->X_add_symbol;
+         expressionP->X_add_symbol=0;
+         expressionP->X_seg=SEG_DIFFERENCE;
+         break;
+       }
+      default:         /* unary on non-absolute is unsuported */
+       as_bad("Unary operator %c ignored because bad operand follows", c);
+       break;
+       /* Expression undisturbed from operand(). */
+      }
+    }
+  else if (c=='\'')
+    {
+/*
+ * 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_add_number = * input_line_pointer ++;
+      expressionP->X_seg        = SEG_ABSOLUTE;
+    }
+  else
+    {
+                     /* can't imagine any other kind of operand */
+      expressionP->X_seg = SEG_ABSENT;
+      input_line_pointer --;
+      md_operand (expressionP);
+    }
+/*
+ * 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 != ' ');
+  return (expressionP->X_seg);
+} /* operand() */
+\f
+/* Internal. Simplify a struct expression for use by expr() */
+
+/*
+ * In: address of a expressionS.
+ *     The X_seg field of the expressionS may only take certain values.
+ *     Now, we permit SEG_PASS1 to make code smaller & faster.
+ *     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_seg from SEG_DIFFERENCE to SEG_ABSOLUTE;
+ *     Unused fields zeroed to help expr().
+ */
+
+static void
+clean_up_expression (expressionP)
+     register expressionS * expressionP;
+{
+  switch (expressionP->X_seg)
+    {
+    case SEG_ABSENT:
+    case SEG_PASS1:
+      expressionP->X_add_symbol        = NULL;
+      expressionP->X_subtract_symbol   = NULL;
+      expressionP->X_add_number        = 0;
+      break;
+
+    case SEG_BIG:
+    case SEG_ABSOLUTE:
+      expressionP->X_subtract_symbol   = NULL;
+      expressionP->X_add_symbol        = NULL;
+      break;
+
+    case SEG_TEXT:
+    case SEG_DATA:
+    case SEG_BSS:
+    case SEG_UNKNOWN:
+      expressionP->X_subtract_symbol   = NULL;
+      break;
+
+    case SEG_DIFFERENCE:
+      /*
+       * It does not hurt to 'cancel' NULL==NULL
+       * when comparing symbols for 'eq'ness.
+       * It is faster to re-cancel them to NULL
+       * than to check for this special case.
+ */
+      if (expressionP->X_subtract_symbol == expressionP->X_add_symbol
+          || (expressionP->X_subtract_symbol
+             && expressionP->X_add_symbol
+             && expressionP->X_subtract_symbol->sy_frag==expressionP->X_add_symbol->sy_frag
+             && S_GET_VALUE(expressionP->X_subtract_symbol) == S_GET_VALUE(expressionP->X_add_symbol))) {
+             expressionP->X_subtract_symbol    = NULL;
+             expressionP->X_add_symbol         = NULL;
+             expressionP->X_seg                        = SEG_ABSOLUTE;
+      }
+      break;
+
+    case SEG_REGISTER:
+      expressionP->X_add_symbol        = NULL;
+      expressionP->X_subtract_symbol   = NULL;
+      break;
+
+    default:
+      BAD_CASE (expressionP->X_seg);
+      break;
+    }
+} /* clean_up_expression() */
+\f
+/*
+ *                     expr_part ()
+ *
+ * Internal. Made a function because this code is used in 2 places.
+ * Generate error or correct X_?????_symbol of expressionS.
+ */
+
+/*
+ * symbol_1 += symbol_2 ... well ... sort of.
+ */
+
+static segT
+expr_part (symbol_1_PP, symbol_2_P)
+     symbolS **        symbol_1_PP;
+     symbolS * symbol_2_P;
+{
+  segT                 return_value;
+
+  know((* symbol_1_PP)                         == NULL
+       || (S_GET_SEGMENT(*symbol_1_PP) == SEG_TEXT)
+       || (S_GET_SEGMENT(*symbol_1_PP) == SEG_DATA)
+       || (S_GET_SEGMENT(*symbol_1_PP) == SEG_BSS)
+       || (!S_IS_DEFINED(* symbol_1_PP)));
+  know(symbol_2_P             == NULL
+       || (S_GET_SEGMENT(symbol_2_P) == SEG_TEXT)
+       || (S_GET_SEGMENT(symbol_2_P) == SEG_DATA)
+       || (S_GET_SEGMENT(symbol_2_P) == SEG_BSS)
+       || (!S_IS_DEFINED(symbol_2_P)));
+  if (* symbol_1_PP)
+    {
+      if (!S_IS_DEFINED(* symbol_1_PP))
+       {
+         if (symbol_2_P)
+           {
+             return_value = SEG_PASS1;
+             * symbol_1_PP = NULL;
+           }
+         else
+           {
+             know(!S_IS_DEFINED(* symbol_1_PP));
+             return_value = SEG_UNKNOWN;
+           }
+       }
+      else
+       {
+         if (symbol_2_P)
+           {
+             if (!S_IS_DEFINED(symbol_2_P))
+               {
+                 * symbol_1_PP = NULL;
+                 return_value = SEG_PASS1;
+               }
+             else
+               {
+                 /* {seg1} - {seg2} */
+                 as_bad("Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"",
+                         S_GET_NAME(* symbol_1_PP), S_GET_NAME(symbol_2_P));
+                 * symbol_1_PP = NULL;
+                 return_value = SEG_ABSOLUTE;
+               }
+           }
+         else
+           {
+             return_value = S_GET_SEGMENT(* symbol_1_PP);
+           }
+       }
+    }
+  else
+    {                          /* (* symbol_1_PP) == NULL */
+      if (symbol_2_P)
+       {
+         * symbol_1_PP = symbol_2_P;
+         return_value = S_GET_SEGMENT(symbol_2_P);
+       }
+      else
+       {
+         * symbol_1_PP = NULL;
+         return_value = SEG_ABSOLUTE;
+       }
+    }
+  know(return_value == SEG_ABSOLUTE
+       || return_value == SEG_TEXT
+       || return_value == SEG_DATA
+       || return_value == SEG_BSS
+       || return_value == SEG_UNKNOWN
+       || return_value == SEG_PASS1);
+  know((* symbol_1_PP) == NULL
+       || (S_GET_SEGMENT(* symbol_1_PP) == return_value));
+  return (return_value);
+}                              /* expr_part() */
+\f
+/* 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.
+ */
+
+typedef enum
+{
+O_illegal,                     /* (0)  what we get for illegal op */
+
+O_multiply,                    /* (1)  * */
+O_divide,                      /* (2)  / */
+O_modulus,                     /* (3)  % */
+O_left_shift,                  /* (4)  < */
+O_right_shift,                 /* (5)  > */
+O_bit_inclusive_or,            /* (6)  | */
+O_bit_or_not,                  /* (7)  ! */
+O_bit_exclusive_or,            /* (8)  ^ */
+O_bit_and,                     /* (9)  & */
+O_add,                         /* (10) + */
+O_subtract                     /* (11) - */
+}
+operatorT;
+
+#define __ O_illegal
+
+static const 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_left_shift, __, O_right_shift, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, __, __, O_bit_exclusive_or, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __,
+__, __, __, __, O_bit_inclusive_or, __, __, __,
+
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
+};
+
+
+/*
+ *     Rank    Examples
+ *     0       operand, (expression)
+ *     1       + -
+ *     2       & ^ ! |
+ *     3       * / % << >>
+ */
+static const operator_rankT
+op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 };
+\f
+/* Return resultP->X_seg. */
+segT expr(rank, resultP)
+register operator_rankT        rank; /* Larger # is higher rank. */
+register expressionS *resultP; /* Deliver result here. */
+{
+  expressionS          right;
+  register operatorT   op_left;
+  register char c_left;        /* 1st operator character. */
+  register operatorT   op_right;
+  register char c_right;
+
+  know(rank >= 0);
+  (void)operand (resultP);
+  know(* input_line_pointer != ' '); /* Operand() gobbles spaces. */
+  c_left = * input_line_pointer; /* Potential operator character. */
+  op_left = op_encoding [c_left];
+  while (op_left != O_illegal && op_rank [(int) op_left] > rank)
+    {
+      input_line_pointer ++;   /*->after 1st character of operator. */
+                               /* Operators "<<" and ">>" have 2 characters. */
+      if (* input_line_pointer == c_left && (c_left == '<' || c_left == '>'))
+       {
+         input_line_pointer ++;
+       }                       /*->after operator. */
+      if (SEG_ABSENT == expr (op_rank[(int) op_left], &right))
+       {
+         as_warn("Missing operand value assumed absolute 0.");
+         resultP->X_add_number = 0;
+         resultP->X_subtract_symbol    = NULL;
+         resultP->X_add_symbol = NULL;
+         resultP->X_seg = SEG_ABSOLUTE;
+       }
+      know(* input_line_pointer != ' ');
+      c_right = * input_line_pointer;
+      op_right = op_encoding [c_right];
+      if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>'))
+       {
+         input_line_pointer ++;
+       }                       /*->after operator. */
+      know((int) op_right == 0
+          || op_rank [(int) op_right] <= op_rank[(int) op_left]);
+      /* input_line_pointer->after right-hand quantity. */
+      /* left-hand quantity in resultP */
+      /* right-hand quantity in right. */
+      /* operator in op_left. */
+      if (resultP->X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1)
+       {
+         resultP->X_seg = SEG_PASS1;
+       }
+      else
+       {
+         if (resultP->X_seg == SEG_BIG)
+           {
+             as_warn("Left operand of %c is a %s.  Integer 0 assumed.",
+                     c_left, resultP->X_add_number > 0 ? "bignum" : "float");
+             resultP->X_seg = SEG_ABSOLUTE;
+             resultP->X_add_symbol = 0;
+             resultP->X_subtract_symbol = 0;
+             resultP->X_add_number = 0;
+           }
+         if (right . X_seg == SEG_BIG)
+           {
+             as_warn("Right operand of %c is a %s.  Integer 0 assumed.",
+                     c_left, right . X_add_number > 0 ? "bignum" : "float");
+             right . X_seg = SEG_ABSOLUTE;
+             right . X_add_symbol = 0;
+             right . X_subtract_symbol = 0;
+             right . X_add_number = 0;
+           }
+         if (op_left == O_subtract)
+           {
+             /*
+              * Convert - into + by exchanging symbols and negating number.
+              * I know -infinity can't be negated in 2's complement:
+              * but then it can't be subtracted either. This trick
+              * does not cause any further inaccuracy.
+              */
+
+             register symbolS *        symbolP;
+
+             right . X_add_number      = - right . X_add_number;
+             symbolP                   = right . X_add_symbol;
+             right . X_add_symbol      = right . X_subtract_symbol;
+             right . X_subtract_symbol = symbolP;
+             if (symbolP)
+               {
+                 right . X_seg         = SEG_DIFFERENCE;
+               }
+             op_left = O_add;
+           }
+\f
+         if (op_left == O_add)
+           {
+             segT      seg1;
+             segT      seg2;
+
+             know(resultP->X_seg == SEG_DATA
+                  || resultP->X_seg == SEG_TEXT
+                  || resultP->X_seg == SEG_BSS
+                  || resultP->X_seg == SEG_UNKNOWN
+                  || resultP->X_seg == SEG_DIFFERENCE
+                  || resultP->X_seg == SEG_ABSOLUTE
+                  || resultP->X_seg == SEG_PASS1);
+             know(right .  X_seg == SEG_DATA
+                  ||   right .  X_seg == SEG_TEXT
+                  ||   right .  X_seg == SEG_BSS
+                  ||   right .  X_seg == SEG_UNKNOWN
+                  ||   right .  X_seg == SEG_DIFFERENCE
+                  ||   right .  X_seg == SEG_ABSOLUTE
+                  ||   right .  X_seg == SEG_PASS1);
+
+             clean_up_expression (& right);
+             clean_up_expression (resultP);
+
+             seg1 = expr_part (& resultP->X_add_symbol, right . X_add_symbol);
+             seg2 = expr_part (& resultP->X_subtract_symbol, right . X_subtract_symbol);
+             if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) {
+                     need_pass_2 = 1;
+                     resultP->X_seg = SEG_PASS1;
+             } else if (seg2 == SEG_ABSOLUTE)
+                 resultP->X_seg = seg1;
+             else if (seg1 != SEG_UNKNOWN
+                      && seg1 != SEG_ABSOLUTE
+                      && seg2 != SEG_UNKNOWN
+                      && seg1 != seg2) {
+                     know(seg2 != SEG_ABSOLUTE);
+                     know(resultP->X_subtract_symbol);
+
+                     know(seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1== SEG_BSS);
+                     know(seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2== SEG_BSS);
+                     know(resultP->X_add_symbol);
+                     know(resultP->X_subtract_symbol);
+                     as_bad("Expression too complex: forgetting %s - %s",
+                             S_GET_NAME(resultP->X_add_symbol),
+                             S_GET_NAME(resultP->X_subtract_symbol));
+                     resultP->X_seg = SEG_ABSOLUTE;
+                     /* Clean_up_expression() will do the rest. */
+             } else
+                 resultP->X_seg = SEG_DIFFERENCE;
+
+             resultP->X_add_number += right . X_add_number;
+             clean_up_expression (resultP);
+      }
+         else
+           {                   /* Not +. */
+             if (resultP->X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN)
+               {
+                 resultP->X_seg = SEG_PASS1;
+                 need_pass_2 = 1;
+               }
+             else
+               {
+                 resultP->X_subtract_symbol = NULL;
+                 resultP->X_add_symbol = NULL;
+                 /* Will be SEG_ABSOLUTE. */
+                 if (resultP->X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE)
+                   {
+                     as_bad("Relocation error. Absolute 0 assumed.");
+                     resultP->X_seg        = SEG_ABSOLUTE;
+                     resultP->X_add_number = 0;
+                   }
+                 else
+                   {
+                     switch (op_left)
+                       {
+                       case O_bit_inclusive_or:
+                         resultP->X_add_number |= right . X_add_number;
+                         break;
+
+                       case O_modulus:
+                         if (right . X_add_number)
+                           {
+                             resultP->X_add_number %= right . X_add_number;
+                           }
+                         else
+                           {
+                             as_warn("Division by 0. 0 assumed.");
+                             resultP->X_add_number = 0;
+                           }
+                         break;
+
+                       case O_bit_and:
+                         resultP->X_add_number &= right . X_add_number;
+                         break;
+
+                       case O_multiply:
+                         resultP->X_add_number *= right . X_add_number;
+                         break;
+
+                       case O_divide:
+                         if (right . X_add_number)
+                           {
+                             resultP->X_add_number /= right . X_add_number;
+                           }
+                         else
+                           {
+                             as_warn("Division by 0. 0 assumed.");
+                             resultP->X_add_number = 0;
+                           }
+                         break;
+
+                       case O_left_shift:
+                         resultP->X_add_number <<= right . X_add_number;
+                         break;
+
+                       case O_right_shift:
+                         resultP->X_add_number >>= right . X_add_number;
+                         break;
+
+                       case O_bit_exclusive_or:
+                         resultP->X_add_number ^= right . X_add_number;
+                         break;
+
+                       case O_bit_or_not:
+                         resultP->X_add_number |= ~ right . X_add_number;
+                         break;
+
+                       default:
+                         BAD_CASE(op_left);
+                         break;
+                       } /* switch(operator) */
+                   }
+               }               /* If we have to force need_pass_2. */
+           }                   /* If operator was +. */
+       }                       /* If we didn't set need_pass_2. */
+      op_left = op_right;
+    }                          /* While next operator is >= this rank. */
+  return (resultP->X_seg);
+}
+\f
+/*
+ *                     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()
+{
+  register char c;
+
+  while (is_part_of_name(c = * input_line_pointer ++))
+    ;
+  * -- input_line_pointer = 0;
+  return (c);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: expr.c */
diff --git a/gas/expr.h b/gas/expr.h
new file mode 100644 (file)
index 0000000..350215e
--- /dev/null
@@ -0,0 +1,79 @@
+/* expr.h -> header file for expr.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+ * Abbreviations (mnemonics).
+ *
+ *     O       operator
+ *     Q       quantity,  operand
+ *     X       eXpression
+ */
+
+/*
+ * 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-bar+42".
+ * In other words we permit a (possibly undefined) minuend, a
+ * (possibly undefined) subtrahend and an (absolute) augend.
+ * RMS says this is so we can have 1-pass assembly for any compiler
+ * emmissions, and a 'case' statement might emit 'undefined1 - undefined2'.
+ *
+ * To simplify table-driven dispatch, we also have a "segment" for the
+ * entire expression. That way we don't require complex reasoning about
+ * whether particular components are defined; and we can change component
+ * semantics without re-working all the dispatch tables in the assembler.
+ * In other words the "type" of an expression is its segment.
+ */
+
+typedef struct
+{
+       symbolS *X_add_symbol;          /* foo */
+       symbolS *X_subtract_symbol;     /* bar */
+       long X_add_number;              /* 42.    Must be signed. */
+       segT    X_seg;                  /* What segment (expr type)? */
+}
+expressionS;
+
+                               /* result should be type (expressionS *). */
+#define expression(result) expr(0,result)
+
+                               /* If an expression is SEG_BIG, look here */
+                               /* for its value. These common data may */
+                               /* be clobbered whenever expr() is called. */
+extern FLONUM_TYPE generic_floating_point_number; /* Flonums returned here. */
+                               /* Enough to hold most precise flonum. */
+extern LITTLENUM_TYPE generic_bignum []; /* Bignums returned here. */
+#define SIZE_OF_LARGE_NUMBER (20)      /* Number of littlenums in above. */
+
+typedef char operator_rankT;
+
+#ifdef __STDC__
+
+char get_symbol_end(void);
+segT expr(int rank, expressionS *resultP);
+
+#else /* __STDC__ */
+
+char get_symbol_end();
+segT expr();
+
+#endif /* __STDC__ */
+
+/* end: expr.h */
diff --git a/gas/flonum-const.c b/gas/flonum-const.c
new file mode 100755 (executable)
index 0000000..25e7baf
--- /dev/null
@@ -0,0 +1,159 @@
+/* flonum_const.c - Useful Flonum constants
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#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 = 11;
+
+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 [] = {
+ 39321, 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 [] = {
+ 10485, 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 [] = {
+ 52533, 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 [] = {
+ 22516, 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 [] = {
+ 45849, 19069, 18068, 36324, 37948, 48745, 10873, 64360, 15961, 20566,
+ 24178, 15922, 59427,   110                                           };
+static const LITTLENUM_TYPE plus_8 [] = {
+ 15873, 11925, 39177,   991, 14589, 19735, 25347, 65086, 53853,  938,
+ 37209, 47086, 33626, 23253, 32586, 42547,  9731, 59679,  590         };
+
+static const LITTLENUM_TYPE minus_9 [] = {
+ 63601, 55221, 43562, 33661, 29067, 28203, 65417, 64352, 22462, 41110,
+ 12570, 28635, 23199, 50572, 28471, 27074, 46375, 64028, 13106, 63700,
+ 32698, 17493, 32420, 34382, 22750, 20681, 12300                      };
+static const LITTLENUM_TYPE plus_9 [] = {
+ 63564, 61556, 29377, 54467, 18621, 28141, 36415, 61241, 47119, 30026,
+ 19740, 46002, 13541, 61413, 30480, 38664, 32205, 50593, 51112, 48904,
+ 48263, 43814,   286, 30826, 52813, 62575, 61390, 24540, 21495,     5 };
+
+static const LITTLENUM_TYPE minus_10 [] = {
+ 50313, 34681,  1464, 25889, 19575, 41125, 17635,  4598, 49708, 13427,
+ 17287, 56115, 53783, 38255, 32415, 17778, 31596,  7557, 20951, 18477,
+ 40353,  1178, 44405, 11837, 11571, 50963, 15649, 11698, 40675,  2308,  };
+static const LITTLENUM_TYPE plus_10[] = {
+18520, 53764, 54535, 61910, 61962, 59843, 46270, 58053, 12473, 63785,
+ 2449, 43230, 50044, 47595, 10403, 35766, 32607,  1124, 24966, 35044,
+25524, 23631, 18826, 14518, 58448, 14562, 49618,  5588, 25396,    28 };
+
+static const LITTLENUM_TYPE minus_11 [] = {
+  6223, 59909, 62437, 59960, 14652, 45336, 48800,  7647, 51962, 37982,
+ 60436, 58176, 26767,  8440,  9831, 48556, 20994, 14148,  6757, 17221,
+ 60624, 46129, 53210, 44085, 54016, 24259, 11232, 21229, 21313,    81,  };
+static const LITTLENUM_TYPE plus_11 [] = {
+ 36159,  2055, 33615, 61362, 23581, 62454,  9748, 15275, 39284, 58636,
+ 16269, 42793, 47240, 45774, 50861, 48400,  9413, 40281,  4030,  9572,
+  7984, 33038, 59522, 19450, 40593, 24486, 54320,  6661, 55766,   805,  };
+
+/* 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, '+'},
+};
+
+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, '+'},
+};
+
+#ifdef VMS
+dummy1()
+{
+}
+#endif
+/* end: flonum_const.c */
diff --git a/gas/flonum-copy.c b/gas/flonum-copy.c
new file mode 100644 (file)
index 0000000..6678bdf
--- /dev/null
@@ -0,0 +1,79 @@
+/* flonum_copy.c - copy a flonum
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include "as.h"
+
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#define bcopy(from,to,n) memcpy(to,from,n)
+#endif
+
+void
+flonum_copy (in, out)
+     FLONUM_TYPE *     in;
+     FLONUM_TYPE *     out;
+{
+  int                  in_length;      /* 0 origin */
+  int                  out_length;     /* 0 origin */
+
+  out -> sign = in -> sign;
+  in_length = in  -> leader - in -> low;
+  if (in_length < 0)
+    {
+      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)
+             {
+               bzero ((char *)(out->low + in_length + 1), out_length - in_length);
+             }
+         }
+         bcopy ((char *)(in->low), (char *)(out->low), (int)((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 ! */
+         bcopy ((char *)(in->low + shorten),(char *)( out->low), (int)((out_length + 1) * sizeof(LITTLENUM_TYPE)));
+         out -> leader = out -> high;
+         out -> exponent = in -> exponent + shorten;
+       }
+    }                          /* if any significant bits */
+}
+
+/* end: flonum_copy.c */
diff --git a/gas/flonum-mult.c b/gas/flonum-mult.c
new file mode 100644 (file)
index 0000000..b01f93b
--- /dev/null
@@ -0,0 +1,201 @@
+/* flonum_multip.c - multiply two flonums
+   Copyright (C) 1987, 1990, 1991 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.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#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 ...)
+*/
+\f
+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
+             work += a -> low [A]   *   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: flonum_multip.c */
diff --git a/gas/flonum.h b/gas/flonum.h
new file mode 100644 (file)
index 0000000..570bd3a
--- /dev/null
@@ -0,0 +1,122 @@
+/* flonum.h - Floating point package
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+/***********************************************************************\
+*                                                                      *
+*      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!                   *
+*                                                                      *
+\***********************************************************************/
+#if !defined(__STDC__) && !defined(const)
+#define const /* empty */
+#endif
+
+#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.                                       *
+*                                                                      *
+\***********************************************************************/
+
+#ifdef __STDC__
+
+int atof_generic(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(FLONUM_TYPE *in, FLONUM_TYPE *out);
+void flonum_multip(const FLONUM_TYPE *a, const FLONUM_TYPE *b, FLONUM_TYPE *product);
+
+#else /* __STDC__ */
+
+int atof_generic();
+void flonum_copy();
+void flonum_multip();
+
+#endif /* __STDC__ */
+
+/***********************************************************************\
+*                                                                      *
+*      Declare error codes.                                            *
+*                                                                      *
+\***********************************************************************/
+
+#define ERROR_EXPONENT_OVERFLOW (2)
+
+/* end: flonum.h */
diff --git a/gas/frags.c b/gas/frags.c
new file mode 100644 (file)
index 0000000..3526603
--- /dev/null
@@ -0,0 +1,285 @@
+/* frags.c - manage frags -
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+struct obstack  frags; /* All, and only, frags live here. */
+
+fragS zero_address_frag = {
+       0,                      /* fr_address */
+       NULL,                   /* fr_next */
+       0,                      /* fr_fix */
+       0,                      /* fr_var */
+       0,                      /* fr_symbol */
+       0,                      /* fr_offset */
+       NULL,                   /* fr_opcode */
+       rs_fill,                /* fr_type */
+       0,                      /* fr_subtype */
+       0,                      /* fr_pcrel_adjust */
+       0,                      /* fr_bsr */
+       0                       /* fr_literal [0] */
+};
+
+fragS bss_address_frag = {
+       0,                      /* fr_address. Gets filled in to make up
+                                  sy_value-s. */
+       NULL,                   /* fr_next */
+       0,                      /* fr_fix */
+       0,                      /* fr_var */
+       0,                      /* fr_symbol */
+       0,                      /* fr_offset */
+       NULL,                   /* fr_opcode */
+       rs_fill,                /* fr_type */
+       0,                      /* fr_subtype */
+       0,                      /* fr_pcrel_adjust */
+       0,                      /* fr_bsr */
+       0                       /* fr_literal [0] */
+};
+\f
+/*
+ *                     frag_grow()
+ *
+ * Internal.
+ * 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.
+ */
+static void frag_grow(nchars)
+unsigned int nchars;
+{
+    if (obstack_room (&frags) < nchars) {
+       unsigned int n,oldn;
+       long oldc;
+
+       frag_wane(frag_now);
+       frag_new(0);
+       oldn=(unsigned)-1;
+       oldc=frags.chunk_size;
+       frags.chunk_size=2*nchars;
+       while((n=obstack_room(&frags))<nchars && n<oldn) {
+               frag_wane(frag_now);
+               frag_new(0);
+               oldn=n;
+       }
+       frags.chunk_size=oldc;
+    }
+    if (obstack_room (&frags) < nchars)
+       as_fatal("Can't extend frag %d. chars", nchars);
+} /* frag_grow() */
+\f
+/*
+ *                     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)
+int old_frags_var_max_size;    /* Number of chars (already allocated on
+                                  obstack frags) */
+ /* in variable_length part of frag. */
+{
+    register    fragS * former_last_fragP;
+/*    char   *throw_away_pointer; JF unused */
+    register    frchainS * frchP;
+    long       tmp;            /* JF */
+
+    frag_now->fr_fix = (char *) (obstack_next_free (&frags)) -
+    (frag_now->fr_literal) - old_frags_var_max_size;
+ /* Fix up old frag's fr_fix. */
+
+    obstack_finish (&frags);
+ /* This will align the obstack so the */
+ /* next struct we allocate on it will */
+ /* begin at a correct boundary. */
+    frchP = frchain_now;
+    know (frchP);
+    former_last_fragP = frchP->frch_last;
+    know (former_last_fragP);
+    know (former_last_fragP == frag_now);
+    obstack_blank (&frags, SIZEOF_STRUCT_FRAG);
+ /* We expect this will begin at a correct */
+ /* boundary for a struct. */
+    tmp=obstack_alignment_mask(&frags);
+    obstack_alignment_mask(&frags)=0;          /* Turn off alignment */
+                                               /* If we ever hit a machine
+                                                  where strings must be
+                                                  aligned, we Lose Big */
+ frag_now=(fragS *)obstack_finish(&frags);
+    obstack_alignment_mask(&frags)=tmp;                /* Restore alignment */
+
+ /* Just in case we don't get zero'd bytes */
+ bzero(frag_now, SIZEOF_STRUCT_FRAG);
+
+/*    obstack_unaligned_done (&frags, &frag_now); */
+/*    know (frags.obstack_c_next_free == frag_now->fr_literal); */
+ /* 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;
+    frag_now->fr_next = NULL;
+}                              /* frag_new() */
+\f
+/*
+ *                     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;
+
+    frag_grow (nchars);
+    retval = obstack_next_free (&frags);
+    obstack_blank_fast (&frags, nchars);
+    return (retval);
+}                              /* frag_more() */
+\f
+/*
+ *                     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;
+long offset;
+char *opcode;
+{
+    register char  *retval;
+
+    frag_grow (max_chars);
+    retval = obstack_next_free (&frags);
+    obstack_blank_fast (&frags, 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. */
+    frag_now->fr_pcrel_adjust = 0;
+    frag_now->fr_bsr = 0;
+    frag_new (max_chars);
+    return (retval);
+}                              /* frag_var() */
+\f
+/*
+ *                     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.
+ *      Two new arguments have been added.
+ */
+
+char *frag_variant(type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr)
+     relax_stateT       type;
+     int                max_chars;
+     int                var;
+     relax_substateT    subtype;
+     symbolS           *symbol;
+     long               offset;
+     char              *opcode;
+     int                pcrel_adjust;
+     char               bsr;
+{
+    register char  *retval;
+
+/*    frag_grow (max_chars); */
+    retval = obstack_next_free (&frags);
+/*  obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */
+    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;
+    frag_now->fr_pcrel_adjust = pcrel_adjust;
+    frag_now->fr_bsr = bsr;
+    frag_new (max_chars);
+    return (retval);
+}                              /* frag_variant() */
+\f
+/*
+ *                     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;
+}
+\f
+/*
+ *                     frag_align()
+ *
+ * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);".
+ * Foo & bar are absolute integers.
+ *
+ * Call to close off the current frag with a ".align", then start a new
+ * (so far empty) frag, in the same subsegment as the last frag.
+ */
+
+void frag_align(alignment, fill_character)
+int alignment;
+int fill_character;
+{
+    *(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0,
+ (long)alignment, (char *)0)) = fill_character;
+} /* frag_align() */
+
+/* end: frags.c */
diff --git a/gas/frags.h b/gas/frags.h
new file mode 100644 (file)
index 0000000..aa08995
--- /dev/null
@@ -0,0 +1,84 @@
+/* frags.h - Header file for the frag concept.
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+extern struct obstack  frags;
+                               /* Frags ONLY live in this obstack. */
+                               /* We use obstack_next_free() macro */
+                               /* so please don't put any other objects */
+                               /* on this stack! */
+
+/*
+ * 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 ); \
+}
+      
+
+#ifdef __STDC__
+
+char *frag_more(int nchars);
+void frag_align(int alignment, int fill_character);
+void frag_new(int old_frags_var_max_size);
+void frag_wane(fragS *fragP);
+
+char *frag_variant(relax_stateT type,
+                  int max_chars,
+                  int var,
+                  relax_substateT subtype,
+                  symbolS *symbol,
+                  long offset,
+                  char *opcode,
+                  int pcrel_adjust,
+                  int bsr);
+
+char *frag_var(relax_stateT type,
+              int max_chars,
+              int var,
+              relax_substateT subtype,
+              symbolS *symbol,
+              long offset,
+              char *opcode);
+
+#else /* __STDC__ */
+
+char *frag_more();
+char *frag_var();
+char *frag_variant();
+void frag_align();
+void frag_new();
+void frag_wane();
+
+#endif /* __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: frags.h */
diff --git a/gas/hash.c b/gas/hash.c
new file mode 100644 (file)
index 0000000..b57ba9e
--- /dev/null
@@ -0,0 +1,990 @@
+/* hash.c - hash table lookup strings -
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * 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!
+ */
+\f
+/*
+ *  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.
+ */
+\f
+/*
+ *  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 (or NULL if there
+ *  is not enough memory). 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.
+ */
+\f
+/*
+ *  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
+
+#define DELETED     ((char *)1)        /* guarenteed invalid address */
+#define START_POWER    (11)    /* power of two: size of new hash table *//* JF was 6 */
+/* JF These next two aren't used any more. */
+/* #define START_SIZE    (64)  / * 2 ** START_POWER */
+/* #define START_FULL    (32)      / * number of entries before table expands */
+#define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED)
+                               /* above TRUE if a symbol is in entry @ ptr */
+
+#define STAT_SIZE      (0)      /* number of slots in hash table */
+                               /* the wall does not count here */
+                               /* we expect this is always a power of 2 */
+#define STAT_ACCESS    (1)     /* number of hash_ask()s */
+#define STAT__READ     (0)      /* reading */
+#define STAT__WRITE    (1)      /* writing */
+#define STAT_COLLIDE   (3)     /* number of collisions (total) */
+                               /* this may exceed STAT_ACCESS if we have */
+                               /* lots of collisions/access */
+#define STAT_USED      (5)     /* slots used right now */
+#define STATLENGTH     (6)     /* size of statistics block */
+#if STATLENGTH != HASH_STATLENGTH
+Panic! Please make #include "stat.h" agree with previous definitions!
+#endif
+
+/* #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
+\f
+/*------------------ 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; "" 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
+
+*/
+\f
+static char hash_found;                /* 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 struct hash_entry * hash_ask();
+static int hash_code ();
+static char * hash_grow();
+\f
+/*
+ *             h a s h _ n e w ( )
+ *
+ */
+struct hash_control *
+hash_new()                     /* create a new hash table */
+                               /* return NULL if failed */
+                               /* return handle (address of struct hash) */
+{
+  register struct hash_control * retval;
+  register struct hash_entry *   room; /* points to hash table */
+  register struct hash_entry *   wall;
+  register struct hash_entry *   entry;
+  register int *                 ip;   /* scan stats block of struct hash_control */
+  register int *                 nd;   /* limit of stats block */
+
+  if (( room = (struct hash_entry *) malloc( sizeof(struct
+                                                   hash_entry)*((1<<START_POWER) + 1) ) ) != NULL)
+                               /* +1 for the wall entry */
+    {
+      if (( retval = (struct hash_control *) malloc(sizeof(struct
+                                                          hash_control)) ) != NULL)
+       {
+         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             = (1<<START_POWER)/2;
+         for (entry=room; entry<=wall; entry++)
+           {
+             entry->hash_string = NULL;
+           }
+       }
+    }
+  else
+    {
+      retval = NULL;           /* no room for table: fake a failure */
+    }
+  return(retval);              /* return NULL or set-up structs */
+}
+
+/*
+ *           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);
+}
+\f
+/*
+ *           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.
+ */
+void
+hash_say(handle,buffer,bufsiz)
+     register struct hash_control * handle;
+     register int                   buffer[/*bufsiz*/];
+     register int                   bufsiz;
+{
+  register int * nd;                   /* limit of statistics block */
+  register 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;
+       }
+    }
+}
+\f
+/*
+ *           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.
+ *
+ */
+char *                         /* NULL if string not in table, else */
+                               /* returns value of deleted symbol */
+hash_delete(handle,string)
+     register struct hash_control * handle;
+     register char *                string;
+{
+  register char *                   retval; /* NULL if string not in table */
+  register struct hash_entry *      entry; /* NULL or entry of this symbol */
+
+  entry = hash_ask(handle,string,STAT__WRITE);
+  if (hash_found)
+    {
+         retval = entry -> hash_value;
+         entry -> hash_string = DELETED; /* mark as deleted */
+         handle -> hash_stat[STAT_USED] -= 1; /* slots-in-use count */
+#ifdef SUSPECT
+         if (handle->hash_stat[STAT_USED]<0)
+           {
+             error("hash_delete");
+           }
+#endif /* def SUSPECT */
+    }
+  else
+    {
+      retval = NULL;
+    }
+  return(retval);
+}
+\f
+/*
+ *                   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.
+ */
+char *
+hash_replace(handle,string,value)
+     register struct hash_control * handle;
+     register char *                string;
+     register char *                value;
+{
+  register struct hash_entry *      entry;
+  register 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);
+}
+\f
+/*
+ *                   h a s h _ i n s e r t ( )
+ *
+ * Insert a (symbol-string, value) into the hash table.
+ * Return an error string, "" means OK.
+ * It is an 'error' to insert an existing symbol.
+ */
+
+char *                         /* return error string */
+hash_insert(handle,string,value)
+     register struct hash_control * handle;
+     register char *                string;
+     register char *                value;
+{
+  register struct hash_entry * entry;
+  register char *              retval;
+
+  retval = "";
+  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);
+}
+\f
+/*
+ *               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) relpaced.
+ * An error message string is returned, "" 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.
+ */
+char *
+hash_jam(handle,string,value)
+     register struct hash_control * handle;
+     register char *                string;
+     register char *                value;
+{
+  register char *                   retval;
+  register struct hash_entry *      entry;
+
+  retval = "";
+  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: "" 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 char *
+hash_grow(handle)                      /* make a hash table grow */
+     struct hash_control * handle;
+{
+  register struct hash_entry *      newwall;
+  register struct hash_entry *      newwhere;
+  struct hash_entry *      newtrack;
+  register struct hash_entry *      oldtrack;
+  register struct hash_entry *      oldwhere;
+  register struct hash_entry *      oldwall;
+  register int                      temp;
+  int                      newsize;
+  char *                   string;
+  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];
+  if (( newwhere = (struct hash_entry *)
+       xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry)))) != NULL)
+                               /* +1 for wall slot */
+    {
+      retval = "";             /* assume success until proven otherwise */
+      /*
+       * have enough room: now we do all the work.
+       * double the size of everything in handle,
+       * note: hash_mask frob works for 1's & for 2's complement machines
+       */
+      handle->hash_mask              = handle->hash_mask + handle->hash_mask + 1;
+      handle->hash_stat[STAT_SIZE] <<= 1;
+      newsize                        = handle->hash_stat[STAT_SIZE];
+      handle->hash_where             = newwhere;
+      handle->hash_full            <<= 1;
+      handle->hash_sizelog         += 1;
+      handle->hash_stat[STAT_USED]   = 0;
+      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;      /* inserts will bump it up to correct */
+      for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++)
+       {
+         if ( ((string=oldtrack->hash_string) != NULL) && string!=DELETED )
+           {
+             if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) )
+               {
+                 break;
+               }
+           }
+       }
+#ifdef SUSPECT
+      if ( !*retval && handle->hash_stat[STAT_USED] != oldused)
+       {
+         retval = "hash_used";
+       }
+#endif
+      if (!*retval)
+       {
+         /*
+          * we have a completely faked up control block.
+          * return the old hash table.
+          */
+         free((char *)oldwhere);
+         /*
+          * Here with success. retval is already "".
+          */
+       }
+    }
+  else
+    {
+      retval = "no room";
+    }
+  return(retval);
+}
+\f
+/*
+ *          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.
+ * To be safe, please make your functions of type char *. If you always
+ * return NULL, then the scan will complete, visiting every symbol in
+ * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet!
+ * Caveat Actor!
+ *
+ * The function you supply should be of the form:
+ *      char * myfunct(string,value)
+ *              char * string;        |* the symbol's name *|
+ *              char * value;         |* the symbol's value *|
+ *      {
+ *        |* ... *|
+ *        return(NULL);
+ *      }
+ *
+ * The returned value of hash_apply() is (char*)NULL. In future it may return
+ * other values. NULL means "completed scan OK". Other values have no meaning
+ * yet. (The function has no graceful failures.)
+ */
+char *
+hash_apply(handle,function)
+     struct hash_control * handle;
+     char*                 (*function)();
+{
+  register struct hash_entry *      entry;
+  register 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);
+       }
+    }
+  return (NULL);
+}
+\f
+/*
+ *          h a s h _ f i n d ( )
+ *
+ * Given symbol string, find value (if any).
+ * Return found value or NULL.
+ */
+char *
+hash_find(handle,string)       /* return char* or NULL */
+     struct hash_control * handle;
+     char *                string;
+{
+  register struct hash_entry *      entry;
+  register char *                   retval;
+
+  entry = hash_ask(handle,string,STAT__READ);
+  if (hash_found)
+    {
+      retval = entry->hash_value;
+    }
+  else
+    {
+      retval = NULL;
+    }
+  return(retval);
+}
+\f
+/*
+ *          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)
+     struct hash_control * handle;
+     char *                string;
+     int                   access; /* access type */
+{
+  register char        *string1;       /* JF avoid strcmp calls */
+  register char *                   s;
+  register int                      c;
+  register struct hash_entry *      slot;
+  register int                      collision; /* count collisions */
+
+  slot = handle->hash_where + hash_code(handle,string); /* start looking here */
+  handle->hash_stat[STAT_ACCESS+access] += 1;
+  collision = 0;
+  hash_found = FALSE;
+  while ( ((s = slot->hash_string) != NULL) && s!=DELETED )
+    {
+       for(string1=string;;) {
+               if((c= *s++) == 0) {
+                       if(!*string1)
+                               hash_found = TRUE;
+                       break;
+               }
+               if(*string1++!=c)
+                       break;
+       }
+       if(hash_found)
+               break;
+      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 )
+       {
+         for(string1=string;*s;string1++,s++) {
+           if(*string1!=*s)
+               break;
+         }
+         if(*s==*string1) {
+             hash_found = TRUE;
+             break;
+           }
+         collision++;
+         slot++;
+       }
+      /*
+       * slot:                                                   return:
+       *       in use: we found it                                slot
+       *       empty:  wall:         ERROR IMPOSSIBLE             !!!!
+       *               in table:     dig here                     slot
+       *       DELETED:dig here                                   slot
+       */
+    }
+/*   fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */
+  handle -> hash_stat[STAT_COLLIDE+access] += collision;
+  return(slot);                        /* also return hash_found */
+}
+\f
+/*
+ *           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;
+     register char *                string;
+{
+  register long                 h;      /* hash code built here */
+  register long                 c;      /* each character lands here */
+  register 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 & handle->hash_mask);
+}
+\f
+/*
+ * 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()
+{
+  char (*applicatee());
+  char * hash_find();
+  char * destroy();
+  char * what();
+  struct hash_control * hash_new();
+  char * hash_replace();
+  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();
+       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);
+}
+
+char *
+destroy(string,value)
+     char * string;
+     char * value;
+{
+  free(string);
+  free(value);
+  return(NULL);
+}
+
+
+char *
+applicatee(string,value)
+     char * string;
+     char * value;
+{
+  printf("%.20s-%.20s\n",string,value);
+  return(NULL);
+}
+
+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: hash.c */
diff --git a/gas/hash.h b/gas/hash.h
new file mode 100644 (file)
index 0000000..fb68fd3
--- /dev/null
@@ -0,0 +1,59 @@
+/* hash.h - for hash.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef hashH
+#define hashH
+
+struct hash_entry
+{
+  char *      hash_string;     /* points to where the symbol string is */
+                               /* NULL means slot is not used */
+                               /* DELETED means slot was deleted */
+  char *      hash_value;      /* user's datum, associated with symbol */
+};
+
+
+#define HASH_STATLENGTH        (6)
+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[HASH_STATLENGTH]; /* lies & statistics */
+                               /* we need STAT_USED & STAT_SIZE */
+};
+
+
+/*                                             returns           */
+struct hash_control *  hash_new();     /* [control block]        */
+void                   hash_die();
+void                   hash_say();
+char *                 hash_delete();  /* previous value         */
+char *                 hash_relpace(); /* previous value         */
+char *                 hash_insert();  /* error string           */
+char *                 hash_apply();   /* 0 means OK             */
+char *                 hash_find();    /* value                  */
+char *                 hash_jam();     /* error text (internal)  */
+#endif                         /* #ifdef hashH */
+
+/* end: hash.c */
diff --git a/gas/hex-value.c b/gas/hex-value.c
new file mode 100644 (file)
index 0000000..64420f5
--- /dev/null
@@ -0,0 +1,57 @@
+/* hex_value.c - char=>radix-value -
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * Export: Hex_value[]. Converts digits to their radix-values.
+ *     As distributed assumes 8 bits per char (256 entries) and ASCII.
+ */
+
+#define __ (42)                        /* blatently illegal digit value */
+                               /* exceeds any normal radix */
+#if !defined(__STDC__) && !defined(const)
+#define const /* empty */
+#endif
+const char
+hex_value [256] = {            /* for fast ASCII -> binary */
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, __, __, __, __, __, __,
+  __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+  __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
+  };
+
+#ifdef VMS
+dummy2()
+{
+}
+#endif
+/* end:hex_value.c */
diff --git a/gas/input-file.c b/gas/input-file.c
new file mode 100644 (file)
index 0000000..cf1a4c3
--- /dev/null
@@ -0,0 +1,322 @@
+/* input_file.c - Deal with Input Files -
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * 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!
+ */
+
+#ifdef USG
+#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size))
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "as.h"
+#include "input-file.h"
+
+/* 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.
+ */
+
+FILE *f_in;
+/* static JF remove static so app.c can use file_name */
+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;
+};
+\f
+/* These hooks accomodate most operating systems. */
+
+void input_file_begin() {
+  f_in = (FILE *)0;
+}
+
+void input_file_end () { }
+
+ /* Return BUFFER_SIZE. */
+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);
+}
+\f
+#ifdef DONTDEF         /* JF save old version in case we need it */
+void
+input_file_open (filename, preprocess, debugging)
+     char *    filename;       /* "" means use stdin. Must not be 0. */
+     int       preprocess;     /* TRUE if needs app. */
+     int       debugging;      /* TRUE if we are debugging assembler. */
+{
+  assert( filename != 0 );     /* Filename may not be NULL. */
+  if (filename [0])
+    {                          /* We have a file name. Suck it and see. */
+      file_handle = open (filename, O_RDONLY, 0);
+      file_name = filename;
+    }
+  else
+    {                          /* use stdin for the input file. */
+      file_handle = fileno (stdin);
+      file_name = "{standard input}"; /* For error messages. */
+    }
+  if (file_handle < 0)
+      as_perror ("Can't open %s for reading", file_name);
+  if ( preprocess )
+    {
+/*
+ * This code was written in haste for a frobbed BSD 4.2.
+ * I have a flight to catch: will someone please do proper
+ * error checks? - Dean.
+ */
+      int      pid;
+      char temporary_file_name [12];
+      int      fd;
+      union wait       status;
+
+      (void)strcpy (temporary_file_name, "#appXXXXXX");
+      (void)mktemp (temporary_file_name);
+      pid = vfork ();
+      if (pid == -1)
+       {
+         as_perror ("Vfork failed", file_name);
+         _exit (144);
+       }
+      if (pid == 0)
+       {
+         (void)dup2 (file_handle, fileno(stdin));
+         fd = open (temporary_file_name, O_WRONLY + O_TRUNC + O_CREAT, 0666);
+         if (fd == -1)
+           {
+             (void)write(2,"Can't open temporary\n",21);
+             _exit (99);
+           }
+         (void)dup2 (fd, fileno(stdout));
+/* JF for testing #define PREPROCESSOR "/lib/app" */
+#define PREPROCESSOR "./app"
+         execl (PREPROCESSOR, PREPROCESSOR, 0);
+         execl ("app","app",0);
+         (void)write(2,"Exec of app failed.  Get help.\n",31);
+         (void)unlink(temporary_file_name);
+         _exit (11);
+       }
+      (void)wait (& status);
+      if (status.w_status & 0xFF00)            /* JF was 0xF000, was wrong */
+       {
+         file_handle = -1;
+         as_bad( "Can't preprocess file \"%s\", status = %xx", file_name, status.w_status );
+       }
+      else
+       {
+         file_handle = open (temporary_file_name, O_RDONLY, 0);
+         if ( ! debugging && unlink(temporary_file_name))
+           as_perror ("Can't delete temp file %s", temporary_file_name);
+       }
+      if (file_handle == -1)
+         as_perror ("Can't retrieve temp file %s", temporary_file_name);
+    }
+}
+#else
+
+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_perror ("Can't open %s for reading", file_name);
+               return;
+       }
+
+#ifndef VMS
+       /* Ask stdio to buffer our input at BUFFER_SIZE, with a dynamically
+          allocated buffer.  */
+       setvbuf(f_in, (char *)NULL, _IOFBF, BUFFER_SIZE);
+#endif /* VMS */
+
+       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);
+
+#ifdef DONTDEF
+       if ( preprocess ) {
+               char temporary_file_name [17];
+               FILE    *f_out;
+
+               (void)strcpy (temporary_file_name, "/tmp/#appXXXXXX");
+               (void)mktemp (temporary_file_name);
+               f_out=fopen(temporary_file_name,"w+");
+               if(f_out==(FILE *)0)
+                       as_perror("Can't open temp file %s",temporary_file_name);
+
+                       /* JF this will have to be moved on any system that
+                          does not support removal of open files.  */
+               (void)unlink(temporary_file_name);/* JF do it NOW */
+               do_scrub(f_in,f_out);
+               (void)fclose(f_in);     /* All done with it */
+               (void)rewind(f_out);
+               f_in=f_out;
+       }
+#endif
+}
+#endif
+
+/* Close input file.  */
+void input_file_close() {
+  fclose (f_in);
+  f_in = 0;
+}
+
+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) {
+       char *p;
+       int n;
+       int ch;
+       extern FILE *scrub_file;
+
+       scrub_file=f_in;
+       for (p = where, n = BUFFER_SIZE; n; --n) {
+
+               ch = do_scrub_next_char(scrub_from_file, scrub_to_file);
+               if (ch == EOF)
+                       break;
+               *p++=ch;
+       }
+       size=BUFFER_SIZE-n;
+  } 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);
+}
diff --git a/gas/input-file.h b/gas/input-file.h
new file mode 100644 (file)
index 0000000..703d4c5
--- /dev/null
@@ -0,0 +1,84 @@
+/* input_file.h header for input-file.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, 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.
+ */
+
+#ifdef __STDC__
+
+char *input_file_give_next_buffer(char *where);
+char *input_file_push(void);
+int input_file_buffer_size(void);
+int input_file_is_open(void);
+void input_file_begin(void);
+void input_file_close(void);
+void input_file_end(void);
+void input_file_open(char *filename, int pre);
+void input_file_pop(char *arg);
+
+#else /* __STDC__ */
+
+char *input_file_give_next_buffer();
+char *input_file_push();
+int input_file_buffer_size();
+int input_file_is_open();
+void input_file_begin();
+void input_file_close();
+void input_file_end();
+void input_file_open();
+void input_file_pop();
+
+#endif /* __STDC__ */
+
+/* end: input_file.h */
diff --git a/gas/input-scrub.c b/gas/input-scrub.c
new file mode 100644 (file)
index 0000000..a710913
--- /dev/null
@@ -0,0 +1,478 @@
+/* input_scrub.c - Break up input buffers into whole numbers of lines.
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include <errno.h>     /* Need this to make errno declaration right */
+#include "as.h"
+#include "input-file.h"
+
+/*
+ * O/S independent module to supply buffers of sanitised source code
+ * to rest of assembler. We get sanitized 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.
+ */
+\f
+#define BEFORE_STRING ("\n")
+#define AFTER_STRING ("\0")    /* bcopy 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 int buffer_length;      /* What is the largest size buffer that */
+                               /* input_file_give_next_buffer() could */
+                               /* return to us? */
+
+/* Saved information about the file that .include'd this one.  When we
+   hit EOF, we automatically pop to that file. */
+
+static char *next_saved_file;
+
+/*
+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,
+     *         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,
+               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];
+       int buffer_length;
+       char *physical_input_file;
+       char *logical_input_file;
+       line_numberT    physical_input_line;
+       line_numberT    logical_input_line;
+       char *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 */
+};
+
+#ifdef __STDC__
+static void as_1_char(unsigned int c, FILE *stream);
+#else /* __STDC__ */
+static void as_1_char();
+#endif /* __STDC__ */
+
+/* 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(). */
+char *
+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;
+       bcopy (saved->save_source,        save_source, sizeof (save_source));
+       saved->next_saved_file          = next_saved_file;
+       saved->input_file_save          = input_file_push ();
+
+       input_scrub_begin ();           /* Reinitialize! */
+
+       return (char *)saved;
+}
+
+char *
+input_scrub_pop (arg)
+       char *arg;
+{
+       register struct input_save *saved;
+       char *saved_position;
+
+       input_scrub_end ();     /* Finish off old buffer */
+
+       saved = (struct input_save *)arg;
+
+       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;
+       partial_where           = saved->partial_where;
+       partial_size            = saved->partial_size;
+       next_saved_file         = saved->next_saved_file;
+       bcopy (save_source,       saved->save_source, sizeof (save_source));
+
+       free(arg);
+       return saved_position;
+}
+
+\f
+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((long)(BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
+  bcopy (BEFORE_STRING, buffer_start, (int)BEFORE_SIZE);
+
+  /* Line number things. */
+  logical_input_line = 0;
+  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();
+}
+
+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, !flagseen['f']);
+  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);
+}
+
+void
+input_scrub_close ()
+{
+  input_file_close ();
+}
+char *
+input_scrub_next_buffer (bufp)
+char **bufp;
+{
+  register char *      limit;  /*->just after last char of buffer. */
+
+  *bufp = buffer_start + BEFORE_SIZE;
+
+#ifdef DONTDEF
+  if(preprocess) {
+    if(save_buffer) {
+      *bufp = save_buffer;
+      save_buffer = 0;
+    }
+    limit = input_file_give_next_buffer(buffer_start+BEFORE_SIZE);
+    if (!limit) {
+      partial_where = 0;
+      if(partial_size)
+        as_warn("Partial line at end of file ignored");
+      return partial_where;
+    }
+
+    if(partial_size)
+      bcopy(save_source, partial_where,(int)AFTER_SIZE);
+    do_scrub(partial_where,partial_size,buffer_start+BEFORE_SIZE,limit-(buffer_start+BEFORE_SIZE),&out_string,&out_length);
+    limit=out_string + out_length;
+    for(p=limit;*--p!='\n';)
+      ;
+    p++;
+    if(p<=buffer_start+BEFORE_SIZE)
+      as_fatal("Source line too long.  Please change file '%s' and re-make the assembler.", __FILE__);
+
+    partial_where = p;
+    partial_size = limit-p;
+    bcopy(partial_where, save_source,(int)AFTER_SIZE);
+    bcopy(AFTER_STRING, partial_where, (int)AFTER_SIZE);
+
+    save_buffer = *bufp;
+    *bufp = out_string;
+
+    return partial_where;
+  }
+
+  /* We're not preprocessing.  Do the right thing */
+#endif
+  if (partial_size)
+    {
+      bcopy (partial_where, buffer_start + BEFORE_SIZE, (int)partial_size);
+      bcopy (save_source, buffer_start + BEFORE_SIZE, (int)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;   * -- p != '\n';)
+       {
+       }
+      ++ p;
+      if (p <= buffer_start + BEFORE_SIZE)
+       {
+         as_fatal("Source line too long. Please change file %s then rebuild assembler.", __FILE__);
+       }
+      partial_where = p;
+      partial_size = limit - p;
+      bcopy (partial_where, save_source,  (int)AFTER_SIZE);
+      bcopy (AFTER_STRING, partial_where, (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);
+}
+\f
+/*
+ * 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 ()
+{
+  ++ physical_input_line;
+  ++ logical_input_line;
+}
+\f
+/*
+ *                     new_logical_line()
+ *
+ * Tells us what the new logical line number and file are.
+ * If the line_number is <0, we don't change the current logical line number.
+ * 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;
+       } /* if we have a line number */
+} /* new_logical_line() */
+\f
+/*
+ *                     a s _ w h e r e ()
+ *
+ * Write a line to stderr locating where we are in reading
+ * input source files.
+ * As a sop to the debugger of AS, pretty-print the offending line.
+ */
+void
+as_where()
+{
+  char *p;
+  line_numberT line;
+
+  if (physical_input_file)
+    {                          /* we tried to read SOME source */
+      if (input_file_is_open())
+       {                       /* we can still read lines from source */
+#ifdef DONTDEF
+         fprintf (stderr," @ physical line %ld., file \"%s\"",
+                  (long) physical_input_line, physical_input_file);
+         fprintf (stderr," @ logical line %ld., file \"%s\"\n",
+                  (long) logical_input_line, logical_input_file);
+         (void)putc(' ', stderr);
+         as_howmuch (stderr);
+         (void)putc('\n', stderr);
+#else
+               p = logical_input_file ? logical_input_file : physical_input_file;
+               line = logical_input_line ? logical_input_line : physical_input_line;
+               fprintf(stderr,"%s:%u: ", p, line);
+#endif
+       }
+      else
+       {
+#ifdef DONTDEF
+         fprintf (stderr," After reading source.\n");
+#else
+       p = logical_input_file ? logical_input_file : physical_input_file;
+       line = logical_input_line ? logical_input_line : physical_input_line;
+       fprintf(stderr, "%s:%d:", p, (int) line);
+#endif
+       }
+    }
+  else
+    {
+#ifdef DONTDEF
+      fprintf (stderr," Before reading source.\n");
+#else
+#endif
+    }
+}
+
+
+
+\f
+/*
+ *                     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. */
+      /* c = *p & 0xFF; JF unused */
+      as_1_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);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: input_scrub.c */
diff --git a/gas/messages.c b/gas/messages.c
new file mode 100644 (file)
index 0000000..90e1f95
--- /dev/null
@@ -0,0 +1,391 @@
+/* messages.c - error reporter -
+   Copyright (C) 1987, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$ */
+
+#include <stdio.h> /* define stderr */
+#include <errno.h>
+
+#include "as.h"
+
+#ifndef NO_STDARG
+#include <stdarg.h>
+#else
+#ifndef NO_VARARGS
+#include <varargs.h>
+#endif /* NO_VARARGS */
+#endif /* NO_STDARG */
+
+/*
+ * 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.
+ */
+
+/*
+  ERRORS
+
+  JF: this is now bogus.  We now print more standard error messages
+  that try to look like everyone else's.
+
+  We print the error message 1st, beginning in column 1.
+  All ancillary info starts in column 2 on lines after the
+  key error text.
+  We try to print a location in logical and physical file
+  just after the main error text.
+  Caller then prints any appendices after that, begining all
+  lines with at least 1 space.
+
+  Optionally, we may die.
+  There is no need for a trailing '\n' in your error text format
+  because we supply one.
+
+  as_warn(fmt,args)  Like fprintf(stderr,fmt,args) but also call errwhere().
+
+  as_fatal(fmt,args) Like as_warn() but exit with a fatal status.
+
+ */
+
+static int warning_count = 0; /* Count of number of warnings issued */
+
+int had_warnings() {
+       return(warning_count);
+} /* had_err() */
+
+/* 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 = 0;
+
+int had_errors() {
+       return(error_count);
+} /* had_errors() */
+
+
+/*
+ *                     a s _ p e r r o r
+ *
+ * Like perror(3), but with more info.
+ */
+void as_perror(gripe, filename)
+char *gripe;           /* Unpunctuated error theme. */
+char *filename;
+{
+       extern int sys_nerr;
+       extern char *sys_errlist[];
+
+       as_where();
+       fprintf(stderr,gripe,filename);
+
+       if (errno > sys_nerr)
+           fprintf(stderr, "Unknown error #%d.\n", errno);
+       else
+           fprintf(stderr, "%s.\n", sys_errlist[errno]);
+       errno = 0; /* After reporting, clear it. */
+} /* as_perror() */
+
+/*
+ *                     a s _ t s k t s k ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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.
+ */
+
+#ifndef NO_STDARG
+void as_tsktsk(Format)
+const char *Format;
+{
+       va_list args;
+       
+       as_where();
+       va_start(args, Format);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       (void) putc('\n', stderr);
+} /* as_tsktsk() */
+#else
+#ifndef NO_VARARGS
+void as_tsktsk(Format,va_alist)
+char *Format;
+va_dcl
+{
+       va_list args;
+       
+       as_where();
+       va_start(args);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       (void) putc('\n', stderr);
+} /* as_tsktsk() */
+#else
+/*VARARGS1 */
+as_tsktsk(Format,args)
+char *Format;
+{
+       as_where();
+       _doprnt (Format, &args, stderr);
+       (void)putc ('\n', stderr);
+       /* as_where(); */
+} /* as_tsktsk */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_tsktsk(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+       as_where();
+       fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+       (void)putc('\n',stderr);
+} /* as_tsktsk() */
+#endif
+/*
+ *                     a s _ w a r n ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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.
+ */
+
+#ifndef NO_STDARG
+void as_warn(Format)
+const char *Format;
+{
+       va_list args;
+       
+       if(!flagseen['W']) {
+               ++warning_count;
+               as_where();
+               va_start(args, Format);
+               vfprintf(stderr, Format, args);
+               va_end(args);
+               (void) putc('\n', stderr);
+       }
+} /* as_warn() */
+#else
+#ifndef NO_VARARGS
+void as_warn(Format,va_alist)
+char *Format;
+va_dcl
+{
+       va_list args;
+       
+       if(!flagseen['W']) {
+               ++warning_count;
+               as_where();
+               va_start(args);
+               vfprintf(stderr, Format, args);
+               va_end(args);
+               (void) putc('\n', stderr);
+       }
+} /* as_warn() */
+#else
+/*VARARGS1 */
+as_warn(Format,args)
+char *Format;
+{
+       /* -W supresses warning messages. */
+       if (! flagseen ['W']) {
+               ++warning_count;
+               as_where();
+               _doprnt (Format, &args, stderr);
+               (void)putc ('\n', stderr);
+               /* as_where(); */
+       }
+} /* as_warn() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+       if(!flagseen['W']) {
+               ++warning_count;
+               as_where();
+               fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+               (void)putc('\n',stderr);
+       }
+} /* as_warn() */
+#endif
+/*
+ *                     a s _ b a d ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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.
+ */
+
+#ifndef NO_STDARG
+void as_bad(Format)
+const char *Format;
+{
+       va_list args;
+
+       ++error_count;
+       as_where();
+       va_start(args, Format);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       (void) putc('\n', stderr);
+} /* as_bad() */
+#else
+#ifndef NO_VARARGS
+void as_bad(Format,va_alist)
+char *Format;
+va_dcl
+{
+       va_list args;
+
+       ++error_count;
+       as_where();
+       va_start(args);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       (void) putc('\n', stderr);
+} /* as_bad() */
+#else
+/*VARARGS1 */
+as_bad(Format,args)
+char *Format;
+{
+       ++error_count;
+       as_where();
+       _doprnt (Format, &args, stderr);
+       (void)putc ('\n', stderr);
+       /* as_where(); */
+} /* as_bad() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+       ++error_count;
+       as_where();
+       fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+       (void)putc('\n',stderr);
+} /* as_bad() */
+#endif
+
+/*
+ *                     a s _ f a t a l ()
+ *
+ * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal
+ * message, and locate stdsource in input file(s).
+ * Please only use this for when we DON'T have some recovery action.
+ * It exit()s with a warning status.
+ */
+
+#ifndef NO_STDARG
+void as_fatal(Format)
+const char *Format;
+{
+       va_list args;
+
+       as_where();
+       va_start(args, Format);
+       fprintf (stderr, "FATAL:");
+       vfprintf(stderr, Format, args);
+       (void) putc('\n', stderr);
+       va_end(args);
+       exit(42);
+} /* as_fatal() */
+#else
+#ifndef NO_VARARGS
+void as_fatal(Format,va_alist)
+char *Format;
+va_dcl
+{
+       va_list args;
+
+       as_where();
+       va_start(args);
+       fprintf (stderr, "FATAL:");
+       vfprintf(stderr, Format, args);
+       (void) putc('\n', stderr);
+       va_end(args);
+       exit(42);
+} /* as_fatal() */
+#else
+/*VARARGS1 */
+as_fatal(Format, args)
+char *Format;
+{
+       as_where();
+       fprintf(stderr,"FATAL:");
+       _doprnt (Format, &args, stderr);
+       (void)putc ('\n', stderr);
+       /* as_where(); */
+       exit(42);                       /* What is a good exit status? */
+} /* as_fatal() */
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+#ifdef DONTDEF
+void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *Format;
+{
+       as_where();
+       fprintf (stderr, "FATAL:");
+       fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+       (void) putc('\n', stderr);
+       exit(42);
+} /* as_fatal() */
+#endif
+
+/* end: messages.c */
diff --git a/gas/obj.h b/gas/obj.h
new file mode 100644 (file)
index 0000000..68e4243
--- /dev/null
+++ b/gas/obj.h
@@ -0,0 +1,67 @@
+/* obj.h - defines the object dependent hooks for all object
+   format backends.
+
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#ifdef __STDC__
+
+char *obj_default_output_file_name(void);
+void obj_crawl_symbol_chain(object_headers *headers);
+void obj_emit_relocations(char **where, fixS *fixP, relax_addressT segment_address_in_file);
+void obj_emit_strings(char **where);
+void obj_emit_symbols(char **where, symbolS *symbol_rootP);
+void obj_header_append(char **where, object_headers *headers);
+void obj_read_begin_hook(void);
+void obj_symbol_new_hook(symbolS *symbolP);
+void obj_symbol_to_chars(char **where, symbolS *symbolP);
+
+#ifndef obj_pre_write_hook
+void obj_pre_write_hook(object_headers *headers);
+#endif /* obj_pre_write_hook */
+
+#else
+
+char *obj_default_output_file_name();
+void obj_crawl_symbol_chain();
+void obj_emit_relocations();
+void obj_emit_strings();
+void obj_emit_symbols();
+void obj_header_append();
+void obj_read_begin_hook();
+void obj_symbol_new_hook();
+void obj_symbol_to_chars();
+
+#ifndef obj_pre_write_hook
+void obj_pre_write_hook();
+#endif /* obj_pre_write_hook */
+
+#endif /* __STDC__ */
+
+extern const pseudo_typeS obj_pseudo_table[];
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of obj.h */
diff --git a/gas/output-file.c b/gas/output-file.c
new file mode 100644 (file)
index 0000000..423bab2
--- /dev/null
@@ -0,0 +1,83 @@
+/* output-file.c -  Deal with the output file
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * Confines all details of emitting object 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!
+ */
+
+ /* note that we do need config info.  xoxorich. */
+
+/* #include "style.h" */
+#include <stdio.h>
+
+#include "as.h"
+
+#include "output-file.h"
+
+static FILE *stdoutput;
+
+void output_file_create(name)
+char *name;
+{
+  if(name[0]=='-' && name[1]=='\0')
+    stdoutput=stdout;
+  else if ( ! (stdoutput = fopen( name, "w" )) )
+    {
+      as_perror ("FATAL: Can't create %s", name);
+      exit(42);
+    }
+} /* output_file_create() */
+
+
+
+void output_file_close(filename)
+char *filename;
+{
+  if ( EOF == fclose( stdoutput ) )
+    {
+      as_perror ("FATAL: Can't close %s", filename);
+      exit(42);
+    }
+  stdoutput = NULL;            /* Trust nobody! */
+} /* output_file_close() */
+
+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");
+       }
+    }
+} /* output_file_append() */
+
+/* end: output-file.c */
diff --git a/gas/output-file.h b/gas/output-file.h
new file mode 100644 (file)
index 0000000..f5c8073
--- /dev/null
@@ -0,0 +1,18 @@
+
+
+#ifdef __STDC__
+
+void output_file_append(char *where, long length, char *filename);
+void output_file_close(char *filename);
+void output_file_create(char *name);
+
+#else /* __STDC__ */
+
+void output_file_append();
+void output_file_close();
+void output_file_create();
+
+#endif /* __STDC__ */
+
+
+/* end of output-file.h */
diff --git a/gas/read.c b/gas/read.c
new file mode 100644 (file)
index 0000000..818f139
--- /dev/null
@@ -0,0 +1,2281 @@
+/* read.c - read a source file -
+   Copyright (C) 1986, 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#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.)
+                                  */
+
+#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
+                               /* This is the largest known floating point */
+                               /* format (for now). It will grow when we */
+                               /* do 4361 style flonums. */
+
+
+/* Routines that read assembler source text to build spagetti in memory. */
+/* Another group of these functions is in the as-expr.c module */
+
+#include "as.h"
+
+#include "obstack.h"
+
+char *input_line_pointer;      /*->next char of source file to parse. */
+
+
+#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!) !
+#endif
+
+const char /* used by is_... macros. our ctype[] */
+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, 3, 0, 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, 0,       /* 0123456789:;<=>? */
+  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, 3, 0, 0, 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, 3, 0, 0, 0, 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
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _  /* */
+};
+#undef _
+
+                               /* Functions private to this file. */
+
+char line_comment_chars[1];
+char line_separator_chars[1];
+
+static char *buffer;           /* 1st char of each buffer of lines is here. */
+static char *buffer_limit;     /*->1 + last char in buffer. */
+
+static char *bignum_low;       /* Lowest char of bignum. */
+static char *bignum_limit;     /* 1st illegal address of bignum. */
+static char *bignum_high;      /* Highest char of bignum. */
+                               /* May point to (bignum_start-1). */
+                               /* Never >= bignum_limit. */
+static char *old_buffer = 0;   /* 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 = 0;
+#endif
+
+#ifdef __STDC__
+
+static char *demand_copy_string(int *lenP);
+static int is_it_end_of_statement(void);
+static unsigned int next_char_of_string(void);
+static segT get_known_segmented_expression(expressionS *expP);
+static void grow_bignum(void);
+static void pobegin(void);
+static void stringer(int append_zero);
+
+#else /* __STDC__ */
+
+static char *demand_copy_string();
+static int is_it_end_of_statement();
+static unsigned int next_char_of_string();
+static segT get_known_segmented_expression();
+static void grow_bignum();
+static void pobegin();
+static void stringer();
+
+#endif /* __STDC__ */
+
+\f
+void
+read_begin()
+{
+  char *p;
+
+  pobegin();
+  obj_read_begin_hook();
+
+  obstack_begin(&notes, 5000);
+  /* Start off assuming that we won't need more than 20 levels
+     of .if/.endif; if we need more, we can always get it. */
+  obstack_begin (&cond_obstack, 20);
+  /* We start life accepting input. */
+  obstack_1grow (&cond_obstack, 1);
+
+#define BIGNUM_BEGIN_SIZE (16)
+  bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
+  bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
+
+  /* Use machine dependent syntax */
+  for (p = line_separator_chars; *p; p++)
+    is_end_of_line[*p] = 1;
+  /* Use more.  FIXME-SOMEDAY. */
+}
+\f
+/* set up pseudo-op tables */
+
+struct hash_control *
+po_hash = NULL;                        /* use before set up: NULL->address error */
+
+#ifdef DONTDEF
+void   s_gdbline(),    s_gdblinetab();
+void   s_gdbbeg(),     s_gdbblock(),   s_gdbend(),     s_gdbsym();
+#endif
+
+static const pseudo_typeS
+potable[] =
+{
+  { "abort",   s_abort,        0       },
+  { "align",   s_align_ptwo,   0       },
+  { "ascii",   stringer,       0       },
+  { "asciz",   stringer,       1       },
+/* block */
+  { "byte",    cons,           1       },
+  { "comm",    s_comm,         0       },
+  { "data",    s_data,         0       },
+/* dim */
+  { "double",  float_cons,     'd'     },
+/* dsect */
+  { "eject",   s_ignore,       0       },      /* Formfeed listing */
+  { "else",    s_else,         0       },
+  { "end",     s_end,          0       },
+  { "endif",   s_endif,        0       },
+/* endef */
+  { "equ",     s_set,          0       },
+/* err */
+/* extend */
+  { "extern",  s_ignore,       0       },      /* We treat all undef as ext */
+  { "app-file",        s_app_file,     0       },
+  { "file",    s_app_file,     0       },
+  { "fill",    s_fill,         0       },
+  { "float",   float_cons,     'f'     },
+#ifdef DONTDEF
+  { "gdbbeg",  s_gdbbeg,       0       },
+  { "gdbblock",        s_gdbblock,     0       },
+  { "gdbend",  s_gdbend,       0       },
+  { "gdbsym",  s_gdbsym,       0       },
+  { "gdbline", s_gdbline,      0       },
+  { "gdblinetab",s_gdblinetab, 0       },
+#endif
+  { "global",  s_globl,        0       },
+  { "globl",   s_globl,        0       },
+  { "hword",   cons,           2       },
+  { "if",      s_if,           0       },
+  { "ifdef",   s_ifdef,        0       },
+  { "ifeqs",   s_ifeqs,        0       },
+  { "ifndef",  s_ifdef,        1       },
+  { "ifnes",   s_ifeqs,        1       },
+  { "ifnotdef",        s_ifdef,        1       },
+  { "include", s_include,      0       },
+  { "int",     cons,           4       },
+  { "lcomm",   s_lcomm,        0       },
+  { "lflags",  s_ignore,       0       },      /* Listing flags */
+  { "list",    s_ignore,       0       },      /* Turn listing on */
+  { "long",    cons,           4       },
+  { "lsym",    s_lsym,         0       },
+  { "nolist",  s_ignore,       0       },      /* Turn listing off */
+  { "octa",    big_cons,       16      },
+  { "org",     s_org,          0       },
+/* print */
+  { "quad",    big_cons,       8       },
+  { "sbttl",   s_ignore,       0       },      /* Subtitle of listing */
+/* scl */
+/* sect */
+  { "set",     s_set,          0       },
+  { "short",   cons,           2       },
+  { "single",  float_cons,     'f'     },
+/* size */
+  { "space",   s_space,        0       },
+/* tag */
+  { "text",    s_text,         0       },
+  { "title",   s_ignore,       0       },      /* Listing title */
+/* type */
+/* use */
+/* val */
+  { "word",    cons,           2       },
+  { NULL}      /* end sentinel */
+};
+
+static void pobegin() {
+       char *  errtxt;         /* error text */
+       const pseudo_typeS * pop;
+
+       po_hash = hash_new();
+
+       /* Do the target-specific pseudo ops. */
+       for (pop=md_pseudo_table; pop->poc_name; pop++) {
+               errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
+               if (errtxt && *errtxt) {
+                       as_fatal("error constructing md pseudo-op table");
+               } /* on error */
+       } /* for each op */
+
+       /* Now object specific.  Skip any that were in the target table. */
+       for (pop=obj_pseudo_table; pop->poc_name; pop++) {
+               errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
+               if (errtxt && *errtxt) {
+                       if (!strcmp (errtxt, "exists")) {
+#ifdef DIE_ON_OVERRIDES
+                               as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name);
+#endif /* DIE_ON_OVERRIDES */
+                               continue;       /* OK if target table overrides. */
+                       } else {
+                               as_fatal("error constructing obj pseudo-op table");
+                       } /* if overridden */
+               } /* on error */
+       } /* for each op */
+
+       /* Now portable ones.  Skip any that we've seen already. */
+       for (pop=potable; pop->poc_name; pop++) {
+               errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
+               if (errtxt && *errtxt) {
+                       if (!strcmp (errtxt, "exists")) {
+#ifdef DIE_ON_OVERRIDES
+                               as_fatal("pseudo op \".%s\" overridden.\n", pop->poc_name);
+#endif /* DIE_ON_OVERRIDES */
+                               continue;       /* OK if target table overrides. */
+                       } else {
+                               as_fatal("error constructing obj pseudo-op table");
+                       } /* if overridden */
+               } /* on error */
+       } /* for each op */
+
+       return;
+} /* pobegin() */
+\f
+#define HANDLE_CONDITIONAL_ASSEMBLY()  \
+  if (ignore_input ())                                 \
+    {                                                  \
+      while (! is_end_of_line[*input_line_pointer++])  \
+       if (input_line_pointer == buffer_limit)         \
+         break;                                        \
+      continue;                                                \
+    }
+
+/*     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;
+       /* register struct frag * fragP; JF unused */   /* a frag we just made */
+       pseudo_typeS    *pop;
+#ifdef DONTDEF
+       void gdb_block_beg();
+       void gdb_block_position();
+       void gdb_block_end();
+       void gdb_symbols_fixup();
+#endif
+
+       buffer = input_scrub_new_file(name);
+
+       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 (input_line_pointer[-1] == '\n') {
+                               bump_line_counters();
+                       } /* just passed a newline */
+                       /*
+                        * 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 = *input_line_pointer++;
+                       }
+                       know(c != ' '); /* No further leading whitespace. */
+                       /*
+                        * 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 (c == ':') {
+                                       colon(s);       /* user-defined label */
+                                       * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */
+                                       /* Input_line_pointer->after ':'. */
+                                       SKIP_WHITESPACE();
+                               } else if (c == '=' || input_line_pointer[1] == '=') { /* JF deal with FOO=BAR */
+                                       equals(s);
+                                       demand_empty_rest_of_line();
+                               } else {                /* expect pseudo-op or machine instruction */
+                                       if (*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 '.'.
+                                                */
+                                               
+                                               pop = (pseudo_typeS *) hash_find(po_hash, s+1);
+                                               
+                                               /* Print the error msg now, while we still can */
+                                               if (!pop) {
+                                                       as_bad("Unknown pseudo-op:  `%s'",s);
+                                                       *input_line_pointer = c;
+                                                       s_ignore(0);
+                                                       break;
+                                               }
+                                               
+                                               /* 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++;
+                                               } /* Skip seperator after keyword. */
+                                               /*
+                                                * Input_line is restored.
+                                                * Input_line_pointer->1st non-blank char
+                                                * after pseudo-operation.
+                                                */
+                                               if (!pop) {
+                                                       ignore_rest_of_line();
+                                                       break;
+                                               } else {
+                                                       (*pop->poc_handler)(pop->poc_val);
+                                               } /* if we have one */
+                                       } else {                /* machine instruction */
+                                               /* 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[*input_line_pointer]) {
+                                                       input_line_pointer++;
+                                               }
+                                               c = *input_line_pointer;
+                                               *input_line_pointer = '\0';
+                                               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) */
+                       
+                       
+                       if (is_end_of_line [c]) {
+                               continue;
+                       } /* empty statement */
+                       
+                       if (isdigit(c)) { /* local label  ("4:") */
+                               HANDLE_CONDITIONAL_ASSEMBLY ();
+                               
+                               temp = c - '0';
+#ifdef LOCAL_LABELS_DOLLAR
+                               if (*input_line_pointer=='$')
+                                   input_line_pointer++;
+#endif
+                               if (* input_line_pointer ++ == ':')
+                                   {
+                                           local_colon (temp);
+                                   }
+                               else
+                                   {
+                                           as_bad("Spurious digit %d.", temp);
+                                           input_line_pointer -- ;
+                                           ignore_rest_of_line();
+                                   }
+                               continue;
+                       } /* 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;
+                               int new_length;
+                               char *tmp_buf = 0;
+                               extern char *scrub_string,*scrub_last_string;
+                               
+                               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) {
+                                       int tmp_len;
+                                       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);
+                                       bcopy(s,tmp_buf,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);
+                                               bcopy(buffer,tmp_buf+tmp_len,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;
+                               }
+                               new_buf=xmalloc(100);
+                               new_length=100;
+                               new_tmp=new_buf;
+
+                               scrub_string=s;
+                               scrub_last_string = ends;
+                               for(;;) {
+                                       int ch;
+
+                                       ch = do_scrub_next_char(scrub_from_string, scrub_to_string);
+                                       if (ch==EOF) break;
+                                       *new_tmp++=ch;
+                                       if (new_tmp==new_buf+new_length) {
+                                               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();
+
+                       /* 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) */
+               if (old_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) */
+       input_scrub_close();    /* Close the input file */
+} /* read_a_source_file() */
+
+void s_abort() {
+       as_fatal(".abort detected.  Abandoning ship.");
+} /* s_abort() */
+
+/* For machines where ".align 4" means align to a 4 byte boundary. */
+void s_align_bytes(arg)
+int arg;
+{
+    register unsigned int temp;
+    register long temp_fill;
+    unsigned int i = 0;
+    unsigned long max_alignment = 1 << 15;
+
+    if (is_end_of_line[*input_line_pointer])
+       temp = arg;             /* Default value from pseudo-op table */
+    else
+       temp = get_absolute_expression ();
+
+    if (temp > max_alignment) {
+       as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
+    }
+
+    /*
+     * For the sparc, `.align (1<<n)' actually means `.align n'
+     * so we have to convert it.
+     */
+    if (temp != 0) {
+       for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
+           ;
+    }
+    if (temp != 1)
+       as_bad("Alignment not a power of 2");
+
+    temp = i;
+    if (*input_line_pointer == ',') {
+       input_line_pointer ++;
+       temp_fill = get_absolute_expression ();
+    } else {
+       temp_fill = 0;
+    }
+    /* Only make a frag if we HAVE to. . . */
+    if (temp && ! need_pass_2)
+       frag_align(temp, (int)temp_fill);
+
+    demand_empty_rest_of_line();
+} /* s_align_bytes() */
+
+/* For machines where ".align 4" means align to 2**4 boundary. */
+void s_align_ptwo() {
+       register int temp;
+       register long temp_fill;
+       long max_alignment = 15;
+
+       temp = get_absolute_expression ();
+       if (temp > max_alignment)
+               as_bad("Alignment too large: %d. assumed.", temp = max_alignment);
+       else if (temp < 0) {
+               as_bad("Alignment negative. 0 assumed.");
+               temp = 0;
+       }
+       if (*input_line_pointer == ',') {
+               input_line_pointer ++;
+               temp_fill = get_absolute_expression ();
+       } else
+               temp_fill = 0;
+       /* Only make a frag if we HAVE to. . . */
+       if (temp && ! need_pass_2)
+               frag_align (temp, (int)temp_fill);
+
+       record_alignment(now_seg, temp);
+
+       demand_empty_rest_of_line();
+} /* s_align_ptwo() */
+
+void s_comm() {
+       register char *name;
+       register char c;
+       register char *p;
+       register int 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();
+       if (*input_line_pointer != ',') {
+               as_bad("Expected comma after symbol-name: rest of line ignored.");
+               ignore_rest_of_line();
+               return;
+       }
+       input_line_pointer ++; /* skip ',' */
+       if ((temp = get_absolute_expression()) < 0) {
+               as_warn(".COMMon length (%d.) <0! Ignored.", temp);
+               ignore_rest_of_line();
+               return;
+       }
+       *p = 0;
+       symbolP = symbol_find_or_make(name);
+       *p = c;
+       if (S_IS_DEFINED(symbolP)) {
+               as_bad("Ignoring attempt to re-define symbol");
+               ignore_rest_of_line();
+               return;
+       }
+       if (S_GET_VALUE(symbolP)) {
+               if (S_GET_VALUE(symbolP) != temp)
+                       as_bad("Length of .comm \"%s\" is already %d. Not changed to %d.",
+                               S_GET_NAME(symbolP),
+                               S_GET_VALUE(symbolP),
+                               temp);
+       } else {
+               S_SET_VALUE(symbolP, temp);
+               S_SET_EXTERNAL(symbolP);
+       }
+#ifdef VMS
+       if (!temp)
+               symbolP->sy_other = const_flag;
+#endif
+       know(symbolP->sy_frag == &zero_address_frag);
+       demand_empty_rest_of_line();
+} /* s_comm() */
+
+void
+s_data()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       subseg_new (SEG_DATA, (subsegT)temp);
+#ifdef VMS
+       const_flag = 0;
+#endif
+       demand_empty_rest_of_line();
+}
+
+void s_app_file() {
+       register char *s;
+       int length;
+
+       /* Some assemblers tolerate immediately following '"' */
+       if ((s = demand_copy_string(&length)) != 0) {
+               new_logical_line(s, -1);
+               demand_empty_rest_of_line();
+       }
+#ifdef OBJ_COFF
+       c_dot_file_symbol(s);
+#endif /* OBJ_COFF */
+} /* s_app_file() */
+
+void s_fill() {
+       long temp_repeat;
+       long temp_size;
+       register long temp_fill;
+       char *p;
+
+       if (get_absolute_expression_and_terminator(& temp_repeat) != ',') {
+               input_line_pointer --; /* Backup over what was not a ','. */
+               as_bad("Expect comma after rep-size in .fill:");
+               ignore_rest_of_line();
+               return;
+       }
+       if (get_absolute_expression_and_terminator(& temp_size) != ',') {
+                 input_line_pointer --; /* Backup over what was not a ','. */
+                 as_bad("Expected comma after size in .fill");
+                 ignore_rest_of_line();
+                 return;
+       }
+       /*
+        * 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_bad(".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) {
+               as_warn("Repeat < 0, .fill ignored");
+               temp_size = 0;
+       }
+       temp_fill = get_absolute_expression ();
+       if (temp_size && !need_pass_2) {
+               p = frag_var(rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
+               bzero (p, (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, 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();
+}
+
+#ifdef DONTDEF
+void
+s_gdbbeg()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       if (temp < 0)
+               as_warn("Block number <0. Ignored.");
+       else if (flagseen ['G'])
+               gdb_block_beg ((long) temp, frag_now, (long)(obstack_next_free(& frags) - frag_now->fr_literal));
+       demand_empty_rest_of_line ();
+}
+
+void
+s_gdbblock()
+{
+       register int position;
+       int temp;
+
+       if (get_absolute_expression_and_terminator (&temp) != ',') {
+               as_bad("expected comma before position in .gdbblock");
+               --input_line_pointer;
+               ignore_rest_of_line ();
+               return;
+       }
+       position = get_absolute_expression ();
+       if (flagseen ['G'])
+               gdb_block_position ((long) temp, (long) position);
+       demand_empty_rest_of_line ();
+}
+
+void
+s_gdbend()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       if (temp < 0)
+               as_warn("Block number <0. Ignored.");
+       else if (flagseen ['G'])
+               gdb_block_end ((long) temp, frag_now, (long)(obstack_next_free(& frags) - frag_now->fr_literal));
+       demand_empty_rest_of_line ();
+}
+
+void
+s_gdbsym()
+{
+       register char *name,
+                       *p;
+       register char c;
+       register symbolS *      symbolP;
+       register int temp;
+
+       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 != ',') {
+               as_bad("Expected comma after name");
+               ignore_rest_of_line();
+               return;
+       }
+       input_line_pointer ++;
+       if ((temp = get_absolute_expression ()) < 0) {
+               as_bad("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
+               ignore_rest_of_line();
+               return;
+       }
+       if (flagseen ['G'])
+               gdb_symbols_fixup (symbolP, (long)temp);
+       demand_empty_rest_of_line ();
+}
+
+void
+s_gdbline()
+{
+       int file_number,
+               lineno;
+
+       if (get_absolute_expression_and_terminator(&file_number) != ',') {
+               as_bad("expected comman after filenum in .gdbline");
+               ignore_rest_of_line();
+               return;
+       }
+       lineno=get_absolute_expression();
+       if (flagseen['G'])
+               gdb_line(file_number,lineno);
+       demand_empty_rest_of_line();
+}
+
+
+void
+s_gdblinetab()
+{
+       int file_number,
+               offset;
+
+       if (get_absolute_expression_and_terminator(&file_number) != ',') {
+               as_bad("expected comma after filenum in .gdblinetab");
+               ignore_rest_of_line();
+               return;
+       }
+       offset=get_absolute_expression();
+       if (flagseen['G'])
+               gdb_line_tab(file_number,offset);
+       demand_empty_rest_of_line();
+}
+#endif
+
+void s_globl() {
+       register char *name;
+       register int c;
+       register 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_EXTERNAL(symbolP);
+               if (c==',') {
+                       input_line_pointer++;
+                       SKIP_WHITESPACE();
+                       if (*input_line_pointer=='\n')
+                               c='\n';
+               }
+       } while(c==',');
+       demand_empty_rest_of_line();
+} /* s_globl() */
+
+void s_lcomm(needs_align)
+int 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)
+                        */
+{
+       register char *name;
+       register char c;
+       register char *p;
+       register int temp;
+       register symbolS *      symbolP;
+       const int max_alignment = 15;
+       int align;
+
+       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;
+       }
+       input_line_pointer ++;
+
+       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 (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(SEG_BSS, align);
+       } /* if needs align */
+
+       *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) == SEG_BSS) && (S_GET_VALUE(symbolP) == local_bss_counter))
+            || (!S_IS_DEFINED(symbolP) && S_GET_VALUE(symbolP) == 0))) {
+               if (needs_align){
+                       /* Align */
+                       align = ~ ((~0) << align);      /* Convert to a mask */
+                       local_bss_counter =
+                           (local_bss_counter + align) & (~align);
+               }
+
+               S_SET_VALUE(symbolP,local_bss_counter);
+               S_SET_SEGMENT(symbolP, SEG_BSS);
+#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 */
+               symbolP->sy_frag  = & bss_address_frag;
+               local_bss_counter += temp;
+       } else {
+               as_bad("Ignoring attempt to re-define symbol from %d. to %d.",
+                       S_GET_VALUE(symbolP), local_bss_counter);
+       }
+       demand_empty_rest_of_line();
+
+       return;
+} /* s_lcomm() */
+
+void
+s_long()
+{
+       cons(4);
+}
+
+void
+s_int()
+{
+       cons(4);
+}
+
+void s_lsym() {
+       register char *name;
+       register char c;
+       register char *p;
+       register segT segment;
+       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 ++;
+       segment = expression(& exp);
+       if (segment != SEG_ABSOLUTE
+        && segment != SEG_DATA
+        && segment != SEG_TEXT
+        && segment != SEG_BSS
+        && segment != SEG_REGISTER) {
+               as_bad("Bad expression: %s", segment_name(segment));
+               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) == SEG_UNKNOWN
+           && S_GET_VALUE(symbolP) == 0) {
+               /* The name might be an undefined .global symbol; be
+                  sure to keep the "external" bit. */
+               S_SET_SEGMENT(symbolP, segment);
+               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() */
+
+void s_org() {
+       register segT segment;
+       expressionS exp;
+       register long temp_fill;
+       register char *p;
+/*
+ * 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 -ve 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) {
+               if (segment != now_seg && segment != SEG_ABSOLUTE)
+                   as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.",
+                          segment_name(segment), segment_name(now_seg));
+               p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol,
+                             exp . X_add_number, (char *)0);
+               * p = temp_fill;
+       } /* if (ok to make frag) */
+       demand_empty_rest_of_line();
+} /* s_org() */
+
+void s_set() {
+       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;
+               register char *ptr;
+
+               segment = get_known_segmented_expression(& exp);
+
+               if (!need_pass_2) {
+                       if (segment != now_seg && segment != SEG_ABSOLUTE)
+                           as_bad("Invalid segment \"%s\". Segment \"%s\" assumed.",
+                                   segment_name(segment),
+                                   segment_name (now_seg));
+                       ptr = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
+                                      exp.X_add_number, (char *)0);
+                       *ptr= 0;
+               } /* if (ok to make frag) */
+
+               *end_name = delim;
+               return;
+       }
+
+       if ((symbolP = symbol_find(name)) == NULL
+           && (symbolP = md_undefined_symbol(name)) == NULL) {
+               symbolP = symbol_new(name,
+                                    SEG_UNKNOWN,
+                                    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;
+       pseudo_set(symbolP);
+       demand_empty_rest_of_line();
+} /* s_set() */
+
+void s_space() {
+       long temp_repeat;
+       register long temp_fill;
+       register char *p;
+
+       /* Just like .fill, but temp_size = 1 */
+       if (get_absolute_expression_and_terminator(& temp_repeat) == ',') {
+               temp_fill = get_absolute_expression ();
+       } else {
+               input_line_pointer --; /* Backup over what was not a ','. */
+               temp_fill = 0;
+       }
+       if (temp_repeat <= 0) {
+               as_warn("Repeat < 0, .space ignored");
+               ignore_rest_of_line();
+               return;
+       }
+       if (! need_pass_2) {
+               p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
+ temp_repeat, (char *)0);
+               * p = temp_fill;
+       }
+       demand_empty_rest_of_line();
+} /* s_space() */
+
+void
+s_text()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       subseg_new (SEG_TEXT, (subsegT)temp);
+       demand_empty_rest_of_line();
+} /* s_text() */
+
+\f
+/*(JF was static, but can't be if machine dependent pseudo-ops are to use it */
+
+void demand_empty_rest_of_line() {
+       SKIP_WHITESPACE();
+       if (is_end_of_line [*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 [* 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 [* input_line_pointer])
+       {
+         input_line_pointer ++;
+       }
+    }
+  input_line_pointer ++;       /* Return pointing just after end-of-line. */
+  know(is_end_of_line [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;
+ *     May set need_pass_2 == 1.
+ */
+void
+pseudo_set (symbolP)
+     symbolS * symbolP;
+{
+  expressionS  exp;
+  register segT        segment;
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+  int ext;
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+  know(symbolP);               /* NULL pointer is logic error. */
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+  ext=S_IS_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+  if ((segment = expression(& exp)) == SEG_ABSENT)
+    {
+      as_bad("Missing expression: absolute 0 assumed");
+      exp . X_seg              = SEG_ABSOLUTE;
+      exp . X_add_number       = 0;
+    }
+
+  switch (segment)
+    {
+    case SEG_BIG:
+      as_bad("%s number invalid. Absolute 0 assumed.",
+             exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
+      S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+      ext ? S_SET_EXTERNAL(symbolP) :
+           S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+      S_SET_VALUE(symbolP, 0);
+      symbolP->sy_frag = & zero_address_frag;
+      break;
+
+    case SEG_ABSENT:
+      as_warn("No expression:  Using absolute 0");
+      S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+      ext ? S_SET_EXTERNAL(symbolP) :
+           S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+      S_SET_VALUE(symbolP, 0);
+      symbolP->sy_frag = & zero_address_frag;
+      break;
+
+    case SEG_DIFFERENCE:
+      if (exp.X_add_symbol && exp.X_subtract_symbol
+          && (S_GET_SEGMENT(exp.X_add_symbol) ==
+             S_GET_SEGMENT(exp.X_subtract_symbol))) {
+       if (exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) {
+         as_bad("Unknown expression: symbols %s and %s are in different frags.",
+                S_GET_NAME(exp.X_add_symbol), S_GET_NAME(exp.X_subtract_symbol));
+         need_pass_2++;
+       }
+       exp.X_add_number+=S_GET_VALUE(exp.X_add_symbol) -
+           S_GET_VALUE(exp.X_subtract_symbol);
+      } else
+       as_bad("Complex expression. Absolute segment assumed.");
+    case SEG_ABSOLUTE:
+      S_SET_SEGMENT(symbolP, SEG_ABSOLUTE);
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+      ext ? S_SET_EXTERNAL(symbolP) :
+           S_CLEAR_EXTERNAL(symbolP);
+#endif /* OBJ_AOUT or OBJ_BOUT */
+      S_SET_VALUE(symbolP, exp.X_add_number);
+      symbolP->sy_frag = & zero_address_frag;
+      break;
+
+    case SEG_DATA:
+    case SEG_TEXT:
+    case SEG_BSS:
+      switch(segment) {
+       case SEG_DATA:  S_SET_SEGMENT(symbolP, SEG_DATA); break;
+       case SEG_TEXT:  S_SET_SEGMENT(symbolP, SEG_TEXT); break;
+       case SEG_BSS:   S_SET_SEGMENT(symbolP, SEG_BSS); break;
+       default:        abort();
+      }        /* switch on segment */
+
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+      if (ext) {
+             S_SET_EXTERNAL(symbolP);
+      } else {
+             S_CLEAR_EXTERNAL(symbolP);
+      }        /* if external */
+#endif /* OBJ_AOUT or OBJ_BOUT */
+
+      S_SET_VALUE(symbolP, exp.X_add_number + S_GET_VALUE(exp.X_add_symbol));
+      symbolP->sy_frag = exp . X_add_symbol->sy_frag;
+      break;
+
+    case SEG_PASS1:            /* Not an error. Just try another pass. */
+      symbolP->sy_forward=exp.X_add_symbol;
+      as_bad("Unknown expression");
+      know(need_pass_2 == 1);
+      break;
+
+    case SEG_UNKNOWN:
+      symbolP->sy_forward=exp.X_add_symbol;
+      /* as_warn("unknown symbol"); */
+      /* need_pass_2 = 1; */
+      break;
+
+    default:
+      BAD_CASE(segment);
+      break;
+    }
+}
+\f
+/*
+ *                     cons()
+ *
+ * CONStruct more frag of .bytes, or .words etc.
+ * Should need_pass_2 be 1 then emit no frag(s).
+ * This understands EXPRESSIONS, as opposed to big_cons().
+ *
+ * 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.
+ */
+
+ /* worker to do .byte etc statements */
+ /* clobbers input_line_pointer, checks */
+ /* end-of-line. */
+void cons(nbytes)
+register unsigned int nbytes;  /* 1=.byte, 2=.word, 4=.long */
+{
+  register char c;
+  register long mask;  /* High-order bits we will left-truncate, */
+                               /* but includes sign bit also. */
+  register long get;   /* what we get */
+  register long use;   /* get after truncation. */
+  register long unmask;        /* what bits we will store */
+  register char *      p;
+  register segT                segment;
+           expressionS exp;
+
+  /*
+   * Input_line_pointer->1st char after pseudo-op-code and could legally
+   * be a end-of-line. (Or, less legally an eof - which we cope with.)
+   */
+  /* JF << of >= number of bits in the object is undefined.  In particular
+     SPARC (Sun 4) has problems */
+
+  if (nbytes>=sizeof(long)) {
+         mask = 0;
+  } else {
+         mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+  } /* bigger than a long */
+
+  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
+
+  /*
+   * The following awkward logic is to parse ZERO or more expressions,
+   * comma seperated. Recall an expression includes its leading &
+   * trailing blanks. We fake a leading ',' if there is (supposed to
+   * be) a 1st expression, and keep demanding 1 expression for each ','.
+   */
+  if (is_it_end_of_statement()) {
+         c = 0;                        /* Skip loop. */
+         input_line_pointer++; /* Matches end-of-loop 'correction'. */
+  } else {
+         c = ',';
+  } /* if the end else fake it */
+
+/* Do loop. */
+  while (c == ',') {
+         unsigned int bits_available = BITS_PER_CHAR * nbytes;
+         /* used for error messages and rescanning */
+         char *hold = input_line_pointer;
+
+         /* At least scan over the expression. */
+         segment = expression(&exp);
+
+#ifdef WANT_BITFIELDS
+         /* Some other 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".
+
+            FIXME-SOMEDAY: If this is considered generally
+            useful, this logic should probably be reworked.
+            xoxorich. */
+
+         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 (segment == SEG_ABSENT) {
+                                 as_warn("Using a bit field width of zero.");
+                                 exp.X_add_number = 0;
+                                 segment = SEG_ABSOLUTE;
+                         } /* implied zero width bitfield */
+                         
+                         if (segment != SEG_ABSOLUTE) {
+                                 *input_line_pointer = '\0';
+                                 as_bad("Field width \"%s\" too complex for a bitfield.\n", 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 %d 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 ':' */
+                         
+                         if ((segment = expression(&exp)) != SEG_ABSOLUTE) {
+                                 char cache = *input_line_pointer;
+                                 
+                                 *input_line_pointer = '\0';
+                                 as_bad("Field value \"%s\" too complex for a bitfield.\n", 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;
+                         segment = expression(&exp);
+                 } /* forever loop */
+
+                 exp.X_add_number = value;
+                 segment = SEG_ABSOLUTE;
+      }        /* if looks like a bitfield */
+#endif /* WANT_BITFIELDS */
+
+      if (!need_pass_2) { /* Still worthwhile making frags. */
+
+         /* Don't call this if we are going to junk this pass anyway! */
+         know(segment != SEG_PASS1);
+
+         if (segment == SEG_DIFFERENCE && exp.X_add_symbol == NULL) {
+                 as_bad("Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
+                        S_GET_NAME(exp.X_subtract_symbol),
+                        segment_name(S_GET_SEGMENT(exp.X_subtract_symbol)));
+                 segment = SEG_ABSOLUTE;
+                 /* Leave exp . X_add_number alone. */
+         }
+         p = frag_more(nbytes);
+         switch (segment) {
+           case SEG_BIG:
+             as_bad("%s number invalid. Absolute 0 assumed.",
+                     exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
+             md_number_to_chars (p, (long)0, nbytes);
+             break;
+
+           case SEG_ABSENT:
+             as_warn("0 assumed for missing expression");
+             exp . X_add_number = 0;
+             know(exp . X_add_symbol == NULL);
+             /* fall into SEG_ABSOLUTE */
+           case SEG_ABSOLUTE:
+             get = exp . X_add_number;
+             use = get & unmask;
+             if ((get & mask) && (get & mask) != mask)
+               {               /* Leading bits contain both 0s & 1s. */
+                 as_warn("Value x%x truncated to x%x.", get, use);
+               }
+             md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
+             break;
+
+           case SEG_DIFFERENCE:
+#ifndef WORKING_DOT_WORD
+             if (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_subtract_symbol;
+               x->addnum=exp.X_add_number;
+               x->added=0;
+               new_broken_words++;
+               break;
+             }
+             /* Else Fall through into. . . */
+#endif
+           case SEG_BSS:
+           case SEG_UNKNOWN:
+           case SEG_TEXT:
+           case SEG_DATA:
+#ifdef TC_NS32K
+             fix_new_ns32k (frag_now, p - frag_now->fr_literal, nbytes,
+                      exp . X_add_symbol, exp . X_subtract_symbol,
+                      exp . X_add_number, 0, 0, 2, 0, 0);
+#else
+             fix_new (frag_now, p - frag_now->fr_literal, nbytes,
+                      exp . X_add_symbol, exp . X_subtract_symbol,
+                      exp . X_add_number, 0, RELOC_32);
+#endif /* TC_NS32K */
+             break;
+
+           default:
+             BAD_CASE(segment);
+             break;
+           } /* switch(segment) */
+       } /* if (!need_pass_2) */
+      c = *input_line_pointer++;
+    } /* while(c==',') */
+  input_line_pointer--;        /* Put terminator back into stream. */
+  demand_empty_rest_of_line();
+} /* cons() */
+\f
+/*
+ *                     big_cons()
+ *
+ * CONStruct more frag(s) of .quads, or .octa etc.
+ * Makes 0 or more new frags.
+ * If need_pass_2 == 1, generate no frag.
+ * This understands only bignums, not expressions. Cons() understands
+ * expressions.
+ *
+ * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
+ *
+ * This creates objects with struct obstack_control objs, destroying
+ * any context objs held about a partially completed object. Beware!
+ *
+ *
+ * I think it sucks to have 2 different types of integers, with 2
+ * routines to read them, store them etc.
+ * It would be nicer to permit bignums in expressions and only
+ * complain if the result overflowed. However, due to "efficiency"...
+ */
+/* worker to do .quad etc statements */
+/* clobbers input_line_pointer, checks */
+/* end-of-line. */
+/* 8=.quad 16=.octa ... */
+
+void big_cons(nbytes)
+     register int nbytes;
+{
+  register char c;     /* input_line_pointer->c. */
+  register int radix;
+  register long length;        /* Number of chars in an object. */
+  register int digit;  /* Value of 1 digit. */
+  register int carry;  /* For multi-precision arithmetic. */
+  register int work;   /* For multi-precision arithmetic. */
+  register char *      p;      /* For multi-precision arithmetic. */
+
+  extern char hex_value[];     /* In hex_value.c. */
+
+  /*
+   * The following awkward logic is to parse ZERO or more strings,
+   * comma seperated. Recall an expression includes its leading &
+   * trailing blanks. We fake a leading ',' if there is (supposed to
+   * be) a 1st expression, and keep demanding 1 expression for each ','.
+   */
+  if (is_it_end_of_statement())
+    {
+      c = 0;                   /* Skip loop. */
+    }
+  else
+    {
+      c = ',';                 /* Do loop. */
+      -- input_line_pointer;
+    }
+  while (c == ',')
+    {
+      ++ input_line_pointer;
+      SKIP_WHITESPACE();
+      c = * input_line_pointer;
+      /* C contains 1st non-blank character of what we hope is a number. */
+      if (c == '0')
+       {
+         c = * ++ input_line_pointer;
+         if (c == 'x' || c=='X')
+           {
+             c = * ++ input_line_pointer;
+             radix = 16;
+           }
+         else
+           {
+             radix = 8;
+           }
+       }
+      else
+       {
+         radix = 10;
+       }
+      /*
+       * This feature (?) is here to stop people worrying about
+       * mysterious zero constants: which is what they get when
+       * they completely omit digits.
+       */
+      if (hex_value[c] >= radix) {
+             as_bad("Missing digits. 0 assumed.");
+      }
+      bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
+      for(;   (digit = hex_value [c]) < radix;   c = * ++ input_line_pointer)
+       {
+         /* Multiply existing number by radix, then add digit. */
+         carry = digit;
+         for (p=bignum_low;   p <= bignum_high;   p++)
+           {
+             work = (*p & MASK_CHAR) * radix + carry;
+             *p = work & MASK_CHAR;
+             carry = work >> BITS_PER_CHAR;
+           }
+         if (carry)
+           {
+             grow_bignum();
+             * bignum_high = carry & MASK_CHAR;
+             know((carry & ~ MASK_CHAR) == 0);
+           }
+       }
+      length = bignum_high - bignum_low + 1;
+      if (length > nbytes)
+       {
+         as_warn("Most significant bits truncated in integer constant.");
+       }
+      else
+       {
+         register long leading_zeroes;
+
+         for(leading_zeroes = nbytes - length;
+             leading_zeroes;
+             leading_zeroes --)
+           {
+             grow_bignum();
+             * bignum_high = 0;
+           }
+       }
+      if (! need_pass_2)
+       {
+         p = frag_more (nbytes);
+         bcopy (bignum_low, p, (int)nbytes);
+       }
+      /* C contains character after number. */
+      SKIP_WHITESPACE();
+      c = * input_line_pointer;
+      /* C contains 1st non-blank character after number. */
+    }
+  demand_empty_rest_of_line();
+} /* big_cons() */
+
+ /* Extend bignum by 1 char. */
+static void grow_bignum() {
+  register long length;
+
+  bignum_high ++;
+  if (bignum_high >= bignum_limit)
+    {
+      length = bignum_limit - bignum_low;
+      bignum_low = xrealloc(bignum_low, length + length);
+      bignum_high = bignum_low + length;
+      bignum_limit = bignum_low + length + length;
+    }
+} /* grow_bignum(); */
+\f
+/*
+ *                     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   /* JF was static, but can't be if VAX.C is goning to use it */
+float_cons(float_type)         /* Worker to do .float etc statements. */
+                               /* Clobbers input_line-pointer, checks end-of-line. */
+     register int float_type;  /* 'f':.ffloat ... 'F':.float ... */
+{
+  register char *      p;
+  register char c;
+  int length;  /* Number of chars in an object. */
+  register char *      err;    /* Error from scanning floating literal. */
+  char temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
+
+  /*
+   * The following awkward logic is to parse ZERO or more strings,
+   * comma seperated. Recall an expression includes its leading &
+   * trailing blanks. We fake a leading ',' if there is (supposed to
+   * be) a 1st expression, and keep demanding 1 expression for each ','.
+   */
+  if (is_it_end_of_statement())
+    {
+      c = 0;                   /* Skip loop. */
+      ++ input_line_pointer;   /*->past termintor. */
+    }
+  else
+    {
+      c = ',';                 /* Do loop. */
+    }
+  while (c == ',')
+    {
+      /* 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;
+
+      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();
+         /* Input_line_pointer->just after end-of-line. */
+         c = 0;                /* Break out of loop. */
+       }
+      else
+       {
+         if (! need_pass_2)
+           {
+             p = frag_more (length);
+             bcopy (temp, p, length);
+           }
+         SKIP_WHITESPACE();
+         c = * input_line_pointer ++;
+         /* C contains 1st non-white character after number. */
+         /* input_line_pointer->just after terminator (c). */
+       }
+    }
+  -- input_line_pointer;               /*->terminator (is not ','). */
+  demand_empty_rest_of_line();
+}                              /* float_cons() */
+\f
+/*
+ *                     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.
+ */
+static 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 char *      p; JF unused */
+       /* register int length; JF unused */    /* Length of string we read, excluding */
+       /* trailing '\0' implied by closing quote. */
+       /* register char *      where; JF unused */
+       /* register fragS *     fragP; JF unused */
+       register unsigned int c;
+       
+       /*
+        * 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. */
+           }
+       for (; c == ','; c = *input_line_pointer++) {
+               SKIP_WHITESPACE();
+               if (*input_line_pointer == '\"') {
+                       ++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] == '\"');
+               } else {
+                       as_warn("Expected \"-ed string");
+               }
+               SKIP_WHITESPACE();
+       }
+       --input_line_pointer;
+       demand_empty_rest_of_line();
+} /* stringer() */
+\f
+ /* 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. */
+
+static 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 '\\':
+               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;
+                       
+#ifdef BACKSLASH_V
+               case 'v':
+                       c = '\013';
+                       break;
+#endif
+                       
+               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;
+                       
+                       for (number = 0; isdigit(c); c = *input_line_pointer++) {
+                               number = number * 8 + c - '0';
+                       }
+                       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';
+                       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;
+               
+       default:
+               break;
+       } /* switch on char */
+       return(c);
+} /* next_char_of_string() */
+\f
+static segT
+get_segmented_expression (expP)
+     register expressionS *    expP;
+{
+  register segT                retval;
+
+  if ((retval = expression(expP)) == SEG_PASS1 || retval == SEG_ABSENT || retval == SEG_BIG)
+    {
+      as_bad("Expected address expression: absolute 0 assumed");
+      retval = expP->X_seg = SEG_ABSOLUTE;
+      expP->X_add_number   = 0;
+      expP->X_add_symbol   = expP->X_subtract_symbol = 0;
+    }
+  return (retval);             /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
+}
+
+static segT get_known_segmented_expression(expP)
+register expressionS *expP;
+{
+  register segT                retval;
+  register char *      name1;
+  register char *      name2;
+
+  if ((retval = get_segmented_expression (expP)) == SEG_UNKNOWN)
+    {
+      name1 = expP->X_add_symbol ? S_GET_NAME(expP->X_add_symbol) : "";
+      name2 = expP->X_subtract_symbol ?
+             S_GET_NAME(expP->X_subtract_symbol) :
+                 "";
+      if (name1 && name2)
+       {
+         as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
+                 name1, name2);
+       }
+      else
+       {
+         as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
+                 name1 ? name1 : name2);
+       }
+      retval = expP->X_seg = SEG_ABSOLUTE;
+      expP->X_add_number   = 0;
+      expP->X_add_symbol   = expP->X_subtract_symbol = NULL;
+    }
+ know(retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE);
+  return (retval);
+}                              /* get_known_segmented_expression() */
+
+
+
+/* static */ long /* JF was static, but can't be if the MD pseudos are to use it */
+get_absolute_expression ()
+{
+  expressionS  exp;
+  register segT s;
+
+  if ((s = expression(& exp)) != SEG_ABSOLUTE)
+    {
+      if (s != SEG_ABSENT)
+       {
+         as_bad("Bad Absolute Expression, absolute 0 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 */
+{
+  * val_pointer = get_absolute_expression ();
+  return (* input_line_pointer ++);
+}
+\f
+/*
+ *                     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);
+}
+\f
+/*
+ *                     demand_copy_string()
+ *
+ * Demand string, but return a safe (=private) copy of the string.
+ * Return NULL if we can't read a string here.
+ */
+static 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(&notes, c);
+                       len ++;
+               }
+               /* JF this next line is so demand_copy_C_string will return a null
+                  termanated string. */
+               obstack_1grow(&notes,'\0');
+               retval=obstack_finish(&notes);
+       } else {
+               as_warn("Missing string");
+               retval = NULL;
+               ignore_rest_of_line();
+       }
+       *lenP = len;
+       return(retval);
+} /* demand_copy_string() */
+\f
+/*
+ *             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.
+ */
+static int is_it_end_of_statement() {
+  SKIP_WHITESPACE();
+  return (is_end_of_line [* input_line_pointer]);
+} /* is_it_end_of_statement() */
+
+void equals(sym_name)
+char *sym_name;
+{
+  register symbolS *symbolP; /* symbol we are working with */
+
+  input_line_pointer++;
+  if (*input_line_pointer=='=')
+    input_line_pointer++;
+
+  while(*input_line_pointer==' ' || *input_line_pointer=='\t')
+    input_line_pointer++;
+
+  if (sym_name[0]=='.' && sym_name[1]=='\0') {
+    /* Turn '. = mumble' into a .org mumble */
+    register segT segment;
+    expressionS exp;
+    register char *p;
+
+    segment = get_known_segmented_expression(& exp);
+    if (! need_pass_2) {
+      if (segment != now_seg && segment != SEG_ABSOLUTE)
+        as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
+                segment_name(segment),
+               segment_name(now_seg));
+      p = frag_var(rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
+                    exp.X_add_number, (char *)0);
+      * p = 0;
+    } /* if (ok to make frag) */
+  } else {
+    symbolP=symbol_find_or_make(sym_name);
+    pseudo_set(symbolP);
+  }
+} /* 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;
+
+  filename = demand_copy_string(&i);
+  demand_empty_rest_of_line();
+  path = malloc(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 **)malloc (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;
+{
+       extern char is_end_of_line[];
+
+       while (!is_end_of_line[*input_line_pointer]) {
+               ++input_line_pointer;
+       }
+       ++input_line_pointer;
+
+       return;
+} /* s_ignore() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of read.c */
diff --git a/gas/read.h b/gas/read.h
new file mode 100644 (file)
index 0000000..01351d6
--- /dev/null
@@ -0,0 +1,137 @@
+/* read.h - of read.c
+   Copyright (C) 1986, 1990 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+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[c] & LEX_BEGIN_NAME )
+#define is_part_of_name(c)      ( lex_type[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 const char lex_type[];
+extern char is_end_of_line[];
+
+#ifdef __STDC__
+
+char *demand_copy_C_string(int *len_pointer);
+char get_absolute_expression_and_terminator(long *val_pointer);
+long get_absolute_expression(void);
+void add_include_dir(char *path);
+void big_cons(int nbytes);
+void cons(unsigned int nbytes);
+void demand_empty_rest_of_line(void);
+void equals(char *sym_name);
+void float_cons(int float_type);
+void ignore_rest_of_line(void);
+void pseudo_set(symbolS *symbolP);
+void read_a_source_file(char *name);
+void read_begin(void);
+void s_abort(void);
+void s_align_bytes(int arg);
+void s_align_ptwo(void);
+void s_app_file(void);
+void s_comm(void);
+void s_data(void);
+void s_else(int arg);
+void s_end(int arg);
+void s_endif(int arg);
+void s_fill(void);
+void s_globl(void);
+void s_if(int arg);
+void s_ifdef(int arg);
+void s_ifeqs(int arg);
+void s_ignore(int arg);
+void s_include(int arg);
+void s_lcomm(int needs_align);
+void s_lsym(void);
+void s_org(void);
+void s_set(void);
+void s_space(void);
+void s_text(void);
+
+#else /* __STDC__ */
+
+char *demand_copy_C_string();
+char get_absolute_expression_and_terminator();
+long get_absolute_expression();
+void add_include_dir();
+void big_cons();
+void cons();
+void demand_empty_rest_of_line();
+void equals();
+void float_cons();
+void ignore_rest_of_line();
+void pseudo_set();
+void read_a_source_file();
+void read_begin();
+void s_abort();
+void s_align_bytes();
+void s_align_ptwo();
+void s_app_file();
+void s_comm();
+void s_data();
+void s_else();
+void s_end();
+void s_endif();
+void s_fill();
+void s_globl();
+void s_if();
+void s_ifdef();
+void s_ifeqs();
+void s_ignore();
+void s_include();
+void s_lcomm();
+void s_lsym();
+void s_org();
+void s_set();
+void s_space();
+void s_text();
+
+#endif /* __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: read.h */
diff --git a/gas/strstr.c b/gas/strstr.c
new file mode 100644 (file)
index 0000000..9823249
--- /dev/null
@@ -0,0 +1,55 @@
+/* strstr - find first occurrence of wanted in s
+   Copyright (C) 1989, 1990, 1991 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 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+ /* If your compiler is really ansi, then you don't need this. */
+#ifndef __STDC__
+
+#define SIZET int
+
+#define        NULL    0
+
+#include <string.h>
+
+char *                         /* found string, or NULL if none */
+strstr(s, wanted)
+char *s;
+char *wanted;
+{
+       register char *scan;
+       register SIZET len;
+       register char firstc;
+
+       /*
+        * The odd placement of the two tests is so "" is findable.
+        * Also, we inline the first char for speed.
+        * The ++ on scan has been moved down for optimization.
+        */
+       firstc = *wanted;
+       len = strlen(wanted);
+       for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
+               if (*scan++ == '\0')
+                       return(NULL);
+       return(scan);
+} /* strstr() */
+
+#endif /* __STDC__ */
+
+/* end of strstr.c */
diff --git a/gas/struc-symbol.h b/gas/struc-symbol.h
new file mode 100644 (file)
index 0000000..2827648
--- /dev/null
@@ -0,0 +1,113 @@
+/* struct_symbol.h - Internal symbol structure
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+struct symbol                  /* our version of an nlist node */
+{
+  obj_symbol_type sy_symbol;   /* what we write in .o file (if permitted) */
+  unsigned long sy_name_offset;        /* 4-origin position of sy_name in symbols */
+                               /* part of object file. */
+                               /* 0 for (nameless) .stabd symbols. */
+                               /* Not used until write_object_file() time. */
+  long sy_number;      /* 24 bit symbol number. */
+                               /* Symbol numbers start at 0 and are */
+                               /* unsigned. */
+  struct symbol *sy_next;      /* forward chain, or NULL */
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+  struct symbol *sy_previous;  /* backward chain, or NULL */
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+  struct frag *sy_frag;        /* NULL or -> frag this symbol attaches to. */
+  struct symbol *sy_forward;   /* value is really that of this other symbol */
+/* We will probably want to add a sy_segment here soon. */
+};
+
+typedef struct symbol symbolS;
+
+typedef unsigned valueT;       /* The type of n_value. Helps casting. */
+
+#ifndef WORKING_DOT_WORD
+struct broken_word {
+       struct broken_word *next_broken_word;/* One of these strucs per .word x-y */
+       fragS   *frag;          /* Which frag its in */
+       char    *word_goes_here;/* Where in the frag it is */
+       fragS   *dispfrag;      /* where to add the break */
+       symbolS *add;           /* symbol_x */
+       symbolS *sub;           /* - symbol_y */
+       long    addnum;         /* + addnum */
+       int     added;          /* nasty thing happend yet? */
+                               /* 1: added and has a long-jump */
+                               /* 2: added but uses someone elses long-jump */
+       struct broken_word *use_jump; /* points to broken_word with a similar
+                                        long-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).
+ */
+/* #define     SYMBOL_TYPE_TO_SEGMENT(symP)  ( N_TYPE_seg [(int) (symP)->sy_type & N_TYPE] ) */
+extern 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 */
+
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+#ifdef __STDC__
+
+void symbol_clear_list_pointers(symbolS *symbolP);
+void symbol_insert(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
+void symbol_remove(symbolS *symbolP, symbolS **rootP, symbolS **lastP);
+void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
+
+#else /* __STDC__ */
+
+void symbol_clear_list_pointers();
+void symbol_insert();
+void symbol_remove();
+void verify_symbol_chain();
+
+#endif /* __STDC__ */
+
+#define symbol_previous(s) ((s)->sy_previous)
+
+#else /* SYMBOLS_NEED_BACKPOINTERS */
+
+#define symbol_clear_list_pointers(clearme) {clearme->sy_next = NULL;}
+
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+#ifdef __STDC__
+void symbol_append(symbolS *addme, symbolS *target, symbolS **rootP, symbolS **lastP);
+#else /* __STDC__ */
+void symbol_append();
+#endif /* __STDC__ */
+
+#define symbol_next(s) ((s)->sy_next)
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of struc-symbol.h */
diff --git a/gas/subsegs.c b/gas/subsegs.c
new file mode 100644 (file)
index 0000000..00937ea
--- /dev/null
@@ -0,0 +1,279 @@
+/* subsegs.c - subsegments -
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+ * Segments & sub-segments.
+ */
+
+#include "as.h"
+
+#include "subsegs.h"
+#include "obstack.h"
+
+frchainS*      frchain_root,
+       *       frchain_now,    /* Commented in "subsegs.h". */
+       *       data0_frchainP;
+
+
+char * const /* in: segT   out: char* */
+seg_name[] = {
+       "absolute",
+       "text",
+       "data",
+       "bss",
+       "unknown",
+       "absent",
+       "pass1",
+       "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
+       "bignum/flonum",
+       "difference",
+       "debug",
+       "transfert vector preload",
+       "transfert vector postload",
+       "register",
+       "",
+}; /* Used by error reporters, dumpers etc. */
+
+\f
+void
+subsegs_begin()
+{
+  /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
+  know( SEG_ABSOLUTE   ==  0 );
+  know( SEG_TEXT       ==  1 );
+  know( SEG_DATA       ==  2 );
+  know( SEG_BSS        ==  3 );
+  know( SEG_UNKNOWN    ==  4 );
+  know( SEG_ABSENT     ==  5 );
+  know( SEG_PASS1      ==  6 );
+  know( SEG_GOOF       ==  7 );
+  know( SEG_BIG                ==  8 );
+  know( SEG_DIFFERENCE ==  9 );
+  know( SEG_DEBUG      == 10 );
+  know( SEG_NTV                == 11 );
+  know( SEG_PTV                == 12 );
+  know( SEG_REGISTER   == 13 );
+  know( SEG_MAXIMUM_ORDINAL == SEG_REGISTER );
+  know( segment_name (SEG_MAXIMUM_ORDINAL + 1) [0] == 0 );
+
+  obstack_begin( &frags, 5000);
+  frchain_root = NULL;
+  frchain_now  = NULL;         /* Warn new_subseg() that we are booting. */
+                               /* Fake up 1st frag. */
+                               /* It won't be used=> is ok if obstack... */
+                               /* pads the end of it for alignment. */
+  frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+  /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */
+                               /* This 1st frag will not be in any frchain. */
+                               /* We simply give subseg_new somewhere to scribble. */
+  now_subseg = 42;             /* Lie for 1st call to subseg_new. */
+  subseg_new (SEG_DATA, 0);    /* .data 0 */
+  data0_frchainP = frchain_now;
+}
+\f
+/*
+ *                     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_new [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 (seg == SEG_DATA)
+    {
+      seg_fix_rootP = & data_fix_root;
+      seg_fix_tailP = & data_fix_tail;
+    }
+  else
+    {
+      know (seg == SEG_TEXT);
+      seg_fix_rootP = & text_fix_root;
+      seg_fix_tailP = & text_fix_tail;
+    }
+}
+\f
+/*
+ *                     subseg_new()
+ *
+ * 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.
+ */
+
+void
+subseg_new (seg, subseg)       /* begin assembly for a new sub-segment */
+     register segT     seg;    /* SEG_DATA or SEG_TEXT */
+     register subsegT  subseg;
+{
+  long tmp;            /* JF for obstack alignment hacking */
+
+  know( seg == SEG_DATA || seg == SEG_TEXT );
+
+  if (seg != now_seg || subseg != now_subseg)
+    {                          /* we just changed sub-segments */
+      register frchainS *      frcP;   /* crawl frchain chain */
+      register frchainS**      lastPP; /* address of last pointer */
+               frchainS *      newP;   /* address of new frchain */
+      register fragS *         former_last_fragP;
+      register fragS *         new_fragP;
+
+      if (frag_now)            /* If not bootstrapping. */
+       {
+         frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal;
+         frag_wane(frag_now);  /* Close off any frag in old subseg. */
+       }
+/*
+ * It would be nice to keep an obstack for each subsegment, if we swap
+ * subsegments a lot. Hence we would have much fewer frag_wanes().
+ */
+      {
+
+       obstack_finish( &frags);
+       /*
+        * If we don't do the above, the next object we put on obstack frags
+        * will appear to start at the fr_literal of the current frag.
+        * Also, above ensures that the next object will begin on a
+        * address that is aligned correctly for the engine that runs
+        * this program.
+        */
+      }
+      subseg_change (seg, (int)subseg);
+      /*
+       * 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
+          && (int)(frcP -> frch_seg) <= (int)seg;
+          frcP = * ( lastPP = & frcP -> frch_next)
+         )
+       {
+         if (   (int)(frcP -> frch_seg) == (int)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
+         || (   (int)(frcP -> frch_seg) > (int)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(&frags,sizeof(frchainS));
+         /* obstack_1blank( &frags, sizeof(frchainS), &newP); */
+                               /* This begines on a good boundary */
+                               /* because a obstack_done() preceeded  it. */
+                               /* It implies an obstack_done(), so we */
+                               /* expect the next object allocated to */
+                               /* begin on a correct boundary. */
+         *lastPP = newP;
+         newP -> frch_next = frcP; /* perhaps NULL */
+         (frcP = newP) -> frch_subseg          = subseg;
+                 newP  -> frch_seg             = seg;
+                 newP  -> frch_last            = NULL;
+       }
+      /*
+       * Here with frcP ->ing to the frchainS for subseg.
+       */
+      frchain_now = frcP;
+      /*
+       * Make a fresh frag for the subsegment.
+       */
+                               /* We expect this to happen on a correct */
+                               /* boundary since it was proceeded by a */
+                               /* obstack_done(). */
+      tmp=obstack_alignment_mask(&frags);      /* JF disable alignment */
+      obstack_alignment_mask(&frags)=0;
+      frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
+      obstack_alignment_mask(&frags)=tmp;
+      /* know( frags . obstack_c_next_free == frag_now -> fr_literal ); */
+                               /* But we want any more chars to come */
+                               /* immediately after the structure we just made. */
+      new_fragP = frag_now;
+      new_fragP -> fr_next = NULL;
+      /*
+       * Append new frag to current frchain.
+       */
+      former_last_fragP = frcP -> frch_last;
+      if (former_last_fragP)
+       {
+         know( former_last_fragP -> fr_next == NULL );
+         know( frchain_now -> frch_root );
+         former_last_fragP -> fr_next = new_fragP;
+       }
+      else
+       {
+         frcP -> frch_root = new_fragP;
+       }
+      frcP -> frch_last = new_fragP;
+    }                          /* if (changing subsegments) */
+}                              /* subseg_new() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: subsegs.c */
diff --git a/gas/subsegs.h b/gas/subsegs.h
new file mode 100644 (file)
index 0000000..b8dbaf7
--- /dev/null
@@ -0,0 +1,65 @@
+/* subsegs.h -> subsegs.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, 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.
+ */
+
+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 */
+};
+
+typedef struct frchain frchainS;
+
+extern frchainS * frchain_root;        /* NULL means no frchains yet. */
+                               /* all subsegments' chains hang off here */
+
+extern frchainS * frchain_now;
+                               /* Frchain we are assembling into now */
+                               /* That is, the current segment's frag */
+                               /* chain, even if it contains no (complete) */
+                               /* frags. */
+
+extern frchainS * data0_frchainP;
+                               /* Sentinel for frchain crawling. */
+                               /* Points to the 1st data-segment frchain. */
+                               /* (Which is pointed to by the last text- */
+                               /* segment frchain.) */
+
+/* end: subsegs.h */
diff --git a/gas/symbols.c b/gas/symbols.c
new file mode 100644 (file)
index 0000000..445160a
--- /dev/null
@@ -0,0 +1,614 @@
+/* symbols.c -symbol table-
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+#include "as.h"
+
+#include "obstack.h"           /* For "symbols.h" */
+#include "subsegs.h"
+
+#ifndef WORKING_DOT_WORD
+extern int new_broken_words;
+#endif
+#ifdef VMS
+extern char const_flag;
+#endif
+
+static
+struct hash_control *
+sy_hash;                       /* symbol-name => struct symbol pointer */
+
+                               /* Below are commented in "symbols.h". */
+unsigned int local_bss_counter;
+symbolS * symbol_rootP;
+symbolS * symbol_lastP;
+symbolS        abs_symbol;
+
+symbolS*               dot_text_symbol;
+symbolS*               dot_data_symbol;
+symbolS*               dot_bss_symbol;
+
+struct obstack notes;
+
+/*
+ * Un*x 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:.
+ *
+ * Like Un*x AS, 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.
+ *
+ * I document the symbol names here to save duplicating words elsewhere.
+ * The mth occurence of label n: is turned into the symbol "Ln^Am" where
+ * n is a digit and m is a decimal 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.
+ */
+
+typedef short unsigned int
+local_label_countT;
+
+static local_label_countT
+local_label_counter[10];
+
+static                         /* Returned to caller, then copied. */
+  char symbol_name_build[12];  /* used for created names ("4f") */
+
+#ifdef LOCAL_LABELS_DOLLAR
+int local_label_defined[10];
+#endif
+
+\f
+void
+symbol_begin()
+{
+  symbol_lastP = NULL;
+  symbol_rootP = NULL;         /* In case we have 0 symbols (!!) */
+  sy_hash = hash_new();
+  bzero ((char *)(& abs_symbol), sizeof(abs_symbol));
+  S_SET_SEGMENT(&abs_symbol, SEG_ABSOLUTE);    /* Can't initialise a union. Sigh. */
+  bzero ((char *)(local_label_counter), sizeof(local_label_counter) );
+  local_bss_counter = 0;
+}
+\f
+/*
+ *                     local_label_name()
+ *
+ * Caller must copy returned name: we re-use the area for the next name.
+ */
+
+char *                         /* Return local label name. */
+local_label_name(n, augend)
+     register int n;   /* we just saw "n:", "nf" or "nb" : n a digit */
+     register int augend; /* 0 for nb, 1 for n:, nf */
+{
+  register char *      p;
+  register char *      q;
+  char symbol_name_temporary[10]; /* build up a number, BACKWARDS */
+
+  know( n >= 0 );
+  know( augend == 0 || augend == 1 );
+  p = symbol_name_build;
+  * p ++ = 'L';
+  * p ++ = n + '0';            /* Make into ASCII */
+  * p ++ = 1;                  /* ^A */
+  n = local_label_counter [ n ] + augend;
+                               /* version number of this local label */
+  /*
+   * Next code just does sprintf( {}, "%d", n);
+   * It is more elegant to do the next part recursively, but a procedure
+   * call for each digit emitted is considered too costly.
+   */
+  q = symbol_name_temporary;
+  for (*q++=0; n; q++)         /* emits NOTHING if n starts as 0 */
+    {
+      know(n>0);               /* We expect n > 0 always */
+      *q = n % 10 + '0';
+      n /= 10;
+    }
+  while (( * p ++ = * -- q ) != '\0') ;;
+
+  /* The label, as a '\0' ended string, starts at symbol_name_build. */
+  return(symbol_name_build);
+} /* local_label_name() */
+
+
+void local_colon (n)
+int n; /* just saw "n:" */
+{
+  local_label_counter [n] ++;
+#ifdef LOCAL_LABELS_DOLLAR
+  local_label_defined[n]=1;
+#endif
+  colon (local_label_name (n, 0));
+}
+\f
+/*
+ *                     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.
+ *
+ *
+ * Please always call this to create a new symbol.
+ *
+ * Changes since 1985: Symbol names may not contain '\0'. Sigh.
+ * 2nd argument is now a SEG rather than a TYPE.  The mapping between
+ * segments and types is mostly encapsulated herein (actually, we inherit it
+ * from macros in struc-symbol.h).
+ */
+
+symbolS *symbol_new(name, segment, value, frag)
+char *name;                    /* It is copied, the caller can destroy/modify */
+segT segment;                  /* Segment identifier (SEG_<something>) */
+long value;                    /* 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(&notes, name, name_length);
+       preserved_copy_of_name = obstack_finish(&notes);
+       symbolP = (symbolS *)obstack_alloc(&notes, sizeof(symbolS));
+       
+#if STRIP_UNDERSCORE
+       S_SET_NAME(symbolP, (*preserved_copy_of_name == '_'
+                                           ? preserved_copy_of_name + 1
+                                           : preserved_copy_of_name));
+#else /* STRIP_UNDERSCORE */
+       S_SET_NAME(symbolP, preserved_copy_of_name);
+#endif /* STRIP_UNDERSCORE */
+
+       S_SET_SEGMENT(symbolP, segment);
+       S_SET_VALUE(symbolP, value);
+       symbol_clear_list_pointers(symbolP);
+
+       symbolP->sy_frag = frag;
+       symbolP->sy_forward = NULL; /* JF */
+       symbolP->sy_number = ~0;
+       symbolP->sy_name_offset = ~0;
+
+       /*
+        * Link to end of symbol chain.
+        */
+       symbol_append(symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP);
+
+       obj_symbol_new_hook(symbolP);
+       
+#ifdef DEBUG
+       verify_symbol_chain(symbol_rootP, symbol_lastP);
+#endif /* DEBUG */
+
+       return(symbolP);
+} /* symbol_new() */
+
+\f
+/*
+ *                     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).
+ *
+ */
+void colon(sym_name)           /* just seen "x:" - rattle symbols & frags */
+     register 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 */
+
+#ifdef LOCAL_LABELS_DOLLAR
+  /* Sun local labels go out of scope whenever a non-local symbol is defined.  */
+
+  if(*sym_name !='L')
+    bzero((void *) local_label_defined, sizeof(local_label_defined));
+#endif
+
+#ifndef WORKING_DOT_WORD
+  if(new_broken_words) {
+    struct broken_word *a;
+    int possible_bytes;
+    fragS *frag_tmp;
+    char *frag_opcode;
+    extern md_short_jump_size;
+    extern 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,
+                        0L,
+                        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
+  if ((symbolP = symbol_find(sym_name)) != 0) {
+#ifdef VMS
+         /*
+          *    If the new symbol is .comm AND it has a size of zero,
+          *    we ignore it (i.e. the old symbol overrides it)
+          */
+         if ((SEGMENT_TO_SYMBOL_TYPE((int) now_seg) == (N_UNDF | N_EXT)) &&
+             ((obstack_next_free(& frags) - frag_now->fr_literal) == 0))
+             return;
+         /*
+          *    If the old symbol is .comm and it has a size of zero,
+          *    we override it with the new symbol value.
+          */
+         if ((symbolP->sy_type == (N_UNDF | N_EXT))
+             && (S_GET_VALUE(symbolP) == 0)) {
+                 symbolP->sy_frag  = frag_now;
+                 symbolP->sy_other = const_flag;
+                 S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
+                 symbolP->sy_type |= SEGMENT_TO_SYMBOL_TYPE((int) now_seg); /* keep N_EXT bit */
+                 return;
+         }
+#endif /* VMS */
+         /*
+          *    Now check for undefined symbols
+          */
+         if (!S_IS_DEFINED(symbolP)) {
+                 if (S_GET_VALUE(symbolP) == 0) {
+                         symbolP->sy_frag  = frag_now;
+#ifdef VMS
+                         symbolP->sy_other = const_flag;
+#endif
+                         S_SET_VALUE(symbolP, obstack_next_free(&frags) - frag_now->fr_literal);
+                         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.
+                          */
+                         char New_Type = SEGMENT_TO_SYMBOL_TYPE((int) now_seg);
+                         
+                         if (((!S_IS_DEBUG(symbolP) && !S_IS_DEFINED(symbolP) && S_IS_EXTERNAL(symbolP))
+                              || (S_GET_SEGMENT(symbolP) == SEG_BSS))
+                             && ((now_seg == SEG_DATA)
+                                 || (now_seg == S_GET_SEGMENT(symbolP)))) {
+                                 /*
+                                  *    Select which of the 2 cases this is
+                                  */
+                                 if (now_seg != SEG_DATA) {
+                                         /*
+                                          *   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) (obstack_next_free(& frags) - frag_now->fr_literal))) {
+                                                 S_SET_VALUE(symbolP, 
+                                                             obstack_next_free(& frags) -
+                                                             frag_now->fr_literal);
+                                         }
+                                 } else {
+                                         /*
+                                          *    It is a .comm/.lcomm being converted
+                                          *    to initialized data.
+                                          */
+                                         symbolP->sy_frag  = frag_now;
+#ifdef VMS
+                                         symbolP->sy_other = const_flag;
+#endif /* VMS */
+                                         S_SET_VALUE(symbolP, obstack_next_free(& frags) - frag_now->fr_literal);
+                                         S_SET_SEGMENT(symbolP, now_seg); /* keep N_EXT bit */
+                                 }
+                         } else {
+#ifdef OBJ_COFF
+                                 as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.",
+                                          sym_name,
+                                          segment_name(S_GET_SEGMENT(symbolP)),
+                                          S_GET_VALUE(symbolP));
+#else /* OBJ_COFF */
+                                 as_fatal("Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
+                                          sym_name,
+                                          segment_name(S_GET_SEGMENT(symbolP)),
+                                          S_GET_OTHER(symbolP), S_GET_DESC(symbolP),
+                                          S_GET_VALUE(symbolP));
+#endif /* OBJ_COFF */
+                         }
+                 } /* if the undefined symbol has no value */
+         } else {
+                 as_fatal("Symbol %s already defined.", sym_name);
+         } /* if this symbol is not yet defined */
+
+  } else {
+         symbolP = symbol_new(sym_name,
+                               now_seg, 
+                               (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
+                               frag_now);
+#ifdef VMS
+         S_SET_OTHER(symbolP, const_flag);
+#endif /* VMS */
+         
+         symbol_table_insert(symbolP);
+  } /* if we have seen this symbol before */
+
+  return;
+} /* colon() */
+
+\f
+/*
+ *                     symbol_table_insert()
+ *
+ * Die if we can't insert the symbol.
+ *
+ */
+
+void symbol_table_insert(symbolP)
+symbolS *symbolP;
+{
+       register char *error_string;
+       
+       know(symbolP);
+       know(S_GET_NAME(symbolP));
+       
+       if (*(error_string = hash_jam(sy_hash, S_GET_NAME(symbolP), (char *)symbolP))) {
+               as_fatal("Inserting \"%s\" into symbol table failed: %s",
+                        S_GET_NAME(symbolP), error_string);
+       } /* on error */
+} /* symbol_table_insert() */
+\f
+/*
+ *                     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)
+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)
+char *name;
+{
+       symbolS *symbolP;
+
+       /* Let the machine description default it, e.g. for register names. */
+       symbolP = md_undefined_symbol(name);
+       
+       if (!symbolP) {
+               symbolP = symbol_new(name,
+                                    SEG_UNKNOWN,
+                                    0,
+                                    &zero_address_frag);
+       } /* if md didn't build us a symbol */
+
+       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)
+char *name;
+{
+#ifndef STRIP_UNDERSCORE
+#define STRIP_UNDERSCORE 0
+#endif /* STRIP_UNDERSCORE */
+    return symbol_find_base(name, STRIP_UNDERSCORE);
+}
+
+symbolS *symbol_find_base(name, strip_underscore)
+char *name;
+int strip_underscore;
+{
+    if(strip_underscore && *name == '_') name++;
+    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);
+               *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 */
+
+#ifdef DEBUG
+       verify_symbol_chain(*rootPP, *lastPP);
+#endif /* DEBUG */
+
+       return;
+} /* symbol_append() */
+
+#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 */
+       
+#ifdef DEBUG
+       verify_symbol_chain(*rootPP, *lastPP);
+#endif /* DEBUG */
+
+       return;
+} /* symbol_remove() */
+
+/* Set the chain pointers of SYMBOL to null. */
+void symbol_clear_list_pointers(symbolP)
+symbolS *symbolP;
+{
+    symbolP->sy_next = NULL;
+    symbolP->sy_previous = NULL;
+} /* symbol_clear_list_pointers() */
+
+/* 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;
+
+#ifdef DEBUG
+    verify_symbol_chain(*rootPP, *lastPP);
+#endif /* DEBUG */
+
+    return;
+} /* symbol_insert() */
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+
+void verify_symbol_chain(rootP, lastP)
+symbolS *rootP;
+symbolS *lastP;
+{
+       symbolS *symbolP = rootP;
+
+       if (symbolP == NULL) {
+               return;
+       } /* empty chain */
+
+       for ( ; symbol_next(symbolP) != NULL; symbolP = symbol_next(symbolP)) {
+#ifdef SYMBOLS_NEED_BACKPOINTERS
+               /*$if (symbolP->sy_previous) {
+                       know(symbolP->sy_previous->sy_next == symbolP);
+               } else {
+                       know(symbolP == rootP);
+               }$*/ /* both directions */
+               know(symbolP->sy_next->sy_previous == symbolP);
+#else /* SYMBOLS_NEED_BACKPOINTERS */
+               ;
+#endif /* SYMBOLS_NEED_BACKPOINTERS */
+       } /* verify pointers */
+
+       know(lastP == symbolP);
+
+       return;
+} /* verify_symbol_chain() */
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: symbols.c */
diff --git a/gas/symbols.h b/gas/symbols.h
new file mode 100644 (file)
index 0000000..8ced0d4
--- /dev/null
@@ -0,0 +1,77 @@
+/* symbols.h -
+   Copyright (C) 1987, 1990 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* $Id$ */
+
+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 unsigned int local_bss_counter; /* Zeroed before a pass. */
+                               /* Only used by .lcomm directive. */
+
+extern symbolS * symbol_rootP; /* all the symbol nodes */
+extern symbolS * symbol_lastP; /* last struct symbol we made, or NULL */
+
+extern symbolS abs_symbol;
+
+extern symbolS*                dot_text_symbol;
+extern symbolS*                dot_data_symbol;
+extern symbolS*                dot_bss_symbol;
+
+#ifdef __STDC__
+
+char *local_label_name(int n, int augend);
+symbolS *symbol_find(char *name);
+symbolS *symbol_find_base(char *name, int strip_underscore);
+symbolS *symbol_find_or_make(char *name);
+symbolS *symbol_make(char *name);
+symbolS *symbol_new(char *name, segT segment, long value, fragS *frag);
+void colon(char *sym_name);
+void local_colon(int n);
+void symbol_begin(void);
+void symbol_table_insert(symbolS *symbolP);
+void verify_symbol_chain(symbolS *rootP, symbolS *lastP);
+
+#else
+
+char *local_label_name();
+symbolS *symbol_find();
+symbolS *symbol_find_base();
+symbolS *symbol_find_or_make();
+symbolS *symbol_make();
+symbolS *symbol_new();
+void colon();
+void local_colon();
+void symbol_begin();
+void symbol_table_insert();
+void verify_symbol_chain();
+
+#endif /* __STDC__ */
+
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end: symbols.h */
diff --git a/gas/tc.h b/gas/tc.h
new file mode 100644 (file)
index 0000000..b87ba60
--- /dev/null
+++ b/gas/tc.h
@@ -0,0 +1,112 @@
+/* tc.h -target cpu dependent- */
+
+/* Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/* 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. */
+
+typedef struct
+{
+       long    rlx_forward;    /* Forward  reach. Signed number. > 0. */
+       long    rlx_backward;   /* Backward reach. Signed number. < 0. */
+       unsigned char rlx_length;       /* Bytes length of this address. */
+       relax_substateT rlx_more;       /* Next longer relax-state. */
+                               /* 0 means there is no 'next' relax-state. */
+}
+relax_typeS;
+
+extern const relax_typeS md_relax_table[]; /* Define it in MACHINE.c */
+
+extern int md_reloc_size; /* Size of a relocation record */
+
+extern void (*md_emit_relocations)();
+
+#ifdef __STDC__
+
+char *md_atof(int what_statement_type, char *literalP, int *sizeP);
+int md_estimate_size_before_relax(fragS *fragP, segT segtype);
+int md_parse_option(char **argP, int *cntP, char ***vecP);
+long md_pcrel_from(fixS *fixP);
+long md_section_align(segT seg, long align);
+short tc_coff_fix2rtype(fixS *fixP);
+symbolS *md_undefined_symbol(char *name);
+void md_apply_fix(fixS *fixP, long val);
+void md_assemble(char *str);
+void md_begin(void);
+void md_convert_frag(fragS *fragP);
+void md_create_long_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
+void md_create_short_jump(char *ptr, long from_addr, long to_addr, fragS *frag, symbolS *to_symbol);
+void md_end(void);
+void md_number_to_chars(char *buf, long val, int n);
+void md_operand(expressionS *expressionP);
+void md_ri_to_chars(char *the_bytes, struct reloc_info_generic *ri);
+
+#ifndef tc_crawl_symbol_chain
+void tc_crawl_symbol_chain(object_headers *headers);
+#endif /* tc_crawl_symbol_chain */
+
+#ifndef tc_headers_hook
+void tc_headers_hook(object_headers *headers);
+#endif /* tc_headers_hook */
+
+#else
+
+char *md_atof();
+int md_estimate_size_before_relax();
+int md_parse_option();
+long md_pcrel_from();
+long md_section_align();
+short tc_coff_fix2rtype();
+symbolS *md_undefined_symbol();
+void md_apply_fix();
+void md_assemble();
+void md_begin();
+void md_convert_frag();
+void md_create_long_jump();
+void md_create_short_jump();
+void md_end();
+void md_number_to_chars();
+void md_operand();
+void md_ri_to_chars();
+
+#ifndef tc_headers_hook
+void tc_headers_hook();
+#endif /* tc_headers_hook */
+
+#ifndef tc_crawl_symbol_chain
+void tc_crawl_symbol_chain();
+#endif /* tc_crawl_symbol_chain */
+
+#endif /* __STDC_ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of tp.h */
diff --git a/gas/testscripts/doboth b/gas/testscripts/doboth
new file mode 100755 (executable)
index 0000000..a8c3358
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $Id$
+
+x=$1 ; shift
+y=$1 ; shift
+
+rm tmp.0 > /dev/null 2>&1
+ln -s $x tmp.0
+$* tmp.0 > tmp.1
+
+rm tmp.0
+ln -s $y tmp.0
+$* tmp.0 > tmp.2
+
+rm tmp.0
+
+diff -c tmp.1 tmp.2
+exit
+
+#eof
diff --git a/gas/testscripts/doobjcmp b/gas/testscripts/doobjcmp
new file mode 100755 (executable)
index 0000000..9fbe46b
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+# $Id$
+# compare two object files, in depth.
+
+x=$1
+y=$2
+BOTH="$1 $2"
+
+
+# if they cmp, we're fine.
+if (cmp $BOTH > /dev/null)
+then
+       exit 0
+fi
+
+# otherwise, we must look closer.
+if (doboth $BOTH size)
+then
+       echo Sizes ok.
+else
+       echo Sizes differ:
+       size $BOTH
+#      exit 1
+fi
+
+if (doboth $BOTH objdump +header)
+then
+       echo Headers ok.
+else
+       echo Header differences.
+#      exit 1
+fi
+
+if (doboth $BOTH objdump +text > /dev/null)
+then
+       echo Text ok.
+else
+       echo Text differences.
+#      doboth $BOTH objdump +text
+#      exit 1
+fi
+
+if (doboth $BOTH objdump +data > /dev/null)
+then
+       echo Data ok.
+else
+       echo Data differences.
+#      doboth $BOTH objdump +data
+#      exit 1
+fi
+
+if (doboth $BOTH objdump +symbols > /dev/null)
+then
+       echo Symbols ok.
+else
+       echo -n Symbol differences...
+
+       if (doboth $BOTH dounsortsymbols)
+       then
+               echo but symbols are simply ordered differently.
+#              echo Now what to do about relocs'?'
+#              exit 1
+       else
+               echo and symbols differ in content.
+               exit 1
+       fi
+fi
+
+# of course, if there were symbol diffs, then the reloc symbol indexes
+# will be off.
+
+if (doboth $BOTH objdump -r > /dev/null)
+then
+       echo Reloc ok.
+else
+       echo -n Reloc differences...
+
+       if (doboth $BOTH dounsortreloc)
+       then
+               echo but relocs are simply ordered differently.
+       else
+               echo and relocs differ in content.
+               exit 1
+       fi
+fi
+
+exit
+
+# eof
diff --git a/gas/testscripts/dostriptest b/gas/testscripts/dostriptest
new file mode 100755 (executable)
index 0000000..4b89df8
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $Id$
+
+x=striptest.xx.$$
+y=striptest.yy.$$
+
+cp $1 $x
+strip $x
+cp $2 $y
+strip $y
+
+doobjcmp $x $y
+exit
+
+#eof
diff --git a/gas/testscripts/dotest b/gas/testscripts/dotest
new file mode 100755 (executable)
index 0000000..8c7a28c
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# ad hoc debug tool
+# $Id$
+
+x=$1
+y=$2
+
+xout=`basename $x`.xxx.$$
+yout=`basename $x`.yyy.$$
+
+mkdir $xout
+mkdir $yout
+
+for i in *.s
+do
+       echo Testing $i...
+       object=`basename $i .s`.o
+       $x $i -o $xout/$object
+       $y $i -o $yout/$object
+
+# if they cmp, we're ok.  Otherwise we have to look closer.
+
+       if (cmp $xout/$object $yout/$object)
+       then
+               echo $i is ok.
+       else
+               if (doobjcmp $xout/$object $yout/$object)
+               then
+                       echo Not the same but objcmp ok.
+               else
+                       exit 1
+               fi
+       fi
+
+       echo
+done
+
+rm -rf $xout $yout
+
+exit 0
+
+# EOF
+
+
diff --git a/gas/testscripts/dounsortreloc b/gas/testscripts/dounsortreloc
new file mode 100755 (executable)
index 0000000..d8da0a9
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id$
+# objdump the reloc table, but strip off the headings and reloc
+# numbers and sort the result.  Intended for use in comparing reloc
+# tables that may not be in the same order.
+
+objdump +reloc +omit-relocation-numbers +omit-symbol-numbers $1 \
+       | sort
+#eof
diff --git a/gas/testscripts/dounsortsymbols b/gas/testscripts/dounsortsymbols
new file mode 100755 (executable)
index 0000000..8fb6db3
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+# $Id$
+# objdump the symbol table, but strip off the headings and symbol
+# numbers and sort the result.  Intended for use in comparing symbol
+# tables that may not be in the same order.
+
+objdump +symbols +omit-symbol-numbers $1 \
+       | sort
+#eof
diff --git a/gas/write.c b/gas/write.c
new file mode 100644 (file)
index 0000000..a0b36c3
--- /dev/null
@@ -0,0 +1,1162 @@
+/* write.c - emit .o file
+   Copyright (C) 1986, 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/* 
+
+   This thing should be set up to do byteordering correctly.  But...
+
+   In order to cross-assemble the target machine must have an a.out header
+   similar to the one in a.out.h on THIS machine.  Byteorder doesn't matter,
+   we take special care of it, but the numbers must be the same SIZE (# of
+   bytes) and in the same PLACE.  If this is not true, you will have some
+   trouble.
+ */
+
+#include "as.h"
+
+#include "subsegs.h"
+#include "obstack.h"
+#include "output-file.h"
+
+/* Hook for machine dependent relocation information output routine.
+   If not defined, the variable is allocated in BSS (Fortran common model).
+   If some other module defines it, we will see their value.  */
+
+void (*md_emit_relocations)();
+
+/*
+ * In: length of relocation (or of address) in chars: 1, 2 or 4.
+ * Out: GNU LD relocation length code: 0, 1, or 2.
+ */
+
+unsigned char
+nbytes_r_length [] = {
+  42, 0, 1, 42, 2
+  };
+
+
+static struct frag *text_frag_root;
+static struct frag *data_frag_root;
+
+static struct frag *text_last_frag;    /* Last frag in segment. */
+static struct frag *data_last_frag;    /* Last frag in segment. */
+
+static object_headers headers;
+
+long string_byte_count;
+
+static char *the_object_file;
+
+char *next_object_file_charP;  /* Tracks object file bytes. */
+
+int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
+
+/* static long         length; JF unused */    /* String length, including trailing '\0'. */
+
+
+#ifdef __STDC__
+
+static int is_dnrange(struct frag *f1, struct frag *f2);
+static long fixup_segment(fixS *fixP, segT this_segment_type);
+static relax_addressT relax_align(relax_addressT address, long alignment);
+static void relax_segment(struct frag *segment_frag_root, segT segment_type);
+
+#else
+
+static int is_dnrange();
+static long fixup_segment();
+static relax_addressT relax_align();
+static void relax_segment();
+
+#endif /* __STDC__ */
+
+/*
+ *                     fix_new()
+ *
+ * Create a fixS in obstack 'notes'.
+ */
+fixS *fix_new(frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+fragS *frag;           /* Which frag? */
+int where;             /* Where in that frag? */
+short int size;                /* 1, 2  or 4 usually. */
+symbolS *add_symbol;   /* X_add_symbol. */
+symbolS *sub_symbol;   /* X_subtract_symbol. */
+long offset;           /* X_add_number. */
+int pcrel;             /* TRUE if PC-relative relocation. */
+enum reloc_type        r_type; /* Relocation type */
+{
+  register fixS *      fixP;
+
+  fixP = (fixS *)obstack_alloc(&notes,sizeof(fixS));
+
+  fixP->fx_frag        = frag;
+  fixP->fx_where       = where;
+  fixP->fx_size        = size;
+  fixP->fx_addsy       = add_symbol;
+  fixP->fx_subsy       = sub_symbol;
+  fixP->fx_offset      = offset;
+  fixP->fx_pcrel       = pcrel;
+  fixP->fx_r_type      = r_type;
+  fixP->fx_next        = NULL;
+
+  /* JF these 'cuz of the NS32K stuff */
+  fixP->fx_im_disp     = 0;
+  fixP->fx_pcrel_adjust = 0;
+  fixP->fx_bsr = 0;
+  fixP->fx_bit_fixP    = 0;
+
+  if (*seg_fix_tailP)
+    (*seg_fix_tailP)->fx_next = fixP;
+  else
+    *seg_fix_rootP = fixP;
+  *seg_fix_tailP = fixP;
+  fixP->fx_callj = 0;
+  return fixP;
+}
+\f
+void write_object_file() {
+  register struct frchain *    frchainP; /* Track along all frchains. */
+  register fragS *             fragP;  /* Track along all frags. */
+  register struct frchain *    next_frchainP;
+  register fragS * *           prev_fragPP;
+/*  register char *            name; */
+/*  symbolS *symbolP; */
+/*  register symbolS **                symbolPP; */
+  /* register fixS *           fixP; JF unused */
+  unsigned int data_siz;
+
+#ifdef DONTDEF
+  void gdb_emit();
+  void gdb_end();
+#endif
+  long object_file_size;
+
+#ifdef 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 /* 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.
+   */
+#define SUB_SEGMENT_ALIGN (2)
+  for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) {
+#ifdef VMS
+         /*
+          *    Under VAX/VMS, the linker (and PSECT specifications)
+          *    take care of correctly aligning the segments.
+          *    Doing the alignment here (on initialized data) can
+          *    mess up the calculation of global data PSECT sizes.
+          */
+#undef SUB_SEGMENT_ALIGN
+#define        SUB_SEGMENT_ALIGN ((frchainP->frch_seg != SEG_DATA) ? 2 : 0)
+#endif /* VMS */
+         subseg_new (frchainP->frch_seg, frchainP->frch_subseg);
+         frag_align (SUB_SEGMENT_ALIGN, 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 );
+         /* know( frags . obstack_c_base == frags . obstack_c_next_free ); */
+         /* Above shows we haven't left a half-completed object on obstack. */
+  } /* walk the frag chain */
+\f
+  /*
+   * From now on, we don't care about sub-segments.
+   * Build one frag chain for each segment. Linked thru fr_next.
+   * We know that there is at least 1 text frchain & at least 1 data frchain.
+   */
+  prev_fragPP = &text_frag_root;
+  for (frchainP = frchain_root; frchainP; frchainP = next_frchainP) {
+         know( frchainP->frch_root );
+         * prev_fragPP = frchainP->frch_root;
+         prev_fragPP = & frchainP->frch_last->fr_next;
+         
+         if (((next_frchainP = frchainP->frch_next) == NULL)
+             || next_frchainP == data0_frchainP) {
+                 prev_fragPP = & data_frag_root;
+                 if (next_frchainP) {
+                         text_last_frag = frchainP->frch_last;
+                 } else {
+                         data_last_frag = frchainP->frch_last;
+                 }
+         }
+  } /* walk the frag chain */
+
+  /*
+   * 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 (flagseen[ 'R' ]) {
+         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;
+         } else
+             text_fix_root=data_fix_root;
+         data_fix_root=NULL;
+  }
+
+  relax_segment(text_frag_root, SEG_TEXT);
+  relax_segment(data_frag_root, SEG_DATA);
+  /*
+   * 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. */
+         
+         for (fragP = data_frag_root;
+              fragP;
+              fragP = fragP->fr_next)
+             {
+                     fragP->fr_address += slide;
+             }
+         know( text_last_frag );
+         text_last_frag->fr_next = data_frag_root;
+  } else {
+         H_SET_DATA_SIZE(&headers,0);
+         data_siz = 0;
+  }
+
+  bss_address_frag.fr_address = H_GET_TEXT_SIZE(&headers) + 
+                                  H_GET_DATA_SIZE(&headers);
+
+  H_SET_BSS_SIZE(&headers,local_bss_counter);
+             
+  /*
+   *
+   * 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;
+  } /* if no strings, then no count. */
+  
+  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) {
+         switch (fragP->fr_type) {
+         case rs_align:
+         case rs_org:
+                 fragP->fr_type = rs_fill;
+                 know( fragP->fr_var == 1 );
+                 know( fragP->fr_next );
+                 fragP->fr_offset
+                     =     fragP->fr_next->fr_address
+                         -   fragP->fr_address
+                             - fragP->fr_fix;
+                 break;
+                 
+         case rs_fill:
+                 break;
+                 
+         case rs_machine_dependent:
+                 md_convert_frag (fragP);
+                 /*
+                  * 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;
+                 extern md_short_jump_size;
+                 extern md_long_jump_size;
+                 
+                 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;
+         } /* switch (fr_type) */
+  } /* for each frag. */
+
+#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) {
+#ifdef TC_NS32K
+                     fix_new_ns32k(lie->frag,
+                                   lie->word_goes_here - lie->frag->fr_literal,
+                                   2,
+                                   lie->add,
+                                   lie->sub,
+                                   lie->addnum,
+                                   0, 0, 2, 0, 0);
+#else /* TC_NS32K */
+                     fix_new(  lie->frag,  lie->word_goes_here - lie->frag->fr_literal,
+                             2,  lie->add,
+                             lie->sub,  lie->addnum,
+                             0,  NO_RELOC);
+#endif /* TC_NS32K */
+                     /* md_number_to_chars(lie->word_goes_here,
+                        S_GET_VALUE(lie->add)
+                        + lie->addnum
+                        - S_GET_VALUE(lie->sub),
+                        2); */
+                     *prevP=lie->next_broken_word;
+             } else
+                 prevP= &(lie->next_broken_word);
+         
+         for (lie=broken_words;lie;) {
+                 struct broken_word *untruth;
+                 char  *table_ptr;
+                 long  table_addr;
+                 long  from_addr,
+                 to_addr;
+                 int   n,
+                 m;
+                 
+                 extern md_short_jump_size;
+                 extern md_long_jump_size;
+                 
+                 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);
+                         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;
+                         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        VMS
+  { /* not vms */
+         /*
+          * Scan every FixS performing fixups. We had to wait until now to do
+          * this because md_convert_frag() may have made some fixSs.
+          */
+         H_SET_RELOCATION_SIZE(&headers,
+                               md_reloc_size * fixup_segment(text_fix_root, SEG_TEXT),
+                               md_reloc_size * fixup_segment(data_fix_root, SEG_DATA));
+         
+ /* 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);
+         
+#ifdef EXEC_MACHINE_TYPE
+         H_SET_MACHINE_TYPE(&headers,EXEC_MACHINE_TYPE);
+#endif
+#ifdef EXEC_VERSION
+         H_SET_VERSION(&headers,EXEC_VERSION);
+#endif
+         
+         obj_pre_write_hook(&headers); /* extra coff stuff */
+         
+         if ((had_warnings() && flagseen['Z'])
+             || had_errors() > 0) {
+                 if (flagseen['Z']) {
+                         as_warn("%d error%s, %d warning%s, generating bad object file.\n",
+                                 had_errors(), had_errors() == 1 ? "" : "s",
+                                 had_warnings(), had_warnings() == 1 ? "" : "s");
+                 } else {
+                         as_fatal("%d error%s, %d warning%s, no object file generated.\n",
+                                 had_errors(), had_errors() == 1 ? "" : "s",
+                                 had_warnings(), had_warnings() == 1 ? "" : "s");
+                 } /* on want output */
+         } /* on error condition */
+
+         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);
+         
+         /*
+          * Emit code.
+          */
+         for (fragP = text_frag_root;  fragP;  fragP = fragP->fr_next) {
+                 register long         count;
+                 register char *               fill_literal;
+                 register long         fill_size;
+                 
+                 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 code frag. */
+         
+         /*
+          * Emit relocations.
+          */
+         obj_emit_relocations(&next_object_file_charP, text_fix_root, (relax_addressT)0);
+         
+#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 */
+         
+         /*
+          * Emit line number entries.
+          */
+         OBJ_EMIT_LINENO(&next_object_file_charP, lineno_rootP, the_object_file);
+         
+         /*
+          * Emit symbols.
+          */
+         obj_emit_symbols(&next_object_file_charP, symbol_rootP);
+         
+         /*
+          * Emit strings.
+          */
+         
+         if (string_byte_count > 0) {
+                 obj_emit_strings(&next_object_file_charP);
+         } /* only if we have a string table */
+         
+         know(next_object_file_charP == the_object_file + object_file_size);
+         /* Write the data to the file */
+         output_file_append(the_object_file,object_file_size,out_file_name);
+         
+#ifdef DONTDEF
+         if (flagseen['G'])            /* GDB symbol file to be appended? */
+             {
+                     gdb_emit (out_file_name);
+                     gdb_end ();
+             }
+#endif /* DONTDEF */
+         
+         output_file_close(out_file_name);
+  } /* non vms output */
+#else  /* VMS */
+  /*
+   *   Now do the VMS-dependent part of writing the object file
+   */
+  VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root);
+#endif /* VMS */
+} /* write_object_file() */
+
+/*
+ *                     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.
+ */
+#ifndef        VMS
+static
+#endif /* not VMS */
+void relax_segment(segment_frag_root, segment_type)
+     struct frag *     segment_frag_root;
+     segT              segment_type; /* SEG_DATA or SEG_TEXT */
+{
+  register struct frag *       fragP;
+  register relax_addressT      address;
+  /* register relax_addressT   old_address; JF unused */
+  /* register relax_addressT   new_address; JF unused */
+
+  know( segment_type == SEG_DATA || segment_type == SEG_TEXT );
+
+  /* In case md_estimate_size_before_relax() wants to make fixSs. */
+  subseg_change(segment_type, 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:
+         address += relax_align(address, fragP->fr_offset);
+         break;
+
+       case rs_org:
+         /*
+          * Assume .org is nugatory. It will grow with 1st relax.
+          */
+         break;
+
+       case rs_machine_dependent:
+         address += md_estimate_size_before_relax(fragP, segment_type);
+         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 */
+\f
+  /*
+   * Do relax().
+   */
+  {
+    register 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. */
+    register 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)
+         {
+           register long growth = 0;
+           register unsigned long was_address;
+           /* register long var; */
+           register long offset;
+           register symbolS *symbolP;
+           register long target;
+           register long after;
+           register long aim;
+
+           was_address = fragP->fr_address;
+           address = fragP->fr_address += stretch;
+           symbolP = fragP->fr_symbol;
+           offset = fragP->fr_offset;
+           /* var = fragP->fr_var; */
+           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;
+               extern int md_short_jump_size;
+               extern int md_long_jump_size;
+
+                       /* 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 (flagseen['k'])
+                                       as_warn(".word %s-%s+%ld didn't fit",
+                                               S_GET_NAME(lie->add),
+                                               S_GET_NAME(lie->sub),
+                                               lie->addnum);
+                               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;
+#endif
+             case rs_align:
+               growth = relax_align ((relax_addressT)(address + fragP->fr_fix), offset)
+                 - relax_align ((relax_addressT)(was_address +  fragP->fr_fix), offset);
+               break;
+
+             case rs_org:
+               target = offset;
+               if (symbolP)
+                 {
+                   know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
+                        (S_GET_SEGMENT(symbolP) == SEG_DATA) ||
+                        (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+                   know(symbolP->sy_frag);
+                   know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || 
+                        symbolP->sy_frag==&zero_address_frag );
+                   target +=
+                     S_GET_VALUE(symbolP)
+                       + symbolP->sy_frag->fr_address;
+                 }
+               know( fragP->fr_next );
+               after = fragP->fr_next->fr_address;
+               growth = ((target - after ) > 0) ? (target - after) : 0;
+                               /* Growth may be -ve, but variable part */
+                               /* of frag cannot have < 0 chars. */
+                               /* That is, we can't .org backwards. */
+
+               growth -= stretch;      /* This is an absolute growth factor */
+               break;
+
+             case rs_machine_dependent:
+               {
+                 register const relax_typeS *  this_type;
+                 register const relax_typeS *  start_type;
+                 register relax_substateT      next_state;
+                 register relax_substateT      this_state;
+
+                 start_type = this_type
+                   = md_relax_table + (this_state = fragP->fr_subtype);
+               target = offset;
+               if (symbolP)
+                 {
+                   know((S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) ||
+                        (S_GET_SEGMENT(symbolP) == SEG_DATA) ||
+                        (S_GET_SEGMENT(symbolP) == SEG_TEXT));
+                   know(symbolP->sy_frag);
+                   know(!(S_GET_SEGMENT(symbolP) == SEG_ABSOLUTE) || 
+                        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.  */
+
+                               /* JF was just address */
+                               /* JF also added is_dnrange hack */
+                               /* There's gotta be a better/faster/etc way
+                                  to do this. . . */
+                       /* gnu@cygnus.com:  I changed this from > to >=
+                          because I ran into a zero-length frag (fr_fix=0)
+                          which was created when the obstack needed a new
+                          chunk JUST AFTER the opcode of a branch.  Since
+                          fr_fix is zero, fr_address of this frag is the same
+                          as fr_address of the next frag.  This
+                          zero-length frag was variable and jumped to .+2
+                          (in the next frag), but since the > comparison
+                          below failed (the two were =, not >), "stretch"
+                          was not added to the target.  Stretch was 178, so
+                          the offset appeared to be .-176 instead, which did
+                          not fit into a byte branch, so the assembler
+                          relaxed the branch to a word.  This didn't compare
+                          with what happened when the same source file was
+                          assembled on other machines, which is how I found it.
+                          You might want to think about what other places have
+                          trouble with zero length frags... */
+
+                   if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP,symbolP->sy_frag))
+                     target += stretch;
+
+                 }
+                 aim = target - address - fragP->fr_fix;
+                 /* The displacement is affected by the instruction size
+                  * for the 32k architecture. I think we ought to be able
+                  * to add fragP->fr_pcrel_adjust in all cases (it should be
+                  * zero if not used), but just in case it breaks something
+                  * else we'll put this inside #ifdef NS32K ... #endif
+                  */
+#ifdef TC_NS32K
+                 aim += fragP->fr_pcrel_adjust;
+#endif /* TC_NS32K */
+
+                 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_type = md_relax_table + (this_state = next_state);
+                             next_state = this_type->rlx_more;
+                           }
+                       }
+                   }
+                 else
+                   {
+#ifdef DONTDEF
+/* JF these next few lines of code are for the mc68020 which can't handle short
+   offsets of zero in branch instructions.  What a kludge! */
+ if (aim==0 && this_state==(1<<2+0)) { /* FOO hard encoded from m.c */
+       aim=this_type->rlx_forward+1;   /* Force relaxation into word mode */
+ }
+#endif
+/* JF end of 68020 code */
+                     /* 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_type = md_relax_table + (this_state = next_state);
+                             next_state = this_type->rlx_more;
+                           }
+                       }
+                   }
+                 if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
+                     fragP->fr_subtype = this_state;
+               }
+               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. */
+  }
+
+  /*
+   * 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() */
+\f
+/*
+ * Relax_align. Advance location counter to next address that has 'alignment'
+ * lowest order bits all 0s.
+ */
+
+ /* 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() */
+\f
+/* 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. */
+{
+       register long seg_reloc_count;
+       register symbolS *add_symbolP;
+       register symbolS *sub_symbolP;
+       register long add_number;
+       register int size;
+       register char *place;
+       register long where;
+       register char pcrel;
+       register fragS *fragP;
+       register segT add_symbol_segment = SEG_ABSOLUTE;
+       fixS *topP = fixP;
+       
+       
+       seg_reloc_count = 0;
+       
+       for ( ;  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;
+#ifdef TC_I960
+               if (fixP->fx_callj && TC_S_IS_CALLNAME(add_symbolP)) {
+                       /* Relocation should be done via the
+                          associated 'bal' entry point
+                          symbol. */
+
+                       if (!TC_S_IS_BALNAME(tc_get_bal_of_call(add_symbolP))) {
+                               as_bad("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);
+               }       /* callj relocation */
+#endif
+               sub_symbolP = fixP->fx_subsy;
+               add_number  = fixP->fx_offset;
+               pcrel     = fixP->fx_pcrel;
+
+               if (add_symbolP) {
+                       add_symbol_segment = S_GET_SEGMENT(add_symbolP);
+               }       /* if there is an addend */
+               
+               if (sub_symbolP) {
+                       if (!add_symbolP) {
+                               /* Its just -sym */
+                               if (S_GET_SEGMENT(sub_symbolP) != SEG_ABSOLUTE) {
+                                       as_bad("Negative of non-absolute symbol %s", S_GET_NAME(sub_symbolP));
+                               } /* not absolute */
+                               
+                               add_number -= S_GET_VALUE(sub_symbolP);
+                               
+                               /* 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)
+                                && ((add_symbol_segment == SEG_DATA)
+                                    || (add_symbol_segment == SEG_TEXT)
+                                    || (add_symbol_segment == SEG_BSS)
+                                    || (add_symbol_segment == SEG_ABSOLUTE))) {
+                               /* 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_callj) {
+                                       as_bad("callj to difference of 2 symbols");
+                               }
+#endif /* TC_I960 */
+                               add_number += S_GET_VALUE(add_symbolP) - 
+                                   S_GET_VALUE(sub_symbolP);
+                               
+                               add_symbolP = NULL;
+                               fixP->fx_addsy = NULL;
+                       } else {
+                               /* Different segments in subtraction. */
+                               know(!(S_IS_EXTERNAL(sub_symbolP) && (S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)));
+                               
+                               if ((S_GET_SEGMENT(sub_symbolP) == SEG_ABSOLUTE)) {
+                                       add_number -= S_GET_VALUE(sub_symbolP);
+                               } else {
+                                       as_bad("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+                                               segment_name(S_GET_SEGMENT(sub_symbolP)),
+                                               S_GET_NAME(sub_symbolP), 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);
+                               pcrel = 0;      /* Lie. Don't want further pcrel processing. */
+                               fixP->fx_addsy = NULL; /* No relocations please. */
+                       } else {
+                               switch (add_symbol_segment) {
+                               case SEG_ABSOLUTE:
+#ifdef TC_I960
+                                       reloc_callj(fixP); /* See comment about reloc_callj() above*/
+#endif /* TC_I960 */
+                                       add_number += S_GET_VALUE(add_symbolP);
+                                       fixP->fx_addsy = NULL;
+                                       add_symbolP = NULL;
+                                       break;
+                                       
+                               case SEG_BSS:
+                               case SEG_DATA:
+                               case SEG_TEXT:
+                                       seg_reloc_count ++;
+                                       add_number += S_GET_VALUE(add_symbolP);
+                                       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("can't use COBR format with external label");
+                                               fixP->fx_addsy = NULL;  /* No relocations please. */
+                                               continue;
+                                       } /* COBR */
+#endif /* TC_I960 */
+ /* FIXME-SOON: I think this is trash, but I'm not sure.  xoxorich. */
+#ifdef comment
+#ifdef OBJ_COFF
+                                       if (S_IS_COMMON(add_symbolP))
+                                           add_number += S_GET_VALUE(add_symbolP);
+#endif /* OBJ_COFF */
+#endif /* comment */
+               
+                                       ++seg_reloc_count;
+                                       break;
+                                       
+                               default:
+                                       BAD_CASE(add_symbol_segment);
+                                       break;
+                               } /* switch on symbol seg */
+                       } /* if not in local seg */
+               } /* if there was a + symbol */
+
+               if (pcrel) {
+                       add_number -= md_pcrel_from(fixP);
+                       if (add_symbolP == 0) {
+                               fixP->fx_addsy = & abs_symbol;
+                               ++seg_reloc_count;
+                       } /* if there's an add_symbol */
+               } /* if pcrel */
+               
+               if (!fixP->fx_bit_fixP) {
+                       if ((size==1 &&
+                            (add_number& ~0xFF)   && (add_number&~0xFF!=(-1&~0xFF))) ||
+                           (size==2 &&
+                            (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF)))) {
+                               as_bad("Value of %d too large for field of %d bytes at 0x%x",
+                                       add_number, size, fragP->fr_address + where);
+                       } /* generic error checking */
+               } /* not a bit fix */
+               
+               md_apply_fix(fixP, add_number);
+       } /* For each fixS in this segment. */
+       
+#ifdef OBJ_COFF
+#ifdef TC_I960
+       /* two relocs per callj under coff. */
+       for (fixP = topP; fixP; fixP = fixP->fx_next) {
+               if (fixP->fx_callj && fixP->fx_addsy != 0) {
+                       ++seg_reloc_count;
+               } /* if callj and not already fixed. */
+       } /* for each fix */
+#endif /* TC_I960 */
+#endif /* OBJ_COFF */
+       return(seg_reloc_count);
+} /* fixup_segment() */
+
+
+static int is_dnrange(f1,f2)
+struct frag *f1;
+struct frag *f2;
+{
+       while (f1) {
+               if (f1->fr_next==f2)
+                       return 1;
+               f1=f1->fr_next;
+       }
+       return 0;
+} /* is_dnrange() */
+
+/* Append a string onto another string, bumping the pointer along.  */
+void
+append (charPP, fromP, length)
+char   **charPP;
+char   *fromP;
+unsigned long length;
+{
+       if (length) {           /* Don't trust bcopy() of 0 chars. */
+               bcopy(fromP, *charPP, (int) length);
+               *charPP += length;
+       }
+}
+
+int section_alignment[SEG_MAXIMUM_ORDINAL];
+
+/*
+ * 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)
+segT seg;      /* Segment to which alignment pertains */
+int align;     /* Alignment, as a power of 2
+                *      (e.g., 1 => 2-byte boundary, 2 => 4-byte boundary, etc.)
+                */
+{
+       
+       if ( align > section_alignment[(int) seg] ){
+               section_alignment[(int) seg] = align;
+       } /* if highest yet */
+       
+       return;
+} /* record_alignment() */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of write.c */
diff --git a/gas/write.h b/gas/write.h
new file mode 100644 (file)
index 0000000..1eecdc0
--- /dev/null
@@ -0,0 +1,130 @@
+/* write.h -> write.c */
+
+/*   MODIFIED BY CHRIS BENENATI, FOR INTEL CORPORATION, 4/89   */
+/* write.h -> write.c
+   Copyright (C) 1987 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef TC_I960
+#ifdef hpux
+#define EXEC_MACHINE_TYPE HP9000S200_ID
+#endif
+#endif /* TC_I960 */
+
+#ifndef LOCAL_LABEL
+#ifdef DOT_LABEL_PREFIX
+#define LOCAL_LABEL(name) (name[0] =='.' \
+                         && ( name [1] == 'L' || name [1] == '.' ))
+#else  /* not defined DOT_LABEL_PREFIX */
+#define LOCAL_LABEL(name) (name [0] == 'L' )
+#endif /* not defined DOT_LABEL_PREFIX */
+#endif /* LOCAL_LABEL */
+
+#define S_LOCAL_NAME(s) (LOCAL_LABEL(S_GET_NAME(s)))
+
+/* 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) 
+ */
+
+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;
+/*
+ * FixSs may be built up in any order.
+ */
+
+struct fix
+{
+  fragS *              fx_frag;        /* Which frag? */
+  long         fx_where;       /* Where is the 1st byte to fix up? */
+  symbolS *            fx_addsy; /* NULL or Symbol whose value we add in. */
+  symbolS *            fx_subsy; /* NULL or Symbol whose value we subtract. */
+  long         fx_offset;      /* Absolute number we add in. */
+  struct fix *         fx_next;        /* NULL or -> next fixS. */
+  short int            fx_size;        /* How many bytes are involved? */
+  char                 fx_pcrel;       /* TRUE: pc-relative. */
+  char                 fx_pcrel_adjust;/* pc-relative offset adjust */
+  char                 fx_im_disp;     /* TRUE: value is a displacement */
+  bit_fixS *           fx_bit_fixP;    /* IF NULL no bitfix's to do */  
+  char                 fx_bsr;         /* sequent-hack */
+  enum reloc_type      fx_r_type;      /* Sparc hacks */
+  char                 fx_callj;       /* TRUE if target is a 'callj'
+                                          (used by i960) */
+  long                 fx_addnumber;
+};
+
+typedef struct fix     fixS;
+
+COMMON char *next_object_file_charP;
+
+COMMON fixS *text_fix_root, *text_fix_tail;    /* Chains fixSs. */
+COMMON fixS *data_fix_root, *data_fix_tail;    /* Chains fixSs. */
+COMMON fixS **seg_fix_rootP, **seg_fix_tailP;  /* -> one of above. */
+extern long string_byte_count;
+extern int section_alignment[];
+
+#ifdef __STDC__
+
+bit_fixS *bit_fix_new(char size, char offset, long base_type, long base_adj, long min, long max, long add);
+void append(char **charPP, char *fromP, unsigned long length);
+void record_alignment(segT seg, int align);
+void write_object_file(void);
+
+fixS *fix_new(fragS *frag,
+             int where,
+             int size,
+             symbolS *add_symbol,
+             symbolS *sub_symbol,
+             long offset,
+             int pcrel,
+             enum reloc_type r_type);
+
+#else
+
+bit_fixS *bit_fix_new();
+fixS *fix_new();
+void append();
+void record_alignment();
+void write_object_file();
+
+#endif /* __STDC__ */
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of write.h */
diff --git a/gas/xmalloc.c b/gas/xmalloc.c
new file mode 100644 (file)
index 0000000..6602987
--- /dev/null
@@ -0,0 +1,71 @@
+/* xmalloc.c - get memory or bust
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* static const char rcsid[] = "$Id$"; */
+
+/*
+NAME
+       xmalloc() - get memory or bust
+INDEX
+       xmalloc() uses malloc()
+
+SYNOPSIS
+       char *  my_memory;
+
+       my_memory = xmalloc(42); / * my_memory gets address of 42 chars * /
+
+DESCRIPTION
+
+       Use xmalloc() as an "error-free" malloc(). It does almost the same job.
+       When it cannot honour your request for memory it BOMBS your program
+       with a "virtual memory exceeded" message. Malloc() returns NULL and
+       does not bomb your program.
+
+SEE ALSO
+       malloc()
+
+*/
+#include <stdio.h>
+
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#ifdef USG
+#include <malloc.h>
+#else
+  char *       malloc();
+#endif /* USG */
+#endif /* __STDC__ */
+
+#define error as_fatal
+
+char * xmalloc(n)
+     long n;
+{
+  char *       retval;
+  void error();
+
+  if ((retval = malloc ((unsigned)n)) == NULL)
+    {
+      error("virtual memory exceeded");
+    }
+  return (retval);
+}
+
+/* end: xmalloc.c */
diff --git a/gas/xrealloc.c b/gas/xrealloc.c
new file mode 100644 (file)
index 0000000..83d3ce6
--- /dev/null
@@ -0,0 +1,70 @@
+/* xrealloc.c -new memory or bust-
+   Copyright (C) 1987, 1990, 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/* static const char rcsid[] = "$Id$"; */
+
+/* 
+
+NAME
+       xrealloc () - get more memory or bust
+INDEX
+       xrealloc () uses realloc ()
+SYNOPSIS
+       char   *my_memory;
+
+       my_memory = xrealloc (my_memory, 42);
+       / * my_memory gets (perhaps new) address of 42 chars * /
+
+DESCRIPTION
+
+       Use xrealloc () as an "error-free" realloc ().It does almost the same
+       job.  When it cannot honour your request for memory it BOMBS your
+       program with a "virtual memory exceeded" message.  Realloc() returns
+       NULL and does not bomb your program.
+
+SEE ALSO
+       realloc ()
+*/
+
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#ifdef USG
+#include <malloc.h>
+#else
+    char   *realloc ();
+#endif /* USG */
+#endif /* __STDC__ */
+
+#define error as_fatal
+
+char   *
+xrealloc (ptr, n)
+register char  *ptr;
+long    n;
+{
+    void       error();
+
+    if ((ptr = realloc (ptr, (unsigned)n)) == 0)
+       error ("virtual memory exceeded");
+    return (ptr);
+}
+
+/* end: xrealloc.c */