Added the new gas directory
authorNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 09:51:23 +0000 (09:51 +0000)
committerNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 09:51:23 +0000 (09:51 +0000)
52 files changed:
gnu/usr.bin/as/COPYING [new file with mode: 0644]
gnu/usr.bin/as/ChangeLog [new file with mode: 0644]
gnu/usr.bin/as/Makefile [new file with mode: 0644]
gnu/usr.bin/as/Makefile.gnu [new file with mode: 0644]
gnu/usr.bin/as/NOTES [new file with mode: 0644]
gnu/usr.bin/as/README.gnu [new file with mode: 0644]
gnu/usr.bin/as/app.c [new file with mode: 0644]
gnu/usr.bin/as/append.c [new file with mode: 0644]
gnu/usr.bin/as/as.1 [new file with mode: 0644]
gnu/usr.bin/as/as.c [new file with mode: 0644]
gnu/usr.bin/as/as.h [new file with mode: 0644]
gnu/usr.bin/as/atof-generic.c [new file with mode: 0644]
gnu/usr.bin/as/bignum-copy.c [new file with mode: 0644]
gnu/usr.bin/as/bignum.h [new file with mode: 0644]
gnu/usr.bin/as/config/Makefile.i386 [new file with mode: 0644]
gnu/usr.bin/as/config/a.out.gnu.h [new file with mode: 0644]
gnu/usr.bin/as/config/atof-ieee.c [new file with mode: 0644]
gnu/usr.bin/as/config/i386-opcode.h [new file with mode: 0644]
gnu/usr.bin/as/config/i386.c [new file with mode: 0644]
gnu/usr.bin/as/config/i386.h [new file with mode: 0644]
gnu/usr.bin/as/expr.c [new file with mode: 0644]
gnu/usr.bin/as/expr.h [new file with mode: 0644]
gnu/usr.bin/as/flonum-const.c [new file with mode: 0644]
gnu/usr.bin/as/flonum-copy.c [new file with mode: 0644]
gnu/usr.bin/as/flonum-mult.c [new file with mode: 0644]
gnu/usr.bin/as/flonum.h [new file with mode: 0644]
gnu/usr.bin/as/frags.c [new file with mode: 0644]
gnu/usr.bin/as/frags.h [new file with mode: 0644]
gnu/usr.bin/as/hash.c [new file with mode: 0644]
gnu/usr.bin/as/hash.h [new file with mode: 0644]
gnu/usr.bin/as/hex-value.c [new file with mode: 0644]
gnu/usr.bin/as/input-file.c [new file with mode: 0644]
gnu/usr.bin/as/input-file.h [new file with mode: 0644]
gnu/usr.bin/as/input-scrub.c [new file with mode: 0644]
gnu/usr.bin/as/md.h [new file with mode: 0644]
gnu/usr.bin/as/messages.c [new file with mode: 0644]
gnu/usr.bin/as/objrecdef.h [new file with mode: 0644]
gnu/usr.bin/as/obstack.c [new file with mode: 0644]
gnu/usr.bin/as/obstack.h [new file with mode: 0644]
gnu/usr.bin/as/output-file.c [new file with mode: 0644]
gnu/usr.bin/as/read.c [new file with mode: 0644]
gnu/usr.bin/as/read.h [new file with mode: 0644]
gnu/usr.bin/as/struc-symbol.h [new file with mode: 0644]
gnu/usr.bin/as/subsegs.c [new file with mode: 0644]
gnu/usr.bin/as/subsegs.h [new file with mode: 0644]
gnu/usr.bin/as/symbols.c [new file with mode: 0644]
gnu/usr.bin/as/symbols.h [new file with mode: 0644]
gnu/usr.bin/as/version.c [new file with mode: 0644]
gnu/usr.bin/as/write.c [new file with mode: 0644]
gnu/usr.bin/as/write.h [new file with mode: 0644]
gnu/usr.bin/as/xmalloc.c [new file with mode: 0644]
gnu/usr.bin/as/xrealloc.c [new file with mode: 0644]

diff --git a/gnu/usr.bin/as/COPYING b/gnu/usr.bin/as/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/gnu/usr.bin/as/ChangeLog b/gnu/usr.bin/as/ChangeLog
new file mode 100644 (file)
index 0000000..3e0e64f
--- /dev/null
@@ -0,0 +1,917 @@
+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'.
+
+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/gnu/usr.bin/as/Makefile b/gnu/usr.bin/as/Makefile
new file mode 100644 (file)
index 0000000..e75351b
--- /dev/null
@@ -0,0 +1,15 @@
+#      @(#)Makefile    6.1 (Berkeley) 3/3/91
+
+PROG=          as
+SRCS=          app.c append.c as.c atof-generic.c bignum-copy.c \
+               expr.c flonum-const.c flonum-copy.c flonum-mult.c \
+               frags.c hash.c hex-value.c input-file.c input-scrub.c \
+               messages.c obstack.c output-file.c read.c subsegs.c \
+               symbols.c version.c write.c xmalloc.c xrealloc.c
+CFLAGS+=       -I$(.CURDIR) -I$(.CURDIR)/config \
+               -DSIGTY=void -Derror=as_fatal
+.PATH: $(.CURDIR)/config
+
+.include "config/Makefile.$(MACHINE)"
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/as/Makefile.gnu b/gnu/usr.bin/as/Makefile.gnu
new file mode 100644 (file)
index 0000000..4b81b0c
--- /dev/null
@@ -0,0 +1,356 @@
+# Makefile for GAS.
+# 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.
+
+# This makefile may be used to make the VAX, 68020, 80386, 
+# SPARC, ns32k, or i860 assembler(s).
+
+BINDIR = /usr/local/bin
+#CC=gcc
+
+# If you are on a BSD system, un-comment the next two lines, and comment out
+# the lines for SystemV and HPUX below
+G0 = -g  -I. #-O -Wall
+LDFLAGS = $(CFLAGS)
+#
+# To compile gas on a System Five machine, comment out the two lines above
+# and un-comment out the next three lines
+# Comment out the -lPW on the LOADLIBES line if you are using GCC.
+# G0 = -g -I. -DUSG
+# LDFLAGS = $(CFLAGS)
+# LOADLIBES = -lmalloc -lPW
+#
+# To compile gas for HPUX, link m-hpux.h to m68k.h , and un-comment the
+# next two lines.  (If you are using GCC, comment out the alloca.o part)
+# (Get alloca from the emacs distribution, or use GCC.)
+# HPUX 7.0 may have a bug in setvbuf.  gas gives an error message like
+# 1:"Unknown operator" -- Statement 'NO_APP' ignored
+# if setvbuf is broken.  Re-compile input-file.c (and only input-file.c
+# with -DVMS and the problem should go away.
+#
+# G0 = -g -I. -DUSG
+# LOADLIBES = alloca.o
+#
+# To compile gas for a Sequent Symmetry, comment out all the above lines,
+# and un-comment the next two lines.
+# G0 = -g -I. -DUSE_SYSTEM_HDR -DEXEC_VERSION=1
+# LOADLIBES = -lc /usr/att/lib/libc.a
+
+# If you just want to compile the vax assembler, type 'make avax'
+
+# If you just want to compile the i386 assembler, type 'make a386'
+
+# If you just want to compile the ns32k assembler, type 'make a32k'
+
+# If you just want to compile the sparc assembler, type 'make asparc'
+
+# If you just want to compile the mc68020 assembler, make sure m68k.h
+# is correctly set up, and type type 'make a68'  (Except on HPUX machines,
+# where you will have to make the changes marked below before typing
+# 'make a68'
+# m68k.h should be a symbolic or hard-link to one of
+# m-sun3.h , m-hpux.h or m-generic.h
+# depending on which machine you want to compile the 68020 assembler for.
+#
+# If you want the 68k assembler to be completely compatable with the the
+# SUN one, un-comment the -DSUN_ASM_SYNTAX line below.
+#
+# If you machine does not have vfprintf, but does have _doprnt(),
+# remove the # from the -DNO_VARARGS line below.
+#
+# If the return-type of a signal-hander is void (instead of int),
+# remove the # from the -DSIGTY line below.
+#
+# To include the mc68851 mmu coprocessor instructions in the 68020 assembler,
+# remove the # from the -Dm68851 line below.
+#
+# If you want the 68020 assembler use a register prefix character, un-comment
+# the REGISTER_PREFIX line, and (maybe) change the '%' to the appropriate
+# character.
+#
+# If you want the assembler to treat .L* or ..* symbols as local, instead of
+# the usual L* symbols, un-comment the DOT_LABEL_PREFIX line.
+#
+# If you want the 80386 assembler to correctly handle fsub/fsubr and fdiv/fdivr
+# opcodes (unlike most 80386 assemblers), remove the # from
+# the -DNON_BROKEN_WORDS line below.
+#
+# To compile 80386 Gas for the Sequent Symmetry, un-comment the -DEXEC_VERSION
+# and the -DUSE_SYSTEM_HDR lines below.
+#
+# To compile gas for the HP 9000/300 un-comment the -DUSE_HP_HDR line below.
+#
+# For the ns32k, the options are 32532 or 32032 CPU and 32381 or 32081 FPU.
+# To select the NS32532, remove the # from the -DNS32532 line below.
+# To compile in tne NS32381 opcodes in addition to the NS32081 opcodes
+# (the 32381 is a superset of the 32081), remove the # from the -DNS32381
+# line below.
+#
+# For the ns32k on a Sequent, uncomment the SEQUENT_COMPATABILITY line below.
+#
+# If you want the .align N directive to align to the next N byte boundry,
+# instead of the next 1<<N boundry, un-comment the OTHER_ALIGN line below.
+# (This option is automatically enabled when building the sparc assembler.
+#
+
+O1 =  -DNO_VARARGS
+O2 = # -DNON_BROKEN_WORDS
+O3 = # -Dm68851
+O4 = # -DEXEC_VERSION=1
+O5 = # -DSIGTY=void
+O6 = # -DNS32532
+O6 = # -DNS32381
+O7 = # -DDOT_LABEL_PREFIX
+O8 = # -DSEQUENT_COMPATABILITY
+O9 = # -DREGISTER_PREFIX=\'%\'
+O10= # -DOTHER_ALIGN
+
+G1 = # -DUSE_SYSTEM_HDR
+G2 = # -DUSE_HP_HDR
+G3 = # -DSUN_ASM_SYNTAX
+
+OPTIONS = $(O1) $(O2) $(O3) $(O4) $(O5) $(O6) $(O7) $(O8) $(O9) $(O10)
+
+CFLAGS = $(G0) $(G1) $(G2) $(G3) $(G4)
+
+#
+# To make the 68020 assembler compile as the default, un-comment the next
+# line, and comment out all the other lines that start with DEFAULT_GAS
+DEFAULT_GAS=a68
+#
+# To make the VAX assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=avax
+#
+# To make the 80386 assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a386
+#
+# To make the ns32k assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a32k
+#
+# To make the sparc assembler compile as the default, un-comment the next
+# line and commment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=asparc
+#
+# To make the i860 assembler compile as the default, un-comment the next
+# line and comment out all the other lines that start with DEFAULT_GAS
+#DEFAULT_GAS=a860
+
+# Global Sources -------------------------------------------------------------
+
+a =\
+as.o           xrealloc.o      xmalloc.o       hash.o          hex-value.o   \
+atof-generic.o append.o        messages.o      expr.o          app.o         \
+frags.o                input-file.o    input-scrub.o   output-file.o                 \
+subsegs.o      symbols.o                                       version.o     \
+flonum-const.o flonum-copy.o   flonum-mult.o   strstr.o        bignum-copy.o \
+obstack.o
+#gdb.o         gdb-file.o      gdb-symbols.o   gdb-blocks.o    gdb-lines.o
+
+a:     $(DEFAULT_GAS)
+       @rm -f a
+       @ln $(DEFAULT_GAS) a
+
+# I860 GAS ------------------------------------------------------------------
+u = i860.o  atof-ieee.o  write-i860.o  read-i860.o
+
+U = i860.c  i860.h i860-opcode.h
+
+i860.o:        i860.c i860.h i860-opcode.h as.h frags.h struc-symbol.h
+i860.o:        flonum.h expr.h hash.h md.h write.h read.h symbols.h
+       $(CC) -c $(CFLAGS) -DI860 i860.c
+
+atof-ieee.o:   flonum.h
+
+write-i860.o:  write.c i860.h
+       $(CC) -c -DI860 $(CFLAGS) write.c
+       mv write.o write-i860.o
+
+read-i860.o: read.c i860.h
+       $(CC) -c -DI860 $(CFLAGS) read.c
+       mv read.o read-i860.o
+
+a860: $a $u
+       $(CC) -o a860 $(LDFLAGS) $a $u $(LOADLIBES)
+
+# SPARC GAS ------------------------------------------------------------------
+v = sparc.o  atof-ieee.o  write-sparc.o  read-sparc.o
+
+V = sparc.c  sparc.h  sparc-opcode.h
+
+atof-ieee.o:   flonum.h
+sparc.o:       sparc.c sparc.h sparc-opcode.h as.h frags.h struc-symbol.h
+sparc.o:       flonum.h expr.h hash.h md.h write.h read.h symbols.h
+       $(CC) -c $(CFLAGS) -DSPARC sparc.c
+
+write-sparc.o: write.c
+       $(CC) -c -DSPARC $(CFLAGS) write.c
+       mv write.o write-sparc.o
+
+read-sparc.o: read.c
+       $(CC) -c -DSPARC $(CFLAGS) read.c
+       mv read.o read-sparc.o
+
+asparc: $a $v
+       $(CC) -o asparc $(LDFLAGS) $a $v $(LOADLIBES)
+
+# NS32K GAS ------------------------------------------------------------------
+w = ns32k.o  atof-ieee.o  write-ns32k.o  read-ns32k.o
+
+W = ns32k.c ns32k-opcode.h
+
+atof-ieee.o:   flonum.h
+ns32k.o:       as.h frags.h struc-symbol.h flonum.h expr.h md.h hash.h
+ns32k.o:       write.h symbols.h ns32k-opcode.h ns32k.c
+       $(CC) $(CFLAGS) $(OPTIONS) -c ns32k.c
+
+write-ns32k.o: write.c
+       $(CC) -c -DNS32K $(CFLAGS) write.c
+       mv write.o write-ns32k.o
+
+read-ns32k.o:
+       $(CC) -c -DNS32K $(CFLAGS) read.c
+       mv read.o read-ns32k.o
+
+a32k: $a $w
+       $(CC) -o a32k $(LDFLAGS) $a $w $(LOADLIBES)
+
+# 80386 GAS ------------------------------------------------------------------
+x = i386.o  atof-ieee.o  write.o  read.o
+
+X = i386.c  i386.h  i386-opcode.h
+
+i386.o:                i386.c as.h read.h flonum.h frags.h struc-symbol.h expr.h
+i386.o:                symbols.h hash.h md.h i386.h i386-opcode.h
+       $(CC) $(CFLAGS) $(OPTIONS) -c i386.c
+
+atof-ieee.o:   flonum.h
+
+a386: $a $x
+       $(CC) -o a386 $(LDFLAGS) $a $x $(LOADLIBES)
+
+# 68020 GAS ------------------------------------------------------------------
+y = m68k.o  atof-ieee.o write.o read.o
+
+Y = m68k.c atof-ieee.c m68k-opcode.h m-hpux.h m-sun3.h m-generic.h
+
+atof-ieee.o:   flonum.h
+
+m68k.o:                m68k.c a.out.gnu.h as.h expr.h flonum.h frags.h hash.h
+m68k.o:                m68k-opcode.h m68k.h md.h obstack.h struc-symbol.h
+       $(CC) $(CFLAGS) $(OPTIONS) -c m68k.c
+
+a68: $a $y
+       $(CC) -o a68 $(LDFLAGS) $a $y $(LOADLIBES)
+
+# VAX GAS --------------------------------------------------------------------
+z = vax.o  atof-vax.o  write.o  read.o
+
+Z = vax.c atof-vax.c vax-opcode.h vax-inst.h \
+    make-gas.com objrecdef.h vms.c vms-dbg.c README-vms-dbg
+
+vax.o:         vax.c a.out.gnu.h as.h expr.h flonum.h frags.h md.h obstack.h
+vax.o:         read.h struc-symbol.h symbols.h vax-inst.h vax-opcode.h
+atof-vax.o:    as.h flonum.h read.h
+
+avax:  $a $z
+       $(CC) -o avax $(LDFLAGS) $a $z $(LOADLIBES)
+
+# global files ---------------------------------------------------------------
+
+as.o: as.c
+       $(CC) $(CFLAGS) $(OPTIONS) -c as.c
+
+messages.o: messages.c
+       $(CC) $(CFLAGS) $(OPTIONS) -c messages.c
+
+hash.o:        hash.c
+       $(CC) $(CFLAGS) -Derror=as_fatal -c hash.c
+
+xmalloc.o:     xmalloc.c
+       $(CC) $(CFLAGS) -Derror=as_fatal -c xmalloc.c
+
+xrealloc.o:    xrealloc.c
+       $(CC) $(CFLAGS) -Derror=as_fatal -c xrealloc.c
+
+A =\
+as.c           xrealloc.c      xmalloc.c       hash.c          hex-value.c \
+atof-generic.c append.c        messages.c      expr.c          bignum-copy.c \
+frags.c                input-file.c    input-scrub.c   output-file.c   read.c \
+subsegs.c      symbols.c       write.c                         strstr.c \
+flonum-const.c flonum-copy.c   flonum-mult.c   app.c           version.c \
+obstack.c \
+#gdb.c         gdb-file.c      gdb-symbols.c   gdb-blocks.c \
+#gdb-lines.c
+
+H = \
+a.out.gnu.h    as.h            bignum.h        expr.h          flonum.h \
+frags.h                hash.h          input-file.h    md.h     \
+obstack.h      read.h          struc-symbol.h  subsegs.h       \
+symbols.h      write.h
+
+dist: COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile
+       echo gas-`sed -n -e '/ version /s/[^0-9.]*\([0-9.]*\).*/\1/p' < version.c` > .fname
+       mkdir `cat .fname`
+
+       ln COPYING README ChangeLog $A $H $Z $Y $X $W $V $U Makefile `cat .fname`
+       tar cvhZf `cat .fname`.tar.Z `cat .fname`
+       -rm -r `cat .fname`
+       -rm .fname
+
+clean:
+       rm -f a avax a68 a386 a32k asparc $a $v $w $x $y $z a core gmon.out bugs a.out
+
+install:       a
+       cp a $(BINDIR)/gas
+
+
+# General .o-->.h dependencies
+
+app.o:         as.h
+as.o:          a.out.gnu.h as.h read.h struc-symbol.h write.h
+atof-generic.o:        flonum.h
+bignum-copy.o: bignum.h
+expr.o:                a.out.gnu.h as.h expr.h flonum.h obstack.h read.h struc-symbol.h
+expr.o:                 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:       a.out.gnu.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:        a.out.gnu.h as.h struc-symbol.h
+hash.o:                hash.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:                a.out.gnu.h as.h expr.h flonum.h frags.h hash.h md.h obstack.h
+read.o:                read.h struc-symbol.h symbols.h
+subsegs.o:     a.out.gnu.h as.h frags.h obstack.h struc-symbol.h subsegs.h write.h
+symbols.o:     a.out.gnu.h as.h frags.h hash.h obstack.h struc-symbol.h symbols.h
+write.o:       a.out.gnu.h as.h md.h obstack.h struc-symbol.h subsegs.h
+write.o:       symbols.h write.h
+
+flonum.h:                                      bignum.h
+
diff --git a/gnu/usr.bin/as/NOTES b/gnu/usr.bin/as/NOTES
new file mode 100644 (file)
index 0000000..b3f3f92
--- /dev/null
@@ -0,0 +1,35 @@
+gdb debugging of assembly sources:
+       write a function linestab() that generates a .stabd symbol
+               independently of the input
+       write a function filestab() to generate a .stabs symbol
+       we need to take especial care with #line directives
+               since we want to handle locore, and locore is passed thru cpp
+               this could be tough
+       outline of a solution:
+               cpp sends us lines of the form
+                       # logical-line "logical-file" trash
+               these lines are interpreted ahead of the gas preprocess pass
+               in the starting state, the logical filename is the same
+                       as the real filename (in case there're no #lines)
+               the initial logical line number is 1
+               every time we're ready to process a new instruction line,
+                       if the source file has changed,
+                               emit a .stabs for the logical file
+                       emit a .stabd for the logical line
+                       bump the logical line number
+                               can gas eat multiple actual lines in one insn?
+
+i386 nits:
+       jmp *$foo produces a short relative branch
+       string quotes in comments
+               Bill says gas eats text across newlines to find matches
+               works fine for me
+               I think it's most likely due to cpp
+       make / no longer be a comment char
+               it's now like the VAX: # is the only comment char
+       incorrectly assembles lcall, int3, into, bsr/f instructions
+       constant expressions fail if more than a few terms
+               gives (low+2)*3+4*5 as an example
+               works fine for me
+       cpp seems to think $ is a valid literal
+               use -$ in /usr/bin/cpp
diff --git a/gnu/usr.bin/as/README.gnu b/gnu/usr.bin/as/README.gnu
new file mode 100644 (file)
index 0000000..46f135f
--- /dev/null
@@ -0,0 +1,133 @@
+This is the beta-test version of the GNU assembler.  (Probably
+around Version 1.35, but check version.c which gets updated more
+often than this readme.)
+
+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.
+
+These files are currently set up to allow you to compile all of the
+versions of the assembler (68020, VAX, ns32k, and i386) on the same
+machine.  To compile the 68020 version, type 'make a68'.  To compile
+the VAX version, type 'make avax'.  To compile the ns32k version,
+type 'make a32k'.  To compile the Intel 80386 version, type 'make
+a386'.  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.
+
+
+       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/gnu/usr.bin/as/app.c b/gnu/usr.bin/as/app.c
new file mode 100644 (file)
index 0000000..a0ec8a2
--- /dev/null
@@ -0,0 +1,392 @@
+/* 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>;.file <filename> pair.
+   This needs better error-handling.
+ */
+#include <stdio.h>
+#ifdef USG
+#define bzero(s,n) memset(s,0,n)
+#endif
+#if !defined(__STDC__) && !defined(const)
+#define const /* Nothing */
+#endif
+
+static char    lex [256];
+static const char      symbol_chars[] = 
+       "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+extern const char comment_chars[];
+extern const char line_comment_chars[];
+
+#define LEX_IS_SYMBOL_COMPONENT                (1)
+#define LEX_IS_WHITESPACE              (2)
+#define LEX_IS_LINE_SEPERATOR          (4)
+#define LEX_IS_COMMENT_START           (8)     /* JF added these two */
+#define LEX_IS_LINE_COMMENT_START      (16)
+#define IS_SYMBOL_COMPONENT(c)         (lex [c] & LEX_IS_SYMBOL_COMPONENT)
+#define IS_WHITESPACE(c)               (lex [c] & LEX_IS_WHITESPACE)
+#define IS_LINE_SEPERATOR(c)           (lex [c] & LEX_IS_LINE_SEPERATOR)
+#define IS_COMMENT(c)                  (lex [c] & LEX_IS_COMMENT_START)
+#define IS_LINE_COMMENT(c)             (lex [c] & LEX_IS_LINE_COMMENT_START)
+
+void
+do_scrub_begin()
+{
+       const char *p;
+
+       bzero (lex, sizeof(lex));               /* Trust NOBODY! */
+       lex [' ']               |= LEX_IS_WHITESPACE;
+       lex ['\t']              |= LEX_IS_WHITESPACE;
+       for (p =symbol_chars;*p;++p)
+               lex [*p] |= LEX_IS_SYMBOL_COMPONENT;
+       lex ['\n']              |= LEX_IS_LINE_SEPERATOR;
+#ifdef DONTDEF
+       lex [':']               |= LEX_IS_LINE_SEPERATOR;
+#endif
+       lex [';']               |= LEX_IS_LINE_SEPERATOR;
+       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;
+}
+
+FILE *scrub_file;
+
+int
+scrub_from_file()
+{
+       return getc(scrub_file);
+}
+
+void
+scrub_to_file(ch)
+int ch;
+{
+       ungetc(ch,scrub_file);
+}
+
+char *scrub_string;
+char *scrub_last_string;
+
+int
+scrub_from_string()
+{
+       return scrub_string == scrub_last_string ? EOF : *scrub_string++;
+}
+
+void
+scrub_to_string(ch)
+int ch;
+{
+       *--scrub_string=ch;
+}
+
+int
+do_scrub_next_char(get,unget)
+int (*get)();
+void (*unget)();
+/* FILE *fp; */
+{
+       /* State 0: beginning of normal line
+               1: After first whitespace on normal line (flush more white)
+               2: After first non-white on normal line (keep 1white)
+               3: after second white on normal line (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 .file, put out string.
+               8: After putting out a .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
+       */
+
+       static state;
+       static old_state;
+       static char *out_string;
+       static char out_buf[20];
+       static add_newlines;
+       int ch;
+
+       if(state==-1) {
+               ch= *out_string++;
+               if(*out_string==0) {
+                       state=old_state;
+                       old_state=3;
+               }
+               return ch;
+       }
+       if(state==-2) {
+               for(;;) {
+                       do ch=(*get)();
+                       while(ch!=EOF && ch!='\n' && ch!='*');
+                       if(ch=='\n' || ch==EOF)
+                               return ch;
+                        ch=(*get)();
+                        if(ch==EOF || ch=='/')
+                               break;
+                       (*unget)(ch);
+               }
+               state=old_state;
+               return ' ';
+       }
+       if(state==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="; .file ";
+                               old_state=7;
+                               state= -1;
+                               return *out_string++;
+                       } else {
+                               while(ch!=EOF && ch!='\n')
+                                       ch=(*get)();
+                               return ch;
+                       }
+               }
+       }
+       if(state==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;
+               }
+       }
+       if(state==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':
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+                       break;
+               default:
+                       as_warn("Unknown escape '\\%c' in string: Ignored",ch);
+                       break;
+
+               case EOF:
+                       as_warn("End of file in string: '\"' inserted");
+                       return '"';
+               }
+               return ch;
+       }
+
+       if(state==7) {
+               ch=(*get)();
+               state=5;
+               old_state=8;
+               return ch;
+       }
+
+       if(state==8) {
+               do ch= (*get)();
+               while(ch!='\n');
+               state=0;
+               return ch;
+       }
+
+ flushchar:
+       ch=(*get)();
+       switch(ch) {
+       case ' ':
+       case '\t':
+               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_SEPERATOR(ch)) {
+                       (*unget)(ch);
+                       goto flushchar;
+               }
+               (*unget)(ch);
+               if(state==0 || state==2) {
+                       state++;
+                       return ' ';
+               } else goto flushchar;
+
+       case '/':
+               ch=(*get)();
+               if(ch=='*') {
+                       for(;;) {
+                               do {
+                                       ch=(*get)();
+                                       if(ch=='\n')
+                                               add_newlines++;
+                               } while(ch!=EOF && ch!='*');
+                               ch=(*get)();
+                               if(ch==EOF || ch=='/')
+                                       break;
+                               (*unget)(ch);
+                       }
+                       if(ch==EOF)
+                               as_warn("End of file in '/' '*' string: */ inserted");
+
+                       (*unget)(' ');
+                       goto flushchar;
+               } else {
+                       if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) {
+                               (*unget)(ch);
+                               ch='/';
+                               goto deal_misc;
+                       }
+                       if(ch!=EOF)
+                               (*unget)(ch);
+                       return '/';
+               }
+               break;
+
+       case '"':
+               old_state=state;
+               state=5;
+               return '"';
+               break;
+
+       case '\'':
+               ch=(*get)();
+               if(ch==EOF) {
+                       as_warn("End-of-file after a ': \000 inserted");
+                       ch=0;
+               }
+               sprintf(out_buf,"(%d)",ch&0xff);
+               old_state=state;
+               state= -1;
+               out_string=out_buf;
+               return *out_string++;
+
+       case ':':
+               if(state!=3)
+                       state=0;
+               return ch;
+
+       case '\n':
+               if(add_newlines) {
+                       --add_newlines;
+                       (*unget)(ch);
+               }
+       case ';':
+               state=0;
+               return ch;
+
+       default:
+       deal_misc:
+               if(state==0 && IS_LINE_COMMENT(ch)) {
+                       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') {
+                               while(ch!=EOF && ch!='\n')
+                                       ch=(*get)();
+                               if(ch==EOF)
+                                       as_warn("EOF in Comment: Newline inserted");
+                               state=0;
+                               return '\n';
+                       }
+                       (*unget)(ch);
+                       old_state=4;
+                       state= -1;
+                       out_string=".line ";
+                       return *out_string++;
+
+               } else if(IS_COMMENT(ch)) {
+                       do ch=(*get)();
+                       while(ch!=EOF && ch!='\n');
+                       if(ch==EOF)
+                               as_warn("EOF in comment:  Newline inserted");
+                       state=0;
+                       return '\n';
+
+               } else if(state==0) {
+                       state=2;
+                       return ch;
+               } else if(state==1) {
+                       state=2;
+                       return ch;
+               } else {
+                       return ch;
+
+               }
+       case EOF:
+               if(state==0)
+                       return ch;
+               as_warn("End-of-File not at end of a line");
+       }
+       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
diff --git a/gnu/usr.bin/as/append.c b/gnu/usr.bin/as/append.c
new file mode 100644 (file)
index 0000000..d51a27f
--- /dev/null
@@ -0,0 +1,37 @@
+/* Append a string ontp another string
+   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:  This is silly.  Why not stuff this in some other file? */
+#ifdef USG
+#define bcopy(from,to,n) memcpy(to,from,n)
+#endif
+
+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;
+       }
+}
+
+/* end: append.c */
diff --git a/gnu/usr.bin/as/as.1 b/gnu/usr.bin/as/as.1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c
new file mode 100644 (file)
index 0000000..db85525
--- /dev/null
@@ -0,0 +1,324 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)as.c       6.3 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* as.c - GAS main program.
+   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.  */
+
+/*
+ * 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.
+ *
+ */
+
+#ifdef _POSIX_SOURCE
+#include <sys/types.h> /* For pid_t in signal.h */
+#endif
+#include <signal.h>
+
+#define COMMON
+#include "as.h"
+#include "struc-symbol.h"
+#include "write.h"
+               /* Warning!  This may have some slightly strange side effects
+                  if you try to compile two or more assemblers in the same
+                  directory!
+                */
+
+#ifndef SIGTY
+#define SIGTY int
+#endif
+
+SIGTY got_sig();
+
+#ifdef DONTDEF
+static char * gdb_symbol_file_name;
+long int gdb_begin();
+#endif
+
+char *myname;          /* argv[0] */
+extern char version_string[];
+\f
+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};
+
+       extern int bad_error;   /* Did we hit a bad error ? */
+
+       char    *stralloc();    /* Make a (safe) copy of a string. */
+       void    symbol_begin();
+       void    read_begin();
+       void    write_object_file();
+
+       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 */
+       out_file_name   = "a.out";      /* default .o file */
+       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.
+        */
+       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)  {/* scan all the 1-char flags */
+                       arg ++; /* arg -> after letter. */
+                       a &= 0x7F;      /* ascii only please */
+                       if (flagseen[a])
+                               as_warn("%s: Flag option -%c has already been seen!",myname,a);
+                       flagseen[a] = TRUE;
+                       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
+
+#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 */
+                               break;
+
+                       case 'g':
+                               /*
+                                * -g asks gas to produce gdb/dbx line number
+                                * and file name stabs so that an assembly
+                                * file can be handled by a source debugger.
+                                */
+                               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. */
+       if (seen_at_least_1_file() && !bad_error)
+               write_object_file();/* relax() addresses then emit object file */
+       input_scrub_end();
+       md_end();                       /* MACHINE.c */
+#ifndef        VMS
+       exit(bad_error);                        /* WIN */
+#else  /* VMS */
+       exit(!bad_error);                       /* WIN */
+#endif /* VMS */
+}
+\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.
+ */
+perform_an_assembly_pass (argc, argv)
+int    argc;
+char **        argv;
+{
+       char *  buffer;         /* Where each bufferful of lines will start. */
+       void    read_a_source_file();
+       int saw_a_file = 0;
+
+       text_fix_root           = NULL;
+       data_fix_root           = NULL;
+       need_pass_2             = FALSE;
+
+       argv++;                 /* skip argv[0] */
+       argc--;                 /* skip argv[0] */
+       while (argc--) {
+               if (*argv) {            /* Is it a file-name argument? */
+                       /* argv -> "" if stdin desired, else -> filename */
+                       if (buffer = input_scrub_new_file (*argv) ) {
+                               saw_a_file++;
+                               read_a_source_file(buffer);
+                       }
+               }
+               argv++;                 /* completed that argv */
+       }
+       if(!saw_a_file)
+               if(buffer = input_scrub_new_file("") )
+                       read_a_source_file(buffer);
+}
+\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.
+ */
+
+char *
+stralloc (str)
+char * str;
+{
+       register char * retval;
+       register long int       len;
+
+       len = strlen (str) + 1;
+       retval = xmalloc (len);
+       (void)strcpy (retval, str);
+       return (retval);
+}
+\f
+lose()
+{
+       as_fatal( "%s: 2nd pass not implemented - get your code from random(3)",myname );
+}
+
+SIGTY
+got_sig(sig)
+int sig;
+{
+       static here_before = 0;
+
+       as_bad("Interrupted by signal %d",sig);
+       if(here_before++)
+               exit(1);
+}
+
+/* end: as.c */
diff --git a/gnu/usr.bin/as/as.h b/gnu/usr.bin/as/as.h
new file mode 100644 (file)
index 0000000..8de4052
--- /dev/null
@@ -0,0 +1,292 @@
+/* as.h - global header file
+   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 asH
+#define asH                    /* Don't declare things twice. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const /* ignore */
+#endif
+
+#ifdef USG
+#define index strchr
+#define bzero(s,n) memset((s),0,(n))
+#define bcopy(from,to,n) memcpy((to),(from),(n))
+#define setbuffer(a,b,c)
+#endif
+
+/*
+ * 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 SUSPECT when debugging.
+ * #define DUMP to include data-structure dumpers.
+ * #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 */
+/* #define DUMP */
+#define NDEBUG         /* JF disable asserts */
+/* These #includes are for type definitions etc. */
+
+/* #include "style.h" */
+#include <stdio.h>
+#include <assert.h>
+#define obstack_chunk_alloc    xmalloc
+#define obstack_chunk_free     xfree
+
+/* These defines are potentially useful */
+#define FALSE  (0)
+#define TRUE   (!FALSE)
+#define ASSERT assert
+#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 */
+
+#ifdef SUSPECT
+#define register               /* no registers: helps debugging */
+#define know(p) ASSERT(p)      /* know() is less ugly than #ifdef SUSPECT/ */
+                               /* assert()/#endif. */
+#else
+#define know(p)                        /* know() checks are no-op.ed */
+#endif                         /* #ifdef SUSPECT */
+
+
+char   *xmalloc();             /* keep C compilers happy */
+char   *xrealloc();            /* " */
+void   free();                 /* " */
+#define xfree free
+\f
+/* input_scrub.c */
+
+/*
+ * Supplies sanitised buffers to read.c.
+ * Also understands printing line-number part of error messages.
+ */
+
+                               /* Line number things. */
+int    seen_at_least_1_file();
+void   bump_line_counters();
+void   new_logical_line();
+void   as_where();
+void   as_perror();
+void   as_howmuch();
+                               /* Sanitising things. */
+void   input_scrub_begin();
+void   input_scrub_end();
+char   *input_scrub_new_file();
+char   *input_scrub_next_buffer();
+\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_NONE                                            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
+ *
+ * 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,
+       SEG_TEXT,
+       SEG_DATA,
+       SEG_BSS,
+       SEG_UNKNOWN,
+       SEG_NONE,               /* Mythical Segment: 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. */
+}              segT;
+#define SEG_MAXIMUM_ORDINAL (SEG_DIFFERENCE)
+
+typedef unsigned char  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 const int   seg_N_TYPE[];
+extern const segT  N_TYPE_seg[];
+void   subsegs_begin();
+void   subseg_change();
+void   subseg_new();
+\f
+/* 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 int relax_substateT;
+
+typedef unsigned long int 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 out.
+
+
+ */
+struct frag                    /* a code fragment */
+{
+       long unsigned int fr_address; /* Object file address. */
+       struct frag *fr_next;   /* Chain forward; ascending address order. */
+                               /* Rooted in frch_root. */
+
+       long int fr_fix;        /* (Fixed) number of chars we know we have. */
+                               /* May be 0. */
+       long int fr_var;        /* (Variable) number of chars after above. */
+                               /* May be 0. */
+       struct symbol *fr_symbol; /* For variable-length tail. */
+       long int 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. */
+
+void           frag_new();
+char *         frag_more();
+char *         frag_var();
+void           frag_wane();
+void           frag_align();
+\f
+
+/* 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. */
+
+
+#endif                         /* #ifdef asH */
+
+/* end: as.h */
diff --git a/gnu/usr.bin/as/atof-generic.c b/gnu/usr.bin/as/atof-generic.c
new file mode 100644 (file)
index 0000000..4975410
--- /dev/null
@@ -0,0 +1,526 @@
+/* atof_generic.c - turn a string of digits into a Flonum
+   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 <ctype.h>
+#include "flonum.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)
+#define index strchr
+#endif
+
+#define        FALSE (0)
+#define TRUE  (1)
+
+char *index();
+
+/***********************************************************************\
+*                                                                      *
+*      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 int              *
+*                                                                      *
+\***********************************************************************/
+
+/*
+
+                       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 int             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 = FALSE;
+    for (p = first_digit;
+        (c = * p)
+        && (!c || ! index (string_of_decimal_marks,          c) )
+        && (!c || ! index (string_of_decimal_exponent_marks, c) );
+        p ++)
+      {
+       if (isdigit(c))
+         {
+           if (seen_significant_digit || c > '0')
+             {
+               number_of_digits_before_decimal ++;
+               seen_significant_digit = TRUE;
+             }
+           else
+             {
+               first_digit++;
+             }
+         }
+       else
+         {
+           break;              /* p -> char after pre-decimal digits. */
+         }
+      }                                /* For each digit before decimal mark. */
+    if (c && index (string_of_decimal_marks, c))
+      {
+       for (p ++;
+            (c = * p)
+            && (!c || ! index (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 */
+    
+    if (c && index (string_of_decimal_exponent_marks, c) )
+      {
+       char            digits_exponent_sign_char;
+       
+       c = * ++ p;
+       if (c && index ("+-",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 int        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 int    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/gnu/usr.bin/as/bignum-copy.c b/gnu/usr.bin/as/bignum-copy.c
new file mode 100644 (file)
index 0000000..2640121
--- /dev/null
@@ -0,0 +1,75 @@
+/* bignum_copy.c - copy a bignum
+   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 "bignum.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/gnu/usr.bin/as/bignum.h b/gnu/usr.bin/as/bignum.h
new file mode 100644 (file)
index 0000000..dbc95a3
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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 int     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/gnu/usr.bin/as/config/Makefile.i386 b/gnu/usr.bin/as/config/Makefile.i386
new file mode 100644 (file)
index 0000000..945246b
--- /dev/null
@@ -0,0 +1,4 @@
+#      @(#)Makefile.i386       6.1 (Berkeley) 3/3/91
+
+CFLAGS+=       -DNON_BROKEN_WORDS
+SRCS+=         i386.c atof-ieee.c
diff --git a/gnu/usr.bin/as/config/a.out.gnu.h b/gnu/usr.bin/as/config/a.out.gnu.h
new file mode 100644 (file)
index 0000000..71b09a0
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+struct exec
+{
+  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
+  unsigned a_text;             /* length of text, in bytes */
+  unsigned a_data;             /* length of data, in bytes */
+  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;             /* length of symbol table data in file, in bytes */
+  unsigned a_entry;            /* start address */
+  unsigned a_trsize;           /* length of relocation info for text, in bytes */
+  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+};
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+enum machine_type {
+#if defined (M_OLDSUN2)
+  M__OLDSUN2 = M_OLDSUN2,
+#else
+  M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+  M__68010 = M_68010,
+#else
+  M_68010 = 1,
+#endif
+#if defined (M_68020)
+  M__68020 = M_68020,
+#else
+  M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+  M__SPARC = M_SPARC,
+#else
+  M_SPARC = 3,
+#endif
+  /* skip a bunch so we don't run into any of sun's numbers */
+  M_386 = 100,
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+       ((exec).a_info = ((magic) & 0xffff) \
+        | (((int)(type) & 0xff) << 16) \
+        | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+       ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+       ((exec).a_info = \
+        ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+       ((exec).a_info = \
+        ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+/* Code indicating object file or impure executable.  */
+#define OMAGIC 0407
+/* Code indicating pure executable.  */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable.  */
+#define ZMAGIC 0413
+
+#if !defined (N_BADMAG)
+#define N_BADMAG(x)                                    \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC         \
+  && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x)                                   \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC         \
+  && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded.  */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+   Note that it is up to you to define SEGMENT_SIZE
+   on machines not listed here.  */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE page_size
+#endif
+#ifdef sony
+#define        SEGMENT_SIZE    0x2000
+#endif /* Sony.  */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded.  */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+\f
+#if !defined (N_NLIST_DECLARED)
+struct nlist {
+  union {
+    char *n_name;
+    struct nlist *n_next;
+    long n_strx;
+  } n_un;
+  unsigned char n_type;
+  char n_other;
+  short n_desc;
+  unsigned long n_value;
+};
+#endif /* no N_NLIST_DECLARED.  */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+   an indirect reference to another symbol.  The other symbol
+   appears as an undefined reference, immediately following this symbol.
+
+   Indirection is asymmetrical.  The other symbol's value will be used
+   to satisfy requests for the indirect symbol, but not vice versa.
+   If the other symbol does not have a definition, libraries will
+   be searched to find a definition.  */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+   All the N_SET[ATDB] symbols with the same name form one set.
+   Space is allocated for the set in the text section, and each set
+   element's value is stored into one word of the space.
+   The first word of the space is the length of the set (number of elements).
+
+   The address of the set is made into an N_SETV symbol
+   whose name is the same as the name of the set.
+   This symbol acts like a N_DATA global symbol
+   in that it can satisfy undefined external references.  */
+
+/* These appear as input to LD, in a .o file.  */
+#define        N_SETA  0x14            /* Absolute set element symbol */
+#define        N_SETT  0x16            /* Text set element symbol */
+#define        N_SETD  0x18            /* Data set element symbol */
+#define        N_SETB  0x1A            /* Bss set element symbol */
+
+/* This is output from LD.  */
+#define N_SETV 0x1C            /* Pointer to set vector in data area.  */
+\f
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* This structure describes a single relocation to be performed.
+   The text-relocation section of the file is a vector of these structures,
+   all of which apply to the text section.
+   Likewise, the data-relocation section applies to the data section.  */
+
+struct relocation_info
+{
+  /* Address (within segment) to be relocated.  */
+  int r_address;
+  /* The meaning of r_symbolnum depends on r_extern.  */
+  unsigned int r_symbolnum:24;
+  /* Nonzero means value is a pc-relative offset
+     and it should be relocated for changes in its own address
+     as well as for changes in the symbol or section specified.  */
+  unsigned int r_pcrel:1;
+  /* Length (as exponent of 2) of the field to be relocated.
+     Thus, a value of 2 indicates 1<<2 bytes.  */
+  unsigned int r_length:2;
+  /* 1 => relocate with value of symbol.
+          r_symbolnum is the index of the symbol
+         in file's the symbol table.
+     0 => relocate with the address of a segment.
+          r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+         (the N_EXT bit may be set also, but signifies nothing).  */
+  unsigned int r_extern:1;
+  /* Four bits that aren't used, but when writing an object file
+     it is desirable to clear them.  */
+#ifdef NS32K
+  unsigned r_bsr:1;
+  unsigned r_disp:1;
+  unsigned r_pad:2;
+#else
+  unsigned int r_pad:4;
+#endif
+};
+#endif /* no N_RELOCATION_INFO_DECLARED.  */
+
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/gnu/usr.bin/as/config/atof-ieee.c b/gnu/usr.bin/as/config/atof-ieee.c
new file mode 100644 (file)
index 0000000..6ff45c8
--- /dev/null
@@ -0,0 +1,505 @@
+/* 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 "flonum.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. */
+#define NULL (0)
+
+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 int 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 int
+unget_bits(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_warn("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 int        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_warn("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 */
+gen_to_words(words,precision,exponent_bits)
+LITTLENUM_TYPE *words;
+long int       exponent_bits;
+int precision;
+{
+       int return_value=0;
+
+       long int        exponent_1;
+       long int        exponent_2;
+       long int        exponent_3;
+       long int        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 int 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 int       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_warn("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/gnu/usr.bin/as/config/i386-opcode.h b/gnu/usr.bin/as/config/i386-opcode.h
new file mode 100644 (file)
index 0000000..35c86c3
--- /dev/null
@@ -0,0 +1,806 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ *
+ *     @(#)i386-opcode.h       6.3 (Berkeley) 5/8/91
+ */
+
+/* i386-opcode.h -- Intel 80386 opcode table
+   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.  */
+   
+template i386_optab[] = {
+
+#define _ None
+/* move instructions */
+{ "mov", 2, 0xa0, _, DW|NoModrm, Disp32, Acc, 0 },
+{ "mov", 2, 0x88, _, DW|Modrm, Reg, Reg|Mem, 0 },
+{ "mov", 2, 0xb0, _, ShortFormW, Imm, Reg, 0 },
+{ "mov", 2, 0xc6, _,  W|Modrm,  Imm, Reg|Mem, 0 },
+{ "mov", 2, 0x8c, _, D|Modrm,  SReg3|SReg2, Reg16|Mem16, 0 },
+/* move to/from control debug registers */
+{ "mov", 2, 0x0f20, _, D|Modrm, Control, Reg32, 0},
+{ "mov", 2, 0x0f21, _, D|Modrm, Debug, Reg32, 0},
+{ "mov", 2, 0x0f24, _, D|Modrm, Test, Reg32, 0},
+
+/* move with sign extend */
+/* "movsbl" & "movsbw" must not be unified into "movsb" to avoid
+   conflict with the "movs" string move instruction.  Thus,
+   {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem,  Reg16|Reg32, 0},
+   is not kosher; we must seperate the two instructions. */
+{"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem,  Reg32, 0},
+{"movsbw", 2, 0x660fbe, _, ReverseRegRegmem|Modrm, Reg8|Mem,  Reg16, 0},
+{"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0},
+
+/* move with zero extend */
+{"movzb", 2, 0x0fb6, _, ReverseRegRegmem|Modrm, Reg8|Mem, Reg16|Reg32, 0},
+{"movzwl", 2, 0x0fb7, _, ReverseRegRegmem|Modrm, Reg16|Mem, Reg32, 0},
+
+/* push instructions */
+{"push", 1, 0x50, _, ShortForm, WordReg,0,0 },
+{"push", 1, 0xff, 0x6,  Modrm, WordReg|WordMem, 0, 0 },
+{"push", 1, 0x6a, _, NoModrm, Imm8S, 0, 0},
+{"push", 1, 0x68, _, NoModrm, Imm32, 0, 0},
+{"push", 1, 0x06, _,  Seg2ShortForm, SReg2,0,0 },
+{"push", 1, 0x0fa0, _, Seg3ShortForm, SReg3,0,0 },
+/* push all */
+{"pusha", 0, 0x60, _, NoModrm, 0, 0, 0 },
+
+/* pop instructions */
+{"pop", 1, 0x58, _, ShortForm, WordReg,0,0 },
+{"pop", 1, 0x8f, 0x0,  Modrm, WordReg|WordMem, 0, 0 },
+#define POP_SEG_SHORT 0x7
+{"pop", 1, 0x07, _,  Seg2ShortForm, SReg2,0,0 },
+{"pop", 1, 0x0fa1, _, Seg3ShortForm, SReg3,0,0 },
+/* pop all */
+{"popa", 0, 0x61, _, NoModrm, 0, 0, 0 },
+
+/* xchg exchange instructions
+   xchg commutes:  we allow both operand orders */
+{"xchg", 2, 0x90, _, ShortForm, WordReg, Acc, 0 },
+{"xchg", 2, 0x90, _, ShortForm, Acc, WordReg, 0 },
+{"xchg", 2, 0x86, _, W|Modrm, Reg, Reg|Mem, 0 },
+{"xchg", 2, 0x86, _, W|Modrm, Reg|Mem, Reg, 0 },
+
+/* in/out from ports */
+{"in", 2, 0xe4, _, W|NoModrm, Imm8, Acc, 0 },
+{"in", 2, 0xec, _, W|NoModrm, InOutPortReg, Acc, 0 },
+{"out", 2, 0xe6, _, W|NoModrm, Acc, Imm8, 0 },
+{"out", 2, 0xee, _, W|NoModrm, Acc, InOutPortReg, 0 },
+
+/* load effective address */
+{"lea", 2, 0x8d, _, Modrm, WordMem, WordReg, 0 },
+
+/* load segment registers from memory */
+{"lds", 2, 0xc5, _, Modrm, Mem, Reg32, 0},
+{"les", 2, 0xc4, _, Modrm, Mem, Reg32, 0},
+{"lfs", 2, 0x0fb4, _, Modrm, Mem, Reg32, 0},
+{"lgs", 2, 0x0fb5, _, Modrm, Mem, Reg32, 0},
+{"lss", 2, 0x0fb2, _, Modrm, Mem, Reg32, 0},
+
+/* flags register instructions */
+{"clc", 0, 0xf8, _, NoModrm, 0, 0, 0},
+{"cld", 0, 0xfc, _, NoModrm, 0, 0, 0},
+{"cli", 0, 0xfa, _, NoModrm, 0, 0, 0},
+{"clts", 0, 0x0f06, _, NoModrm, 0, 0, 0},
+{"cmc", 0, 0xf5, _, NoModrm, 0, 0, 0},
+{"lahf", 0, 0x9f, _, NoModrm, 0, 0, 0},
+{"sahf", 0, 0x9e, _, NoModrm, 0, 0, 0},
+{"pushf", 0, 0x9c, _, NoModrm, 0, 0, 0},
+{"popf", 0, 0x9d, _, NoModrm, 0, 0, 0},
+{"stc", 0, 0xf9, _, NoModrm, 0, 0, 0},
+{"std", 0, 0xfd, _, NoModrm, 0, 0, 0},
+{"sti", 0, 0xfb, _, NoModrm, 0, 0, 0},
+
+{"add", 2, 0x0,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"add", 2, 0x83, 0,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"add", 2, 0x4,  _,  W|NoModrm, Imm,  Acc,    0},
+{"add", 2, 0x80, 0, W|Modrm, Imm, Reg|Mem, 0},
+
+{"inc", 1, 0x40, _, ShortForm, WordReg, 0, 0},
+{"inc", 1, 0xfe, 0, W|Modrm, Reg|Mem, 0, 0},
+
+{"sub", 2, 0x28,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"sub", 2, 0x83, 5,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"sub", 2, 0x2c,  _,  W|NoModrm, Imm,  Acc,    0},
+{"sub", 2, 0x80, 5,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"dec", 1, 0x48, _, ShortForm, WordReg, 0, 0},
+{"dec", 1, 0xfe, 1, W|Modrm, Reg|Mem, 0, 0},
+
+{"sbb", 2, 0x18,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"sbb", 2, 0x83, 3,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"sbb", 2, 0x1c,  _,  W|NoModrm, Imm,  Acc,    0},
+{"sbb", 2, 0x80, 3,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"cmp", 2, 0x38,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"cmp", 2, 0x83, 7,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"cmp", 2, 0x3c,  _,  W|NoModrm, Imm,  Acc,    0},
+{"cmp", 2, 0x80, 7,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"test", 2, 0x84, _, W|Modrm, Reg|Mem, Reg, 0},
+{"test", 2, 0x84, _, W|Modrm, Reg, Reg|Mem, 0},
+{"test", 2, 0xa8, _, W|NoModrm, Imm, Acc, 0},
+{"test", 2, 0xf6, 0, W|Modrm, Imm, Reg|Mem, 0},
+
+{"and", 2, 0x20,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"and", 2, 0x83, 4,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"and", 2, 0x24,  _,  W|NoModrm, Imm,  Acc,    0},
+{"and", 2, 0x80, 4,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"or", 2, 0x08,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"or", 2, 0x83, 1,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"or", 2, 0x0c,  _,  W|NoModrm, Imm,  Acc,    0},
+{"or", 2, 0x80, 1,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"xor", 2, 0x30,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"xor", 2, 0x83, 6,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"xor", 2, 0x34,  _,  W|NoModrm, Imm,  Acc,    0},
+{"xor", 2, 0x80, 6,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"adc", 2, 0x10,  _, DW|Modrm, Reg, Reg|Mem, 0},
+{"adc", 2, 0x83, 2,  Modrm, Imm8S, WordReg|WordMem, 0},
+{"adc", 2, 0x14,  _,  W|NoModrm, Imm,  Acc,    0},
+{"adc", 2, 0x80, 2,  W|Modrm, Imm, Reg|Mem, 0},
+
+{"neg", 1, 0xf6, 3, W|Modrm, Reg|Mem, 0, 0},
+{"not", 1, 0xf6, 2, W|Modrm, Reg|Mem, 0, 0},
+
+{"aaa", 0, 0x37, _, NoModrm, 0, 0, 0},
+{"aas", 0, 0x3f, _, NoModrm, 0, 0, 0},
+{"daa", 0, 0x27, _, NoModrm, 0, 0, 0},
+{"das", 0, 0x2f, _, NoModrm, 0, 0, 0},
+{"aad", 0, 0xd50a, _, NoModrm, 0, 0, 0},
+{"aam", 0, 0xd40a, _, NoModrm, 0, 0, 0},
+
+/* conversion insns */
+/* conversion:  intel naming */
+{"cbw", 0, 0x6698, _, NoModrm, 0, 0, 0},
+{"cwd", 0, 0x6699, _, NoModrm, 0, 0, 0},
+{"cwde", 0, 0x98, _, NoModrm, 0, 0, 0},
+{"cdq", 0, 0x99, _, NoModrm, 0, 0, 0},
+/*  att naming */
+{"cbtw", 0, 0x6698, _, NoModrm, 0, 0, 0},
+{"cwtl", 0, 0x98, _, NoModrm, 0, 0, 0},
+{"cwtd", 0, 0x6699, _, NoModrm, 0, 0, 0},
+{"cltd", 0, 0x99, _, NoModrm, 0, 0, 0},
+
+/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand!  They are
+   expanding 64-bit multiplies, and *cannot* be selected to accomplish
+   'imul %ebx, %eax' (opcode 0x0faf must be used in this case)
+   These multiplies can only be selected with single opearnd forms. */
+{"mul",  1, 0xf6, 4, W|Modrm, Reg|Mem, 0, 0},
+{"imul", 1, 0xf6, 5, W|Modrm, Reg|Mem, 0, 0},
+
+
+
+
+/* imulKludge here is needed to reverse the i.rm.reg & i.rm.regmem fields.
+   These instructions are exceptions:  'imul $2, %eax, %ecx' would put
+   '%eax' in the reg field and '%ecx' in the regmem field if we did not
+   switch them. */
+{"imul", 2, 0x0faf, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"imul", 3, 0x6b, _, Modrm|ReverseRegRegmem, Imm8S, WordReg|Mem, WordReg},
+{"imul", 3, 0x69, _, Modrm|ReverseRegRegmem, Imm16|Imm32, WordReg|Mem, WordReg},
+/*
+  imul with 2 operands mimicks imul with 3 by puting register both
+  in i.rm.reg & i.rm.regmem fields
+*/
+{"imul", 2, 0x6b, _, Modrm|imulKludge, Imm8S, WordReg, 0},
+{"imul", 2, 0x69, _, Modrm|imulKludge, Imm16|Imm32, WordReg, 0},
+{"div", 1, 0xf6, 6, W|Modrm, Reg|Mem, 0, 0},
+{"div", 2, 0xf6, 6, W|Modrm, Reg|Mem, Acc, 0},
+{"idiv", 1, 0xf6, 7, W|Modrm, Reg|Mem, 0, 0},
+{"idiv", 2, 0xf6, 7, W|Modrm, Reg|Mem, Acc, 0},
+
+{"rol", 2, 0xd0, 0, W|Modrm, Imm1, Reg|Mem, 0},
+{"rol", 2, 0xc0, 0, W|Modrm, Imm8, Reg|Mem, 0},
+{"rol", 2, 0xd2, 0, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rol", 1, 0xd0, 0, W|Modrm, Reg|Mem, 0, 0},
+
+{"ror", 2, 0xd0, 1, W|Modrm, Imm1, Reg|Mem, 0},
+{"ror", 2, 0xc0, 1, W|Modrm, Imm8, Reg|Mem, 0},
+{"ror", 2, 0xd2, 1, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"ror", 1, 0xd0, 1, W|Modrm, Reg|Mem, 0, 0},
+
+{"rcl", 2, 0xd0, 2, W|Modrm, Imm1, Reg|Mem, 0},
+{"rcl", 2, 0xc0, 2, W|Modrm, Imm8, Reg|Mem, 0},
+{"rcl", 2, 0xd2, 2, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rcl", 1, 0xd0, 2, W|Modrm, Reg|Mem, 0, 0},
+
+{"rcr", 2, 0xd0, 3, W|Modrm, Imm1, Reg|Mem, 0},
+{"rcr", 2, 0xc0, 3, W|Modrm, Imm8, Reg|Mem, 0},
+{"rcr", 2, 0xd2, 3, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"rcr", 1, 0xd0, 3, W|Modrm, Reg|Mem, 0, 0},
+
+{"sal", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0},
+{"sal", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0},
+{"sal", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"sal", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0},
+{"shl", 2, 0xd0, 4, W|Modrm, Imm1, Reg|Mem, 0},
+{"shl", 2, 0xc0, 4, W|Modrm, Imm8, Reg|Mem, 0},
+{"shl", 2, 0xd2, 4, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"shl", 1, 0xd0, 4, W|Modrm, Reg|Mem, 0, 0},
+
+{"shld", 3, 0x0fa4, _, Modrm, Imm8, WordReg, WordReg|Mem},
+{"shld", 3, 0x0fa5, _, Modrm, ShiftCount, WordReg, WordReg|Mem},
+
+{"shr", 2, 0xd0, 5, W|Modrm, Imm1, Reg|Mem, 0},
+{"shr", 2, 0xc0, 5, W|Modrm, Imm8, Reg|Mem, 0},
+{"shr", 2, 0xd2, 5, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"shr", 1, 0xd0, 5, W|Modrm, Reg|Mem, 0, 0},
+
+{"shrd", 3, 0x0fac, _, Modrm, Imm8, WordReg, WordReg|Mem},
+{"shrd", 3, 0x0fad, _, Modrm, ShiftCount, WordReg, WordReg|Mem},
+
+{"sar", 2, 0xd0, 7, W|Modrm, Imm1, Reg|Mem, 0},
+{"sar", 2, 0xc0, 7, W|Modrm, Imm8, Reg|Mem, 0},
+{"sar", 2, 0xd2, 7, W|Modrm, ShiftCount, Reg|Mem, 0},
+{"sar", 1, 0xd0, 7, W|Modrm, Reg|Mem, 0, 0},
+
+/* control transfer instructions */
+#define CALL_PC_RELATIVE 0xe8
+{"call", 1, 0xe8, _, JumpDword, Disp32, 0, 0},
+{"call", 1, 0xff, 2, Modrm, Reg|Mem|JumpAbsolute, 0, 0},
+#define CALL_FAR_IMMEDIATE 0x9a
+{"lcall", 2, 0x9a, _, JumpInterSegment, Imm16, Imm32, 0},
+{"lcall", 1, 0xff, 3, Modrm, Mem, 0, 0},
+
+#define JUMP_PC_RELATIVE 0xeb
+{"jmp", 1, 0xeb, _, Jump, Disp, 0, 0},
+{"jmp", 1, 0xff, 4, Modrm, Reg32|Mem|JumpAbsolute, 0, 0},
+#define JUMP_FAR_IMMEDIATE 0xea
+{"ljmp", 2, 0xea, _, JumpInterSegment, Imm16, Imm32, 0},
+{"ljmp", 1, 0xff, 5, Modrm, Mem, 0, 0},
+
+{"ret", 0, 0xc3, _, NoModrm, 0, 0, 0},
+{"ret", 1, 0xc2, _, NoModrm, Imm16, 0, 0},
+{"lret", 0, 0xcb, _, NoModrm, 0, 0, 0},
+{"lret", 1, 0xca, _, NoModrm, Imm16, 0, 0},
+{"enter", 2, 0xc8, _, NoModrm, Imm16, Imm8, 0},
+{"leave", 0, 0xc9, _, NoModrm, 0, 0, 0},
+
+/* conditional jumps */
+{"jo", 1, 0x70, _, Jump, Disp, 0, 0},
+
+{"jno", 1, 0x71, _, Jump, Disp, 0, 0},
+
+{"jb", 1, 0x72, _, Jump, Disp, 0, 0},
+{"jc", 1, 0x72, _, Jump, Disp, 0, 0},
+{"jnae", 1, 0x72, _, Jump, Disp, 0, 0},
+
+{"jnb", 1, 0x73, _, Jump, Disp, 0, 0},
+{"jnc", 1, 0x73, _, Jump, Disp, 0, 0},
+{"jae", 1, 0x73, _, Jump, Disp, 0, 0},
+
+{"je", 1, 0x74, _, Jump, Disp, 0, 0},
+{"jz", 1, 0x74, _, Jump, Disp, 0, 0},
+
+{"jne", 1, 0x75, _, Jump, Disp, 0, 0},
+{"jnz", 1, 0x75, _, Jump, Disp, 0, 0},
+
+{"jbe", 1, 0x76, _, Jump, Disp, 0, 0},
+{"jna", 1, 0x76, _, Jump, Disp, 0, 0},
+
+{"jnbe", 1, 0x77, _, Jump, Disp, 0, 0},
+{"ja", 1, 0x77, _, Jump, Disp, 0, 0},
+
+{"js", 1, 0x78, _, Jump, Disp, 0, 0},
+
+{"jns", 1, 0x79, _, Jump, Disp, 0, 0},
+
+{"jp", 1, 0x7a, _, Jump, Disp, 0, 0},
+{"jpe", 1, 0x7a, _, Jump, Disp, 0, 0},
+
+{"jnp", 1, 0x7b, _, Jump, Disp, 0, 0},
+{"jpo", 1, 0x7b, _, Jump, Disp, 0, 0},
+
+{"jl", 1, 0x7c, _, Jump, Disp, 0, 0},
+{"jnge", 1, 0x7c, _, Jump, Disp, 0, 0},
+
+{"jnl", 1, 0x7d, _, Jump, Disp, 0, 0},
+{"jge", 1, 0x7d, _, Jump, Disp, 0, 0},
+
+{"jle", 1, 0x7e, _, Jump, Disp, 0, 0},
+{"jng", 1, 0x7e, _, Jump, Disp, 0, 0},
+
+{"jnle", 1, 0x7f, _, Jump, Disp, 0, 0},
+{"jg", 1, 0x7f, _, Jump, Disp, 0, 0},
+
+/* these turn into pseudo operations when disp is larger than 8 bits */
+#define IS_JUMP_ON_CX_ZERO(o) \
+  (o == 0x67e3)
+#define IS_JUMP_ON_ECX_ZERO(o) \
+  (o == 0xe3)
+
+{"jcxz", 1, 0x67e3, _, JumpByte, Disp, 0, 0},
+{"jecxz", 1, 0xe3, _, JumpByte, Disp, 0, 0},
+
+#define IS_LOOP_ECX_TIMES(o) \
+  (o == 0xe2 || o == 0xe1 || o == 0xe0)
+
+{"loop", 1, 0xe2, _, JumpByte, Disp, 0, 0},
+
+{"loopz", 1, 0xe1, _, JumpByte, Disp, 0, 0},
+{"loope", 1, 0xe1, _, JumpByte, Disp, 0, 0},
+
+{"loopnz", 1, 0xe0, _, JumpByte, Disp, 0, 0},
+{"loopne", 1, 0xe0, _, JumpByte, Disp, 0, 0},
+
+/* set byte on flag instructions */
+{"seto", 1, 0x0f90, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setno", 1, 0x0f91, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setb", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnae", 1, 0x0f92, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnb", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0},
+{"setae", 1, 0x0f93, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"sete", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0},
+{"setz", 1, 0x0f94, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setne", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnz", 1, 0x0f95, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setbe", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0},
+{"setna", 1, 0x0f96, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnbe", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0},
+{"seta", 1, 0x0f97, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"sets", 1, 0x0f98, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setns", 1, 0x0f99, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setp", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0},
+{"setpe", 1, 0x0f9a, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnp", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0},
+{"setpo", 1, 0x0f9b, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setl", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0},
+{"setnge", 1, 0x0f9c, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnl", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0},
+{"setge", 1, 0x0f9d, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setle", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0},
+{"setng", 1, 0x0f9e, 0, Modrm, Reg8|Mem, 0, 0},
+
+{"setnle", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0},
+{"setg", 1, 0x0f9f, 0, Modrm, Reg8|Mem, 0, 0},
+
+#define IS_STRING_INSTRUCTION(o) \
+  ((o) == 0xa6 || (o) == 0x6c || (o) == 0x6e || (o) == 0x6e || \
+   (o) == 0xac || (o) == 0xa4 || (o) == 0xae || (o) == 0xaa || \
+   (o) == 0xd7)
+
+/* string manipulation */
+{"cmps", 0, 0xa6, _, W|NoModrm, 0, 0, 0},
+{"ins", 0, 0x6c, _, W|NoModrm, 0, 0, 0},
+{"outs", 0, 0x6e, _, W|NoModrm, 0, 0, 0},
+{"lods", 0, 0xac, _, W|NoModrm, 0, 0, 0},
+{"movs", 0, 0xa4, _, W|NoModrm, 0, 0, 0},
+{"scas", 0, 0xae, _, W|NoModrm, 0, 0, 0},
+{"stos", 0, 0xaa, _, W|NoModrm, 0, 0, 0},
+{"xlat", 0, 0xd7, _, NoModrm, 0, 0, 0},
+
+/* bit manipulation */
+{"bsf", 2, 0x0fbc, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0},
+{"bsr", 2, 0x0fbd, _, Modrm|ReverseRegRegmem, Reg|Mem, Reg, 0},
+{"bt", 2, 0x0fa3, _, Modrm, Reg, Reg|Mem, 0},
+{"bt", 2, 0x0fba, 4, Modrm, Imm8, Reg|Mem, 0},
+{"btc", 2, 0x0fbb, _, Modrm, Reg, Reg|Mem, 0},
+{"btc", 2, 0x0fba, 7, Modrm, Imm8, Reg|Mem, 0},
+{"btr", 2, 0x0fb3, _, Modrm, Reg, Reg|Mem, 0},
+{"btr", 2, 0x0fba, 6, Modrm, Imm8, Reg|Mem, 0},
+{"bts", 2, 0x0fab, _, Modrm, Reg, Reg|Mem, 0},
+{"bts", 2, 0x0fba, 5, Modrm, Imm8, Reg|Mem, 0},
+
+/* interrupts & op. sys insns */
+/* See i386.c for conversion of 'int $3' into the special int 3 insn. */
+#define INT_OPCODE 0xcd
+#define INT3_OPCODE 0xcc
+{"int", 1, 0xcd, _, NoModrm, Imm8, 0, 0},
+{"int3", 0, 0xcc, _, NoModrm, 0, 0, 0},
+{"into", 0, 0xce, _, NoModrm, 0, 0, 0},
+{"iret", 0, 0xcf, _, NoModrm, 0, 0, 0},
+
+{"boundl", 2, 0x62, _, Modrm, Reg32, Mem, 0},
+{"boundw", 2, 0x6662, _, Modrm, Reg16, Mem, 0},
+
+{"hlt", 0, 0xf4, _, NoModrm, 0, 0, 0},
+{"wait", 0, 0x9b, _, NoModrm, 0, 0, 0},
+/* nop is actually 'xchgl %eax, %eax' */
+{"nop", 0, 0x90, _, NoModrm, 0, 0, 0},
+
+/* protection control */
+{"arpl", 2, 0x63, _, Modrm, Reg16, Reg16|Mem, 0},
+{"lar", 2, 0x0f02, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"lgdt", 1, 0x0f01, 2, Modrm, Mem, 0, 0},
+{"lidt", 1, 0x0f01, 3, Modrm, Mem, 0, 0},
+{"lldt", 1, 0x0f00, 2, Modrm, WordReg|Mem, 0, 0},
+{"lmsw", 1, 0x0f01, 6, Modrm, WordReg|Mem, 0, 0},
+{"lsl", 2, 0x0f03, _, Modrm|ReverseRegRegmem, WordReg|Mem, WordReg, 0},
+{"ltr", 1, 0x0f00, 3, Modrm, WordReg|Mem, 0, 0},
+
+{"sgdt", 1, 0x0f01, 0, Modrm, Mem, 0, 0},
+{"sidt", 1, 0x0f01, 1, Modrm, Mem, 0, 0},
+{"sldt", 1, 0x0f00, 0, Modrm, WordReg|Mem, 0, 0},
+{"smsw", 1, 0x0f01, 4, Modrm, WordReg|Mem, 0, 0},
+{"str", 1, 0x0f00, 1, Modrm, Reg16|Mem, 0, 0},
+
+{"verr", 1, 0x0f00, 4, Modrm, WordReg|Mem, 0, 0},
+{"verw", 1, 0x0f00, 5, Modrm, WordReg|Mem, 0, 0},
+
+/* floating point instructions */
+
+/* load */
+{"fld", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"flds", 1, 0xd9, 0, Modrm, Mem, 0, 0},           /* %st0 <-- mem float */
+{"fildl", 1, 0xdb, 0, Modrm, Mem, 0, 0},           /* %st0 <-- mem word */
+{"fldl", 1, 0xdd, 0, Modrm, Mem, 0, 0},           /* %st0 <-- mem double */
+{"fldl", 1, 0xd9c0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"filds", 1, 0xdf, 0, Modrm, Mem, 0, 0},           /* %st0 <-- mem dword */
+{"fildq", 1, 0xdf, 5, Modrm, Mem, 0, 0},           /* %st0 <-- mem qword */
+{"fldt", 1, 0xdb, 5, Modrm, Mem, 0, 0},           /* %st0 <-- mem efloat */
+{"fbld", 1, 0xdf, 4, Modrm, Mem, 0, 0},           /* %st0 <-- mem bcd */
+
+/* store (no pop) */
+{"fst", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fsts", 1, 0xd9, 2, Modrm, Mem, 0, 0},           /* %st0 --> mem float */
+{"fistl", 1, 0xdb, 2, Modrm, Mem, 0, 0},           /* %st0 --> mem dword */
+{"fstl", 1, 0xdd, 2, Modrm, Mem, 0, 0},           /* %st0 --> mem double */
+{"fstl", 1, 0xddd0, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fists", 1, 0xdf, 2, Modrm, Mem, 0, 0},           /* %st0 --> mem word */
+
+/* store (with pop) */
+{"fstp", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fstps", 1, 0xd9, 3, Modrm, Mem, 0, 0},           /* %st0 --> mem float */
+{"fistpl", 1, 0xdb, 3, Modrm, Mem, 0, 0},           /* %st0 --> mem word */
+{"fstpl", 1, 0xdd, 3, Modrm, Mem, 0, 0},           /* %st0 --> mem double */
+{"fstpl", 1, 0xddd8, _, ShortForm, FloatReg, 0, 0}, /* register */
+{"fistps", 1, 0xdf, 3, Modrm, Mem, 0, 0},           /* %st0 --> mem dword */
+{"fistpq", 1, 0xdf, 7, Modrm, Mem, 0, 0},           /* %st0 --> mem qword */
+{"fstpt", 1, 0xdb, 7, Modrm, Mem, 0, 0},           /* %st0 --> mem efloat */
+{"fbstp", 1, 0xdf, 6, Modrm, Mem, 0, 0},           /* %st0 --> mem bcd */
+
+/* exchange %st<n> with %st0 */
+{"fxch", 1, 0xd9c8, _, ShortForm, FloatReg, 0, 0},
+
+/* comparison (without pop) */
+{"fcom", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0},
+{"fcoms", 1, 0xd8, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem float  */
+{"ficoml", 1, 0xda, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem word  */ 
+{"fcoml", 1, 0xdc, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem double  */
+{"fcoml", 1, 0xd8d0, _, ShortForm, FloatReg, 0, 0},
+{"ficoms", 1, 0xde, 2, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */
+
+/* comparison (with pop) */
+{"fcomp", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0},
+{"fcomps", 1, 0xd8, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem float  */
+{"ficompl", 1, 0xda, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem word  */ 
+{"fcompl", 1, 0xdc, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem double  */
+{"fcompl", 1, 0xd8d8, _, ShortForm, FloatReg, 0, 0},
+{"ficomps", 1, 0xde, 3, Modrm, Mem, 0, 0}, /* compare %st0, mem dword */
+{"fcompp", 0, 0xded9, _, NoModrm, 0, 0, 0}, /* compare %st0, %st1 & pop twice */
+
+/* unordered comparison (with pop) */
+{"fucom", 1, 0xdde0, _, ShortForm, FloatReg, 0, 0},
+{"fucomp", 1, 0xdde8, _, ShortForm, FloatReg, 0, 0},
+{"fucompp", 0, 0xdae9, _, NoModrm, 0, 0, 0}, /* ucompare %st0, %st1 & pop twice */
+
+{"ftst", 0, 0xd9e4, _, NoModrm, 0, 0, 0},   /* test %st0 */
+{"fxam", 0, 0xd9e5, _, NoModrm, 0, 0, 0},   /* examine %st0 */
+
+/* load constants into %st0 */
+{"fld1", 0, 0xd9e8, _, NoModrm, 0, 0, 0},   /* %st0 <-- 1.0 */
+{"fldl2t", 0, 0xd9e9, _, NoModrm, 0, 0, 0},   /* %st0 <-- log2(10) */
+{"fldl2e", 0, 0xd9ea, _, NoModrm, 0, 0, 0},   /* %st0 <-- log2(e) */
+{"fldpi", 0, 0xd9eb, _, NoModrm, 0, 0, 0},   /* %st0 <-- pi */
+{"fldlg2", 0, 0xd9ec, _, NoModrm, 0, 0, 0},   /* %st0 <-- log10(2) */
+{"fldln2", 0, 0xd9ed, _, NoModrm, 0, 0, 0},   /* %st0 <-- ln(2) */
+{"fldz", 0, 0xd9ee, _, NoModrm, 0, 0, 0},   /* %st0 <-- 0.0 */
+
+/* arithmetic */
+
+/* add */
+{"fadd", 1, 0xd8c0, _, ShortForm, FloatReg, 0, 0},
+{"fadd", 2, 0xd8c0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fadd", 0, 0xdcc1, _, NoModrm, 0, 0, 0}, /* alias for fadd %st, %st(1) */
+{"faddp", 1, 0xdac0, _, ShortForm, FloatReg, 0, 0},
+{"faddp", 2, 0xdac0, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"faddp", 0, 0xdec1, _, NoModrm, 0, 0, 0}, /* alias for faddp %st, %st(1) */
+{"fadds", 1, 0xd8, 0, Modrm, Mem, 0, 0},
+{"fiaddl", 1, 0xda, 0, Modrm, Mem, 0, 0},
+{"faddl", 1, 0xdc, 0, Modrm, Mem, 0, 0},
+{"fiadds", 1, 0xde, 0, Modrm, Mem, 0, 0},
+
+/* sub */
+/* Note:  intel has decided that certain of these operations are reversed
+   in assembler syntax. */
+{"fsub", 1, 0xd8e0, _, ShortForm, FloatReg, 0, 0},
+{"fsub", 2, 0xd8e0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsub", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsub", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsub", 0, 0xdce1, _, NoModrm, 0, 0, 0},
+{"fsubp", 1, 0xdae0, _, ShortForm, FloatReg, 0, 0},
+{"fsubp", 2, 0xdae0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubp", 0, 0xdee1, _, NoModrm, 0, 0, 0},
+{"fsubs", 1, 0xd8, 4, Modrm, Mem, 0, 0},
+{"fisubl", 1, 0xda, 4, Modrm, Mem, 0, 0},
+{"fsubl", 1, 0xdc, 4, Modrm, Mem, 0, 0},
+{"fisubs", 1, 0xde, 4, Modrm, Mem, 0, 0},
+
+/* sub reverse */
+{"fsubr", 1, 0xd8e8, _, ShortForm, FloatReg, 0, 0},
+{"fsubr", 2, 0xd8e8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubr", 2, 0xdce0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubr", 2, 0xdce8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubr", 0, 0xdce9, _, NoModrm, 0, 0, 0},
+{"fsubrp", 1, 0xdae8, _, ShortForm, FloatReg, 0, 0},
+{"fsubrp", 2, 0xdae8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fsubrp", 2, 0xdee0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fsubrp", 2, 0xdee8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fsubrp", 0, 0xdee9, _, NoModrm, 0, 0, 0},
+{"fsubrs", 1, 0xd8, 5, Modrm, Mem, 0, 0},
+{"fisubrl", 1, 0xda, 5, Modrm, Mem, 0, 0},
+{"fsubrl", 1, 0xdc, 5, Modrm, Mem, 0, 0},
+{"fisubrs", 1, 0xde, 5, Modrm, Mem, 0, 0},
+
+/* mul */
+{"fmul", 1, 0xd8c8, _, ShortForm, FloatReg, 0, 0},
+{"fmul", 2, 0xd8c8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fmul", 0, 0xdcc9, _, NoModrm, 0, 0, 0},
+{"fmulp", 1, 0xdac8, _, ShortForm, FloatReg, 0, 0},
+{"fmulp", 2, 0xdac8, _, ShortForm|FloatD, FloatReg, FloatAcc, 0},
+{"fmulp", 0, 0xdec9, _, NoModrm, 0, 0, 0},
+{"fmuls", 1, 0xd8, 1, Modrm, Mem, 0, 0},
+{"fimull", 1, 0xda, 1, Modrm, Mem, 0, 0},
+{"fmull", 1, 0xdc, 1, Modrm, Mem, 0, 0},
+{"fimuls", 1, 0xde, 1, Modrm, Mem, 0, 0},
+
+/* div */
+/* Note:  intel has decided that certain of these operations are reversed
+   in assembler syntax. */
+{"fdiv", 1, 0xd8f0, _, ShortForm, FloatReg, 0, 0},
+{"fdiv", 2, 0xd8f0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdiv", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdiv", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdiv", 0, 0xdcf1, _, NoModrm, 0, 0, 0},
+{"fdivp", 1, 0xdaf0, _, ShortForm, FloatReg, 0, 0},
+{"fdivp", 2, 0xdaf0, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivp", 0, 0xdef1, _, NoModrm, 0, 0, 0},
+{"fdivs", 1, 0xd8, 6, Modrm, Mem, 0, 0},
+{"fidivl", 1, 0xda, 6, Modrm, Mem, 0, 0},
+{"fdivl", 1, 0xdc, 6, Modrm, Mem, 0, 0},
+{"fidivs", 1, 0xde, 6, Modrm, Mem, 0, 0},
+
+/* div reverse */
+{"fdivr", 1, 0xd8f8, _, ShortForm, FloatReg, 0, 0},
+{"fdivr", 2, 0xd8f8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivr", 2, 0xdcf0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivr", 2, 0xdcf8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivr", 0, 0xdcf9, _, NoModrm, 0, 0, 0},
+{"fdivrp", 1, 0xdaf8, _, ShortForm, FloatReg, 0, 0},
+{"fdivrp", 2, 0xdaf8, _, ShortForm, FloatReg, FloatAcc, 0},
+#ifdef NON_BROKEN_OPCODES
+{"fdivrp", 2, 0xdef0, _, ShortForm, FloatAcc, FloatReg, 0},
+#else
+{"fdivrp", 2, 0xdef8, _, ShortForm, FloatAcc, FloatReg, 0},
+#endif
+{"fdivrp", 0, 0xdef9, _, NoModrm, 0, 0, 0},
+{"fdivrs", 1, 0xd8, 7, Modrm, Mem, 0, 0},
+{"fidivrl", 1, 0xda, 7, Modrm, Mem, 0, 0},
+{"fdivrl", 1, 0xdc, 7, Modrm, Mem, 0, 0},
+{"fidivrs", 1, 0xde, 7, Modrm, Mem, 0, 0},
+
+{"f2xm1", 0,   0xd9f0, _, NoModrm, 0, 0, 0},
+{"fyl2x", 0,   0xd9f1, _, NoModrm, 0, 0, 0},
+{"fptan", 0,   0xd9f2, _, NoModrm, 0, 0, 0},
+{"fpatan", 0,  0xd9f3, _, NoModrm, 0, 0, 0},
+{"fxtract", 0, 0xd9f4, _, NoModrm, 0, 0, 0},
+{"fprem1", 0,  0xd9f5, _, NoModrm, 0, 0, 0},
+{"fdecstp", 0,  0xd9f6, _, NoModrm, 0, 0, 0},
+{"fincstp", 0,  0xd9f7, _, NoModrm, 0, 0, 0},
+{"fprem", 0,   0xd9f8, _, NoModrm, 0, 0, 0},
+{"fyl2xp1", 0, 0xd9f9, _, NoModrm, 0, 0, 0},
+{"fsqrt", 0,   0xd9fa, _, NoModrm, 0, 0, 0},
+{"fsincos", 0, 0xd9fb, _, NoModrm, 0, 0, 0},
+{"frndint", 0, 0xd9fc, _, NoModrm, 0, 0, 0},
+{"fscale", 0,  0xd9fd, _, NoModrm, 0, 0, 0},
+{"fsin", 0,    0xd9fe, _, NoModrm, 0, 0, 0},
+{"fcos", 0,    0xd9ff, _, NoModrm, 0, 0, 0},
+
+{"fchs", 0, 0xd9e0, _, NoModrm, 0, 0, 0},
+{"fabs", 0, 0xd9e1, _, NoModrm, 0, 0, 0},
+
+/* processor control */
+{"fninit", 0, 0xdbe3, _, NoModrm, 0, 0, 0},
+{"finit", 0, 0xdbe3, _, NoModrm, 0, 0, 0},
+{"fldcw", 1, 0xd9, 5, Modrm, Mem, 0, 0},
+{"fnstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0},
+{"fstcw", 1, 0xd9, 7, Modrm, Mem, 0, 0},
+{"fnstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0},
+{"fnstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0},
+{"fnstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0},
+{"fstsw", 1, 0xdfe0, _, NoModrm, Acc, 0, 0},
+{"fstsw", 1, 0xdd, 7, Modrm, Mem, 0, 0},
+{"fstsw", 0, 0xdfe0, _, NoModrm, 0, 0, 0},
+{"fnclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0},
+{"fclex", 0, 0xdbe2, _, NoModrm, 0, 0, 0},
+/*
+ We ignore the short format (287) versions of fstenv/fldenv & fsave/frstor
+ instructions;  i'm not sure how to add them or how they are different.
+ My 386/387 book offers no details about this.
+*/
+{"fnstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0},
+{"fstenv", 1, 0xd9, 6, Modrm, Mem, 0, 0},
+{"fldenv", 1, 0xd9, 4, Modrm, Mem, 0, 0},
+{"fnsave", 1, 0xdd, 6, Modrm, Mem, 0, 0},
+{"fsave", 1, 0xdd, 6, Modrm, Mem, 0, 0},
+{"frstor", 1, 0xdd, 4, Modrm, Mem, 0, 0},
+
+{"ffree", 1, 0xddc0, _, ShortForm, FloatReg, 0, 0},
+{"fnop", 0, 0xd9d0, _, NoModrm, 0, 0, 0},
+{"fwait", 0, 0x9b, _, NoModrm, 0, 0, 0},
+
+/*
+  opcode prefixes; we allow them as seperate insns too
+  (see prefix table below)
+*/
+{"aword", 0, 0x67, _, NoModrm, 0, 0, 0},
+{"word", 0, 0x66, _, NoModrm, 0, 0, 0},
+{"lock", 0, 0xf0, _, NoModrm, 0, 0, 0},
+{"cs", 0, 0x2e, _, NoModrm, 0, 0, 0},
+{"ds", 0, 0x3e, _, NoModrm, 0, 0, 0},
+{"es", 0, 0x26, _, NoModrm, 0, 0, 0},
+{"fs", 0, 0x64, _, NoModrm, 0, 0, 0},
+{"gs", 0, 0x65, _, NoModrm, 0, 0, 0},
+{"ss", 0, 0x36, _, NoModrm, 0, 0, 0},
+{"rep", 0, 0xf3, _, NoModrm, 0, 0, 0},
+{"repe", 0, 0xf3, _, NoModrm, 0, 0, 0},
+{ "repne", 0, 0xf2, _, NoModrm, 0, 0, 0},
+
+{"", 0, 0, 0, 0, 0, 0, 0}      /* sentinal */
+};
+#undef _
+
+template *i386_optab_end 
+  = i386_optab + sizeof (i386_optab)/sizeof(i386_optab[0]);
+
+/* 386 register table */
+
+reg_entry i386_regtab[] = {
+  /* 8 bit regs */
+  {"al", Reg8|Acc, 0}, {"cl", Reg8|ShiftCount, 1}, {"dl", Reg8, 2},
+  {"bl", Reg8, 3},
+  {"ah", Reg8, 4}, {"ch", Reg8, 5}, {"dh", Reg8, 6}, {"bh", Reg8, 7},
+  /* 16 bit regs */
+  {"ax", Reg16|Acc, 0}, {"cx", Reg16, 1}, {"dx", Reg16|InOutPortReg, 2}, {"bx", Reg16, 3},
+  {"sp", Reg16, 4}, {"bp", Reg16, 5}, {"si", Reg16, 6}, {"di", Reg16, 7},
+  /* 32 bit regs */
+  {"eax", Reg32|Acc, 0}, {"ecx", Reg32, 1}, {"edx", Reg32, 2}, {"ebx", Reg32, 3},
+  {"esp", Reg32, 4}, {"ebp", Reg32, 5}, {"esi", Reg32, 6}, {"edi", Reg32, 7},
+  /* segment registers */
+  {"es", SReg2, 0}, {"cs", SReg2, 1}, {"ss", SReg2, 2},
+  {"ds", SReg2, 3}, {"fs", SReg3, 4}, {"gs", SReg3, 5},
+  /* control registers */
+  {"cr0", Control, 0},   {"cr2", Control, 2},   {"cr3", Control, 3},
+  /* debug registers */
+  {"db0", Debug, 0},   {"db1", Debug, 1},   {"db2", Debug, 2},
+  {"db3", Debug, 3},   {"db6", Debug, 6},   {"db7", Debug, 7},
+  /* test registers */
+  {"tr6", Test, 6}, {"tr7", Test, 7},
+  /* float registers */
+  {"st(0)", FloatReg|FloatAcc, 0},
+  {"st", FloatReg|FloatAcc, 0},
+  {"st(1)", FloatReg, 1}, {"st(2)", FloatReg, 2}, 
+  {"st(3)", FloatReg, 3}, {"st(4)", FloatReg, 4}, {"st(5)", FloatReg, 5}, 
+  {"st(6)", FloatReg, 6}, {"st(7)", FloatReg, 7}
+};
+
+#define MAX_REG_NAME_SIZE 8    /* for parsing register names from input */
+
+reg_entry *i386_regtab_end
+  = i386_regtab + sizeof(i386_regtab)/sizeof(i386_regtab[0]);
+
+/* segment stuff */
+seg_entry cs = { "cs", 0x2e };
+seg_entry ds = { "ds", 0x3e };
+seg_entry ss = { "ss", 0x36 };
+seg_entry es = { "es", 0x26 };
+seg_entry fs = { "fs", 0x64 };
+seg_entry gs = { "gs", 0x65 };
+seg_entry null = { "", 0x0 };
+
+/*
+  This table is used to store the default segment register implied by all
+  possible memory addressing modes.
+  It is indexed by the mode & modrm entries of the modrm byte as follows:
+      index = (mode<<3) | modrm;
+*/
+seg_entry *one_byte_segment_defaults[] = {
+  /* mode 0 */
+  &ds, &ds, &ds, &ds, &null, &ds, &ds, &ds,
+  /* mode 1 */
+  &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds,
+  /* mode 2 */
+  &ds, &ds, &ds, &ds, &null, &ss, &ds, &ds,
+  /* mode 3 --- not a memory reference; never referenced */
+};
+
+seg_entry *two_byte_segment_defaults[] = {
+  /* mode 0 */
+  &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+  /* mode 1 */
+  &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+  /* mode 2 */
+  &ds, &ds, &ds, &ds, &ss, &ds, &ds, &ds,
+  /* mode 3 --- not a memory reference; never referenced */
+};
+
+prefix_entry i386_prefixtab[] = {
+  { "addr16", 0x67 },          /* address size prefix ==> 16bit addressing
+                                * (How is this useful?) */
+#define WORD_PREFIX_OPCODE 0x66
+  { "data16", 0x66 },          /* operand size prefix */
+  { "lock", 0xf0 },            /* bus lock prefix */
+  { "wait", 0x9b },            /* wait for coprocessor */
+  { "cs", 0x2e }, { "ds", 0x3e }, /* segment overrides ... */
+  { "es", 0x26 }, { "fs", 0x64 },
+  { "gs", 0x65 }, { "ss", 0x36 },
+/* REPE & REPNE used to detect rep/repne with a non-string instruction */
+#define REPNE 0xf2
+#define REPE  0xf3
+  { "rep", 0xf3 }, { "repe", 0xf3 }, /* repeat string instructions */
+  { "repne", 0xf2 }
+};
+
+prefix_entry *i386_prefixtab_end
+  = i386_prefixtab + sizeof(i386_prefixtab)/sizeof(i386_prefixtab[0]);
+
diff --git a/gnu/usr.bin/as/config/i386.c b/gnu/usr.bin/as/config/i386.c
new file mode 100644 (file)
index 0000000..2281acd
--- /dev/null
@@ -0,0 +1,1946 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)i386.c     6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* i386.c -- Assemble code for the Intel 80386
+   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.  */
+   
+/*
+  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 <stdio.h>
+#include <varargs.h>
+#include <ctype.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+extern char *alloca();
+#endif
+#ifdef USG
+#define index strchr
+#endif
+
+#include "as.h"
+#include "read.h"
+#include "flonum.h"
+#include "obstack.h"
+#include "frags.h"
+#include "struc-symbol.h"
+#include "expr.h"
+#include "symbols.h"
+#include "hash.h"
+#include "md.h"
+#include "i386.h"
+#include "i386-opcode.h"
+
+long omagic = OMAGIC;
+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},
+
+};
+
+void float_cons (), cons ();
+
+/* 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 */
+       { "def",        dummy,          0   },
+       { "optim",      dummy,          0   }, /* For sun386i cc */
+       { "version",    dummy,          0   },
+       { "ln",    dummy,          0   },
+       { 0, 0, 0 }
+};
+
+/* for interface with expression () */
+extern char * input_line_pointer;
+char * index ();
+
+char * output_invalid ();
+reg_entry * parse_register ();
+
+/* 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 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 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 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 && index(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");
+  }
+}
+
+char *seg_names[] = {
+"SEG_ABSOLUTE", "SEG_TEXT", "SEG_DATA", "SEG_BSS", "SEG_UNKNOWN",
+"SEG_NONE", "SEG_PASS1", "SEG_GOOF", "SEG_BIG", "SEG_DIFFERENCE" };
+
+static void pe (e)
+     expressionS *e;
+{
+  fprintf (stdout, "    segment       %s\n", seg_names[(int) 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");
+  }
+}
+
+#define SYMBOL_TYPE(t) \
+  (((t&N_TYPE) == N_UNDF) ? "UNDEFINED" : \
+   (((t&N_TYPE) == N_ABS) ? "ABSOLUTE" : \
+    (((t&N_TYPE) == N_TEXT) ? "TEXT" : \
+     (((t&N_TYPE) == N_DATA) ? "DATA" : \
+      (((t&N_TYPE) == N_BSS) ? "BSS" : "Bad n_type!")))))
+
+static void ps (s)
+     symbolS *s;
+{
+  fprintf (stdout, "%s type %s%s",
+          s->sy_nlist.n_un.n_name,
+          (s->sy_nlist.n_type&N_EXT) ? "EXTERNAL " : "",
+          SYMBOL_TYPE (s->sy_nlist.n_type));
+}
+
+struct type_name {
+  uint 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)
+     uint 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. */
+
+    /* TRUE if operand is pending after ','. */
+    uint expecting_operand = 0;
+    /* TRUE if we found a prefix only acceptable with string insns. */
+    uint expecting_string_instruction = 0;
+    /* Non-zero if operand parens not balenced. */
+    uint 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 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 = TRUE;
+       /* 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 */
+         uint 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 = TRUE;
+       }
+      } 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 uint overlap0, overlap1;
+    expressionS * exp;
+    uint overlap2;
+    uint 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) {
+      uint 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) {
+       uint first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
+       uint 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. */
+       uint 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) {
+         uint 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) {
+           uint fake_zero_displacement = FALSE;
+           uint 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 = TRUE;
+               /* 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 = TRUE; /* 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 = TRUE;
+                 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) {
+             uint seg_index;
+             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) {
+           uint 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,
+                 ((uchar) *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);
+       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);
+      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, (uint) *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 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);
+           }
+         }
+       }
+      }                                /* end displacement output */
+      
+      /* output immediate */
+      if (i.imm_operands) {
+       register 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);
+           }
+         }
+       }
+      }                                /* 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. */
+
+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_NONE:    /* 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;
+    uint 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 = FALSE;
+    if (*base_string == ')') {
+      uint 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 = TRUE;
+    }
+
+    /* 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_NONE:
+       /* 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_type)
+     register fragS *  fragP;
+     register int      segment_type; /* N_DATA or N_TEXT. */
+{
+  register uchar *     opcode;
+  register int         old_fr_fix;
+
+  old_fr_fix = fragP -> fr_fix;
+  opcode = (uchar *) fragP -> fr_opcode;
+  /* We've already got fragP->fr_subtype right;  all we have to do is check
+     for un-relaxable symbols. */
+  if ((fragP -> fr_symbol -> sy_type & N_TYPE) != segment_type) {
+    /* 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);
+      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);
+      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 uchar * opcode;
+  uchar * where_to_put_displacement;
+  uint target_address, opcode_address;
+  uint extension;
+  int displacement_from_opcode_start;
+
+  opcode = (uchar *) fragP -> fr_opcode;
+
+  /* Address we want to reach in file space. */
+  target_address = fragP->fr_symbol->sy_value + 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 */
+
+void md_create_short_jump(ptr, from_addr, to_addr)
+     char      *ptr;
+     long      from_addr, to_addr;
+{
+  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 - to_symbol->sy_value;
+    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 int) 0, 0);
+  } 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 int  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);
+  }
+}
+
+void                           /* Knows about order of bytes in address. */
+md_number_to_disp (con, value, nbytes)
+     char      con []; /* Return 'nbytes' of chars here. */
+     long int  value;          /* The value of the bits. */
+     int       nbytes;         /* Number of bytes in the output. */
+{
+  char * answer = alloca (nbytes);
+  register char * p = answer;
+
+  switch (nbytes) {
+  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 (nbytes);
+  }
+  bcopy (answer, con, nbytes);
+}
+
+void                           /* Knows about order of bytes in address. */
+md_number_to_imm (con, value, nbytes)
+     char      con []; /* Return 'nbytes' of chars here. */
+     long int  value;          /* The value of the bits. */
+     int       nbytes;         /* Number of bytes in the output. */
+{
+  char * answer = alloca (nbytes);
+  register char * p = answer;
+
+  switch (nbytes) {
+  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 (nbytes);
+  }
+  bcopy (answer, con, nbytes);
+}
+
+void                           /* Knows about order of bytes in address. */
+md_number_to_field (con, value, nbytes)
+     char      con []; /* Return 'nbytes' of chars here. */
+     long int  value;          /* The value of the bits. */
+     int       nbytes;         /* Number of bytes in the output. */
+{
+  char * answer = alloca (nbytes);
+  register char * p = answer;
+
+  switch (nbytes) {
+  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 (nbytes);
+  }
+  bcopy (answer, con, nbytes);
+}
+
+long int                       /* 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 int     retval;
+  for (retval=0, con+=nbytes-1; nbytes--; con--)
+    {
+      retval <<= BITS_PER_CHAR;
+      retval |= *con;
+    }
+  return retval;
+}
+
+void md_ri_to_chars(ri_p, ri)
+     struct relocation_info *ri_p, ri;
+{
+  unsigned char the_bytes[8];
+  
+  /* 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; 
+  /* now put it back where you found it */
+  bcopy (the_bytes, (char *)ri_p, sizeof(struct relocation_info));
+}
+
+\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;
+  char *atof_ieee();
+
+  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];
+
+char * output_invalid (c)
+     char c;
+{
+  if (isprint(c)) sprintf (output_invalid_buf, "'%c'", c);
+  else sprintf (output_invalid_buf, "(0x%x)", c);
+  return output_invalid_buf;
+}
+
+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);
+}
+
diff --git a/gnu/usr.bin/as/config/i386.h b/gnu/usr.bin/as/config/i386.h
new file mode 100644 (file)
index 0000000..c569c1c
--- /dev/null
@@ -0,0 +1,296 @@
+/* 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 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 unsigned char uchar;
+typedef unsigned int uint;
+
+typedef struct {
+  /* instruction name sans width suffix ("mov" for movl insns) */
+  char          *name;
+
+  /* how many operands */
+  uint    operands;
+
+  /* base_opcode is the fundamental opcode byte with a optional prefix(es). */
+  uint    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 */
+  uchar    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 */
+  uint    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 */
+  uint 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;
+  uint   reg_type;
+  uint   reg_num;
+} reg_entry;
+
+typedef struct {
+  char * seg_name;
+  uint   seg_prefix;
+} seg_entry;
+
+/* these are for prefix name --> prefix code hash lookup */
+typedef struct {
+  char * prefix_name;
+  uchar  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;
+
+/* '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. */
+  uint               operands;
+
+  /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number of
+     given register, displacement, memory operands and immediate operands. */
+  uint               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. */
+  uint               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;
+  uint                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];
+  uint              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;
diff --git a/gnu/usr.bin/as/expr.c b/gnu/usr.bin/as/expr.c
new file mode 100644 (file)
index 0000000..f3a377d
--- /dev/null
@@ -0,0 +1,980 @@
+/* expr.c -operands, expressions-
+   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 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 "as.h"
+#include "flonum.h"
+#include "read.h"
+#include "struc-symbol.h"
+#include "expr.h"
+#include "obstack.h"
+#include "symbols.h"
+
+static void clean_up_expression();     /* Internal. */
+extern const char EXP_CHARS[]; /* JF hide MD floating pt stuff all the same place */
+extern const char FLT_CHARS[];
+
+#ifdef SUN_ASM_SYNTAX
+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_NONE.
+ *     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 struct symbol *     symbolP; /* Points to symbol */
+
+  extern  char hex_value[];    /* In hex_value.c */
+  char *local_label_name();
+
+  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;        /* 8, 10 or 16 */
+                               /* 0 means we saw start of a floating- */
+                               /* point constant. */
+      register short int maxdig;/* Highest permitted digit value. */
+      register int     too_many_digits; /* 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 */
+             if(c=='f' && (! *input_line_pointer ||
+                           (!index("+-.0123456789",*input_line_pointer) &&
+                           !index(EXP_CHARS,*input_line_pointer))))
+               {
+                 maxdig = radix = 10;
+                 too_many_digits = 11;
+                 c='0';
+                 input_line_pointer-=2;
+               }
+             else if (c && index (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 = 8;
+                 maxdig = 10;  /* Un*x sux. Compatibility. */
+                 too_many_digits = 11;
+               }
+           }
+         /* c == char after "0" or "0x" or "0X" or "0e" etc.*/
+       }
+      else
+       {
+         maxdig = radix = 10;
+         too_many_digits = 11;
+       }
+      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 int          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 int  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( BITS_PER_INT == 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 = TRUE;
+               }
+             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)
+               {
+#ifdef SUN_ASM_SYNTAX
+                 if (c=='b' || (c=='$' && local_label_defined[number]))
+#else
+                 if (c=='b')
+#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_table_lookup(name)) /* seen before */
+                         && (symbolP -> sy_type & N_TYPE) != N_UNDF /* symbol is defined: OK */
+                         )
+                       {               /* Expected path: symbol defined. */
+                         /* Local labels are never absolute. Don't waste time checking absoluteness. */
+                         know(   (symbolP -> sy_type & N_TYPE) == N_DATA
+                              || (symbolP -> sy_type & N_TYPE) == N_TEXT );
+                         expressionP -> X_add_symbol = symbolP;
+                         expressionP -> X_add_number = 0;
+                         expressionP -> X_seg        = N_TYPE_seg [symbolP -> sy_type];
+                       }
+                     else
+                       {               /* Either not seen or not defined. */
+                         as_warn( "Backw. ref to unknown label \"%d:\", 0 assumed.",
+                                 number
+                                 );
+                         expressionP -> X_add_number = 0;
+                         expressionP -> X_seg        = SEG_ABSOLUTE;
+                       }
+                   }
+                 else
+                   {
+#ifdef SUN_ASM_SYNTAX
+                     if (c=='f' || (c=='$' && !local_label_defined[number]))
+#else
+                     if (c=='f')
+#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);
+                         if ( symbolP = symbol_table_lookup( name ))
+                           {
+                             /* We have no need to check symbol properties. */
+                             know(   (symbolP -> sy_type & N_TYPE) == N_UNDF
+                                  || (symbolP -> sy_type & N_TYPE) == N_DATA
+                                  || (symbolP -> sy_type & N_TYPE) == N_TEXT);
+                           }
+                         else
+                           {
+                             symbolP = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag);
+                             symbol_table_insert (symbolP);
+                           }
+                         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_warn( "Bad floating-point constant: exponent overflow, probably assembling junk" );
+               }
+             else
+               {             
+                 as_warn( "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",
+                        (unsigned char)(seg_N_TYPE[(int)now_seg]),
+                        0,
+                        0,
+                        (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_table_lookup(name);
+      if (symbolP)
+           {
+          /*
+           * If we have an absolute symbol, then we know it's value now.
+           */
+          register segT        seg;
+
+          seg = N_TYPE_seg [(int) symbolP -> sy_type & N_TYPE];
+          if ((expressionP -> X_seg = seg) == SEG_ABSOLUTE )
+           {
+             expressionP -> X_add_number = symbolP -> sy_value;
+           }
+         else
+           {
+             expressionP -> X_add_number  = 0;
+             expressionP -> X_add_symbol  = symbolP;
+           }
+       }
+      else
+       {
+         expressionP -> X_add_symbol
+               = symbolP
+               = symbol_new (name, N_UNDF, 0,0,0, & zero_address_frag);
+
+         expressionP -> X_add_number  = 0;
+         expressionP -> X_seg         = SEG_UNKNOWN;
+         symbol_table_insert (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_warn( "Missing ')' assumed");
+         input_line_pointer --;
+       }
+      /* here with input_line_pointer -> char after "(...)" */
+    }
+  else if ( 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
+         {
+           expressionP -> X_add_number = ~ expressionP -> X_add_number;
+         }
+         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_warn("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_NONE;
+      input_line_pointer --;
+    }
+/*
+ * 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_NONE.
+ * 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_NONE:
+    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
+             && expressionP->X_subtract_symbol->sy_value==expressionP->X_add_symbol->sy_value))
+       {
+         expressionP -> X_subtract_symbol      = NULL;
+         expressionP -> X_add_symbol           = NULL;
+         expressionP -> X_seg                  = SEG_ABSOLUTE;
+       }
+      break;
+
+    default:
+      BAD_CASE( expressionP -> X_seg);
+      break;
+    }
+}
+\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)
+     struct symbol **  symbol_1_PP;
+     struct symbol *   symbol_2_P;
+{
+  segT                 return_value;
+
+  know(    (* symbol_1_PP)                     == NULL
+       || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_TEXT
+       || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_DATA
+       || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_BSS
+       || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF
+       );
+  know(      symbol_2_P             == NULL
+       ||    (symbol_2_P   -> sy_type & N_TYPE) == N_TEXT
+       ||    (symbol_2_P   -> sy_type & N_TYPE) == N_DATA
+       ||    (symbol_2_P   -> sy_type & N_TYPE) == N_BSS
+       ||    (symbol_2_P   -> sy_type & N_TYPE) == N_UNDF
+       );
+  if (* symbol_1_PP)
+    {
+      if (((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF)
+       {
+         if (symbol_2_P)
+           {
+             return_value = SEG_PASS1;
+             * symbol_1_PP = NULL;
+           }
+         else
+           {
+             know( ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF)
+             return_value = SEG_UNKNOWN;
+           }
+       }
+      else
+       {
+         if (symbol_2_P)
+           {
+             if ((symbol_2_P -> sy_type & N_TYPE) == N_UNDF)
+               {
+                 * symbol_1_PP = NULL;
+                 return_value = SEG_PASS1;
+               }
+             else
+               {
+                 /* {seg1} - {seg2} */
+                 as_warn( "Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"",
+                         (* symbol_1_PP) -> sy_name, symbol_2_P -> sy_name );
+                 * symbol_1_PP = NULL;
+                 return_value = SEG_ABSOLUTE;
+               }
+           }
+         else
+           {
+             return_value = N_TYPE_seg [(* symbol_1_PP) -> sy_type & N_TYPE];
+           }
+       }
+    }
+  else
+    {                          /* (* symbol_1_PP) == NULL */
+      if (symbol_2_P)
+       {
+         * symbol_1_PP = symbol_2_P;
+         return_value = N_TYPE_seg [(symbol_2_P) -> sy_type & N_TYPE];
+       }
+      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                              
+       || ((* symbol_1_PP) -> sy_type & N_TYPE) == seg_N_TYPE [(int) 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       * / % < >
+ */
+typedef char operator_rankT;
+static const operator_rankT
+op_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 };
+\f
+segT                           /* Return resultP -> X_seg. */
+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_NONE == 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 struct symbol *  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 = TRUE;
+                 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_warn("Expression too complex: forgetting %s - %s",
+                         resultP -> X_add_symbol      -> sy_name,
+                         resultP -> X_subtract_symbol -> sy_name);
+                 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 = TRUE;
+               }
+             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_warn( "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);
+}
+
+/* end: expr.c */
diff --git a/gnu/usr.bin/as/expr.h b/gnu/usr.bin/as/expr.h
new file mode 100644 (file)
index 0000000..964d3b9
--- /dev/null
@@ -0,0 +1,69 @@
+/* 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 int 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. */
+
+
+segT           expr();
+char           get_symbol_end();
+
+/* end: expr.h */
diff --git a/gnu/usr.bin/as/flonum-const.c b/gnu/usr.bin/as/flonum-const.c
new file mode 100644 (file)
index 0000000..617e585
--- /dev/null
@@ -0,0 +1,157 @@
+/* flonum_const.c - Useful Flonum constants
+   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 "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/gnu/usr.bin/as/flonum-copy.c b/gnu/usr.bin/as/flonum-copy.c
new file mode 100644 (file)
index 0000000..3a51f06
--- /dev/null
@@ -0,0 +1,76 @@
+/* flonum_copy.c - copy a flonum
+   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 "flonum.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/gnu/usr.bin/as/flonum-mult.c b/gnu/usr.bin/as/flonum-mult.c
new file mode 100644 (file)
index 0000000..1b7b5ea
--- /dev/null
@@ -0,0 +1,200 @@
+/* flonum_multip.c - multiply two flonums
+   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.  */
+
+#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)
+     FLONUM_TYPE *     a,
+                *      b,
+                *      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 int    work;
+  unsigned long int    carry;
+  long int             exponent;
+  LITTLENUM_TYPE *     q;
+  long int             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/gnu/usr.bin/as/flonum.h b/gnu/usr.bin/as/flonum.h
new file mode 100644 (file)
index 0000000..b2e841a
--- /dev/null
@@ -0,0 +1,111 @@
+/* flonum.h - Floating point package
+   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 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 int             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.                                       *
+*                                                                      *
+\***********************************************************************/
+
+void   flonum_multip();
+void   flonum_copy();
+void   flonum_print();
+char * flonum_get();           /* Returns "" or error string. */
+void   flonum_normal();
+
+int    atof_generic();
+
+
+/***********************************************************************\
+*                                                                      *
+*      Declare error codes.                                            *
+*                                                                      *
+\***********************************************************************/
+
+#define ERROR_EXPONENT_OVERFLOW (2)
+
+/* end: flonum.h */
diff --git a/gnu/usr.bin/as/frags.c b/gnu/usr.bin/as/frags.c
new file mode 100644 (file)
index 0000000..ee10321
--- /dev/null
@@ -0,0 +1,292 @@
+/* frags.c - manage frags -
+   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"
+#include "subsegs.h"
+#include "obstack.h"
+#include "frags.h"
+#include "struc-symbol.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)
+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);
+}
+\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 int       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 int           offset;
+     char              *opcode;
+     char               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;
+}
+
+/* end: frags.c */
diff --git a/gnu/usr.bin/as/frags.h b/gnu/usr.bin/as/frags.h
new file mode 100644 (file)
index 0000000..6d7310b
--- /dev/null
@@ -0,0 +1,41 @@
+/* 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 ); \
+}
+      
+
+/* end: frags.h */
diff --git a/gnu/usr.bin/as/hash.c b/gnu/usr.bin/as/hash.c
new file mode 100644 (file)
index 0000000..21f0cc0
--- /dev/null
@@ -0,0 +1,981 @@
+/* hash.c - hash table lookup strings -
+   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.  */
+
+/*
+ * 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>
+#define TRUE           (1)
+#define FALSE          (0)
+#include <ctype.h>
+#define min(a, b)      ((a) < (b) ? (a) : (b))
+
+#include "hash.h"
+char *xmalloc();
+
+#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;
+  char *                malloc();
+  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) ) )
+                               /* +1 for the wall entry */
+    {
+      if ( retval = (struct hash_control *) malloc(sizeof(struct hash_control)) )
+       {
+         nd = retval->hash_stat + STATLENGTH;
+         for (ip=retval->hash_stat; ip<nd; ip++)
+           {
+             *ip = 0;
+           }
+
+         retval -> hash_stat[STAT_SIZE]  = 1<<START_POWER;
+         retval -> hash_mask             = (1<<START_POWER) - 1;
+         retval -> hash_sizelog          = START_POWER;
+                               /* works for 1's compl ok */
+         retval -> hash_where            = room;
+         retval -> hash_wall             =
+           wall                          = room + (1<<START_POWER);
+         retval -> hash_full             = (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))))
+                               /* +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) && 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) && s!=DELETED )
+    {
+       for(string1=string;;) {
+               if(!(c= *s++)) {
+                       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) && 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 int                 h;      /* hash code built here */
+  register long int                 c;      /* each character lands here */
+  register int                    n;      /* Amount to shift h by */
+
+  n = (handle->hash_sizelog - 3);
+  h = 0;
+  while (c = *string++)
+    {
+      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/gnu/usr.bin/as/hash.h b/gnu/usr.bin/as/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/gnu/usr.bin/as/hex-value.c b/gnu/usr.bin/as/hex-value.c
new file mode 100644 (file)
index 0000000..f97c2ab
--- /dev/null
@@ -0,0 +1,55 @@
+/* hex_value.c - char=>radix-value -
+   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.  */
+
+/*
+ * 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/gnu/usr.bin/as/input-file.c b/gnu/usr.bin/as/input-file.c
new file mode 100644 (file)
index 0000000..8de1dcf
--- /dev/null
@@ -0,0 +1,306 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input-file.c       6.2 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* input_file.c - Deal with Input Files -
+   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.  */
+
+/*
+ * 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!
+ */
+
+#define NDEBUG         /* JF remove asserts */
+
+#ifdef USG
+#define index strchr
+/* JF:  What's the difference between _IOLBF and _IOFBF ? */
+#define setbuffer(stream, buf, size) setvbuf((stream), (buf), _IOFBF, (size))
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+/* #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h> */
+
+/* #include "style.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;
+
+void   as_perror();
+
+/*
+ * 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)
+
+static char in_buf[BUFFER_SIZE];
+
+/*
+ * We use static data: the data area is not sharable.
+ */
+
+FILE *f_in;    /* JF do things the RIGHT way */
+/* static JF remove static so app.c can use file_name */
+char * file_name;
+\f
+/* These hooks accomodate most operating systems. */
+
+void
+input_file_begin ()
+{
+  /* file_handle = -1; */
+  f_in = (FILE *)0;
+}
+
+void
+input_file_end ()
+{
+}
+
+int                            /* Return BUFFER_SIZE. */
+input_file_buffer_size ()
+{
+  return (BUFFER_SIZE);
+}
+
+int
+input_file_is_open ()
+{
+  /* return (file_handle >= 0); */
+  return f_in!=(FILE *)0;
+}
+\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;
+      char     *mktemp();
+
+      (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_warn( "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
+       setbuffer(f_in,in_buf,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(!index(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];
+               char    *mktemp();
+               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
+
+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.
+       */
+  /* size = read (file_handle, where, BUFFER_SIZE); */
+  if(preprocess) {
+       char *p;
+       int n;
+       int ch;
+       extern FILE *scrub_file;
+       int scrub_from_file();
+       void scrub_to_file();
+       int do_scrub_next_char();
+
+       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);
+}
+
+/* end: input_file.c */
diff --git a/gnu/usr.bin/as/input-file.h b/gnu/usr.bin/as/input-file.h
new file mode 100644 (file)
index 0000000..42f490a
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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.
+ *
+ * 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.
+ */
+
+void   input_file_begin();
+void   input_file_end();
+int    input_file_buffer_size();
+int    input_file_is_open();
+void   input_file_open();
+char * input_file_give_next_buffer();
+
+/* end: input_file.h */
diff --git a/gnu/usr.bin/as/input-scrub.c b/gnu/usr.bin/as/input-scrub.c
new file mode 100644 (file)
index 0000000..71af8a0
--- /dev/null
@@ -0,0 +1,427 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input-scrub.c      6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* input_scrub.c - layer between app and the rest of the world
+   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"
+#include "read.h"
+#include "input-file.h"
+
+/*
+ * O/S independent module to supply buffers of sanitised source code
+ * to rest of assembler. We get raw input data of some length.
+ * Also looks after line numbers, for e.g. error messages.
+ * This module used to do the sanitising, but now a pre-processor program
+ * (app) does that job so this module is degenerate.
+ * Now input is pre-sanitised, so we only worry about finding the
+ * last partial line. A buffer of full lines is returned to 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. The last character before AFTER_STRING is a newline.
+ */
+
+/*
+ * We expect 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? */
+
+static void as_1_char ();
+
+/*
+We never have more than one source file open at once.
+We may, however, read more than 1 source file in an assembly.
+NULL means we have no file open right now.
+*/
+
+
+/*
+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;
+\f
+void
+input_scrub_begin ()
+{
+  know( strlen(BEFORE_STRING) == BEFORE_SIZE );
+  know( strlen( AFTER_STRING) ==  AFTER_SIZE );
+
+  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. */
+  do_scrub_begin();
+}
+
+void
+input_scrub_end ()
+{
+  input_file_end ();
+}
+
+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);
+}
+
+char *
+input_scrub_next_buffer (bufp)
+char **bufp;
+{
+  register char *      limit;  /* -> just after last char of buffer. */
+
+#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" );
+       }
+    }
+  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 ( line_number >= 0 )
+    {
+      logical_input_line = line_number;
+    }
+}
+\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:unknown:", p);
+#endif
+       }
+    }
+  else
+    {
+#ifdef DONTDEF
+      fprintf (stderr," Before reading source.\n");
+#else
+#endif
+    }
+}
+\f
+/*
+ * Support for source file debugging.  These functions handle
+ * logical lines and logical files.
+ */
+static char *saved_file;
+static int saved_len;
+static line_numberT saved_line;
+
+void
+filestab()
+{
+  char *file;
+  int len;
+
+  if (!physical_input_file ||
+      !input_file_is_open())
+    return;
+
+  file = logical_input_file ? logical_input_file : physical_input_file;
+
+  if (saved_file == 0 || strcmp(file, saved_file) != 0)
+    {
+      stabs(file);
+      len = strlen(file) + 1;
+      if (len > saved_len)
+       {
+         if (saved_file == 0)
+           saved_file = xmalloc(len);
+         else
+           saved_file = xrealloc(saved_file, len);
+         memcpy(saved_file, file, len);
+         saved_len = len;
+       }
+      else
+       strcpy(saved_file, file);
+      saved_line = 0;
+    }
+}
+
+void
+funcstab(func)
+     char *func;
+{
+  if (now_seg != SEG_TEXT)
+    return;
+
+  filestab();
+  stabf(func);
+}
+
+void
+linestab()
+{
+  line_numberT line;
+
+  if (now_seg != SEG_TEXT)
+    return;
+
+  filestab();
+
+  line = logical_input_line ? logical_input_line : physical_input_line;
+
+  if (saved_line == 0 || line != saved_line)
+    {
+      stabd(line);
+      saved_line = line;
+    }
+}
+\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 char c;
+     FILE *    stream;
+{
+  if ( c > 127 )
+    {
+      (void)putc( '%', stream);
+      c -= 128;
+    }
+  if ( c < 32 )
+    {
+      (void)putc( '^', stream);
+      c += '@';
+    }
+  (void)putc( c, stream);
+}
+
+/* end: input_scrub.c */
diff --git a/gnu/usr.bin/as/md.h b/gnu/usr.bin/as/md.h
new file mode 100644 (file)
index 0000000..681d027
--- /dev/null
@@ -0,0 +1,57 @@
+/* md.h -machine dependent- */
+
+/* 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.  */
+
+/* In theory (mine, at least!) the machine dependent part of the assembler
+   should only have to include one file.  This one.  -- JF */
+
+/* JF added this here */
+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;
+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 */
+
+char *         md_atof();
+void           md_assemble();
+void           md_begin();
+void           md_convert_frag();
+void           md_end();
+int            md_estimate_size_before_relax();
+void           md_number_to_chars();
+
+/* end: md.h */
diff --git a/gnu/usr.bin/as/messages.c b/gnu/usr.bin/as/messages.c
new file mode 100644 (file)
index 0000000..a7b1205
--- /dev/null
@@ -0,0 +1,238 @@
+/* messages.c - error reporter -
+   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 <stdio.h>             /* define stderr */
+#ifdef VMS
+#include <errno.h>     /* Need this to make errno declaration right */
+#include <perror.h>    /* Need this to make sys_errlist/sys_nerr right */
+#endif /* VMS */
+
+#include "as.h"
+
+#ifndef NO_VARARGS
+#include <varargs.h>
+#endif
+
+/*
+               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.
+
+*/
+
+
+/* Nonzero if we've hit a 'bad error', and should not write an obj file,
+   and exit with a nonzero error code */
+
+int bad_error = 0;
+
+
+/*
+ *                     a s _ p e r r o r
+ *
+ * Like perror(3), but with more info.
+ */
+/* JF moved from input-scrub.c to here.  */
+void
+as_perror(gripe, filename)
+     char *    gripe;          /* Unpunctuated error theme. */
+     char *    filename;
+{
+  extern int errno;            /* See perror(3) for details. */
+  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. */
+}
+
+/*
+ *                     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.
+ */
+
+#ifdef NO_VARARGS
+/*VARARGS1*/
+as_warn(Format,args)
+char *Format;
+{
+  if ( ! flagseen ['W'])       /* -W supresses warning messages. */
+    {
+      as_where();
+      _doprnt (Format, &args, stderr);
+      (void)putc ('\n', stderr);
+      /* as_where(); */
+    }
+}
+#else
+void
+as_warn(Format,va_alist)
+char *Format;
+va_dcl
+{
+  va_list args;
+
+  if( ! flagseen['W'])
+    {
+      as_where();
+      va_start(args);
+      vfprintf(stderr, Format, args);
+      va_end(args);
+      (void) putc('\n', stderr);
+    }
+}
+#endif
+#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']) {
+               as_where();
+               fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+               (void)putc('\n',stderr);
+       }
+}
+#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.
+ */
+
+#ifdef NO_VARARGS
+/*VARARGS1*/
+as_bad(Format,args)
+char *Format;
+{
+  bad_error=1;
+  as_where();
+  _doprnt (Format, &args, stderr);
+  (void)putc ('\n', stderr);
+  /* as_where(); */
+}
+#else
+void
+as_bad(Format,va_alist)
+char *Format;
+va_dcl
+{
+  va_list args;
+
+  bad_error=1;
+  as_where();
+  va_start(args);
+  vfprintf(stderr, Format, args);
+  va_end(args);
+  (void) putc('\n', stderr);
+}
+#endif
+#ifdef DONTDEF
+void
+as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an)
+char *format;
+{
+       as_where();
+       bad_error=1;
+       fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an);
+       (void)putc('\n',stderr);
+}
+#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.
+ */
+
+#ifdef NO_VARARGS
+/*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? */
+}
+#else
+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);
+}
+#endif
+#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);
+}
+#endif
+
+/* end: messages.c */
diff --git a/gnu/usr.bin/as/objrecdef.h b/gnu/usr.bin/as/objrecdef.h
new file mode 100644 (file)
index 0000000..fca8af4
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *
+ *     $OBJRECDEF
+ *     Generated automatically by "vms_struct Version 1.00"
+ *     Created from VMS definition file "objrecdef.mar"
+ *     Mon Oct 14 14:01:29 1985
+ *
+ */
+struct OBJREC {
+       unsigned char   obj$b_rectyp;
+       unsigned char   obj$b_subtyp;
+       unsigned char   obj$b_mhd_strlv;
+       unsigned char   obj$b_mhd_recsz[2];
+       unsigned char   obj$t_mhd_name[1];
+       };
+\f
+#define        OBJ$C_HDR       0
+#define        OBJ$C_HDR_MHD   0
+#define        OBJ$C_HDR_LNM   1
+#define        OBJ$C_HDR_SRC   2
+#define        OBJ$C_HDR_TTL   3
+#define        OBJ$C_HDR_CPR   4
+#define        OBJ$C_HDR_MTC   5
+#define        OBJ$C_HDR_GTX   6
+#define        OBJ$C_GSD       1
+#define        OBJ$C_GSD_PSC   0
+#define        OBJ$C_GSD_SYM   1
+#define        OBJ$C_GSD_EPM   2
+#define        OBJ$C_GSD_PRO   3
+#define        OBJ$C_GSD_SYMW  4
+#define        OBJ$C_GSD_EPMW  5
+#define        OBJ$C_GSD_PROW  6
+#define        OBJ$C_GSD_IDC   7
+#define        OBJ$C_GSD_ENV   8
+#define        OBJ$C_GSD_LSY   9
+#define        OBJ$C_GSD_LEPM  10
+#define        OBJ$C_GSD_LPRO  11
+#define        OBJ$C_GSD_SPSC  12
+#define        OBJ$C_TIR       2
+#define        OBJ$C_EOM       3
+#define        OBJ$C_DBG       4
+#define        OBJ$C_TBT       5
+#define        OBJ$C_LNK       6
+#define        OBJ$C_EOMW      7
+#define        OBJ$C_MAXRECTYP 7
+#define        OBJ$K_SUBTYP    1
+#define        OBJ$C_SUBTYP    1
+#define        OBJ$C_MAXRECSIZ 2048
+#define        OBJ$C_STRLVL    0
+#define        OBJ$C_SYMSIZ    31
+#define        OBJ$C_STOREPLIM -1
+#define        OBJ$C_PSCALILIM 9
+\f
+#define        MHD$C_MHD       0
+#define        MHD$C_LNM       1
+#define        MHD$C_SRC       2
+#define        MHD$C_TTL       3
+#define        MHD$C_CPR       4
+#define        MHD$C_MTC       5
+#define        MHD$C_GTX       6
+#define        MHD$C_MAXHDRTYP 6
+\f
+#define        GSD$K_ENTRIES   1
+#define        GSD$C_ENTRIES   1
+#define        GSD$C_PSC       0
+#define        GSD$C_SYM       1
+#define        GSD$C_EPM       2
+#define        GSD$C_PRO       3
+#define        GSD$C_SYMW      4
+#define        GSD$C_EPMW      5
+#define        GSD$C_PROW      6
+#define        GSD$C_IDC       7
+#define        GSD$C_ENV       8
+#define        GSD$C_LSY       9
+#define        GSD$C_LEPM      10
+#define        GSD$C_LPRO      11
+#define        GSD$C_SPSC      12
+#define        GSD$C_SYMV      13
+#define        GSD$C_EPMV      14
+#define        GSD$C_PROV      15
+#define        GSD$C_MAXRECTYP 15
+\f
+#define        GSY$M_WEAK      1
+#define        GSY$M_DEF       2
+#define        GSY$M_UNI       4
+#define        GSY$M_REL       8
+\f
+#define        GPS$M_PIC       1
+#define        GPS$M_LIB       2
+#define        GPS$M_OVR       4
+#define        GPS$M_REL       8
+#define        GPS$M_GBL       16
+#define        GPS$M_SHR       32
+#define        GPS$M_EXE       64
+#define        GPS$M_RD        128
+#define        GPS$M_WRT       256
+#define        GPS$M_VEC       512
+#define        GPS$K_NAME      9
+#define        GPS$C_NAME      9
+\f
+#define        TIR$C_STA_GBL   0
+#define        TIR$C_STA_SB    1
+#define        TIR$C_STA_SW    2
+#define        TIR$C_STA_LW    3
+#define        TIR$C_STA_PB    4
+#define        TIR$C_STA_PW    5
+#define        TIR$C_STA_PL    6
+#define        TIR$C_STA_UB    7
+#define        TIR$C_STA_UW    8
+#define        TIR$C_STA_BFI   9
+#define        TIR$C_STA_WFI   10
+#define        TIR$C_STA_LFI   11
+#define        TIR$C_STA_EPM   12
+#define        TIR$C_STA_CKARG 13
+#define        TIR$C_STA_WPB   14
+#define        TIR$C_STA_WPW   15
+#define        TIR$C_STA_WPL   16
+#define        TIR$C_STA_LSY   17
+#define        TIR$C_STA_LIT   18
+#define        TIR$C_STA_LEPM  19
+#define        TIR$C_MAXSTACOD 19
+#define        TIR$C_MINSTOCOD 20
+#define        TIR$C_STO_SB    20
+#define        TIR$C_STO_SW    21
+#define        TIR$C_STO_L     22
+#define        TIR$C_STO_BD    23
+#define        TIR$C_STO_WD    24
+#define        TIR$C_STO_LD    25
+#define        TIR$C_STO_LI    26
+#define        TIR$C_STO_PIDR  27
+#define        TIR$C_STO_PICR  28
+#define        TIR$C_STO_RSB   29
+#define        TIR$C_STO_RSW   30
+#define        TIR$C_STO_RL    31
+#define        TIR$C_STO_VPS   32
+#define        TIR$C_STO_USB   33
+#define        TIR$C_STO_USW   34
+#define        TIR$C_STO_RUB   35
+#define        TIR$C_STO_RUW   36
+#define        TIR$C_STO_B     37
+#define        TIR$C_STO_W     38
+#define        TIR$C_STO_RB    39
+#define        TIR$C_STO_RW    40
+#define        TIR$C_STO_RIVB  41
+#define        TIR$C_STO_PIRR  42
+#define        TIR$C_MAXSTOCOD 42
+#define        TIR$C_MINOPRCOD 50
+#define        TIR$C_OPR_NOP   50
+#define        TIR$C_OPR_ADD   51
+#define        TIR$C_OPR_SUB   52
+#define        TIR$C_OPR_MUL   53
+#define        TIR$C_OPR_DIV   54
+#define        TIR$C_OPR_AND   55
+#define        TIR$C_OPR_IOR   56
+#define        TIR$C_OPR_EOR   57
+#define        TIR$C_OPR_NEG   58
+#define        TIR$C_OPR_COM   59
+#define        TIR$C_OPR_INSV  60
+#define        TIR$C_OPR_ASH   61
+#define        TIR$C_OPR_USH   62
+#define        TIR$C_OPR_ROT   63
+#define        TIR$C_OPR_SEL   64
+#define        TIR$C_OPR_REDEF 65
+#define        TIR$C_OPR_DFLIT 66
+#define        TIR$C_MAXOPRCOD 66
+#define        TIR$C_MINCTLCOD 80
+#define        TIR$C_CTL_SETRB 80
+#define        TIR$C_CTL_AUGRB 81
+#define        TIR$C_CTL_DFLOC 82
+#define        TIR$C_CTL_STLOC 83
+#define        TIR$C_CTL_STKDL 84
+#define        TIR$C_MAXCTLCOD 84
+\f
+/*
+ *     Debugger symbol definitions:  These are done by hand, as no
+ *                                     machine-readable version seems
+ *                                     to be available.
+ */
+#define        DST$C_C         7               /* Language == "C"      */
+#define DST$C_VERSION  153
+#define        DST$C_SOURCE    155             /* Source file          */
+#define DST$C_PROLOG   162
+#define        DST$C_BLKBEG    176             /* Beginning of block   */
+#define        DST$C_BLKEND    177             /* End of block */
+#define DST$C_ENTRY    181
+#define DST$C_PSECT    184
+#define        DST$C_LINE_NUM  185             /* Line Number          */
+#define DST$C_LBLORLIT 186
+#define DST$C_LABEL    187
+#define        DST$C_MODBEG    188             /* Beginning of module  */
+#define        DST$C_MODEND    189             /* End of module        */
+#define        DST$C_RTNBEG    190             /* Beginning of routine */
+#define        DST$C_RTNEND    191             /* End of routine       */
+#define        DST$C_DELTA_PC_W        1               /* Incr PC      */
+#define        DST$C_INCR_LINUM        2               /* Incr Line #  */
+#define        DST$C_INCR_LINUM_W      3               /* Incr Line #  */
+#define DST$C_SET_LINUM_INCR   4
+#define DST$C_SET_LINUM_INCR_W 5
+#define DST$C_RESET_LINUM_INCR 6
+#define DST$C_BEG_STMT_MODE    7
+#define DST$C_END_STMT_MODE    8
+#define        DST$C_SET_LINE_NUM      9               /* Set Line #   */
+#define DST$C_SET_PC           10
+#define DST$C_SET_PC_W         11
+#define DST$C_SET_PC_L         12
+#define DST$C_SET_STMTNUM      13
+#define DST$C_TERM             14              /* End of lines */
+#define DST$C_TERM_W           15              /* End of lines */
+#define        DST$C_SET_ABS_PC        16              /* Set PC       */
+#define        DST$C_DELTA_PC_L        17              /* Incr PC      */
+#define DST$C_INCR_LINUM_L     18              /* Incr Line #  */
+#define DST$C_SET_LINUM_B      19              /* Set Line #   */
+#define DST$C_SET_LINUM_L      20              /* Set Line #   */
+#define        DST$C_TERM_L            21              /* End of lines */
+/* these are used with DST$C_SOURCE */
+#define        DST$C_SRC_FORMFEED      16              /* ^L counts    */
+#define        DST$C_SRC_DECLFILE      1               /* Declare file */
+#define        DST$C_SRC_SETFILE       2               /* Set file     */
+#define        DST$C_SRC_SETREC_L      3               /* Set record   */
+#define        DST$C_SRC_DEFLINES_W    10              /* # of line    */
+/* the following are the codes for the various data types.  Anything not on
+ * the list is included under 'advanced_type'
+ */
+#define DBG$C_UCHAR            0x02
+#define DBG$C_USINT            0x03
+#define DBG$C_ULINT            0x04
+#define DBG$C_SCHAR            0x06
+#define DBG$C_SSINT            0x07
+#define DBG$C_SLINT            0x08
+#define DBG$C_REAL4            0x0a
+#define DBG$C_REAL8            0x0b
+#define DBG$C_FUNCTION_ADDR    0x17
+#define DBG$C_ADVANCED_TYPE    0xa3
+/*  These are the codes that are used to generate the definitions of struct
+ *  union and enum records
+ */
+#define DBG$C_ENUM_ITEM                        0xa4
+#define DBG$C_ENUM_START               0xa5
+#define DBG$C_ENUM_END                 0xa6
+#define DBG$C_STRUCT_START             0xab
+#define DBG$C_STRUCT_ITEM              0xff
+#define DBG$C_STRUCT_END               0xac
+/*  These are the codes that are used in the suffix records to determine the
+ *  actual data type
+ */
+#define DBG$C_BASIC                    0x01
+#define DBG$C_BASIC_ARRAY              0x02
+#define DBG$C_STRUCT                   0x03
+#define DBG$C_POINTER                  0x04
+#define DBG$C_VOID                     0x05
+#define DBG$C_COMPLEX_ARRAY            0x07
+/* These codes are used in the generation of the symbol definition records
+ */
+#define DBG$C_FUNCTION_PARAMETER       0xc9
+#define DBG$C_LOCAL_SYM                        0xd9
diff --git a/gnu/usr.bin/as/obstack.c b/gnu/usr.bin/as/obstack.c
new file mode 100644 (file)
index 0000000..c9cf561
--- /dev/null
@@ -0,0 +1,337 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+   Copyright (C) 1988 Free Software Foundation, Inc.
+
+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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "obstack.h"
+
+#ifdef __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment.  */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+   But in fact it might be less smart and round addresses to as much as
+   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+   On some machines, copying successive ints does not work;
+   in such a case, redefine COPYING_UNIT to `long' (if that works)
+   or `char' as a last resort.  */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+/* The non-GNU-C macros copy the obstack into this global variable
+   to avoid multiple evaluation.  */
+
+struct obstack *_obstack;
+\f
+/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
+   Objects start on multiples of ALIGNMENT (0 means use default).
+   CHUNKFUN is the function to use to allocate chunks,
+   and FREEFUN the function to free them.  */
+
+void
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+     struct obstack *h;
+     int size;
+     int alignment;
+     POINTER (*chunkfun) ();
+     void (*freefun) ();
+{
+  register struct _obstack_chunk* chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+        Use the values for range checking, because if range checking is off,
+        the extra bytes won't be missed terribly, but if range checking is on
+        and we used a larger request, a whole extra 4096 bytes would be
+        allocated.
+
+        These number are irrelevant to the new GNU malloc.  I suspect it is
+        less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+                   + 4 + DEFAULT_ROUNDING - 1)
+                  & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+  h->freefun = freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+
+  chunk        = h->chunk = (*h->chunkfun) (h->chunk_size);
+  h->next_free = h->object_base = chunk->contents;
+  h->chunk_limit = chunk->limit
+   = (char *) chunk + h->chunk_size;
+  chunk->prev = 0;
+}
+
+/* Allocate a new current chunk for the obstack *H
+   on the assumption that LENGTH bytes need to be added
+   to the current object, or a new object of length LENGTH allocated.
+   Copies any partial object from the end of the old chunk
+   to the beginning of the new one.  */
+
+void
+_obstack_newchunk (h, length)
+     struct obstack *h;
+     int length;
+{
+  register struct _obstack_chunk*      old_chunk = h->chunk;
+  register struct _obstack_chunk*      new_chunk;
+  register long        new_size;
+  register int obj_size = h->next_free - h->object_base;
+  register int i;
+  int already;
+
+  /* Compute size for new chunk.  */
+  new_size = (obj_size + length) + (obj_size >> 3) + 100;
+  if (new_size < h->chunk_size)
+    new_size = h->chunk_size;
+
+  /* Allocate and initialize the new chunk.  */
+  new_chunk = h->chunk = (*h->chunkfun) (new_size);
+  new_chunk->prev = old_chunk;
+  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+  /* Move the existing object to the new chunk.
+     Word at a time is fast and is safe if the object
+     is sufficiently aligned.  */
+  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+    {
+      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+          i >= 0; i--)
+       ((COPYING_UNIT *)new_chunk->contents)[i]
+         = ((COPYING_UNIT *)h->object_base)[i];
+      /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+        but that can cross a page boundary on a machine
+        which does not do strict alignment for COPYING_UNITS.  */
+      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+    }
+  else
+    already = 0;
+  /* Copy remaining bytes one by one.  */
+  for (i = already; i < obj_size; i++)
+    new_chunk->contents[i] = h->object_base[i];
+
+  /* If the object just copied was the only data in OLD_CHUNK,
+     free that chunk and remove it from the chain.  */
+  if (h->object_base == old_chunk->contents)
+    {
+      new_chunk->prev = old_chunk->prev;
+      (*h->freefun) (old_chunk);
+    }
+
+  h->object_base = new_chunk->contents;
+  h->next_free = h->object_base + obj_size;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+   This is here for debugging.
+   If you use it in a program, you are probably losing.  */
+
+int
+_obstack_allocated_p (h, obj)
+     struct obstack *h;
+     POINTER obj;
+{
+  register struct _obstack_chunk*  lp; /* below addr of any objects in this chunk */
+  register struct _obstack_chunk*  plp;        /* point to previous chunk if any */
+
+  lp = (h)->chunk;
+  while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj))
+    {
+      plp = lp -> prev;
+      lp = plp;
+    }
+  return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+   more recently than OBJ.  If OBJ is zero, free everything in H.  */
+
+void
+#ifdef __STDC__
+#undef obstack_free
+obstack_free (struct obstack *h, POINTER obj)
+#else
+_obstack_free (h, obj)
+     struct obstack *h;
+     POINTER obj;
+#endif
+{
+  register struct _obstack_chunk*  lp; /* below addr of any objects in this chunk */
+  register struct _obstack_chunk*  plp;        /* point to previous chunk if any */
+
+  lp = (h)->chunk;
+  /* We use >= because there cannot be an object at the beginning of a chunk.
+     But there can be an empty object at that address
+     at the end of another chunk.  */
+  while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+    {
+      plp = lp -> prev;
+      (*h->freefun) (lp);
+      lp = plp;
+    }
+  if (lp)
+    {
+      (h)->object_base = (h)->next_free = (char *)(obj);
+      (h)->chunk_limit = lp->limit;
+      (h)->chunk = lp;
+    }
+  else if (obj != 0)
+    /* obj is not in any of the chunks! */
+    abort ();
+}
+
+/* Let same .o link with output of gcc and other compilers.  */
+
+#ifdef __STDC__
+void
+_obstack_free (h, obj)
+     struct obstack *h;
+     POINTER obj;
+{
+  obstack_free (h, obj);
+}
+#endif
+\f
+#if 0
+/* These are now turned off because the applications do not use it
+   and it uses bcopy via obstack_grow, which causes trouble on sysV.  */
+
+/* Now define the functional versions of the obstack macros.
+   Define them to simply use the corresponding macros to do the job.  */
+
+#ifdef __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+   they won't pass through the macro names in parentheses.  */
+
+/* The function names appear in parentheses in order to prevent
+   the macro-definitions of the names from being expanded there.  */
+
+POINTER (obstack_base) (obstack)
+     struct obstack *obstack;
+{
+  return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+     struct obstack *obstack;
+{
+  return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+     struct obstack *obstack;
+{
+  return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+     struct obstack *obstack;
+{
+  return obstack_room (obstack);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+     struct obstack *obstack;
+     POINTER pointer;
+     int length;
+{
+  obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+     struct obstack *obstack;
+     POINTER pointer;
+     int length;
+{
+  obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+     struct obstack *obstack;
+     int character;
+{
+  obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+     struct obstack *obstack;
+     int length;
+{
+  obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+     struct obstack *obstack;
+     int character;
+{
+  obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+     struct obstack *obstack;
+     int length;
+{
+  obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+     struct obstack *obstack;
+{
+  return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+     struct obstack *obstack;
+     int length;
+{
+  return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+     struct obstack *obstack;
+     POINTER pointer;
+     int length;
+{
+  return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+     struct obstack *obstack;
+     POINTER pointer;
+     int length;
+{
+  return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
diff --git a/gnu/usr.bin/as/obstack.h b/gnu/usr.bin/as/obstack.h
new file mode 100644 (file)
index 0000000..fd779c4
--- /dev/null
@@ -0,0 +1,418 @@
+/* obstack.h - object stack macros
+   Copyright (C) 1988 Free Software Foundation, Inc.
+
+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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects.  Each object starts life
+small, and may grow to maturity.  (Consider building a word syllable
+by syllable.)  An object can move while it is growing.  Once it has
+been "finished" it never changes address again.  So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'.  On occasion, they free chunks,
+by calling `obstack_chunk_free'.  You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables.  Unless you are "fascist pig with a read-only mind"
+[Gosper's immortal quote from HAKMEM item 154, out of context] you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols.  At the time you are reading a symbol you don't know
+how long it is.  One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer.  This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently.  Use one obstack for all symbol
+names.  As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it.  Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses.  When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk.  When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies.  No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk.  We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object.  This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+       We allocate large chunks.
+       We carve out one object at a time from the current chunk.
+       Once carved, an object never moves.
+       We are free to append data of any size to the currently
+         growing object.
+       Exactly one object is growing in an obstack at any one time.
+       You can run one obstack per control block.
+       You may have as many control blocks as you dare.
+       Because of the way we do it, you can `unwind' a obstack
+         back to a previous state. (You may remove objects much
+         as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once.  */
+
+#ifndef __OBSTACKS__
+#define __OBSTACKS__
+\f
+/* We use subtraction of (char *)0 instead of casting to int
+   because on word-addressable machines a simple cast to int
+   may ignore the byte-within-word field of the pointer.  */
+
+#ifndef __PTR_TO_INT
+#define __PTR_TO_INT(P) ((P) - (char *)0)
+#endif
+
+#ifndef __INT_TO_PTR
+#define __INT_TO_PTR(P) ((P) + (char *)0)
+#endif
+
+struct _obstack_chunk          /* Lives at front of each chunk. */
+{
+  char  *limit;                        /* 1 past end of this chunk */
+  struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+  char contents[4];            /* objects begin here */
+};
+
+struct obstack         /* control current object in current chunk */
+{
+  long chunk_size;             /* preferred size to allocate chunks in */
+  struct _obstack_chunk* chunk;        /* address of current struct obstack_chunk */
+  char *object_base;           /* address of object we are building */
+  char *next_free;             /* where to add next char to current object */
+  char *chunk_limit;           /* address of char after current chunk */
+  int  temp;                   /* Temporary for some macros.  */
+  int   alignment_mask;                /* Mask of alignment for each object. */
+  struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk.  */
+  void (*freefun) ();          /* User's function to free a chunk.  */
+};
+
+/* Declare the external functions we use; they are in obstack.c.  */
+
+#ifdef __STDC__
+  extern void _obstack_newchunk (struct obstack *, int);
+  extern void _obstack_free (struct obstack *, void *);
+  extern void _obstack_begin (struct obstack *, int, int,
+                             void *(*) (), void (*) ());
+#else
+  extern void _obstack_newchunk ();
+  extern void _obstack_free ();
+  extern void _obstack_begin ();
+#endif
+\f
+#ifdef __STDC__
+
+/* Do the function-declarations after the structs
+   but before defining the macros.  */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+   so we do not declare them.  */
+\f
+/* Pointer to beginning of object being allocated or to be allocated next.
+   Note that this might not be the final address of the object
+   because a new chunk might be needed to hold the final size.  */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks.  */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk.  */
+
+#define obstack_next_free(h)   ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object.  */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+#define obstack_init(h) \
+  _obstack_begin ((h), 0, 0, \
+                 (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free)
+
+#define obstack_begin(h, size) \
+  _obstack_begin ((h), (size), 0, \
+                 (void *(*) ()) obstack_chunk_alloc, obstack_chunk_free)
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+\f
+#if defined (__GNUC__) && defined (__STDC__)
+
+/* For GNU C, if not -traditional,
+   we can define these macros to compute all args only once
+   without using a global variable.
+   Also, we can avoid using the `temp' slot, to make faster code.  */
+
+#define obstack_object_size(OBSTACK)                                   \
+  ({ struct obstack *__o = (OBSTACK);                                  \
+     (unsigned) (__o->next_free - __o->object_base); })
+
+#define obstack_room(OBSTACK)                                          \
+  ({ struct obstack *__o = (OBSTACK);                                  \
+     (unsigned) (__o->chunk_limit - __o->next_free); })
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+   so that we can avoid having void expressions
+   in the arms of the conditional expression.
+   Casting the third operand to void was tried before,
+   but some compilers won't accept it.  */
+#define obstack_grow(OBSTACK,where,length)                             \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   ((__o->next_free + __len > __o->chunk_limit)                                \
+    ? (_obstack_newchunk (__o, __len), 0) : 0);                                \
+   bcopy (where, __o->next_free, __len);                               \
+   __o->next_free += __len;                                            \
+   (void) 0; })
+
+#define obstack_grow0(OBSTACK,where,length)                            \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   ((__o->next_free + __len + 1 > __o->chunk_limit)                    \
+    ? (_obstack_newchunk (__o, __len + 1), 0) : 0),                    \
+   bcopy (where, __o->next_free, __len),                               \
+   __o->next_free += __len,                                            \
+   *(__o->next_free)++ = 0;                                            \
+   (void) 0; })
+
+#define obstack_1grow(OBSTACK,datum)                                   \
+({ struct obstack *__o = (OBSTACK);                                    \
+   ((__o->next_free + 1 > __o->chunk_limit)                            \
+    ? (_obstack_newchunk (__o, 1), 0) : 0),                            \
+   *(__o->next_free)++ = (datum);                                      \
+   (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+   and that the data added so far to the current object
+   shares that much alignment.  */
+   
+#define obstack_ptr_grow(OBSTACK,datum)                                        \
+({ struct obstack *__o = (OBSTACK);                                    \
+   ((__o->next_free + sizeof (void *) > __o->chunk_limit)              \
+    ? (_obstack_newchunk (__o, sizeof (void *)), 0) : 0),              \
+   *((void **)__o->next_free)++ = ((void *)datum);                     \
+   (void) 0; })
+
+#define obstack_int_grow(OBSTACK,datum)                                        \
+({ struct obstack *__o = (OBSTACK);                                    \
+   ((__o->next_free + sizeof (int) > __o->chunk_limit)                 \
+    ? (_obstack_newchunk (__o, sizeof (int)), 0) : 0),                 \
+   *((int *)__o->next_free)++ = ((int)datum);                          \
+   (void) 0; })
+
+#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(OBSTACK,length)                                  \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   ((__o->chunk_limit - __o->next_free < __len)                                \
+    ? (_obstack_newchunk (__o, __len), 0) : 0);                                \
+   __o->next_free += __len;                                            \
+   (void) 0; })
+
+#define obstack_alloc(OBSTACK,length)                                  \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_blank (__h, (length));                                      \
+   obstack_finish (__h); })
+
+#define obstack_copy(OBSTACK,where,length)                             \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_grow (__h, (where), (length));                              \
+   obstack_finish (__h); })
+
+#define obstack_copy0(OBSTACK,where,length)                            \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_grow0 (__h, (where), (length));                             \
+   obstack_finish (__h); })
+
+#define obstack_finish(OBSTACK)                                        \
+({ struct obstack *__o = (OBSTACK);                                    \
+   void *value = (void *) __o->object_base;                            \
+   __o->next_free                                                      \
+     = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\
+                    & ~ (__o->alignment_mask));                        \
+   ((__o->next_free - (char *)__o->chunk                               \
+     > __o->chunk_limit - (char *)__o->chunk)                          \
+    ? (__o->next_free = __o->chunk_limit) : 0);                                \
+   __o->object_base = __o->next_free;                                  \
+   value; })
+
+#define obstack_free(OBSTACK, OBJ)                                     \
+({ struct obstack *__o = (OBSTACK);                                    \
+   void *__obj = (OBJ);                                                        \
+   if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
+     __o->next_free = __o->object_base = __obj;                                \
+   else (obstack_free) (__o, __obj); })
+\f
+#else /* not __GNUC__ or not __STDC__ */
+
+#define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+#define obstack_room(h)                \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+#define obstack_grow(h,where,length)                                   \
+( (h)->temp = (length),                                                        \
+  (((h)->next_free + (h)->temp > (h)->chunk_limit)                     \
+   ? (_obstack_newchunk ((h), (h)->temp), 0) : 0),                     \
+  bcopy (where, (h)->next_free, (h)->temp),                            \
+  (h)->next_free += (h)->temp)
+
+#define obstack_grow0(h,where,length)                                  \
+( (h)->temp = (length),                                                        \
+  (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit)                 \
+   ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0),                 \
+  bcopy (where, (h)->next_free, (h)->temp),                            \
+  (h)->next_free += (h)->temp,                                         \
+  *((h)->next_free)++ = 0)
+
+#define obstack_1grow(h,datum)                                         \
+( (((h)->next_free + 1 > (h)->chunk_limit)                             \
+   ? (_obstack_newchunk ((h), 1), 0) : 0),                             \
+  *((h)->next_free)++ = (datum))
+
+#define obstack_ptr_grow(h,datum)                                      \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit)               \
+   ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),               \
+  *((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum))
+
+#define obstack_int_grow(h,datum)                                      \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit)                  \
+   ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),                  \
+  *((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum))
+
+#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr)
+#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+
+#define obstack_blank(h,length)                                                \
+( (h)->temp = (length),                                                        \
+  (((h)->chunk_limit - (h)->next_free < (h)->temp)                     \
+   ? (_obstack_newchunk ((h), (h)->temp), 0) : 0),                     \
+  (h)->next_free += (h)->temp)
+
+#define obstack_alloc(h,length)                                                \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+#define obstack_copy(h,where,length)                                   \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_copy0(h,where,length)                                  \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+#define obstack_finish(h)                                              \
+( (h)->temp = __PTR_TO_INT ((h)->object_base),                         \
+  (h)->next_free                                                       \
+    = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask)        \
+                   & ~ ((h)->alignment_mask)),                         \
+  (((h)->next_free - (char *)(h)->chunk                                        \
+    > (h)->chunk_limit - (char *)(h)->chunk)                           \
+   ? ((h)->next_free = (h)->chunk_limit) : 0),                         \
+  (h)->object_base = (h)->next_free,                                   \
+  __INT_TO_PTR ((h)->temp))
+
+#ifdef __STDC__
+#define obstack_free(h,obj)                                            \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk,                     \
+  (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+   ? (int) ((h)->next_free = (h)->object_base                          \
+           = (h)->temp + (char *) (h)->chunk)                          \
+   : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+#else
+#define obstack_free(h,obj)                                            \
+( (h)->temp = (char *)(obj) - (char *) (h)->chunk,                     \
+  (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+   ? (int) ((h)->next_free = (h)->object_base                          \
+           = (h)->temp + (char *) (h)->chunk)                          \
+   : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+#endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#endif /* not __OBSTACKS__ */
diff --git a/gnu/usr.bin/as/output-file.c b/gnu/usr.bin/as/output-file.c
new file mode 100644 (file)
index 0000000..ff71f40
--- /dev/null
@@ -0,0 +1,81 @@
+/* output-file.c -  Deal with the output file
+   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.  */
+
+/*
+ * 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!
+ */
+
+/* #include "style.h" */
+#include <stdio.h>
+
+void   as_perror();
+
+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);
+    }
+}
+
+
+
+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! */
+}
+
+void
+output_file_append (where, length, filename)
+     char *            where;
+     long int          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");
+       }
+    }
+}
+
+/* end: output-file.c */
diff --git a/gnu/usr.bin/as/read.c b/gnu/usr.bin/as/read.c
new file mode 100644 (file)
index 0000000..8357107
--- /dev/null
@@ -0,0 +1,2188 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)read.c     6.4 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* read.c - read a source file -
+   Copyright (C) 1986,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 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 <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "as.h"
+#include "read.h"
+#include "md.h"
+#include "hash.h"
+#include "obstack.h"
+#include "frags.h"
+#include "flonum.h"
+#include "struc-symbol.h"
+#include "expr.h"
+#include "symbols.h"
+
+#ifdef SPARC
+#include "sparc.h"
+#define OTHER_ALIGN
+#endif
+#ifdef I860
+#include "i860.h"
+#endif
+
+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: TRUE if this character ends a line.
+ */
+#define _ (0)
+const char is_end_of_line [256] = {
+ _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
+ _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _  /*                  */
+};
+#undef _
+
+                               /* Functions private to this file. */
+void                   equals();
+void                   big_cons();
+void                   cons();
+static char*           demand_copy_C_string();
+static char*           demand_copy_string();
+void                   demand_empty_rest_of_line();
+void                   float_cons();
+long int               get_absolute_expression();
+static char            get_absolute_expression_and_terminator();
+static segT            get_known_segmented_expression();
+void                   ignore_rest_of_line();
+static int             is_it_end_of_statement();
+static void            pobegin();
+static void            pseudo_set();
+static void            stab();
+static void            stringer();
+
+extern char line_comment_chars[];
+
+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;
+
+#ifndef WORKING_DOT_WORD
+struct broken_word *broken_words;
+int new_broken_words = 0;
+#endif
+
+static void grow_bignum ();
+static int next_char_of_string ();
+\f
+void
+read_begin()
+{
+  pobegin();
+  obstack_begin( &notes, 5000 );
+#define BIGNUM_BEGIN_SIZE (16)
+  bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
+  bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
+}
+\f
+/* set up pseudo-op tables */
+
+static struct hash_control *
+po_hash = NULL;                        /* use before set up: NULL-> address error */
+
+
+void   s_abort(),      s_align(),      s_comm(),       s_data();
+void   s_desc(),       s_even(),       s_file(),       s_fill();
+void   s_globl(),      s_lcomm(),      s_line(),       s_lsym();
+void   s_org(),        s_set(),        s_space(),      s_text();
+#ifdef VMS
+char const_flag = 0;
+void s_const();
+#endif
+
+#ifdef DONTDEF
+void   s_gdbline(),    s_gdblinetab();
+void   s_gdbbeg(),     s_gdbblock(),   s_gdbend(),     s_gdbsym();
+#endif
+
+void   stringer();
+void   cons();
+void   float_cons();
+void   big_cons();
+void   stab();
+
+static const pseudo_typeS
+potable[] =
+{
+  { "abort",   s_abort,        0       },
+  { "align",   s_align,        0       },
+  { "ascii",   stringer,       0       },
+  { "asciz",   stringer,       1       },
+  { "byte",    cons,           1       },
+  { "comm",    s_comm,         0       },
+#ifdef VMS
+  { "const",   s_const,        0       },
+#endif
+  { "data",    s_data,         0       },
+  { "desc",    s_desc,         0       },
+  { "double",  float_cons,     'd'     },
+  { "file",    s_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
+  { "globl",   s_globl,        0       },
+  { "int",     cons,           4       },
+  { "lcomm",   s_lcomm,        0       },
+  { "line",    s_line,         0       },
+  { "long",    cons,           4       },
+  { "lsym",    s_lsym,         0       },
+  { "octa",    big_cons,       16      },
+  { "org",     s_org,          0       },
+  { "quad",    big_cons,       8       },
+  { "set",     s_set,          0       },
+  { "short",   cons,           2       },
+  { "single",  float_cons,     'f'     },
+  { "space",   s_space,        0       },
+  { "stabd",   stab,           'd'     },
+  { "stabn",   stab,           'n'     },
+  { "stabs",   stab,           's'     },
+  { "text",    s_text,         0       },
+#ifndef SPARC
+  { "word",    cons,           2       },
+#endif
+  { NULL}      /* end sentinel */
+};
+
+static void
+pobegin()
+{
+  char *       errtxt;         /* error text */
+  const pseudo_typeS * pop;
+
+  po_hash = hash_new();
+  errtxt = "";                 /* OK so far */
+  for (pop=potable; pop->poc_name && !*errtxt; pop++)
+    {
+      errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
+    }
+
+  for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++)
+      errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
+
+  if (*errtxt)
+    {
+      as_fatal ("error constructing pseudo-op table");
+    }
+}                              /* pobegin() */
+\f
+/*                     read_a_source_file()
+ *
+ * File has already been opened, and will be closed by our caller.
+ *
+ * We read the file, putting things into a web that
+ * represents what we have been reading.
+ */
+void
+read_a_source_file (buffer)
+     char *    buffer;         /* 1st character of each buffer of lines is here. */
+{
+  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
+
+  subseg_new (SEG_TEXT, 0);
+  while ( buffer_limit = input_scrub_next_buffer (&buffer) )
+    {                          /* We have another line to parse. */
+      know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */
+      input_line_pointer = buffer;
+ 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 ();
+           }
+         /*
+          * 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 */
+             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 == ':' )
+               {
+                 if (flagseen['g'])
+                   /* set line number for function definition */
+                   funcstab(s);
+                 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);
+
+                               /* 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 seperates keyword from operands. */
+                     if ( c == ' ' || c == '\t' )
+                       {       /* Skip seperator after keyword. */
+                         input_line_pointer ++;
+                       }
+                     /*
+                      * 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);
+                   }
+                 else
+                   {           /* machine instruction */
+                     /* If source file debugging, emit a stab. */
+                     if (flagseen['g'])
+                       linestab();
+
+                     /* 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] )
+           {                   /* empty statement */
+             continue;
+           }
+
+         if ( isdigit(c) )
+           {                   /* local label  ("4:") */
+             temp = c - '0';
+#ifdef SUN_ASM_SYNTAX
+             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;
+           }
+         if(c && index(line_comment_chars,c)) {        /* Its a comment.  Better say APP or NO_APP */
+               char *ends;
+               char *strstr();
+               char    *new_buf;
+               char    *new_tmp;
+               int     new_length;
+               char    *tmp_buf = 0;
+               extern char *scrub_string,*scrub_last_string;
+               int     scrub_from_string();
+               void    scrub_to_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;
+         }
+
+         as_bad("Junk character %d.",c);
+         ignore_rest_of_line();
+       }                       /* while (input_line_pointer<buffer_limit )*/
+       if(old_buffer) {
+               bump_line_counters();
+               if(old_input == 0)
+                       return;
+               buffer=old_buffer;
+               input_line_pointer=old_input;
+               buffer_limit=old_limit;
+               old_buffer = 0;
+               goto contin;
+       }
+    }                          /* while (more bufrers to scan) */
+}                              /* read_a_source_file() */
+
+void
+s_abort()
+{
+       as_fatal(".abort detected.  Abandoning ship.");
+}
+
+#ifdef OTHER_ALIGN
+static void
+s_align()
+{
+    register unsigned int temp;
+    register long int temp_fill;
+    unsigned int i;
+
+    temp = get_absolute_expression ();
+#define MAX_ALIGNMENT (1 << 15)
+    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();
+}
+#else
+
+void
+s_align()
+{
+       register int temp;
+       register long int temp_fill;
+
+       temp = get_absolute_expression ();
+#define MAX_ALIGNMENT (15)
+       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);
+       demand_empty_rest_of_line();
+}
+#endif
+
+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");
+               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 (   (symbolP -> sy_type & N_TYPE) != N_UNDF ||
+ symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) {
+               as_warn( "Ignoring attempt to re-define symbol");
+               ignore_rest_of_line();
+               return;
+       }
+       if (symbolP -> sy_value) {
+               if (symbolP -> sy_value != temp)
+                       as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
+ symbolP -> sy_name, symbolP -> sy_value, temp);
+       } else {
+               symbolP -> sy_value = temp;
+               symbolP -> sy_type |= N_EXT;
+       }
+#ifdef VMS
+       if(!temp)
+               symbolP->sy_other = const_flag;
+#endif
+       know( symbolP -> sy_frag == &zero_address_frag );
+       demand_empty_rest_of_line();
+}
+
+#ifdef VMS
+void
+s_const()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       subseg_new (SEG_DATA, (subsegT)temp);
+       const_flag = 1;
+       demand_empty_rest_of_line();
+}
+#endif
+
+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_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;
+       symbolP = symbol_table_lookup (name);
+       * 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;
+               symbolP -> sy_desc = temp;
+       }
+       demand_empty_rest_of_line();
+}
+
+void
+s_file()
+{
+       register char *s;
+       int     length;
+
+       /* Some assemblers tolerate immediately following '"' */
+       if ( s = demand_copy_string( & length ) ) {
+               new_logical_line (s, -1);
+               demand_empty_rest_of_line();
+       }
+}
+
+void
+s_fill()
+{
+       long int temp_repeat;
+       long int temp_size;
+       register long int temp_fill;
+       char    *p;
+
+       if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) {
+               input_line_pointer --; /* Backup over what was not a ','. */
+               as_warn("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_warn("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 int) temp, frag_now, (long int)(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_warn( "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 int) temp, (long int) 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 int) temp, frag_now, (long int)(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_warn("Expected comma after name");
+               ignore_rest_of_line();
+               return;
+       }
+       input_line_pointer ++;
+       if ( (temp = get_absolute_expression ()) < 0 ) {
+               as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
+               ignore_rest_of_line();
+               return;
+       }
+       if (flagseen ['G'])
+               gdb_symbols_fixup (symbolP, (long int)temp);
+       demand_empty_rest_of_line ();
+}
+
+void
+s_gdbline()
+{
+       int     file_number,
+               lineno;
+
+       if(get_absolute_expression_and_terminator(&file_number) != ',') {
+               as_warn("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_warn("expected comman 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();
+               symbolP -> sy_type |= N_EXT;
+               if(c==',') {
+                       input_line_pointer++;
+                       SKIP_WHITESPACE();
+                       if(*input_line_pointer=='\n')
+                               c='\n';
+               }
+       } while(c==',');
+       demand_empty_rest_of_line();
+}
+
+void
+s_lcomm()
+{
+       register char *name;
+       register char c;
+       register char *p;
+       register int temp;
+       register symbolS *      symbolP;
+
+       name = input_line_pointer;
+       c = get_symbol_end();
+       p = input_line_pointer;
+       *p = c;
+       SKIP_WHITESPACE();
+       if ( * input_line_pointer != ',' ) {
+               as_warn("Expected comma after name");
+               ignore_rest_of_line();
+               return;
+       }
+       input_line_pointer ++;
+       if ( (temp = get_absolute_expression ()) < 0 ) {
+               as_warn("BSS length (%d.) <0! Ignored.", temp);
+               ignore_rest_of_line();
+               return;
+       }
+       *p = 0;
+       symbolP = symbol_find_or_make (name);
+       *p = c;
+       if (   symbolP -> sy_other == 0
+           && symbolP -> sy_desc  == 0
+           && (   (   symbolP -> sy_type  == N_BSS
+           && symbolP -> sy_value == local_bss_counter)
+           || (   (symbolP -> sy_type & N_TYPE) == N_UNDF
+           && symbolP -> sy_value == 0))) {
+               symbolP -> sy_value = local_bss_counter;
+               symbolP -> sy_type  = N_BSS;
+               symbolP -> sy_frag  = & bss_address_frag;
+               local_bss_counter += temp;
+       } else
+               as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
+ symbolP -> sy_value, local_bss_counter );
+       demand_empty_rest_of_line();
+}
+
+void
+s_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();
+}
+
+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 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_warn("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) {
+               as_bad("Bad expression: %s", seg_name [(int)segment]);
+               ignore_rest_of_line();
+               return;
+       }
+ know(   segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS );
+       *p = 0;
+       symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
+ 0, 0, (valueT)(exp . X_add_number), & zero_address_frag);
+       *p = c;
+       demand_empty_rest_of_line();
+}
+
+void
+s_org()
+{
+       register segT segment;
+       expressionS exp;
+       register long int 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==TRUE.
+ */
+       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_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
+ seg_name [(int) segment], seg_name [(int) 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();
+}
+
+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_warn("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_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
+                     seg_name [(int) segment], seg_name [(int) 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;
+       }
+       symbolP = symbol_find_or_make (name);
+       *end_name = delim;
+       pseudo_set (symbolP);
+       demand_empty_rest_of_line ();
+}
+
+void
+s_space()
+{
+       long int temp_repeat;
+       register long int 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();
+}
+
+void
+s_text()
+{
+       register int temp;
+
+       temp = get_absolute_expression ();
+       subseg_new (SEG_TEXT, (subsegT)temp);
+       demand_empty_rest_of_line();
+}
+
+\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])
+    {
+      as_warn("Rest of line ignored. 1st junk character valued %d (%c)."
+             , * input_line_pointer, *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]] );
+}
+\f
+/*
+ *                     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
+stab (what)
+int what;
+{
+  register symbolS *   symbolP;
+  register char *      string;
+          int          saved_type;
+          int          length;
+          int          goof;   /* TRUE if we have aborted. */
+          long int     longint;
+
+/*
+ * Enter with input_line_pointer pointing past .stabX and any following
+ * whitespace.
+ */
+       goof = FALSE; /* JF who forgot this?? */
+       if (what == 's') {
+               string = demand_copy_C_string (& length);
+               SKIP_WHITESPACE();
+               if (* input_line_pointer == ',')
+                       input_line_pointer ++;
+               else {
+                       as_warn( "I need a comma after symbol's name" );
+                       goof = TRUE;
+               }
+       } else
+               string = "";
+
+/*
+ * Input_line_pointer->after ','.  String -> symbol name.
+ */
+       if (! goof) {
+               symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0);
+               switch (what) {
+               case 'd':
+                       symbolP->sy_name = NULL; /* .stabd feature. */
+                       symbolP->sy_value = 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_type = saved_type = longint;
+               else {
+                       as_warn( "I want a comma after the n_type expression" );
+                       goof = TRUE;
+                       input_line_pointer --; /* Backup over a non-',' char. */
+               }
+       }
+       if (! goof) {
+               if (get_absolute_expression_and_terminator (& longint) == ',')
+                       symbolP->sy_other = longint;
+               else {
+                       as_warn( "I want a comma after the n_other expression" );
+                       goof = TRUE;
+                       input_line_pointer --; /* Backup over a non-',' char. */
+               }
+       }
+       if (! goof) {
+               symbolP->sy_desc = get_absolute_expression ();
+               if (what == 's' || what == 'n') {
+                       if (* input_line_pointer != ',') {
+                               as_warn( "I want a comma after the n_desc expression" );
+                               goof = TRUE;
+                       } else {
+                               input_line_pointer ++;
+                       }
+               }
+       }
+       if ((! goof) && (what=='s' || what=='n')) {
+               pseudo_set (symbolP);
+               symbolP->sy_type = saved_type;
+       }
+       if (goof)
+               ignore_rest_of_line ();
+       else
+               demand_empty_rest_of_line ();
+}
+\f
+/*
+ *                     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 sy_type, sy_value, sy_frag;
+ *     May set need_pass_2 == TRUE.
+ */
+static void
+pseudo_set (symbolP)
+     symbolS * symbolP;
+{
+  expressionS  exp;
+  register segT        segment;
+  int ext;
+
+  know( symbolP );             /* NULL pointer is logic error. */
+  ext=(symbolP->sy_type&N_EXT);
+  if ((segment = expression( & exp )) == SEG_NONE)
+    {
+      as_warn( "Missing expression: absolute 0 assumed" );
+      exp . X_seg              = SEG_ABSOLUTE;
+      exp . X_add_number       = 0;
+    }
+  switch (segment)
+    {
+    case SEG_BIG:
+      as_warn( "%s number illegal. Absolute 0 assumed.",
+             exp . X_add_number > 0 ? "Bignum" : "Floating-Point" );
+      symbolP -> sy_type = N_ABS | ext;
+      symbolP -> sy_value = 0;
+      symbolP -> sy_frag = & zero_address_frag;
+      break;
+
+    case SEG_NONE:
+      as_warn("No expression:  Using absolute 0");
+      symbolP -> sy_type = N_ABS | ext;
+      symbolP -> sy_value = 0;
+      symbolP -> sy_frag = & zero_address_frag;
+      break;
+
+    case SEG_DIFFERENCE:
+      if (exp.X_add_symbol && exp.X_subtract_symbol
+          &&    (exp.X_add_symbol->sy_type & N_TYPE)
+            == (exp.X_subtract_symbol->sy_type & N_TYPE)) {
+       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.",exp.X_add_symbol->sy_name, exp.X_subtract_symbol->sy_name);
+         need_pass_2++;
+       }
+       exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value;
+      } else
+       as_warn( "Complex expression. Absolute segment assumed." );
+    case SEG_ABSOLUTE:
+      symbolP -> sy_type = N_ABS | ext;
+      symbolP -> sy_value = exp . X_add_number;
+      symbolP -> sy_frag = & zero_address_frag;
+      break;
+    case SEG_DATA:
+    case SEG_TEXT:
+    case SEG_BSS:
+      symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext;
+      symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value;
+      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_warn("Unknown expression");
+      know( need_pass_2 == TRUE );
+      break;
+      
+    case SEG_UNKNOWN:
+      symbolP->sy_forward=exp.X_add_symbol;
+      /* as_warn("unknown symbol"); */
+      /* need_pass_2 = TRUE; */
+      break;
+      
+    default:
+      BAD_CASE( segment );
+      break;
+    }
+}
+\f
+/*
+ * stabs(file), stabf(func) and stabd(line) -- for the purpose of
+ * source file debugging of assembly files, generate file,
+ * function and line number stabs, respectively.
+ * These functions have corresponding functions named
+ * filestab(), funcstab() and linestab() in input-scrub.c,
+ * where logical files and logical line numbers are handled.
+ */
+
+#include <stab.h>
+
+stabs(file)
+     char *file;
+{
+  /* .stabs "file",100,0,0,. */
+  (void) symbol_new(file,
+                   N_SO,
+                   0,
+                   0,
+                   obstack_next_free(& frags) - frag_now->fr_literal,
+                   frag_now);
+}
+
+stabf(func)
+     char *func;
+{
+  symbolS *symbolP;
+  static int void_undefined = 1;
+
+  /* crudely filter uninteresting labels: require an initial '_' */
+  if (*func++ != '_')
+    return;
+
+  /* assembly functions are assumed to have void type */
+  if (void_undefined)
+    {
+      /* .stabs "void:t15=15",128,0,0,0 */
+      (void) symbol_new("void:t1=1",
+                       N_LSYM,
+                       0,
+                       0,
+                       0,
+                       &zero_address_frag);
+      void_undefined = 0;
+    }
+
+  /* .stabs "func:F1",36,0,0,. */
+  symbolP = symbol_new((char *) 0,
+                      N_FUN,
+                      0,
+                      0,
+                      obstack_next_free(& frags) - frag_now->fr_literal,
+                      frag_now);
+  obstack_grow(&notes, func, strlen(func));
+  obstack_1grow(&notes, ':');
+  obstack_1grow(&notes, 'F');
+  obstack_1grow(&notes, '1');
+  obstack_1grow(&notes, '\0');
+  symbolP->sy_name = obstack_finish(&notes);
+}
+
+stabd(line)
+     unsigned line;
+{
+  /* .stabd 68,0,line */
+  (void) symbol_new((char *)0,
+                   N_SLINE,
+                   0,
+                   line,
+                   obstack_next_free(& frags) - frag_now->fr_literal,
+                   frag_now);
+}
+\f
+/*
+ *                     cons()
+ *
+ * CONStruct more frag of .bytes, or .words etc.
+ * Should need_pass_2 be TRUE 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.
+ */
+void
+cons(nbytes)                   /* worker to do .byte etc statements */
+                               /* clobbers input_line_pointer, checks */
+                               /* end-of-line. */
+     register int      nbytes; /* 1=.byte, 2=.word, 4=.long */
+{
+  register char                c;
+  register long int    mask;   /* High-order bits we will left-truncate, */
+                               /* but includes sign bit also. */
+  register long int     get;   /* what we get */
+  register long int    use;    /* get after truncation. */
+  register long int    unmask; /* what bits we will store */
+  register char *      p;
+  register segT                segment;
+           expressionS exp;
+#ifdef NS32K
+  void fix_new_ns32k();
+#else
+  void fix_new();
+#endif
+
+  /*
+   * 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 int))
+    mask = 0;
+  else 
+    mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
+  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 = ',';                 /* Do loop. */
+  while ( c == ','  )
+    {
+      segment = expression( &exp ); /* At least scan over the expression. */
+      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_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
+                     exp . X_subtract_symbol -> sy_name,
+                     seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]);
+             segment = SEG_ABSOLUTE;
+             /* Leave exp . X_add_number alone. */
+           }
+         p = frag_more (nbytes);
+         switch (segment)
+           {
+           case SEG_BIG:
+             as_warn( "%s number illegal. Absolute 0 assumed.",
+                     exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
+             md_number_to_chars (p, (long)0, nbytes);
+             break;
+
+           case SEG_NONE:
+             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:
+#if defined(SPARC) || defined(I860)
+             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
+#ifdef 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);
+#endif
+#if !defined(SPARC) && !defined(NS32K) && !defined(I860)
+             fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
+                      exp . X_add_symbol, exp . X_subtract_symbol,
+                      exp . X_add_number, 0);
+#endif
+             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 == TRUE, 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"...
+ */
+void
+big_cons(nbytes)               /* worker to do .quad etc statements */
+                               /* clobbers input_line_pointer, checks */
+                               /* end-of-line. */
+     register int      nbytes; /* 8=.quad 16=.octa ... */
+{
+  register char                c;      /* input_line_pointer -> c. */
+  register int         radix;
+  register long int    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_warn( "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 int     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() */
+
+static void
+grow_bignum()                  /* Extend bignum by 1 char. */
+{
+  register long int    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 == TRUE, 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 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_warn( "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 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 ( (c = next_char_of_string()) >= 0)
+           {
+             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
+static int
+next_char_of_string ()
+{
+  register int c;
+
+  c = * input_line_pointer ++;
+  switch (c)
+    {
+    case '\"':
+      c = -1;
+      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;
+
+       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 int number;
+
+           for (number = 0;   isdigit(c);   c = * input_line_pointer ++)
+             {
+               number = number * 8 + c - '0';
+             }
+           c = number;
+         }
+         -- input_line_pointer;
+         break;
+
+       case '\n':
+/*       as_fatal( "Unterminated string - use app!" ); */
+/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
+         c = '\n';
+         break;
+
+       default:
+         as_warn( "Bad escaped character in string, '?' assumed" );
+         c = '?';
+         break;
+       }
+      break;
+
+    default:
+      break;
+    }
+  return (c);
+}
+\f
+static segT
+get_segmented_expression ( expP )
+     register expressionS *    expP;
+{
+  register segT                retval;
+
+  if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG )
+    {
+      as_warn("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 ? expP -> X_add_symbol -> sy_name : "";
+      name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : "";
+      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 int /* 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_NONE )
+       {
+         as_warn( "Bad Absolute Expression, absolute 0 assumed.");
+       }
+      exp . X_add_number = 0;
+    }
+  return (exp . X_add_number);
+}
+
+static char                    /* return terminator */
+get_absolute_expression_and_terminator( val_pointer)
+     long int *                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.
+ */
+static char *
+demand_copy_C_string (len_pointer)
+     int *     len_pointer;
+{
+  register char *      s;
+
+  if (s = demand_copy_string (len_pointer))
+    {
+      register int     len;
+
+      for (len = * len_pointer;
+          len > 0;
+          len--)
+       {
+         if (* s == 0)
+           {
+             s = 0;
+             len = 1;
+             * len_pointer = 0;
+             as_warn( "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 int         c;
+  register int         len;
+          char *       retval;
+
+  len = 0;
+  SKIP_WHITESPACE();
+  if (* input_line_pointer == '\"')
+    {
+      input_line_pointer ++;   /* Skip opening quote. */
+      while ( (c = next_char_of_string()) >= 0 ) {
+         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);
+}
+\f
+/*
+ *             is_it_end_of_statement()
+ *
+ * In: Input_line_pointer -> next character.
+ *
+ * Do: Skip input_line_pointer over all whitespace.
+ *
+ * Out:        TRUE if input_line_pointer -> end-of-line.
+ */
+static int
+is_it_end_of_statement()
+{
+  SKIP_WHITESPACE();
+  return (is_end_of_line [* input_line_pointer]);
+}
+
+void
+equals(sym_name)
+char *sym_name;
+{
+  register struct symbol * 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.",
+                seg_name [(int) segment], seg_name [(int) 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);
+  }
+}
+
+/* end: read.c */
diff --git a/gnu/usr.bin/as/read.h b/gnu/usr.bin/as/read.h
new file mode 100644 (file)
index 0000000..6b46e8f
--- /dev/null
@@ -0,0 +1,47 @@
+/* read.h - of read.c
+   Copyright (C) 1986 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 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() ASSERT( * 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       )
+
+extern const char lex_type[];
+
+void           read_begin();
+void           read_end();
+void           read_a_source_file();
+
+/* end: read.h */
diff --git a/gnu/usr.bin/as/struc-symbol.h b/gnu/usr.bin/as/struc-symbol.h
new file mode 100644 (file)
index 0000000..11eab6b
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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.  */
+
+#ifndef                VMS
+#include "a.out.gnu.h"         /* Needed to define struct nlist. Sigh. */
+#else
+#include "a_out.h"
+#endif
+
+struct symbol                  /* our version of an nlist node */
+{
+  struct nlist sy_nlist;       /* what we write in .o file (if permitted) */
+  long unsigned 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 int     sy_number;      /* 24 bit symbol number. */
+                               /* Symbol numbers start at 0 and are */
+                               /* unsigned. */
+  struct symbol * sy_next;     /* forward chain, or NULL */
+  struct frag *        sy_frag;        /* NULL or -> frag this symbol attaches to. */
+  struct symbol *sy_forward;   /* value is really that of this other symbol */
+};
+
+typedef struct symbol symbolS;
+
+#define sy_name                sy_nlist .n_un. n_name
+                               /* Name field always points to a string. */
+                               /* 0 means .stabd-like anonymous symbol. */
+#define sy_type        sy_nlist.       n_type
+#define sy_other       sy_nlist.       n_other
+#define sy_desc                sy_nlist.       n_desc
+#define sy_value       sy_nlist.       n_value
+                               /* Value of symbol is this value + object */
+                               /* file address of sy_frag. */
+
+typedef unsigned valueT;       /* The type of n_value. Helps casting. */
+
+/* end: struct_symbol.h */
+#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
diff --git a/gnu/usr.bin/as/subsegs.c b/gnu/usr.bin/as/subsegs.c
new file mode 100644 (file)
index 0000000..c9eea3d
--- /dev/null
@@ -0,0 +1,292 @@
+/* subsegs.c - subsegments -
+   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.  */
+
+/*
+ * Segments & sub-segments.
+ */
+
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+#include "frags.h"
+#include "struc-symbol.h"
+#include "write.h"
+
+frchainS*      frchain_root,
+       *       frchain_now,    /* Commented in "subsegs.h". */
+       *       data0_frchainP;
+
+
+const int                              /* in: segT   out: N_TYPE bits */
+seg_N_TYPE[] = {
+  N_ABS,
+  N_TEXT,
+  N_DATA,
+  N_BSS,
+  N_UNDF,
+  N_UNDF,
+  N_UNDF,
+  N_UNDF,
+  N_UNDF,
+  N_UNDF
+};
+
+
+char * const                           /* in: segT   out: char* */
+seg_name[] = {
+  "absolute",
+  "text",
+  "data",
+  "bss",
+  "unknown",
+  "absent",
+  "pass1",
+  "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
+  "bignum/flonum",
+  "difference",
+  ""
+  };                           /* Used by error reporters, dumpers etc. */
+
+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_GOOF, SEG_GOOF
+};
+\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_NONE       ==5 );
+  know( SEG_PASS1      ==6 );
+  know( SEG_GOOF       ==7 );
+  know( SEG_BIG                ==8 );
+  know( SEG_DIFFERENCE ==9 );
+  know( SEG_MAXIMUM_ORDINAL == SEG_DIFFERENCE );
+  know( seg_name [(int) 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;
+    }
+  else
+    {
+      know (seg == SEG_TEXT);
+      seg_fix_rootP = & text_fix_root;
+    }
+}
+\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() */
+
+/* end: subsegs.c */
diff --git a/gnu/usr.bin/as/subsegs.h b/gnu/usr.bin/as/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/gnu/usr.bin/as/symbols.c b/gnu/usr.bin/as/symbols.c
new file mode 100644 (file)
index 0000000..ce7197a
--- /dev/null
@@ -0,0 +1,438 @@
+/* symbols.c -symbol table-
+   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"
+#include "hash.h"
+#include "obstack.h"           /* For "symbols.h" */
+#include "struc-symbol.h"
+#include "symbols.h"
+#include "frags.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;
+struct obstack notes;
+
+
+
+symbolS * symbol_find();       /* Keep C compiler happy. */
+
+/*
+ * 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 SUN_ASM_SYNTAX
+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));
+  abs_symbol . sy_type = N_ABS;        /* 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 )
+    {
+    }
+  /* The label, as a '\0' ended string, starts at symbol_name_build. */
+  return (symbol_name_build);
+}
+
+
+void
+local_colon (n)
+     int               n;      /* just saw "n:" */
+{
+  local_label_counter [n] ++;
+#ifdef SUN_ASM_SYNTAX
+  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.
+ */
+
+symbolS *
+symbol_new (name, type, other, desc, value, frag)
+     char *            name;   /* We copy this: OK to alter your copy. */
+     unsigned char     type;   /* As in <a.out.h>. */
+     char              other;  /* As in <a.out.h>. */
+     short int         desc;   /* As in <a.out.h>. */
+     valueT            value;  /* As in <a.out.h>, often an address. */
+                               /* Often used as offset from frag address. */
+     struct frag *     frag;   /* For sy_frag. */
+{
+  register symbolS *           symbolP;
+  register char *              preserved_copy_of_name;
+  register unsigned int                name_length;
+           char *              p;
+
+  name_length = strlen(name) + 1;
+  obstack_grow(&notes,name,name_length);
+  p=obstack_finish(&notes);
+  /* obstack_1done( &notes, name, name_length, &p ); */
+  preserved_copy_of_name = p;
+  p=obstack_alloc(&notes,sizeof(struct symbol));
+  /* obstack_1blank( &notes, sizeof(struct symbol), &p ); */
+  symbolP                      = (symbolS *) p;
+  symbolP -> sy_name           = preserved_copy_of_name;
+  symbolP -> sy_type           = type;
+  symbolP -> sy_other          = other;
+  symbolP -> sy_desc           = desc;
+  symbolP -> sy_value          = value;
+  symbolP -> sy_frag           = frag;
+  symbolP -> sy_next           = NULL; /* End of chain. */
+  symbolP -> sy_forward                = NULL; /* JF */
+#ifdef SUSPECT
+  symbolP -> sy_name_offset    = ~ 0; /* Impossible offset catches errors. */
+  symbolP -> sy_number         = ~ 0; /* Ditto. */
+#endif
+  /*
+   * Link to end of symbol chain.
+   */
+  if (symbol_lastP)
+    {
+      symbol_lastP -> sy_next = symbolP;
+    }
+  else
+    {
+      symbol_rootP = symbolP;
+    }
+  symbol_lastP = symbolP;
+
+  return (symbolP);
+}
+\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 struct symbol * symbolP; /* symbol we are working with */
+
+#ifdef SUN_ASM_SYNTAX
+  /* Sun local labes 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,(long int)0,(char *)0);
+
+    /* 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_table_lookup( sym_name ))
+    {
+#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 ((seg_N_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)) &&
+         (symbolP->sy_value == 0)) {
+             symbolP -> sy_frag  = frag_now;
+             symbolP -> sy_other = const_flag;
+             symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
+             symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
+             return;
+      }
+#endif /* VMS */
+      /*
+       *       Now check for undefined symbols
+       */
+      if ((symbolP -> sy_type & N_TYPE) == N_UNDF)
+       {
+         if(   symbolP -> sy_other == 0
+            && symbolP -> sy_desc  == 0
+            && symbolP -> sy_value == 0)
+           {
+             symbolP -> sy_frag  = frag_now;
+#ifdef VMS
+               symbolP -> sy_other = const_flag;
+#endif
+             symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
+             know( N_UNDF == 0 );
+             symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
+           }
+         else
+           {
+#ifdef VMS
+             /*
+              *        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
+              */
+             char New_Type = seg_N_TYPE [(int) now_seg];
+             if (((symbolP->sy_type == (N_UNDF | N_EXT)) ||
+                  (symbolP->sy_type == N_BSS)) &&
+                 (((New_Type & ~N_EXT) == N_DATA) ||
+                  (New_Type == symbolP->sy_type))) {
+                       /*
+                        *      Select which of the 2 cases this is
+                        */
+                       if (New_Type == symbolP->sy_type) {
+                               /*
+                                *      If the new size is larger we just
+                                *      change its value.  If the new size
+                                *      is smaller, we ignore this symbol
+                                */
+                               if (symbolP->sy_value <
+                                       (obstack_next_free(& frags) -
+                                               frag_now -> fr_literal)) {
+                                     symbolP -> sy_value = 
+                                       obstack_next_free(& frags) -
+                                               frag_now -> fr_literal;
+                               }
+                       } else {
+                               /*
+                                *      It is a .comm/.lcomm being converted
+                                *      to initialized data.
+                                */
+                               symbolP -> sy_frag  = frag_now;
+                               symbolP -> sy_other = const_flag;
+                               symbolP -> sy_value = obstack_next_free(& frags) - frag_now -> fr_literal;
+                               symbolP -> sy_type |= seg_N_TYPE [(int) now_seg]; /* keep N_EXT bit */
+                       }
+             } else {
+#endif /* VMS */
+             as_fatal( "Symbol \"%s\" is already defined as \"%s\"/%d.%d.%d.",
+                     sym_name,
+                     seg_name [(int) N_TYPE_seg [symbolP -> sy_type & N_TYPE]],
+                     symbolP -> sy_other, symbolP -> sy_desc,
+                     symbolP -> sy_value);
+#ifdef VMS
+               }
+#endif /* VMS */
+           }
+       }
+      else
+       {
+         as_fatal("Symbol %s already defined.",sym_name);
+       }
+    }
+  else
+    {
+      symbolP = symbol_new (sym_name,
+                           (unsigned char)(seg_N_TYPE [(int) now_seg]),
+#ifdef VMS
+                           const_flag,
+#else
+                           0,
+#endif
+                           0,
+                           (valueT)(obstack_next_free(&frags)-frag_now->fr_literal),
+                           frag_now);
+      symbol_table_insert (symbolP);
+    }
+}
+
+\f
+/*
+ *                     symbol_table_insert()
+ *
+ * Die if we can't insert the symbol.
+ *
+ */
+
+void
+symbol_table_insert (symbolP)
+     struct symbol *   symbolP;
+{
+  register char *      error_string;
+
+  know( symbolP );
+  know( symbolP -> sy_name );
+  if ( * (error_string = hash_jam (sy_hash, symbolP -> sy_name, (char *)symbolP)))
+    {
+      as_fatal( "Inserting \"%s\" into symbol table failed: %s",
+             symbolP -> sy_name, error_string);
+    }
+}
+\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_table_lookup (name);
+  if (symbolP == NULL)
+    {
+      symbolP = symbol_new (name, N_UNDF, 0, 0, 0, & zero_address_frag);
+      symbol_table_insert (symbolP);
+    }
+  return (symbolP);
+}
+
+/*
+ *                     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;
+{
+  return ( (symbolS *) hash_find( sy_hash, name ));
+}
+
+
+/* end: symbols.c */
diff --git a/gnu/usr.bin/as/symbols.h b/gnu/usr.bin/as/symbols.h
new file mode 100644 (file)
index 0000000..5a52790
--- /dev/null
@@ -0,0 +1,42 @@
+/* symbols.h -
+   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  notes; /* eg FixS live here. */
+
+#define symbol_table_lookup(name) ((symbolS *)(symbol_find (name)))
+
+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;
+
+symbolS *      symbol_find();
+void           symbol_begin();
+char *         local_label_name();
+void           local_colon();
+symbolS *      symbol_new();
+void           colon();
+void           symbol_table_insert();
+symbolS *      symbol_find_or_make();
+
+/* end: symbols.h */
diff --git a/gnu/usr.bin/as/version.c b/gnu/usr.bin/as/version.c
new file mode 100644 (file)
index 0000000..f94d3f4
--- /dev/null
@@ -0,0 +1,23 @@
+#if defined(__STDC__) || defined(const)
+const
+#endif
+char version_string[] = "GNU assembler version 1.38\n";
+\f
+/* DO NOT PUT COMMENTS ABOUT CHANGES IN THIS FILE.
+
+   This file exists only to define `version_string'.
+
+   Log changes in ChangeLog.  The easiest way to do this is with
+   the Emacs command `add-change-log-entry'.  If you don't use Emacs,
+   add entries of the form:
+
+Thu Jan  1 00:00:00 1970  Dennis Ritchie  (dmr at alice)
+
+       * universe.c (temporal_reality): Began Time.
+*/
+
+#ifdef VMS
+dummy3()
+{
+}
+#endif
diff --git a/gnu/usr.bin/as/write.c b/gnu/usr.bin/as/write.c
new file mode 100644 (file)
index 0000000..a850555
--- /dev/null
@@ -0,0 +1,1259 @@
+/* write.c - emit .o file - Copyright(C)1986 Free Software Foundation, Inc.
+   Copyright (C) 1986,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.  */
+
+/* 
+
+   Umm, with real good luck, this thing should be set up to do byteordering
+   correctly, but I may have managed to miss a place or two.  Treat a.out
+   very carefully until you're SURE that it works. . .
+
+   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 "md.h"
+#include "subsegs.h"
+#include "obstack.h"
+#include "struc-symbol.h"
+#include "write.h"
+#include "symbols.h"
+
+#ifdef SPARC
+#include "sparc.h"
+#endif
+#ifdef I860
+#include "i860.h"
+#endif
+
+void   append();
+
+#ifdef hpux
+#define EXEC_MACHINE_TYPE HP9000S200_ID
+#endif
+
+#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 */
+
+/*
+ * 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
+  };
+
+
+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 struct exec     the_exec;
+
+static long int string_byte_count;
+
+static char *          the_object_file;
+
+#if !defined(SPARC) && !defined(I860)
+static
+#endif
+char *         next_object_file_charP; /* Tracks object file bytes. */
+
+static long int                size_of_the_object_file; /* # bytes in object file. */
+
+/* static long int             length; JF unused */    /* String length, including trailing '\0'. */
+
+static void    relax_segment();
+void           emit_segment();
+static relax_addressT  relax_align();
+static long int        fixup_segment();
+#if !defined(SPARC) && !defined(I860)
+static void            emit_relocations();
+#endif
+\f/*
+ *                     fix_new()
+ *
+ * Create a fixS in obstack 'notes'.
+ */
+void
+#if defined(SPARC) || defined(I860)
+fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+#else
+fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel)
+#endif
+     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 int  offset;         /* X_add_number. */
+     int       pcrel;          /* TRUE if PC-relative relocation. */
+#if defined(SPARC) || defined(I860)
+    int                r_type;
+#endif
+{
+  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_next      = * seg_fix_rootP;
+
+  /* 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 defined(SPARC) || defined(I860)
+  fixP->fx_r_type = r_type;
+#endif
+
+  * seg_fix_rootP = 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;
+  register symbolS *           symbolP;
+  register symbolS **          symbolPP;
+  /* register fixS *           fixP; JF unused */
+  unsigned
+       text_siz,
+       data_siz,
+       syms_siz,
+       tr_siz,
+       dr_siz;
+  void output_file_create();
+  void output_file_append();
+  void output_file_close();
+#ifdef DONTDEF
+  void gdb_emit();
+  void gdb_end();
+#endif
+  extern long omagic;          /* JF magic # to write out.  Is different for
+                                  Suns and Vaxen and other boxes */
+
+#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. */
+    }
+\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;
+           }
+       }
+    }                          /* for(each struct frchain) */
+
+  /*
+   * 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 );
+  text_siz=text_last_frag->fr_address;
+#ifdef SPARC
+  text_siz= (text_siz+7)&(~7);
+  text_last_frag->fr_address=text_siz;
+#endif
+  md_number_to_chars((char *)&the_exec.a_text,text_siz, sizeof(the_exec.a_text));
+  /* the_exec . a_text = text_last_frag -> fr_address; */
+\f
+  /*
+   * 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 );
+      data_siz=data_last_frag->fr_address;
+#ifdef SPARC
+      data_siz += (8 - (data_siz % 8)) % 8;
+      data_last_frag->fr_address = data_siz;
+#endif
+      md_number_to_chars((char *)&the_exec.a_data,data_siz,sizeof(the_exec.a_data));
+      /* the_exec . a_data = data_last_frag -> fr_address; */
+      slide = text_siz; /* Address 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 {
+      md_number_to_chars((char *)&the_exec.a_data,0,sizeof(the_exec.a_data));
+      data_siz = 0;
+  }
+
+  bss_address_frag . fr_address = text_siz + data_siz;
+#ifdef SPARC
+  local_bss_counter=(local_bss_counter+7)&(~7);
+#endif
+  md_number_to_chars((char *)&the_exec.a_bss,local_bss_counter,sizeof(the_exec.a_bss));
+
+             
+  /*
+   *
+   * 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.
+   *
+   * Count the (length of the nlists of the) (remaining) symbols.
+   * Assign a symbol number to each symbol.
+   * Count the number of string-table chars we will emit.
+   *
+   */
+  know( zero_address_frag . fr_address == 0 );
+  string_byte_count = sizeof( string_byte_count );
+
+  /* JF deal with forward references first. . . */
+  for(symbolP=symbol_rootP;symbolP;symbolP=symbolP->sy_next) {
+       if(symbolP->sy_forward) {
+               symbolP->sy_value+=symbolP->sy_forward->sy_value+symbolP->sy_forward->sy_frag->fr_address;
+               symbolP->sy_forward=0;
+       }
+  }
+  symbolPP = & symbol_rootP;   /* -> last symbol chain link. */
+  {
+    register long int          symbol_number;
+
+    symbol_number = 0;
+    while (symbolP  = * symbolPP)
+      {
+       name = symbolP -> sy_name;
+       if(flagseen['R'] && (symbolP->sy_nlist.n_type&N_DATA)) {
+         symbolP->sy_nlist.n_type&= ~N_DATA;
+         symbolP->sy_nlist.n_type|= N_TEXT;
+       }
+       /* if(symbolP->sy_forward) {
+         symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address;
+       } */
+       
+       symbolP -> sy_value += symbolP -> sy_frag -> fr_address;
+               /* JF the 128 bit is a hack so stabs like
+                  "LET_STMT:23. . ."  don't go away */
+       /* CPH: 128 bit hack is moby loser.  N_SO for file "Lower.c"
+          fell through the cracks.  I think that N_STAB should be
+          used instead of 128. */
+               /* JF the \001 bit is to make sure that local labels
+                  ( 1: - 9: don't make it into the symtable either */
+#ifndef        VMS     /* Under VMS we need to keep local symbols */
+       if ( !name || (symbolP->sy_nlist.n_type&N_STAB)
+           || (name[2]!='\001' && (flagseen ['L'] || ! LOCAL_LABEL(name) )))
+#endif /* not VMS */
+         {
+           symbolP -> sy_number = symbol_number ++;
+#ifndef        VMS
+           if (name)
+             {                 /* Ordinary case. */
+               symbolP -> sy_name_offset = string_byte_count;
+               string_byte_count += strlen (symbolP  -> sy_name) + 1;
+             }
+           else                        /* .Stabd case. */
+#endif /* not VMS */
+               symbolP -> sy_name_offset = 0;
+           symbolPP = & (symbolP -> sy_next);
+         }
+#ifndef        VMS
+       else
+           * symbolPP = symbolP -> sy_next;
+#endif /* not VMS */
+      }                                /* for each symbol */
+
+    syms_siz = sizeof( struct nlist) * symbol_number;
+    md_number_to_chars((char *)&the_exec.a_syms,syms_siz,sizeof(the_exec.a_syms));
+    /* the_exec . a_syms = sizeof( struct nlist) * symbol_number; */
+  }
+
+  /*
+   * 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) {
+#if defined(SPARC) || defined(I860)
+         fix_new(      lie->frag,  lie->word_goes_here - lie->frag->fr_literal,
+                       2,  lie->add,
+                       lie->sub,  lie->addnum,
+                       0,  NO_RELOC);
+#endif
+#ifdef 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);
+#endif
+#if !defined(SPARC) && !defined(NS32K) && !defined(I860)
+         fix_new(      lie->frag,  lie->word_goes_here - lie->frag->fr_literal,
+                       2,  lie->add,
+                       lie->sub,  lie->addnum,
+                       0);
+#endif
+         /* md_number_to_chars(lie->word_goes_here,
+                              lie->add->sy_value
+                              + lie->addnum
+                              - (lie->sub->sy_value),
+                            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;
+       void    md_create_short_jump();
+       void    md_create_long_jump();
+
+
+
+       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
+                   - (lie->sub->sy_value);
+         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=lie->add->sy_value+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
+#ifndef        VMS
+  /*
+   * Scan every FixS performing fixups. We had to wait until now to do
+   * this because md_convert_frag() may have made some fixSs.
+   */
+  /* the_exec . a_trsize
+    = sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT);
+  the_exec . a_drsize
+    = sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA); */
+
+  tr_siz=sizeof(struct relocation_info) * fixup_segment (text_fix_root, N_TEXT);
+  md_number_to_chars((char *)&the_exec.a_trsize, tr_siz ,sizeof(the_exec.a_trsize));
+  dr_siz=sizeof(struct relocation_info) * fixup_segment (data_fix_root, N_DATA);
+  md_number_to_chars((char *)&the_exec.a_drsize, dr_siz, sizeof(the_exec.a_drsize));
+  md_number_to_chars((char *)&the_exec.a_info,omagic,sizeof(the_exec.a_info));
+  md_number_to_chars((char *)&the_exec.a_entry,0,sizeof(the_exec.a_entry));
+
+#ifdef EXEC_MACHINE_TYPE
+  md_number_to_chars((char *)&the_exec.a_machtype, EXEC_MACHINE_TYPE, sizeof(the_exec.a_machtype));
+#endif
+#ifdef EXEC_VERSION
+  md_number_to_chars((char *)&the_exec.a_version,EXEC_VERSION,sizeof(the_exec.a_version));
+#endif
+  
+  /* the_exec . a_entry = 0; */
+
+  size_of_the_object_file =
+    sizeof( the_exec ) +
+      text_siz +
+        data_siz +
+         syms_siz +
+           tr_siz +
+             dr_siz +
+               string_byte_count;
+       
+  next_object_file_charP
+    = the_object_file
+      = xmalloc ( size_of_the_object_file );
+
+  output_file_create (out_file_name);
+
+  append (& next_object_file_charP, (char *)(&the_exec), (unsigned long)sizeof(the_exec));
+\f
+  /*
+   * Emit code.
+   */
+  for (fragP = text_frag_root;  fragP;  fragP = fragP -> fr_next)
+    {
+      register long int                count;
+      register char *          fill_literal;
+      register long int                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.
+   */
+  emit_relocations (text_fix_root, (relax_addressT)0);
+  emit_relocations (data_fix_root, text_last_frag -> fr_address);
+  /*
+   * Emit all symbols left in the symbol chain.
+   * Any symbol still undefined is made N_EXT.
+   */
+  for (   symbolP = symbol_rootP;   symbolP;   symbolP = symbolP -> sy_next   )
+    {
+      register char *  temp;
+
+      temp = symbolP -> sy_nlist . n_un . n_name;
+      /* JF fix the numbers up. Call by value RULES! */
+      md_number_to_chars((char *)&(symbolP -> sy_nlist  . n_un . n_strx ),symbolP -> sy_name_offset,sizeof(symbolP -> sy_nlist  . n_un . n_strx ));
+      md_number_to_chars((char *)&(symbolP->sy_nlist.n_desc),symbolP->sy_nlist.n_desc,sizeof(symbolP -> sy_nlist  . n_desc));
+      md_number_to_chars((char *)&(symbolP->sy_nlist.n_value),symbolP->sy_nlist.n_value,sizeof(symbolP->sy_nlist.n_value));
+      /* symbolP -> sy_nlist  . n_un . n_strx = symbolP -> sy_name_offset; JF replaced by md above */
+      if (symbolP -> sy_type == N_UNDF)
+         symbolP -> sy_type |= N_EXT; /* Any undefined symbols become N_EXT. */
+      append (& next_object_file_charP, (char *)(& symbolP -> sy_nlist),
+             (unsigned long)sizeof(struct nlist));
+      symbolP -> sy_nlist . n_un . n_name = temp;
+    }                          /* for each symbol */
+
+  /*
+   * next_object_file_charP -> slot for next object byte.
+   * Emit strings.
+   * Find strings by crawling along symbol table chain.
+   */
+/* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */
+  md_number_to_chars((char *)&string_byte_count, string_byte_count, sizeof(string_byte_count));
+
+  append (& next_object_file_charP, (char *)&string_byte_count, (unsigned long)sizeof(string_byte_count));
+  for (   symbolP = symbol_rootP;   symbolP;   symbolP = symbolP -> sy_next   )
+    {
+      if (symbolP -> sy_name)
+       {                       /* Ordinary case: not .stabd. */
+         append (& next_object_file_charP, symbolP -> sy_name,
+                 (unsigned long)(strlen (symbolP -> sy_name) + 1));
+       }
+    }                          /* for each symbol */
+
+  know( next_object_file_charP == the_object_file + size_of_the_object_file );
+
+  output_file_append (the_object_file, size_of_the_object_file, out_file_name);
+
+#ifdef DONTDEF
+  if (flagseen['G'])           /* GDB symbol file to be appended? */
+    {
+      gdb_emit (out_file_name);
+      gdb_end ();
+    }
+#endif
+
+  output_file_close (out_file_name);
+#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() */
+\f
+/*
+ *                     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; /* N_DATA or N_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, seg_N_TYPE [(int) 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 int  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 int 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 int   growth;
+           register long int   was_address;
+           /* register long int        var; */
+           register long int   offset;
+           register symbolS *  symbolP;
+           register long int   target;
+           register long int   after;
+           register long int   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+lie->add->sy_value + lie->addnum -
+                               (lie->sub->sy_frag->fr_address+lie->sub->sy_value);
+                       if(offset<=-32768 || offset>=32767) {
+                               if(flagseen['k'])
+                                       as_warn(".word %s-%s+%ld didn't fit",lie->add->sy_name,lie->sub->sy_name,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 && untruth->add->sy_value==lie->add->sy_value) {
+                                               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(   ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type & N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT));
+                   know( symbolP -> sy_frag );
+                   know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag );
+                   target +=
+                     symbolP -> sy_value
+                       + 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(   ((symbolP -> sy_type & N_TYPE) == N_ABS) || ((symbolP -> sy_type &
+ N_TYPE) == N_DATA) || ((symbolP -> sy_type & N_TYPE) == N_TEXT));
+                   know( symbolP -> sy_frag );
+                   know( (symbolP->sy_type&N_TYPE)!=N_ABS || symbolP->sy_frag==&zero_address_frag );
+                   target +=
+                     symbolP -> sy_value
+                       + 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 NS32K
+                 aim += fragP->fr_pcrel_adjust;
+#endif
+
+                 if (aim < 0)
+                   {
+                     /* Look backwards. */
+                     for (next_state = this_type -> rlx_more;  next_state;  )
+                       {
+                         if (aim >= this_type -> rlx_backward)
+                             next_state = 0;
+                         else
+                           {   /* Grow to next state. */
+                             this_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)
+                     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.
+ */
+
+static relax_addressT          /* How many addresses does the .align take? */
+relax_align (address, alignment)
+     register relax_addressT   address; /* Address now. */
+     register long int         alignment; /* Alignment (binary). */
+{
+  relax_addressT       mask;
+  relax_addressT       new_address;
+
+  mask = ~ ( (~0) << alignment );
+  new_address = (address + mask) & (~ mask);
+  return (new_address - address);
+}
+\f
+/*
+ *                     fixup_segment()
+ */
+static long int
+fixup_segment (fixP, this_segment_type)
+     register fixS *   fixP;
+     int               this_segment_type; /* N_TYPE bits for segment. */
+{
+  register long int            seg_reloc_count;
+               /* JF these all used to be local to the for loop, but GDB doesn't seem to be able to deal with them there, so I moved them here for a bit. */
+      register symbolS *       add_symbolP;
+      register symbolS *       sub_symbolP;
+      register long int                add_number;
+      register int             size;
+      register char *          place;
+      register long int                where;
+      register char            pcrel;
+      register fragS *         fragP;
+      register int             add_symbol_N_TYPE;
+
+
+  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;
+      sub_symbolP = fixP  -> fx_subsy;
+      add_number  = fixP  -> fx_offset;
+      pcrel      = fixP  -> fx_pcrel;
+      if(add_symbolP)
+       add_symbol_N_TYPE = add_symbolP -> sy_type & N_TYPE;
+      if (sub_symbolP)
+       {
+         if(!add_symbolP)      /* Its just -sym */
+           {
+             if(sub_symbolP->sy_type!=N_ABS)
+               as_warn("Negative of non-absolute symbol %s", sub_symbolP->sy_name);
+             add_number-=sub_symbolP->sy_value;
+           }
+         else if (   ((sub_symbolP -> sy_type ^ add_symbol_N_TYPE) & N_TYPE) == 0
+             && (   add_symbol_N_TYPE == N_DATA
+                 || add_symbol_N_TYPE == N_TEXT
+                 || add_symbol_N_TYPE == N_BSS
+                 || add_symbol_N_TYPE == N_ABS))
+           {
+             /* Difference of 2 symbols from same segment. */
+             /* Can't make difference of 2 undefineds: 'value' means */
+             /* something different for N_UNDF. */
+             add_number += add_symbolP -> sy_value - sub_symbolP -> sy_value;
+             add_symbolP = NULL;
+             fixP -> fx_addsy = NULL;
+           }
+         else
+           {
+             /* Different segments in subtraction. */
+             know( sub_symbolP -> sy_type != (N_ABS | N_EXT))
+               if (sub_symbolP -> sy_type == N_ABS)
+                   add_number -= sub_symbolP -> sy_value;
+               else
+                 {
+                          as_warn("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+                                   seg_name[(int)N_TYPE_seg[sub_symbolP->sy_type&N_TYPE]],
+                                   sub_symbolP -> sy_name, fragP -> fr_address + where);
+                 }
+           }
+       }
+      if (add_symbolP)
+       {
+         if (add_symbol_N_TYPE == 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.
+              */
+             add_number += add_symbolP -> sy_value;
+             add_number -=
+#ifndef NS32K
+                     size +
+#endif
+                     where + fragP -> fr_address;
+#if defined(NS32K) && defined(SEQUENT_COMPATABILITY)
+             if (fragP->fr_bsr)
+               add_number -= 0x12;     /* FOO Kludge alert! */
+#endif
+               /* Kenny thinks this needs *
+               /* add_number +=size-2; */
+             pcrel = 0;        /* Lie. Don't want further pcrel processing. */
+             fixP -> fx_addsy = NULL; /* No relocations please. */
+             /*
+              * It would be nice to check that the address does not overflow.
+              * I didn't do this check because:
+              * +  It is machine dependent in the general case (eg 32032)
+              * +  Compiler output will never need this checking, so why
+              *    slow down the usual case?
+              */
+           }
+         else
+           {
+             switch (add_symbol_N_TYPE)
+               {
+               case N_ABS:
+                 add_number += add_symbolP -> sy_value;
+                 fixP -> fx_addsy = NULL;
+                 add_symbolP = NULL;
+                 break;
+                 
+               case N_BSS:
+               case N_DATA:
+               case N_TEXT:
+                 seg_reloc_count ++;
+                 add_number += add_symbolP -> sy_value;
+                 break;
+                 
+               case N_UNDF:
+                 seg_reloc_count ++;
+                 break;
+                 
+               default:
+                 BAD_CASE( add_symbol_N_TYPE );
+                 break;
+               }               /* switch on symbol seg */
+           }                   /* if not in local seg */
+       }                       /* if there was a + symbol */
+      if (pcrel)
+       {
+         add_number -=
+#ifndef NS32K
+                 size + 
+#endif
+                 where + fragP -> fr_address;
+         if (add_symbolP == 0)
+           {
+             fixP -> fx_addsy = & abs_symbol;
+             seg_reloc_count ++;
+           }
+       }
+      /* OVE added fx_im_disp for ns32k and others */
+      if (!fixP->fx_bit_fixP) {
+       /* JF I hope this works . . . */
+       if((size==1 && (add_number& ~0xFF)   && (add_number&~0xFF!=(-1&~0xFF))) ||
+          (size==2 && (add_number& ~0xFFFF) && (add_number&~0xFFFF!=(-1&~0xFFFF))))
+         as_warn("Fixup of %d too large for field width of %d",add_number, size);
+
+       switch (fixP->fx_im_disp) {
+       case 0:
+#if defined(SPARC) || defined(I860)
+         fixP->fx_addnumber = add_number;
+         md_number_to_imm(place, add_number, size, fixP, this_segment_type);
+#else
+         md_number_to_imm (place, add_number, size);
+         /* OVE: the immediates, like disps, have lsb at lowest address */
+#endif
+         break;
+       case 1:
+         md_number_to_disp (place,
+                            fixP->fx_pcrel ? add_number+fixP->fx_pcrel_adjust:add_number,
+                            size);
+         break;
+       case 2: /* fix requested for .long .word etc */
+         md_number_to_chars (place, add_number, size);
+         break;
+       default:
+         as_fatal("Internal error in write.c in fixup_segment");
+       } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */
+      } else {
+       md_number_to_field (place, add_number, fixP->fx_bit_fixP);
+      }
+    }                          /* For each fixS in this segment. */
+  return (seg_reloc_count);
+}                              /* fixup_segment() */
+\f
+
+/* The sparc needs its own emit_relocations() */
+#if !defined(SPARC) && !defined(I860)
+/*
+ *             emit_relocations()
+ *
+ * Crawl along a fixS chain. Emit the segment's relocations.
+ */
+static void
+emit_relocations (fixP, segment_address_in_file)
+     register fixS *   fixP;   /* Fixup chain for this segment. */
+     relax_addressT    segment_address_in_file;
+{
+  struct relocation_info       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)
+       {
+
+#ifdef NS32K
+               /* These two 'cuz of NS32K */
+         ri . r_bsr            = fixP -> fx_bsr;
+         ri . r_disp           = fixP -> fx_im_disp;
+#endif
+
+         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 ((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;
+           }
+
+         /* 
+           The 68k machines assign bit-fields from higher bits to 
+           lower bits ("left-to-right") within the int.  VAXen assign 
+           bit-fields from lower bits to higher bits ("right-to-left").
+           Both handle multi-byte numbers in their usual fashion
+           (Big-endian and little-endian stuff).
+           Thus we need a machine dependent routine to make
+           sure the structure is written out correctly.  FUN!
+          */
+         md_ri_to_chars((char *) &ri, ri); 
+         append (&next_object_file_charP, (char *)& ri, (unsigned long)sizeof(ri));
+       }
+    }
+
+}
+#endif
+
+int
+is_dnrange(f1,f2)
+struct frag *f1,*f2;
+{
+       while(f1) {
+               if(f1->fr_next==f2)
+                       return 1;
+               f1=f1->fr_next;
+       }
+       return 0;
+}
+/* End: as-write.c */
diff --git a/gnu/usr.bin/as/write.h b/gnu/usr.bin/as/write.h
new file mode 100644 (file)
index 0000000..7327690
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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.  */
+
+/* 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 int             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 int             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 */
+#if defined(SPARC) || defined(I860)
+  char                 fx_r_type;      /* Sparc hacks */
+  long                 fx_addnumber;
+#endif
+};
+
+typedef struct fix     fixS;
+
+
+COMMON fixS *  text_fix_root;  /* Chains fixSs. */
+COMMON fixS *  data_fix_root;  /* Chains fixSs. */
+COMMON fixS ** seg_fix_rootP;  /* -> one of above. */
+
+bit_fixS *bit_fix_new();
+/* end: write.h */
+
diff --git a/gnu/usr.bin/as/xmalloc.c b/gnu/usr.bin/as/xmalloc.c
new file mode 100644 (file)
index 0000000..78c8c7f
--- /dev/null
@@ -0,0 +1,60 @@
+/* xmalloc.c - get memory or bust
+   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.  */
+
+/*
+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()
+
+*/
+#ifdef USG
+#include <malloc.h>
+#endif
+
+char * xmalloc(n)
+     long n;
+{
+  char *       retval;
+  char *       malloc();
+  void error();
+
+  if ( ! (retval = malloc ((unsigned)n)) )
+    {
+      error("virtual memory exceeded");
+    }
+  return (retval);
+}
+
+/* end: xmalloc.c */
diff --git a/gnu/usr.bin/as/xrealloc.c b/gnu/usr.bin/as/xrealloc.c
new file mode 100644 (file)
index 0000000..a5010bc
--- /dev/null
@@ -0,0 +1,61 @@
+/* xrealloc.c -new memory or bust-
+   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.  */
+
+
+/* 
+
+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 USG
+#include <malloc.h>
+#endif
+
+char   *
+xrealloc (ptr, n)
+register char  *ptr;
+long    n;
+{
+    char   *realloc ();
+    void       error();
+
+    if ((ptr = realloc (ptr, (unsigned)n)) == 0)
+       error ("virtual memory exceeded");
+    return (ptr);
+}
+
+/* end: xrealloc.c */