summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gnu/usr.bin/as/COPYING249
-rw-r--r--gnu/usr.bin/as/ChangeLog917
-rw-r--r--gnu/usr.bin/as/Makefile15
-rw-r--r--gnu/usr.bin/as/Makefile.gnu356
-rw-r--r--gnu/usr.bin/as/NOTES35
-rw-r--r--gnu/usr.bin/as/README.gnu133
-rw-r--r--gnu/usr.bin/as/app.c392
-rw-r--r--gnu/usr.bin/as/append.c37
-rw-r--r--gnu/usr.bin/as/as.10
-rw-r--r--gnu/usr.bin/as/as.1aout0
-rw-r--r--gnu/usr.bin/as/as.c324
-rw-r--r--gnu/usr.bin/as/as.h292
-rw-r--r--gnu/usr.bin/as/atof-generic.c526
-rw-r--r--gnu/usr.bin/as/bignum-copy.c75
-rw-r--r--gnu/usr.bin/as/bignum.h48
-rw-r--r--gnu/usr.bin/as/config/Makefile.i3864
-rw-r--r--gnu/usr.bin/as/config/a.out.gnu.h261
-rw-r--r--gnu/usr.bin/as/config/atof-ieee.c505
-rw-r--r--gnu/usr.bin/as/config/i386-opcode.h806
-rw-r--r--gnu/usr.bin/as/config/i386.c1946
-rw-r--r--gnu/usr.bin/as/config/i386.h296
-rw-r--r--gnu/usr.bin/as/expr.c980
-rw-r--r--gnu/usr.bin/as/expr.h69
-rw-r--r--gnu/usr.bin/as/flonum-const.c157
-rw-r--r--gnu/usr.bin/as/flonum-copy.c76
-rw-r--r--gnu/usr.bin/as/flonum-mult.c200
-rw-r--r--gnu/usr.bin/as/flonum.h111
-rw-r--r--gnu/usr.bin/as/frags.c292
-rw-r--r--gnu/usr.bin/as/frags.h41
-rw-r--r--gnu/usr.bin/as/hash.c981
-rw-r--r--gnu/usr.bin/as/hash.h59
-rw-r--r--gnu/usr.bin/as/hex-value.c55
-rw-r--r--gnu/usr.bin/as/input-file.c306
-rw-r--r--gnu/usr.bin/as/input-file.h57
-rw-r--r--gnu/usr.bin/as/input-scrub.c427
-rw-r--r--gnu/usr.bin/as/md.h57
-rw-r--r--gnu/usr.bin/as/messages.c238
-rw-r--r--gnu/usr.bin/as/objrecdef.h255
-rw-r--r--gnu/usr.bin/as/obstack.c337
-rw-r--r--gnu/usr.bin/as/obstack.h418
-rw-r--r--gnu/usr.bin/as/output-file.c81
-rw-r--r--gnu/usr.bin/as/read.c2188
-rw-r--r--gnu/usr.bin/as/read.h47
-rw-r--r--gnu/usr.bin/as/struc-symbol.h72
-rw-r--r--gnu/usr.bin/as/subsegs.c292
-rw-r--r--gnu/usr.bin/as/subsegs.h65
-rw-r--r--gnu/usr.bin/as/symbols.c438
-rw-r--r--gnu/usr.bin/as/symbols.h42
-rw-r--r--gnu/usr.bin/as/version.c23
-rw-r--r--gnu/usr.bin/as/write.c1259
-rw-r--r--gnu/usr.bin/as/write.h77
-rw-r--r--gnu/usr.bin/as/xmalloc.c60
-rw-r--r--gnu/usr.bin/as/xrealloc.c61
53 files changed, 17038 insertions, 0 deletions
diff --git a/gnu/usr.bin/as/COPYING b/gnu/usr.bin/as/COPYING
new file mode 100644
index 0000000..9a17037
--- /dev/null
+++ b/gnu/usr.bin/as/COPYING
@@ -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.
+
+ 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.
+
+ 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.
+
+ 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
+
+ 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
index 0000000..3e0e64f
--- /dev/null
+++ b/gnu/usr.bin/as/ChangeLog
@@ -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.
+
+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
index 0000000..e75351b6
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile
@@ -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
index 0000000..4b81b0c
--- /dev/null
+++ b/gnu/usr.bin/as/Makefile.gnu
@@ -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
index 0000000..b3f3f92
--- /dev/null
+++ b/gnu/usr.bin/as/NOTES
@@ -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
index 0000000..46f135fc
--- /dev/null
+++ b/gnu/usr.bin/as/README.gnu
@@ -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
index 0000000..a0ec8a2
--- /dev/null
+++ b/gnu/usr.bin/as/app.c
@@ -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
index 0000000..d51a27f
--- /dev/null
+++ b/gnu/usr.bin/as/append.c
@@ -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
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/as.1
diff --git a/gnu/usr.bin/as/as.1aout b/gnu/usr.bin/as/as.1aout
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gnu/usr.bin/as/as.1aout
diff --git a/gnu/usr.bin/as/as.c b/gnu/usr.bin/as/as.c
new file mode 100644
index 0000000..db85525
--- /dev/null
+++ b/gnu/usr.bin/as/as.c
@@ -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[];
+
+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 */
+}
+
+
+/* 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);
+}
+
+/*
+ * 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);
+}
+
+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
index 0000000..8de4052
--- /dev/null
+++ b/gnu/usr.bin/as/as.h
@@ -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__); \
+}
+
+
+
+
+/* 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
+
+/* 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();
+
+/* 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();
+
+/* 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. */
+
+
+/* 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();
+
+
+/* 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
index 0000000..4975410
--- /dev/null
+++ b/gnu/usr.bin/as/atof-generic.c
@@ -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"}
+
+*/
+
+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;
+
+ {
+ /*
+ * 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;
+ }
+
+ 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
index 0000000..2640121
--- /dev/null
+++ b/gnu/usr.bin/as/bignum-copy.c
@@ -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
index 0000000..dbc95a3
--- /dev/null
+++ b/gnu/usr.bin/as/bignum.h
@@ -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
index 0000000..945246b
--- /dev/null
+++ b/gnu/usr.bin/as/config/Makefile.i386
@@ -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
index 0000000..71b09a0
--- /dev/null
+++ b/gnu/usr.bin/as/config/a.out.gnu.h
@@ -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
+
+#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. */
+
+#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
index 0000000..6ff45c8
--- /dev/null
+++ b/gnu/usr.bin/as/config/atof-ieee.c
@@ -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
+ };
+
+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;
+}
+
+/***********************************************************************\
+* 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
index 0000000..35c86c3
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386-opcode.h
@@ -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
index 0000000..2281acd
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386.c
@@ -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;
+
+
+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. */
+
+
+#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 */
+
+/*
+ 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;
+}
+
+/* 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 */
+}
+
+/*
+ * 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() */
+
+/*
+ * 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;
+}
+
+
+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);
+ }
+}
+
+int
+md_parse_option(argP,cntP,vecP)
+char **argP;
+int *cntP;
+char ***vecP;
+{
+ return 1;
+}
+
+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));
+}
+
+
+#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 */
+}
+
+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
index 0000000..c569c1c
--- /dev/null
+++ b/gnu/usr.bin/as/config/i386.h
@@ -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
index 0000000..f3a377d
--- /dev/null
+++ b/gnu/usr.bin/as/expr.c
@@ -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;
+
+/*
+ * 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.
+ *
+ */
+
+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 */
+
+/* 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;
+ }
+}
+
+/*
+ * 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() */
+
+/* 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 };
+
+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;
+ }
+
+ 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);
+}
+
+/*
+ * 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
index 0000000..964d3b9
--- /dev/null
+++ b/gnu/usr.bin/as/expr.h
@@ -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
index 0000000..617e585
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-const.c
@@ -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
index 0000000..3a51f06
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-copy.c
@@ -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
index 0000000..1b7b5ea
--- /dev/null
+++ b/gnu/usr.bin/as/flonum-mult.c
@@ -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 ...)
+*/
+
+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
index 0000000..b2e841a
--- /dev/null
+++ b/gnu/usr.bin/as/flonum.h
@@ -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
index 0000000..ee10321
--- /dev/null
+++ b/gnu/usr.bin/as/frags.c
@@ -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] */
+};
+
+/*
+ * 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);
+}
+
+/*
+ * 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() */
+
+/*
+ * 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() */
+
+/*
+ * 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() */
+
+/*
+ * 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() */
+
+/*
+ * 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;
+}
+
+/*
+ * 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
index 0000000..6d7310b
--- /dev/null
+++ b/gnu/usr.bin/as/frags.h
@@ -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
index 0000000..21f0cc0
--- /dev/null
+++ b/gnu/usr.bin/as/hash.c
@@ -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!
+ */
+
+/*
+ * The idea is to implement a symbol table. A test jig is here.
+ * Symbols are arbitrary strings; they can't contain '\0'.
+ * [See hsh.c for a more general symbol flavour.]
+ * Each symbol is associated with a char*, which can point to anything
+ * you want, allowing an arbitrary property list for each symbol.
+ *
+ * The basic operations are:
+ *
+ * new creates symbol table, returns handle
+ * find (symbol) returns char*
+ * insert (symbol,char*) error if symbol already in table
+ * delete (symbol) returns char* if symbol was in table
+ * apply so you can delete all symbols before die()
+ * die destroy symbol table (free up memory)
+ *
+ * Supplementary functions include:
+ *
+ * say how big? what % full?
+ * replace (symbol,newval) report previous value
+ * jam (symbol,value) assert symbol:=value
+ *
+ * You, the caller, have control over errors: this just reports them.
+ *
+ * This package requires malloc(), free().
+ * Malloc(size) returns NULL or address of char[size].
+ * Free(address) frees same.
+ */
+
+/*
+ * The code and its structures are re-enterent.
+ * Before you do anything else, you must call hash_new() which will
+ * return the address of a hash-table-control-block (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.
+ */
+
+/*
+ * 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
+
+/*------------------ 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
+
+*/
+
+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();
+
+/*
+ * 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);
+}
+
+/*
+ * 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;
+ }
+ }
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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 */
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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
index 0000000..fb68fd3
--- /dev/null
+++ b/gnu/usr.bin/as/hash.h
@@ -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
index 0000000..f97c2ab3
--- /dev/null
+++ b/gnu/usr.bin/as/hex-value.c
@@ -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
index 0000000..8de1dcf
--- /dev/null
+++ b/gnu/usr.bin/as/input-file.c
@@ -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;
+
+/* 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;
+}
+
+#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
index 0000000..42f490a
--- /dev/null
+++ b/gnu/usr.bin/as/input-file.h
@@ -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
index 0000000..71af8a0
--- /dev/null
+++ b/gnu/usr.bin/as/input-scrub.c
@@ -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.
+ */
+
+#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;
+
+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);
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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
+ }
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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
index 0000000..681d027
--- /dev/null
+++ b/gnu/usr.bin/as/md.h
@@ -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
index 0000000..a7b1205
--- /dev/null
+++ b/gnu/usr.bin/as/messages.c
@@ -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
index 0000000..fca8af4
--- /dev/null
+++ b/gnu/usr.bin/as/objrecdef.h
@@ -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];
+ };
+
+#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
+
+#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
+
+#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
+
+#define GSY$M_WEAK 1
+#define GSY$M_DEF 2
+#define GSY$M_UNI 4
+#define GSY$M_REL 8
+
+#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
+
+#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
+
+/*
+ * 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
index 0000000..c9cf561
--- /dev/null
+++ b/gnu/usr.bin/as/obstack.c
@@ -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;
+
+/* 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
+
+#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
index 0000000..fd779c4
--- /dev/null
+++ b/gnu/usr.bin/as/obstack.h
@@ -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__
+
+/* 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
+
+#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. */
+
+/* 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))
+
+#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); })
+
+#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
index 0000000..ff71f40
--- /dev/null
+++ b/gnu/usr.bin/as/output-file.c
@@ -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
index 0000000..8357107
--- /dev/null
+++ b/gnu/usr.bin/as/read.c
@@ -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 ();
+
+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;
+}
+
+/* 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() */
+
+/* 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();
+}
+
+
+/*( 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]] );
+}
+
+/*
+ * 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 ();
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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() */
+
+/*
+ * 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(); */
+
+/*
+ * 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() */
+
+/*
+ * 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() */
+
+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);
+}
+
+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 ++ );
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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
index 0000000..6b46e8f
--- /dev/null
+++ b/gnu/usr.bin/as/read.h
@@ -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
index 0000000..11eab6b
--- /dev/null
+++ b/gnu/usr.bin/as/struc-symbol.h
@@ -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
index 0000000..c9eea3d
--- /dev/null
+++ b/gnu/usr.bin/as/subsegs.c
@@ -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
+};
+
+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;
+}
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * 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
index 0000000..b8dbaf7
--- /dev/null
+++ b/gnu/usr.bin/as/subsegs.h
@@ -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
index 0000000..ce7197a
--- /dev/null
+++ b/gnu/usr.bin/as/symbols.c
@@ -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
+
+
+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;
+}
+
+/*
+ * 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));
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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);
+ }
+}
+
+
+/*
+ * 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);
+ }
+}
+
+/*
+ * 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
index 0000000..5a52790
--- /dev/null
+++ b/gnu/usr.bin/as/symbols.h
@@ -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
index 0000000..f94d3f4
--- /dev/null
+++ b/gnu/usr.bin/as/version.c
@@ -0,0 +1,23 @@
+#if defined(__STDC__) || defined(const)
+const
+#endif
+char version_string[] = "GNU assembler version 1.38\n";
+
+/* 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
index 0000000..a850555
--- /dev/null
+++ b/gnu/usr.bin/as/write.c
@@ -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
+ /*
+ * 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;
+}
+
+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. */
+ }
+
+ /*
+ * 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; */
+
+ /*
+ * 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));
+
+ /*
+ * 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() */
+
+/*
+ * 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 */
+
+ /*
+ * 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() */
+
+/*
+ * 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);
+}
+
+/*
+ * 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() */
+
+
+/* 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
index 0000000..7327690
--- /dev/null
+++ b/gnu/usr.bin/as/write.h
@@ -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
index 0000000..78c8c7f
--- /dev/null
+++ b/gnu/usr.bin/as/xmalloc.c
@@ -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
index 0000000..a5010bc
--- /dev/null
+++ b/gnu/usr.bin/as/xrealloc.c
@@ -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 */
OpenPOWER on IntegriCloud