Category : UNIX Files
Archive   : GAS138.ZIP
Filename : GAS138.TAR

 
Output of file : GAS138.TAR contained in archive : GAS138.ZIP
gas-1.38/ 777 11660 0 0 4751053656 7311 5ustar hackgas-1.38/COPYING 666 12120 0 30310 4401053477 10315 0ustar rms
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.


Copyright (C) 19yy

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.

, 1 April 1989
Ty Coon, President of Vice

That's all there is to it!
gas-1.38/README 666 11660 0 13356 4651640265 10276 0ustar hackThis 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 [email protected] If you can't
get through to prep, try [email protected] or [email protected]

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
[email protected] 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 [email protected]


------------------------------ 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.
gas-1.38/ChangeLog 666 13200 0 67360 4741142653 11705 0ustar kingdonFri Jan 4 12:48:22 EST 1991 Jay Fenlason ([email protected])

* 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 ([email protected])

* 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 ([email protected])

* vms.c (VMS_TBT_Routine_END) Add a four line patch from
Eric Youngdale.

Tue Nov 13 14:02:15 EST 1990 Jay Fenlason ([email protected])

* vms-dbg.c (VMS_DBG_record()) Another one character patch from
Eric Youngdale.

Mon Oct 29 15:49:21 EST 1990 Jay Fenlason ([email protected])

* read.c Replace some as_warn calls with as_bad.

Fri Oct 26 15:21:15 EDT 1990 Jay Fenlason ([email protected])

* i386.c, i860.c, ns32k.c Add const changes.

Mon Oct 22 14:04:26 EDT 1990 Jay Fenlason ([email protected])

* 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 ([email protected])

* i860.c i860-opcode.h Added patches from [email protected]

* read.c, symbols.c, vms.c, + new_file vms-dbg-module.c
Added Eric Youngdale's 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 ([email protected])

* 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%[email protected]).

* 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 ([email protected])

* 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 ([email protected])

* 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 ([email protected])

* 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
([email protected])

Mon Sep 24 11:43:15 EDT 1990 Jay Fenlason ([email protected])

* as.c #include if _POSIX_SOURCE defined. This because
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 ([email protected])

* 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
([email protected])

Wed Aug 1 13:30:48 EDT 1990 Jay Fenlason ([email protected])

* 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


Fri Jul 20 13:39:02 EDT 1990 Jay Fenlason ([email protected])

* README Added README.APOLLO and README.COFF stuff

Wed Jul 18 16:29:22 EDT 1990 Jay Fenlason ([email protected])

* Makefile Added option for SEQUENT_COMPATABILITY

* ns32k.c Add configurable syntax feature from
[email protected]@augean.ua.oz.au
and SEQUENT_COMPATABILITY

* ns32k-opcode.h Add configurable syntax feature.

Mon Jul 16 11:44:14 EDT 1990 Jay Fenlason ([email protected])

* 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 [email protected]

* ns32k.c (md_atof, convert_iif) Emit floating point numbers in
the correct byte order. A seven line patch from
[email protected]

* ns32k.c (all over) Some lint fixes.

Mon Jul 9 13:17:00 EDT 1990 Jay Fenlason ([email protected])

* 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.
([email protected]).

* 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 ([email protected])

* 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 ([email protected])

* sparc.c #ifdef DONTDEF s_sparc_align, since it isn't called from
anywhere.

Fri Jun 15 15:53:30 EDT 1990 Jay Fenlason ([email protected])

* 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 ([email protected])

* 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 ([email protected])

* 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
([email protected])

* i386.c (md_assemble) Call frag_wane() before calling frag_new()
A one line patch from Steve Bleazard ([email protected]

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
([email protected])

* 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 ([email protected])

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 ([email protected])

* 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 ([email protected]).

Thu Mar 8 19:18:59 EST 1990 hack@wookumz
* vms.c Some trivial patches from Eric Youngdale
([email protected])

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
([email protected])

Tue Mar 6 16:01:09 EST 1990 hack@wookumz

* Makefile Include ns32k options in makefile. A small patch from
David Taylor ([email protected]).

* 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 ([email protected])

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 [email protected]

* 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 [email protected]

* 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 [email protected]

* 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 [email protected]

* 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 [email protected]

* atof-generic.c, flonum-mult.c A real fix for the trailing-zeroes
problem from Georg Feil ([email protected]) (two line change)

Mon Nov 27 15:30:46 EST 1989 [email protected]

* i386-opcode.h Fixed opcode-table entry for ljmp. A one char
patch from [email protected]

Mon Nov 20 12:41:28 EST 1989 [email protected]

* 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
([email protected]) for c++? (A dozen lines or so)

Mon Nov 13 11:48:44 EST 1989 [email protected]

* 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 [email protected]

* version.c New version: 1.35 will be distributed with the
1.36 gcc release.

Mon Oct 30 10:38:11 EST 1989 [email protected]

* 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 [email protected]

* 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 [email protected]

* 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 [email protected] (real name unknown)).

Tue Oct 10 14:39:44 EDT 1989 [email protected]
* 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 [email protected]

* app.c (do_scrub_next_char) Fixed parsing of
# "file" garbage
text so that it'll work again? (8 line patch from Mike Hibler
([email protected]))

Mon Sep 18 16:26:01 EDT 1989 [email protected]

* 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 [email protected]

* sparc.c (md_number_to_imm) Dozen line patch from [email protected]
(Jyrki Kuoppala) so that gas output will work with shared libraries.

* ns32k.c Include instead of 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
[email protected] (Josef Moellers)

Fri Sep 1 11:39:52 EDT 1989 [email protected]

* atof-m68k.c (gen_to_words) Get the sign right on negative
floating-point numbers.

Wed Aug 30 13:59:57 EDT 1989 [email protected]

* Makefile Remove the rest of the $< entries that kill sun make

Fri Aug 25 15:00:30 EDT 1989 Nobody You Know ([email protected])

* 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 [email protected].
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 ([email protected]).

* 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 #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 ([email protected]).

* 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:
gas-1.38/as.c 666 12412 0 20116 4705116451 10353 0ustar randy/* 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 /* For pid_t in signal.h */
#endif
#include

#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;

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 */
gas-1.38/xrealloc.c 666 12412 0 3010 4403071501 11522 0ustar randy/* 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
#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 */
gas-1.38/xmalloc.c 666 12412 0 2715 4403071502 11364 0ustar randy/* 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
#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 */
gas-1.38/hash.c 666 12412 0 73011 4707355670 10707 0ustar randy/* 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
#define TRUE (1)
#define FALSE (0)
#include
#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< /* +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 {
*ip = 0;
}

retval -> hash_stat[STAT_SIZE] = 1< retval -> hash_mask = (1< retval -> hash_sizelog = START_POWER;
/* works for 1's compl ok */
retval -> hash_where = room;
retval -> hash_wall =
wall = room + (1< retval -> hash_full = (1< 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 {
*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 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 {
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 {
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 {
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 */
gas-1.38/hex-value.c 666 12412 0 4320 4705116456 11632 0ustar randy/* 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 */
gas-1.38/atof-generic.c 666 12412 0 40210 4705116453 12312 0ustar randy/* 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
#include "flonum.h"
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
#ifdef sparc
#include
#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:

::=
::= '+' | '-' | {empty}
::=
|
|
|
::= {empty} |
::= |
::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
::= {one character from "string_of_decimal_exponent_marks"}
::= {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 */
gas-1.38/append.c 666 12412 0 2160 4403071603 11170 0ustar randy/* 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 */
gas-1.38/messages.c 666 12412 0 12527 4741142651 11567 0ustar randy/* 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 /* define stderr */
#ifdef VMS
#include /* Need this to make errno declaration right */
#include /* Need this to make sys_errlist/sys_nerr right */
#endif /* VMS */

#include "as.h"

#ifndef NO_VARARGS
#include
#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 */
gas-1.38/expr.c 666 12412 0 73443 4751051516 10742 0ustar randy/* 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
#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]) {
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 */
gas-1.38/bignum-copy.c 666 12412 0 4431 4403071573 12163 0ustar randy/* 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 */
gas-1.38/frags.c 666 12412 0 17663 4472613661 11075 0ustar randy/* 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)) 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 */
gas-1.38/input-file.c 666 12412 0 16762 4741142651 12041 0ustar randy/* 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
#include
/* #include
#include
#include
#include */

/* #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 */
gas-1.38/input-scrub.c 666 12412 0 22401 4741142652 12224 0ustar randy/* 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
}
}




/*
* 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 */
gas-1.38/output-file.c 666 12412 0 3675 4741142650 12220 0ustar randy/* 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

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 */
gas-1.38/read.c 666 12412 0 154332 4713344573 10722 0ustar randy/* 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
#include
#include
#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( ¬es, 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 == ':' )
{
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 */
/* 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 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< * 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;
}
}

/*
* 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 ( ¬es, c );
len ++;
}
/* JF this next line is so demand_copy_C_string will return a null
termanated string. */
obstack_1grow(¬es,'\0');
retval=obstack_finish( ¬es);
} 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 */
gas-1.38/subsegs.c 666 12412 0 21114 4705116457 11430 0ustar randy/* 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 */
gas-1.38/symbols.c 666 12412 0 27546 4707405011 11451 0ustar randy/* 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 . */
char other; /* As in . */
short int desc; /* As in . */
valueT value; /* As in , 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(¬es,name,name_length);
p=obstack_finish(¬es);
/* obstack_1done( ¬es, name, name_length, &p ); */
preserved_copy_of_name = p;
p=obstack_alloc(¬es,sizeof(struct symbol));
/* obstack_1blank( ¬es, 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 ":".
* 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 */
gas-1.38/write.c 666 12412 0 113647 4705116447 11143 0ustar randy/* 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(¬es,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. . . */
/* [email protected]: 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 */
gas-1.38/strstr.c 666 12412 0 2571 4403071520 11266 0ustar randy/* strstr - find first occurrence of wanted in s
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 CONST
#define SIZET int

#define NULL 0

char * /* found string, or NULL if none */
strstr(s, wanted)
CONST char *s;
CONST char *wanted;
{
register CONST char *scan;
register SIZET len;
register char firstc;
extern int strcmp();
extern SIZET strlen();

/*
* The odd placement of the two tests is so "" is findable.
* Also, we inline the first char for speed.
* The ++ on scan has been moved down for optimization.
*/
firstc = *wanted;
len = strlen(wanted);
for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
if (*scan++ == '\0')
return(NULL);
return(scan);
}
gas-1.38/flonum-const.c 666 12412 0 16224 4710632223 12375 0ustar randy/* 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 */
gas-1.38/flonum-copy.c 666 12412 0 4432 4403071566 12205 0ustar randy/* 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 */
gas-1.38/flonum-mult.c 666 12412 0 12021 4535570415 12230 0ustar randy/* 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 */
gas-1.38/app.c 666 12412 0 17204 4705116451 10534 0ustar randy/* 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
# into a .line ;.file pair.
This needs better error-handling.
*/
#include
#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
gas-1.38/version.c 666 12241 0 1010 4745377662 11570 0ustar roland#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
gas-1.38/obstack.c 666 12120 0 22576 4714552241 11073 0ustar rms/* 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 */
gas-1.38/a.out.gnu.h 666 11660 0 16171 4650425402 11374 0ustar hack#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__ */
gas-1.38/as.h 666 12412 0 20620 4705116452 10361 0ustar randy/* 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
#include
#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 */
gas-1.38/bignum.h 666 12412 0 3423 4474306630 11223 0ustar randy/* 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 */
gas-1.38/expr.h 666 12412 0 4635 4403071570 10720 0ustar randy/* 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 */
gas-1.38/flonum.h 666 12412 0 7504 4705116455 11247 0ustar randy/* 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 */
gas-1.38/frags.h 666 12412 0 2427 4403071563 11043 0ustar randy/* 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 */
gas-1.38/hash.h 666 12412 0 4015 4403071553 10656 0ustar randy/* 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 */
gas-1.38/input-file.h 666 12412 0 3674 4403071544 12021 0ustar randy/* 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 */
gas-1.38/md.h 666 11660 0 3752 4705116456 10146 0ustar hack/* 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 */
gas-1.38/obstack.h 666 12120 0 37635 4732675523 11113 0ustar rms/* 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__ */
gas-1.38/read.h 666 12412 0 3135 4705116456 10657 0ustar randy/* 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 */
gas-1.38/struc-symbol.h 666 12412 0 5154 4645155700 12410 0ustar randy/* 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
gas-1.38/subsegs.h 666 12412 0 5060 4403071514 11404 0ustar randy/* 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 */
gas-1.38/symbols.h 666 12412 0 2530 4403071513 11417 0ustar randy/* 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 */
gas-1.38/write.h 666 12412 0 5513 4705120653 11072 0ustar randy/* 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 */

gas-1.38/vax.c 666 11660 0 273253 4705125532 10377 0ustar hack/* vax.c - vax-specific -
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 I moved almost all the vax specific stuff into this one file 'cuz RMS
seems to think its a good idea. I hope I managed to get all the VAX-isms */


#include "as.h"
#include "read.h"
#include "flonum.h"
#include "vax-inst.h"
#include "md.h"
#include "obstack.h" /* For FRAG_APPEND_1_CHAR macro in "frags.h" */
#include "frags.h"
#include "struc-symbol.h"
#include "expr.h"
#include "symbols.h"

/* This is the number to put at the beginning of the a.out file */
long omagic = OMAGIC;

/* These chars start a comment anywhere in a source file (except inside
another comment */
const char comment_chars[] = "#";

/* These chars only start a comment at the beginning of a line. */
/* Note that for the VAX the are the same as comment_chars above. */
const char line_comment_chars[] = "#";

/* Chars that can be used to separate mant from exp in floating point nums */
const char EXP_CHARS[] = "eE";

/* Chars that mean this number is a floating point constant */
/* as in 0f123.456 */
/* or 0H1.234E-12 (see exp chars above) */
const char FLT_CHARS[] = "dDfFgGhH";

/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
changed in read.c . Ideally it shouldn't have to know about it at all,
but nothing is ideal around here.
*/

static expressionS /* Hold details of an operand expression */
exp_of_operand[VIT_MAX_OPERANDS];

static struct vit
v; /* A vax instruction after decoding. */

LITTLENUM_TYPE big_operand_bits[VIT_MAX_OPERANDS][SIZE_OF_LARGE_NUMBER];
/* Hold details of big operands. */
FLONUM_TYPE float_operand[VIT_MAX_OPERANDS];
/* Above is made to point into */
/* big_operand_bits by md_begin(). */

/*
* For VAX, relative addresses of "just the right length" are easy.
* The branch displacement is always the last operand, even in
* synthetic instructions.
* For VAX, we encode the relax_substateTs (in e.g. fr_substate) as:
*
* 4 3 2 1 0 bit number
* ---/ /--+-------+-------+-------+-------+-------+
* | what state ? | how long ? |
* ---/ /--+-------+-------+-------+-------+-------+
*
* The "how long" bits are 00=byte, 01=word, 10=long.
* This is a Un*x convention.
* Not all lengths are legit for a given value of (what state).
* The "how long" refers merely to the displacement length.
* The address usually has some constant bytes in it as well.
*

groups for VAX address relaxing.

1. "foo" pc-relative.
length of byte, word, long

2a. J where is a simple flag test.
length of byte, word, long.
VAX opcodes are: (Hex)
bneq/bnequ 12
beql/beqlu 13
bgtr 14
bleq 15
bgeq 18
blss 19
bgtru 1a
blequ 1b
bvc 1c
bvs 1d
bgequ/bcc 1e
blssu/bcs 1f
Always, you complement 0th bit to reverse condition.
Always, 1-byte opcode, then 1-byte displacement.

2b. J where cond tests a memory bit.
length of byte, word, long.
Vax opcodes are: (Hex)
bbs e0
bbc e1
bbss e2
bbcs e3
bbsc e4
bbcc e5
bbssi e6
bbcci e7
Always, you complement 0th bit to reverse condition.
Always, 1-byte opcde, longword-address, byte-address, 1-byte-displacement

2c. J where cond tests low-order memory bit
length of byte,word,long.
Vax opcodes are: (Hex)
blbs e8
blbc e9
Always, you complement 0th bit to reverse condition.
Always, 1-byte opcode, longword-address, 1-byte displacement.

3. Jbs/Jbr.
length of byte,word,long.
Vax opcodes are: (Hex)
bsbb 10
brb 11
These are like (2) but there is no condition to reverse.
Always, 1 byte opcode, then displacement/absolute.

4a. JacbX
length of word, long.
Vax opcodes are: (Hex)
acbw 3d
acbf 4f
acbd 6f
abcb 9d
acbl f1
acbg 4ffd
acbh 6ffd
Always, we cannot reverse the sense of the branch; we have a word
displacement.
The double-byte op-codes don't hurt: we never want to modify the
opcode, so we don't care how many bytes are between the opcode and
the operand.

4b. JXobXXX
length of long, long, byte.
Vax opcodes are: (Hex)
aoblss f2
aobleq f3
sobgeq f4
sobgtr f5
Always, we cannot reverse the sense of the branch; we have a byte
displacement.

The only time we need to modify the opcode is for class 2 instructions.
After relax() we may complement the lowest order bit of such instruction
to reverse sense of branch.

For class 2 instructions, we store context of "where is the opcode literal".
We can change an opcode's lowest order bit without breaking anything else.

We sometimes store context in the operand literal. This way we can figure out
after relax() what the original addressing mode was.
*/

/* These displacements are relative to */
/* the start address of the displacement. */
/* The first letter is Byte, Word. */
/* 2nd letter is Forward, Backward. */
#define BF (1+ 127)
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
/* Dont need LF, LB because they always */
/* reach. [They are coded as 0.] */


#define C(a,b) ENCODE_RELAX(a,b)
/* This macro has no side-effects. */
#define ENCODE_RELAX(what,length) (((what) << 2) + (length))

const relax_typeS
md_relax_table[] =
{
{
1, 1, 0, 0
}, /* error sentinel 0,0 */
{
1, 1, 0, 0
}, /* unused 0,1 */
{
1, 1, 0, 0
}, /* unused 0,2 */
{
1, 1, 0, 0
}, /* unused 0,3 */
{
BF + 1, BB + 1, 2, C (1, 1)
}, /* B^"foo" 1,0 */
{
WF + 1, WB + 1, 3, C (1, 2)
}, /* W^"foo" 1,1 */
{
0, 0, 5, 0
}, /* L^"foo" 1,2 */
{
1, 1, 0, 0
}, /* unused 1,3 */
{
BF, BB, 1, C (2, 1)
}, /* b B^"foo" 2,0 */
{
WF + 2, WB + 2, 4, C (2, 2)
}, /* br.+? brw X 2,1 */
{
0, 0, 7, 0
}, /* br.+? jmp X 2,2 */
{
1, 1, 0, 0
}, /* unused 2,3 */
{
BF, BB, 1, C (3, 1)
}, /* brb B^foo 3,0 */
{
WF, WB, 2, C (3, 2)
}, /* brw W^foo 3,1 */
{
0, 0, 5, 0
}, /* Jmp L^foo 3,2 */
{
1, 1, 0, 0
}, /* unused 3,3 */
{
1, 1, 0, 0
}, /* unused 4,0 */
{
WF, WB, 2, C (4, 2)
}, /* acb_ ^Wfoo 4,1 */
{
0, 0, 10, 0
}, /* acb_,br,jmp L^foo4,2 */
{
1, 1, 0, 0
}, /* unused 4,3 */
{
BF, BB, 1, C (5, 1)
}, /* Xob___,,foo 5,0 */
{
WF + 4, WB + 4, 6, C (5, 2)
}, /* Xob.+2,brb.+3,brw5,1 */
{
0, 0, 9, 0
}, /* Xob.+2,brb.+6,jmp5,2 */
};

#undef C
#undef BF
#undef BB
#undef WF
#undef WB

void float_cons ();

const pseudo_typeS md_pseudo_table[] =
{
{"dfloat", float_cons, 'd'},
{"ffloat", float_cons, 'f'},
{"gfloat", float_cons, 'g'},
{"hfloat", float_cons, 'h'},
{0}
};

#define STATE_PC_RELATIVE (1)
#define STATE_CONDITIONAL_BRANCH (2)
#define STATE_ALWAYS_BRANCH (3) /* includes BSB... */
#define STATE_COMPLEX_BRANCH (4)
#define STATE_COMPLEX_HOP (5)

#define STATE_BYTE (0)
#define STATE_WORD (1)
#define STATE_LONG (2)
#define STATE_UNDF (3) /* Symbol undefined in pass1 */


#define min(a, b) ((a) < (b) ? (a) : (b))


void
md_begin ()
{
char *vip_begin ();
char *errtxt;
FLONUM_TYPE *fP;
int i;

if (*(errtxt = vip_begin (TRUE, "$", "*", "`")))
{
as_fatal ("VIP_BEGIN error:%s", errtxt);
}

for (i = 0, fP = float_operand;
fP < float_operand + VIT_MAX_OPERANDS;
i++, fP++)
{
fP->low = &big_operand_bits[i][0];
fP->high = &big_operand_bits[i][SIZE_OF_LARGE_NUMBER - 1];
}
}

void
md_end ()
{
vip_end ();
}

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. */
{
int n;
long v;

n = nbytes;
v = value;
while (nbytes--)
{
*con++ = value; /* Lint wants & MASK_CHAR. */
value >>= BITS_PER_CHAR;
}
/* XXX line number probably botched for this warning message. */
if (value != 0 && value != -1)
as_warn ("Displacement (%ld) long for instruction field length (%d).", v, n);
}

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. */
{
int n;
long v;

n = nbytes;
v = value;
while (nbytes--)
{
*con++ = value; /* Lint wants & MASK_CHAR. */
value >>= BITS_PER_CHAR;
}
/* XXX line number probably botched for this warning message. */
if (value != 0 && value != -1)
as_warn ("Displacement (%ld) too long for instruction field length (%d).", v, n);
}

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. */
{
abort ();
while (nbytes--)
{
*con++ = value; /* Lint wants & MASK_CHAR. */
value >>= BITS_PER_CHAR;
}
/* XXX line number probably botched for this warning message. */
if (value != 0 && value != -1)
as_warn ("Displacement too long for instruction field length.");
}

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. */
{
abort ();
while (nbytes--)
{
*con++ = value; /* Lint wants & MASK_CHAR. */
value >>= BITS_PER_CHAR;
}
/* XXX line number probably botched for this warning message. */
if (value != 0 && value != -1)
as_warn ("Displacement too long for instruction field length.");
}

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;
}

/* vax:md_assemble() emit frags for 1 instruction */

void
md_assemble (instruction_string)
char *instruction_string; /* A string: assemble 1 instruction. */
{
char *p;
register struct vop *operandP;/* An operand. Scans all operands. */
char *save_input_line_pointer;
char c_save; /* What used to live after an expression. */
struct frag *fragP; /* Fragment of code we just made. */
register int goofed; /* TRUE: instruction_string bad for all passes. */
register struct vop *end_operandP; /* -> slot just after last operand */
/* Limit of the for (each operand). */
register expressionS *expP; /* -> expression values for this operand */

/* These refer to an instruction operand expression. */
segT to_seg; /* Target segment of the address. */
register valueT this_add_number;
register struct symbol *this_add_symbol; /* +ve (minuend) symbol. */
register struct symbol *this_subtract_symbol; /* -ve(subtrahend) symbol. */

long int opcode_as_number; /* As a number. */
char *opcode_as_chars; /* Least significant byte 1st. */
/* As an array of characters. */
char *opcode_low_byteP; /* Least significant byte 1st */
struct details *detP; /* The details of an ADxxx frag. */
int length; /* length (bytes) meant by vop_short. */
int at; /* 0, or 1 if '@' is in addressing mode. */
int nbytes; /* From vop_nbytes: vax_operand_width (in bytes) */
FLONUM_TYPE *floatP;
char *vip ();
LITTLENUM_TYPE literal_float[8];
/* Big enough for any floating point literal. */

if (*(p = vip (&v, instruction_string)))
{
as_fatal ("vax_assemble\"%s\" in=\"%s\"", p, instruction_string);
}
/*
* Now we try to find as many as_warn()s as we can. If we do any as_warn()s
* then goofed=TRUE. Notice that we don't make any frags yet.
* Should goofed be TRUE, then this instruction will wedge in any pass,
* and we can safely flush it, without causing interpass symbol phase
* errors. That is, without changing label values in different passes.
*/
if (goofed = (*v.vit_error))
{
as_warn ("Ignoring statement due to \"%s\"", v.vit_error);
}
/*
* We need to use expression() and friends, which require us to diddle
* input_line_pointer. So we save it and restore it later.
*/
save_input_line_pointer = input_line_pointer;
for (operandP = v.vit_operand,
expP = exp_of_operand,
floatP = float_operand,
end_operandP = v.vit_operand + v.vit_operands;

operandP < end_operandP;

operandP++,
expP++,
floatP++
) /* for each operand */
{
if (*(operandP->vop_error))
{
as_warn ("Ignoring statement because \"%s\"", (operandP->vop_error));
goofed = TRUE;
}
else
{ /* statement has no syntax goofs: lets sniff the expression */
int can_be_short; /* TRUE if a bignum can be reduced to a short literal. */

input_line_pointer = operandP->vop_expr_begin;
c_save = operandP->vop_expr_end[1];
operandP->vop_expr_end[1] = '\0';
/* If to_seg == SEG_PASS1, expression() will have set need_pass_2 = TRUE. */
switch (to_seg = expression (expP))
{
case SEG_NONE:
/* for BSD4.2 compatibility, missing expression is absolute 0 */
to_seg = expP->X_seg = SEG_ABSOLUTE;
expP->X_add_number = 0;
/* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol, X_add_symbol to any particular value. */
/* But, we will program defensively. Since this situation occurs */
/* rarely so it costs us little to do, and stops Dean */
/* worrying about the origin of random bits in expressionS's. */
expP->X_add_symbol = NULL;
expP->X_subtract_symbol = NULL;
case SEG_TEXT:
case SEG_DATA:
case SEG_BSS:
case SEG_ABSOLUTE:
case SEG_UNKNOWN:
break;

case SEG_DIFFERENCE:
case SEG_PASS1:
/*
* Major bug. We can't handle the case of a
* SEG_DIFFERENCE expression in a VIT_OPCODE_SYNTHETIC
* variable-length instruction.
* We don't have a frag type that is smart enough to
* relax a SEG_DIFFERENCE, and so we just force all
* SEG_DIFFERENCEs to behave like SEG_PASS1s.
* Clearly, if there is a demand we can invent a new or
* modified frag type and then coding up a frag for this
* case will be easy. SEG_DIFFERENCE was invented for the
* .words after a CASE opcode, and was never intended for
* instruction operands.
*/
need_pass_2 = TRUE;
as_warn("Can't relocate expression");
break;

case SEG_BIG:
/* Preserve the bits. */
if (expP->X_add_number > 0)
{
bignum_copy (generic_bignum, expP->X_add_number,
floatP->low, SIZE_OF_LARGE_NUMBER);
}
else
{
know (expP->X_add_number < 0);
flonum_copy (&generic_floating_point_number,
floatP);
if (index ("s i", operandP->vop_short))
{ /* Could possibly become S^# */
flonum_gen2vax (-expP->X_add_number, floatP, literal_float);
switch (-expP->X_add_number)
{
case 'f':
can_be_short =
(literal_float[0] & 0xFC0F) == 0x4000
&& literal_float[1] == 0;
break;

case 'd':
can_be_short =
(literal_float[0] & 0xFC0F) == 0x4000
&& literal_float[1] == 0
&& literal_float[2] == 0
&& literal_float[3] == 0;
break;

case 'g':
can_be_short =
(literal_float[0] & 0xFF81) == 0x4000
&& literal_float[1] == 0
&& literal_float[2] == 0
&& literal_float[3] == 0;
break;

case 'h':
can_be_short =
(literal_float[0] & 0xFFF8) == 0x4000
&& (literal_float[1] & 0xE000) == 0
&& literal_float[2] == 0
&& literal_float[3] == 0
&& literal_float[4] == 0
&& literal_float[5] == 0
&& literal_float[6] == 0
&& literal_float[7] == 0;
break;

default:
BAD_CASE (-expP->X_add_number);
break;
} /* switch (float type) */
} /* if (could want to become S^#...) */
} /* bignum or flonum ? */

if (operandP->vop_short == 's'
|| operandP->vop_short == 'i'
|| (operandP->vop_short == ' '
&& operandP->vop_reg == 0xF
&& (operandP->vop_mode & 0xE) == 0x8))
{
/* Saw a '#'. */
if (operandP->vop_short == ' ')
{ /* We must chose S^ or I^. */
if (expP->X_add_number > 0)
{ /* Bignum: Short literal impossible. */
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF; /* VAX PC. */
}
else
{ /* Flonum: Try to do it. */
if (can_be_short)
{
operandP->vop_short = 's';
operandP->vop_mode = 0;
operandP->vop_ndx = -1;
operandP->vop_reg = -1;
/* JF hope this is the right thing */
expP->X_seg = SEG_ABSOLUTE;
}
else
{
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF; /* VAX PC */
}
} /* bignum or flonum ? */
} /* if #, but no S^ or I^ seen. */
/* No more ' ' case: either 's' or 'i'. */
if (operandP->vop_short == 's')
{
/* Wants to be a short literal. */
if (expP->X_add_number > 0)
{
as_warn ("Bignum not permitted in short literal. Immediate mode assumed.");
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF; /* VAX PC. */
}
else
{
if (!can_be_short)
{
as_warn ("Can't do flonum short literal: immediate mode used.");
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF; /* VAX PC. */
}
else
{ /* Encode short literal now. */
register int temp;

switch (-expP->X_add_number)
{
case 'f':
case 'd':
temp = literal_float[0] >> 4;
break;

case 'g':
temp = literal_float[0] >> 1;
break;

case 'h':
temp = ((literal_float[0] << 3) & 070)
| ((literal_float[1] >> 13) & 07);
break;

default:
BAD_CASE (-expP->X_add_number);
break;
}

floatP->low[0] = temp & 077;
floatP->low[1] = 0;
} /* if can be short literal float */
} /* flonum or bignum ? */
}
else
{ /* I^# seen: set it up if float. */
if (expP->X_add_number < 0)
{
bcopy (literal_float, floatP->low, sizeof (literal_float));
}
} /* if S^# seen. */
}
else
{
as_warn ("A bignum/flonum may not be a displacement: 0x%x used",
expP->X_add_number = 0x80000000);
/* Chosen so luser gets the most offset bits to patch later. */
}
expP->X_add_number = floatP->low[0]
| ((LITTLENUM_MASK & (floatP->low[1])) << LITTLENUM_NUMBER_OF_BITS);
/*
* For the SEG_BIG case we have:
* If vop_short == 's' then a short floating literal is in the
* lowest 6 bits of floatP -> low [0], which is
* big_operand_bits [---] [0].
* If vop_short == 'i' then the appropriate number of elements
* of big_operand_bits [---] [...] are set up with the correct
* bits.
* Also, just in case width is byte word or long, we copy the lowest
* 32 bits of the number to X_add_number.
*/
break;

default:
BAD_CASE (to_seg);
break;
}
if (input_line_pointer != operandP->vop_expr_end + 1)
{
as_warn ("Junk at end of expression \"%s\"", input_line_pointer);
goofed = TRUE;
}
operandP->vop_expr_end[1] = c_save;
}
} /* for(each operand) */
input_line_pointer = save_input_line_pointer;

if (!need_pass_2 && !goofed)
{
/* We saw no errors in any operands - try to make frag(s) */
int is_undefined; /* True if operand expression's */
/* segment not known yet. */
int length_code;

/* Emit op-code. */
/* Remember where it is, in case we want to modify the op-code later. */
opcode_low_byteP = frag_more (v.vit_opcode_nbytes);
bcopy (v.vit_opcode, opcode_low_byteP, v.vit_opcode_nbytes);
opcode_as_number = md_chars_to_number (opcode_as_chars = v.vit_opcode, 4);
for (operandP = v.vit_operand,
expP = exp_of_operand,
floatP = float_operand,
end_operandP = v.vit_operand + v.vit_operands;

operandP < end_operandP;

operandP++,
floatP++,
expP++
) /* for each operand */
{
if (operandP->vop_ndx >= 0)
{
/* indexed addressing byte */
/* Legality of indexed mode already checked: it is OK */
FRAG_APPEND_1_CHAR (0x40 + operandP->vop_ndx);
} /* if(vop_ndx>=0) */

/* Here to make main operand frag(s). */
this_add_number = expP->X_add_number;
this_add_symbol = expP->X_add_symbol;
this_subtract_symbol = expP->X_subtract_symbol;
to_seg = expP->X_seg;
is_undefined = (to_seg == SEG_UNKNOWN);
know (to_seg == SEG_UNKNOWN \
||to_seg == SEG_ABSOLUTE \
||to_seg == SEG_DATA \
||to_seg == SEG_TEXT \
||to_seg == SEG_BSS \
||to_seg == SEG_BIG \
);
at = operandP->vop_mode & 1;
length = operandP->vop_short == 'b' ? 1 : operandP->vop_short == 'w' ? 2 : operandP->vop_short == 'l' ? 4 : 0;
nbytes = operandP->vop_nbytes;
if (operandP->vop_access == 'b')
{
if (to_seg == now_seg || is_undefined)
{ /* If is_undefined, then it might BECOME now_seg. */
if (nbytes)
{
p = frag_more (nbytes);
fix_new (frag_now, p - frag_now->fr_literal, nbytes,
this_add_symbol, 0, this_add_number, 1);
}
else
{ /* to_seg==now_seg || to_seg == SEG_UNKNOWN */
/* nbytes==0 */
length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
/* br or jsb */
frag_var (rs_machine_dependent, 5, 1,
ENCODE_RELAX (STATE_ALWAYS_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
length_code = STATE_WORD; /* JF: There is no state_byte for this one! */
frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_COMPLEX_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
frag_var (rs_machine_dependent, 9, 1,
ENCODE_RELAX (STATE_COMPLEX_HOP, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
}
}
else
{
know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
frag_var (rs_machine_dependent, 7, 1,
ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
this_add_symbol, this_add_number,
opcode_low_byteP);
}
}
}
else
{ /* to_seg != now_seg && to_seg != SEG_UNKNOWN */
/*
* --- SEG FLOAT MAY APPEAR HERE ----
*/
if (to_seg == SEG_ABSOLUTE)
{
if (nbytes)
{
know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
p = frag_more (nbytes);
/* Conventional relocation. */
fix_new (frag_now, p - frag_now->fr_literal,
nbytes, &abs_symbol, 0, this_add_number, 1);
}
else
{
know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
/* br or jsb */
*opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
know (opcode_as_chars[1] == 0);
p = frag_more (5);
p[0] = VAX_ABSOLUTE_MODE; /* @#... */
md_number_to_chars (p + 1, this_add_number, 4);
/* Now (eg) JMP @#foo or JSB @#foo. */
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
p = frag_more (10);
p[0] = 2;
p[1] = 0;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_ABSOLUTE_MODE; /* @#... */
md_number_to_chars (p + 6, this_add_number, 4);
/*
* Now (eg) ACBx 1f
* BRB 2f
* 1: JMP @#foo
* 2:
*/
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
p = frag_more (9);
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_PC_RELATIVE_MODE + 1; /* @#... */
md_number_to_chars (p + 5, this_add_number, 4);
/*
* Now (eg) xOBxxx 1f
* BRB 2f
* 1: JMP @#foo
* 2:
*/
}
}
}
else
{
/* b */
*opcode_low_byteP ^= 1; /* To reverse the condition in a VAX branch, complement the lowest order bit. */
p = frag_more (7);
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_ABSOLUTE_MODE; /* @#... */
md_number_to_chars (p + 3, this_add_number, 4);
/*
* Now (eg) BLEQ 1f
* JMP @#foo
* 1:
*/
}
}
}
else
{ /* to_seg != now_seg && to_seg != SEG_UNKNOWN && to_Seg != SEG_ABSOLUTE */
if (nbytes > 0)
{
/* Pc-relative. Conventional relocation. */
know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC));
p = frag_more (nbytes);
fix_new (frag_now, p - frag_now->fr_literal,
nbytes, &abs_symbol, 0, this_add_number, 1);
}
else
{
know (opcode_as_number & VIT_OPCODE_SYNTHETIC);
if (opcode_as_number & VIT_OPCODE_SPECIAL)
{
if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP)
{
/* br or jsb */
know (opcode_as_chars[1] == 0);
*opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG;
p = frag_more (5);
p[0] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 1 - frag_now->fr_literal, 4,
this_add_symbol, 0,
this_add_number, 1);
/* Now eg JMP foo or JSB foo. */
}
else
{
if (operandP->vop_width == VAX_WIDTH_WORD_JUMP)
{
p = frag_more (10);
p[0] = 0;
p[1] = 2;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 6 - frag_now->fr_literal, 4,
this_add_symbol, 0,
this_add_number, 1);
/*
* Now (eg) ACBx 1f
* BRB 2f
* 1: JMP foo
* 2:
*/
}
else
{
know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP);
p = frag_more (10);
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now,
p + 5 - frag_now->fr_literal,
4, this_add_symbol, 0,
this_add_number, 1);
/*
* Now (eg) xOBxxx 1f
* BRB 2f
* 1: JMP foo
* 2:
*/
}
}
}
else
{
know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP);
*opcode_low_byteP ^= 1; /* Reverse branch condition. */
p = frag_more (7);
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_PC_RELATIVE_MODE;
fix_new (frag_now, p + 3 - frag_now->fr_literal,
4, this_add_symbol, 0,
this_add_number, 1);
}
}
}
}
}
else
{
know (operandP->vop_access != 'b'); /* So it is ordinary operand. */
know (operandP->vop_access != ' '); /* ' ' target-independent: elsewhere. */
know (operandP->vop_access == 'a' || operandP->vop_access == 'm' || operandP->vop_access == 'r' || operandP->vop_access == 'v' || operandP->vop_access == 'w');
if (operandP->vop_short == 's')
{
if (to_seg == SEG_ABSOLUTE)
{
if (this_add_number < 0 || this_add_number >= 64)
{
as_warn ("Short literal overflow(%d.), immediate mode assumed.", this_add_number);
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
}
else
{
as_warn ("Forced short literal to immediate mode. now_seg=%s to_seg=%s", seg_name[(int) now_seg], seg_name[(int) to_seg]);
operandP->vop_short = 'i';
operandP->vop_mode = 8;
operandP->vop_reg = 0xF;
}
}
if (operandP->vop_reg >= 0 && (operandP->vop_mode < 8 || (operandP->vop_reg != 0xF && operandP->vop_mode < 10)))
{ /* One byte operand. */
know (operandP->vop_mode > 3);
FRAG_APPEND_1_CHAR (operandP->vop_mode << 4 | operandP->vop_reg);
/* All 1-bytes except S^# happen here. */
}
else
{ /* {@}{q^}foo{(Rn)} or S^#foo */
if (operandP->vop_reg == -1 && operandP->vop_short != 's')
{ /* "{@}{q^}foo" */
if (to_seg == now_seg)
{
if (length == 0)
{
know (operandP->vop_short == ' ');
p = frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE),
this_add_symbol, this_add_number,
opcode_low_byteP);
know (operandP->vop_mode == 10 + at);
*p = at << 4;
/* At is the only context we need to carry to */
/* other side of relax() process. */
/* Must be in the correct bit position of VAX */
/* operand spec. byte. */
}
else
{
know (length);
know (operandP->vop_short != ' ');
p = frag_more (length + 1);
/* JF is this array stuff really going to work? */
p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
fix_new (frag_now, p + 1 - frag_now->fr_literal,
length, this_add_symbol, 0,
this_add_number, 1);
}
}
else
{ /* to_seg != now_seg */
if (this_add_symbol == NULL)
{
know (to_seg == SEG_ABSOLUTE);
/* Do @#foo: simpler relocation than foo-.(pc) anyway. */
p = frag_more (5);
p[0] = VAX_ABSOLUTE_MODE; /* @#... */
md_number_to_chars (p + 1, this_add_number, 4);
if (length && length != 4)
{
as_warn ("Length specification ignored. Address mode 9F used");
}
}
else
{
/* {@}{q^}other_seg */
know ((length == 0 && operandP->vop_short == ' ') \
||(length > 0 && operandP->vop_short != ' '));
if (is_undefined)
{
/*
* We have a SEG_UNKNOWN symbol. It might
* turn out to be in the same segment as
* the instruction, permitting relaxation.
*/
p = frag_var (rs_machine_dependent, 5, 2,
ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF),
this_add_symbol, this_add_number,
0);
p[0] = at << 4;
}
else
{
if (length == 0)
{
know (operandP->vop_short == ' ');
length = 4; /* Longest possible. */
}
p = frag_more (length + 1);
p[0] = 0xF | ((at + "?\12\14?\16"[length]) << 4);
md_number_to_chars (p + 1, this_add_number, length);
fix_new (frag_now,
p + 1 - frag_now->fr_literal,
length, this_add_symbol, 0,
this_add_number, 1);
}
}
}
}
else
{ /* {@}{q^}foo(Rn) or S^# or I^# or # */
if (operandP->vop_mode < 0xA)
{ /* # or S^# or I^# */
/* know( (length == 0 && operandP->vop_short == ' ') \
|| (length > 0 && operandP->vop_short != ' ')); */
if (length == 0
&& to_seg == SEG_ABSOLUTE
&& operandP->vop_mode == 8 /* No '@'. */
&& this_add_number < 64
&& this_add_number >= 0)
{
operandP->vop_short = 's';
}
if (operandP->vop_short == 's')
{
FRAG_APPEND_1_CHAR (this_add_number);
}
else
{ /* I^#... */
know (nbytes);
p = frag_more (nbytes + 1);
know (operandP->vop_reg == 0xF);
p[0] = (operandP->vop_mode << 4) | 0xF;
if (to_seg == SEG_ABSOLUTE)
{
/*
* If nbytes > 4, then we are scrod. We don't know if the
* high order bytes are to be 0xFF or 0x00.
* BSD4.2 & RMS say use 0x00. OK --- but this
* assembler needs ANOTHER rewrite to
* cope properly with this bug.
*/
md_number_to_chars (p + 1, this_add_number, min (4, nbytes));
if (nbytes > 4)
{
bzero (p + 5, nbytes - 4);
}
}
else
{
if (to_seg == SEG_BIG)
{
/*
* Problem here is to get the bytes in the right order.
* We stored our constant as LITTLENUMs, not bytes.
*/
LITTLENUM_TYPE *lP;

lP = floatP->low;
if (nbytes & 1)
{
know (nbytes == 1);
p[1] = *lP;
}
else
{
for (p++; nbytes; nbytes -= 2, p += 2, lP++)
{
md_number_to_chars (p, *lP, 2);
}
}
}
else
{
fix_new (frag_now, p + 1 - frag_now->fr_literal,
nbytes, this_add_symbol, 0,
this_add_number, 0);
}
}
}
}
else
{ /* {@}{q^}foo(Rn) */
know ((length == 0 && operandP->vop_short == ' ') \
||(length > 0 && operandP->vop_short != ' '));
if (length == 0)
{
if (to_seg == SEG_ABSOLUTE)
{
register long int test;

test = this_add_number;

if (test < 0)
test = ~test;

length = test & 0xffff8000 ? 4
: test & 0xffffff80 ? 2
: 1;
}
else
{
length = 4;
}
}
p = frag_more (1 + length);
know (operandP->vop_reg >= 0);
p[0] = operandP->vop_reg
| ((at | "?\12\14?\16"[length]) << 4);
if (to_seg == SEG_ABSOLUTE)
{
md_number_to_chars (p + 1, this_add_number, length);
}
else
{
fix_new (frag_now, p + 1 - frag_now->fr_literal,
length, this_add_symbol, 0,
this_add_number, 0);
}
}
}
} /* if(single-byte-operand) */
}
} /* for(operandP) */
} /* if(!need_pass_2&&!goofed) */
} /* vax_assemble() */

/*
* 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 char *p;
register int old_fr_fix;

old_fr_fix = fragP->fr_fix;
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_UNDF):
if ((fragP->fr_symbol->sy_type & N_TYPE) == segment_type)
{ /* A relaxable case. */
fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
p[0] |= VAX_PC_RELATIVE_MODE; /* Preserve @ bit. */
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
fragP->fr_offset, 1);
frag_wane (fragP);
}
break;

case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
if ((fragP->fr_symbol->sy_type & N_TYPE) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*fragP->fr_opcode ^= 1; /* Reverse sense of branch. */
p[0] = 6;
p[1] = VAX_JMP;
p[2] = VAX_PC_RELATIVE_MODE; /* ...(PC) */
fragP->fr_fix += 1 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 3, 4, fragP->fr_symbol, 0,
fragP->fr_offset, 1);
frag_wane (fragP);
}
break;

case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_UNDF):
if ((fragP->fr_symbol->sy_type & N_TYPE) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD);
}
else
{
p = fragP->fr_literal + old_fr_fix;
p[0] = 2;
p[1] = 0;
p[2] = VAX_BRB;
p[3] = 6;
p[4] = VAX_JMP;
p[5] = VAX_PC_RELATIVE_MODE; /* ...(pc) */
fragP->fr_fix += 2 + 2 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 6, 4, fragP->fr_symbol, 0,
fragP->fr_offset, 1);
frag_wane (fragP);
}
break;

case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_UNDF):
if ((fragP->fr_symbol->sy_type & N_TYPE) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
p[0] = 2;
p[1] = VAX_BRB;
p[2] = 6;
p[3] = VAX_JMP;
p[4] = VAX_PC_RELATIVE_MODE; /* ...(pc) */
fragP->fr_fix += 1 + 2 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 5, 4, fragP->fr_symbol, 0,
fragP->fr_offset, 1);
frag_wane (fragP);
}
break;

case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_UNDF):
if ((fragP->fr_symbol->sy_type & N_TYPE) == segment_type)
{
fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
}
else
{
p = fragP->fr_literal + old_fr_fix;
*fragP->fr_opcode += VAX_WIDEN_LONG;
p[0] = VAX_PC_RELATIVE_MODE; /* ...(PC) */
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, 4, fragP->fr_symbol, 0,
fragP->fr_offset, 1);
frag_wane (fragP);
}
break;

default:
break;
}
return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
} /* md_estimate_size_before_relax() */

/*
* md_convert_frag();
*
* Called after relax() is finished.
* In: Address of frag.
* fr_type == rs_machine_dependent.
* fr_subtype is what the address relaxed to.
*
* Out: Any fixSs and constants are set up.
* Caller will turn frag into a ".space 0".
*/
void
md_convert_frag (fragP)
register fragS *fragP;
{
register char *addressP; /* -> _var to change. */
register char *opcodeP; /* -> opcode char(s) to change. */
register short int length_code; /* 2=long 1=word 0=byte */
register short int extension; /* Size of relaxed address. */
/* Added to fr_fix: incl. ALL var chars. */
register symbolS *symbolP;
register long int where;
register long int address_of_var;
/* Where, in file space, is _var of *fragP? */
register long int target_address;
/* Where, in file space, does addr point? */

know (fragP->fr_type == rs_machine_dependent);
length_code = fragP->fr_subtype & 3; /* depends on ENCODE_RELAX() */
know (length_code >= 0 && length_code < 3);
where = fragP->fr_fix;
addressP = fragP->fr_literal + where;
opcodeP = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
know (symbolP);
target_address = symbolP->sy_value + fragP->fr_offset;
address_of_var = fragP->fr_address + where;
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
know (*addressP == 0 || *addressP == 0x10); /* '@' bit. */
addressP[0] |= 0xAF; /* Byte displacement. */
addressP[1] = target_address - (address_of_var + 2);
extension = 2;
break;

case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
know (*addressP == 0 || *addressP == 0x10); /* '@' bit. */
addressP[0] |= 0xCF; /* Word displacement. */
md_number_to_chars (addressP + 1, target_address - (address_of_var + 3), 2);
extension = 3;
break;

case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
know (*addressP == 0 || *addressP == 0x10); /* '@' bit. */
addressP[0] |= 0xEF; /* Long word displacement. */
md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
extension = 5;
break;

case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
addressP[0] = target_address - (address_of_var + 1);
extension = 1;
break;

case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
opcodeP[0] ^= 1; /* Reverse sense of test. */
addressP[0] = 3;
addressP[1] = VAX_BRB + VAX_WIDEN_WORD;
md_number_to_chars (addressP + 2, target_address - (address_of_var + 4), 2);
extension = 4;
break;

case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
opcodeP[0] ^= 1; /* Reverse sense of test. */
addressP[0] = 6;
addressP[1] = VAX_JMP;
addressP[2] = VAX_PC_RELATIVE_MODE;
md_number_to_chars (addressP + 3, target_address, 4);
extension = 7;
break;

case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
addressP[0] = target_address - (address_of_var + 1);
extension = 1;
break;

case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
opcodeP[0] += VAX_WIDEN_WORD; /* brb -> brw, bsbb -> bsbw */
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;

case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
opcodeP[0] += VAX_WIDEN_LONG; /* brb -> jmp, bsbb -> jsb */
addressP[0] = VAX_PC_RELATIVE_MODE;
md_number_to_chars (addressP + 1, target_address - (address_of_var + 5), 4);
extension = 5;
break;

case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_WORD):
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;

case ENCODE_RELAX (STATE_COMPLEX_BRANCH, STATE_LONG):
addressP[0] = 2;
addressP[1] = 0;
addressP[2] = VAX_BRB;
addressP[3] = 6;
addressP[4] = VAX_JMP;
addressP[5] = VAX_PC_RELATIVE_MODE;
md_number_to_chars (addressP + 6, target_address, 4);
extension = 10;
break;

case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_BYTE):
addressP[0] = target_address - (address_of_var + 1);
extension = 1;
break;

case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_WORD):
addressP[0] = 2;
addressP[1] = VAX_BRB;
addressP[2] = 3;
addressP[3] = VAX_BRW;
md_number_to_chars (addressP + 4, target_address - (address_of_var + 6), 2);
extension = 6;
break;

case ENCODE_RELAX (STATE_COMPLEX_HOP, STATE_LONG):
addressP[0] = 2;
addressP[1] = VAX_BRB;
addressP[2] = 6;
addressP[3] = VAX_JMP;
addressP[4] = VAX_PC_RELATIVE_MODE;
md_number_to_chars (addressP + 5, target_address, 4);
extension = 9;
break;

default:
BAD_CASE (fragP->fr_subtype);
break;
}
fragP->fr_fix += extension;
}

/* the bit-field entries in the relocation_info struct plays hell
with the byte-order problems of cross-assembly. So as a hack,
I added this mach. dependent ri twiddler. Ugly, but it gets
you there. -KWK */
/* on vax: first 4 bytes are normal unsigned long, next three bytes
are symbolnum, least sig. byte first. Last byte is broken up with
the upper nibble as nuthin, bit 3 as extern, bits 2 & 1 as length, and
bit 0 as pcrel. */
void
md_ri_to_chars (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));
}



/* JF this used to be a separate file */
/* vax_ins_parse.c - a part for a VAX assembler */

/* Copyright (C) 1987 Free Software Foundtation, Inc */

/*
* BUGS, GRIPES, APOLOGIA, etc.
*
* The opcode table 'votstrs' needs to be sorted on opcode frequency.
* That is, AFTER we hash it with hash_...(), we want most-used opcodes
* to come out of the hash table faster.
*
* I am sorry to inflict
* yet another VAX assembler on the world, but RMS says we must
* do everything from scratch, to prevent pin-heads restricting
* this software.
*/

/*
* This is a vaguely modular set of routines in C to parse VAX
* assembly code using DEC mnemonics. It is NOT un*x specific.
*
* The idea here is that the assembler has taken care of all:
* labels
* macros
* listing
* pseudo-ops
* line continuation
* comments
* condensing any whitespace down to exactly one space
* and all we have to do is parse 1 line into a vax instruction
* partially formed. We will accept a line, and deliver:
* an error message (hopefully empty)
* a skeleton VAX instruction (tree structure)
* textual pointers to all the operand expressions
* a warning message that notes a silly operand (hopefully empty)
*/

/*
* E D I T H I S T O R Y
*
* 17may86 Dean Elsner. Bug if line ends immediately after opcode.
* 30apr86 Dean Elsner. New vip_op() uses arg block so change call.
* 6jan86 Dean Elsner. Crock vip_begin() to call vip_op_defaults().
* 2jan86 Dean Elsner. Invent synthetic opcodes.
* Widen vax_opcodeT to 32 bits. Use a bit for VIT_OPCODE_SYNTHETIC,
* which means this is not a real opcode, it is like a macro; it will
* be relax()ed into 1 or more instructions.
* Use another bit for VIT_OPCODE_SPECIAL if the op-code is not optimised
* like a regular branch instruction. Option added to vip_begin():
* exclude synthetic opcodes. Invent synthetic_votstrs[].
* 31dec85 Dean Elsner. Invent vit_opcode_nbytes.
* Also make vit_opcode into a char[]. We now have n-byte vax opcodes,
* so caller's don't have to know the difference between a 1-byte & a
* 2-byte op-code. Still need vax_opcodeT concept, so we know how
* big an object must be to hold an op.code.
* 30dec85 Dean Elsner. Widen typedef vax_opcodeT in "vax-inst.h"
* because vax opcodes may be 16 bits. Our crufty C compiler was
* happily initialising 8-bit vot_codes with 16-bit numbers!
* (Wouldn't the 'phone company like to compress data so easily!)
* 29dec85 Dean Elsner. New static table vax_operand_width_size[].
* Invented so we know hw many bytes a "I^#42" needs in its immediate
* operand. Revised struct vop in "vax-inst.h": explicitly include
* byte length of each operand, and it's letter-code datum type.
* 17nov85 Dean Elsner. Name Change.
* Due to ar(1) truncating names, we learned the hard way that
* "vax-inst-parse.c" -> "vax-inst-parse." dropping the "o" off
* the archived object name. SO... we shortened the name of this
* source file, and changed the makefile.
*/

/* #include JF for one big happy file */

/* JF #include "vax-inst.h" /* define the tree we parse it into */


static char *op_hash = NULL; /* handle of the OPCODE hash table */
/* NULL means any use before vip_begin() */
/* will crash */

/*
* In: 1 character, from "bdfghloqpw" being the data-type of an operand
* of a vax instruction.
*
* Out: the length of an operand of that type, in bytes.
* Special branch operands types "-?!" have length 0.
*/

static const short int vax_operand_width_size[256] =
{

#define _ 0
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16, /* ..b.d.fgh...l..o */
_, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _, /* .q.....w........ */
_, _, 1, _, 8, _, 4, 8, 16, _, _, _, 4, _, _, 16, /* ..b.d.fgh...l..o */
_, 8, _, _, _, _, _, 2, _, _, _, _, _, _, _, _, /* .q.....w........ */
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _};
#undef _

/*
* This perversion encodes all the vax opcodes as a bunch of strings.
* RMS says we should build our hash-table at run-time. Hmm.
* Please would someone arrange these in decreasing frequency of opcode?
* Because of the way hash_...() works, the most frequently used opcode
* should be textually first and so on.
*
* Input for this table was 'vax.opcodes', awk(1)ed by 'vax.opcodes.c.awk' .
* So change 'vax.opcodes', then re-generate this table.
*/

#include "vax-opcode.h"

/*
* This is a table of optional op-codes. All of them represent
* 'synthetic' instructions that seem popular.
*
* Here we make some pseudo op-codes. Every code has a bit set to say
* it is synthetic. This lets you catch them if you want to
* ban these opcodes. They are mnemonics for "elastic" instructions
* that are supposed to assemble into the fewest bytes needed to do a
* branch, or to do a conditional branch, or whatever.
*
* The opcode is in the usual place [low-order n*8 bits]. This means
* that if you mask off the bucky bits, the usual rules apply about
* how long the opcode is.
*
* All VAX branch displacements come at the end of the instruction.
* For simple branches (1-byte opcode + 1-byte displacement) the last
* operand is coded 'b?' where the "data type" '?' is a clue that we
* may reverse the sense of the branch (complement lowest order bit)
* and branch around a jump. This is by far the most common case.
* That is why the VIT_OPCODE_SYNTHETIC bit is set: it says this is
* a 0-byte op-code followed by 2 or more bytes of operand address.
*
* If the op-code has VIT_OPCODE_SPECIAL set, then we have a more unusual
* case.
*
* For JBSB & JBR the treatment is the similar, except (1) we have a 'bw'
* option before (2) we can directly JSB/JMP because there is no condition.
* These operands have 'b-' as their access/data type.
*
* That leaves a bunch of random opcodes: JACBx, JxOBxxx. In these
* cases, we do the same idea. JACBxxx are all marked with a 'b!'
* JAOBxxx & JSOBxxx are marked with a 'b:'.
*
*/
#if (VIT_OPCODE_SYNTHETIC != 0x80000000)
You have just broken the encoding below, which assumes the sign bit
means 'I am an imaginary instruction'.
#endif

#if (VIT_OPCODE_SPECIAL != 0x40000000)
You have just broken the encoding below, which assumes the 0x40 M bit means
'I am not to be "optimised" the way normal branches are'.
#endif

static const struct vot
synthetic_votstrs[] =
{
{"jbsb",
{"b-", 0xC0000010}}, /* BSD 4.2 */
/* jsb used already */
{"jbr",
{"b-", 0xC0000011}}, /* BSD 4.2 */
{"jr",
{"b-", 0xC0000011}}, /* consistent */
{"jneq",
{"b?", 0x80000012}},
{"jnequ",
{"b?", 0x80000012}},
{"jeql",
{"b?", 0x80000013}},
{"jeqlu",
{"b?", 0x80000013}},
{"jgtr",
{"b?", 0x80000014}},
{"jleq",
{"b?", 0x80000015}},
/* un-used opcodes here */
{"jgeq",
{"b?", 0x80000018}},
{"jlss",
{"b?", 0x80000019}},
{"jgtru",
{"b?", 0x8000001a}},
{"jlequ",
{"b?", 0x8000001b}},
{"jvc",
{"b?", 0x8000001c}},
{"jvs",
{"b?", 0x8000001d}},
{"jgequ",
{"b?", 0x8000001e}},
{"jcc",
{"b?", 0x8000001e}},
{"jlssu",
{"b?", 0x8000001f}},
{"jcs",
{"b?", 0x8000001f}},

{"jacbw",
{"rwrwmwb!", 0xC000003d}},
{"jacbf",
{"rfrfmfb!", 0xC000004f}},
{"jacbd",
{"rdrdmdb!", 0xC000006f}},
{"jacbb",
{"rbrbmbb!", 0xC000009d}},
{"jacbl",
{"rlrlmlb!", 0xC00000f1}},
{"jacbg",
{"rgrgmgb!", 0xC0004ffd}},
{"jacbh",
{"rhrhmhb!", 0xC0006ffd}},

{"jbs",
{"rlvbb?", 0x800000e0}},
{"jbc",
{"rlvbb?", 0x800000e1}},
{"jbss",
{"rlvbb?", 0x800000e2}},
{"jbcs",
{"rlvbb?", 0x800000e3}},
{"jbsc",
{"rlvbb?", 0x800000e4}},
{"jbcc",
{"rlvbb?", 0x800000e5}},
{"jbssi",
{"rlvbb?", 0x800000e6}},
{"jbcci",
{"rlvbb?", 0x800000e7}},
{"jlbs",
{"rlb?", 0x800000e8}}, /* JF changed from rlvbb? */
{"jlbc",
{"rlb?", 0x800000e9}}, /* JF changed from rlvbb? */

{"jaoblss",
{"rlmlb:", 0xC00000f2}},
{"jaobleq",
{"rlmlb:", 0xC00000f3}},
{"jsobgeq",
{"mlb:", 0xC00000f4}}, /* JF was rlmlb: */
{"jsobgtr",
{"mlb:", 0xC00000f5}}, /* JF was rlmlb: */

/* CASEx has no branch addresses in our conception of it. */
/* You should use ".word ..." statements after the "case ...". */

{"", ""} /* empty is end sentinel */

}; /* synthetic_votstrs */

/*
* v i p _ b e g i n ( )
*
* Call me once before you decode any lines.
* I decode votstrs into a hash table at op_hash (which I create).
* I return an error text: hopefully "".
* If you want, I will include the 'synthetic' jXXX instructions in the
* instruction table.
* You must nominate metacharacters for eg DEC's "#", "@", "^".
*/

char *
vip_begin (synthetic_too, immediate, indirect, displen)
int synthetic_too; /* TRUE means include jXXX op-codes. */
char *immediate, *indirect, *displen;
{
register const struct vot *vP; /* scan votstrs */
register char *retval; /* error text */

char *hash_insert (); /* */
char *hash_new (); /* lies */

if ((op_hash = hash_new ()))
{
retval = ""; /* OK so far */
for (vP = votstrs; *vP->vot_name && !*retval; vP++)
{
retval = hash_insert (op_hash, vP->vot_name, &vP->vot_detail);
}
if (synthetic_too)
{
for (vP = synthetic_votstrs; *vP->vot_name && !*retval; vP++)
{
retval = hash_insert (op_hash, vP->vot_name, &vP->vot_detail);
}
}
}
else
{
retval = "virtual memory exceeded";
}
#ifndef CONST_TABLE
vip_op_defaults (immediate, indirect, displen);
#endif

return (retval);
}


/*
* v i p _ e n d ( )
*
* Call me once after you have decoded all lines.
* I do any cleaning-up needed.
*
* We don't have to do any cleanup ourselves: all of our operand
* symbol table is static, and free()ing it is naughty.
*/
vip_end ()
{
}

/*
* v i p ( )
*
* This converts a string into a vax instruction.
* The string must be a bare single instruction in dec-vax (with BSD4 frobs)
* format.
* It provides some error messages: at most one fatal error message (which
* stops the scan) and at most one warning message for each operand.
* The vax instruction is returned in exploded form, since we have no
* knowledge of how you parse (or evaluate) your expressions.
* We do however strip off and decode addressing modes and operation
* mnemonic.
*
* The exploded instruction is returned to a struct vit of your choice.
* #include "vax-inst.h" to know what a struct vit is.
*
* This function's value is a string. If it is not "" then an internal
* logic error was found: read this code to assign meaning to the string.
* No argument string should generate such an error string:
* it means a bug in our code, not in the user's text.
*
* You MUST have called vip_begin() once and vip_end() never before using
* this function.
*/

char * /* "" or bug string */
vip (vitP, instring)
struct vit *vitP; /* We build an exploded instruction here. */
char *instring; /* Text of a vax instruction: we modify. */
{
register struct vot_wot *vwP; /* How to bit-encode this opcode. */
register char *p; /* 1/skip whitespace.2/scan vot_how */
register char *q; /* */
register char *bug; /* "" or program logic error */
register unsigned char count; /* counts number of operands seen */
register struct vop *operandp;/* scan operands in struct vit */
register char *alloperr; /* error over all operands */
register char c; /* Remember char, (we clobber it */
/* with '\0' temporarily). */
register vax_opcodeT oc; /* Op-code of this instruction. */

struct vot_wot *hash_find ();
char *vip_op ();

bug = "";
if (*instring == ' ')
++instring; /* Skip leading whitespace. */
for (p = instring; *p && *p != ' '; p++)
; /* MUST end in end-of-string or exactly 1 space. */
/* Scanned up to end of operation-code. */
/* Operation-code is ended with whitespace. */
if (p - instring == 0)
{
vitP->vit_error = "No operator";
count = 0;
bzero (vitP->vit_opcode, sizeof (vitP->vit_opcode));
}
else
{
c = *p;
*p = '\0';
/*
* Here with instring pointing to what better be an op-name, and p
* pointing to character just past that.
* We trust instring points to an op-name, with no whitespace.
*/
vwP = hash_find (op_hash, instring);
*p = c; /* Restore char after op-code. */
if (vwP == 0)
{
vitP->vit_error = "Unknown operator";
count = 0;
bzero (vitP->vit_opcode, sizeof (vitP->vit_opcode));
}
else
{
/*
* We found a match! So lets pick up as many operands as the
* instruction wants, and even gripe if there are too many.
* We expect comma to seperate each operand.
* We let instring track the text, while p tracks a part of the
* struct vot.
*/
/*
* The lines below know about 2-byte opcodes starting FD,FE or FF.
* They also understand synthetic opcodes. Note:
* we return 32 bits of opcode, including bucky bits, BUT
* an opcode length is either 8 or 16 bits for vit_opcode_nbytes.
*/
oc = vwP->vot_code; /* The op-code. */
vitP->vit_opcode_nbytes = (oc & 0xFF) >= 0xFD ? 2 : 1;
md_number_to_chars (vitP->vit_opcode, oc, 4);
count = 0; /* no operands seen yet */
instring = p; /* point just past operation code */
alloperr = "";
for (p = vwP->vot_how, operandp = vitP->vit_operand;
!*alloperr && !*bug && *p;
operandp++, p += 2
)
{
/*
* Here to parse one operand. Leave instring pointing just
* past any one ',' that marks the end of this operand.
*/
if (!p[1])
bug = "p"; /* ODD(!!) number of bytes in vot_how?? */
else if (*instring)
{
for (q = instring; (c = *q) && c != ','; q++)
;
/*
* Q points to ',' or '\0' that ends argument. C is that
* character.
*/
*q = 0;
operandp->vop_width = p[1];
operandp->vop_nbytes = vax_operand_width_size[p[1]];
operandp->vop_access = p[0];
bug = vip_op (instring, operandp);
*q = c; /* Restore input text. */
if (*(operandp->vop_error))
alloperr = "Bad operand";
instring = q + (c ? 1 : 0); /* next operand (if any) */
count++; /* won another argument, may have an operr */
}
else
alloperr = "Not enough operands";
}
if (!*alloperr)
{
if (*instring == ' ')
instring++; /* Skip whitespace. */
if (*instring)
alloperr = "Too many operands";
}
vitP->vit_error = alloperr;
}
}
vitP->vit_operands = count;
return (bug);
}

#ifdef test

/*
* Test program for above.
*/

struct vit myvit; /* build an exploded vax instruction here */
char answer[100]; /* human types a line of vax assembler here */
char *mybug; /* "" or an internal logic diagnostic */
int mycount; /* number of operands */
struct vop *myvop; /* scan operands from myvit */
int mysynth; /* TRUE means want synthetic opcodes. */
char my_immediate[200];
char my_indirect[200];
char my_displen[200];

char *vip ();

main ()
{
char *p;
char *vip_begin ();

printf ("0 means no synthetic instructions. ");
printf ("Value for vip_begin? ");
gets (answer);
sscanf (answer, "%d", &mysynth);
printf ("Synthetic opcodes %s be included.\n", mysynth ? "will" : "will not");
printf ("enter immediate symbols eg enter # ");
gets (my_immediate);
printf ("enter indirect symbols eg enter @ ");
gets (my_indirect);
printf ("enter displen symbols eg enter ^ ");
gets (my_displen);
if (*(p = vip_begin (mysynth, my_immediate, my_indirect, my_displen)))
{
error ("vip_begin=%s", p);
}
printf ("An empty input line will quit you from the vax instruction parser\n");
for (;;)
{
printf ("vax instruction: ");
fflush (stdout);
gets (answer);
if (!*answer)
{
break; /* out of for each input text loop */
}
mybug = vip (&myvit, answer);
if (*mybug)
{
printf ("BUG:\"%s\"\n", mybug);
}
if (*myvit.vit_error)
{
printf ("ERR:\"%s\"\n", myvit.vit_error);
}
printf ("opcode=");
for (mycount = myvit.vit_opcode_nbytes, p = myvit.vit_opcode;
mycount;
mycount--, p++
)
{
printf ("%02x ", *p & 0xFF);
}
printf (" operand count=%d.\n", mycount = myvit.vit_operands);
for (myvop = myvit.vit_operand; mycount; mycount--, myvop++)
{
printf ("mode=%xx reg=%xx ndx=%xx len='%c'=%c%c%d. expr=\"",
myvop->vop_mode, myvop->vop_reg, myvop->vop_ndx,
myvop->vop_short, myvop->vop_access, myvop->vop_width,
myvop->vop_nbytes);
for (p = myvop->vop_expr_begin; p <= myvop->vop_expr_end; p++)
{
putchar (*p);
}
printf ("\"\n");
if (*myvop->vop_error)
{
printf (" err:\"%s\"\n", myvop->vop_error);
}
if (*myvop->vop_warn)
{
printf (" wrn:\"%s\"\n", myvop->vop_warn);
}
}
}
vip_end ();
exit ();
}

#endif /* #ifdef test */

/* end of vax_ins_parse.c */

/* JF this used to be a separate file also */
/* vax_reg_parse.c - convert a VAX register name to a number */

/* Copyright (C) 1987 Free Software Foundation, Inc. A part of GNU. */

/*
* v a x _ r e g _ p a r s e ( )
*
* Take 3 char.s, the last of which may be `\0` (non-existent)
* and return the VAX register number that they represent.
*
* Return -1 if they don't form a register name. Good names return
* a number from 0:15 inclusive.
*
* Case is not important in a name.
*
* Register names understood are:
*
* R0
* R1
* R2
* R3
* R4
* R5
* R6
* R7
* R8
* R9
* R10
* R11
* R12 AP
* R13 FP
* R14 SP
* R15 PC
*
*/

#include
#define AP (12)
#define FP (13)
#define SP (14)
#define PC (15)

int /* return -1 or 0:15 */
vax_reg_parse (c1, c2, c3) /* 3 chars of register name */
char c1, c2, c3; /* c3 == 0 if 2-character reg name */
{
register int retval; /* return -1:15 */

retval = -1;

if (isupper (c1))
c1 = tolower (c1);
if (isupper (c2))
c2 = tolower (c2);
if (isdigit (c2) && c1 == 'r')
{
retval = c2 - '0';
if (isdigit (c3))
{
retval = retval * 10 + c3 - '0';
retval = (retval > 15) ? -1 : retval;
/* clamp the register value to 1 hex digit */
}
else if (c3)
retval = -1; /* c3 must be '\0' or a digit */
}
else if (c3) /* There are no three letter regs */
retval = -1;
else if (c2 == 'p')
{
switch (c1)
{
case 's':
retval = SP;
break;
case 'f':
retval = FP;
break;
case 'a':
retval = AP;
break;
default:
retval = -1;
}
}
else if (c1 == 'p' && c2 == 'c')
retval = PC;
else
retval = -1;
return (retval);
}

/* end: vax_reg_parse.c */

/* JF this was another separate prog */
/* vip_op.c - parse 1 VAX instr's operand.(C)1986 Free Software Foundation. */

/* JF #include */
/* #include "vax_inst.h" */

/*
* v i p _ o p ( )
*
* Parse a vax operand in DEC assembler notation.
* For speed, expect a string of whitespace to be reduced to a single ' '.
* This is the case for GNU AS, and is easy for other DEC-compatible
* assemblers.
*
* Knowledge about DEC VAX assembler operand notation lives here.
* This doesn't even know what a register name is, except it believes
* all register names are 2 or 3 characters, and lets vax_reg_parse() say
* what number each name represents.
* It does, however, know that PC, SP etc are special registers so it can
* detect addressing modes that are silly for those registers.
*
* Where possible, it delivers 1 fatal or 1 warning message if the operand
* is suspect. Exactly what we test for is still evolving.
*/

/*
* B u g s
*
* Arg block.
*
* There were a number of 'mismatched argument type' bugs to vip_op.
* The most general solution is to typedef each (of many) arguments.
* We used instead a typedef'd argument block. This is less modular
* than using seperate return pointers for each result, but runs faster
* on most engines, and seems to keep programmers happy. It will have
* to be done properly if we ever want to use vip_op as a general-purpose
* module (it was designed to be).
*
* G^
*
* Doesn't support DEC "G^" format operands. These always take 5 bytes
* to express, and code as modes 8F or 9F. Reason: "G^" deprives you of
* optimising to (say) a "B^" if you are lucky in the way you link.
* When someone builds a linker smart enough to convert "G^" to "B^", "W^"
* whenever possible, then we should implement it.
* If there is some other use for "G^", feel free to code it in!
*
*
* speed
*
* If I nested if()s more, I could avoid testing (*err) which would save
* time, space and page faults. I didn't nest all those if()s for clarity
* and because I think the mode testing can be re-arranged 1st to test the
* commoner constructs 1st. Does anybody have statistics on this?
*
*
*
* error messages
*
* In future, we should be able to 'compose' error messages in a scratch area
* and give the user MUCH more informative error messages. Although this takes
* a little more code at run-time, it will make this module much more self-
* documenting. As an example of what sucks now: most error messages have
* hardwired into them the DEC VAX metacharacters "#^@" which are nothing like
* the Un*x characters "$`*", that most users will expect from this AS.
*/

/*
* The input is a string, ending with '\0'.
*
* We also require a 'hint' of what kind of operand is expected: so
* we can remind caller not to write into literals for instance.
*
* The output is a skeletal instruction.
*
* The algorithm has two parts.
* 1. extract the syntactic features (parse off all the @^#-()+[] mode crud);
* 2. express the @^#-()+[] as some parameters suited to further analysis.
*
* 2nd step is where we detect the googles of possible invalid combinations
* a human (or compiler) might write. Note that if we do a half-way
* decent assembler, we don't know how long to make (eg) displacement
* fields when we first meet them (because they may not have defined values).
* So we must wait until we know how many bits are needed for each address,
* then we can know both length and opcodes of instructions.
* For reason(s) above, we will pass to our caller a 'broken' instruction
* of these major components, from which our caller can generate instructions:
* - displacement length I^ S^ L^ B^ W^ unspecified
* - mode (many)
* - register R0-R15 or absent
* - index register R0-R15 or absent
* - expression text what we don't parse
* - error text(s) why we couldn't understand the operand
*/

/*
* To decode output of this, test errtxt. If errtxt[0] == '\0', then
* we had no errors that prevented parsing. Also, if we ever report
* an internal bug, errtxt[0] is set non-zero. So one test tells you
* if the other outputs are to be taken seriously.
*/


/* vax registers we need to know */
/* JF #define SP (14)
/* JF for one big happy file #define PC (15) */

/* useful ideas */
/* #define TRUE (1) */
/* #define FALSE (0) */

/*
* Because this module is useful for both VMS and UN*X style assemblers
* and because of the variety of UN*X assemblers we must recognise
* the different conventions for assembler operand notation. For example
* VMS says "#42" for immediate mode, while most UN*X say "$42".
* We permit arbitrary sets of (single) characters to represent the
* 3 concepts that DEC writes '#', '@', '^'.
*/

/* character tests */
#define VIP_IMMEDIATE 01 /* Character is like DEC # */
#define VIP_INDIRECT 02 /* Char is like DEC @ */
#define VIP_DISPLEN 04 /* Char is like DEC ^ */

#define IMMEDIATEP(c) (vip_metacharacters [(c)&0xff]&VIP_IMMEDIATE)
#define INDIRECTP(c) (vip_metacharacters [(c)&0xff]&VIP_INDIRECT)
#define DISPLENP(c) (vip_metacharacters [(c)&0xff]&VIP_DISPLEN)

/* We assume 8 bits per byte. Use vip_op_defaults() to set these up BEFORE we
* are ever called.
*/

#if defined(CONST_TABLE)
#define _ 0,
#define I VIP_IMMEDIATE,
#define S VIP_INDIRECT,
#define D VIP_DISPLEN,
static const char
vip_metacharacters[256] = {
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*^@ ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J ^K ^L ^M ^N ^O*/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y ^Z ^[ ^\ ^] ^^ ^_*/
_ _ _ _ I _ _ _ _ _ S _ _ _ _ _/*sp ! " # $ % & ' ( ) * + , - . /*/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*0 1 2 3 4 5 6 7 8 9 : ; < = > ?*/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*@ A B C D E F G H I J K L M N O*/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*P Q R S T U V W X Y Z [ \ ] ^ _*/
D _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*` a b c d e f g h i j k l m n o*/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _/*p q r s t u v w x y z { | } ~ ^?*/

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};
#undef _
#undef I
#undef S
#undef D
#else
static char vip_metacharacters[256];

/* Macro is faster under GCC; The constant table is faster yet, but only works with ASCII */
#if 0
static
#ifdef __GNUC__
inline
#endif
static void
vip_op_1(bit,syms)
int bit;
char *syms;
{
unsigned char t;

while(t= *syms++)
vip_metacharacters[t]|=bit;
}
#else
#define vip_op_1(bit,syms) { \
unsigned char t; \
char *table=vip_metacharacters; \
while(t= *syms++) \
table[t]|=bit; \
}
#endif

vip_op_defaults (immediate, indirect, displen) /* can be called any time */
char *immediate, /* Strings of characters for each job. */
*indirect, *displen; /* more arguments may appear in future! */
{
vip_op_1 (VIP_IMMEDIATE, immediate);
vip_op_1 (VIP_INDIRECT, indirect);
vip_op_1 (VIP_DISPLEN, displen);
}
#endif


/*
* Dec defines the semantics of address modes (and values)
* by a two-letter code, explained here.
*
* letter 1: access type
*
* a address calculation - no data access, registers forbidden
* b branch displacement
* m read - let go of bus - write back "modify"
* r read
* v bit field address: like 'a' but registers are OK
* w write
* space no operator (eg ".long foo") [our convention]
*
* letter 2: data type (i.e. width, alignment)
*
* b byte
* d double precision floating point (D format)
* f single precision floating point (F format)
* g G format floating
* h H format floating
* l longword
* o octaword
* q quadword
* w word
* ? simple synthetic branch operand
* - unconditional synthetic JSB/JSR operand
* ! complex synthetic branch operand
*
* The '-?!' letter 2's are not for external consumption. They are used
* for various assemblers. Generally, all unknown widths are assumed 0.
* We don't limit your choice of width character.
*
* DEC operands are hard work to parse. For example, '@' as the first
* character means indirect (deferred) mode but elswhere it is a shift
* operator.
* The long-winded explanation of how this is supposed to work is
* cancelled. Read a DEC vax manual.
* We try hard not to parse anything that MIGHT be part of the expression
* buried in that syntax. For example if we see @...(Rn) we don't check
* for '-' before the '(' because mode @-(Rn) does not exist.
*
* After parsing we have:
*
* at TRUE if leading '@' (or Un*x '*')
* len takes one value from " bilsw". eg B^ -> 'b'.
* hash TRUE if leading '#' (or Un*x '$')
* expr_begin, expr_end the expression we did not parse
* even though we don't interpret it, we make use
* of its presence or absence.
* sign -1: -(Rn) 0: absent +1: (Rn)+
* paren TRUE if () are around register
* reg major register number 0:15 -1 means absent
* ndx index register number 0:15 -1 means absent
*
* Again, I dare not explain it: just trace ALL the code!
*/

char * /* (code here) bug message, "" = OK */
/* our code bug, NOT bad assembly language */
vip_op (optext, vopP)
char *optext; /* user's input string e.g.: */
/* "@B^foo@bar(AP)[FP]:" */
struct vop *vopP; /* In: vop_access, vop_width. */
/* Out: _ndx, _reg, _mode, _short, _warn, */
/* _error _expr_begin, _expr_end, _nbytes. */
/* vop_nbytes : number of bytes in a datum. */
{
char *p; /* track operand text forward */
char *q; /* track operand text backward */
int at; /* TRUE if leading '@' ('*') seen */
char len; /* one of " bilsw" */
int hash; /* TRUE if leading '#' ('$') seen */
int sign; /* -1, 0 or +1 */
int paren; /* TRUE if () surround register */
int reg; /* register number, -1:absent */
int ndx; /* index register number -1:absent */
char *bug; /* report any logic error in here, ""==OK */
char *err; /* report illegal operand, ""==OK */
/* " " is a FAKE error: means we won */
/* ANY err that begins with ' ' is a fake. */
/* " " is converted to "" before return */
char *wrn; /* warn about weird modes pf address */
char *oldq; /* preserve q in case we backup */
int mode; /* build up 4-bit operand mode here */
/* note: index mode is in ndx, this is */
/* the major mode of operand address */
/*
* Notice how we move wrong-arg-type bugs INSIDE this module: if we
* get the types wrong below, we lose at compile time rather than at
* lint or run time.
*/
char access; /* vop_access. */
char width; /* vop_width. */

int vax_reg_parse (); /* returns 0:15 or -1 if not a register */

access = vopP->vop_access;
width = vopP->vop_width;
bug = /* none of our code bugs (yet) */
err = /* no user text errors */
wrn = ""; /* no warnings even */

p = optext;

if (*p == ' ') /* Expect all whitespace reduced to ' '. */
p++; /* skip over whitespace */

if (at = INDIRECTP (*p))
{ /* TRUE if *p=='@'(or '*' for Un*x) */
p++; /* at is determined */
if (*p == ' ') /* Expect all whitespace reduced to ' '. */
p++; /* skip over whitespace */
}

/*
* This code is subtle. It tries to detect all legal (letter)'^'
* but it doesn't waste time explicitly testing for premature '\0' because
* this case is rejected as a mismatch against either (letter) or '^'.
*/
{
register char c;

c = *p;
if (isupper (c))
c = tolower (c);
if (DISPLENP (p[1]) && index ("bilws", len = c))
p += 2; /* skip (letter) '^' */
else /* no (letter) '^' seen */
len = ' '; /* len is determined */
}

if (*p == ' ') /* Expect all whitespace reduced to ' '. */
p++; /* skip over whitespace */

if (hash = IMMEDIATEP (*p)) /* TRUE if *p=='#' ('$' for Un*x) */
p++; /* hash is determined */

/*
* p points to what may be the beginning of an expression.
* We have peeled off the front all that is peelable.
* We know at, len, hash.
*
* Lets point q at the end of the text and parse that (backwards).
*/

for (q = p; *q; q++)
;
q--; /* now q points at last char of text */

if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
q--;
/* reverse over whitespace, but don't */
/* run back over *p */

/*
* As a matter of policy here, we look for [Rn], although both Rn and S^#
* forbid [Rn]. This is because it is easy, and because only a sick
* cyborg would have [...] trailing an expression in a VAX-like assembler.
* A meticulous parser would first check for Rn followed by '(' or '['
* and not parse a trailing ']' if it found another. We just ban expressions
* ending in ']'.
*/
if (*q == ']')
{
while (q >= p && *q != '[')
q--;
/* either q

if (q < p)
err = "no '[' to match ']'";
else
{
/*
* Confusers like "[]" will eventually lose with a bad register
* name error. So again we don't need to check for early '\0'.
*/
if (q[3] == ']')
ndx = vax_reg_parse (q[1], q[2], 0);
else if (q[4] == ']')
ndx = vax_reg_parse (q[1], q[2], q[3]);
else
ndx = -1;
/*
* Since we saw a ']' we will demand a register name in the [].
* If luser hasn't given us one: be rude.
*/
if (ndx < 0)
err = "bad register in []";
else if (ndx == PC)
err = "[PC] index banned";
else
q--; /* point q just before "[...]" */
}
}
else
ndx = -1; /* no ']', so no iNDeX register */

/*
* If err = "..." then we lost: run away.
* Otherwise ndx == -1 if there was no "[...]".
* Otherwise, ndx is index register number, and q points before "[...]".
*/

if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
q--;
/* reverse over whitespace, but don't */
/* run back over *p */
if (!*err)
{
sign = 0; /* no ()+ or -() seen yet */

if (q > p + 3 && *q == '+' && q[-1] == ')')
{
sign = 1; /* we saw a ")+" */
q--; /* q points to ')' */
}

if (*q == ')' && q > p + 2)
{
paren = TRUE; /* assume we have "(...)" */
while (q >= p && *q != '(')
q--;
/* either q

if (q < p)
err = "no '(' to match ')'";
else
{
/*
* Confusers like "()" will eventually lose with a bad register
* name error. So again we don't need to check for early '\0'.
*/
if (q[3] == ')')
reg = vax_reg_parse (q[1], q[2], 0);
else if (q[4] == ')')
reg = vax_reg_parse (q[1], q[2], q[3]);
else
reg = -1;
/*
* Since we saw a ')' we will demand a register name in the ')'.
* This is nasty: why can't our hypothetical assembler permit
* parenthesised expressions? BECAUSE I AM LAZY! That is why.
* Abuse luser if we didn't spy a register name.
*/
if (reg < 0)
{
/* JF allow parenthasized expressions. I hope this works */
paren = FALSE;
while (*q != ')')
q++;
/* err = "unknown register in ()"; */
}
else
q--; /* point just before '(' of "(...)" */
/*
* If err == "..." then we lost. Run away.
* Otherwise if reg >= 0 then we saw (Rn).
*/
}
/*
* If err == "..." then we lost.
* Otherwise paren==TRUE and reg = register in "()".
*/
}
else
paren = FALSE;
/*
* If err == "..." then we lost.
* Otherwise, q points just before "(Rn)", if any.
* If there was a "(...)" then paren==TRUE, and reg is the register.
*/

/*
* We should only seek '-' of "-(...)" if:
* we saw "(...)" paren == TRUE
* we have no errors so far ! *err
* we did not see '+' of "(...)+" sign < 1
* We don't check len. We want a specific error message later if
* user tries "x^...-(Rn)". This is a feature not a bug.
*/
if (!*err)
{
if (paren && sign < 1)/* !sign is adequate test */
{
if (*q == '-')
{
sign = -1;
q--;
}
}
/*
* We have back-tracked over most
* of the crud at the end of an operand.
* Unless err, we know: sign, paren. If paren, we know reg.
* The last case is of an expression "Rn".
* This is worth hunting for if !err, !paren.
* We wouldn't be here if err.
* We remember to save q, in case we didn't want "Rn" anyway.
*/
if (!paren)
{
if (*q == ' ' && q >= p) /* Expect all whitespace reduced to ' '. */
q--;
/* reverse over whitespace, but don't */
/* run back over *p */
if (q > p && q < p + 3) /* room for Rn or Rnn exactly? */
reg = vax_reg_parse (p[0], p[1], q < p + 2 ? 0 : p[2]);
else
reg = -1; /* always comes here if no register at all */
/*
* Here with a definitive reg value.
*/
if (reg >= 0)
{
oldq = q;
q = p - 1;
}
}
}
}
/*
* have reg. -1:absent; else 0:15
*/

/*
* We have: err, at, len, hash, ndx, sign, paren, reg.
* Also, any remaining expression is from *p through *q inclusive.
* Should there be no expression, q==p-1. So expression length = q-p+1.
* This completes the first part: parsing the operand text.
*/

/*
* We now want to boil the data down, checking consistency on the way.
* We want: len, mode, reg, ndx, err, p, q, wrn, bug.
* We will deliver a 4-bit reg, and a 4-bit mode.
*/

/*
* Case of branch operand. Different. No L^B^W^I^S^ allowed for instance.
*
* in: at ?
* len ?
* hash ?
* p:q ?
* sign ?
* paren ?
* reg ?
* ndx ?
*
* out: mode 0
* reg -1
* len ' '
* p:q whatever was input
* ndx -1
* err " " or error message, and other outputs trashed
*/
/* branch operands have restricted forms */
if (!*err && access == 'b')
{
if (at || hash || sign || paren || ndx >= 0 || reg >= 0 || len != ' ')
err = "invalid branch operand";
else
err = " ";
}

/* Since nobody seems to use it: comment this 'feature'(?) out for now. */
#ifdef NEVER
/*
* Case of stand-alone operand. e.g. ".long foo"
*
* in: at ?
* len ?
* hash ?
* p:q ?
* sign ?
* paren ?
* reg ?
* ndx ?
*
* out: mode 0
* reg -1
* len ' '
* p:q whatever was input
* ndx -1
* err " " or error message, and other outputs trashed
*/
if (!*err)
{
if (access == ' ')
{ /* addresses have restricted forms */
if (at)
err = "address prohibits @";
else
{
if (hash)
err = "address prohibits #";
else
{
if (sign)
{
if (sign < 0)
err = "address prohibits -()";
else
err = "address prohibits ()+";
}
else
{
if (paren)
err = "address prohibits ()";
else
{
if (ndx >= 0)
err = "address prohibits []";
else
{
if (reg >= 0)
err = "address prohibits register";
else
{
if (len != ' ')
err = "address prohibits displacement length specifier";
else
{
err = " "; /* succeed */
mode = 0;
}
}
}
}
}
}
}
}
}
#endif /*#Ifdef NEVER*/

/*
* Case of S^#.
*
* in: at FALSE
* len 's' definition
* hash TRUE demand
* p:q demand not empty
* sign 0 by paren==FALSE
* paren FALSE by "()" scan logic because "S^" seen
* reg -1 or nn by mistake
* ndx -1
*
* out: mode 0
* reg -1
* len 's'
* exp
* ndx -1
*/
if (!*err && len == 's')
{
if (!hash || paren || at || ndx >= 0)
err = "invalid operand of S^#";
else
{
if (reg >= 0)
{
/*
* SHIT! we saw S^#Rnn ! put the Rnn back in
* expression. KLUDGE! Use oldq so we don't
* need to know exact length of reg name.
*/
q = oldq;
reg = 0;
}
/*
* We have all the expression we will ever get.
*/
if (p > q)
err = "S^# needs expression";
else if (access == 'r')
{
err = " "; /* WIN! */
mode = 0;
}
else
err = "S^# may only read-access";
}
}

/*
* Case of -(Rn), which is weird case.
*
* in: at FALSE
* len '
* hash FALSE
* p:q q * sign -1 by definition
* paren TRUE by definition
* reg present by definition
* ndx optional
*
* out: mode 7
* reg present
* len ' '
* exp "" enforce empty expression
* ndx optional warn if same as reg
*/
if (!*err && sign < 0)
{
if (len != ' ' || hash || at || p <= q)
err = "invalid operand of -()";
else
{
err = " "; /* win */
mode = 7;
if (reg == PC)
wrn = "-(PC) unpredictable";
else if (reg == ndx)
wrn = "[]index same as -()register: unpredictable";
}
}

/*
* We convert "(Rn)" to "@Rn" for our convenience.
* (I hope this is convenient: has someone got a better way to parse this?)
* A side-effect of this is that "@Rn" is a valid operand.
*/
if (paren && !sign && !hash && !at && len == ' ' && p > q)
{
at = TRUE;
paren = FALSE;
}

/*
* Case of (Rn)+, which is slightly different.
*
* in: at
* len ' '
* hash FALSE
* p:q q * sign +1 by definition
* paren TRUE by definition
* reg present by definition
* ndx optional
*
* out: mode 8+@
* reg present
* len ' '
* exp "" enforce empty expression
* ndx optional warn if same as reg
*/
if (!*err && sign > 0)
{
if (len != ' ' || hash || p <= q)
err = "invalid operand of ()+";
else
{
err = " "; /* win */
mode = 8 + (at ? 1 : 0);
if (reg == PC)
wrn = "(PC)+ unpredictable";
else if (reg == ndx)
wrn = "[]index same as ()+register: unpredictable";
}
}

/*
* Case of #, without S^.
*
* in: at
* len ' ' or 'i'
* hash TRUE by definition
* p:q
* sign 0
* paren FALSE
* reg absent
* ndx optional
*
* out: mode 8+@
* reg PC
* len ' ' or 'i'
* exp
* ndx optional
*/
if (!*err && hash)
{
if (len != 'i' && len != ' ')
err = "# conflicts length";
else if (paren)
err = "# bars register";
else
{
if (reg >= 0)
{
/*
* SHIT! we saw #Rnn! Put the Rnn back into the expression.
* By using oldq, we don't need to know how long Rnn was.
* KLUDGE!
*/
q = oldq;
reg = -1; /* no register any more */
}
err = " "; /* win */

/* JF a bugfix, I think! */
if(at && access=='a')
vopP->vop_nbytes=4;

mode = (at ? 9 : 8);
reg = PC;
if ((access == 'm' || access == 'w') && !at)
wrn = "writing or modifying # is unpredictable";
}
}
/*
* If !*err, then sign == 0
* hash == FALSE
*/

/*
* Case of Rn. We seperate this one because it has a few special
* errors the remaining modes lack.
*
* in: at optional
* len ' '
* hash FALSE by program logic
* p:q empty
* sign 0 by program logic
* paren FALSE by definition
* reg present by definition
* ndx optional
*
* out: mode 5+@
* reg present
* len ' ' enforce no length
* exp "" enforce empty expression
* ndx optional warn if same as reg
*/
if (!*err && !paren && reg >= 0)
{
if (len != ' ')
err = "length not needed";
else if (at)
{
err = " "; /* win */
mode = 6; /* @Rn */
}
else if (ndx >= 0)
err = "can't []index a register, because it has no address";
else if (access == 'a')
err = "a register has no address";
else
{
/*
* Idea here is to detect from length of datum
* and from register number if we will touch PC.
* Warn if we do.
* vop_nbytes is number of bytes in operand.
* Compute highest byte affected, compare to PC0.
*/
if ((vopP->vop_nbytes + reg * 4) > 60)
wrn = "PC part of operand unpredictable";
err = " "; /* win */
mode = 5; /* Rn */
}
}
/*
* If !*err, sign == 0
* hash == FALSE
* paren == TRUE OR reg==-1
*/

/*
* Rest of cases fit into one bunch.
*
* in: at optional
* len ' ' or 'b' or 'w' or 'l'
* hash FALSE by program logic
* p:q expected (empty is not an error)
* sign 0 by program logic
* paren optional
* reg optional
* ndx optional
*
* out: mode 10 + @ + len
* reg optional
* len ' ' or 'b' or 'w' or 'l'
* exp maybe empty
* ndx optional warn if same as reg
*/
if (!*err)
{
err = " "; /* win (always) */
mode = 10 + (at ? 1 : 0);
switch (len)
{
case 'l':
mode += 2;
case 'w':
mode += 2;
case ' ': /* assumed B^ until our caller changes it */
case 'b':
break;
}
}

/*
* here with completely specified mode
* len
* reg
* expression p,q
* ndx
*/

if (*err == ' ')
err = ""; /* " " is no longer an error */

vopP->vop_mode = mode;
vopP->vop_reg = reg;
vopP->vop_short = len;
vopP->vop_expr_begin = p;
vopP->vop_expr_end = q;
vopP->vop_ndx = ndx;
vopP->vop_error = err;
vopP->vop_warn = wrn;
return (bug);

} /* vip_op() */

/*

Summary of vip_op outputs.

mode reg len ndx
(Rn) => @Rn
{@}Rn 5+@ n ' ' optional
branch operand 0 -1 ' ' -1
S^#foo 0 -1 's' -1
-(Rn) 7 n ' ' optional
{@}(Rn)+ 8+@ n ' ' optional
{@}#foo, no S^ 8+@ PC " i" optional
{@}{q^}{(Rn)} 10+@+q option " bwl" optional

*/

#ifdef TEST /* #Define to use this testbed. */

/*
* Follows a test program for this function.
* We declare arrays non-local in case some of our tiny-minded machines
* default to small stacks. Also, helps with some debuggers.
*/

#include

char answer[100]; /* human types into here */
char *p; /* */
char *myerr;
char *mywrn;
char *mybug;
char myaccess;
char mywidth;
char mymode;
char myreg;
char mylen;
char *myleft;
char *myright;
char myndx;
int my_operand_length;
char my_immediate[200];
char my_indirect[200];
char my_displen[200];

main ()
{
char *vip_op (); /* make cc happy */

printf ("enter immediate symbols eg enter # ");
gets (my_immediate);
printf ("enter indirect symbols eg enter @ ");
gets (my_indirect);
printf ("enter displen symbols eg enter ^ ");
gets (my_displen);
vip_op_defaults (my_immediate, my_indirect, my_displen);
for (;;)
{
printf ("access,width (eg 'ab' or 'wh') [empty line to quit] : ");
fflush (stdout);
gets (answer);
if (!answer[0])
exit (0);
myaccess = answer[0];
mywidth = answer[1];
switch (mywidth)
{
case 'b':
my_operand_length = 1;
break;
case 'd':
my_operand_length = 8;
break;
case 'f':
my_operand_length = 4;
break;
case 'g':
my_operand_length = 16;
break;
case 'h':
my_operand_length = 32;
break;
case 'l':
my_operand_length = 4;
break;
case 'o':
my_operand_length = 16;
break;
case 'q':
my_operand_length = 8;
break;
case 'w':
my_operand_length = 2;
break;
case '!':
case '?':
case '-':
my_operand_length = 0;
break;

default:
my_operand_length = 2;
printf ("I dn't understand access width %c\n", mywidth);
break;
}
printf ("VAX assembler instruction operand: ");
fflush (stdout);
gets (answer);
mybug = vip_op (answer, myaccess, mywidth, my_operand_length,
&mymode, &myreg, &mylen, &myleft, &myright, &myndx,
&myerr, &mywrn);
if (*myerr)
{
printf ("error: \"%s\"\n", myerr);
if (*mybug)
printf (" bug: \"%s\"\n", mybug);
}
else
{
if (*mywrn)
printf ("warning: \"%s\"\n", mywrn);
mumble ("mode", mymode);
mumble ("register", myreg);
mumble ("index", myndx);
printf ("width:'%c' ", mylen);
printf ("expression: \"");
while (myleft <= myright)
putchar (*myleft++);
printf ("\"\n");
}
}
}

mumble (text, value)
char *text;
int value;
{
printf ("%s:", text);
if (value >= 0)
printf ("%xx", value);
else
printf ("ABSENT");
printf (" ");
}

#endif /* ifdef TEST */

/* end: vip_op.c */

/* end: vax.c */

/* JF: new routines */

const int md_short_jump_size = 3;

const int md_long_jump_size = 6;

void
md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
long from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
long offset;

offset = to_addr - (from_addr + 1);
*ptr++ = 0x31;
md_number_to_chars (ptr, offset, 2);
}

void
md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
long from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
long offset;

offset = to_addr - to_symbol->sy_value;
*ptr++ = 0x17;
*ptr++ = 0x9F;
md_number_to_chars (ptr, offset, 4);
fix_new (frag, ptr - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long int) 0, 0);
}

int
md_parse_option (argP, cntP, vecP)
char **argP;
int *cntP;
char ***vecP;
{
char *temp_name; /* name for -t or -d options */
char opt;

switch (**argP)
{
case 'J':
/* as_warn ("I can do better than -J!"); */
break;

case 'S':
as_warn ("SYMBOL TABLE not implemented");
break; /* SYMBOL TABLE not implemented */

case 'T':
as_warn ("TOKEN TRACE not implemented");
break; /* TOKEN TRACE not implemented */

case 'd':
case 't':
opt= **argP;
if (**argP)
{ /* Rest of argument is filename. */
temp_name = *argP;
while (**argP)
(*argP)++;
}
else if (*cntP)
{
while (**argP)
(*argP)++;
--(*cntP);
temp_name = *++(*vecP);
**vecP = NULL; /* Remember this is not a file-name. */
}
else
{
as_warn ("I expected a filename after -%c.",opt);
temp_name = "{absent}";
}

if(opt=='d')
as_warn ("Displacement length %s ignored!", temp_name);
else
as_warn ("I don't need or use temp. file \"%s\".", temp_name);
break;

case 'V':
as_warn ("I don't use an interpass file! -V ignored");
break;

#ifdef VMS
case '+': /* For g++ */
break;

case 'h': /* No hashing of mixed-case names */
break;

case 'H': /* Show new symbol after hash truncation */
break;
#endif

default:
return 0;

}
return 1;
}
gas-1.38/atof-vax.c 666 12412 0 32347 4705116453 11510 0ustar randy/* atof_vax.c - turn a Flonum into a VAX floating point number
Copyright (C) 1987 Free Software Foundation, Inc.

This file is part of GAS, the GNU Assembler.

GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* JF added these two for md_atof() */
#include "as.h"
#include "read.h"

#include "flonum.h"


/* Precision in LittleNums. */
#define MAX_PRECISION (8)
#define H_PRECISION (8)
#define G_PRECISION (4)
#define D_PRECISION (4)
#define F_PRECISION (2)

/* Length in LittleNums of guard bits. */
#define GUARD (2)

int /* Number of chars in flonum type 'letter'. */
atof_vax_sizeof (letter)
char letter;
{
int return_value;

/*
* Permitting uppercase letters is probably a bad idea.
* Please use only lower-cased letters in case the upper-cased
* ones become unsupported!
*/
switch (letter)
{
case 'f':
case 'F':
return_value = 4;
break;

case 'd':
case 'D':
case 'g':
case 'G':
return_value = 8;
break;

case 'h':
case 'H':
return_value = 16;
break;

default:
return_value = 0;
break;
}
return (return_value);
} /* atof_vax_sizeof */

static const long 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
};


/* Shared between flonum_gen2vax and next_bits */
static int bits_left_in_littlenum;
static LITTLENUM_TYPE * littlenum_pointer;
static LITTLENUM_TYPE * littlenum_end;

static int
next_bits (number_of_bits)
int number_of_bits;
{
int return_value;

if(littlenum_pointer return 0;
if (number_of_bits >= bits_left_in_littlenum)
{
return_value = mask [bits_left_in_littlenum] & * littlenum_pointer;
number_of_bits -= bits_left_in_littlenum;
return_value <<= number_of_bits;
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
littlenum_pointer --;
if(littlenum_pointer>=littlenum_end)
return_value |= ( (* littlenum_pointer) >> (bits_left_in_littlenum) ) & mask [number_of_bits];
}
else
{
bits_left_in_littlenum -= number_of_bits;
return_value = mask [number_of_bits] & ( (* littlenum_pointer) >> bits_left_in_littlenum);
}
return (return_value);
}

static void
make_invalid_floating_point_number (words)
LITTLENUM_TYPE * words;
{
* words = 0x8000; /* Floating Reserved Operand Code */
}

static int /* 0 means letter is OK. */
what_kind_of_float (letter, precisionP, exponent_bitsP)
char letter; /* In: lowercase please. What kind of float? */
int * precisionP; /* Number of 16-bit words in the float. */
long int * exponent_bitsP; /* Number of exponent bits. */
{
int retval; /* 0: OK. */

retval = 0;
switch (letter)
{
case 'f':
* precisionP = F_PRECISION;
* exponent_bitsP = 8;
break;

case 'd':
* precisionP = D_PRECISION;
* exponent_bitsP = 8;
break;

case 'g':
* precisionP = G_PRECISION;
* exponent_bitsP = 11;
break;

case 'h':
* precisionP = H_PRECISION;
* exponent_bitsP = 15;
break;

default:
retval = 69;
break;
}
return (retval);
}

/***********************************************************************\
* *
* Warning: this returns 16-bit LITTLENUMs, because that is *
* what the VAX thinks in. It is up to the caller to figure *
* out any alignment problems and to conspire for the bytes/word *
* to be emitted in the right order. Bigendians beware! *
* *
\***********************************************************************/

char * /* Return pointer past text consumed. */
atof_vax (str, what_kind, words)
char * str; /* Text to convert to binary. */
char what_kind; /* 'd', 'f', 'g', 'h' */
LITTLENUM_TYPE * words; /* Build the binary here. */
{
FLONUM_TYPE f;
LITTLENUM_TYPE bits [MAX_PRECISION + MAX_PRECISION + GUARD];
/* Extra bits for zeroed low-order bits. */
/* The 1st MAX_PRECISION are zeroed, */
/* the last contain flonum bits. */
char * return_value;
int precision; /* Number of 16-bit words in the format. */
long int exponent_bits;

return_value = str;
f . low = bits + MAX_PRECISION;
f . high = NULL;
f . leader = NULL;
f . exponent = NULL;
f . sign = '\0';

if (what_kind_of_float (what_kind, & precision, & exponent_bits))
{
return_value = NULL; /* We lost. */
make_invalid_floating_point_number (words);
}
if (return_value)
{
bzero (bits, sizeof(LITTLENUM_TYPE) * MAX_PRECISION);

/* Use more LittleNums than seems */
/* necessary: the highest flonum may have */
/* 15 leading 0 bits, so could be useless. */
f . high = f . low + precision - 1 + GUARD;

if (atof_generic (& return_value, ".", "eE", & f))
{
make_invalid_floating_point_number (words);
return_value = NULL; /* we lost */
}
else
{
if (flonum_gen2vax (what_kind, & f, words))
{
return_value = NULL;
}
}
}
return (return_value);
}

/*
* In: a flonum, a vax floating point format.
* Out: a vax floating-point bit pattern.
*/

int /* 0: OK. */
flonum_gen2vax (format_letter, f, words)
char format_letter; /* One of 'd' 'f' 'g' 'h'. */
FLONUM_TYPE * f;
LITTLENUM_TYPE * words; /* Deliver answer here. */
{
LITTLENUM_TYPE * lp;
int precision;
long int exponent_bits;
int return_value; /* 0 == OK. */

return_value = what_kind_of_float (format_letter, & precision, & exponent_bits);
if (return_value != 0)
{
make_invalid_floating_point_number (words);
}
else
{
if (f -> low > f -> leader)
{
/* 0.0e0 seen. */
bzero (words, sizeof(LITTLENUM_TYPE) * precision);
}
else
{
long int exponent_1;
long int exponent_2;
long int exponent_3;
long int exponent_4;
int exponent_skippage;
LITTLENUM_TYPE word1;

/* JF: Deal with new Nan, +Inf and -Inf codes */
if(f->sign!='-' && f->sign!='+') {
make_invalid_floating_point_number(words);
return return_value;
}
/*
* All vaxen floating_point formats (so far) have:
* Bit 15 is sign bit.
* Bits 14:n are excess-whatever exponent.
* Bits n-1:0 (if any) are most significant bits of fraction.
* Bits 15:0 of the next word are the next most significant bits.
* And so on for each other word.
*
* All this to be compatible with a KF11?? (Which is still faster
* than lots of vaxen I can think of, but it also has higher
* maintenance costs ... sigh).
*
* So we need: number of bits of exponent, number of bits of
* mantissa.
*/

#ifdef NEVER /******* This zeroing seems redundant - Dean 3may86 **********/
/*
* No matter how few bits we got back from the atof()
* routine, add enough zero littlenums so the rest of the
* code won't run out of "significant" bits in the mantissa.
*/
{
LITTLENUM_TYPE * ltp;
for (ltp = f -> leader + 1;
ltp <= f -> low + precision;
ltp ++)
{
* ltp = 0;
}
}
#endif

bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
littlenum_pointer = f -> leader;
littlenum_end = f->low;
/* Seek (and forget) 1st significant bit */
for (exponent_skippage = 0;
! next_bits(1);
exponent_skippage ++)
{
}
exponent_1 = f -> exponent + f -> leader + 1 - f -> low;
/* Radix LITTLENUM_RADIX, point just higher than f -> leader. */
exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
/* Radix 2. */
exponent_3 = exponent_2 - exponent_skippage;
/* Forget leading zeros, forget 1st bit. */
exponent_4 = exponent_3 + (1 << (exponent_bits - 1));
/* Offset exponent. */

if (exponent_4 & ~ mask [exponent_bits])
{
/*
* Exponent overflow. Lose immediately.
*/

make_invalid_floating_point_number (words);

/*
* We leave return_value alone: admit we read the
* number, but return a floating exception
* because we can't encode the number.
*/
}
else
{
lp = words;

/* Word 1. Sign, exponent and perhaps high bits. */
/* Assume 2's complement integers. */
word1 = ((exponent_4 & mask [exponent_bits]) << (15 - exponent_bits))
| ((f -> sign == '+') ? 0 : 0x8000)
| next_bits (15 - exponent_bits);
* lp ++ = word1;

/* The rest of the words are just mantissa bits. */
for (; lp < words + precision; lp++)
{
* lp = next_bits (LITTLENUM_NUMBER_OF_BITS);
}

if (next_bits (1))
{
/*
* Since the NEXT bit is a 1, round UP the mantissa.
* The cunning design of these hidden-1 floats permits
* us to let the mantissa overflow into the exponent, and
* it 'does the right thing'. However, we lose if the
* highest-order bit of the lowest-order word flips.
* Is that clear?
*/

unsigned long int carry;

/*
#if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
Please allow at least 1 more bit in carry than is in a LITTLENUM.
We need that extra bit to hold a carry during a LITTLENUM carry
propagation. Another extra bit (kept 0) will assure us that we
don't get a sticky sign bit after shifting right, and that
permits us to propagate the carry without any masking of bits.
#endif
*/
for (carry = 1, lp --;
carry && (lp >= words);
lp --)
{
carry = * lp + carry;
* lp = carry;
carry >>= LITTLENUM_NUMBER_OF_BITS;
}

if ( (word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)) )
{
make_invalid_floating_point_number (words);
/*
* We leave return_value alone: admit we read the
* number, but return a floating exception
* because we can't encode the number.
*/
}
} /* if (we needed to round up) */
} /* if (exponent overflow) */
} /* if (0.0e0) */
} /* if (float_type was OK) */
return (return_value);
}


/* JF this used to be in vax.c but this looks like a better place for it */

/*
* md_atof()
*
* In: input_line_pointer -> the 1st character of a floating-point
* number.
* 1 letter denoting the type of statement that wants a
* binary floating point number returned.
* Address of where to build floating point literal.
* Assumed to be 'big enough'.
* Address of where to return size of literal (in chars).
*
* Out: Input_line_pointer -> of next char after floating number.
* Error message, or "".
* Floating point literal.
* Number of chars we used for the literal.
*/

int atof_vax_sizeof();

#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */

char *
md_atof (what_statement_type, literalP, sizeP)
char what_statement_type;
char * literalP;
int * sizeP;
{
LITTLENUM_TYPE words [MAXIMUM_NUMBER_OF_LITTLENUMS];
register char kind_of_float;
register int number_of_chars;
register LITTLENUM_TYPE * littlenum_pointer;

switch (what_statement_type)
{
case 'F': /* .float */
case 'f': /* .ffloat */
kind_of_float = 'f';
break;

case 'D': /* .double */
case 'd': /* .dfloat */
kind_of_float = 'd';
break;

case 'g': /* .gfloat */
kind_of_float = 'g';
break;

case 'h': /* .hfloat */
kind_of_float = 'h';
break;

default:
kind_of_float = 0;
break;
};

if (kind_of_float)
{
register LITTLENUM_TYPE * limit;
char * atof_vax();

input_line_pointer = atof_vax (input_line_pointer,
kind_of_float,
words);
/*
* The atof_vax() builds up 16-bit numbers.
* Since the assembler may not be running on
* a little-endian machine, be very careful about
* converting words to chars.
*/
number_of_chars = atof_vax_sizeof (kind_of_float);
know( number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof(LITTLENUM_TYPE) );
limit = words + (number_of_chars / sizeof(LITTLENUM_TYPE));
for (littlenum_pointer = words;
littlenum_pointer < limit;
littlenum_pointer ++)
{
md_number_to_chars (literalP, * littlenum_pointer, sizeof(LITTLENUM_TYPE));
literalP += sizeof(LITTLENUM_TYPE);
};
}
else
{
number_of_chars = 0;
};

* sizeP = number_of_chars;
return (kind_of_float ? "" : "Bad call to md_atof()");
} /* md_atof() */

/* atof_vax.c */
gas-1.38/vax-opcode.h 666 12412 0 32305 4705116460 12025 0ustar randy/* Vax opcde list.
Copyright (C) 1989, Free Software Foundation, Inc.

This file is part of GDB and GAS.

GDB and GAS are 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.

GDB and GAS are distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GDB or GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#ifndef vax_opcodeT
#define vax_opcodeT int
#endif /* no vax_opcodeT */

struct vot_wot /* vax opcode table: wot to do with this */
/* particular opcode */
{
char * args; /* how to compile said opcode */
vax_opcodeT code; /* op-code (may be > 8 bits!) */
};

struct vot /* vax opcode text */
{
char * name; /* opcode name: lowercase string [key] */
struct vot_wot detail; /* rest of opcode table [datum] */
};

#define vot_how args
#define vot_code code
#define vot_detail detail
#define vot_name name

static const struct vot
votstrs[] =
{
{ "halt", {"", 0x00 } },
{ "nop", {"", 0x01 } },
{ "rei", {"", 0x02 } },
{ "bpt", {"", 0x03 } },
{ "ret", {"", 0x04 } },
{ "rsb", {"", 0x05 } },
{ "ldpctx", {"", 0x06 } },
{ "svpctx", {"", 0x07 } },
{ "cvtps", {"rwabrwab", 0x08 } },
{ "cvtsp", {"rwabrwab", 0x09 } },
{ "index", {"rlrlrlrlrlwl", 0x0a } },
{ "crc", {"abrlrwab", 0x0b } },
{ "prober", {"rbrwab", 0x0c } },
{ "probew", {"rbrwab", 0x0d } },
{ "insque", {"abab", 0x0e } },
{ "remque", {"abwl", 0x0f } },
{ "bsbb", {"bb", 0x10 } },
{ "brb", {"bb", 0x11 } },
{ "bneq", {"bb", 0x12 } },
{ "bnequ", {"bb", 0x12 } },
{ "beql", {"bb", 0x13 } },
{ "beqlu", {"bb", 0x13 } },
{ "bgtr", {"bb", 0x14 } },
{ "bleq", {"bb", 0x15 } },
{ "jsb", {"ab", 0x16 } },
{ "jmp", {"ab", 0x17 } },
{ "bgeq", {"bb", 0x18 } },
{ "blss", {"bb", 0x19 } },
{ "bgtru", {"bb", 0x1a } },
{ "blequ", {"bb", 0x1b } },
{ "bvc", {"bb", 0x1c } },
{ "bvs", {"bb", 0x1d } },
{ "bcc", {"bb", 0x1e } },
{ "bgequ", {"bb", 0x1e } },
{ "blssu", {"bb", 0x1f } },
{ "bcs", {"bb", 0x1f } },
{ "addp4", {"rwabrwab", 0x20 } },
{ "addp6", {"rwabrwabrwab", 0x21 } },
{ "subp4", {"rwabrwab", 0x22 } },
{ "subp6", {"rwabrwabrwab", 0x23 } },
{ "cvtpt", {"rwababrwab", 0x24 } },
{ "mulp", {"rwabrwabrwab", 0x25 } },
{ "cvttp", {"rwababrwab", 0x26 } },
{ "divp", {"rwabrwabrwab", 0x27 } },
{ "movc3", {"rwabab", 0x28 } },
{ "cmpc3", {"rwabab", 0x29 } },
{ "scanc", {"rwababrb", 0x2a } },
{ "spanc", {"rwababrb", 0x2b } },
{ "movc5", {"rwabrbrwab", 0x2c } },
{ "cmpc5", {"rwabrbrwab", 0x2d } },
{ "movtc", {"rwabrbabrwab", 0x2e } },
{ "movtuc", {"rwabrbabrwab", 0x2f } },
{ "bsbw", {"bw", 0x30 } },
{ "brw", {"bw", 0x31 } },
{ "cvtwl", {"rwwl", 0x32 } },
{ "cvtwb", {"rwwb", 0x33 } },
{ "movp", {"rwabab", 0x34 } },
{ "cmpp3", {"rwabab", 0x35 } },
{ "cvtpl", {"rwabwl", 0x36 } },
{ "cmpp4", {"rwabrwab", 0x37 } },
{ "editpc", {"rwababab", 0x38 } },
{ "matchc", {"rwabrwab", 0x39 } },
{ "locc", {"rbrwab", 0x3a } },
{ "skpc", {"rbrwab", 0x3b } },
{ "movzwl", {"rwwl", 0x3c } },
{ "acbw", {"rwrwmwbw", 0x3d } },
{ "movaw", {"awwl", 0x3e } },
{ "pushaw", {"aw", 0x3f } },
{ "addf2", {"rfmf", 0x40 } },
{ "addf3", {"rfrfwf", 0x41 } },
{ "subf2", {"rfmf", 0x42 } },
{ "subf3", {"rfrfwf", 0x43 } },
{ "mulf2", {"rfmf", 0x44 } },
{ "mulf3", {"rfrfwf", 0x45 } },
{ "divf2", {"rfmf", 0x46 } },
{ "divf3", {"rfrfwf", 0x47 } },
{ "cvtfb", {"rfwb", 0x48 } },
{ "cvtfw", {"rfww", 0x49 } },
{ "cvtfl", {"rfwl", 0x4a } },
{ "cvtrfl", {"rfwl", 0x4b } },
{ "cvtbf", {"rbwf", 0x4c } },
{ "cvtwf", {"rwwf", 0x4d } },
{ "cvtlf", {"rlwf", 0x4e } },
{ "acbf", {"rfrfmfbw", 0x4f } },
{ "movf", {"rfwf", 0x50 } },
{ "cmpf", {"rfrf", 0x51 } },
{ "mnegf", {"rfwf", 0x52 } },
{ "tstf", {"rf", 0x53 } },
{ "emodf", {"rfrbrfwlwf", 0x54 } },
{ "polyf", {"rfrwab", 0x55 } },
{ "cvtfd", {"rfwd", 0x56 } },
/* opcode 57 is not defined yet */
{ "adawi", {"rwmw", 0x58 } },
/* opcode 59 is not defined yet */
/* opcode 5a is not defined yet */
/* opcode 5b is not defined yet */
{ "insqhi", {"abaq", 0x5c } },
{ "insqti", {"abaq", 0x5d } },
{ "remqhi", {"aqwl", 0x5e } },
{ "remqti", {"aqwl", 0x5f } },
{ "addd2", {"rdmd", 0x60 } },
{ "addd3", {"rdrdwd", 0x61 } },
{ "subd2", {"rdmd", 0x62 } },
{ "subd3", {"rdrdwd", 0x63 } },
{ "muld2", {"rdmd", 0x64 } },
{ "muld3", {"rdrdwd", 0x65 } },
{ "divd2", {"rdmd", 0x66 } },
{ "divd3", {"rdrdwd", 0x67 } },
{ "cvtdb", {"rdwb", 0x68 } },
{ "cvtdw", {"rdww", 0x69 } },
{ "cvtdl", {"rdwl", 0x6a } },
{ "cvtrdl", {"rdwl", 0x6b } },
{ "cvtbd", {"rbwd", 0x6c } },
{ "cvtwd", {"rwwd", 0x6d } },
{ "cvtld", {"rlwd", 0x6e } },
{ "acbd", {"rdrdmdbw", 0x6f } },
{ "movd", {"rdwd", 0x70 } },
{ "cmpd", {"rdrd", 0x71 } },
{ "mnegd", {"rdwd", 0x72 } },
{ "tstd", {"rd", 0x73 } },
{ "emodd", {"rdrbrdwlwd", 0x74 } },
{ "polyd", {"rdrwab", 0x75 } },
{ "cvtdf", {"rdwf", 0x76 } },
/* opcode 77 is not defined yet */
{ "ashl", {"rbrlwl", 0x78 } },
{ "ashq", {"rbrqwq", 0x79 } },
{ "emul", {"rlrlrlwq", 0x7a } },
{ "ediv", {"rlrqwlwl", 0x7b } },
{ "clrd", {"wd", 0x7c } },
{ "clrg", {"wg", 0x7c } },
{ "clrq", {"wd", 0x7c } },
{ "movq", {"rqwq", 0x7d } },
{ "movaq", {"aqwl", 0x7e } },
{ "movad", {"adwl", 0x7e } },
{ "pushaq", {"aq", 0x7f } },
{ "pushad", {"ad", 0x7f } },
{ "addb2", {"rbmb", 0x80 } },
{ "addb3", {"rbrbwb", 0x81 } },
{ "subb2", {"rbmb", 0x82 } },
{ "subb3", {"rbrbwb", 0x83 } },
{ "mulb2", {"rbmb", 0x84 } },
{ "mulb3", {"rbrbwb", 0x85 } },
{ "divb2", {"rbmb", 0x86 } },
{ "divb3", {"rbrbwb", 0x87 } },
{ "bisb2", {"rbmb", 0x88 } },
{ "bisb3", {"rbrbwb", 0x89 } },
{ "bicb2", {"rbmb", 0x8a } },
{ "bicb3", {"rbrbwb", 0x8b } },
{ "xorb2", {"rbmb", 0x8c } },
{ "xorb3", {"rbrbwb", 0x8d } },
{ "mnegb", {"rbwb", 0x8e } },
{ "caseb", {"rbrbrb", 0x8f } },
{ "movb", {"rbwb", 0x90 } },
{ "cmpb", {"rbrb", 0x91 } },
{ "mcomb", {"rbwb", 0x92 } },
{ "bitb", {"rbrb", 0x93 } },
{ "clrb", {"wb", 0x94 } },
{ "tstb", {"rb", 0x95 } },
{ "incb", {"mb", 0x96 } },
{ "decb", {"mb", 0x97 } },
{ "cvtbl", {"rbwl", 0x98 } },
{ "cvtbw", {"rbww", 0x99 } },
{ "movzbl", {"rbwl", 0x9a } },
{ "movzbw", {"rbww", 0x9b } },
{ "rotl", {"rbrlwl", 0x9c } },
{ "acbb", {"rbrbmbbw", 0x9d } },
{ "movab", {"abwl", 0x9e } },
{ "pushab", {"ab", 0x9f } },
{ "addw2", {"rwmw", 0xa0 } },
{ "addw3", {"rwrwww", 0xa1 } },
{ "subw2", {"rwmw", 0xa2 } },
{ "subw3", {"rwrwww", 0xa3 } },
{ "mulw2", {"rwmw", 0xa4 } },
{ "mulw3", {"rwrwww", 0xa5 } },
{ "divw2", {"rwmw", 0xa6 } },
{ "divw3", {"rwrwww", 0xa7 } },
{ "bisw2", {"rwmw", 0xa8 } },
{ "bisw3", {"rwrwww", 0xa9 } },
{ "bicw2", {"rwmw", 0xaa } },
{ "bicw3", {"rwrwww", 0xab } },
{ "xorw2", {"rwmw", 0xac } },
{ "xorw3", {"rwrwww", 0xad } },
{ "mnegw", {"rwww", 0xae } },
{ "casew", {"rwrwrw", 0xaf } },
{ "movw", {"rwww", 0xb0 } },
{ "cmpw", {"rwrw", 0xb1 } },
{ "mcomw", {"rwww", 0xb2 } },
{ "bitw", {"rwrw", 0xb3 } },
{ "clrw", {"ww", 0xb4 } },
{ "tstw", {"rw", 0xb5 } },
{ "incw", {"mw", 0xb6 } },
{ "decw", {"mw", 0xb7 } },
{ "bispsw", {"rw", 0xb8 } },
{ "bicpsw", {"rw", 0xb9 } },
{ "popr", {"rw", 0xba } },
{ "pushr", {"rw", 0xbb } },
{ "chmk", {"rw", 0xbc } },
{ "chme", {"rw", 0xbd } },
{ "chms", {"rw", 0xbe } },
{ "chmu", {"rw", 0xbf } },
{ "addl2", {"rlml", 0xc0 } },
{ "addl3", {"rlrlwl", 0xc1 } },
{ "subl2", {"rlml", 0xc2 } },
{ "subl3", {"rlrlwl", 0xc3 } },
{ "mull2", {"rlml", 0xc4 } },
{ "mull3", {"rlrlwl", 0xc5 } },
{ "divl2", {"rlml", 0xc6 } },
{ "divl3", {"rlrlwl", 0xc7 } },
{ "bisl2", {"rlml", 0xc8 } },
{ "bisl3", {"rlrlwl", 0xc9 } },
{ "bicl2", {"rlml", 0xca } },
{ "bicl3", {"rlrlwl", 0xcb } },
{ "xorl2", {"rlml", 0xcc } },
{ "xorl3", {"rlrlwl", 0xcd } },
{ "mnegl", {"rlwl", 0xce } },
{ "casel", {"rlrlrl", 0xcf } },
{ "movl", {"rlwl", 0xd0 } },
{ "cmpl", {"rlrl", 0xd1 } },
{ "mcoml", {"rlwl", 0xd2 } },
{ "bitl", {"rlrl", 0xd3 } },
{ "clrf", {"wf", 0xd4 } },
{ "clrl", {"wl", 0xd4 } },
{ "tstl", {"rl", 0xd5 } },
{ "incl", {"ml", 0xd6 } },
{ "decl", {"ml", 0xd7 } },
{ "adwc", {"rlml", 0xd8 } },
{ "sbwc", {"rlml", 0xd9 } },
{ "mtpr", {"rlrl", 0xda } },
{ "mfpr", {"rlwl", 0xdb } },
{ "movpsl", {"wl", 0xdc } },
{ "pushl", {"rl", 0xdd } },
{ "moval", {"alwl", 0xde } },
{ "movaf", {"afwl", 0xde } },
{ "pushal", {"al", 0xdf } },
{ "pushaf", {"af", 0xdf } },
{ "bbs", {"rlabbb", 0xe0 } },
{ "bbc", {"rlabbb", 0xe1 } },
{ "bbss", {"rlabbb", 0xe2 } },
{ "bbcs", {"rlabbb", 0xe3 } },
{ "bbsc", {"rlabbb", 0xe4 } },
{ "bbcc", {"rlabbb", 0xe5 } },
{ "bbssi", {"rlabbb", 0xe6 } },
{ "bbcci", {"rlabbb", 0xe7 } },
{ "blbs", {"rlbb", 0xe8 } },
{ "blbc", {"rlbb", 0xe9 } },
{ "ffs", {"rlrbvbwl", 0xea } },
{ "ffc", {"rlrbvbwl", 0xeb } },
{ "cmpv", {"rlrbvbrl", 0xec } },
{ "cmpzv", {"rlrbvbrl", 0xed } },
{ "extv", {"rlrbvbwl", 0xee } },
{ "extzv", {"rlrbvbwl", 0xef } },
{ "insv", {"rlrlrbvb", 0xf0 } },
{ "acbl", {"rlrlmlbw", 0xf1 } },
{ "aoblss", {"rlmlbb", 0xf2 } },
{ "aobleq", {"rlmlbb", 0xf3 } },
{ "sobgeq", {"mlbb", 0xf4 } },
{ "sobgtr", {"mlbb", 0xf5 } },
{ "cvtlb", {"rlwb", 0xf6 } },
{ "cvtlw", {"rlww", 0xf7 } },
{ "ashp", {"rbrwabrbrwab", 0xf8 } },
{ "cvtlp", {"rlrwab", 0xf9 } },
{ "callg", {"abab", 0xfa } },
{ "calls", {"rlab", 0xfb } },
{ "xfc", {"", 0xfc } },
/* undefined opcodes here */
{ "cvtdh", {"rdwh", 0x32fd } },
{ "cvtgf", {"rgwh", 0x33fd } },
{ "addg2", {"rgmg", 0x40fd } },
{ "addg3", {"rgrgwg", 0x41fd } },
{ "subg2", {"rgmg", 0x42fd } },
{ "subg3", {"rgrgwg", 0x43fd } },
{ "mulg2", {"rgmg", 0x44fd } },
{ "mulg3", {"rgrgwg", 0x45fd } },
{ "divg2", {"rgmg", 0x46fd } },
{ "divg3", {"rgrgwg", 0x47fd } },
{ "cvtgb", {"rgwb", 0x48fd } },
{ "cvtgw", {"rgww", 0x49fd } },
{ "cvtgl", {"rgwl", 0x4afd } },
{ "cvtrgl", {"rgwl", 0x4bfd } },
{ "cvtbg", {"rbwg", 0x4cfd } },
{ "cvtwg", {"rwwg", 0x4dfd } },
{ "cvtlg", {"rlwg", 0x4efd } },
{ "acbg", {"rgrgmgbw", 0x4ffd } },
{ "movg", {"rgwg", 0x50fd } },
{ "cmpg", {"rgrg", 0x51fd } },
{ "mnegg", {"rgwg", 0x52fd } },
{ "tstg", {"rg", 0x53fd } },
{ "emodg", {"rgrwrgwlwg", 0x54fd } },
{ "polyg", {"rgrwab", 0x55fd } },
{ "cvtgh", {"rgwh", 0x56fd } },
/* undefined opcodes here */
{ "addh2", {"rhmh", 0x60fd } },
{ "addh3", {"rhrhwh", 0x61fd } },
{ "subh2", {"rhmh", 0x62fd } },
{ "subh3", {"rhrhwh", 0x63fd } },
{ "mulh2", {"rhmh", 0x64fd } },
{ "mulh3", {"rhrhwh", 0x65fd } },
{ "divh2", {"rhmh", 0x66fd } },
{ "divh3", {"rhrhwh", 0x67fd } },
{ "cvthb", {"rhwb", 0x68fd } },
{ "cvthw", {"rhww", 0x69fd } },
{ "cvthl", {"rhwl", 0x6afd } },
{ "cvtrhl", {"rhwl", 0x6bfd } },
{ "cvtbh", {"rbwh", 0x6cfd } },
{ "cvtwh", {"rwwh", 0x6dfd } },
{ "cvtlh", {"rlwh", 0x6efd } },
{ "acbh", {"rhrhmhbw", 0x6ffd } },
{ "movh", {"rhwh", 0x70fd } },
{ "cmph", {"rhrh", 0x71fd } },
{ "mnegh", {"rhwh", 0x72fd } },
{ "tsth", {"rh", 0x73fd } },
{ "emodh", {"rhrwrhwlwh", 0x74fd } },
{ "polyh", {"rhrwab", 0x75fd } },
{ "cvthg", {"rhwg", 0x76fd } },
/* undefined opcodes here */
{ "clrh", {"wh", 0x7cfd } },
{ "clro", {"wo", 0x7cfd } },
{ "movo", {"rowo", 0x7dfd } },
{ "movah", {"ahwl", 0x7efd } },
{ "movao", {"aowl", 0x7efd } },
{ "pushah", {"ah", 0x7ffd } },
{ "pushao", {"ao", 0x7ffd } },
/* undefined opcodes here */
{ "cvtfh", {"rfwh", 0x98fd } },
{ "cvtfg", {"rfwg", 0x99fd } },
/* undefined opcodes here */
{ "cvthf", {"rhwf", 0xf6fd } },
{ "cvthd", {"rhwd", 0xf7fd } },
/* undefined opcodes here */
{ "bugl", {"rl", 0xfdff } },
{ "bugw", {"rw", 0xfeff } },
/* undefined opcodes here */

{ "" , "" } /* empty is end sentinel */

}; /* votstrs */

/* end: vax.opcode.h */
gas-1.38/vax-inst.h 666 12412 0 6615 4403071512 11507 0ustar randy/* vax-inst.h - GNU - Part of vax.c
Copyright (C) 1987 Free Software Foundation, Inc.

This file is part of GAS, the GNU Assembler.

GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/*
* This is part of vax-ins-parse.c & friends.
* We want to parse a vax instruction text into a tree defined here.
*/

#define VIT_MAX_OPERANDS (6) /* maximum number of operands in one */
/* single vax instruction */

struct vop /* vax instruction operand */
{
short int vop_ndx; /* -1, or index register. eg 7=[R7] */
short int vop_reg; /* -1, or register number. eg @I^#=0xF */
/* Helps distinguish "abs" from "abs(PC)". */
short int vop_mode; /* addressing mode 4 bits. eg I^#=0x9 */
char vop_short; /* operand displacement length as written */
/* ' '=none, "bilsw"=B^I^L^S^W^. */
char vop_access; /* 'b'branch ' 'no-instruction 'amrvw'norm */
char vop_width; /* Operand width, one of "bdfghloqw" */
char * vop_warn; /* warning message of this operand, if any */
char * vop_error; /* say if operand is inappropriate */
char * vop_expr_begin; /* Unparsed expression, 1st char ... */
char * vop_expr_end; /* ... last char. */
unsigned char vop_nbytes; /* number of bytes in datum */
};


typedef long int vax_opcodeT; /* For initialising array of opcodes */
/* Some synthetic opcodes > 16 bits! */

#define VIT_OPCODE_SYNTHETIC 0x80000000 /* Not real hardware instruction. */
#define VIT_OPCODE_SPECIAL 0x40000000 /* Not normal branch optimising. */
/* Never set without ..._SYNTHETIC */

#define VAX_WIDTH_UNCONDITIONAL_JUMP '-' /* These are encoded into */
#define VAX_WIDTH_CONDITIONAL_JUMP '?' /* vop_width when vop_access=='b' */
#define VAX_WIDTH_WORD_JUMP '!' /* and VIT_OPCODE_SYNTHETIC set. */
#define VAX_WIDTH_BYTE_JUMP ':' /* */

#define VAX_JMP (0x17) /* Useful for branch optimising. Jump instr*/
#define VAX_PC_RELATIVE_MODE (0xef) /* Use it after VAX_JMP */
#define VAX_ABSOLUTE_MODE (0x9F) /* Use as @#... */
#define VAX_BRB (0x11) /* Canonical branch. */
#define VAX_BRW (0x31) /* Another canonical branch */
#define VAX_WIDEN_WORD (0x20) /* Add this to byte branch to get word br. */
#define VAX_WIDEN_LONG (0x6) /* Add this to byte branch to get long jmp.*/
/* Needs VAX_PC_RELATIVE_MODE byte after it*/

struct vit /* vax instruction tree */
{
/* vit_opcode is char[] for portability. */
char vit_opcode [ sizeof (vax_opcodeT) ];
unsigned char vit_opcode_nbytes; /* How long is _opcode? (chars) */
unsigned char vit_operands;/* */
struct vop vit_operand[VIT_MAX_OPERANDS]; /* operands */
char * vit_error; /* "" or error text */
};

/* end: vax-inst.h */
gas-1.38/make-gas.com 666 11660 0 5316 4727012304 11547 0ustar hack$! Set the def dir to proper place for use in batch. Works for interactive to.
$flnm = f$enviroment("PROCEDURE") ! get current procedure name
$set default 'f$parse(flnm,,,"DEVICE")''f$parse(flnm,,,"DIRECTORY")'
$!
$! Command file to build a GNU assembler on VMS
$!
$! If you are using a version of GCC that supports global constants
$! you should remove the define="const=" from the gcc lines.
$ if "''p1'" .eqs. "LINK" then goto Link
$ gcc/debug/define=("VMS","const=") as.c
$ gcc/debug/define=("VMS", "error=as_fatal","const=") xrealloc.c
$ gcc/debug/define=("VMS", "error=as_fatal","const=") xmalloc.c
$ gcc/debug/define=("VMS", "error=as_fatal","const=") hash.c
$ gcc/debug/define=("VMS","const=") obstack.c
$ gcc/debug/define=("VMS","const=") hex-value.c
$ gcc/debug/define=("VMS","const=") atof-generic.c
$ gcc/debug/define=("VMS","const=") append.c
$ gcc/debug/define=("VMS","const=") messages.c
$ gcc/debug/define=("VMS","const=") expr.c
$ gcc/debug/define=("VMS","const=") app.c
$ gcc/debug/define=("VMS","const=") frags.c
$ gcc/debug/define=("VMS","const=") input-file.c
$ gcc/debug/define=("VMS","const=") input-scrub.c
$ gcc/debug/define=("VMS","const=") output-file.c
$ gcc/debug/define=("VMS","const=") read.c
$ gcc/debug/define=("VMS","const=") subsegs.c
$ gcc/debug/define=("VMS","const=") symbols.c
$ gcc/debug/define=("VMS","const=") write.c
$ gcc/debug/define=("VMS","const=") version.c
$ gcc/debug/define=("VMS","const=") flonum-const.c
$ gcc/debug/define=("VMS","const=") flonum-copy.c
$ gcc/debug/define=("VMS","const=") flonum-mult.c
$ gcc/debug/define=("VMS","const=") strstr.c
$ gcc/debug/define=("VMS","const=") bignum-copy.c
$ gcc/debug/define=("VMS", "error=as_fatal","const=") vax.c
$ gcc/debug/define=("VMS","const=") atof-vax.c
$ write sys$output " If you are building gas to work with the G++ compiler"
$ write sys$output " based upon gcc version 1.37.n or earlier, you should"
$ write sys$output " edit make-gas.com and make the changes indicated in the"
$ write sys$output "comments."
$! For older versions of G++, we need the jsb hack, the HACK_DEC_C_STARTUP
$! enables this. Just use the compilation for vms.c that defines this instead
$! of the other one.
$ gcc/debug/define=("VMS", "error=as_fatal","const=") vms.c
$! gcc/debug/define=("VMS", "error=as_fatal","HACK_DEC_C_STARTUP","const=") vms.c
$ gcc/debug/define=("VMS","const=") vms-dbg.c
$ Link:
$ link/exec=gcc-as sys$input:/opt
!
! Linker options file for GNU assembler
!
as,xrealloc,xmalloc,hash,hex-value,atof-generic,append,messages,expr,app,-
frags,input-file,input-scrub,output-file,read,subsegs,symbols,write,-
version,flonum-const,flonum-copy,flonum-mult,strstr,bignum-copy,-
obstack,vax,atof-vax,vms,vms-dbg,-
gnu_cc:[000000]gcclib/lib,sys$share:vaxcrtl/lib
gas-1.38/objrecdef.h 666 11660 0 15260 4662031725 11503 0ustar hack/*
*
* $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
gas-1.38/vms.c 666 12412 0 211720 4722560260 10600 0ustar randy/* vms.c -- Write out a VAX/VMS object file
Copyright (C) 1987, 1988 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. */

/* Written by David L. Kashtan */
#include
#include
#include "as.h"
#include "md.h"
#include "subsegs.h"
#include "obstack.h"
#include "struc-symbol.h"
#include "write.h"
#include "symbols.h"

#ifdef VMS /* THIS MODULE IS FOR VMS ONLY */

#include
#include "objrecdef.h" /* Define VMS Object record lang. */
#include /* Define File Access Block */
#include /* Define NAM Block */
#include /* Define XAB */
#include /* Define Date XAB */
#include /* Define File Header XAB */

/*
* Version string of the compiler that produced the code we are
* assembling. (And this assembler, if we do not have compiler info.)
*/
extern char version_string[];
char *compiler_version_string;

extern char *myname;
static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */

/*
* We augment the "gas" symbol structure with this
*/
struct VMS_Symbol {
struct VMS_Symbol *Next;
struct symbol *Symbol;
int Size;
int Psect_Index;
int Psect_Offset;
};
struct VMS_Symbol *VMS_Symbols = 0;

/* we need this to keep track of the various input files, so that we can
* give the debugger the correct source line
*/

struct input_file{
struct input_file* next;
struct input_file* same_file_fpnt;
int file_number;
int max_line;
int min_line;
int offset;
char flag;
char * name;
symbolS * spnt;
};

static struct input_file * file_root = (struct input_file*)NULL;

struct input_file * find_file(symbolS *);


/*
* If the procedure "main()" exists we have to add the instruction
* "jsb c$main_args" at the beginning to be compatible with VAX-11 "C".
*/
VMS_Check_For_Main()
{
register symbolS *symbolP;
#ifdef HACK_DEC_C_STARTUP /* JF */
register struct frchain *frchainP;
register fragS *fragP;
register fragS **prev_fragPP;
register struct fix *fixP;
register fragS *New_Frag;
int i;
#endif HACK_DEC_C_STARTUP

symbolP = (struct symbol *)symbol_find("_main");
if (symbolP && (symbolP->sy_nlist.n_type == (N_TEXT | N_EXT))) {
#ifdef HACK_DEC_C_STARTUP
if( !flagseen['+']) {
#endif
/*
* Remember the entry point symbol
*/
Entry_Point_Symbol = symbolP;
#ifdef HACK_DEC_C_STARTUP
} else {
/*
* Scan all the fragment chains for the one with "_main"
* (Actually we know the fragment from the symbol, but we need
* the previous fragment so we can change its pointer)
*/
frchainP = frchain_root;
while(frchainP) {
/*
* Scan all the fragments in this chain, remembering
* the "previous fragment"
*/
prev_fragPP = &frchainP->frch_root;
fragP = frchainP->frch_root;
while(fragP && (fragP != frchainP->frch_last)) {
/*
* Is this the fragment?
*/
if (fragP == symbolP->sy_frag) {
/*
* Yes: Modify the fragment by replacing
* it with a new fragment.
*/
New_Frag = (fragS *)
xmalloc(sizeof(*New_Frag) +
fragP->fr_fix +
fragP->fr_var +
5);
/*
* The fragments are the same except
* that the "fixed" area is larger
*/
*New_Frag = *fragP;
New_Frag->fr_fix += 6;
/*
* Copy the literal data opening a hole
* 2 bytes after "_main" (i.e. just after
* the entry mask). Into which we place
* the JSB instruction.
*/
New_Frag->fr_literal[0] = fragP->fr_literal[0];
New_Frag->fr_literal[1] = fragP->fr_literal[1];
New_Frag->fr_literal[2] = 0x16; /* Jsb */
New_Frag->fr_literal[3] = 0xef;
New_Frag->fr_literal[4] = 0;
New_Frag->fr_literal[5] = 0;
New_Frag->fr_literal[6] = 0;
New_Frag->fr_literal[7] = 0;
for(i = 2; i < fragP->fr_fix + fragP->fr_var; i++)
New_Frag->fr_literal[i+6] =
fragP->fr_literal[i];
/*
* Now replace the old fragment with the
* newly generated one.
*/
*prev_fragPP = New_Frag;
/*
* Remember the entry point symbol
*/
Entry_Point_Symbol = symbolP;
/*
* Scan the text area fixup structures
* as offsets in the fragment may have
* changed
*/
for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
/*
* Look for references to this
* fragment.
*/
if (fixP->fx_frag == fragP) {
/*
* Change the fragment
* pointer
*/
fixP->fx_frag = New_Frag;
/*
* If the offset is after
* the entry mask we need
* to account for the JSB
* instruction we just
* inserted.
*/
if (fixP->fx_where >= 2)
fixP->fx_where += 6;
}
}
/*
* Scan the symbols as offsets in the
* fragment may have changed
*/
for(symbolP = symbol_rootP;
symbolP;
symbolP = symbolP->sy_next) {
/*
* Look for references to this
* fragment.
*/
if (symbolP->sy_frag == fragP) {
/*
* Change the fragment
* pointer
*/
symbolP->sy_frag = New_Frag;
/*
* If the offset is after
* the entry mask we need
* to account for the JSB
* instruction we just
* inserted.
*/
if (symbolP->sy_nlist.n_value >= 2)
symbolP->sy_nlist.n_value += 6;
}
}
/*
* Make a symbol reference to
* "_c$main_args" so we can get
* its address inserted into the
* JSB instruction.
*/
symbolP = (symbolS *)xmalloc(sizeof(*symbolP));
symbolP->sy_nlist.n_un.n_name = "_c$main_args";
symbolP->sy_nlist.n_type = N_UNDF;
symbolP->sy_nlist.n_other = 0;
symbolP->sy_nlist.n_desc = 0;
symbolP->sy_nlist.n_value = 0;
symbolP->sy_name_offset = 0;
symbolP->sy_number = 0;
symbolP->sy_frag = New_Frag;
symbolP->sy_forward = 0;
symbolP->sy_next = symbol_rootP;
symbol_rootP = symbolP;
/*
* Generate a text fixup structure
* to get "_c$main_args" stored into the
* JSB instruction.
*/
fixP = (struct fix *)xmalloc(sizeof(*fixP));
fixP->fx_frag = New_Frag;
fixP->fx_where = 4;
fixP->fx_addsy = symbolP;
fixP->fx_subsy = 0;
fixP->fx_offset = 0;
fixP->fx_size = sizeof(long);
fixP->fx_pcrel = 1;
fixP->fx_next = text_fix_root;
text_fix_root = fixP;
/*
* Now make sure we exit from the loop
*/
frchainP = 0;
break;
}
/*
* Try the next fragment
*/
prev_fragPP = &fragP->fr_next;
fragP = fragP->fr_next;
}
/*
* Try the next fragment chain
*/
if (frchainP) frchainP=frchainP->frch_next;
}
}
#endif /* HACK_DEC_C_STARTUP */
}
}

/*
* Write a VAX/VMS object file (everything else has been done!)
*/
VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root)
unsigned text_siz;
unsigned data_siz;
struct frag *text_frag_root;
struct frag *data_frag_root;
{
register fragS * fragP;
register symbolS * symbolP;
register symbolS * sp;
register struct fix * fixP;
register struct VMS_Symbol * vsp;
int Local_Initialized_Data_Size = 0;
int Psect_Number = 0; /* Psect Index Number */
int Text_Psect = -1; /* Text Psect Index */
int Data_Psect = -2; /* Data Psect Index JF: Was -1 */
int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */

/*
* Create the VMS object file
*/
Create_VMS_Object_File();
/*
* Write the module header records
*/
Write_VMS_MHD_Records();

/*
* Generate the VMS object file records
* 1st GSD then TIR records
*/

/******* Global Symbol Dictionary *******/
/*
* Define the Text Psect
*/
if (text_siz > 0) {
Text_Psect = Psect_Number++;
VMS_Psect_Spec("$code",text_siz,"TEXT");
}
/*
* Define the BSS Psect
*/
if (local_bss_counter > 0) {
Bss_Psect = Psect_Number++;
VMS_Psect_Spec("$uninitialized_data",local_bss_counter,"DATA");
}
/*
* Now scan the symbols and emit the appropriate GSD records
*/
for (sp = symbol_rootP; sp; sp = sp->sy_next) {
/*
* Dispatch on symbol type
*/
switch(sp->sy_type) {
/*
* Global uninitialized data
*/
case N_UNDF | N_EXT:
/*
* Make a VMS data symbol entry
*/
vsp = (struct VMS_Symbol *)
xmalloc(sizeof(*vsp));
vsp->Symbol = sp;
vsp->Size = sp->sy_nlist.n_value;
vsp->Psect_Index = Psect_Number++;
vsp->Psect_Offset = 0;
vsp->Next = VMS_Symbols;
VMS_Symbols = vsp;
sp->sy_number = (int)vsp;
/*
* Make the psect for this data
*/
if(sp->sy_nlist.n_other)
VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
vsp->Size,
"CONST");
else
VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
vsp->Size,
"COMMON");
#ifdef NOT_VAX_11_C_COMPATIBLE
/*
* Place a global symbol at the
* beginning of the Psect
*/
VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
vsp->Psect_Index,
0,
1);
#endif NOT_VAX_11_C_COMPATIBLE
break;
/*
* Local uninitialized data
*/
case N_BSS:
/*
* Make a VMS data symbol entry
*/
vsp = (struct VMS_Symbol *)
xmalloc(sizeof(*vsp));
vsp->Symbol = sp;
vsp->Size = 0;
vsp->Psect_Index = Bss_Psect;
vsp->Psect_Offset =
sp->sy_nlist.n_value -
bss_address_frag . fr_address;
vsp->Next = VMS_Symbols;
VMS_Symbols = vsp;
sp->sy_number = (int)vsp;
break;
/*
* Global initialized data
*/
case N_DATA | N_EXT:
/*
* Make a VMS data symbol entry
*/
vsp = (struct VMS_Symbol *)
xmalloc(sizeof(*vsp));
vsp->Symbol = sp;
vsp->Size = VMS_Initialized_Data_Size(sp,
text_siz + data_siz);
vsp->Psect_Index = Psect_Number++;
vsp->Psect_Offset = 0;
vsp->Next = VMS_Symbols;
VMS_Symbols = vsp;
sp->sy_number = (int)vsp;
/*
* Make its psect
*/
if(sp->sy_nlist.n_other)
VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
vsp->Size,
"CONST");
else
VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
vsp->Size,
"COMMON");
#ifdef NOT_VAX_11_C_COMPATIBLE
/*
* Place a global symbol at the
* beginning of the Psect
*/
VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
vsp->Psect_Index,
0,
1);
#endif NOT_VAX_11_C_COMPATIBLE
break;
/*
* Local initialized data
*/
case N_DATA:
/*
* Make a VMS data symbol entry
*/
vsp = (struct VMS_Symbol *)
xmalloc(sizeof(*vsp));
vsp->Symbol = sp;
vsp->Size =
VMS_Initialized_Data_Size(sp,
text_siz + data_siz);
vsp->Psect_Index = Data_Psect;
vsp->Psect_Offset =
Local_Initialized_Data_Size;
Local_Initialized_Data_Size += vsp->Size;
vsp->Next = VMS_Symbols;
VMS_Symbols = vsp;
sp->sy_number = (int)vsp;
break;
/*
* Global Text definition
*/
case N_TEXT | N_EXT: {
unsigned short Entry_Mask;

/*
* Get the entry mask
*/
fragP = sp->sy_frag;
Entry_Mask = (fragP->fr_literal[0] & 0xff) +
((fragP->fr_literal[1] & 0xff)
<< 8);
/*
* Define the Procedure entry pt.
*/
VMS_Procedure_Entry_Pt(sp->sy_nlist.n_un.n_name,
Text_Psect,
sp->sy_nlist.n_value,
Entry_Mask);
break;
}
/*
* Local Text definition
*/
case N_TEXT:
/*
* Make a VMS data symbol entry
*/
if(Text_Psect != -1) {
vsp = (struct VMS_Symbol *)
xmalloc(sizeof(*vsp));
vsp->Symbol = sp;
vsp->Size = 0;
vsp->Psect_Index = Text_Psect;
vsp->Psect_Offset = sp->sy_nlist.n_value;
vsp->Next = VMS_Symbols;
VMS_Symbols = vsp;
sp->sy_number = (int)vsp;
}
break;
/*
* Global Reference
*/
case N_UNDF:
/*
* Make a GSD global symbol reference
* record.
*/
VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
0,
0,
0);
break;
/*
* Anything else
*/
default:
/*
* Ignore STAB symbols
* Including .stabs emitted by g++
*/
if ((sp->sy_type & N_STAB) != 0 || sp->sy_nlist.n_type==22)
break;
/*
* Error
*/
if(sp->sy_nlist.n_type !=22)
printf(" ERROR, unknown type (%d)\n",
sp->sy_nlist.n_type);
break;
}
}
/*
* Define the Data Psect
*/
if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) {
/*
* Do it
*/
Data_Psect = Psect_Number++;
VMS_Psect_Spec("$data",
Local_Initialized_Data_Size,
"DATA");
/*
* Scan the VMS symbols and fill in the data psect
*/
for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
/*
* Only look for undefined psects
*/
if (vsp->Psect_Index < 0) {
/*
* And only initialized data
*/
if (vsp->Symbol->sy_nlist.n_type == N_DATA)
vsp->Psect_Index = Data_Psect;
}
}
}

/******* Text Information and Relocation Records *******/
/*
* Write the text segment data
*/
if (text_siz > 0) {
/*
* Scan the text fragments
*/
for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
/*
* Stop if we get to the data fragments
*/
if (fragP == data_frag_root) break;
/*
* Ignore fragments with no data
*/
if ((fragP->fr_fix == 0) && (fragP->fr_var == 0))
continue;
/*
* Go the the appropriate offset in the
* Text Psect.
*/
VMS_Set_Psect(Text_Psect,fragP->fr_address,OBJ$C_TIR);
/*
* Store the "fixed" part
*/
if (fragP->fr_fix)
VMS_Store_Immediate_Data(fragP->fr_literal,
fragP->fr_fix,
OBJ$C_TIR);
/*
* Store the "variable" part
*/
if (fragP->fr_var && fragP->fr_offset)
VMS_Store_Repeated_Data(fragP->fr_offset,
fragP->fr_literal+
fragP->fr_fix,
fragP->fr_var,
OBJ$C_TIR);
}
/*
* Now we go through the text segment fixups and
* generate TIR records to fix up addresses within
* the Text Psect
*/
for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
/*
* We DO handle the case of "Symbol - Symbol" as
* long as it is in the same segment.
*/
if (fixP->fx_subsy && fixP->fx_addsy) {
int i;

/*
* They need to be in the same segment
*/
if (fixP->fx_subsy->sy_type !=
fixP->fx_addsy->sy_type)
error("Fixup data addsy and subsy didn't have the same type");
/*
* And they need to be in one that we
* can check the psect on
*/
if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT))
error("Fixup data addsy and subsy didn't have an appropriate type");
/*
* This had better not be PC relative!
*/
if (fixP->fx_pcrel)
error("Fixup data was erroneously \"pcrel\"");
/*
* Subtract their values to get the
* difference.
*/
i = fixP->fx_addsy->sy_value -
fixP->fx_subsy->sy_value;
/*
* Now generate the fixup object records
* Set the psect and store the data
*/
VMS_Set_Psect(Text_Psect,
fixP->fx_where +
fixP->fx_frag->fr_address,
OBJ$C_TIR);
VMS_Store_Immediate_Data(&i,
fixP->fx_size,
OBJ$C_TIR);
/*
* Done
*/
continue;
}
/*
* Size will HAVE to be "long"
*/
if (fixP->fx_size != sizeof(long))
error("Fixup datum was not a longword");
/*
* Symbol must be "added" (if it is ever
* subtracted we can
* fix this assumption)
*/
if (fixP->fx_addsy == 0)
error("Fixup datum was not \"fixP->fx_addsy\"");
/*
* Store the symbol value in a PIC fashion
*/
VMS_Store_PIC_Symbol_Reference(fixP->fx_addsy,
fixP->fx_offset,
fixP->fx_pcrel,
Text_Psect,
fixP->fx_where +
fixP->fx_frag->fr_address,
OBJ$C_TIR);
/*
* Check for indirect address reference,
* which has to be fixed up (as the linker
* will screw it up with TIR$C_STO_PICR).
*/
if (fixP->fx_pcrel)
VMS_Fix_Indirect_Reference(Text_Psect,
fixP->fx_where +
fixP->fx_frag->fr_address,
fixP->fx_frag,
text_frag_root);
}
}
/*
* Store the Data segment:
*
* Since this is REALLY hard to do any other way,
* we actually manufacture the data segment and
* the store the appropriate values out of it.
*/
if (data_siz > 0) {
char *Data_Segment;

/*
* Allocate the data segment
*/
Data_Segment = (char *)xmalloc(data_siz);
/*
* Run through the data fragments, filling in the segment
*/
for(fragP = data_frag_root; fragP; fragP = fragP->fr_next) {
register long int count;
register char * fill_literal;
register long int fill_size;
int i;

i = fragP->fr_address - text_siz;
if (fragP->fr_fix)
bcopy(fragP->fr_literal,
Data_Segment + i,
fragP->fr_fix);
i += fragP->fr_fix;

fill_literal= fragP -> fr_literal + fragP -> fr_fix;
fill_size = fragP -> fr_var;
for (count = fragP -> fr_offset; count; count --) {
if (fill_size)
bcopy(fill_literal,
Data_Segment + i,
fill_size);
i += fill_size;
}
}
/*
* Now we can run through all the data symbols
* and store the data
*/
for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
/*
* Ignore anything other than data symbols
*/
if ((vsp->Symbol->sy_nlist.n_type & ~N_EXT) != N_DATA)
continue;
/*
* Set the Psect + Offset
*/
VMS_Set_Psect(vsp->Psect_Index,
vsp->Psect_Offset,
OBJ$C_TIR);
/*
* Store the data
*/
VMS_Store_Immediate_Data(Data_Segment +
vsp->Symbol->sy_nlist.n_value -
text_siz,
vsp->Size,
OBJ$C_TIR);
}
/*
* Now we go through the data segment fixups and
* generate TIR records to fix up addresses within
* the Data Psects
*/
for(fixP = data_fix_root; fixP; fixP = fixP->fx_next) {
/*
* Find the symbol for the containing datum
*/
for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
/*
* Only bother with Data symbols
*/
sp = vsp->Symbol;
if ((sp->sy_nlist.n_type & ~N_EXT) != N_DATA)
continue;
/*
* Ignore symbol if After fixup
*/
if (sp->sy_nlist.n_value >
(fixP->fx_where +
fixP->fx_frag->fr_address))
continue;
/*
* See if the datum is here
*/
if ((sp->sy_nlist.n_value + vsp->Size) <=
(fixP->fx_where +
fixP->fx_frag->fr_address))
continue;
/*
* We DO handle the case of "Symbol - Symbol" as
* long as it is in the same segment.
*/
if (fixP->fx_subsy && fixP->fx_addsy) {
int i;

/*
* They need to be in the same segment
*/
if (fixP->fx_subsy->sy_type !=
fixP->fx_addsy->sy_type)
error("Fixup data addsy and subsy didn't have the same type");
/*
* And they need to be in one that we
* can check the psect on
*/
if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT))
error("Fixup data addsy and subsy didn't have an appropriate type");
/*
* This had better not be PC relative!
*/
if (fixP->fx_pcrel)
error("Fixup data was erroneously \"pcrel\"");
/*
* Subtract their values to get the
* difference.
*/
i = fixP->fx_addsy->sy_value -
fixP->fx_subsy->sy_value;
/*
* Now generate the fixup object records
* Set the psect and store the data
*/
VMS_Set_Psect(vsp->Psect_Index,
fixP->fx_frag->fr_address +
fixP->fx_where -
vsp->Symbol->sy_value +
vsp->Psect_Offset,
OBJ$C_TIR);
VMS_Store_Immediate_Data(&i,
fixP->fx_size,
OBJ$C_TIR);
/*
* Done
*/
break;
}
/*
* Size will HAVE to be "long"
*/
if (fixP->fx_size != sizeof(long))
error("Fixup datum was not a longword");
/*
* Symbol must be "added" (if it is ever
* subtracted we can
* fix this assumption)
*/
if (fixP->fx_addsy == 0)
error("Fixup datum was not \"fixP->fx_addsy\"");
/*
* Store the symbol value in a PIC fashion
*/
VMS_Store_PIC_Symbol_Reference(
fixP->fx_addsy,
fixP->fx_offset,
fixP->fx_pcrel,
vsp->Psect_Index,
fixP->fx_frag->fr_address +
fixP->fx_where -
vsp->Symbol->sy_value +
vsp->Psect_Offset,
OBJ$C_TIR);
/*
* Done
*/
break;
}

}
}

/*
* Write the Traceback Begin Module record
*/
VMS_TBT_Module_Begin();
/*
* Scan the symbols and write out the routines
* (this makes the assumption that symbols are in
* order of ascending text segment offset)
*/
{
struct symbol *Current_Routine = 0;
int Current_Line_Number = 0;
int Current_Offset = -1;
struct input_file * Current_File;

/* Output debugging info for global variables and static variables that are not
* specific to one routine. We also need to examine all stabs directives, to
* find the definitions to all of the advanced data types, and this is done by
* VMS_LSYM_Parse. This needs to be done before any definitions are output to
* the object file, since there can be forward references in the stabs
* directives. When through with parsing, the text of the stabs directive
* is altered, with the definitions removed, so that later passes will see
* directives as they would be written if the type were already defined.
*
* We also look for files and include files, and make a list of them. We
* examine the source file numbers to establish the actual lines that code was
* generated from, and then generate offsets.
*/
VMS_LSYM_Parse();
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
/*
* Deal with STAB symbols
*/
if ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
/*
* Dispatch on STAB type
*/
switch((unsigned char)symbolP->sy_nlist.n_type) {
case N_SLINE:
if(symbolP->sy_nlist.n_desc > Current_File->max_line)
Current_File->max_line = symbolP->sy_nlist.n_desc;
if(symbolP->sy_nlist.n_desc < Current_File->min_line)
Current_File->min_line = symbolP->sy_nlist.n_desc;
break;
case N_SO:
Current_File =find_file(symbolP);
Current_File->flag = 1;
Current_File->min_line = 1;
break;
case N_SOL:
Current_File = find_file(symbolP);
break;
case N_GSYM:
VMS_GSYM_Parse(symbolP,Text_Psect);
break;
case N_LCSYM:
VMS_LCSYM_Parse(symbolP,Text_Psect);
break;
case N_FUN: /* For static constant symbols */
case N_STSYM:
VMS_STSYM_Parse(symbolP,Text_Psect);
break;
}
}
}

/* now we take a quick sweep through the files and assign offsets
to each one. This will essentially be the starting line number to the
debugger for each file. Output the info for the debugger to specify the
files, and then tell it how many lines to use */
{
int File_Number = 0;
int Debugger_Offset = 0;
int file_available;
Current_File = file_root;
for(Current_File = file_root; Current_File; Current_File = Current_File->next){
if(Current_File == (struct input_file*) NULL) break;
if(Current_File->max_line == 0) continue;
if((strncmp(Current_File->name,"GNU_GXX_INCLUDE:",16) == 0) &&
!flagseen['D']) continue;
if((strncmp(Current_File->name,"GNU_CC_INCLUDE:",15) == 0) &&
!flagseen['D']) continue;
/* show a few extra lines at the start of the region selected */
if(Current_File->min_line > 2) Current_File->min_line -= 2;
Current_File->offset = Debugger_Offset - Current_File->min_line + 1;
Debugger_Offset += Current_File->max_line - Current_File->min_line + 1;
if(Current_File->same_file_fpnt != (struct input_file *) NULL)
Current_File->file_number =Current_File->same_file_fpnt->file_number;
else {
Current_File->file_number = ++File_Number;
file_available = VMS_TBT_Source_File(Current_File->name,
Current_File->file_number);
if(!file_available) {Current_File->file_number = 0;
File_Number--;
continue;};
};
VMS_TBT_Source_Lines(Current_File->file_number,
Current_File->min_line,
Current_File->max_line-Current_File->min_line+1);
}; /* for */
}; /* scope */
Current_File = (struct input_file*) NULL;

for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
/*
* Deal with text symbols
*/
if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
/*
* Ignore symbols starting with "L",
* as they are local symbols
*/
if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue;
/*
* If there is a routine start defined,
* terminate it.
*/
if (Current_Routine) {
/*
* End the routine
*/
VMS_TBT_Routine_End(text_siz,Current_Routine);
}
/*
* Store the routine begin traceback info
*/
if(Text_Psect != -1) {
VMS_TBT_Routine_Begin(symbolP,Text_Psect);
Current_Routine = symbolP;
}
/* Output local symbols, i.e. all symbols that are associated with a specific
* routine. We output them now so the debugger recognizes them as local to
* this routine.
*/
{ symbolS * symbolP1;
char* pnt;
char* pnt1;
for(symbolP1 = Current_Routine; symbolP1; symbolP1 = symbolP1->sy_next) {
if ((symbolP1->sy_nlist.n_type & N_STAB) == 0) continue;
if (symbolP1->sy_nlist.n_type != N_FUN) continue;
pnt=symbolP->sy_nlist.n_un.n_name;
pnt1=symbolP1->sy_nlist.n_un.n_name;
if(*pnt++ != '_') continue;
while(*pnt++ == *pnt1++) {};
if((*(--pnt) == '\0') && (*(--pnt1) == ':')) break;
};
if(symbolP1 != (symbolS *) NULL)
VMS_DBG_Define_Routine(symbolP1,Current_Routine,Text_Psect);
} /* local symbol block */
/*
* Done
*/
continue;
}
/*
* Deal with STAB symbols
*/
if ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
/*
* Dispatch on STAB type
*/
switch((unsigned char)symbolP->sy_nlist.n_type) {
/*
* Line number
*/
case N_SLINE:
/* Offset the line into the correct portion
* of the file */
if(Current_File->file_number == 0) break;
/* Sometimes the same offset gets several source
* lines assigned to it.
* We should be selective about which lines
* we allow, we should prefer lines that are
* in the main source file when debugging
* inline functions. */
if((Current_File->file_number != 1) &&
symbolP->sy_nlist.n_value ==
Current_Offset) break;
/* calculate actual debugger source line */
symbolP->sy_nlist.n_desc
+= Current_File->offset;
/*
* If this is the 1st N_SLINE, setup
* PC/Line correlation. Otherwise
* do the delta PC/Line. If the offset
* for the line number is not +ve we need
* to do another PC/Line correlation
* setup
*/
if (Current_Offset == -1) {
VMS_TBT_Line_PC_Correlation(
symbolP->sy_nlist.n_desc,
symbolP->sy_nlist.n_value,
Text_Psect,
0);
} else {
if ((symbolP->sy_nlist.n_desc -
Current_Line_Number) <= 0) {
/*
* Line delta is not +ve, we
* need to close the line and
* start a new PC/Line
* correlation.
*/
VMS_TBT_Line_PC_Correlation(0,
symbolP->sy_nlist.n_value -
Current_Offset,
0,
-1);
VMS_TBT_Line_PC_Correlation(
symbolP->sy_nlist.n_desc,
symbolP->sy_nlist.n_value,
Text_Psect,
0);
} else {
/*
* Line delta is +ve, all is well
*/
VMS_TBT_Line_PC_Correlation(
symbolP->sy_nlist.n_desc -
Current_Line_Number,
symbolP->sy_nlist.n_value -
Current_Offset,
0,
1);
}
}
/*
* Update the current line/PC
*/
Current_Line_Number = symbolP->sy_nlist.n_desc;
Current_Offset = symbolP->sy_nlist.n_value;
/*
* Done
*/
break;
/*
* Source file
*/
case N_SO:
/*
* Remember that we had a source file
* and emit the source file debugger
* record
*/
Current_File =
find_file(symbolP);
break;
/* We need to make sure that we are really in the actual source file when
* we compute the maximum line number. Otherwise the debugger gets really
* confused */
case N_SOL:
Current_File =
find_file(symbolP);
break;
}
}
}
/*
* If there is a routine start defined,
* terminate it (and the line numbers)
*/
if (Current_Routine) {
/*
* Terminate the line numbers
*/
VMS_TBT_Line_PC_Correlation(0,
text_siz - Current_Routine->sy_nlist.n_value,
0,
-1);
/*
* Terminate the routine
*/
VMS_TBT_Routine_End(text_siz,Current_Routine);
}
}
/*
* Write the Traceback End Module TBT record
*/
VMS_TBT_Module_End();

/*
* Write the End Of Module record
*/
if (Entry_Point_Symbol == 0)
Write_VMS_EOM_Record(-1,0);
else
Write_VMS_EOM_Record(Text_Psect,
Entry_Point_Symbol->sy_nlist.n_value);

/*
* All done, close the object file
*/
Close_VMS_Object_File();
}


/****** VMS OBJECT FILE HACKING ROUTINES *******/


/*
* Global data (Object records limited to 512 bytes by VAX-11 "C" runtime)
*/
static int VMS_Object_File_FD; /* File Descriptor for object file */
static char Object_Record_Buffer[512]; /* Buffer for object file records */
static int Object_Record_Offset; /* Offset to end of data */
static int Current_Object_Record_Type; /* Type of record in above */

/*
* Macros for placing data into the object record buffer
*/
#define PUT_LONG(val) *((long *)(Object_Record_Buffer + \
Object_Record_Offset)) = val; \
Object_Record_Offset += sizeof(long)

#define PUT_SHORT(val) *((short *)(Object_Record_Buffer + \
Object_Record_Offset)) = val; \
Object_Record_Offset += sizeof(short)

#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val

#define PUT_COUNTED_STRING(cp) {\
register char *p = cp; \
PUT_CHAR(strlen(p)); \
while(*p) PUT_CHAR(*p++);}

/*
* Macro for determining if a Name has psect attributes attached
* to it.
*/
#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_"
#define PSECT_ATTRIBUTES_STRING_LENGTH 18

#define HAS_PSECT_ATTRIBUTES(Name) \
(strncmp((Name[0] == '_' ? Name + 1 : Name), \
PSECT_ATTRIBUTES_STRING, \
PSECT_ATTRIBUTES_STRING_LENGTH) == 0)


/*
* Create the VMS object file
*/
Create_VMS_Object_File()
{
#ifdef eunice
VMS_Object_File_FD = creat(out_file_name, 0777, "var");
#else eunice
VMS_Object_File_FD = creat(out_file_name, 0, "rfm=var");
#endif eunice
/*
* Deal with errors
*/
if (VMS_Object_File_FD < 0) {
char Error_Line[256];

sprintf(Error_Line,"Couldn't create VMS object file \"%s\"",
out_file_name);
error(Error_Line);
}
/*
* Initialize object file hacking variables
*/
Object_Record_Offset = 0;
Current_Object_Record_Type = -1;
}


/*
* Declare a particular type of object file record
*/
Set_VMS_Object_File_Record(Type)
int Type;
{
/*
* If the type matches, we are done
*/
if (Type == Current_Object_Record_Type) return;
/*
* Otherwise: flush the buffer
*/
Flush_VMS_Object_Record_Buffer();
/*
* Set the new type
*/
Current_Object_Record_Type = Type;
}


/*
* Flush the object record buffer to the object file
*/
Flush_VMS_Object_Record_Buffer()
{
int i;

/*
* If the buffer is empty, we are done
*/
if (Object_Record_Offset == 0) return;
/*
* Write the data to the file
*/
i= write(VMS_Object_File_FD,
Object_Record_Buffer,
Object_Record_Offset);
if (i != Object_Record_Offset)
error("I/O error writing VMS object file");
/*
* The buffer is now empty
*/
Object_Record_Offset = 0;
}


/*
* Close the VMS Object file
*/
Close_VMS_Object_File()
{
close(VMS_Object_File_FD);
}


/*
* Write the MHD (Module Header) records
*/
Write_VMS_MHD_Records()
{
register char *cp,*cp1;
register int i;
struct {int Size; char *Ptr;} Descriptor;
char Module_Name[256];
char Now[17];

/*
* We are writing a module header record
*/
Set_VMS_Object_File_Record(OBJ$C_HDR);
/*
* ***************************
* *MAIN MODULE HEADER RECORD*
* ***************************
*
* Store record type and header type
*/
PUT_CHAR(OBJ$C_HDR);
PUT_CHAR(MHD$C_MHD);
/*
* Structure level is 0
*/
PUT_CHAR(OBJ$C_STRLVL);
/*
* Maximum record size is size of the object record buffer
*/
PUT_SHORT(sizeof(Object_Record_Buffer));
/*
* Get module name (the FILENAME part of the object file)
*/
cp = out_file_name;
cp1 = Module_Name;
while(*cp) {
if ((*cp == ']') || (*cp == '>') ||
(*cp == ':') || (*cp == '/')) {
cp1 = Module_Name;
cp++;
continue;
}
*cp1++ = islower(*cp) ? toupper(*cp++) : *cp++;
}
*cp1 = 0;
/*
* Limit it to 31 characters and store in the object record
*/
while(--cp1 >= Module_Name)
if (*cp1 == '.') *cp1 = 0;
if (strlen(Module_Name) > 31) {
if(flagseen['+'])
printf("%s: Module name truncated: %s\n", myname, Module_Name);
Module_Name[31] = 0;
}
PUT_COUNTED_STRING(Module_Name);
/*
* Module Version is "V1.0"
*/
PUT_COUNTED_STRING("V1.0");
/*
* Creation time is "now" (17 chars of time string)
*/
Descriptor.Size = 17;
Descriptor.Ptr = Now;
sys$asctim(0,&Descriptor,0,0);
for(i = 0; i < 17; i++) PUT_CHAR(Now[i]);
/*
* Patch time is "never" (17 zeros)
*/
for(i = 0; i < 17; i++) PUT_CHAR(0);
/*
* Flush the record
*/
Flush_VMS_Object_Record_Buffer();
/*
* *************************
* *LANGUAGE PROCESSOR NAME*
* *************************
*
* Store record type and header type
*/
PUT_CHAR(OBJ$C_HDR);
PUT_CHAR(MHD$C_LNM);
/*
* Store language processor name and version
* (not a counted string!)
*/
cp = compiler_version_string;
if (cp == 0) {
cp ="GNU AS V";
while(*cp) PUT_CHAR(*cp++);
cp = strchr(&version_string,'.');
while(*cp != ' ') cp--; cp++;
};
while(*cp >= 32) PUT_CHAR(*cp++);
/*
* Flush the record
*/
Flush_VMS_Object_Record_Buffer();
}


/*
* Write the EOM (End Of Module) record
*/
Write_VMS_EOM_Record(Psect, Offset)
int Psect;
int Offset;
{
/*
* We are writing an end-of-module record
*/
Set_VMS_Object_File_Record(OBJ$C_EOM);
/*
* Store record Type
*/
PUT_CHAR(OBJ$C_EOM);
/*
* Store the error severity (0)
*/
PUT_CHAR(0);
/*
* Store the entry point, if it exists
*/
if (Psect >= 0) {
/*
* Store the entry point Psect
*/
PUT_CHAR(Psect);
/*
* Store the entry point Psect offset
*/
PUT_LONG(Offset);
}
/*
* Flush the record
*/
Flush_VMS_Object_Record_Buffer();
}


/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/

static int
hash_string (ptr)
unsigned char *ptr;
{
register unsigned char *p = ptr;
register unsigned char *end = p + strlen(ptr);
register unsigned char c;
register int hash = 0;

while (p != end)
{
c = *p++;
hash = ((hash<<3) + (hash<<15) + (hash>>28) + c);
}
return hash;
}

/*
* Generate a Case-Hacked VMS symbol name (limited to 31 chars)
*/
VMS_Case_Hack_Symbol(In,Out)
register char *In;
register char *Out;
{
long int init = 0;
long int result;
char *pnt;
char *new_name;
char *old_name;
register int i;
int destructor = 0; /*hack to allow for case sens in a destructor*/
int truncate = 0;
int Case_Hack_Bits = 0;
int Saw_Dollar = 0;
static char Hex_Table[16] =
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

/*
* Kill any leading "_"
*/
if (*In == '_') In++;

new_name=Out; /* save this for later*/

if((In[0]=='_')&&(In[1]=='$')&&(In[2]=='_'))
destructor=1;

/* We may need to truncate the symbol, save the hash for later*/
if(strlen(In)>23) result = hash_string(In);
/*
* Is there a Psect Attribute to skip??
*/
if (HAS_PSECT_ATTRIBUTES(In)) {
/*
* Yes: Skip it
*/
In += PSECT_ATTRIBUTES_STRING_LENGTH;
while(*In) {
if ((In[0] == '$') && (In[1] == '$')) {
In += 2;
break;
}
In++;
}
}

old_name=In;
/* if(strlen(In) > 31 && flagseen['+'])
printf("%s: Symbol name truncated: %s\n",myname,In);*/
/*
* Do the case conversion
*/
i = 23; /* Maximum of 23 chars */
while(*In && (--i >= 0)) {
Case_Hack_Bits <<= 1;
if (*In == '$') Saw_Dollar = 1;
if ((destructor==1)&&(i==21)) Saw_Dollar = 0;
if (isupper(*In)) {
*Out++ = *In++;
Case_Hack_Bits |= 1;
} else {
*Out++ = islower(*In) ? toupper(*In++) : *In++;
}
}
/*
* If we saw a dollar sign, we don't do case hacking
*/
if(flagseen['h'] || Saw_Dollar)
Case_Hack_Bits = 0;

/*
* If we have more than 23 characters and everything is lowercase
* we can insert the full 31 characters
*/
if (*In) {
/*
* We have more than 23 characters
* If we must add the case hack, then we have truncated the str
*/
pnt=Out;
truncate=1;
if (Case_Hack_Bits == 0) {
/*
* And so far they are all lower case:
* Check up to 8 more characters
* and ensure that they are lowercase
*/
if(flagseen['h'])
i=8;
else
for(i = 0; (In[i] != 0) && (i < 8); i++)
if (isupper(In[i]) && !Saw_Dollar)
break;
if(In[i]==0)
truncate=0;

if ((i >= 8) || (In[i] == 0)) {
/*
* They are: Copy up to 31 characters
* to the output string
*/
i = 8;
while((--i >= 0) && (*In))
*Out++ = islower(*In) ?
toupper(*In++) :
*In++;
}
}
}
/*
* If there were any uppercase characters in the name we
* take on the case hacking string
*/

/* Old behavior for regular GNU-C compiler */
if (!flagseen['+'])
truncate=0;
if ((Case_Hack_Bits != 0)||(truncate==1)) {
if(truncate==0) {
*Out++ = '_';
for(i = 0; i < 6; i++) {
*Out++ = Hex_Table[Case_Hack_Bits & 0xf];
Case_Hack_Bits >>= 4;
}
*Out++ = 'X';
} else {
Out=pnt; /*Cut back to 23 characters maximum */
*Out++ = '_';
for( i=0; i < 7; i++) {
init = result & 0x01f;
if (init < 10)
*Out++='0'+init;
else
*Out++ = 'A'+init-10;
result = result >> 5;
}
}
} /*Case Hack */
/*
* Done
*/
*Out = 0;
if( truncate==1 && flagseen['+'] && flagseen['H'])
printf("%s: Symbol %s replaced by %s\n",myname,old_name,new_name);
}


/*
* Scan a symbol name for a psect attribute specification
*/
VMS_Modify_Psect_Attributes(Name, Attribute_Pointer)
char *Name;
int *Attribute_Pointer;
{
register int i;
register char *cp;
int Negate;
static struct {
char *Name;
int Value;
} Attributes[] = {
{"PIC", GPS$M_PIC},
{"LIB", GPS$M_LIB},
{"OVR", GPS$M_OVR},
{"REL", GPS$M_REL},
{"GBL", GPS$M_GBL},
{"SHR", GPS$M_SHR},
{"EXE", GPS$M_EXE},
{"RD", GPS$M_RD},
{"WRT", GPS$M_WRT},
{"VEC", GPS$M_VEC},
{0, 0}};

/*
* Kill leading "_"
*/
if (*Name == '_') Name++;
/*
* Check for a PSECT attribute list
*/
if (!HAS_PSECT_ATTRIBUTES(Name)) return; /* If not, return */
/*
* Skip the attribute list indicator
*/
Name += PSECT_ATTRIBUTES_STRING_LENGTH;
/*
* Process the attributes ("_" separated, "$" terminated)
*/
while(*Name != '$') {
/*
* Assume not negating
*/
Negate = 0;
/*
* Check for "NO"
*/
if ((Name[0] == 'N') && (Name[1] == 'O')) {
/*
* We are negating (and skip the NO)
*/
Negate = 1;
Name += 2;
}
/*
* Find the token delimiter
*/
cp = Name;
while(*cp && (*cp != '_') && (*cp != '$')) cp++;
/*
* Look for the token in the attribute list
*/
for(i = 0; Attributes[i].Name; i++) {
/*
* If the strings match, set/clear the attr.
*/
if (strncmp(Name, Attributes[i].Name, cp - Name) == 0) {
/*
* Set or clear
*/
if (Negate)
*Attribute_Pointer &=
~Attributes[i].Value;
else
*Attribute_Pointer |=
Attributes[i].Value;
/*
* Done
*/
break;
}
}
/*
* Now skip the attribute
*/
Name = cp;
if (*Name == '_') Name++;
}
/*
* Done
*/
return;
}


/*
* Define a psect
*/
VMS_Psect_Spec(Name, Size, Type)
char *Name;
int Size;
char *Type;
{
char Local[32];
int Psect_Attributes;

/*
* We are writing a GSD record
*/
Set_VMS_Object_File_Record(OBJ$C_GSD);
/*
* If the buffer is empty we must insert the GSD record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
/*
* We are writing a PSECT definition subrecord
*/
PUT_CHAR(GSD$C_PSC);
/*
* Psects are always LONGWORD aligned
*/
PUT_CHAR(2);
/*
* Generate the appropriate PSECT flags given the PSECT type
*/
if (strcmp(Type,"COMMON") == 0) {
/*
* Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT
*/
Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
GPS$M_SHR|GPS$M_RD|GPS$M_WRT);
} else if (strcmp(Type,"CONST") == 0) {
/*
* Common block psects are: PIC,OVR,REL,GBL,SHR,RD
*/
Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
GPS$M_SHR|GPS$M_RD);
} else if (strcmp(Type,"DATA") == 0) {
/*
* The Data psects are PIC,REL,RD,WRT
*/
Psect_Attributes =
(GPS$M_PIC|GPS$M_REL|GPS$M_RD|GPS$M_WRT);
} else if (strcmp(Type,"TEXT") == 0) {
/*
* The Text psects are PIC,REL,SHR,EXE,RD
*/
Psect_Attributes =
(GPS$M_PIC|GPS$M_REL|GPS$M_SHR|
GPS$M_EXE|GPS$M_RD);
} else {
/*
* Error: Unknown psect type
*/
error("Unknown VMS psect type");
}
/*
* Modify the psect attributes according to any attribute string
*/
if (HAS_PSECT_ATTRIBUTES(Name))
VMS_Modify_Psect_Attributes(Name,&Psect_Attributes);
/*
* Specify the psect attributes
*/
PUT_SHORT(Psect_Attributes);
/*
* Specify the allocation
*/
PUT_LONG(Size);
/*
* Finally, the psect name
*/
VMS_Case_Hack_Symbol(Name,Local);
PUT_COUNTED_STRING(Local);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}


/*
* Define a global symbol
*/
VMS_Global_Symbol_Spec(Name, Psect_Number, Psect_Offset, Defined)
char *Name;
int Psect_Number;
int Psect_Offset;
{
char Local[32];

/*
* We are writing a GSD record
*/
Set_VMS_Object_File_Record(OBJ$C_GSD);
/*
* If the buffer is empty we must insert the GSD record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
/*
* We are writing a Global symbol definition subrecord
*/
if (Psect_Number <= 255) {
PUT_CHAR(GSD$C_SYM);
} else {
PUT_CHAR(GSD$C_SYMW);
}
/*
* Data type is undefined
*/
PUT_CHAR(0);
/*
* Switch on Definition/Reference
*/
if (Defined) {
/*
* Definition:
* Flags = "RELOCATABLE" and "DEFINED"
*/
PUT_SHORT(GSY$M_DEF|GSY$M_REL);
/*
* Psect Number
*/
if (Psect_Number <= 255) {
PUT_CHAR(Psect_Number);
} else {
PUT_SHORT(Psect_Number);
}
/*
* Offset
*/
PUT_LONG(Psect_Offset);
} else {
/*
* Reference:
* Flags = "RELOCATABLE"
*/
PUT_SHORT(GSY$M_REL);
}
/*
* Finally, the global symbol name
*/
VMS_Case_Hack_Symbol(Name,Local);
PUT_COUNTED_STRING(Local);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}


/*
* Define a procedure entry pt/mask
*/
VMS_Procedure_Entry_Pt(Name, Psect_Number, Psect_Offset, Entry_Mask)
char *Name;
int Psect_Number;
int Psect_Offset;
int Entry_Mask;
{
char Local[32];

/*
* We are writing a GSD record
*/
Set_VMS_Object_File_Record(OBJ$C_GSD);
/*
* If the buffer is empty we must insert the GSD record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
/*
* We are writing a Procedure Entry Pt/Mask subrecord
*/
if (Psect_Number <= 255) {
PUT_CHAR(GSD$C_EPM);
} else {
PUT_CHAR(GSD$C_EPMW);
}
/*
* Data type is undefined
*/
PUT_CHAR(0);
/*
* Flags = "RELOCATABLE" and "DEFINED"
*/
PUT_SHORT(GSY$M_DEF|GSY$M_REL);
/*
* Psect Number
*/
if (Psect_Number <= 255) {
PUT_CHAR(Psect_Number);
} else {
PUT_SHORT(Psect_Number);
}
/*
* Offset
*/
PUT_LONG(Psect_Offset);
/*
* Entry mask
*/
PUT_SHORT(Entry_Mask);
/*
* Finally, the global symbol name
*/
VMS_Case_Hack_Symbol(Name,Local);
PUT_COUNTED_STRING(Local);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}


/*
* Set the current location counter to a particular Psect and Offset
*/
VMS_Set_Psect(Psect_Index, Offset, Record_Type)
int Psect_Index;
int Offset;
int Record_Type;
{
/*
* We are writing a "Record_Type" record
*/
Set_VMS_Object_File_Record(Record_Type);
/*
* If the buffer is empty we must insert the record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Stack the Psect base + Longword Offset
*/
if (Psect_Index < 255) {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(Psect_Index);
} else {
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect_Index);
}
PUT_LONG(Offset);
/*
* Set relocation base
*/
PUT_CHAR(TIR$C_CTL_SETRB);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}

/*
* Make a data reference
*/
VMS_Set_Data(Psect_Index, Offset, Record_Type,Force)
int Psect_Index;
int Offset;
int Record_Type;
int Force;
{
/*
* We are writing a "Record_Type" record
*/
Set_VMS_Object_File_Record(Record_Type);
/*
* If the buffer is empty we must insert the record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Stack the Psect base + Longword Offset
*/
if(Force==1){
if(Psect_Index>127){
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect_Index);
PUT_LONG(Offset);}
else {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(Psect_Index);
PUT_LONG(Offset);}
} else {if(Offset>32767){
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect_Index);
PUT_LONG(Offset);}
else if(Offset>127){
PUT_CHAR(TIR$C_STA_WPW);
PUT_SHORT(Psect_Index);
PUT_SHORT(Offset);}
else{
PUT_CHAR(TIR$C_STA_WPB);
PUT_SHORT(Psect_Index);
PUT_CHAR(Offset);};};
/*
* Set relocation base
*/
PUT_CHAR(TIR$C_STO_PIDR);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}

/*
* Make a debugger reference to a struct, union or enum.
*/
VMS_Store_Struct(int Struct_Index)
{
/*
* We are writing a "OBJ$C_DBG" record
*/
Set_VMS_Object_File_Record(OBJ$C_DBG);
/*
* If the buffer is empty we must insert the record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
PUT_CHAR(TIR$C_STA_UW);
PUT_SHORT(Struct_Index);
PUT_CHAR(TIR$C_CTL_STKDL);
PUT_CHAR(TIR$C_STO_L);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}

/*
* Make a debugger reference to partially define a struct, union or enum.
*/
VMS_Def_Struct(int Struct_Index)
{
/*
* We are writing a "OBJ$C_DBG" record
*/
Set_VMS_Object_File_Record(OBJ$C_DBG);
/*
* If the buffer is empty we must insert the record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
PUT_CHAR(TIR$C_STA_UW);
PUT_SHORT(Struct_Index);
PUT_CHAR(TIR$C_CTL_DFLOC);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}

VMS_Set_Struct(int Struct_Index)
{/* see previous functions for comments */
Set_VMS_Object_File_Record(OBJ$C_DBG);
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
PUT_CHAR(TIR$C_STA_UW);
PUT_SHORT(Struct_Index);
PUT_CHAR(TIR$C_CTL_STLOC);
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}

/*
* Store immediate data in current Psect
*/
VMS_Store_Immediate_Data(Pointer, Size, Record_Type)
register char *Pointer;
int Size;
int Record_Type;
{
register int i;

/*
* We are writing a "Record_Type" record
*/
Set_VMS_Object_File_Record(Record_Type);
/*
* We can only store 128 bytes at a time
*/
while(Size > 0) {
/*
* Store a maximum of 128 bytes
*/
i = (Size > 128) ? 128 : Size;
Size -= i;
/*
* If we cannot accommodate this record, flush the
* buffer.
*/
if ((Object_Record_Offset + i + 1) >=
sizeof(Object_Record_Buffer))
Flush_VMS_Object_Record_Buffer();
/*
* If the buffer is empty we must insert record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Store the count
*/
PUT_CHAR(-i & 0xff);
/*
* Store the data
*/
while(--i >= 0) PUT_CHAR(*Pointer++);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}
}


/*
* Store repeated immediate data in current Psect
*/
VMS_Store_Repeated_Data(Repeat_Count,Pointer, Size, Record_Type)
int Repeat_Count;
register char *Pointer;
int Size;
int Record_Type;
{

/*
* Ignore zero bytes/words/longwords
*/
if ((Size == sizeof(char)) && (*Pointer == 0)) return;
if ((Size == sizeof(short)) && (*(short *)Pointer == 0)) return;
if ((Size == sizeof(long)) && (*(long *)Pointer == 0)) return;
/*
* If the data is too big for a TIR$C_STO_RIVB sub-record
* then we do it manually
*/
if (Size > 255) {
while(--Repeat_Count >= 0)
VMS_Store_Immediate_Data(Pointer,Size,Record_Type);
return;
}
/*
* We are writing a "Record_Type" record
*/
Set_VMS_Object_File_Record(Record_Type);
/*
* If the buffer is empty we must insert record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Stack the repeat count
*/
PUT_CHAR(TIR$C_STA_LW);
PUT_LONG(Repeat_Count);
/*
* And now the command and its data
*/
PUT_CHAR(TIR$C_STO_RIVB);
PUT_CHAR(Size);
while(--Size >= 0) PUT_CHAR(*Pointer++);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}


/*
* Store a Position Independent Reference
*/
VMS_Store_PIC_Symbol_Reference(Symbol, Offset, PC_Relative,
Psect, Psect_Offset, Record_Type)
struct symbol *Symbol;
int Offset;
int PC_Relative;
int Psect;
int Psect_Offset;
int Record_Type;
{
register struct VMS_Symbol *vsp =
(struct VMS_Symbol *)(Symbol->sy_number);
char Local[32];

/*
* We are writing a "Record_Type" record
*/
Set_VMS_Object_File_Record(Record_Type);
/*
* If the buffer is empty we must insert record type
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Set to the appropriate offset in the Psect
*/
if (PC_Relative) {
/*
* For a Code reference we need to fix the operand
* specifier as well (so back up 1 byte)
*/
VMS_Set_Psect(Psect, Psect_Offset - 1, Record_Type);
} else {
/*
* For a Data reference we just store HERE
*/
VMS_Set_Psect(Psect, Psect_Offset, Record_Type);
}
/*
* Make sure we are still generating a "Record Type" record
*/
if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
/*
* Dispatch on symbol type (so we can stack its value)
*/
switch(Symbol->sy_nlist.n_type) {
/*
* Global symbol
*/
#ifdef NOT_VAX_11_C_COMPATIBLE
case N_UNDF | N_EXT:
case N_DATA | N_EXT:
#endif NOT_VAX_11_C_COMPATIBLE
case N_UNDF:
case N_TEXT | N_EXT:
/*
* Get the symbol name (case hacked)
*/
VMS_Case_Hack_Symbol(Symbol->sy_nlist.n_un.n_name,Local);
/*
* Stack the global symbol value
*/
PUT_CHAR(TIR$C_STA_GBL);
PUT_COUNTED_STRING(Local);
if (Offset) {
/*
* Stack the longword offset
*/
PUT_CHAR(TIR$C_STA_LW);
PUT_LONG(Offset);
/*
* Add the two, leaving the result on the stack
*/
PUT_CHAR(TIR$C_OPR_ADD);
}
break;
/*
* Uninitialized local data
*/
case N_BSS:
/*
* Stack the Psect (+offset)
*/
if (vsp->Psect_Index < 255) {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(vsp->Psect_Index);
} else {
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(vsp->Psect_Index);
}
PUT_LONG(vsp->Psect_Offset + Offset);
break;
/*
* Local text
*/
case N_TEXT:
/*
* Stack the Psect (+offset)
*/
if (vsp->Psect_Index < 255) {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(vsp->Psect_Index);
} else {
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(vsp->Psect_Index);
}
PUT_LONG(Symbol->sy_nlist.n_value);
break;
/*
* Initialized local or global data
*/
case N_DATA:
#ifndef NOT_VAX_11_C_COMPATIBLE
case N_UNDF | N_EXT:
case N_DATA | N_EXT:
#endif NOT_VAX_11_C_COMPATIBLE
/*
* Stack the Psect (+offset)
*/
if (vsp->Psect_Index < 255) {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(vsp->Psect_Index);
} else {
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(vsp->Psect_Index);
}
PUT_LONG(vsp->Psect_Offset + Offset);
break;
}
/*
* Store either a code or data reference
*/
PUT_CHAR(PC_Relative ? TIR$C_STO_PICR : TIR$C_STO_PIDR);
/*
* Flush the buffer if it is more than 75% full
*/
if (Object_Record_Offset >
(sizeof(Object_Record_Buffer)*3/4))
Flush_VMS_Object_Record_Buffer();
}


/*
* Check in the text area for an indirect pc-relative reference
* and fix it up with addressing mode 0xff [PC indirect]
*
* THIS SHOULD BE REPLACED BY THE USE OF TIR$C_STO_PIRR IN THE
* PIC CODE GENERATING FIXUP ROUTINE.
*/
VMS_Fix_Indirect_Reference(Text_Psect, Offset, fragP, text_frag_root)
int Text_Psect;
int Offset;
register fragS *fragP;
struct frag *text_frag_root;
{
/*
* The addressing mode byte is 1 byte before the address
*/
Offset--;
/*
* Is it in THIS frag??
*/
if ((Offset < fragP->fr_address) ||
(Offset >= (fragP->fr_address + fragP->fr_fix))) {
/*
* We need to search for the fragment containing this
* Offset
*/
for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
if ((Offset >= fragP->fr_address) &&
(Offset < (fragP->fr_address + fragP->fr_fix)))
break;
}
/*
* If we couldn't find the frag, things are BAD!!
*/
if (fragP == 0)
error("Couldn't find fixup fragment when checking for indirect reference");
}
/*
* Check for indirect PC relative addressing mode
*/
if (fragP->fr_literal[Offset - fragP->fr_address] == (char)0xff) {
static char Address_Mode = 0xff;

/*
* Yes: Store the indirect mode back into the image
* to fix up the damage done by STO_PICR
*/
VMS_Set_Psect(Text_Psect,Offset,OBJ$C_TIR);
VMS_Store_Immediate_Data(&Address_Mode,1,OBJ$C_TIR);
}
}


/*
* Write the Traceback Module Begin record
*/
VMS_TBT_Module_Begin()
{
register char *cp,*cp1;
int Size;
char Module_Name[256];
char Local[256];

/*
* Get module name (the FILENAME part of the object file)
*/
cp = out_file_name;
cp1 = Module_Name;
while(*cp) {
if ((*cp == ']') || (*cp == '>') ||
(*cp == ':') || (*cp == '/')) {
cp1 = Module_Name;
cp++;
continue;
}
*cp1++ = islower(*cp) ? toupper(*cp++) : *cp++;
}
*cp1 = 0;
/*
* Limit it to 31 characters
*/
while(--cp1 >= Module_Name)
if (*cp1 == '.') *cp1 = 0;
if (strlen(Module_Name) > 31) {
if(flagseen['+'])
printf("%s: Module name truncated: %s\n",myname, Module_Name);
Module_Name[31] = 0;
}
/*
* Arrange to store the data locally (leave room for size byte)
*/
cp = Local+1;
/*
* Begin module
*/
*cp++ = DST$C_MODBEG;
/*
* Unused
*/
*cp++ = 0;
/*
* Language type == "C"
*/
*(long *)cp = DST$C_C;
cp += sizeof(long);
/*
* Store the module name
*/
*cp++ = strlen(Module_Name);
cp1 = Module_Name;
while(*cp1) *cp++ = *cp1++;
/*
* Now we can store the record size
*/
Size = (cp - Local);
Local[0] = Size-1;
/*
* Put it into the object record
*/
VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT);
}


/*
* Write the Traceback Module End record
*/
VMS_TBT_Module_End()
{
char Local[2];

/*
* End module
*/
Local[0] = 1;
Local[1] = DST$C_MODEND;
/*
* Put it into the object record
*/
VMS_Store_Immediate_Data(Local, 2, OBJ$C_TBT);
}


/*
* Write the Traceback Routine Begin record
*/
VMS_TBT_Routine_Begin(symbolP, Psect)
struct symbol *symbolP;
int Psect;
{
register char *cp,*cp1;
char *Name;
int Offset;
int Size;
char Local[512];

/*
* Strip the leading "_" from the name
*/
Name = symbolP->sy_nlist.n_un.n_name;
if (*Name == '_') Name++;
/*
* Get the text psect offset
*/
Offset = symbolP->sy_nlist.n_value;
/*
* Calculate the record size
*/
Size = 1+1+4+1+strlen(Name);
/*
* Record Size
*/
Local[0] = Size;
/*
* Begin Routine
*/
Local[1] = DST$C_RTNBEG;
/*
* Uses CallS/CallG
*/
Local[2] = 0;
/*
* Store the data so far
*/
VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
/*
* Make sure we are still generating a OBJ$C_TBT record
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
/*
* Now get the symbol address
*/
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect);
PUT_LONG(Offset);
/*
* Store the data reference
*/
PUT_CHAR(TIR$C_STO_PIDR);
/*
* Store the counted string as data
*/
cp = Local;
cp1 = Name;
Size = strlen(cp1) + 1;
*cp++ = Size - 1;
while(*cp1) *cp++ = *cp1++;
VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT);
}


/*
* Write the Traceback Routine End record
* We *must* search the symbol table to find the next routine, since
* the assember has a way of reassembling the symbol table OUT OF ORDER
* Thus the next routine in the symbol list is not necessarily the
* next one in memory. For debugging to work correctly we must know the
* size of the routine.
*/
VMS_TBT_Routine_End(Max_Size,sp)
int Max_Size;
symbolS *sp;
{
symbolS *symbolP;
int Size = 0x7fffffff;
char Local[16];


for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue;
if((symbolP->sy_nlist.n_value > sp->sy_nlist.n_value) &&
(symbolP->sy_nlist.n_value < Size ))
Size = symbolP->sy_nlist.n_value;
/* check if gcc_compiled. has size of zero */
if((symbolP->sy_nlist.n_value == sp->sy_nlist.n_value) &&
sp != symbolP &&
!strcmp(sp->sy_nlist.n_un.n_name,"gcc_compiled."))
Size = symbolP->sy_nlist.n_value;

};
};
if(Size == 0x7fffffff) Size = Max_Size;
Size -= sp->sy_nlist.n_value; /* and get the size of the routine */
/*
* Record Size
*/
Local[0] = 6;
/*
* End of Routine
*/
Local[1] = DST$C_RTNEND;
/*
* Unused
*/
Local[2] = 0;
/*
* Size of routine
*/
*((long *)(Local+3)) = Size;
/*
* Store the record
*/
VMS_Store_Immediate_Data(Local,7, OBJ$C_TBT);
}
/*
* Write the Traceback Block End record
*/
VMS_TBT_Block_Begin(symbolP, Psect, Name)
struct symbol *symbolP;
int Psect;
char* Name;
{
register char *cp,*cp1;
int Offset;
int Size;
char Local[512];
/*
* Begin block
*/
Size = 1+1+4+1+strlen(Name);
/*
* Record Size
*/
Local[0] = Size;
/*
* Begin Block - We simulate with a phony routine
*/
Local[1] = DST$C_BLKBEG;
/*
* Uses CallS/CallG
*/
Local[2] = 0;
/*
* Store the data so far
*/
VMS_Store_Immediate_Data(Local, 3, OBJ$C_DBG);
/*
* Make sure we are still generating a OBJ$C_DBG record
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
/*
* Now get the symbol address
*/
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect);
/*
* Get the text psect offset
*/
Offset = symbolP->sy_nlist.n_value;
PUT_LONG(Offset);
/*
* Store the data reference
*/
PUT_CHAR(TIR$C_STO_PIDR);
/*
* Store the counted string as data
*/
cp = Local;
cp1 = Name;
Size = strlen(cp1) + 1;
*cp++ = Size - 1;
while(*cp1) *cp++ = *cp1++;
VMS_Store_Immediate_Data(Local, Size, OBJ$C_DBG);
}


/*
* Write the Traceback Block End record
*/
VMS_TBT_Block_End(int Size)
{
char Local[16];

/*
* End block - simulate with a phony end routine
*/
Local[0] = 6;
Local[1] = DST$C_BLKEND;
*((long *)(Local+3)) = Size;
/*
* Unused
*/
Local[2] = 0;
VMS_Store_Immediate_Data(Local,7, OBJ$C_DBG);
}



/*
* Write a Line number / PC correlation record
*/
VMS_TBT_Line_PC_Correlation(Line_Number, Offset, Psect, Do_Delta)
int Line_Number;
int Offset;
int Psect;
int Do_Delta;
{
register char *cp;
char Local[64];

/*
* If not delta, set our PC/Line number correlation
*/
if (Do_Delta == 0) {
/*
* Size
*/
Local[0] = 1+1+2+1+4;
/*
* Line Number/PC correlation
*/
Local[1] = DST$C_LINE_NUM;
/*
* Set Line number
*/
Local[2] = DST$C_SET_LINE_NUM;
*((unsigned short *)(Local+3)) = Line_Number-1;
/*
* Set PC
*/
Local[5] = DST$C_SET_ABS_PC;
VMS_Store_Immediate_Data(Local, 6, OBJ$C_TBT);
/*
* Make sure we are still generating a OBJ$C_TBT record
*/
if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
if (Psect < 255) {
PUT_CHAR(TIR$C_STA_PL);
PUT_CHAR(Psect);
} else {
PUT_CHAR(TIR$C_STA_WPL);
PUT_SHORT(Psect);
}
PUT_LONG(Offset);
PUT_CHAR(TIR$C_STO_PIDR);
/*
* Do a PC offset of 0 to register the line number
*/
Local[0] = 2;
Local[1] = DST$C_LINE_NUM;
Local[2] = 0; /* Increment PC by 0 and register line # */
VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
} else {
/*
* If Delta is negative, terminate the line numbers
*/
if (Do_Delta < 0) {
Local[0] = 1+1+4;
Local[1] = DST$C_LINE_NUM;
Local[2] = DST$C_TERM_L;
*((long *)(Local+3)) = Offset;
VMS_Store_Immediate_Data(Local, 7, OBJ$C_TBT);
/*
* Done
*/
return;
}
/*
* Do a PC/Line delta
*/
cp = Local+1;
*cp++ = DST$C_LINE_NUM;
if (Line_Number > 1) {
/*
* We need to increment the line number
*/
if (Line_Number-1 <= 255) {
*cp++ = DST$C_INCR_LINUM;
*cp++ = Line_Number-1;
} else {
*cp++ = DST$C_INCR_LINUM_W;
*(short *)cp = Line_Number-1;
cp += sizeof(short);
}
}
/*
* Increment the PC
*/
if (Offset <= 128) {
*cp++ = -Offset;
} else {
if (Offset < 0x10000) {
*cp++ = DST$C_DELTA_PC_W;
*(short *)cp = Offset;
cp += sizeof(short);
} else {
*cp++ = DST$C_DELTA_PC_L;
*(long *)cp = Offset;
cp += sizeof(long);
}
}
Local[0] = cp - (Local+1);
VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
}
}


/*
* Describe a source file to the debugger
*/
VMS_TBT_Source_File(Filename, ID_Number)
char *Filename;
int ID_Number;
{
register char *cp,*cp1;
int Status,i;
char Local[512];
static struct FAB Fab;
static struct NAM Nam;
static struct XABDAT Date_Xab;
static struct XABFHC File_Header_Xab;
char Es_String[255],Rs_String[255];

/*
* Setup the Fab
*/
Fab.fab$b_bid = FAB$C_BID;
Fab.fab$b_bln = sizeof(Fab);
Fab.fab$l_nam = (&Nam);
Fab.fab$l_xab = (struct XAB *)&Date_Xab;
/*
* Setup the Nam block so we can find out the FULL name
* of the source file.
*/
Nam.nam$b_bid = NAM$C_BID;
Nam.nam$b_bln = sizeof(Nam);
Nam.nam$l_rsa = Rs_String;
Nam.nam$b_rss = sizeof(Rs_String);
Nam.nam$l_esa = Es_String;
Nam.nam$b_ess = sizeof(Es_String);
/*
* Setup the Date and File Header Xabs
*/
Date_Xab.xab$b_cod = XAB$C_DAT;
Date_Xab.xab$b_bln = sizeof(Date_Xab);
Date_Xab.xab$l_nxt = (char *)&File_Header_Xab;
File_Header_Xab.xab$b_cod = XAB$C_FHC;
File_Header_Xab.xab$b_bln = sizeof(File_Header_Xab);
/* ((struct XAB *)&Date_Xab)->xab$b_cod = XAB$C_DAT; */
/* ((struct XAB *)&Date_Xab)->xab$b_bln = sizeof(Date_Xab); */
/* ((struct XAB *)&Date_Xab)->xab$l_nxt = (struct XAB *)&File_Header_Xab; */
/* ((struct XAB *)&File_Header_Xab)->xab$b_cod = XAB$C_FHC; */
/* ((struct XAB *)&File_Header_Xab)->xab$b_bln = sizeof(File_Header_Xab); */
/*
* Get the file information
*/
Fab.fab$l_fna = Filename;
Fab.fab$b_fns = strlen(Filename);
Status = sys$open(&Fab);
if (!(Status & 1)) {
printf("gas: Couldn't find source file \"%s\", Error = %%X%x\n",
Filename, Status);
return(0);
}
sys$close(&Fab);
/*
* Calculate the size of the resultant string
*/
i = Nam.nam$b_rsl;
/*
* Size of record
*/
Local[0] = 1+1+1+1+1+2+8+4+2+1+1+i+1;
/*
* Source declaration
*/
Local[1] = DST$C_SOURCE;
/*
* Make formfeeds count as source records
*/
Local[2] = DST$C_SRC_FORMFEED;
/*
* Declare source file
*/
Local[3] = DST$C_SRC_DECLFILE;
Local[4] = 1+2+8+4+2+1+1+i+1;
cp = Local+5;
/*
* Flags
*/
*cp++ = 0;
/*
* File ID
*/
*(short *)cp = ID_Number;
cp += sizeof(short);
/*
* Creation Date
*/
*(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[0];
cp += sizeof(long);
*(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[1];
cp += sizeof(long);
/*
* End of file block
*/
*(long *)cp = File_Header_Xab.xab$l_ebk;
cp += sizeof(long);
/*
* First free byte
*/
*(short *)cp = File_Header_Xab.xab$w_ffb;
cp += sizeof(short);
/*
* Record format
*/
*cp++ = File_Header_Xab.xab$b_rfo;
/*
* Filename
*/
*cp++ = i;
cp1 = Rs_String;
while(--i >= 0) *cp++ = *cp1++;
/*
* Library module name (none)
*/
*cp++ = 0;
/*
* Done
*/
VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
}


/*
* Give the number of source lines to the debugger
*/
VMS_TBT_Source_Lines(ID_Number,Starting_Line_Number,Number_Of_Lines)
int ID_Number;
int Starting_Line_Number;
int Number_Of_Lines;
{
char *cp,*cp1;
char Local[16];

/*
* Size of record
*/
Local[0] = 1+1+2+1+4+1+2;
/*
* Source declaration
*/
Local[1] = DST$C_SOURCE;
/*
* Set Source File
*/
cp = Local+2;
*cp++ = DST$C_SRC_SETFILE;
/*
* File ID Number
*/
*(short *)cp = ID_Number;
cp += sizeof(short);
/*
* Set record number
*/
*cp++ = DST$C_SRC_SETREC_L;
*(long *)cp = Starting_Line_Number;
cp += sizeof(long);
/*
* Define lines
*/
*cp++ = DST$C_SRC_DEFLINES_W;
*(short *)cp = Number_Of_Lines;
cp += sizeof(short);
/*
* Done
*/
VMS_Store_Immediate_Data(Local, cp-Local, OBJ$C_TBT);
}


/*
* Given the pointer to a symbol we calculate how big the data at the
* symbol is. We do this by looking for the next symbol (local or
* global) which will indicate the start of another datum.
*/
int VMS_Initialized_Data_Size(sp, End_Of_Data)
register struct symbol *sp;
int End_Of_Data;
{
register struct symbol *sp1,*Next_Symbol;

/*
* Find the next symbol
* it delimits this datum
*/
Next_Symbol = 0;
for (sp1 = symbol_rootP; sp1; sp1 = sp1->sy_next) {
/*
* The data type must match
*/
if ((sp1->sy_nlist.n_type & ~N_EXT) != N_DATA) continue;
/*
* The symbol must be AFTER this symbol
*/
if (sp1->sy_nlist.n_value <= sp->sy_nlist.n_value) continue;
/*
* We ignore THIS symbol
*/
if (sp1 == sp) continue;
/*
* If there is already a candidate selected for the
* next symbol, see if we are a better candidate
*/
if (Next_Symbol) {
/*
* We are a better candidate if we are "closer"
* to the symbol
*/
if (sp1->sy_nlist.n_value >
Next_Symbol->sy_nlist.n_value)
continue;
/*
* Win: Make this the candidate
*/
Next_Symbol = sp1;
} else {
/*
* This is the 1st candidate
*/
Next_Symbol = sp1;
}
}
/*
* Calculate its size
*/
return(Next_Symbol ?
(Next_Symbol->sy_nlist.n_value -
sp->sy_nlist.n_value) :
(End_Of_Data - sp->sy_nlist.n_value));
}



/* this routine locates a file in the list of files. If an entry does not
* exist, one is created. For include files, a new entry is always created
* such that inline functions can be properly debugged */
struct input_file *
find_file(sp)
symbolS * sp;
{
struct input_file * same_file;
struct input_file * fpnt;
same_file = (struct input_file*) NULL;
for(fpnt = file_root; fpnt; fpnt = fpnt->next){
if(fpnt == (struct input_file*) NULL) break;
if(fpnt->spnt == sp) return fpnt;
};
for(fpnt = file_root; fpnt; fpnt = fpnt->next){
if(fpnt == (struct input_file*) NULL) break;
if (strcmp(sp->sy_nlist.n_un.n_name,fpnt->name) == 0){
if(fpnt->flag == 1)return fpnt;
same_file = fpnt;
break;
};
};
fpnt = (struct input_file*) malloc(sizeof(struct input_file));
if(file_root == (struct input_file*) NULL) file_root = fpnt;
else {
struct input_file * fpnt1;
for(fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next);
fpnt1->next = fpnt;
};
fpnt->next = (struct input_file*) NULL;
fpnt->name = sp->sy_nlist.n_un.n_name;
fpnt->min_line = 0x7fffffff;
fpnt->max_line = 0;
fpnt->offset = 0;
fpnt->flag = 0;
fpnt->file_number = 0;
fpnt->spnt = sp;
fpnt->same_file_fpnt = same_file;
return fpnt;
}


/*
* This is a hacked _doprnt() for VAX-11 "C". It understands that
* it is ONLY called by as_fatal(Format, Args) with a pointer to the
* "Args" argument. From this we can make it all work right!
*/
#ifndef eunice
_doprnt(Format, a, f)
char *Format;
FILE *f;
char **a;
{
int Nargs = ((int *)a)[-2]; /* This understands as_fatal() */

switch(Nargs) {
default: fprintf(f,"_doprnt error on \"%s\"!!",Format); break;
case 1: fprintf(f,Format); break;
case 2: fprintf(f,Format,a[0]); break;
case 3: fprintf(f,Format,a[0],a[1]); break;
case 4: fprintf(f,Format,a[0],a[1],a[2]); break;
case 5: fprintf(f,Format,a[0],a[1],a[2],a[3]); break;
case 6: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4]); break;
case 7: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5]); break;
case 8: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6]); break;
case 9: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]); break;
case 10: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); break;
}
}

#endif /* eunice */

#endif /* VMS */
gas-1.38/vms-dbg.c 666 11660 0 111667 4720042064 11133 0ustar hack#include
#include "as.h"
#include "struc-symbol.h"
#include "symbols.h"
#include "objrecdef.h"
#include

/* This file contains many of the routines needed to output debugging info into
* the object file that the VMS debugger needs to understand symbols. These
* routines are called very late in the assembly process, and thus we can be
* fairly lax about changing things, since the GSD and the TIR sections have
* already been output.
*/

/* We need this info to cross correlate between the stabs def for a symbol and
* the actual symbol def. The actual symbol def contains the psect number and
* offset, which is needed to declare a variable to the debugger for global
* and static variables
*/
struct VMS_Symbol {
struct VMS_Symbol *Next;
struct symbol *Symbol;
int Size;
int Psect_Index;
int Psect_Offset;
};
extern struct VMS_Symbol *VMS_Symbols;

enum advanced_type {BASIC,POINTER,ARRAY,ENUM,STRUCT,UNION,FUNCTION,VOID,UNKNOWN};

/* this structure contains the information from the stabs directives, and the
* information is filled in by VMS_typedef_parse. Everything that is needed
* to generate the debugging record for a given symbol is present here.
* This could be done more efficiently, using nested struct/unions, but for now
* I am happy that it works.
*/
struct VMS_DBG_Symbol{
struct VMS_DBG_Symbol * next;
enum advanced_type advanced; /* description of what this is */
int dbx_type; /* this record is for this type */
int type2; /* For advanced types this is the type referred to.
i.e. the type a pointer points to, or the type
of object that makes up an array */
int VMS_type; /* Use this type when generating a variable def */
int index_min; /* used for arrays - this will be present for all */
int index_max; /* entries, but will be meaningless for non-arrays */
int data_size; /* size in bytes of the data type. For an array, this
is the size of one element in the array */
int struc_numb; /* Number of the structure/union/enum - used for ref */
};

struct VMS_DBG_Symbol *VMS_Symbol_type_list={(struct VMS_DBG_Symbol*) NULL};

/* we need this structure to keep track of forward references to
* struct/union/enum that have not been defined yet. When they are ultimately
* defined, then we can go back and generate the TIR commands to make a back
* reference.
*/

struct forward_ref{
struct forward_ref * next;
int dbx_type;
int struc_numb;
char resolved;
};

struct forward_ref * f_ref_root={(struct forward_ref*) NULL};

static char * symbol_name;
static structure_count=0;

/* this routine converts a number string into an integer, and stops when it
* sees an invalid character the return value is the address of the character
* just past the last character read. No error is generated.
*/
static char * cvt_integer(char* str,int * rtn){
int ival, neg;
neg = *str == '-' ? ++str, -1 : 1;
ival=0; /* first get the number of the type for dbx */
while((*str <= '9') && (*str >= '0'))
ival = 10*ival + *str++ -'0';
*rtn = neg*ival;
return str;
}

/* this routine fixes the names that are generated by C++, ".this" is a good
* example. The period does not work for the debugger, since it looks like
* the syntax for a structure element, and thus it gets mightily confused
*/
static fix_name(char* pnt){
for( ;*pnt != 0; pnt++){
if(*pnt == '.') *pnt = '$';
};
}

/* this routine is used to compare the names of certain types to various
* fixed types that are known by the debugger.
*/
#define type_check(x) !strcmp( symbol_name , x )

/* When defining a structure, this routine is called to find the name of
* the actual structure. It is assumed that str points to the equal sign
* in the definition, and it moves backward until it finds the start of the
* name. If it finds a 0, then it knows that this structure def is in the
* outermost level, and thus symbol_name points to the symbol name.
*/
static char* get_struct_name(char* str){
char* pnt;
pnt=str;
while((*pnt != ':') && (*pnt != '\0')) pnt--;
if(*pnt == '\0') return symbol_name;
*pnt-- = '\0';
while((*pnt != ';') && (*pnt != '=')) pnt--;
if(*pnt == ';') return pnt+1;
while((*pnt < '0') || (*pnt > '9')) pnt++;
while((*pnt >= '0') && (*pnt <= '9')) pnt++;
return pnt;
}
/* search symbol list for type number dbx_type. Return a pointer to struct */
static struct VMS_DBG_Symbol* find_symbol(int dbx_type){
struct VMS_DBG_Symbol* spnt;
spnt=VMS_Symbol_type_list;
while (spnt!=(struct VMS_DBG_Symbol*) NULL){
if(spnt->dbx_type==dbx_type) break;
spnt=spnt->next;};
if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/
return spnt;
}


/* Many good programmers cringe when they see a fixed size array - since I am
* using this to generate the various descriptors for the data types present,
* you might argue that the descriptor could overflow the array for a
* complicated variable, and then I am in deep doo-doo. My answer to this is
* that the debugger records that we write have all sorts of length bytes
* stored in them all over the place, and if we exceed 127 bytes (since the top
* bit indicates data, rather than a command), we are dead anyhow. So I figure
* why not do this the easy way. Besides, to get 128 bytes, you need something
* like an array with 10 indicies, or something like
* char **************************************** var;
* Lets get real. If some idiot writes programs like that he/she gets what
* they deserve. (It is possible to overflow the record with a somewhat
* simpler example, like: int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5];
* but still...). And if someone in the peanut gallery wants to know "What
* does VAX-C do with something like this?", I will tell you. It crashes.
* At least this code has the good sense to convert it to *void.
* In practice, I do not think that this presents too much of a problem, since
* struct/union/enum all use defined types, which sort of terminate the
* definition. It occurs to me that we could possibly do the same thing with
* arrays and pointers, but I don't know quite how it would be coded.
*
* And now back to the regularly scheduled program...
*/
#define MAX_DEBUG_RECORD 128
static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */
static int Lpnt; /* index into Local */
static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */
static int Apoint; /* index into Asuffix */
static char overflow; /* flag to indicate we have written too much*/
static int total_len; /* used to calculate the total length of variable
descriptor plus array descriptor - used for len byte*/
static int struct_number; /* counter used to assign indexes to struct
unions and enums */

/* this routine puts info into either Local or Asuffix, depending on the sign
* of size. The reason is that it is easier to build the variable descriptor
* backwards, while the array descriptor is best built forwards. In the end
* they get put together, if there is not a struct/union/enum along the way
*/
push(int value, int size){
char * pnt;
int i;
int size1;
long int val;
val=value;
pnt=(char*) &val;
size1 = size;
if (size < 0) {size1 = -size; pnt += size1-1;};
if(size < 0)
for(i=0;i Local[Lpnt--] = *pnt--;
if(Lpnt < 0) {overflow = 1; Lpnt = 1;};}
else for(i=0;i Asuffix[Apoint++] = *pnt++;
if(Apoint >= MAX_DEBUG_RECORD)
{overflow = 1; Apoint =MAX_DEBUG_RECORD-1;};}
}

/* this routine generates the array descriptor for a given array */
static array_suffix(struct VMS_DBG_Symbol* spnt2){
struct VMS_DBG_Symbol * spnt;
struct VMS_DBG_Symbol * spnt1;
int rank;
int total_size;
int i;
rank=0;
spnt=spnt2;
while(spnt->advanced != ARRAY) {
spnt=find_symbol(spnt->type2);
if(spnt == (struct VMS_DBG_Symbol *) NULL) return;};
spnt1=spnt;
spnt1=spnt;
total_size= 1;
while(spnt1->advanced == ARRAY) {rank++;
total_size *= (spnt1->index_max - spnt1->index_min +1);
spnt1=find_symbol(spnt1->type2);};
total_size = total_size * spnt1->data_size;
push(spnt1->data_size,2);
if(spnt1->VMS_type == 0xa3) push(0,1);
else push(spnt1->VMS_type,1);
push(4,1);
for(i=0;i<6;i++) push(0,1);
push(0xc0,1);
push(rank,1);
push(total_size,4);
push(0,4);
spnt1=spnt;
while(spnt1->advanced == ARRAY) {
push(spnt1->index_max - spnt1->index_min+1,4);
spnt1=find_symbol(spnt1->type2);};
spnt1=spnt;
while(spnt1->advanced == ARRAY) {
push(spnt1->index_min,4);
push(spnt1->index_max,4);
spnt1=find_symbol(spnt1->type2);};
}

/* this routine generates the start of a variable descriptor based upon
* a struct/union/enum that has yet to be defined. We define this spot as
* a new location, and save four bytes for the address. When the struct is
* finally defined, then we can go back and plug in the correct address
*/
static new_forward_ref(int dbx_type){
struct forward_ref* fpnt;
fpnt = (struct forward_ref*) malloc(sizeof(struct forward_ref));
fpnt->next = f_ref_root;
f_ref_root = fpnt;
fpnt->dbx_type = dbx_type;
fpnt->struc_numb = ++structure_count;
fpnt->resolved = 'N';
push(3,-1);
total_len = 5;
push(total_len,-2);
struct_number = - fpnt->struc_numb;
}

/* this routine generates the variable descriptor used to describe non-basic
* variables. It calls itself recursively until it gets to the bottom of it
* all, and then builds the descriptor backwards. It is easiest to do it this
*way since we must periodically write length bytes, and it is easiest if we know
*the value when it is time to write it.
*/
static int gen1(struct VMS_DBG_Symbol * spnt,int array_suffix_len){
struct VMS_DBG_Symbol * spnt1;
int i;
switch(spnt->advanced){
case VOID:
push(DBG$C_VOID,-1);
total_len += 1;
push(total_len,-2);
return 0;
case BASIC:
case FUNCTION:
if(array_suffix_len == 0) {
push(spnt->VMS_type,-1);
push(DBG$C_BASIC,-1);
total_len = 2;
push(total_len,-2);
return 1;};
push(0,-4);
push(0xfa02,-2);
total_len = -2;
return 1;
case STRUCT:
case UNION:
case ENUM:
struct_number=spnt->struc_numb;
if(struct_number < 0) {
new_forward_ref(spnt->dbx_type);
return 1;
}
push(DBG$C_STRUCT,-1);
total_len = 5;
push(total_len,-2);
return 1;
case POINTER:
spnt1=find_symbol(spnt->type2);
i=1;
if(spnt1 == (struct VMS_DBG_Symbol *) NULL)
new_forward_ref(spnt->type2);
else i=gen1(spnt1,0);
if(i){ /* (*void) is a special case, do not put pointer suffix*/
push(DBG$C_POINTER,-1);
total_len += 3;
push(total_len,-2);
};
return 1;
case ARRAY:
spnt1=spnt;
while(spnt1->advanced == ARRAY)
{spnt1 = find_symbol(spnt1->type2);
if(spnt1 == (struct VMS_DBG_Symbol *) NULL) {
printf("gcc-as warning(debugger output):");
printf("Forward reference error, dbx type %d\n",
spnt->type2);
return;}
};
/* It is too late to generate forward references, so the user gets a message.
* This should only happen on a compiler error */
i=gen1(spnt1,1);
i=Apoint;
array_suffix(spnt);
array_suffix_len = Apoint - i;
switch(spnt1->advanced){
case BASIC:
case FUNCTION:
break;
default:
push(0,-2);
total_len += 2;
push(total_len,-2);
push(0xfa,-1);
push(0x0101,-2);
push(DBG$C_COMPLEX_ARRAY,-1);
};
total_len += array_suffix_len + 8;
push(total_len,-2);
};
}

/* this generates a suffix for a variable. If it is not a defined type yet,
* then dbx_type contains the type we are expecting so we can generate a
* forward reference. This calls gen1 to build most of the descriptor, and
* then it puts the icing on at the end. It then dumps whatever is needed
* to get a complete descriptor (i.e. struct reference, array suffix ).
*/
static generate_suffix(struct VMS_DBG_Symbol * spnt,int dbx_type){
int ilen;
int i;
char pvoid[6] = {5,0xaf,0,1,0,5};
struct VMS_DBG_Symbol * spnt1;
Apoint=0;
Lpnt =MAX_DEBUG_RECORD-1;
total_len=0;
struct_number = 0;
overflow = 0;
if(spnt == (struct VMS_DBG_Symbol*) NULL)
new_forward_ref(dbx_type);
else{
if(spnt->VMS_type != 0xa3) return 0; /* no suffix needed */
gen1(spnt,0);
};
push(0x00af,-2);
total_len += 4;
push(total_len,-1);
/* if the variable descriptor overflows the record, output a descriptor for
* a pointer to void.
*/
if((total_len >= MAX_DEBUG_RECORD) || overflow) {
printf(" Variable descriptor %d too complicated. Defined as *void ",spnt->dbx_type);
VMS_Store_Immediate_Data(pvoid, 6, OBJ$C_DBG);
return;
};
i=0;
while(Lpnt < MAX_DEBUG_RECORD-1) Local[i++] = Local[++Lpnt];
Lpnt = i;
/* we use this for a reference to a structure that has already been defined */
if(struct_number > 0){
VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0;
VMS_Store_Struct(struct_number);};
/* we use this for a forward reference to a structure that has yet to be
*defined. We store four bytes of zero to make room for the actual address once
* it is known
*/
if(struct_number < 0){
struct_number = -struct_number;
VMS_Store_Immediate_Data(Local, Lpnt,OBJ$C_DBG);Lpnt=0;
VMS_Def_Struct(struct_number);
for(i=0;i<4;i++) Local[Lpnt++] = 0;
VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0;
};
i=0;
while(i if(Lpnt != 0)
VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);
Lpnt=0;
}

/* This routine generates a symbol definition for a C sybmol for the debugger.
* It takes a psect and offset for global symbols - if psect < 0, then this is
* a local variable and the offset is relative to FP. In this case it can
* be either a variable (Offset < 0) or a parameter (Offset > 0).
*/
VMS_DBG_record(struct VMS_DBG_Symbol* spnt,int Psect,int Offset, char* Name)
{
char* pnt;
int j;
int maxlen;
int i=0;
if(Psect < 0) { /* this is a local variable, referenced to SP */
maxlen=7+strlen(Name);
Local[i++] = maxlen;
Local[i++]=spnt->VMS_type;
if(Offset > 0) Local[i++] = DBG$C_FUNCTION_PARAMETER;
else Local[i++] = DBG$C_LOCAL_SYM;
pnt=(char*) &Offset;
for(j=0;j<4;j++) Local[i++]=*pnt++; /* copy the offset */
} else {
maxlen=7+strlen(Name); /* symbols fixed in memory */
Local[i++]=7+strlen(Name);
Local[i++]=spnt->VMS_type;
Local[i++]=1;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
VMS_Set_Data(Psect,Offset,OBJ$C_DBG,0);
}
Local[i++]=strlen(Name);
pnt=Name;
fix_name(pnt); /* if there are bad characters in name, convert them */
while(*pnt!='\0') Local[i++]=*pnt++;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG);
if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0);
}


/* This routine parses the stabs entries in order to make the definition
* for the debugger of local symbols and function parameters
*/
int VMS_local_stab_Parse(symbolS * sp){
char *pnt;
char *pnt1;
char *str;
struct VMS_DBG_Symbol* spnt;
struct VMS_Symbol * vsp;
int dbx_type;
int VMS_type;
dbx_type=0;
str=sp->sy_nlist.n_un.n_name;
pnt=(char*) strchr(str,':');
if(pnt==(char*) NULL) return; /* no colon present */
pnt1=pnt++; /* save this for later, and skip colon */
if(*pnt == 'c') return 0; /* ignore static constants */
/* there is one little catch that we must be aware of. Sometimes function
* parameters are optimized into registers, and the compiler, in its infiite
* wisdom outputs stabs records for *both*. In general we want to use the
* register if it is present, so we must search the rest of the symbols for
* this function to see if this parameter is assigned to a register.
*/
{
char *str1;
char *pnt2;
symbolS * sp1;
if(*pnt == 'p'){
for(sp1 = sp->sy_next; sp1; sp1 = sp1->sy_next) {
if ((sp1->sy_nlist.n_type & N_STAB) == 0) continue;
if((unsigned char)sp1->sy_nlist.n_type == N_FUN) break;
if((unsigned char)sp1->sy_nlist.n_type != N_RSYM) continue;
str1=sp1->sy_nlist.n_un.n_name; /* and get the name */
pnt2=str;
while(*pnt2 != ':') {
if(*pnt2 != *str1) break;
pnt2++; str1++;};
if((*str1 != ':') || (*pnt2 != ':') ) continue;
return; /* they are the same! lets skip this one */
}; /* for */
/* first find the dbx symbol type from list, and then find VMS type */
pnt++; /* skip p in case no register */
};/* if */ }; /* p block */
pnt = cvt_integer( pnt, &dbx_type);
spnt = find_symbol(dbx_type);
if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/
*pnt1='\0';
VMS_DBG_record(spnt,-1,sp->sy_nlist.n_value,str);
*pnt1=':'; /* and restore the string */
return 1;
}

/* this routine parses a stabs entry to find the information required to define
* a variable. It is used for global and static variables.
* Basically we need to know the address of the symbol. With older versions
* of the compiler, const symbols are
* treated differently, in that if they are global they are written into the
* text psect. The global symbol entry for such a const is actually written
* as a program entry point (Yuk!!), so if we cannot find a symbol in the list
* of psects, we must search the entry points as well. static consts are even
* harder, since they are never assigned a memory address. The compiler passes
* a stab to tell us the value, but I am not sure what to do with it.
*/
static gave_compiler_message = 0;

static int VMS_stab_parse(symbolS * sp,char expected_type,
int type1,int type2,int Text_Psect){
char *pnt;
char *pnt1;
char *str;
symbolS * sp1;
struct VMS_DBG_Symbol* spnt;
struct VMS_Symbol * vsp;
int dbx_type;
int VMS_type;
dbx_type=0;
str=sp->sy_nlist.n_un.n_name;
pnt=(char*) strchr(str,':');
if(pnt==(char*) NULL) return; /* no colon present */
pnt1=pnt; /* save this for later*/
pnt++;
if(*pnt==expected_type){
pnt = cvt_integer(pnt+1,&dbx_type);
spnt = find_symbol(dbx_type);
if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/
/* now we need to search the symbol table to find the psect and offset for
* this variable.
*/
*pnt1='\0';
vsp=VMS_Symbols;
while(vsp != (struct VMS_Symbol*) NULL)
{pnt=vsp->Symbol->sy_nlist.n_un.n_name;
if(pnt!=(char*) NULL) if(*pnt++ == '_')
/* make sure name is the same, and make sure correct symbol type */
if((strlen(pnt) == strlen(str)) && (strcmp(pnt,str)==0)
&& ((vsp->Symbol->sy_type == type1) ||
(vsp->Symbol->sy_type == type2))) break;
vsp=vsp->Next;};
if(vsp != (struct VMS_Symbol*) NULL){
VMS_DBG_record(spnt,vsp->Psect_Index,vsp->Psect_Offset,str);
*pnt1=':'; /* and restore the string */
return 1;};
/* the symbol was not in the symbol list, but it may be an "entry point"
if it was a constant */
for(sp1 = symbol_rootP; sp1; sp1 = sp1->sy_next) {
/*
* Dispatch on STAB type
*/
if(sp1->sy_type != (N_TEXT | N_EXT) && sp1->sy_type!=N_TEXT)
continue;
pnt = sp1->sy_nlist.n_un.n_name;
if(*pnt == '_') pnt++;
if(strcmp(pnt,str) == 0){
if(!gave_compiler_message && expected_type=='G'){
printf("***Warning - the assembly code generated by the compiler has placed\n");
printf("global constant(s) in the text psect. These will not be available to\n");
printf("other modules, since this is not the correct way to handle this. You\n");
printf("have two options: 1) get a patched compiler that does not put global\n");
printf("constants in the text psect, or 2) remove the 'const' keyword from\n");
printf("definitions of global variables in your source module(s). Don't say\n");
printf("I didn't warn you!");
gave_compiler_message = 1;};
VMS_DBG_record(spnt,
Text_Psect,
sp1->sy_nlist.n_value,
str);
*pnt1=':';
*(sp1->sy_nlist.n_un.n_name) = 'L';
/* fool assembler to not output this
* as a routine in the TBT */
return 1;};
};
};
*pnt1=':'; /* and restore the string */
return 0;
}


VMS_GSYM_Parse(symbolS * sp,int Text_Psect){ /* Global variables */
VMS_stab_parse(sp,'G',(N_UNDF | N_EXT),(N_DATA | N_EXT),Text_Psect);
}


VMS_LCSYM_Parse(symbolS * sp,int Text_Psect){/* Static symbols - uninitialized */
VMS_stab_parse(sp,'S',N_BSS,-1,Text_Psect);
}

VMS_STSYM_Parse(symbolS * sp,int Text_Psect){ /*Static symbols - initialized */
VMS_stab_parse(sp,'S',N_DATA,-1,Text_Psect);
}


/* for register symbols, we must figure out what range of addresses within the
* psect are valid. We will use the brackets in the stab directives to give us
* guidance as to the PC range that this variable is in scope. I am still not
* completely comfortable with this but as I learn more, I seem to get a better
* handle on what is going on.
* Caveat Emptor.
*/
VMS_RSYM_Parse(symbolS * sp,symbolS * Current_Routine,int Text_Psect){
char* pnt;
char* pnt1;
char* str;
int dbx_type;
struct VMS_DBG_Symbol* spnt;
int j;
int maxlen;
int i=0;
int bcnt=0;
int Min_Offset=-1; /* min PC of validity */
int Max_Offset=0; /* max PC of validity */
symbolS * symbolP;
for(symbolP = sp; symbolP; symbolP = symbolP->sy_next) {
/*
* Dispatch on STAB type
*/
switch((unsigned char)symbolP->sy_type) {
case N_LBRAC:
if(bcnt++==0) Min_Offset = symbolP->sy_nlist.n_value;
break;
case N_RBRAC:
if(--bcnt==0) Max_Offset =
symbolP->sy_nlist.n_value-1;
break;
}
if((Min_Offset != -1) && (bcnt == 0)) break;
if((unsigned char)symbolP->sy_type == N_FUN) break;
}
/* check to see that the addresses were defined. If not, then there were no
* brackets in the function, and we must try to search for the next function
* Since functions can be in any order, we should search all of the symbol list
* to find the correct ending address. */
if(Min_Offset == -1){
int Max_Source_Offset;
int This_Offset;
Min_Offset = sp->sy_nlist.n_value;
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
/*
* Dispatch on STAB type
*/
This_Offset = symbolP->sy_nlist.n_value;
switch(symbolP->sy_type) {
case N_TEXT | N_EXT:
if((This_Offset > Min_Offset) && (This_Offset < Max_Offset))
Max_Offset = This_Offset;
break;
case N_SLINE:
if(This_Offset > Max_Source_Offset)
Max_Source_Offset=This_Offset;
}
}
/* if this is the last routine, then we use the PC of the last source line
* as a marker of the max PC for which this reg is valid */
if(Max_Offset == 0x7fffffff) Max_Offset = Max_Source_Offset;
};
dbx_type=0;
str=sp->sy_nlist.n_un.n_name;
pnt=(char*) strchr(str,':');
if(pnt==(char*) NULL) return; /* no colon present */
pnt1=pnt; /* save this for later*/
pnt++;
if(*pnt!='r') return 0;
pnt = cvt_integer( pnt+1, &dbx_type);
spnt = find_symbol(dbx_type);
if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is yet*/
*pnt1='\0';
maxlen=25+strlen(sp->sy_nlist.n_un.n_name);
Local[i++]=maxlen;
Local[i++]=spnt->VMS_type;
Local[i++]=0xfb;
Local[i++]=strlen(sp->sy_nlist.n_un.n_name)+1;
Local[i++]=0x00;
Local[i++]=0x00;
Local[i++]=0x00;
Local[i++]=strlen(sp->sy_nlist.n_un.n_name);
pnt=sp->sy_nlist.n_un.n_name;
fix_name(pnt); /* if there are bad characters in name, convert them */
while(*pnt!='\0') Local[i++]=*pnt++;
Local[i++]=0xfd;
Local[i++]=0x0f;
Local[i++]=0x00;
Local[i++]=0x03;
Local[i++]=0x01;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
VMS_Set_Data(Text_Psect,Min_Offset,OBJ$C_DBG,1);
VMS_Set_Data(Text_Psect,Max_Offset,OBJ$C_DBG,1);
Local[i++]=0x03;
Local[i++]=sp->sy_nlist.n_value;
Local[i++]=0x00;
Local[i++]=0x00;
Local[i++]=0x00;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG);
*pnt1=':';
if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0);
}

/* this function examines a structure definition, checking all of the elements
* to make sure that all of them are fully defined. The only thing that we
* kick out are arrays of undefined structs, since we do not know how big
* they are. All others we can handle with a normal forward reference.
*/
static int forward_reference(char* pnt){
int i;
struct VMS_DBG_Symbol * spnt;
struct VMS_DBG_Symbol * spnt1;
pnt = cvt_integer(pnt+1,&i);
if(*pnt == ';') return 0; /* no forward references */
do{
pnt=(char*) strchr(pnt,':');
pnt = cvt_integer(pnt+1,&i);
spnt = find_symbol(i);
if(spnt == (struct VMS_DBG_Symbol*) NULL) return 0;
while((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)){
i=spnt->type2;
spnt1 = find_symbol(spnt->type2);
if((spnt->advanced == ARRAY) &&
(spnt1 == (struct VMS_DBG_Symbol*) NULL))return 1;
if(spnt1 == (struct VMS_DBG_Symbol*) NULL) break;
spnt=spnt1;
};
pnt = cvt_integer(pnt+1,&i);
pnt = cvt_integer(pnt+1,&i);
}while(*++pnt != ';');
return 0; /* no forward refences found */
}

/* This routine parses the stabs directives to find any definitions of dbx type
* numbers. It makes a note of all of them, creating a structure element
* of VMS_DBG_Symbol that describes it. This also generates the info for the
* debugger that describes the struct/union/enum, so that further references
* to these data types will be by number
* We have to process pointers right away, since there can be references
* to them later in the same stabs directive. We cannot have forward
* references to pointers, (but we can have a forward reference to a pointer to
* a structure/enum/union) and this is why we process them immediately.
* After we process the pointer, then we search for defs that are nested even
* deeper.
*/
static int VMS_typedef_parse(char* str){
char* pnt;
char* pnt1;
char* pnt2;
int i;
int dtype;
struct forward_ref * fpnt;
int i1,i2,i3;
int convert_integer;
struct VMS_DBG_Symbol* spnt;
struct VMS_DBG_Symbol* spnt1;
/* check for any nested def's */
pnt=(char*)strchr(str+1,'=');
if((pnt != (char*) NULL) && (*(str+1) != '*'))
if(VMS_typedef_parse(pnt) == 1 ) return 1;
/* now find dbx_type of entry */
pnt=str-1;
if(*pnt == 'c'){ /* check for static constants */
*str = '\0'; /* for now we ignore them */
return 0;};
while((*pnt <= '9')&& (*pnt >= '0')) pnt--;
pnt++; /* and get back to the number */
cvt_integer(pnt,&i1);
spnt = find_symbol(i1);
/* first we see if this has been defined already, due to a forward reference*/
if(spnt == (struct VMS_DBG_Symbol*) NULL) {
if(VMS_Symbol_type_list==(struct VMS_DBG_Symbol*) NULL)
{spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol));
spnt->next = (struct VMS_DBG_Symbol*) NULL;
VMS_Symbol_type_list=spnt;}
else
{spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol));
spnt->next=VMS_Symbol_type_list;
VMS_Symbol_type_list = spnt;};
spnt->dbx_type = i1; /* and save the type */
};
/* for structs and unions, do a partial parse, otherwise we sometimes get
* circular definitions that are impossible to resolve. We read enough info
* so that any reference to this type has enough info to be resolved
*/
pnt=str + 1; /* point to character past equal sign */
if((*pnt == 'u') || (*pnt == 's')){
};
if((*pnt <= '9') && (*pnt >= '0')){
if(type_check("void")){ /* this is the void symbol */
*str='\0';
spnt->advanced = VOID;
return 0;};
printf("gcc-as warning(debugger output):");
printf(" %d is an unknown untyped variable.\n",spnt->dbx_type);
return 1; /* do not know what this is */
};
/* now define this module*/
pnt=str + 1; /* point to character past equal sign */
switch (*pnt){
case 'r':
spnt->advanced= BASIC;
if(type_check("int")) {
spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;}
else if(type_check("long int")) {
spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;}
else if(type_check("unsigned int")) {
spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;}
else if(type_check("long unsigned int")) {
spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;}
else if(type_check("short int")) {
spnt->VMS_type=DBG$C_SSINT; spnt->data_size = 2;}
else if(type_check("short unsigned int")) {
spnt->VMS_type=DBG$C_USINT; spnt->data_size = 2;}
else if(type_check("char")) {
spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;}
else if(type_check("signed char")) {
spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;}
else if(type_check("unsigned char")) {
spnt->VMS_type=DBG$C_UCHAR; spnt->data_size = 1;}
else if(type_check("float")) {
spnt->VMS_type=DBG$C_REAL4; spnt->data_size = 4;}
else if(type_check("double")) {
spnt->VMS_type=DBG$C_REAL8; spnt->data_size = 8;}
pnt1=(char*) strchr(str,';')+1;
break;
case 's':
case 'u':
if(*pnt == 's') spnt->advanced= STRUCT;
else spnt->advanced= UNION;
spnt->VMS_type = DBG$C_ADVANCED_TYPE;
pnt1 = cvt_integer(pnt+1,&spnt->data_size);
if(forward_reference(pnt)) {
spnt->struc_numb = -1;
return 1;
}
spnt->struc_numb = ++structure_count;
pnt1--;
pnt=get_struct_name(str);
VMS_Def_Struct(spnt->struc_numb);
fpnt = f_ref_root;
while(fpnt != (struct forward_ref*) NULL){
if(fpnt->dbx_type == spnt->dbx_type) {
fpnt->resolved = 'Y';
VMS_Set_Struct(fpnt->struc_numb);
VMS_Store_Struct(spnt->struc_numb);};
fpnt = fpnt->next;};
VMS_Set_Struct(spnt->struc_numb);
i=0;
Local[i++] = 11+strlen(pnt);
Local[i++] = DBG$C_STRUCT_START;
Local[i++] = 0x80;
for(i1=0;i1<4;i1++) Local[i++] = 0x00;
Local[i++] = strlen(pnt);
pnt2=pnt;
while(*pnt2 != '\0') Local[i++] = *pnt2++;
i2=spnt->data_size * 8; /* number of bits */
pnt2=(char*) &i2;
for(i1=0;i1<4;i1++) Local[i++] = *pnt2++;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
if(pnt != symbol_name) {
pnt += strlen(pnt);
*pnt=':';}; /* replace colon for later */
while(*++pnt1 != ';'){
pnt=(char*) strchr(pnt1,':');
*pnt='\0';
pnt2=pnt1;
pnt1 = cvt_integer(pnt+1,&dtype);
pnt1 = cvt_integer(pnt1+1,&i2);
pnt1 = cvt_integer(pnt1+1,&i3);
if((dtype == 1) && (i3 != 32)) { /* bitfield */
Apoint = 0;
push(19+strlen(pnt2),1);
push(0xfa22,2);
push(1+strlen(pnt2),4);
push(strlen(pnt2),1);
while(*pnt2 != '\0') push(*pnt2++,1);
push(i3,2); /* size of bitfield */
push(0x0d22,2);
push(0x00,4);
push(i2,4); /* start position */
VMS_Store_Immediate_Data(Asuffix,Apoint,OBJ$C_DBG);
Apoint=0;
}else{
Local[i++] = 7+strlen(pnt2);
spnt1 = find_symbol(dtype);
/* check if this is a forward reference */
if(spnt1 != (struct VMS_DBG_Symbol*) NULL)
Local[i++] = spnt1->VMS_type;
else
Local[i++] = DBG$C_ADVANCED_TYPE;
Local[i++] = DBG$C_STRUCT_ITEM;
pnt=(char*) &i2;
for(i1=0;i1<4;i1++) Local[i++] = *pnt++;
Local[i++] = strlen(pnt2);
while(*pnt2 != '\0') Local[i++] = *pnt2++;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
if(spnt1 == (struct VMS_DBG_Symbol*) NULL)
generate_suffix(spnt1,dtype);
else if(spnt1->VMS_type == DBG$C_ADVANCED_TYPE)
generate_suffix(spnt1,0);
};
};
pnt1++;
Local[i++] = 0x01; /* length byte */
Local[i++] = DBG$C_STRUCT_END;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
break;
case 'e':
spnt->advanced= ENUM;
spnt->VMS_type = DBG$C_ADVANCED_TYPE;
spnt->struc_numb = ++structure_count;
spnt->data_size=4;
VMS_Def_Struct(spnt->struc_numb);
fpnt = f_ref_root;
while(fpnt != (struct forward_ref*) NULL){
if(fpnt->dbx_type == spnt->dbx_type) {
fpnt->resolved = 'Y';
VMS_Set_Struct(fpnt->struc_numb);
VMS_Store_Struct(spnt->struc_numb);};
fpnt = fpnt->next;};
VMS_Set_Struct(spnt->struc_numb);
i=0;
Local[i++] = 3+strlen(symbol_name);
Local[i++] = DBG$C_ENUM_START;
Local[i++] = 0x20;
Local[i++] = strlen(symbol_name);
pnt2=symbol_name;
while(*pnt2 != '\0') Local[i++] = *pnt2++;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
while(*++pnt != ';') {
pnt1=(char*) strchr(pnt,':');
*pnt1++='\0';
pnt1 = cvt_integer(pnt1,&i1);
Local[i++] = 7+strlen(pnt);
Local[i++] = DBG$C_ENUM_ITEM;
Local[i++] = 0x00;
pnt2=(char*) &i1;
for(i2=0;i2<4;i2++) Local[i++] = *pnt2++;
Local[i++] = strlen(pnt);
pnt2=pnt;
while(*pnt != '\0') Local[i++] = *pnt++;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
pnt= pnt1; /* Skip final semicolon */
};
Local[i++] = 0x01; /* len byte */
Local[i++] = DBG$C_ENUM_END;
VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
pnt1=pnt + 1;
break;
case 'a':
spnt->advanced= ARRAY;
spnt->VMS_type = DBG$C_ADVANCED_TYPE;
pnt=(char*)strchr(pnt,';'); if (pnt == (char*) NULL) return 1;
pnt1 = cvt_integer(pnt+1,&spnt->index_min);
pnt1 = cvt_integer(pnt1+1,&spnt->index_max);
pnt1 = cvt_integer(pnt1+1,&spnt->type2);
break;
case 'f':
spnt->advanced= FUNCTION;
spnt->VMS_type = DBG$C_FUNCTION_ADDR;
/* this masquerades as a basic type*/
spnt->data_size=4;
pnt1 = cvt_integer(pnt+1,&spnt->type2);
break;
case '*':
spnt->advanced= POINTER;
spnt->VMS_type = DBG$C_ADVANCED_TYPE;
spnt->data_size=4;
pnt1 = cvt_integer(pnt+1,&spnt->type2);
pnt=(char*)strchr(str+1,'=');
if((pnt != (char*) NULL))
if(VMS_typedef_parse(pnt) == 1 ) return 1;
break;
default:
spnt->advanced= UNKNOWN;
spnt->VMS_type = 0;
printf("gcc-as warning(debugger output):");
printf(" %d is an unknown type of variable.\n",spnt->dbx_type);
return 1; /* unable to decipher */
};
/* this removes the evidence of the definition so that the outer levels of
parsing do not have to worry about it */
pnt=str;
while (*pnt1 != '\0') *pnt++ = *pnt1++;
*pnt = '\0';
return 0;
}


/*
* This is the root routine that parses the stabs entries for definitions.
* it calls VMS_typedef_parse, which can in turn call itself.
* We need to be careful, since sometimes there are forward references to
* other symbol types, and these cannot be resolved until we have completed
* the parse.
*/
int VMS_LSYM_Parse(){
char *pnt;
char *pnt1;
char *pnt2;
char *str;
char fixit[10];
int incomplete,i,pass,incom1;
struct VMS_DBG_Symbol* spnt;
struct VMS_Symbol * vsp;
struct forward_ref * fpnt;
symbolS * sp;
pass=0;
incomplete = 0;
do{
incom1=incomplete;
incomplete = 0;
for(sp = symbol_rootP; sp; sp = sp->sy_next) {
/*
* Deal with STAB symbols
*/
if ((sp->sy_nlist.n_type & N_STAB) != 0) {
/*
* Dispatch on STAB type
*/
switch((unsigned char)sp->sy_nlist.n_type) {
case N_GSYM:
case N_LCSYM:
case N_STSYM:
case N_PSYM:
case N_RSYM:
case N_LSYM:
case N_FUN: /*sometimes these contain typedefs*/
str=sp->sy_nlist.n_un.n_name;
symbol_name = str;
pnt=(char*)strchr(str,':');
if(pnt== (char*) NULL) break;
*pnt='\0';
pnt1=pnt+1;
pnt2=(char*)strchr(pnt1,'=');
if(pnt2 == (char*) NULL){
*pnt=':'; /* replace colon */
break;}; /* no symbol here */
incomplete += VMS_typedef_parse(pnt2);
*pnt=':'; /* put back colon so variable def code finds dbx_type*/
break;
} /*switch*/
} /* if */
} /*for*/
pass++;
} while((incomplete != 0) && (incomplete != incom1 ));
/* repeat until all refs resolved if possible */
/* if(pass > 1) printf(" Required %d passes\n",pass);*/
if(incomplete != 0){
printf("gcc-as warning(debugger output):");
printf("Unable to resolve %d circular references.\n",incomplete);
};
fpnt = f_ref_root;
symbol_name="\0";
while(fpnt != (struct forward_ref*) NULL){
if(fpnt->resolved != 'Y') {
if( find_symbol(fpnt->dbx_type) !=
(struct VMS_DBG_Symbol*) NULL){
printf("gcc-as warning(debugger output):");
printf("Forward reference error, dbx type %d\n",
fpnt->dbx_type);
break;};
fixit[0]=0;
sprintf(&fixit[1],"%d=s4;",fpnt->dbx_type);
pnt2=(char*)strchr(&fixit[1],'=');
VMS_typedef_parse(pnt2);
};
fpnt = fpnt->next;};
}

static symbolS* Current_Routine;
static int Text_Psect;

static Define_Local_Symbols(symbolS* s1,symbolS* s2){
symbolS * symbolP1;
for(symbolP1 = s1->sy_next; symbolP1 != s2; symbolP1 = symbolP1->sy_next) {
if (symbolP1 == (symbolS *)NULL) return;
if (symbolP1->sy_nlist.n_type == N_FUN) return;
/*
* Deal with STAB symbols
*/
if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) {
/*
* Dispatch on STAB type
*/
switch((unsigned char)symbolP1->sy_nlist.n_type) {
case N_LSYM:
case N_PSYM:
VMS_local_stab_Parse(symbolP1);
break;
case N_RSYM:
VMS_RSYM_Parse(symbolP1,Current_Routine,Text_Psect);
break;
} /*switch*/
} /* if */
} /* for */
}

static symbolS* Define_Routine(symbolS* symbolP,int Level){
symbolS * sstart;
symbolS * symbolP1;
char str[10];
char * pnt;
int rcount = 0;
int Offset;
sstart = symbolP;
for(symbolP1 = symbolP->sy_next; symbolP1; symbolP1 = symbolP1->sy_next) {
if (symbolP1->sy_nlist.n_type == N_FUN) break;
/*
* Deal with STAB symbols
*/
if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) {
/*
* Dispatch on STAB type
*/
if((unsigned char)symbolP1->sy_nlist.n_type == N_FUN) break;
switch((unsigned char)symbolP1->sy_nlist.n_type) {
case N_LBRAC:
if(Level != 0) {
pnt = str +sprintf(str,"$%d",rcount++);
*pnt = '\0';
VMS_TBT_Block_Begin(symbolP1,Text_Psect,str);
};
Offset = symbolP1->sy_nlist.n_value;
Define_Local_Symbols(sstart,symbolP1);
symbolP1 =
Define_Routine(symbolP1,Level+1);
if(Level != 0)
VMS_TBT_Block_End(symbolP1->sy_nlist.n_value -
Offset);
sstart=symbolP1;
break;
case N_RBRAC:
return symbolP1;
} /*switch*/
} /* if */
} /* for */
/* we end up here if there were no brackets in this function. Define
everything */
Define_Local_Symbols(sstart,(symbolS *) 0);
}

VMS_DBG_Define_Routine(symbolS* symbolP,symbolS* Curr_Routine,int Txt_Psect){
Current_Routine = Curr_Routine;
Text_Psect = Txt_Psect;
Define_Routine(symbolP,0);
}
gas-1.38/README-vms-dbg 666 11660 0 16076 4662032003 11620 0ustar hack 1) You should be aware that GNU-C, as with any other decent compiler,
will do things when optimization is turned on that you may not expect.
Sometimes intermediate results are not written to variables, if they are only
used in one place, and sometimes variables that are not used at all will not be
written to the symbol table. Also, parameters to inline functions are often
inaccessible. You can see the assembly code equivalent by using KP7 in the
debugger, and from this you can tell if in fact a variable should have the
value that you expect. You can find out if a variable lives withing a register
by doing a 'show symbol/addr'.

2) Overly complex data types, such as:

int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5];

will not be debugged properly, since the debugging record overflows an internal
debugger buffer. gcc-as will convert these to *void as far as the debugger
symbol table is concerned, which will avoid any problems, and the assembler
will give you a message informing you that this has happened.

3) You must, of course, compile and link with /debug. If you link
without debug, you still get traceback table in the executable, but there is no
symbol table for variables.

4) Included in the patches to VMS.C are fixes to two bugs that are
unrelated to the changes that I have made. One of these made it impossible to
debug small programs sometimes, and the other caused the debugger to become
confused about which routine it was in, and give this incorrect info in
tracebacks.

5) If you are using the GNU-C++ compiler, you should modify the
compiler driver file GNU_CC:[000000]GCC.COM (or GXX.COM). If you have a
seperate GXX.COM, then you need to change one line in GXX.COM to:
$ if f$locate("D",p2) .ne. P2_Length then Debug = " ""-G0"""
Notice zero---> ^
If you are using a GCC.COM that does both C and C++, add the following lines to
GCC.COM:

$!
$! Use old style debugging records for VMS
$!
$ if (Debug.nes."" ).and. Plus then Debug = " ""-G0"""

after the variables Plus and Debug are set. The reason for this, is that C++
compiler by default generates debugging records that are more complex,
with many new syntactical elements that allow for the new features of the
language. The -G0 switch tells the C++ compiler to use the old style debugging
records. Until the debugger understands C++ there is not any point to try and
use the expanded syntax.

6) When you have nested scopes, i.e.:
main(){
int i;
{int i;
{int i;
};};}
and you say "EXAM i" the debugger needs to figure out which variable you
actually want to reference. I have arranged things to define a block to the
debugger when you use brackets to enter a new scope, so in the example above,
the variables would be described as:
TEST\main\i
TEST\main\$0\i
TEST\main\$0\$0\i
At each level, the block name is a number with a dollar sign prefix, the
numbers start with 0 and count upward. When you say EXAM i, the debugger looks
at the current PC, and decides which block it is currently in. It works from
the innermost level outward until it finds a block that has the variable "i"
defined. You can always specify the scope explicitly.

7) With C++, there can be a lot of inline functions, and it would be
rather restrictive to force the user to debug the program by converting all of
the inline functions to normal functions. What I have done is to essentially
"add" (with the debugger) source lines from the include files that contain the
inline functions. Thus when you step into an inline function it appears as if
you have called the function, and you can examine variables and so forth.
There are several *very* important differences, however. First of all, since
there is no function call involved, you cannot step over the inline function
call - you always step into it. Secondly, since the same source lines are used
in many locations, there is a seperate copy of the source for *each* usage.
Without this, breakpoints do not work, since we must have a 1-to-1 mapping
between source lines and PC.
Since you cannot step over inline function calls, it can be a real pain
if you are not really interested in what is going on for that function call.
What I have done is to use the "-D" switch for the assembler to toggle the
following behavior. With the "-D" switch, all inline functions are included in
the object file, and you can debug everything. Without the "-D" switch
(default case with VMS implementation), inline functions are included *only* if
they did not come from system header files (i.e. from GNU_CC_INCLUDE: or
GNU_GXX_INCLUDE:). Thus, without the switch the user only debugs his/her own
inline functions, and not the system ones. (This is especially useful if you do
a lot of stream I/O in C++). This probably will not provide enough granularity
for many users, but for now this is still somewhat experimental, and I would
like to reflect upon it and get some feedback before I go any further.
Possible solutions include an interactive prompting, a logical name, or a new
command line option in gcc.c (which is then passed through somehow to the guts
of the assembler).
The inline functions from header files appear after the source code
for the source file. This has the advantage that the source file itself is
numbered with the same line numbers that you get with an editor. In addition,
the entire header file is not included, since the assembler makes a list of
the min and max source lines that are used, and only includes those lines from
the first to the last actually used. (It is easy to change it to include the
whole file).

8) When you are debugging C++ objects, the object "this" is refered to
as "$this". Actually, the compiler writes it as ".this", but the period is
not good for the debugger, so I have a routine to convert it to a $. (It
actually converts all periods to $, but only for variables, since this was
intended to allow us to access "this".

9) If you use the asm("...") keyword for global symbols, you will not
be able to see that symbol with the debugger. The reason is that there are two
records for the symbol stored in the data structures of the assembler. One
contains the info such as psect number and offset, and the other one contains
the information having to do with the data type of the variable. In order to
debug as symbol, you need to be able to coorelate these records, and the only
way to do this is by name. The record with the storage attributes will take
the name used in the asm directive, and the record that specifies the data type
has the actual variable name, and thus when you use the asm directive to change
a variable name, the symbol becomes invisible.

10) Older versions of the compiler ( GNU-C 1.37.92 and earlier) place
global constants in the text psect. This is unfortunate, since to the linker
this appears to be an entry point. I sent a patch to the compiler to RMS,
which will generate a .const section for these variables, and patched the
assembler to put these variables into a psect just like that for normal
variables, except that they are marked NOWRT. static constants are still
placed in the text psect, since there is no need for any external access.
gas-1.38/m68k.c 666 11660 0 235000 4727005770 10357 0ustar hack/* m68k.c All the m68020 specific stuff in one convenient, huge,
slow to compile, easy to find 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. */

#include

#include "m68k-opcode.h"
#include "as.h"
#include "obstack.h"
#include "frags.h"
#include "struc-symbol.h"
#include "flonum.h"
#include "expr.h"
#include "hash.h"
#include "md.h"
#include "m68k.h"

#ifdef M_SUN
/* This variable contains the value to write out at the beginning of
the a.out file. The 2<<16 means that this is a 68020 file instead
of an old-style 68000 file */

long omagic = 2<<16|OMAGIC; /* Magic byte for header file */
#else
long omagic = OMAGIC;
#endif


/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful */
const char comment_chars[] = "|";

/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
.line and .file directives will appear in the pre-processed output */
/* Note that input_file.c hand checks for '#' at the beginning of the
first line of the input file. This is because the compiler outputs
#NO_APP at the beginning of its output. */
/* Also note that '/*' will always start a comment */
const char line_comment_chars[] = "#";

/* Chars that can be used to separate mant from exp in floating point nums */
const char EXP_CHARS[] = "eE";

/* Chars that mean this number is a floating point constant */
/* As in 0f12.456 */
/* or 0d1.2345e12 */

const char FLT_CHARS[] = "rRsSfFdDxXeEpP";

/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
changed in read.c . Ideally it shouldn't have to know about it at all,
but nothing is ideal around here.
*/

void fix_new();
void install_operand();
void install_gen_operand();

/* Its an arbitrary name: This means I don't approve of it */
/* See flames below */
struct obstack robyn;

#define TAB(x,y) (((x)<<2)+(y))
#define TABTYPE(xy) ((xy) >> 2)
#define BYTE 0
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3

#define BRANCH 1
#define FBRANCH 2
#define PCREL 3
#define BCC68000 4
#define DBCC 5
#define PCLEA 6

/* BCC68000 is for patching in an extra jmp instruction for long offsets
on the 68000. The 68000 doesn't support long branches with branchs */

/* This table desribes how you change sizes for the various types of variable
size expressions. This version only supports two kinds. */

/* Note that calls to frag_var need to specify the maximum expansion needed */
/* This is currently 10 bytes for DBCC */

/* The fields are:
How far Forward this mode will reach:
How far Backward this mode will reach:
How many bytes this mode will add to the size of the frag
Which mode to go to if the offset won't fit in this one
*/
const relax_typeS
md_relax_table[] = {
{ 1, 1, 0, 0 }, /* First entries aren't used */
{ 1, 1, 0, 0 }, /* For no good reason except */
{ 1, 1, 0, 0 }, /* that the VAX doesn't either */
{ 1, 1, 0, 0 },

{ (127), (-128), 0, TAB(BRANCH,SHORT)},
{ (32767), (-32768), 2, TAB(BRANCH,LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },

{ 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */
{ (32767), (-32768), 2, TAB(FBRANCH,LONG)},
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },

{ 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */
{ (32767), (-32768), 2, TAB(PCREL,LONG)},
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },

{ (127), (-128), 0, TAB(BCC68000,SHORT)},
{ (32767), (-32768), 2, TAB(BCC68000,LONG) },
{ 0, 0, 6, 0 }, /* jmp long space */
{ 1, 1, 0, 0 },

{ 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */
{ (32767), (-32768), 2, TAB(DBCC,LONG) },
{ 0, 0, 10, 0 }, /* bra/jmp long space */
{ 1, 1, 0, 0 },

{ 1, 1, 0, 0 }, /* PCLEA doesn't come BYTE */
{ 32767, -32768, 2, TAB(PCLEA,LONG) },
{ 0, 0, 6, 0 },
{ 1, 1, 0, 0 },

};

void s_data1(), s_data2(), s_even(), s_space();
void s_proc(), float_cons();

/* These are the machine dependent pseudo-ops. These are included so
the assembler can work on the output from the SUN C compiler, which
generates these.
*/

/* This table describes all the machine specific pseudo-ops the assembler
has to support. The fields are:
pseudo-op name without dot
function to call to execute this pseudo-op
Integer arg to pass to the function
*/
const pseudo_typeS md_pseudo_table[] = {
{ "data1", s_data1, 0 },
{ "data2", s_data2, 0 },
{ "even", s_even, 0 },
{ "skip", s_space, 0 },
{ "proc", s_proc, 0 },
{ 0, 0, 0 }
};


/* #define isbyte(x) ((x)>=-128 && (x)<=127) */
/* #define isword(x) ((x)>=-32768 && (x)<=32767) */

#define issbyte(x) ((x)>=-128 && (x)<=127)
#define isubyte(x) ((x)>=0 && (x)<=255)
#define issword(x) ((x)>=-32768 && (x)<=32767)
#define isuword(x) ((x)>=0 && (x)<=65535)

#define isbyte(x) ((x)>=-128 && (x)<=255)
#define isword(x) ((x)>=-32768 && (x)<=65535)
#define islong(x) (1)

extern char *input_line_pointer;

/* Operands we can parse: (And associated modes)

numb: 8 bit num
numw: 16 bit num
numl: 32 bit num
dreg: data reg 0-7
reg: address or data register
areg: address register
apc: address register, PC, ZPC or empty string
num: 16 or 32 bit num
num2: like num
sz: w or l if omitted, l assumed
scale: 1 2 4 or 8 if omitted, 1 assumed

7.4 IMMED #num --> NUM
0.? DREG dreg --> dreg
1.? AREG areg --> areg
2.? AINDR areg@ --> *(areg)
3.? AINC areg@+ --> *(areg++)
4.? ADEC areg@- --> *(--areg)
5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here
6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)
6.? AINDX apc@(reg:sz:scale) --> same, with num=0
6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)
6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0
6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)
6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)
6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
7.0 ABSL num:sz --> *(num)
num --> *(num) (sz L assumed)
*** MSCR otherreg --> Magic
With -l option
5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still

examples:
#foo #0x35 #12
d2
a4
a3@
a5@+
a6@-
a2@(12) pc@(14)
a1@(5,d2:w:1) @(45,d6:l:4)
pc@(a2) @(d4)
etc . . .


#name@(numw) -->turn into PC rel mode
apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)

*/

#define IMMED 1
#define DREG 2
#define AREG 3
#define AINDR 4
#define ADEC 5
#define AINC 6
#define AOFF 7
#define AINDX 8
#define APODX 9
#define AMIND 10
#define APRDX 11
#define ABSL 12
#define MSCR 13
#define REGLST 14

#define FAIL 0
#define OK 1

/* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg,
8-15==addr reg for operands that take both types */
#define DATA 1 /* 1- 8 == data registers 0-7 */
#define ADDR (DATA+8) /* 9-16 == address regs 0-7 */
#define FPREG (ADDR+8) /* 17-24 Eight FP registers */
#define COPNUM (FPREG+8) /* 25-32 Co-processor #1-#8 */

#define PC (COPNUM+8) /* 33 Program counter */
#define ZPC (PC+1) /* 34 Hack for Program space, but 0 addressing */
#define SR (ZPC+1) /* 35 Status Reg */
#define CCR (SR+1) /* 36 Condition code Reg */

/* These have to be in order for the movec instruction to work. */
#define USP (CCR+1) /* 37 User Stack Pointer */
#define ISP (USP+1) /* 38 Interrupt stack pointer */
#define SFC (ISP+1) /* 39 */
#define DFC (SFC+1) /* 40 */
#define CACR (DFC+1) /* 41 */
#define VBR (CACR+1) /* 42 */
#define CAAR (VBR+1) /* 43 */
#define MSP (CAAR+1) /* 44 */

#define FPI (MSP+1) /* 45 */
#define FPS (FPI+1) /* 46 */
#define FPC (FPS+1) /* 47 */
/*
* these defines should be in m68k.c but
* i put them here to keep all the m68851 stuff
* together -rab
* JF--Make sure these #s don't clash with the ones in m68k.c
* That would be BAD.
*/
#define TC (FPC+1) /* 48 */
#define DRP (TC+1) /* 49 */
#define SRP (DRP+1) /* 50 */
#define CRP (SRP+1) /* 51 */
#define CAL (CRP+1) /* 52 */
#define VAL (CAL+1) /* 53 */
#define SCC (VAL+1) /* 54 */
#define AC (SCC+1) /* 55 */
#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */
#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */
#define PSR (BAC+8) /* 72 */
#define PCSR (PSR+1) /* 73 */


/* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */
/* I think. . . */

#define SP ADDR+7

/* JF these tables here are for speed at the expense of size */
/* You can replace them with the #if 0 versions if you really
need space and don't mind it running a bit slower */

static char mklower_table[256];
#define mklower(c) (mklower_table[(unsigned char)(c)])
static char notend_table[256];
static char alt_notend_table[256];
#define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\
alt_notend_table[(unsigned char)(s[1])])))

#if 0
#define mklower(c) (isupper(c) ? tolower(c) : c)
#endif


struct m68k_exp {
char *e_beg;
char *e_end;
expressionS e_exp;
short e_siz; /* 0== default 1==short/byte 2==word 3==long */
};

/* Internal form of an operand. */
struct m68k_op {
char *error; /* Couldn't parse it */
int mode; /* What mode this instruction is in. */
unsigned long int reg; /* Base register */
struct m68k_exp *con1;
int ireg; /* Index register */
int isiz; /* 0==unspec 1==byte(?) 2==short 3==long */
int imul; /* Multipy ireg by this (1,2,4,or 8) */
struct m68k_exp *con2;
};

/* internal form of a 68020 instruction */
struct m68_it {
char *error;
char *args; /* list of opcode info */
int numargs;

int numo; /* Number of shorts in opcode */
short opcode[11];

struct m68k_op operands[6];

int nexp; /* number of exprs in use */
struct m68k_exp exprs[4];

int nfrag; /* Number of frags we have to produce */
struct {
int fragoff; /* Where in the current opcode[] the frag ends */
symbolS *fadd;
long int foff;
int fragty;
} fragb[4];

int nrel; /* Num of reloc strucs in use */
struct {
int n;
symbolS *add,
*sub;
long int off;
char wid;
char pcrel;
} reloc[5]; /* Five is enough??? */
};

struct m68_it the_ins; /* the instruction being assembled */


/* Macros for adding things to the m68_it struct */

#define addword(w) the_ins.opcode[the_ins.numo++]=(w)

/* Like addword, but goes BEFORE general operands */
#define insop(w) {int z;\
for(z=the_ins.numo;z>opcode->m_codenum;--z)\
the_ins.opcode[z]=the_ins.opcode[z-1];\
for(z=0;z the_ins.reloc[z].n+=2;\
the_ins.opcode[opcode->m_codenum]=w;\
the_ins.numo++;\
}


#define add_exp(beg,end) (\
the_ins.exprs[the_ins.nexp].e_beg=beg,\
the_ins.exprs[the_ins.nexp].e_end=end,\
&the_ins.exprs[the_ins.nexp++]\
)


/* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/
#define add_fix(width,exp,pc_rel) {\
the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
(((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\
the_ins.reloc[the_ins.nrel].add=adds((exp));\
the_ins.reloc[the_ins.nrel].sub=subs((exp));\
the_ins.reloc[the_ins.nrel].off=offs((exp));\
the_ins.reloc[the_ins.nrel].wid=width;\
the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\
}

#define add_frag(add,off,type) {\
the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
the_ins.fragb[the_ins.nfrag].fadd=add;\
the_ins.fragb[the_ins.nfrag].foff=off;\
the_ins.fragb[the_ins.nfrag++].fragty=type;\
}

#define isvar(exp) ((exp) && (adds(exp) || subs(exp)))

#define seg(exp) ((exp)->e_exp.X_seg)
#define adds(exp) ((exp)->e_exp.X_add_symbol)
#define subs(exp) ((exp)->e_exp.X_subtract_symbol)
#define offs(exp) ((exp)->e_exp.X_add_number)


struct m68_incant {
char *m_operands;
unsigned long m_opcode;
short m_opnum;
short m_codenum;
struct m68_incant *m_next;
};

#define getone(x) ((((x)->m_opcode)>>16)&0xffff)
#define gettwo(x) (((x)->m_opcode)&0xffff)


/* JF modified this to handle cases where the first part of a symbol name
looks like a register */

int
m68k_reg_parse(ccp)
register char **ccp;
{
register char c1,
c2,
c3,
c4;
register int n = 0,
ret = FAIL;

c1=mklower(ccp[0][0]);
#ifdef REGISTER_PREFIX
if(c1!=REGISTER_PREFIX)
return FAIL;
c1=mklower(ccp[0][1]);
c2=mklower(ccp[0][2]);
c3=mklower(ccp[0][3]);
c4=mklower(ccp[0][4]);
#else
c2=mklower(ccp[0][1]);
c3=mklower(ccp[0][2]);
c4=mklower(ccp[0][3]);
#endif
switch(c1) {
case 'a':
if(c2>='0' && c2<='7') {
n=2;
ret=ADDR+c2-'0';
}
#ifdef m68851
else if (c2 == 'c') {
n = 2;
ret = AC;
}
#endif
break;
#ifdef m68851
case 'b':
if (c2 == 'a') {
if (c3 == 'd') {
if (c4 >= '0' && c4 <= '7') {
n = 4;
ret = BAD + c4 - '0';
}
}
if (c3 == 'c') {
if (c4 >= '0' && c4 <= '7') {
n = 4;
ret = BAC + c4 - '0';
}
}
}
break;
#endif
case 'c':
#ifdef m68851
if (c2 == 'a' && c3 == 'l') {
n = 3;
ret = CAL;
} else
#endif
/* This supports both CCR and CC as the ccr reg. */
if(c2=='c' && c3=='r') {
n=3;
ret = CCR;
} else if(c2=='c') {
n=2;
ret = CCR;
} else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') {
n=4;
ret = c3=='a' ? CAAR : CACR;
}
#ifdef m68851
else if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (CRP);
}
#endif
break;
case 'd':
if(c2>='0' && c2<='7') {
n=2;
ret = DATA+c2-'0';
} else if(c2=='f' && c3=='c') {
n=3;
ret = DFC;
}
#ifdef m68851
else if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (DRP);
}
#endif
break;
case 'f':
if(c2=='p') {
if(c3>='0' && c3<='7') {
n=3;
ret = FPREG+c3-'0';
if(c4==':')
ccp[0][3]=',';
} else if(c3=='i') {
n=3;
ret = FPI;
} else if(c3=='s') {
n= (c4 == 'r' ? 4 : 3);
ret = FPS;
} else if(c3=='c') {
n= (c4 == 'r' ? 4 : 3);
ret = FPC;
}
}
break;
case 'i':
if(c2=='s' && c3=='p') {
n=3;
ret = ISP;
}
break;
case 'm':
if(c2=='s' && c3=='p') {
n=3;
ret = MSP;
}
break;
case 'p':
if(c2=='c') {
#ifdef m68851
if(c3 == 's' && c4=='r') {
n=4;
ret = (PCSR);
} else
#endif
{
n=2;
ret = PC;
}
}
#ifdef m68851
else if (c2 == 's' && c3 == 'r') {
n = 3;
ret = (PSR);
}
#endif
break;
case 's':
#ifdef m68851
if (c2 == 'c' && c3 == 'c') {
n = 3;
ret = (SCC);
} else if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (SRP);
} else
#endif
if(c2=='r') {
n=2;
ret = SR;
} else if(c2=='p') {
n=2;
ret = ADDR+7;
} else if(c2=='f' && c3=='c') {
n=3;
ret = SFC;
}
break;
#ifdef m68851
case 't':
if(c2 == 'c') {
n=2;
ret=TC;
}
break;
#endif
case 'u':
if(c2=='s' && c3=='p') {
n=3;
ret = USP;
}
break;
case 'v':
#ifdef m68851
if (c2 == 'a' && c3 == 'l') {
n = 3;
ret = (VAL);
} else
#endif
if(c2=='b' && c3=='r') {
n=3;
ret = VBR;
}
break;
case 'z':
if(c2=='p' && c3=='c') {
n=3;
ret = ZPC;
}
break;
default:
break;
}
if(n) {
#ifdef REGISTER_PREFIX
n++;
#endif
if(isalnum(ccp[0][n]) || ccp[0][n]=='_')
ret=FAIL;
else
ccp[0]+=n;
} else
ret = FAIL;
return ret;
}

#define SKIP_WHITE() { str++; if(*str==' ') str++;}

int
m68k_ip_op(str,opP)
char *str;
register struct m68k_op *opP;
{
char *strend;
long i;
char *parse_index();

if(*str==' ')
str++;
/* Find the end of the string */
if(!*str) {
/* Out of gas */
opP->error="Missing operand";
return FAIL;
}
for(strend=str;*strend;strend++)
;
--strend;

/* Guess what: A constant. Shar and enjoy */
if(*str=='#') {
str++;
opP->con1=add_exp(str,strend);
opP->mode=IMMED;
return OK;
}
i=m68k_reg_parse(&str);
if((i==FAIL || *str!='\0') && *str!='@') {
char *stmp;
char *index();

if(i!=FAIL && (*str=='/' || *str=='-')) {
opP->mode=REGLST;
return get_regs(i,str,opP);
}
if(stmp=index(str,'@')) {
opP->con1=add_exp(str,stmp-1);
if(stmp==strend) {
opP->mode=AINDX;
return OK;
}
stmp++;
if(*stmp++!='(' || *strend--!=')') {
opP->error="Malformed operand";
return FAIL;
}
i=try_index(&stmp,opP);
opP->con2=add_exp(stmp,strend);
if(i==FAIL) opP->mode=AMIND;
else opP->mode=APODX;
return OK;
}
opP->mode=ABSL;
opP->con1=add_exp(str,strend);
return OK;
}
opP->reg=i;
if(*str=='\0') {
if(i>=DATA+0 && i<=DATA+7)
opP->mode=DREG;
else if(i>=ADDR+0 && i<=ADDR+7)
opP->mode=AREG;
else
opP->mode=MSCR;
return OK;
}
if((iADDR+7) && i!=PC && i!=ZPC && i!=FAIL) { /* Can't indirect off non address regs */
opP->error="Invalid indirect register";
return FAIL;
}
if(*str!='@')
abort();
str++;
switch(*str) {
case '\0':
opP->mode=AINDR;
return OK;
case '-':
opP->mode=ADEC;
return OK;
case '+':
opP->mode=AINC;
return OK;
case '(':
str++;
break;
default:
opP->error="Junk after indirect";
return FAIL;
}
/* Some kind of indexing involved. Lets find out how bad it is */
i=try_index(&str,opP);
/* Didn't start with an index reg, maybe its offset or offset,reg */
if(i==FAIL) {
char *beg_str;

beg_str=str;
for(i=1;i;) {
switch(*str++) {
case '\0':
opP->error="Missing )";
return FAIL;
case ',': i=0; break;
case '(': i++; break;
case ')': --i; break;
}
}
/* if(str[-3]==':') {
int siz;

switch(str[-2]) {
case 'b':
case 'B':
siz=1;
break;
case 'w':
case 'W':
siz=2;
break;
case 'l':
case 'L':
siz=3;
break;
default:
opP->error="Specified size isn't :w or :l";
return FAIL;
}
opP->con1=add_exp(beg_str,str-4);
opP->con1->e_siz=siz;
} else */
opP->con1=add_exp(beg_str,str-2);
/* Should be offset,reg */
if(str[-1]==',') {
i=try_index(&str,opP);
if(i==FAIL) {
opP->error="Malformed index reg";
return FAIL;
}
}
}
/* We've now got offset) offset,reg) or reg) */

if(*str=='\0') {
/* Th-the-thats all folks */
if(opP->reg==FAIL) opP->mode=AINDX; /* Other form of indirect */
else if(opP->ireg==FAIL) opP->mode=AOFF;
else opP->mode=AINDX;
return OK;
}
/* Next thing had better be another @ */
if(*str!='@' || str[1]!='(') {
opP->error="junk after indirect";
return FAIL;
}
str+=2;
if(opP->ireg!=FAIL) {
opP->mode=APRDX;
i=try_index(&str,opP);
if(i!=FAIL) {
opP->error="Two index registers! not allowed!";
return FAIL;
}
} else
i=try_index(&str,opP);
if(i==FAIL) {
char *beg_str;

beg_str=str;
for(i=1;i;) {
switch(*str++) {
case '\0':
opP->error="Missing )";
return FAIL;
case ',': i=0; break;
case '(': i++; break;
case ')': --i; break;
}
}
opP->con2=add_exp(beg_str,str-2);
if(str[-1]==',') {
if(opP->ireg!=FAIL) {
opP->error="Can't have two index regs";
return FAIL;
}
i=try_index(&str,opP);
if(i==FAIL) {
opP->error="malformed index reg";
return FAIL;
}
opP->mode=APODX;
} else if(opP->ireg!=FAIL)
opP->mode=APRDX;
else
opP->mode=AMIND;
} else
opP->mode=APODX;
if(*str!='\0') {
opP->error="Junk after indirect";
return FAIL;
}
return OK;
}

int
try_index(s,opP)
char **s;
struct m68k_op *opP;
{
register int i;
char *ss;
#define SKIP_W() { ss++; if(*ss==' ') ss++;}

ss= *s;
/* SKIP_W(); */
i=m68k_reg_parse(&ss);
if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
*s=ss;
return FAIL;
}
opP->ireg=i;
/* SKIP_W(); */
if(*ss==')') {
opP->isiz=0;
opP->imul=1;
SKIP_W();
*s=ss;
return OK;
}
if(*ss!=':') {
opP->error="Missing : in index register";
*s=ss;
return FAIL;
}
SKIP_W();
switch(*ss) {
case 'w':
case 'W':
opP->isiz=2;
break;
case 'l':
case 'L':
opP->isiz=3;
break;
default:
opP->error="Index register size spec not :w or :l";
*s=ss;
return FAIL;
}
SKIP_W();
if(*ss==':') {
SKIP_W();
switch(*ss) {
case '1':
case '2':
case '4':
case '8':
opP->imul= *ss-'0';
break;
default:
opP->error="index multiplier not 1, 2, 4 or 8";
*s=ss;
return FAIL;
}
SKIP_W();
} else opP->imul=1;
if(*ss!=')') {
opP->error="Missing )";
*s=ss;
return FAIL;
}
SKIP_W();
*s=ss;
return OK;
}

#ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */
main()
{
char buf[128];
struct m68k_op thark;

for(;;) {
if(!gets(buf))
break;
bzero(&thark,sizeof(thark));
if(!m68k_ip_op(buf,&thark)) printf("FAIL:");
if(thark.error)
printf("op1 error %s in %s\n",thark.error,buf);
printf("mode %d, reg %d, ",thark.mode,thark.reg);
if(thark.b_const)
printf("Constant: '%.*s',",1+thark.e_const-thark.b_const,thark.b_const);
printf("ireg %d, isiz %d, imul %d ",thark.ireg,thark.isiz,thark.imul);
if(thark.b_iadd)
printf("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd);
printf("\n");
}
exit(0);
}

#endif


static struct hash_control* op_hash = NULL; /* handle of the OPCODE hash table
NULL means any use before m68_ip_begin()
will crash */


/*
* m 6 8 _ i p ( )
*
* This converts a string into a 68k instruction.
* The string must be a bare single instruction in sun format
* with RMS-style 68020 indirects
* (example: )
*
* It provides some error messages: at most one fatal error message (which
* stops the scan) and at most one warning message for each operand.
* The 68k instruction is returned in exploded form, since we have no
* knowledge of how you parse (or evaluate) your expressions.
* We do however strip off and decode addressing modes and operation
* mnemonic.
*
* This function's value is a string. If it is not "" then an internal
* logic error was found: read this code to assign meaning to the string.
* No argument string should generate such an error string:
* it means a bug in our code, not in the user's text.
*
* You MUST have called m86_ip_begin() once and m86_ip_end() never before using
* this function.
*/

/* JF this function no longer returns a useful value. Sorry */
void
m68_ip (instring)
char *instring;
{
register char *p;
register struct m68k_op *opP;
register struct m68_incant *opcode;
register char *s;
register int tmpreg,
baseo,
outro,
nextword;
int siz1,
siz2;
char c;
int losing;
int opsfound;
char *crack_operand();
LITTLENUM_TYPE words[6];
LITTLENUM_TYPE *wordp;

if (*instring == ' ')
instring++; /* skip leading whitespace */

/* Scan up to end of operation-code, which MUST end in end-of-string
or exactly 1 space. */
for (p = instring; *p != '\0'; p++)
if (*p == ' ')
break;


if (p == instring) {
the_ins.error = "No operator";
the_ins.opcode[0] = NULL;
/* the_ins.numo=1; */
return;
}

/* p now points to the end of the opcode name, probably whitespace.
make sure the name is null terminated by clobbering the whitespace,
look it up in the hash table, then fix it back. */
c = *p;
*p = '\0';
opcode = (struct m68_incant *)hash_find (op_hash, instring);
*p = c;

if (opcode == NULL) {
the_ins.error = "Unknown operator";
the_ins.opcode[0] = NULL;
/* the_ins.numo=1; */
return;
}

/* found a legitimate opcode, start matching operands */
for(opP= &the_ins.operands[0];*p;opP++) {
p = crack_operand (p, opP);
if(opP->error) {
the_ins.error=opP->error;
return;
}
}

opsfound=opP- &the_ins.operands[0];
/* This ugly hack is to support the floating pt opcodes in their standard form */
/* Essentially, we fake a first enty of type COP#1 */
if(opcode->m_operands[0]=='I') {
int n;

for(n=opsfound;n>0;--n)
the_ins.operands[n]=the_ins.operands[n-1];

/* bcopy((char *)(&the_ins.operands[0]),(char *)(&the_ins.operands[1]),opsfound*sizeof(the_ins.operands[0])); */
bzero((char *)(&the_ins.operands[0]),sizeof(the_ins.operands[0]));
the_ins.operands[0].mode=MSCR;
the_ins.operands[0].reg=COPNUM; /* COP #1 */
opsfound++;
}
/* We've got the operands. Find an opcode that'll
accept them */
for(losing=0;;) {
if(opsfound!=opcode->m_opnum)
losing++;
else for(s=opcode->m_operands,opP= &the_ins.operands[0];*s && !losing;s+=2,opP++) {
/* Warning: this switch is huge! */
/* I've tried to organize the cases into this order:
non-alpha first, then alpha by letter. lower-case goes directly
before uppercase counterpart. */
/* Code with multiple case ...: gets sorted by the lowest case ...
it belongs to. I hope this makes sense. */
switch(*s) {
case '!':
if(opP->mode==MSCR || opP->mode==IMMED ||
opP->mode==DREG || opP->mode==AREG || opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
losing++;
break;

case '#':
if(opP->mode!=IMMED)
losing++;
else {
long t;

t=get_num(opP->con1,80);
if(s[1]=='b' && !isbyte(t))
losing++;
else if(s[1]=='w' && !isword(t))
losing++;
}
break;

case '^':
case 'T':
if(opP->mode!=IMMED)
losing++;
break;

case '$':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;

case '%':
if(opP->mode==MSCR || opP->reg==PC ||
opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;


case '&':
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
losing++;
break;

case '*':
if(opP->mode==MSCR || opP->mode==REGLST)
losing++;
break;

case '+':
if(opP->mode!=AINC)
losing++;
break;

case '-':
if(opP->mode!=ADEC)
losing++;
break;

case '/':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
losing++;
break;

case ';':
if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
losing++;
break;

case '?':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->reg==PC ||
opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;

case '@':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==IMMED || opP->mode==REGLST)
losing++;
break;

case '~': /* For now! (JF FOO is this right?) */
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;

case 'A':
if(opP->mode!=AREG)
losing++;
break;

case 'B': /* FOO */
if(opP->mode!=ABSL)
losing++;
break;

case 'C':
if(opP->mode!=MSCR || opP->reg!=CCR)
losing++;
break;

case 'd': /* FOO This mode is a KLUDGE!! */
if(opP->mode!=AOFF && (opP->mode!=ABSL ||
opP->con1->e_beg[0]!='(' || opP->con1->e_end[0]!=')'))
losing++;
break;

case 'D':
if(opP->mode!=DREG)
losing++;
break;

case 'F':
if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
losing++;
break;

case 'I':
if(opP->mode!=MSCR || opP->reg opP->reg>=COPNUM+7)
losing++;
break;

case 'J':
if(opP->mode!=MSCR || opP->regreg>MSP)
losing++;
break;

case 'k':
if(opP->mode!=IMMED)
losing++;
break;

case 'l':
case 'L':
if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
if(s[1]=='8')
losing++;
else {
opP->mode=REGLST;
opP->reg=1<<(opP->reg-DATA);
}
} else if(opP->mode!=REGLST) {
losing++;
} else if(s[1]=='8' && opP->reg&0x0FFffFF)
losing++;
else if(s[1]=='3' && opP->reg&0x7000000)
losing++;
break;

case 'M':
if(opP->mode!=IMMED)
losing++;
else {
long t;

t=get_num(opP->con1,80);
if(!issbyte(t) || isvar(opP->con1))
losing++;
}
break;

case 'O':
if(opP->mode!=DREG && opP->mode!=IMMED)
losing++;
break;

case 'Q':
if(opP->mode!=IMMED)
losing++;
else {
long t;

t=get_num(opP->con1,80);
if(t<1 || t>8 || isvar(opP->con1))
losing++;
}
break;

case 'R':
if(opP->mode!=DREG && opP->mode!=AREG)
losing++;
break;

case 's':
if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
losing++;
break;

case 'S':
if(opP->mode!=MSCR || opP->reg!=SR)
losing++;
break;

case 'U':
if(opP->mode!=MSCR || opP->reg!=USP)
losing++;
break;

/* JF these are out of order. We could put them
in order if we were willing to put up with
bunches of #ifdef m68851s in the code */
#ifdef m68851
/* Memory addressing mode used by pflushr */
case '|':
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==REGLST)
losing++;
break;

case 'f':
if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
losing++;
break;

case 'P':
if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
losing++;
break;

case 'V':
if (opP->reg != VAL)
losing++;
break;

case 'W':
if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
opP->reg != CRP))
losing++;
break;

case 'X':
if (opP->mode != MSCR ||
(!(opP->reg >= BAD && opP->reg <= BAD+7) &&
!(opP->reg >= BAC && opP->reg <= BAC+7)))
losing++;
break;

case 'Y':
if (opP->reg != PSR)
losing++;
break;

case 'Z':
if (opP->reg != PCSR)
losing++;
break;
#endif
default:
as_fatal("Internal error: Operand mode %c unknown",*s);
}
}
if(!losing)
break;
opcode=opcode->m_next;
if(!opcode) { /* Fell off the end */
the_ins.error="instruction/operands mismatch";
return;
}
losing=0;
}
the_ins.args=opcode->m_operands;
the_ins.numargs=opcode->m_opnum;
the_ins.numo=opcode->m_codenum;
the_ins.opcode[0]=getone(opcode);
the_ins.opcode[1]=gettwo(opcode);

for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) {
/* This switch is a doozy.
What the first step; its a big one! */
switch(s[0]) {

case '*':
case '~':
case '%':
case ';':
case '@':
case '!':
case '&':
case '$':
case '?':
case '/':
#ifdef m68851
case '|':
#endif
switch(opP->mode) {
case IMMED:
tmpreg=0x3c; /* 7.4 */
if(index("bwl",s[1])) nextword=get_num(opP->con1,80);
else nextword=nextword=get_num(opP->con1,0);
if(isvar(opP->con1))
add_fix(s[1],opP->con1,0);
switch(s[1]) {
case 'b':
if(!isbyte(nextword))
opP->error="operand out of range";
addword(nextword);
baseo=0;
break;
case 'w':
if(!isword(nextword))
opP->error="operand out of range";
addword(nextword);
baseo=0;
break;
case 'l':
addword(nextword>>16);
addword(nextword);
baseo=0;
break;

case 'f':
baseo=2;
outro=8;
break;
case 'F':
baseo=4;
outro=11;
break;
case 'x':
baseo=6;
outro=15;
break;
case 'p':
baseo=6;
outro= -1;
break;
default:
as_fatal("Internal error: Can't decode %c%c",*s,s[1]);
}
if(!baseo)
break;

/* We gotta put out some float */
if(seg(opP->con1)!=SEG_BIG) {
int_to_gen(nextword);
gen_to_words(words,baseo,(long int)outro);
for(wordp=words;baseo--;wordp++)
addword(*wordp);
break;
} /* Its BIG */
if(offs(opP->con1)>0) {
as_warn("Bignum assumed to be binary bit-pattern");
if(offs(opP->con1)>baseo) {
as_warn("Bignum too big for %c format; truncated",s[1]);
offs(opP->con1)=baseo;
}
baseo-=offs(opP->con1);
for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
addword(*wordp);
while(baseo--)
addword(0);
break;
}
gen_to_words(words,baseo,(long int)outro);
for(wordp=words;baseo--;wordp++)
addword(*wordp);
break;
case DREG:
tmpreg=opP->reg-DATA; /* 0.dreg */
break;
case AREG:
tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
break;
case AINDR:
tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
break;
case ADEC:
tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
break;
case AINC:
tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
break;
case AOFF:

nextword=get_num(opP->con1,80);
/* Force into index mode. Hope this works */

/* We do the first bit for 32-bit displacements,
and the second bit for 16 bit ones. It is
possible that we should make the default be
WORD instead of LONG, but I think that'd
break GCC, so we put up with a little
inefficiency for the sake of working output.
*/

if( !issword(nextword)
|| ( isvar(opP->con1)
&& ( ( opP->con1->e_siz==0
&& flagseen['l']==0)
|| opP->con1->e_siz==3))) {

if(opP->reg==PC)
tmpreg=0x3B; /* 7.3 */
else
tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
if(isvar(opP->con1)) {
if(opP->reg==PC) {
add_frag(adds(opP->con1),
offs(opP->con1),
TAB(PCLEA,SZ_UNDEF));
break;
} else {
addword(0x0170);
add_fix('l',opP->con1,1);
}
} else
addword(0x0170);
addword(nextword>>16);
} else {
if(opP->reg==PC)
tmpreg=0x3A; /* 7.2 */
else
tmpreg=0x28+opP->reg-ADDR; /* 5.areg */

if(isvar(opP->con1)) {
if(opP->reg==PC) {
add_fix('w',opP->con1,1);
} else
add_fix('w',opP->con1,0);
}
}
addword(nextword);
break;
case AINDX:
case APODX:
case AMIND:
case APRDX:
nextword=0;
baseo=get_num(opP->con1,80);
outro=get_num(opP->con2,80);
/* Figure out the 'addressing mode' */
/* Also turn on the BASE_DISABLE bit, if needed */
if(opP->reg==PC || opP->reg==ZPC) {
tmpreg=0x3b; /* 7.3 */
if(opP->reg==ZPC)
nextword|=0x80;
} else if(opP->reg==FAIL) {
nextword|=0x80;
tmpreg=0x30; /* 6.garbage */
} else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */

siz1= (opP->con1) ? opP->con1->e_siz : 0;
siz2= (opP->con2) ? opP->con2->e_siz : 0;

/* Index register stuff */
if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
nextword|=(opP->ireg-DATA)<<12;

if(opP->isiz==0 || opP->isiz==3)
nextword|=0x800;
switch(opP->imul) {
case 1: break;
case 2: nextword|=0x200; break;
case 4: nextword|=0x400; break;
case 8: nextword|=0x600; break;
default: abort();
}
/* IF its simple,
GET US OUT OF HERE! */

/* Must be INDEX, with an index
register. Address register
cannot be ZERO-PC, and either
:b was forced, or we know
it will fit */
if( opP->mode==AINDX
&& opP->reg!=FAIL
&& opP->reg!=ZPC
&& ( siz1==1
|| ( issbyte(baseo)
&& !isvar(opP->con1)))) {
nextword +=baseo&0xff;
addword(nextword);
if(isvar(opP->con1))
add_fix('B',opP->con1,0);
break;
}
} else
nextword|=0x40; /* No index reg */

/* It aint simple */
nextword|=0x100;
/* If the guy specified a width, we assume that
it is wide enough. Maybe it isn't. Ifso, we lose
*/
switch(siz1) {
case 0:
if(isvar(opP->con1) || !issword(baseo)) {
siz1=3;
nextword|=0x30;
} else if(baseo==0)
nextword|=0x10;
else {
nextword|=0x20;
siz1=2;
}
break;
case 1:
as_warn("Byte dispacement won't work. Defaulting to :w");
case 2:
nextword|=0x20;
break;
case 3:
nextword|=0x30;
break;
}

/* Figure out innner displacement stuff */
if(opP->mode!=AINDX) {
switch(siz2) {
case 0:
if(isvar(opP->con2) || !issword(outro)) {
siz2=3;
nextword|=0x3;
} else if(outro==0)
nextword|=0x1;
else {
nextword|=0x2;
siz2=2;
}
break;
case 1:
as_warn("Byte dispacement won't work. Defaulting to :w");
case 2:
nextword|=0x2;
break;
case 3:
nextword|=0x3;
break;
}
if(opP->mode==APODX) nextword|=0x04;
else if(opP->mode==AMIND) nextword|=0x40;
}
addword(nextword);

if(isvar(opP->con1)) {
if(opP->reg==PC || opP->reg==ZPC) {
add_fix(siz1==3 ? 'l' : 'w',opP->con1,1);
opP->con1->e_exp.X_add_number+=6;
} else
add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
}
if(siz1==3)
addword(baseo>>16);
if(siz1)
addword(baseo);

if(isvar(opP->con2)) {
if(opP->reg==PC || opP->reg==ZPC) {
add_fix(siz2==3 ? 'l' : 'w',opP->con2,1);
opP->con1->e_exp.X_add_number+=6;
} else
add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
}
if(siz2==3)
addword(outro>>16);
if(siz2)
addword(outro);

break;

case ABSL:
nextword=get_num(opP->con1,80);
switch(opP->con1->e_siz) {
default:
as_warn("Unknown size for absolute reference");
case 0:
if(!isvar(opP->con1) && issword(offs(opP->con1))) {
tmpreg=0x38; /* 7.0 */
addword(nextword);
break;
}
/* Don't generate pc relative code
on 68010 and 68000 */
if(isvar(opP->con1) &&
!subs(opP->con1) &&
seg(opP->con1)==SEG_TEXT &&
now_seg==SEG_TEXT &&
flagseen['m']==0 &&
!index("~%&$?", s[0])) {
tmpreg=0x3A; /* 7.2 */
add_frag(adds(opP->con1),
offs(opP->con1),
TAB(PCREL,SZ_UNDEF));
break;
}
case 3: /* Fall through into long */
if(isvar(opP->con1))
add_fix('l',opP->con1,0);

tmpreg=0x39; /* 7.1 mode */
addword(nextword>>16);
addword(nextword);
break;

case 2: /* Word */
if(isvar(opP->con1))
add_fix('w',opP->con1,0);

tmpreg=0x38; /* 7.0 mode */
addword(nextword);
break;
}
break;
case MSCR:
default:
as_bad("unknown/incorrect operand");
/* abort(); */
}
install_gen_operand(s[1],tmpreg);
break;

case '#':
case '^':
switch(s[1]) { /* JF: I hate floating point! */
case 'j':
tmpreg=70;
break;
case '8':
tmpreg=20;
break;
case 'C':
tmpreg=50;
break;
case '3':
default:
tmpreg=80;
break;
}
tmpreg=get_num(opP->con1,tmpreg);
if(isvar(opP->con1))
add_fix(s[1],opP->con1,0);
switch(s[1]) {
case 'b': /* Danger: These do no check for
certain types of overflow.
user beware! */
if(!isbyte(tmpreg))
opP->error="out of range";
insop(tmpreg);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
case 'w':
if(!isword(tmpreg))
opP->error="out of range";
insop(tmpreg);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
case 'l':
insop(tmpreg); /* Because of the way insop works, we put these two out backwards */
insop(tmpreg>>16);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
case '3':
tmpreg&=0xFF;
case '8':
case 'C':
install_operand(s[1],tmpreg);
break;
default:
as_fatal("Internal error: Unknown mode #%c",s[1]);
}
break;

case '+':
case '-':
case 'A':
install_operand(s[1],opP->reg-ADDR);
break;

case 'B':
tmpreg=get_num(opP->con1,80);
switch(s[1]) {
case 'g':
if(opP->con1->e_siz) { /* Deal with fixed size stuff by hand */
switch(opP->con1->e_siz) {
case 1:
add_fix('b',opP->con1,1);
break;
case 2:
add_fix('w',opP->con1,1);
addword(0);
break;
case 3:
add_fix('l',opP->con1,1);
addword(0);
addword(0);
break;
default:
as_fatal("Bad size for expression %d",opP->con1->e_siz);
}
} else if(subs(opP->con1)) {
/* We can't relax it */
the_ins.opcode[the_ins.numo-1]|=0xff;
add_fix('l',opP->con1,1);
addword(0);
addword(0);
} else if(adds(opP->con1)) {
if (flagseen['m'] &&
(the_ins.opcode[0] >= 0x6200) &&
(the_ins.opcode[0] <= 0x6f00)) {
add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
} else {
add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
}
} else {
/* JF: This is the WRONG thing to do
add_frag((symbolS *)0,offs(opP->con1),TAB(BRANCH,BYTE)); */
the_ins.opcode[the_ins.numo-1]|=0xff;
offs(opP->con1)+=4;
add_fix('l',opP->con1,1);
addword(0);
addword(0);
}
break;
case 'w':
if(isvar(opP->con1)) {
/* check for DBcc instruction */
if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8) {
/* size varies if patch */
/* needed for long form */
add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
break;
}

/* Don't ask! */
opP->con1->e_exp.X_add_number+=2;
add_fix('w',opP->con1,1);
}
addword(0);
break;
case 'c':
if(opP->con1->e_siz) {
switch(opP->con1->e_siz) {
case 2:
add_fix('w',opP->con1,1)
addword(0);
break;
case 3:
the_ins.opcode[the_ins.numo-1]|=0x40;
add_fix('l',opP->con1,1);
addword(0);
addword(0);
break;
default:
as_bad("Bad size for offset, must be word or long");
break;
}
} else if(subs(opP->con1)) {
add_fix('l',opP->con1,1);
add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
} else if(adds(opP->con1)) {
add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF));
} else {
/* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
the_ins.opcode[the_ins.numo-1]|=0x40;
add_fix('l',opP->con1,1);
addword(0);
addword(4);
}
break;
default:
as_fatal("Internal error: operand type B%c unknown",s[1]);
}
break;

case 'C': /* Ignore it */
break;

case 'd': /* JF this is a kludge */
if(opP->mode==AOFF) {
install_operand('s',opP->reg-ADDR);
} else {
char *tmpP;

tmpP=opP->con1->e_end-2;
opP->con1->e_beg++;
opP->con1->e_end-=4; /* point to the , */
baseo=m68k_reg_parse(&tmpP);
if(baseoADDR+7) {
as_bad("Unknown address reg, using A0");
baseo=0;
} else baseo-=ADDR;
install_operand('s',baseo);
}
tmpreg=get_num(opP->con1,80);
if(!issword(tmpreg)) {
as_warn("Expression out of range, using 0");
tmpreg=0;
}
addword(tmpreg);
break;

case 'D':
install_operand(s[1],opP->reg-DATA);
break;

case 'F':
install_operand(s[1],opP->reg-FPREG);
break;

case 'I':
tmpreg=1+opP->reg-COPNUM;
if(tmpreg==8)
tmpreg=0;
install_operand(s[1],tmpreg);
break;

case 'J': /* JF foo */
switch(opP->reg) {
case SFC:
tmpreg=0;
break;
case DFC:
tmpreg=0x001;
break;
case CACR:
tmpreg=0x002;
break;
case USP:
tmpreg=0x800;
break;
case VBR:
tmpreg=0x801;
break;
case CAAR:
tmpreg=0x802;
break;
case MSP:
tmpreg=0x803;
break;
case ISP:
tmpreg=0x804;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;

case 'k':
tmpreg=get_num(opP->con1,55);
install_operand(s[1],tmpreg&0x7f);
break;

case 'l':
tmpreg=opP->reg;
if(s[1]=='w') {
if(tmpreg&0x7FF0000)
as_bad("Floating point register in register list");
insop(reverse_16_bits(tmpreg));
} else {
if(tmpreg&0x700FFFF)
as_bad("Wrong register in floating-point reglist");
install_operand(s[1],reverse_8_bits(tmpreg>>16));
}
break;

case 'L':
tmpreg=opP->reg;
if(s[1]=='w') {
if(tmpreg&0x7FF0000)
as_bad("Floating point register in register list");
insop(tmpreg);
} else if(s[1]=='8') {
if(tmpreg&0x0FFFFFF)
as_bad("incorrect register in reglist");
install_operand(s[1],tmpreg>>24);
} else {
if(tmpreg&0x700FFFF)
as_bad("wrong register in floating-point reglist");
else
install_operand(s[1],tmpreg>>16);
}
break;

case 'M':
install_operand(s[1],get_num(opP->con1,60));
break;

case 'O':
tmpreg= (opP->mode==DREG)
? 0x20+opP->reg-DATA
: (get_num(opP->con1,40)&0x1F);
install_operand(s[1],tmpreg);
break;

case 'Q':
tmpreg=get_num(opP->con1,10);
if(tmpreg==8)
tmpreg=0;
install_operand(s[1],tmpreg);
break;

case 'R':
/* This depends on the fact that ADDR registers are
eight more than their corresponding DATA regs, so
the result will have the ADDR_REG bit set */
install_operand(s[1],opP->reg-DATA);
break;

case 's':
if(opP->reg==FPI) tmpreg=0x1;
else if(opP->reg==FPS) tmpreg=0x2;
else if(opP->reg==FPC) tmpreg=0x4;
else abort();
install_operand(s[1],tmpreg);
break;

case 'S': /* Ignore it */
break;

case 'T':
install_operand(s[1],get_num(opP->con1,30));
break;

case 'U': /* Ignore it */
break;

#ifdef m68851
/* JF: These are out of order, I fear. */
case 'f':
switch (opP->reg) {
case SFC:
tmpreg=0;
break;
case DFC:
tmpreg=1;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;

case 'P':
switch(opP->reg) {
case TC:
tmpreg=0;
break;
case CAL:
tmpreg=4;
break;
case VAL:
tmpreg=5;
break;
case SCC:
tmpreg=6;
break;
case AC:
tmpreg=7;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;

case 'V':
if (opP->reg == VAL)
break;
abort();

case 'W':
switch(opP->reg) {

case DRP:
tmpreg=1;
break;
case SRP:
tmpreg=2;
break;
case CRP:
tmpreg=3;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;

case 'X':
switch (opP->reg) {
case BAD: case BAD+1: case BAD+2: case BAD+3:
case BAD+4: case BAD+5: case BAD+6: case BAD+7:
tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
break;

case BAC: case BAC+1: case BAC+2: case BAC+3:
case BAC+4: case BAC+5: case BAC+6: case BAC+7:
tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
break;

default:
abort();
}
install_operand(s[1], tmpreg);
break;
case 'Y':
if (opP->reg == PSR)
break;
abort();

case 'Z':
if (opP->reg == PCSR)
break;
abort();
#endif /* m68851 */
default:
as_fatal("Internal error: Operand type %c unknown",s[0]);
}
}
/* By the time whe get here (FINALLY) the_ins contains the complete
instruction, ready to be emitted. . . */
}

int
get_regs(i,str,opP)
struct m68k_op *opP;
char *str;
{
/* 26, 25, 24, 23-16, 15-8, 0-7 */
/* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
unsigned long int cur_regs = 0;
int reg1,
reg2;

#define ADD_REG(x) { if(x==FPI) cur_regs|=(1<<24);\
else if(x==FPS) cur_regs|=(1<<25);\
else if(x==FPC) cur_regs|=(1<<26);\
else cur_regs|=(1<<(x-1)); }

reg1=i;
for(;;) {
if(*str=='/') {
ADD_REG(reg1);
str++;
} else if(*str=='-') {
str++;
reg2=m68k_reg_parse(&str);
if(reg2=FPREG+8 || reg1==FPI || reg1==FPS || reg1==FPC) {
opP->error="unknown register in register list";
return FAIL;
}
while(reg1<=reg2) {
ADD_REG(reg1);
reg1++;
}
if(*str=='\0')
break;
} else if(*str=='\0') {
ADD_REG(reg1);
break;
} else {
opP->error="unknow character in register list";
return FAIL;
}
/* DJA -- Bug Fix. Did't handle d1-d2/a1 until the following instruction was added */
if (*str=='/')
str ++;
reg1=m68k_reg_parse(&str);
if((reg1=FPREG+8) && !(reg1==FPI || reg1==FPS || reg1==FPC)) {
opP->error="unknown register in register list";
return FAIL;
}
}
opP->reg=cur_regs;
return OK;
}

int
reverse_16_bits(in)
int in;
{
int out=0;
int n;

static int mask[16] = {
0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
};
for(n=0;n<16;n++) {
if(in&mask[n])
out|=mask[15-n];
}
return out;
}

int
reverse_8_bits(in)
int in;
{
int out=0;
int n;

static int mask[8] = {
0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
};

for(n=0;n<8;n++) {
if(in&mask[n])
out|=mask[7-n];
}
return out;
}

void
install_operand(mode,val)
int mode;
int val;
{
switch(mode) {
case 's':
the_ins.opcode[0]|=val & 0xFF; /* JF FF is for M kludge */
break;
case 'd':
the_ins.opcode[0]|=val<<9;
break;
case '1':
the_ins.opcode[1]|=val<<12;
break;
case '2':
the_ins.opcode[1]|=val<<6;
break;
case '3':
the_ins.opcode[1]|=val;
break;
case '4':
the_ins.opcode[2]|=val<<12;
break;
case '5':
the_ins.opcode[2]|=val<<6;
break;
case '6':
/* DANGER! This is a hack to force cas2l and cas2w cmds
to be three words long! */
the_ins.numo++;
the_ins.opcode[2]|=val;
break;
case '7':
the_ins.opcode[1]|=val<<7;
break;
case '8':
the_ins.opcode[1]|=val<<10;
break;
#ifdef m68851
case '9':
the_ins.opcode[1]|=val<<5;
break;
#endif

case 't':
the_ins.opcode[1]|=(val<<10)|(val<<7);
break;
case 'D':
the_ins.opcode[1]|=(val<<12)|val;
break;
case 'g':
the_ins.opcode[0]|=val=0xff;
break;
case 'i':
the_ins.opcode[0]|=val<<9;
break;
case 'C':
the_ins.opcode[1]|=val;
break;
case 'j':
the_ins.opcode[1]|=val;
the_ins.numo++; /* What a hack */
break;
case 'k':
the_ins.opcode[1]|=val<<4;
break;
case 'b':
case 'w':
case 'l':
break;
case 'c':
default:
abort();
}
}

void
install_gen_operand(mode,val)
int mode;
int val;
{
switch(mode) {
case 's':
the_ins.opcode[0]|=val;
break;
case 'd':
/* This is a kludge!!! */
the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
break;
case 'b':
case 'w':
case 'l':
case 'f':
case 'F':
case 'x':
case 'p':
the_ins.opcode[0]|=val;
break;
/* more stuff goes here */
default:
abort();
}
}

char *
crack_operand(str,opP)
register char *str;
register struct m68k_op *opP;
{
register int parens;
register int c;
register char *beg_str;

if(!str) {
return str;
}
beg_str=str;
for(parens=0;*str && (parens>0 || notend(str));str++) {
if(*str=='(') parens++;
else if(*str==')') {
if(!parens) { /* ERROR */
opP->error="Extra )";
return str;
}
--parens;
}
}
if(!*str && parens) { /* ERROR */
opP->error="Missing )";
return str;
}
c= *str;
*str='\0';
if(m68k_ip_op(beg_str,opP)==FAIL) {
*str=c;
return str;
}
*str=c;
if(c=='}')
c= *++str; /* JF bitfield hack */
if(c) {
c= *++str;
if(!c)
as_bad("Missing operand");
}
return str;
}

/* See the comment up above where the #define notend(... is */
#if 0
notend(s)
char *s;
{
if(*s==',') return 0;
if(*s=='{' || *s=='}')
return 0;
if(*s!=':') return 1;
/* This kludge here is for the division cmd, which is a kludge */
if(index("aAdD#",s[1])) return 0;
return 1;
}
#endif

/* This is the guts of the machine-dependent assembler. STR points to a
machine dependent instruction. This funciton is supposed to emit
the frags/bytes it assembles to.
*/
void
md_assemble(str)
char *str;
{
char *er;
short *fromP;
char *toP;
int m,n;
char *to_beg_P;
int shorts_this_frag;

bzero((char *)(&the_ins),sizeof(the_ins)); /* JF for paranoia sake */
m68_ip(str);
er=the_ins.error;
if(!er) {
for(n=the_ins.numargs;n;--n)
if(the_ins.operands[n].error) {
er=the_ins.operands[n].error;
break;
}
}
if(er) {
as_bad("\"%s\" -- Statement '%s' ignored",er,str);
return;
}

if(the_ins.nfrag==0) { /* No frag hacking involved; just put it out */
toP=frag_more(2*the_ins.numo);
fromP= &the_ins.opcode[0];
for(m=the_ins.numo;m;--m) {
md_number_to_chars(toP,(long)(*fromP),2);
toP+=2;
fromP++;
}
/* put out symbol-dependent info */
for(m=0;m switch(the_ins.reloc[m].wid) {
case 'B':
n=1;
break;
case 'b':
n=1;
break;
case '3':
n=2;
break;
case 'w':
n=2;
break;
case 'l':
n=4;
break;
default:
as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid);
}

fix_new(frag_now,
(toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
n,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel);
}
return;
}

/* There's some frag hacking */
for(n=0,fromP= &the_ins.opcode[0];n int wid;

if(n==0) wid=2*the_ins.fragb[n].fragoff;
else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff);
toP=frag_more(wid);
to_beg_P=toP;
shorts_this_frag=0;
for(m=wid/2;m;--m) {
md_number_to_chars(toP,(long)(*fromP),2);
toP+=2;
fromP++;
shorts_this_frag++;
}
for(m=0;m if((the_ins.reloc[m].n)>= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) {
the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */;
break;
}
wid=the_ins.reloc[m].wid;
if(wid==0)
continue;
the_ins.reloc[m].wid=0;
wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;

fix_new(frag_now,
(toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
wid,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel);
}
know(the_ins.fragb[n].fadd);
(void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
}
n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
shorts_this_frag=0;
if(n) {
toP=frag_more(n*sizeof(short));
while(n--) {
md_number_to_chars(toP,(long)(*fromP),2);
toP+=2;
fromP++;
shorts_this_frag++;
}
}
for(m=0;m int wid;

wid=the_ins.reloc[m].wid;
if(wid==0)
continue;
the_ins.reloc[m].wid=0;
wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;

fix_new(frag_now,
(the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2,
wid,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel);
}
}

/* This function is called once, at assembler startup time. This should
set up all the tables, etc that the MD part of the assembler needs
*/
void
md_begin()
{
/*
* md_begin -- set up hash tables with 68000 instructions.
* similar to what the vax assembler does. ---phr
*/
/* RMS claims the thing to do is take the m68k-opcode.h table, and make
a copy of it at runtime, adding in the information we want but isn't
there. I think it'd be better to have an awk script hack the table
at compile time. Or even just xstr the table and use it as-is. But
my lord ghod hath spoken, so we do it this way. Excuse the ugly var
names. */

register struct m68k_opcode *ins;
register struct m68_incant *hack,
*slak;
register char *retval = 0; /* empty string, or error msg text */
register int i;
register char c;

if ((op_hash = hash_new()) == NULL)
as_fatal("Virtual memory exhausted");

obstack_begin(&robyn,4000);
for (ins = m68k_opcodes; ins < endop; ins++) {
hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant));
do {
slak->m_operands=ins->args;
slak->m_opnum=strlen(slak->m_operands)/2;
slak->m_opcode=ins->opcode;
/* This is kludgey */
slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) {
slak->m_next=(struct m68_incant *)
obstack_alloc(&robyn,sizeof(struct m68_incant));
ins++;
} else
slak->m_next=0;
slak=slak->m_next;
} while(slak);

retval = hash_insert (op_hash, ins->name,(char *)hack);
/* Didn't his mommy tell him about null pointers? */
if(retval && *retval)
as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
}

for (i = 0; i < sizeof(mklower_table) ; i++)
mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;

for (i = 0 ; i < sizeof(notend_table) ; i++) {
notend_table[i] = 0;
alt_notend_table[i] = 0;
}
notend_table[','] = 1;
notend_table['{'] = 1;
notend_table['}'] = 1;
alt_notend_table['a'] = 1;
alt_notend_table['A'] = 1;
alt_notend_table['d'] = 1;
alt_notend_table['D'] = 1;
alt_notend_table['#'] = 1;
alt_notend_table['f'] = 1;
alt_notend_table['F'] = 1;
#ifdef REGISTER_PREFIX
alt_notend_table[REGISTER_PREFIX] = 1;
#endif
}

#if 0
#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
|| (*s == ':' && index("aAdD#", s[1]))) \
? 0 : 1)
#endif

/* This funciton is called once, before the assembler exits. It is
supposed to do any final cleanup for this part of the assembler.
*/
void
md_end()
{
}

/* Equal to MAX_PRECISION in atof-ieee.c */
#define MAX_LITTLENUMS 6

/* Turn a string in input_line_pointer into a floating point constant of type
type, and store the appropriate bytes in *litP. The number of LITTLENUMS
emitted is stored in *sizeP . An error message is returned, or NULL on OK.
*/
char *
md_atof(type,litP,sizeP)
char type;
char *litP;
int *sizeP;
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
char *atof_ieee();

switch(type) {
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;

case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;

case 'x':
case 'X':
prec = 6;
break;

case 'p':
case 'P':
prec = 6;
break;

default:
*sizeP=0;
return "Bad call to MD_ATOF()";
}
t=atof_ieee(input_line_pointer,type,words);
if(t)
input_line_pointer=t;

*sizeP=prec * sizeof(LITTLENUM_TYPE);
for(wordP=words;prec--;) {
md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
litP+=sizeof(LITTLENUM_TYPE);
}
return ""; /* Someone should teach Dean about null pointers */
}

/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
for use in the a.out file, and stores them in the array pointed to by buf.
This knows about the endian-ness of the target machine and does
THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
2 (short) and 4 (long) Floating numbers are put out as a series of
LITTLENUMS (shorts, here at least)
*/
void
md_number_to_chars(buf,val,n)
char *buf;
long val;
int n;
{
switch(n) {
case 1:
*buf++=val;
break;
case 2:
*buf++=(val>>8);
*buf++=val;
break;
case 4:
*buf++=(val>>24);
*buf++=(val>>16);
*buf++=(val>>8);
*buf++=val;
break;
default:
abort();
}
}

void
md_number_to_imm(buf,val,n)
char *buf;
long val;
int n;
{
switch(n) {
case 1:
*buf++=val;
break;
case 2:
*buf++=(val>>8);
*buf++=val;
break;
case 4:
*buf++=(val>>24);
*buf++=(val>>16);
*buf++=(val>>8);
*buf++=val;
break;
default:
abort();
}
}

void
md_number_to_disp(buf,val,n)
char *buf;
long val;
int n;
{
abort();
}

void
md_number_to_field(buf,val,fix)
char *buf;
long val;
void *fix;
{
abort();
}


/* *fragP has been relaxed to its final size, and now needs to have
the bytes inside it modified to conform to the new size There is UGLY
MAGIC here. ..
*/
void
md_convert_frag(fragP)
register fragS *fragP;
{
long disp;
long ext;

/* Address in gas core of the place to store the displacement. */
register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
/* Address in object code of the displacement. */
register int object_address = fragP -> fr_fix + fragP -> fr_address;

know(fragP->fr_symbol);

/* The displacement of the address, from current location. */
disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;

switch(fragP->fr_subtype) {
case TAB(BCC68000,BYTE):
case TAB(BRANCH,BYTE):
know(issbyte(disp));
if(disp==0)
as_bad("short branch with zero offset: use :w");
fragP->fr_opcode[1]=disp;
ext=0;
break;
case TAB(DBCC,SHORT):
know(issword(disp));
ext=2;
break;
case TAB(BCC68000,SHORT):
case TAB(BRANCH,SHORT):
know(issword(disp));
fragP->fr_opcode[1]=0x00;
ext=2;
break;
case TAB(BRANCH,LONG):
if(flagseen['m']) {
if(fragP->fr_opcode[0]==0x61) {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0);
fragP->fr_fix+=4;
ext=0;
} else if(fragP->fr_opcode[0]==0x60) {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0);
fragP->fr_fix+=4;
ext=0;
}else {
as_bad("Long branch offset not supported.");
}
} else {
fragP->fr_opcode[1]=0xff;
ext=4;
}
break;
case TAB(BCC68000,LONG):
/* only Bcc 68000 instructions can come here */
/* change bcc into b!cc/jmp absl long */
fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */

/* JF: these used to be fr_opcode[2,3], but they may be in a
different frag, in which case refering to them is a no-no.
Only fr_opcode[0,1] are guaranteed to work. */
*buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
*buffer_address++ = 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix += 4;
ext=0;
break;
case TAB(DBCC,LONG):
/* only DBcc 68000 instructions can come here */
/* change dbcc into dbcc/jmp absl long */
/* JF: these used to be fr_opcode[2-7], but that's wrong */
*buffer_address++ = 0x00; /* branch offset = 4 */
*buffer_address++ = 0x04;
*buffer_address++ = 0x60; /* put in bra pc+6 */
*buffer_address++ = 0x06;
*buffer_address++ = 0x4e; /* put in jmp long (0x4ef9) */
*buffer_address++ = 0xf9;

fragP->fr_fix += 6; /* account for bra/jmp instructions */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix += 4;
ext=0;
break;
case TAB(FBRANCH,SHORT):
know((fragP->fr_opcode[1]&0x40)==0);
ext=2;
break;
case TAB(FBRANCH,LONG):
fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */
ext=4;
break;
case TAB(PCREL,SHORT):
ext=2;
break;
case TAB(PCREL,LONG):
/* The thing to do here is force it to ABSOLUTE LONG, since
PCREL is really trying to shorten an ABSOLUTE address anyway */
/* JF FOO This code has not been tested */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0);
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
as_bad("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
fragP->fr_opcode[0],fragP->fr_address);
fragP->fr_opcode[1]&= ~0x3F;
fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
fragP->fr_fix+=4;
/* md_number_to_chars(buffer_address,
(long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
4); */
ext=0;
break;
case TAB(PCLEA,SHORT):
subseg_change(SEG_TEXT,0);
fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1);
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x3A;
ext=2;
break;
case TAB(PCLEA,LONG):
subseg_change(SEG_TEXT,0);
fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1);
*buffer_address++ = 0x01;
*buffer_address++ = 0x70;
fragP->fr_fix+=2;
/* buffer_address+=2; */
ext=4;
break;

}
if(ext) {
md_number_to_chars(buffer_address,(long)disp,(int)ext);
fragP->fr_fix+=ext;
}
}

/* Force truly undefined symbols to their maximum size, and generally set up
the frag list to be relaxed
*/
int
md_estimate_size_before_relax(fragP,segtype)
register fragS *fragP;
int segtype;
{
int old_fix;
register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;

old_fix=fragP->fr_fix;

/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
switch(fragP->fr_subtype) {
case TAB(BRANCH,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
break;
} else if(flagseen['m']) {
if(fragP->fr_opcode[0]==0x61) {
if(flagseen['l']) {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xB8; /* JBSR with ABSL WORD offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 2,
fragP->fr_symbol, 0, fragP->fr_offset, 0);
fragP->fr_fix+=2;
} else {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 4,
fragP->fr_symbol, 0, fragP->fr_offset, 0);
fragP->fr_fix+=4;
}
frag_wane(fragP);
} else if(fragP->fr_opcode[0]==0x60) {
if(flagseen['l']) {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xF8; /* JMP with ABSL WORD offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 2,
fragP->fr_symbol, 0, fragP->fr_offset, 0);
fragP->fr_fix+=2;
} else {
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
subseg_change(SEG_TEXT, 0);
fix_new(fragP, fragP->fr_fix, 4,
fragP->fr_symbol, 0, fragP->fr_offset, 0);
fragP->fr_fix+=4;
}
frag_wane(fragP);
} else {
as_warn("Long branch offset to extern symbol not supported.");
}
} else if(flagseen['l']) { /* Symbol is still undefined. Make it simple */
fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,
(symbolS *)0,fragP->fr_offset + 2,1);
fragP->fr_fix+=2;
fragP->fr_opcode[1]=0x00;
frag_wane(fragP);
} else {
fix_new(fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol,
(symbolS *)0,fragP->fr_offset + 4,1);
fragP->fr_fix+=4;
fragP->fr_opcode[1]=0xff;
frag_wane(fragP);
break;
}
break;

case TAB(FBRANCH,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype || flagseen['l']) {
fragP->fr_subtype=TAB(FBRANCH,SHORT);
fragP->fr_var+=2;
} else {
fragP->fr_subtype=TAB(FBRANCH,LONG);
fragP->fr_var+=4;
}
break;

case TAB(PCREL,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype || flagseen['l']) {
fragP->fr_subtype=TAB(PCREL,SHORT);
fragP->fr_var+=2;
} else {
fragP->fr_subtype=TAB(PCREL,LONG);
fragP->fr_var+=4;
}
break;

case TAB(BCC68000,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
fragP->fr_subtype=TAB(BCC68000,BYTE);
break;
}
/* only Bcc 68000 instructions can come here */
/* change bcc into b!cc/jmp absl long */
fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
if(flagseen['l']) {
fragP->fr_opcode[1] = 0x04; /* branch offset = 6 */
/* JF: these were fr_opcode[2,3] */
buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[1] = 0xf8;
fragP->fr_fix += 2; /* account for jmp instruction */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix += 2;
} else {
fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
/* JF: these were fr_opcode[2,3] */
buffer_address[2] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[3] = 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix += 4;
}
frag_wane(fragP);
break;

case TAB(DBCC,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
fragP->fr_subtype=TAB(DBCC,SHORT);
fragP->fr_var+=2;
break;
}
/* only DBcc 68000 instructions can come here */
/* change dbcc into dbcc/jmp absl long */
/* JF: these used to be fr_opcode[2-4], which is wrong. */
buffer_address[0] = 0x00; /* branch offset = 4 */
buffer_address[1] = 0x04;
buffer_address[2] = 0x60; /* put in bra pc + ... */
if(flagseen['l']) {
/* JF: these were fr_opcode[5-7] */
buffer_address[3] = 0x04; /* plus 4 */
buffer_address[4] = 0x4e;/* Put in Jump Word */
buffer_address[5] = 0xf8;
fragP->fr_fix += 6; /* account for bra/jmp instruction */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix+=2;
} else {
/* JF: these were fr_opcode[5-7] */
buffer_address[3] = 0x06; /* Plus 6 */
buffer_address[4] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[5] = 0xf9;
fragP->fr_fix += 6; /* account for bra/jmp instruction */
subseg_change(SEG_TEXT,0);
fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
fragP->fr_offset,0);
fragP->fr_fix += 4;
}
frag_wane(fragP);
break;

case TAB(PCLEA,SZ_UNDEF):
if((fragP->fr_symbol->sy_type&N_TYPE)==segtype || flagseen['l']) {
fragP->fr_subtype=TAB(PCLEA,SHORT);
fragP->fr_var+=2;
} else {
fragP->fr_subtype=TAB(PCLEA,LONG);
fragP->fr_var+=6;
}
break;

default:
break;
}

/* now that SZ_UNDEF are taken care of, check others */
switch(fragP->fr_subtype) {
case TAB(BCC68000,BYTE):
case TAB(BRANCH,BYTE):
/* We can't do a short jump to the next instruction,
so we force word mode. */
if(fragP->fr_symbol && fragP->fr_symbol->sy_value==0 &&
fragP->fr_symbol->sy_frag==fragP->fr_next) {
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
fragP->fr_var+=2;
}
break;
default:
break;
}
return fragP->fr_var + fragP->fr_fix - old_fix;
}

/* the bit-field entries in the relocation_info struct plays hell
with the byte-order problems of cross-assembly. So as a hack,
I added this mach. dependent ri twiddler. Ugly, but it gets
you there. -KWK */
/* on m68k: first 4 bytes are normal unsigned long, next three bytes
are symbolnum, most sig. byte first. Last byte is broken up with
bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
nibble as nuthin. (on Sun 3 at least) */
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[4] = (ri.r_symbolnum >> 16) & 0x0ff;
the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
the_bytes[6] = ri.r_symbolnum & 0x0ff;
the_bytes[7] = (((ri.r_pcrel << 7) & 0x80) | ((ri.r_length << 5) & 0x60) |
((ri.r_extern << 4) & 0x10));
/* now put it back where you found it */
bcopy (the_bytes, (char *)ri_p, sizeof(struct relocation_info));
}

#ifndef WORKING_DOT_WORD
const int md_short_jump_size = 4;
const int md_long_jump_size = 6;

void
md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
char *ptr;
long from_addr,
to_addr;
fragS *frag;
symbolS *to_symbol;
{
long offset;

offset = to_addr - (from_addr+2);

md_number_to_chars(ptr ,(long)0x6000,2);
md_number_to_chars(ptr+2,(long)offset,2);
}

void
md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
char *ptr;
long from_addr,
to_addr;
fragS *frag;
symbolS *to_symbol;
{
long offset;

if(flagseen['m']) {
offset=to_addr-to_symbol->sy_value;
md_number_to_chars(ptr ,(long)0x4EF9,2);
md_number_to_chars(ptr+2,(long)offset,4);
fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long int)0,0);
} else {
offset=to_addr - (from_addr+2);
md_number_to_chars(ptr ,(long)0x60ff,2);
md_number_to_chars(ptr+2,(long)offset,4);
}
}

#endif
/* Different values of OK tell what its OK to return. Things that aren't OK are an error (what a shock, no?)

0: Everything is OK
10: Absolute 1:8 only
20: Absolute 0:7 only
30: absolute 0:15 only
40: Absolute 0:31 only
50: absolute 0:127 only
55: absolute -64:63 only
60: absolute -128:127 only
70: absolute 0:4095 only
80: No bignums

*/
int
get_num(exp,ok)
struct m68k_exp *exp;
int ok;
{
#ifdef TEST2
long l = 0;

if(!exp->e_beg)
return 0;
if(*exp->e_beg=='0') {
if(exp->e_beg[1]=='x')
sscanf(exp->e_beg+2,"%x",&l);
else
sscanf(exp->e_beg+1,"%O",&l);
return l;
}
return atol(exp->e_beg);
#else
char *save_in;
char c_save;

if(!exp) {
/* Can't do anything */
return 0;
}
if(!exp->e_beg || !exp->e_end) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Null expression defaults to %ld",offs(exp));
return 0;
}

exp->e_siz=0;
if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) {
switch(exp->e_end[0]) {
case 's':
case 'S':
case 'b':
case 'B':
exp->e_siz=1;
break;
case 'w':
case 'W':
exp->e_siz=2;
break;
case 'l':
case 'L':
exp->e_siz=3;
break;
default:
as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
}
exp->e_end-=2;
}
c_save=exp->e_end[1];
exp->e_end[1]='\0';
save_in=input_line_pointer;
input_line_pointer=exp->e_beg;
switch(expression(&(exp->e_exp))) {
case SEG_PASS1:
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Unknown expression: '%s' defaulting to %d",exp->e_beg,offs(exp));
break;

case SEG_NONE:
/* Do the same thing the VAX asm does */
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)=0;
if(ok==10) {
as_warn("expression out of range: defaulting to 1");
offs(exp)=1;
}
break;
case SEG_ABSOLUTE:
switch(ok) {
case 10:
if(offs(exp)<1 || offs(exp)>8) {
as_warn("expression out of range: defaulting to 1");
offs(exp)=1;
}
break;
case 20:
if(offs(exp)<0 || offs(exp)>7)
goto outrange;
break;
case 30:
if(offs(exp)<0 || offs(exp)>15)
goto outrange;
break;
case 40:
if(offs(exp)<0 || offs(exp)>32)
goto outrange;
break;
case 50:
if(offs(exp)<0 || offs(exp)>127)
goto outrange;
break;
case 55:
if(offs(exp)<-64 || offs(exp)>63)
goto outrange;
break;
case 60:
if(offs(exp)<-128 || offs(exp)>127)
goto outrange;
break;
case 70:
if(offs(exp)<0 || offs(exp)>4095) {
outrange:
as_warn("expression out of range: defaulting to 0");
offs(exp)=0;
}
break;
default:
break;
}
break;
case SEG_TEXT:
case SEG_DATA:
case SEG_BSS:
case SEG_UNKNOWN:
case SEG_DIFFERENCE:
if(ok>=10 && ok<=70) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
}
break;
case SEG_BIG:
if(ok==80 && offs(exp)<0) { /* HACK! Turn it into a long */
LITTLENUM_TYPE words[6];

gen_to_words(words,2,8L);/* These numbers are magic! */
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)=words[1]|(words[0]<<16);
} else if(ok!=0) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
}
break;
default:
abort();
}
if(input_line_pointer!=exp->e_end+1)
as_bad("Ignoring junk after expression");
exp->e_end[1]=c_save;
input_line_pointer=save_in;
if(exp->e_siz) {
switch(exp->e_siz) {
case 1:
if(!isbyte(offs(exp)))
as_warn("expression doesn't fit in BYTE");
break;
case 2:
if(!isword(offs(exp)))
as_warn("expression doesn't fit in WORD");
break;
}
}
return offs(exp);
#endif
}

/* These are the back-ends for the various machine dependent pseudo-ops. */
void demand_empty_rest_of_line(); /* Hate those extra verbose names */

void
s_data1()
{
subseg_new(SEG_DATA,1);
demand_empty_rest_of_line();
}

void
s_data2()
{
subseg_new(SEG_DATA,2);
demand_empty_rest_of_line();
}

void
s_even()
{
register int temp;
register long int temp_fill;

temp = 1; /* JF should be 2? */
temp_fill = get_absolute_expression ();
if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */
frag_align (temp, (int)temp_fill);
demand_empty_rest_of_line();
}

void
s_proc()
{
demand_empty_rest_of_line();
}

/* s_space is defined in read.c .skip is simply an alias to it. */

int
md_parse_option(argP,cntP,vecP)
char **argP;
int *cntP;
char ***vecP;
{
switch(**argP) {
case 'l': /* -l means keep external to 2 bit offset
rather than 16 bit one */
break;

case 'm':
/* Gas almost ignores this option! */
(*argP)++;
if(**argP=='c')
(*argP)++;
if(!strcmp(*argP,"68000"))
flagseen['m']=2;
else if(!strcmp(*argP,"68010")) {
#ifdef M_SUN
omagic= 1<<16|OMAGIC;
#endif
flagseen['m']=1;
} else if(!strcmp(*argP,"68020"))
flagseen['m']=0;
else
as_warn("Unknown -m option ignored");
while(**argP)
(*argP)++;
break;

default:
return 0;
}
return 1;
}


#ifdef TEST2

/* TEST2: Test md_assemble() */
/* Warning, this routine probably doesn't work anymore */

main()
{
struct m68_it the_ins;
char buf[120];
char *cp;
int n;

m68_ip_begin();
for(;;) {
if(!gets(buf) || !*buf)
break;
if(buf[0]=='|' || buf[1]=='.')
continue;
for(cp=buf;*cp;cp++)
if(*cp=='\t')
*cp=' ';
if(is_label(buf))
continue;
bzero(&the_ins,sizeof(the_ins));
m68_ip(&the_ins,buf);
if(the_ins.error) {
printf("Error %s in %s\n",the_ins.error,buf);
} else {
printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args);
for(n=0;n printf(" 0x%x",the_ins.opcode[n]&0xffff);
printf(" ");
print_the_insn(&the_ins.opcode[0],stdout);
(void)putchar('\n');
}
for(n=0;n if(the_ins.operands[n].error) {
printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf);
continue;
}
printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg);
if(the_ins.operands[n].b_const)
printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul);
if(the_ins.operands[n].b_iadd)
printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
(void)putchar('\n');
}
}
m68_ip_end();
return 0;
}

is_label(str)
char *str;
{
while(*str==' ')
str++;
while(*str && *str!=' ')
str++;
if(str[-1]==':' || str[1]=='=')
return 1;
return 0;
}

#endif

/* Possible states for relaxation:

0 0 branch offset byte (bra, etc)
0 1 word
0 2 long

1 0 indexed offsets byte a0@(32,d4:w:1) etc
1 1 word
1 2 long

2 0 two-offset index word-word a0@(32,d4)@(45) etc
2 1 word-long
2 2 long-word
2 3 long-long

*/



#ifdef DONTDEF
abort()
{
printf("ABORT!\n");
exit(12);
}

char *index(s,c)
char *s;
{
while(*s!=c) {
if(!*s) return 0;
s++;
}
return s;
}

bzero(s,n)
char *s;
{
while(n--)
*s++=0;
}

print_frags()
{
fragS *fragP;
extern fragS *text_frag_root;

for(fragP=text_frag_root;fragP;fragP=fragP->fr_next) {
printf("addr %lu next 0x%x fix %ld var %ld symbol 0x%x offset %ld\n",
fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
printf("opcode 0x%x type %d subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype);
}
fflush(stdout);
return 0;
}
#endif

#ifdef DONTDEF
/*VARARGS1*/
panic(format,args)
char *format;
{
fputs("Internal error:",stderr);
_doprnt(format,&args,stderr);
(void)putc('\n',stderr);
as_where();
abort();
}
#endif
gas-1.38/atof-ieee.c 666 12412 0 33042 4650363631 11613 0ustar randy/* 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 *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
gas-1.38/m68k-opcode.h 666 13200 13 252507 4655622057 13307 0ustar kingdonuser/* Opcode table for m68000/m68020 and m68881.
Copyright (C) 1989, Free Software Foundation.

This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.

Both GDB and GAS are free software; you can redistribute and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GDB and GAS are distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GDB or GAS; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


struct m68k_opcode
{
char *name;
unsigned long opcode;
unsigned long match;
char *args;
};

/* We store four bytes of opcode for all opcodes because that
is the most any of them need. The actual length of an instruction
is always at least 2 bytes, and is as much longer as necessary to
hold the operands it has.

The match component is a mask saying which bits must match
particular opcode in order for an instruction to be an instance
of that opcode.

The args component is a string containing two characters
for each operand of the instruction. The first specifies
the kind of operand; the second, the place it is stored. */

/* Kinds of operands:
D data register only. Stored as 3 bits.
A address register only. Stored as 3 bits.
R either kind of register. Stored as 4 bits.
F floating point coprocessor register only. Stored as 3 bits.
O an offset (or width): immediate data 0-31 or data register.
Stored as 6 bits in special format for BF... insns.
+ autoincrement only. Stored as 3 bits (number of the address register).
- autodecrement only. Stored as 3 bits (number of the address register).
Q quick immediate data. Stored as 3 bits.
This matches an immediate operand only when value is in range 1 .. 8.
M moveq immediate data. Stored as 8 bits.
This matches an immediate operand only when value is in range -128..127
T trap vector immediate data. Stored as 4 bits.

k K-factor for fmove.p instruction. Stored as a 7-bit constant or
a three bit register offset, depending on the field type.

# immediate data. Stored in special places (b, w or l)
which say how many bits to store.
^ immediate data for floating point instructions. Special places
are offset by 2 bytes from '#'...
B pc-relative address, converted to an offset
that is treated as immediate data.
d displacement and register. Stores the register as 3 bits
and stores the displacement in the entire second word.

C the CCR. No need to store it; this is just for filtering validity.
S the SR. No need to store, just as with CCR.
U the USP. No need to store, just as with CCR.

I Coprocessor ID. Not printed if 1. The Coprocessor ID is always
extracted from the 'd' field of word one, which means that an extended
coprocessor opcode can be skipped using the 'i' place, if needed.

s System Control register for the floating point coprocessor.
S List of system control registers for floating point coprocessor.

J Misc register for movec instruction, stored in 'j' format.
Possible values:
000 SFC Source Function Code reg
001 DFC Data Function Code reg
002 CACR Cache Control Register
800 USP User Stack Pointer
801 VBR Vector Base reg
802 CAAR Cache Address Register
803 MSP Master Stack Pointer
804 ISP Interrupt Stack Pointer

L Register list of the type d0-d7/a0-a7 etc.
(New! Improved! Can also hold fp0-fp7, as well!)
The assembler tries to see if the registers match the insn by
looking at where the insn wants them stored.

l Register list like L, but with all the bits reversed.
Used for going the other way. . .

They are all stored as 6 bits using an address mode and a register number;
they differ in which addressing modes they match.

* all (modes 0-6,7.*)
~ alterable memory (modes 2-6,7.0,7.1)(not 0,1,7.~)
% alterable (modes 0-6,7.0,7.1)(not 7.~)
; data (modes 0,2-6,7.*)(not 1)
@ data, but not immediate (modes 0,2-6,7.? ? ?)(not 1,7.?) This may really be ;, the 68020 book says it is
! control (modes 2,5,6,7.*-)(not 0,1,3,4,7.4)
& alterable control (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?)
$ alterable data (modes 0,2-6,7.0,7.1)(not 1,7.~)
? alterable control, or data register (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~)
/ control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4)
*/

/* JF: for the 68851 */
/*
I didn't use much imagination in choosing the
following codes, so many of them aren't very
mnemonic. -rab

P pmmu register
Possible values:
000 TC Translation Control reg
100 CAL Current Access Level
101 VAL Validate Access Level
110 SCC Stack Change Control
111 AC Access Control

W wide pmmu registers
Possible values:
001 DRP Dma Root Pointer
010 SRP Supervisor Root Pointer
011 CRP Cpu Root Pointer

f function code register
0 SFC
1 DFC

V VAL register only

X BADx, BACx
100 BAD Breakpoint Acknowledge Data
101 BAC Breakpoint Acknowledge Control

Y PSR
Z PCSR

| memory (modes 2-6, 7.*)

*/

/* Places to put an operand, for non-general operands:
s source, low bits of first word.
d dest, shifted 9 in first word
1 second word, shifted 12
2 second word, shifted 6
3 second word, shifted 0
4 third word, shifted 12
5 third word, shifted 6
6 third word, shifted 0
7 second word, shifted 7
8 second word, shifted 10
D store in both place 1 and place 3; for divul and divsl.
b second word, low byte
w second word (entire)
l second and third word (entire)
g branch offset for bra and similar instructions.
The place to store depends on the magnitude of offset.
t store in both place 7 and place 8; for floating point operations
c branch offset for cpBcc operations.
The place to store is word two if bit six of word one is zero,
and words two and three if bit six of word one is one.
i Increment by two, to skip over coprocessor extended operands. Only
works with the 'I' format.
k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number.
Also used for dynamic fmovem instruction.
C floating point coprocessor constant - 7 bits. Also used for static
K-factors...
j Movec register #, stored in 12 low bits of second word.

Places to put operand, for general operands:
d destination, shifted 6 bits in first word
b source, at low bit of first word, and immediate uses one byte
w source, at low bit of first word, and immediate uses two bytes
l source, at low bit of first word, and immediate uses four bytes
s source, at low bit of first word.
Used sometimes in contexts where immediate is not allowed anyway.
f single precision float, low bit of 1st word, immediate uses 4 bytes
F double precision float, low bit of 1st word, immediate uses 8 bytes
x extended precision float, low bit of 1st word, immediate uses 12 bytes
p packed float, low bit of 1st word, immediate uses 12 bytes
*/

#define one(x) ((x) << 16)
#define two(x, y) (((x) << 16) + y)

/*
*** DANGER WILL ROBINSON ***

The assembler requires that all instances of the same mnemonic must be
consecutive. If they aren't, the assembler will bomb at runtime
*/
struct m68k_opcode m68k_opcodes[] =
{
{"abcd", one(0140400), one(0170770), "DsDd"},
{"abcd", one(0140410), one(0170770), "-s-d"},

/* Add instructions */
{"addal", one(0150700), one(0170700), "*lAd"},
{"addaw", one(0150300), one(0170700), "*wAd"},
{"addib", one(0003000), one(0177700), "#b$b"},
{"addil", one(0003200), one(0177700), "#l$l"},
{"addiw", one(0003100), one(0177700), "#w$w"},
{"addqb", one(0050000), one(0170700), "Qd$b"},
{"addql", one(0050200), one(0170700), "Qd%l"},
{"addqw", one(0050100), one(0170700), "Qd%w"},

{"addb", one(0050000), one(0170700), "Qd$b"}, /* addq written as add */
{"addb", one(0003000), one(0177700), "#b$b"}, /* addi written as add */
{"addb", one(0150000), one(0170700), ";bDd"}, /* addb , Dd */
{"addb", one(0150400), one(0170700), "Dd~b"}, /* addb Dd, */

{"addw", one(0050100), one(0170700), "Qd%w"}, /* addq written as add */
{"addw", one(0003100), one(0177700), "#w$w"}, /* addi written as add */
{"addw", one(0150300), one(0170700), "*wAd"}, /* adda written as add */
{"addw", one(0150100), one(0170700), "*wDd"}, /* addw , Dd */
{"addw", one(0150500), one(0170700), "Dd~w"}, /* addw Dd, */

{"addl", one(0050200), one(0170700), "Qd%l"}, /* addq written as add */
{"addl", one(0003200), one(0177700), "#l$l"}, /* addi written as add */
{"addl", one(0150700), one(0170700), "*lAd"}, /* adda written as add */
{"addl", one(0150200), one(0170700), "*lDd"}, /* addl , Dd */
{"addl", one(0150600), one(0170700), "Dd~l"}, /* addl Dd, */

{"addxb", one(0150400), one(0170770), "DsDd"},
{"addxb", one(0150410), one(0170770), "-s-d"},
{"addxl", one(0150600), one(0170770), "DsDd"},
{"addxl", one(0150610), one(0170770), "-s-d"},
{"addxw", one(0150500), one(0170770), "DsDd"},
{"addxw", one(0150510), one(0170770), "-s-d"},

{"andib", one(0001000), one(0177700), "#b$b"},
{"andib", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */
{"andiw", one(0001100), one(0177700), "#w$w"},
{"andiw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */
{"andil", one(0001200), one(0177700), "#l$l"},

{"andb", one(0001000), one(0177700), "#b$b"}, /* andi written as or */
{"andb", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */
{"andb", one(0140000), one(0170700), ";bDd"}, /* memory to register */
{"andb", one(0140400), one(0170700), "Dd~b"}, /* register to memory */
{"andw", one(0001100), one(0177700), "#w$w"}, /* andi written as or */
{"andw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */
{"andw", one(0140100), one(0170700), ";wDd"}, /* memory to register */
{"andw", one(0140500), one(0170700), "Dd~w"}, /* register to memory */
{"andl", one(0001200), one(0177700), "#l$l"}, /* andi written as or */
{"andl", one(0140200), one(0170700), ";lDd"}, /* memory to register */
{"andl", one(0140600), one(0170700), "Dd~l"}, /* register to memory */

{"aslb", one(0160400), one(0170770), "QdDs"},
{"aslb", one(0160440), one(0170770), "DdDs"},
{"asll", one(0160600), one(0170770), "QdDs"},
{"asll", one(0160640), one(0170770), "DdDs"},
{"aslw", one(0160500), one(0170770), "QdDs"},
{"aslw", one(0160540), one(0170770), "DdDs"},
{"aslw", one(0160700), one(0177700), "~s"}, /* Shift memory */
{"asrb", one(0160000), one(0170770), "QdDs"},
{"asrb", one(0160040), one(0170770), "DdDs"},
{"asrl", one(0160200), one(0170770), "QdDs"},
{"asrl", one(0160240), one(0170770), "DdDs"},
{"asrw", one(0160100), one(0170770), "QdDs"},
{"asrw", one(0160140), one(0170770), "DdDs"},
{"asrw", one(0160300), one(0177700), "~s"}, /* Shift memory */

{"bhi", one(0061000), one(0177400), "Bg"},
{"bls", one(0061400), one(0177400), "Bg"},
{"bcc", one(0062000), one(0177400), "Bg"},
{"bcs", one(0062400), one(0177400), "Bg"},
{"bne", one(0063000), one(0177400), "Bg"},
{"beq", one(0063400), one(0177400), "Bg"},
{"bvc", one(0064000), one(0177400), "Bg"},
{"bvs", one(0064400), one(0177400), "Bg"},
{"bpl", one(0065000), one(0177400), "Bg"},
{"bmi", one(0065400), one(0177400), "Bg"},
{"bge", one(0066000), one(0177400), "Bg"},
{"blt", one(0066400), one(0177400), "Bg"},
{"bgt", one(0067000), one(0177400), "Bg"},
{"ble", one(0067400), one(0177400), "Bg"},

{"bchg", one(0000500), one(0170700), "Dd$s"},
{"bchg", one(0004100), one(0177700), "#b$s"},
{"bclr", one(0000600), one(0170700), "Dd$s"},
{"bclr", one(0004200), one(0177700), "#b$s"},
{"bfchg", two(0165300, 0), two(0177700, 0170000), "?sO2O3"},
{"bfclr", two(0166300, 0), two(0177700, 0170000), "?sO2O3"},
{"bfexts", two(0165700, 0), two(0177700, 0100000), "/sO2O3D1"},
{"bfextu", two(0164700, 0), two(0177700, 0100000), "/sO2O3D1"},
{"bfffo", two(0166700, 0), two(0177700, 0100000), "/sO2O3D1"},
{"bfins", two(0167700, 0), two(0177700, 0100000), "D1?sO2O3"},
{"bfset", two(0167300, 0), two(0177700, 0170000), "?sO2O3"},
{"bftst", two(0164300, 0), two(0177700, 0170000), "/sO2O3"},
{"bset", one(0000700), one(0170700), "Dd$s"},
{"bset", one(0004300), one(0177700), "#b$s"},
{"btst", one(0000400), one(0170700), "Dd@s"},
{"btst", one(0004000), one(0177700), "#b@s"},

{"bkpt", one(0044110), one(0177770), "Qs"},
{"bra", one(0060000), one(0177400), "Bg"},
{"bras", one(0060000), one(0177400), "Bw"},
{"bsr", one(0060400), one(0177400), "Bg"},
{"bsrs", one(0060400), one(0177400), "Bw"},

{"callm", one(0003300), one(0177700), "#b!s"},
{"cas2l", two(0007374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF FOO this is really a 3 word ins */
{"cas2w", two(0006374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF ditto */
{"casb", two(0005300, 0), two(0177700, 0177070), "D3D2~s"},
{"casl", two(0007300, 0), two(0177700, 0177070), "D3D2~s"},
{"casw", two(0006300, 0), two(0177700, 0177070), "D3D2~s"},

/* {"chk", one(0040600), one(0170700), ";wDd"}, JF FOO this looks wrong */
{"chk2b", two(0000300, 0004000), two(0177700, 07777), "!sR1"},
{"chk2l", two(0002300, 0004000), two(0177700, 07777), "!sR1"},
{"chk2w", two(0001300, 0004000), two(0177700, 07777), "!sR1"},
{"chkl", one(0040400), one(0170700), ";lDd"},
{"chkw", one(0040600), one(0170700), ";wDd"},
{"clrb", one(0041000), one(0177700), "$s"},
{"clrl", one(0041200), one(0177700), "$s"},
{"clrw", one(0041100), one(0177700), "$s"},

{"cmp2b", two(0000300, 0), two(0177700, 07777), "!sR1"},
{"cmp2l", two(0002300, 0), two(0177700, 07777), "!sR1"},
{"cmp2w", two(0001300, 0), two(0177700, 07777), "!sR1"},
{"cmpal", one(0130700), one(0170700), "*lAd"},
{"cmpaw", one(0130300), one(0170700), "*wAd"},
{"cmpib", one(0006000), one(0177700), "#b;b"},
{"cmpil", one(0006200), one(0177700), "#l;l"},
{"cmpiw", one(0006100), one(0177700), "#w;w"},
{"cmpb", one(0006000), one(0177700), "#b;b"}, /* cmpi written as cmp */
{"cmpb", one(0130000), one(0170700), ";bDd"},
{"cmpw", one(0006100), one(0177700), "#w;w"},
{"cmpw", one(0130100), one(0170700), "*wDd"},
{"cmpw", one(0130300), one(0170700), "*wAd"}, /* cmpa written as cmp */
{"cmpl", one(0006200), one(0177700), "#l;l"},
{"cmpl", one(0130200), one(0170700), "*lDd"},
{"cmpl", one(0130700), one(0170700), "*lAd"},
{"cmpmb", one(0130410), one(0170770), "+s+d"},
{"cmpml", one(0130610), one(0170770), "+s+d"},
{"cmpmw", one(0130510), one(0170770), "+s+d"},

{"dbcc", one(0052310), one(0177770), "DsBw"},
{"dbcs", one(0052710), one(0177770), "DsBw"},
{"dbeq", one(0053710), one(0177770), "DsBw"},
{"dbf", one(0050710), one(0177770), "DsBw"},
{"dbge", one(0056310), one(0177770), "DsBw"},
{"dbgt", one(0057310), one(0177770), "DsBw"},
{"dbhi", one(0051310), one(0177770), "DsBw"},
{"dble", one(0057710), one(0177770), "DsBw"},
{"dbls", one(0051710), one(0177770), "DsBw"},
{"dblt", one(0056710), one(0177770), "DsBw"},
{"dbmi", one(0055710), one(0177770), "DsBw"},
{"dbne", one(0053310), one(0177770), "DsBw"},
{"dbpl", one(0055310), one(0177770), "DsBw"},
{"dbra", one(0050710), one(0177770), "DsBw"},
{"dbt", one(0050310), one(0177770), "DsBw"},
{"dbvc", one(0054310), one(0177770), "DsBw"},
{"dbvs", one(0054710), one(0177770), "DsBw"},

{"divsl", two(0046100, 0006000), two(0177700, 0107770), ";lD3D1"},
{"divsl", two(0046100, 0004000), two(0177700, 0107770), ";lDD"},
{"divsll", two(0046100, 0004000), two(0177700, 0107770), ";lD3D1"},
{"divsw", one(0100700), one(0170700), ";wDd"},
{"divs", one(0100700), one(0170700), ";wDd"},
{"divul", two(0046100, 0002000), two(0177700, 0107770), ";lD3D1"},
{"divul", two(0046100, 0000000), two(0177700, 0107770), ";lDD"},
{"divull", two(0046100, 0000000), two(0177700, 0107770), ";lD3D1"},
{"divuw", one(0100300), one(0170700), ";wDd"},
{"divu", one(0100300), one(0170700), ";wDd"},
{"eorb", one(0005000), one(0177700), "#b$s"}, /* eori written as or */
{"eorb", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */
{"eorb", one(0130400), one(0170700), "Dd$s"}, /* register to memory */
{"eorib", one(0005000), one(0177700), "#b$s"},
{"eorib", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */
{"eoril", one(0005200), one(0177700), "#l$s"},
{"eoriw", one(0005100), one(0177700), "#w$s"},
{"eoriw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */
{"eorl", one(0005200), one(0177700), "#l$s"},
{"eorl", one(0130600), one(0170700), "Dd$s"},
{"eorw", one(0005100), one(0177700), "#w$s"},
{"eorw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */
{"eorw", one(0130500), one(0170700), "Dd$s"},

{"exg", one(0140500), one(0170770), "DdDs"},
{"exg", one(0140510), one(0170770), "AdAs"},
{"exg", one(0140610), one(0170770), "DdAs"},
{"exg", one(0140610), one(0170770), "AsDd"},

{"extw", one(0044200), one(0177770), "Ds"},
{"extl", one(0044300), one(0177770), "Ds"},
{"extbl", one(0044700), one(0177770), "Ds"},
{"extb.l", one(0044700), one(0177770), "Ds"}, /* Not sure we should support this one*/

{"illegal", one(0045374), one(0177777), ""},
{"jmp", one(0047300), one(0177700), "!s"},
{"jsr", one(0047200), one(0177700), "!s"},
{"lea", one(0040700), one(0170700), "!sAd"},
{"linkw", one(0047120), one(0177770), "As#w"},
{"linkl", one(0044010), one(0177770), "As#l"},
{"link", one(0047120), one(0177770), "As#w"},
{"link", one(0044010), one(0177770), "As#l"},

{"lslb", one(0160410), one(0170770), "QdDs"}, /* lsrb #Q, Ds */
{"lslb", one(0160450), one(0170770), "DdDs"}, /* lsrb Dd, Ds */
{"lslw", one(0160510), one(0170770), "QdDs"}, /* lsrb #Q, Ds */
{"lslw", one(0160550), one(0170770), "DdDs"}, /* lsrb Dd, Ds */
{"lslw", one(0161700), one(0177700), "~s"}, /* Shift memory */
{"lsll", one(0160610), one(0170770), "QdDs"}, /* lsrb #Q, Ds */
{"lsll", one(0160650), one(0170770), "DdDs"}, /* lsrb Dd, Ds */

{"lsrb", one(0160010), one(0170770), "QdDs"} /* lsrb #Q, Ds */,
{"lsrb", one(0160050), one(0170770), "DdDs"}, /* lsrb Dd, Ds */
{"lsrl", one(0160210), one(0170770), "QdDs"}, /* lsrb #Q, Ds */
{"lsrl", one(0160250), one(0170770), "DdDs"}, /* lsrb #Q, Ds */
{"lsrw", one(0160110), one(0170770), "QdDs"}, /* lsrb #Q, Ds */
{"lsrw", one(0160150), one(0170770), "DdDs"}, /* lsrb #Q, Ds */
{"lsrw", one(0161300), one(0177700), "~s"}, /* Shift memory */

{"moveal", one(0020100), one(0170700), "*lAd"},
{"moveaw", one(0030100), one(0170700), "*wAd"},
{"moveb", one(0010000), one(0170000), ";b$d"}, /* move */
{"movel", one(0070000), one(0170400), "MsDd"}, /* moveq written as move */
{"movel", one(0020000), one(0170000), "*l$d"},
{"movel", one(0020100), one(0170700), "*lAd"},
{"movel", one(0047140), one(0177770), "AsUd"}, /* move to USP */
{"movel", one(0047150), one(0177770), "UdAs"}, /* move from USP */

{"movec", one(0047173), one(0177777), "R1Jj"},
{"movec", one(0047173), one(0177777), "R1#j"},
{"movec", one(0047172), one(0177777), "JjR1"},
{"movec", one(0047172), one(0177777), "#jR1"},

/* JF added these next four for the assembler */
{"moveml", one(0044300), one(0177700), "Lw&s"}, /* movem reg to mem. */
{"moveml", one(0044340), one(0177770), "lw-s"}, /* movem reg to autodecrement. */
{"moveml", one(0046300), one(0177700), "!sLw"}, /* movem mem to reg. */
{"moveml", one(0046330), one(0177770), "+sLw"}, /* movem autoinc to reg. */

{"moveml", one(0044300), one(0177700), "#w&s"}, /* movem reg to mem. */
{"moveml", one(0044340), one(0177770), "#w-s"}, /* movem reg to autodecrement. */
{"moveml", one(0046300), one(0177700), "!s#w"}, /* movem mem to reg. */
{"moveml", one(0046330), one(0177770), "+s#w"}, /* movem autoinc to reg. */

/* JF added these next four for the assembler */
{"movemw", one(0044200), one(0177700), "Lw&s"}, /* movem reg to mem. */
{"movemw", one(0044240), one(0177770), "lw-s"}, /* movem reg to autodecrement. */
{"movemw", one(0046200), one(0177700), "!sLw"}, /* movem mem to reg. */
{"movemw", one(0046230), one(0177770), "+sLw"}, /* movem autoinc to reg. */

{"movemw", one(0044200), one(0177700), "#w&s"}, /* movem reg to mem. */
{"movemw", one(0044240), one(0177770), "#w-s"}, /* movem reg to autodecrement. */
{"movemw", one(0046200), one(0177700), "!s#w"}, /* movem mem to reg. */
{"movemw", one(0046230), one(0177770), "+s#w"}, /* movem autoinc to reg. */

{"movepl", one(0000510), one(0170770), "dsDd"}, /* memory to register */
{"movepl", one(0000710), one(0170770), "Ddds"}, /* register to memory */
{"movepw", one(0000410), one(0170770), "dsDd"}, /* memory to register */
{"movepw", one(0000610), one(0170770), "Ddds"}, /* register to memory */
{"moveq", one(0070000), one(0170400), "MsDd"},
{"movew", one(0030000), one(0170000), "*w$d"},
{"movew", one(0030100), one(0170700), "*wAd"}, /* movea, written as move */
{"movew", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */
{"movew", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */
{"movew", one(0042300), one(0177700), ";wCd"}, /* move to ccr */
{"movew", one(0043300), one(0177700), ";wSd"}, /* move to sr */

{"movesb", two(0007000, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */
{"movesb", two(0007000, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */
{"movesl", two(0007200, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */
{"movesl", two(0007200, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */
{"movesw", two(0007100, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */
{"movesw", two(0007100, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */

{"mulsl", two(0046000, 004000), two(0177700, 0107770), ";lD1"},
{"mulsl", two(0046000, 006000), two(0177700, 0107770), ";lD3D1"},
{"mulsw", one(0140700), one(0170700), ";wDd"},
{"muls", one(0140700), one(0170700), ";wDd"},
{"mulul", two(0046000, 000000), two(0177700, 0107770), ";lD1"},
{"mulul", two(0046000, 002000), two(0177700, 0107770), ";lD3D1"},
{"muluw", one(0140300), one(0170700), ";wDd"},
{"mulu", one(0140300), one(0170700), ";wDd"},
{"nbcd", one(0044000), one(0177700), "$s"},
{"negb", one(0042000), one(0177700), "$s"},
{"negl", one(0042200), one(0177700), "$s"},
{"negw", one(0042100), one(0177700), "$s"},
{"negxb", one(0040000), one(0177700), "$s"},
{"negxl", one(0040200), one(0177700), "$s"},
{"negxw", one(0040100), one(0177700), "$s"},
{"nop", one(0047161), one(0177777), ""},
{"notb", one(0043000), one(0177700), "$s"},
{"notl", one(0043200), one(0177700), "$s"},
{"notw", one(0043100), one(0177700), "$s"},

{"orb", one(0000000), one(0177700), "#b$s"}, /* ori written as or */
{"orb", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */
{"orb", one(0100000), one(0170700), ";bDd"}, /* memory to register */
{"orb", one(0100400), one(0170700), "Dd~s"}, /* register to memory */
{"orib", one(0000000), one(0177700), "#b$s"},
{"orib", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */
{"oril", one(0000200), one(0177700), "#l$s"},
{"oriw", one(0000100), one(0177700), "#w$s"},
{"oriw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */
{"orl", one(0000200), one(0177700), "#l$s"},
{"orl", one(0100200), one(0170700), ";lDd"}, /* memory to register */
{"orl", one(0100600), one(0170700), "Dd~s"}, /* register to memory */
{"orw", one(0000100), one(0177700), "#w$s"},
{"orw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */
{"orw", one(0100100), one(0170700), ";wDd"}, /* memory to register */
{"orw", one(0100500), one(0170700), "Dd~s"}, /* register to memory */

{"pack", one(0100500), one(0170770), "DsDd#w"}, /* pack Ds, Dd, #w */
{"pack", one(0100510), one(0170770), "-s-d#w"}, /* pack -(As), -(Ad), #w */
{"pea", one(0044100), one(0177700), "!s"},
{"reset", one(0047160), one(0177777), ""},

{"rolb", one(0160430), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"rolb", one(0160470), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"roll", one(0160630), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"roll", one(0160670), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"rolw", one(0160530), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"rolw", one(0160570), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"rolw", one(0163700), one(0177700), "~s"}, /* Rotate memory */
{"rorb", one(0160030), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"rorb", one(0160070), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"rorl", one(0160230), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"rorl", one(0160270), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"rorw", one(0160130), one(0170770), "QdDs"}, /* rorb #Q, Ds */
{"rorw", one(0160170), one(0170770), "DdDs"}, /* rorb Dd, Ds */
{"rorw", one(0163300), one(0177700), "~s"}, /* Rotate memory */

{"roxlb", one(0160420), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxlb", one(0160460), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxll", one(0160620), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxll", one(0160660), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxlw", one(0160520), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxlw", one(0160560), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxlw", one(0162700), one(0177700), "~s"}, /* Rotate memory */
{"roxrb", one(0160020), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxrb", one(0160060), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxrl", one(0160220), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxrl", one(0160260), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxrw", one(0160120), one(0170770), "QdDs"}, /* roxrb #Q, Ds */
{"roxrw", one(0160160), one(0170770), "DdDs"}, /* roxrb Dd, Ds */
{"roxrw", one(0162300), one(0177700), "~s"}, /* Rotate memory */

{"rtd", one(0047164), one(0177777), "#w"},
{"rte", one(0047163), one(0177777), ""},
{"rtm", one(0003300), one(0177760), "Rs"},
{"rtr", one(0047167), one(0177777), ""},
{"rts", one(0047165), one(0177777), ""},

{"scc", one(0052300), one(0177700), "$s"},
{"scs", one(0052700), one(0177700), "$s"},
{"seq", one(0053700), one(0177700), "$s"},
{"sf", one(0050700), one(0177700), "$s"},
{"sge", one(0056300), one(0177700), "$s"},
{"sgt", one(0057300), one(0177700), "$s"},
{"shi", one(0051300), one(0177700), "$s"},
{"sle", one(0057700), one(0177700), "$s"},
{"sls", one(0051700), one(0177700), "$s"},
{"slt", one(0056700), one(0177700), "$s"},
{"smi", one(0055700), one(0177700), "$s"},
{"sne", one(0053300), one(0177700), "$s"},
{"spl", one(0055300), one(0177700), "$s"},
{"st", one(0050300), one(0177700), "$s"},
{"svc", one(0054300), one(0177700), "$s"},
{"svs", one(0054700), one(0177700), "$s"},

{"sbcd", one(0100400), one(0170770), "DsDd"},
{"sbcd", one(0100410), one(0170770), "-s-d"},
{"stop", one(0047162), one(0177777), "#w"},

{"subal", one(0110700), one(0170700), "*lAd"},
{"subaw", one(0110300), one(0170700), "*wAd"},
{"subb", one(0050400), one(0170700), "Qd%s"}, /* subq written as sub */
{"subb", one(0002000), one(0177700), "#b$s"}, /* subi written as sub */
{"subb", one(0110000), one(0170700), ";bDd"}, /* subb ? ?, Dd */
{"subb", one(0110400), one(0170700), "Dd~s"}, /* subb Dd, ? ? */
{"subib", one(0002000), one(0177700), "#b$s"},
{"subil", one(0002200), one(0177700), "#l$s"},
{"subiw", one(0002100), one(0177700), "#w$s"},
{"subl", one(0050600), one(0170700), "Qd%s"},
{"subl", one(0002200), one(0177700), "#l$s"},
{"subl", one(0110700), one(0170700), "*lAd"},
{"subl", one(0110200), one(0170700), "*lDd"},
{"subl", one(0110600), one(0170700), "Dd~s"},
{"subqb", one(0050400), one(0170700), "Qd%s"},
{"subql", one(0050600), one(0170700), "Qd%s"},
{"subqw", one(0050500), one(0170700), "Qd%s"},
{"subw", one(0050500), one(0170700), "Qd%s"},
{"subw", one(0002100), one(0177700), "#w$s"},
{"subw", one(0110100), one(0170700), "*wDd"},
{"subw", one(0110300), one(0170700), "*wAd"}, /* suba written as sub */
{"subw", one(0110500), one(0170700), "Dd~s"},
{"subxb", one(0110400), one(0170770), "DsDd"}, /* subxb Ds, Dd */
{"subxb", one(0110410), one(0170770), "-s-d"}, /* subxb -(As), -(Ad) */
{"subxl", one(0110600), one(0170770), "DsDd"},
{"subxl", one(0110610), one(0170770), "-s-d"},
{"subxw", one(0110500), one(0170770), "DsDd"},
{"subxw", one(0110510), one(0170770), "-s-d"},

{"swap", one(0044100), one(0177770), "Ds"},

{"tas", one(0045300), one(0177700), "$s"},
{"trap", one(0047100), one(0177760), "Ts"},

{"trapcc", one(0052374), one(0177777), ""},
{"trapcs", one(0052774), one(0177777), ""},
{"trapeq", one(0053774), one(0177777), ""},
{"trapf", one(0050774), one(0177777), ""},
{"trapge", one(0056374), one(0177777), ""},
{"trapgt", one(0057374), one(0177777), ""},
{"traphi", one(0051374), one(0177777), ""},
{"traple", one(0057774), one(0177777), ""},
{"trapls", one(0051774), one(0177777), ""},
{"traplt", one(0056774), one(0177777), ""},
{"trapmi", one(0055774), one(0177777), ""},
{"trapne", one(0053374), one(0177777), ""},
{"trappl", one(0055374), one(0177777), ""},
{"trapt", one(0050374), one(0177777), ""},
{"trapvc", one(0054374), one(0177777), ""},
{"trapvs", one(0054774), one(0177777), ""},

{"trapcc.w", one(0052372), one(0177777), ""},
{"trapcs.w", one(0052772), one(0177777), ""},
{"trapeq.w", one(0053772), one(0177777), ""},
{"trapf.w", one(0050772), one(0177777), ""},
{"trapge.w", one(0056372), one(0177777), ""},
{"trapgt.w", one(0057372), one(0177777), ""},
{"traphi.w", one(0051372), one(0177777), ""},
{"traple.w", one(0057772), one(0177777), ""},
{"trapls.w", one(0051772), one(0177777), ""},
{"traplt.w", one(0056772), one(0177777), ""},
{"trapmi.w", one(0055772), one(0177777), ""},
{"trapne.w", one(0053372), one(0177777), ""},
{"trappl.w", one(0055372), one(0177777), ""},
{"trapt.w", one(0050372), one(0177777), ""},
{"trapvc.w", one(0054372), one(0177777), ""},
{"trapvs.w", one(0054772), one(0177777), ""},

{"trapcc.l", one(0052373), one(0177777), ""},
{"trapcs.l", one(0052773), one(0177777), ""},
{"trapeq.l", one(0053773), one(0177777), ""},
{"trapf.l", one(0050773), one(0177777), ""},
{"trapge.l", one(0056373), one(0177777), ""},
{"trapgt.l", one(0057373), one(0177777), ""},
{"traphi.l", one(0051373), one(0177777), ""},
{"traple.l", one(0057773), one(0177777), ""},
{"trapls.l", one(0051773), one(0177777), ""},
{"traplt.l", one(0056773), one(0177777), ""},
{"trapmi.l", one(0055773), one(0177777), ""},
{"trapne.l", one(0053373), one(0177777), ""},
{"trappl.l", one(0055373), one(0177777), ""},
{"trapt.l", one(0050373), one(0177777), ""},
{"trapvc.l", one(0054373), one(0177777), ""},
{"trapvs.l", one(0054773), one(0177777), ""},

{"trapv", one(0047166), one(0177777), ""},

{"tstb", one(0045000), one(0177700), ";b"},
{"tstw", one(0045100), one(0177700), "*w"},
{"tstl", one(0045200), one(0177700), "*l"},

{"unlk", one(0047130), one(0177770), "As"},
{"unpk", one(0100600), one(0170770), "DsDd#w"},
{"unpk", one(0100610), one(0170770), "-s-d#w"},
/* JF floating pt stuff moved down here */

{"fabsb", two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fabsd", two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fabsl", two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fabsp", two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fabss", two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fabsw", two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fabsx", two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt"},

{"facosb", two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"facosd", two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"facosl", two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"facosp", two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"facoss", two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"facosw", two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7"},
{"facosx", two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt"},

{"faddb", two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"faddd", two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"faddl", two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"faddp", two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fadds", two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"faddw", two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7"},
{"faddx", two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiFt"}, JF removed */

{"fasinb", two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fasind", two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fasinl", two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fasinp", two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fasins", two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fasinw", two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fasinx", two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt"},

{"fatanb", two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fatand", two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fatanl", two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fatanp", two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fatans", two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fatanw", two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fatanx", two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt"},

{"fatanhb", two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fatanhd", two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fatanhl", two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fatanhp", two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fatanhs", two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fatanhw", two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt"},

{"fbeq", one(0xF081), one(0xF1BF), "IdBc"},
{"fbf", one(0xF080), one(0xF1BF), "IdBc"},
{"fbge", one(0xF093), one(0xF1BF), "IdBc"},
{"fbgl", one(0xF096), one(0xF1BF), "IdBc"},
{"fbgle", one(0xF097), one(0xF1BF), "IdBc"},
{"fbgt", one(0xF092), one(0xF1BF), "IdBc"},
{"fble", one(0xF095), one(0xF1BF), "IdBc"},
{"fblt", one(0xF094), one(0xF1BF), "IdBc"},
{"fbne", one(0xF08E), one(0xF1BF), "IdBc"},
{"fbnge", one(0xF09C), one(0xF1BF), "IdBc"},
{"fbngl", one(0xF099), one(0xF1BF), "IdBc"},
{"fbngle", one(0xF098), one(0xF1BF), "IdBc"},
{"fbngt", one(0xF09D), one(0xF1BF), "IdBc"},
{"fbnle", one(0xF09A), one(0xF1BF), "IdBc"},
{"fbnlt", one(0xF09B), one(0xF1BF), "IdBc"},
{"fboge", one(0xF083), one(0xF1BF), "IdBc"},
{"fbogl", one(0xF086), one(0xF1BF), "IdBc"},
{"fbogt", one(0xF082), one(0xF1BF), "IdBc"},
{"fbole", one(0xF085), one(0xF1BF), "IdBc"},
{"fbolt", one(0xF084), one(0xF1BF), "IdBc"},
{"fbor", one(0xF087), one(0xF1BF), "IdBc"},
{"fbseq", one(0xF091), one(0xF1BF), "IdBc"},
{"fbsf", one(0xF090), one(0xF1BF), "IdBc"},
{"fbsne", one(0xF09E), one(0xF1BF), "IdBc"},
{"fbst", one(0xF09F), one(0xF1BF), "IdBc"},
{"fbt", one(0xF08F), one(0xF1BF), "IdBc"},
{"fbueq", one(0xF089), one(0xF1BF), "IdBc"},
{"fbuge", one(0xF08B), one(0xF1BF), "IdBc"},
{"fbugt", one(0xF08A), one(0xF1BF), "IdBc"},
{"fbule", one(0xF08D), one(0xF1BF), "IdBc"},
{"fbult", one(0xF08C), one(0xF1BF), "IdBc"},
{"fbun", one(0xF088), one(0xF1BF), "IdBc"},

{"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fcmpl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fcmpp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fcmps", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fcmpw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fcmpx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiFt"}, JF removed */

{"fcosb", two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fcosd", two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fcosl", two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fcosp", two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fcoss", two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fcosw", two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fcosx", two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt"},

{"fcoshb", two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fcoshd", two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fcoshl", two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fcoshp", two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fcoshs", two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fcoshw", two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fcoshx", two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt"},

{"fdbeq", two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbf", two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbge", two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbgl", two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbgle", two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbgt", two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdble", two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdblt", two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbne", two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbnge", two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbngl", two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbngle", two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbngt", two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbnle", two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbnlt", two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdboge", two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbogl", two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbogt", two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbole", two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbolt", two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbor", two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbseq", two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbsf", two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbsne", two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbst", two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbt", two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbueq", two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbuge", two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbugt", two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbule", two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbult", two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw"},
{"fdbun", two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw"},

{"fdivb", two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fdivd", two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fdivl", two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fdivp", two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fdivs", two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fdivw", two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fdivx", two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiFt"}, JF */

{"fetoxb", two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fetoxd", two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fetoxl", two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fetoxp", two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fetoxs", two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fetoxw", two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fetoxx", two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt"},

{"fetoxm1b", two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fetoxm1d", two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fetoxm1l", two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fetoxm1p", two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fetoxm1s", two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fetoxm1w", two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fetoxm1x", two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt"},

{"fgetexpb", two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fgetexpd", two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fgetexpl", two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fgetexpp", two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fgetexps", two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fgetexpw", two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fgetexpx", two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt"},

{"fgetmanb", two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fgetmand", two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fgetmanl", two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fgetmanp", two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fgetmans", two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fgetmanw", two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fgetmanx", two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt"},

{"fintb", two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fintd", two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fintl", two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fintp", two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fints", two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fintw", two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fintx", two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt"},

{"fintrzb", two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fintrzd", two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fintrzl", two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fintrzp", two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fintrzs", two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fintrzw", two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fintrzx", two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt"},

{"flog10b", two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"flog10d", two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"flog10l", two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"flog10p", two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"flog10s", two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"flog10w", two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7"},
{"flog10x", two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt"},

{"flog2b", two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"flog2d", two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"flog2l", two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"flog2p", two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"flog2s", two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"flog2w", two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7"},
{"flog2x", two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt"},

{"flognb", two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"flognd", two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"flognl", two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"flognp", two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"flogns", two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"flognw", two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7"},
{"flognx", two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt"},

{"flognp1b", two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"flognp1d", two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"flognp1l", two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"flognp1p", two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"flognp1s", two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"flognp1w", two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7"},
{"flognp1x", two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt"},

{"fmodb", two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fmodd", two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fmodl", two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fmodp", two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fmods", two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fmodw", two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fmodx", two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiFt"}, JF */

{"fmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7"}, /* fmove from to fp */
{"fmoveb", two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7@b"}, /* fmove from fp to */
{"fmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7"}, /* fmove from to fp */
{"fmoved", two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7@F"}, /* fmove from fp to */
{"fmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7"}, /* fmove from to fp */
{"fmovel", two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7@l"}, /* fmove from fp to */
/* Warning: The addressing modes on these are probably not right:
esp, Areg direct is only allowed for FPI */
/* fmove.l from/to system control registers: */
{"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"},
{"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8"},

/* {"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"},
{"fmovel", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*ss8"}, */

{"fmovep", two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7"}, /* fmove from to fp */
{"fmovep", two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7@pkC"}, /* fmove.p with k-factors: */
{"fmovep", two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7@pDk"}, /* fmove.p with k-factors: */

{"fmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7"}, /* fmove from to fp */
{"fmoves", two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7@f"}, /* fmove from fp to */
{"fmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7"}, /* fmove from to fp */
{"fmovew", two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7@w"}, /* fmove from fp to */
{"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7"}, /* fmove from to fp */
{"fmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7"}, /* fmove from to fp */
{"fmovex", two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7@x"}, /* fmove from fp to */
/* JF removed {"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiFt"}, / * fmove from to fp */

{"fmovecrx", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"}, /* fmovecr.x #ccc, FPn */
{"fmovecr", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"},

/* Other fmovemx. */
{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s"}, /* fmovem.x to autodecrement, static and dynamic */
{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s"}, /* fmovem.x to autodecrement, static and dynamic */

{"fmovemx", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s"}, /* fmovem.x to autodecrement, static and dynamic */

{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */
{"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */
{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3"}, /* fmovem.x from control, static and dynamic: */
{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk"}, /* fmovem.x from control, static and dynamic: */
{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s"}, /* fmovem.x to control, static and dynamic: */
{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3"}, /* fmovem.x from control, static and dynamic: */

{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3"}, /* fmovem.x from autoincrement, static and dynamic: */
{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3"}, /* fmovem.x from autoincrement, static and dynamic: */
{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk"}, /* fmovem.x from autoincrement, static and dynamic: */

{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s"},
{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Ii#8@s"},
{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"},

{"fmoveml", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8"},
{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*s#8"},
{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8"},

/* fmovemx with register lists */
{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s"}, /* fmovem.x to autodecrement, static and dynamic */
{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s"}, /* fmovem.x to control, static and dynamic: */
{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3"}, /* fmovem.x from autoincrement, static and dynamic: */
{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3"}, /* fmovem.x from control, static and dynamic: */

/* Alternate mnemonics for GNU as and GNU CC */
{"fmovem", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s"}, /* fmovem.x to autodecrement, static and dynamic */
{"fmovem", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s"}, /* fmovem.x to autodecrement, static and dynamic */

{"fmovem", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */
{"fmovem", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */

{"fmovem", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3"}, /* fmovem.x from autoincrement, static and dynamic: */
{"fmovem", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk"}, /* fmovem.x from autoincrement, static and dynamic: */

{"fmovem", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3"}, /* fmovem.x from control, static and dynamic: */
{"fmovem", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk"}, /* fmovem.x from control, static and dynamic: */

/* fmoveml a FP-control register */
{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"},
{"fmovem", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8"},

/* fmoveml a FP-control reglist */
{"fmovem", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8@s"},
{"fmovem", two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8"},

{"fmulb", two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fmuld", two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fmull", two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fmulp", two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fmuls", two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fmulw", two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fmulx", two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiFt"}, JF */

{"fnegb", two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fnegd", two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fnegl", two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fnegp", two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fnegs", two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fnegw", two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt"},

{"fnop", two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii"},

{"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fremp", two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"frems", two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fremw", two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fremx", two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiFt"}, JF */

{"frestore", one(0xF140), one(0xF1C0), "Id&s"},
{"frestore", one(0xF158), one(0xF1F8), "Id+s"},
{"fsave", one(0xF100), one(0xF1C0), "Id&s"},
{"fsave", one(0xF120), one(0xF1F8), "Id-s"},

{"fsincosb", two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7"},
{"fsincosd", two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7"},
{"fsincosl", two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7"},
{"fsincosp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7"},
{"fsincoss", two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7"},
{"fsincosw", two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7"},
{"fsincosx", two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7"},
{"fsincosx", two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7"},

{"fscaleb", two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fscaled", two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fscalel", two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fscalep", two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fscales", two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fscalew", two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fscalex", two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7"},
/* {"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiFt"}, JF */

/* $ is necessary to prevent the assembler from using PC-relative.
If @ were used, "label: fseq label" could produce "ftrapeq",
because "label" became "pc@label". */
{"fseq", two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsf", two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsge", two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsgl", two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsgle", two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsgt", two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsle", two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fslt", two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsne", two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsnge", two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsngl", two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsngle", two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsngt", two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsnle", two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsnlt", two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsoge", two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsogl", two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsogt", two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsole", two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsolt", two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsor", two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsseq", two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fssf", two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fssne", two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsst", two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fst", two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsueq", two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsuge", two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsugt", two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsule", two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsult", two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s"},
{"fsun", two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s"},

{"fsgldivb", two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsgldivd", two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsgldivl", two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsgldivp", two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsgldivs", two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsgldivw", two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsgldivx", two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt"},

{"fsglmulb", two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsglmuld", two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsglmull", two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsglmulp", two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsglmuls", two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsglmulw", two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsglmulx", two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt"},

{"fsinb", two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsind", two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsinl", two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsinp", two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsins", two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsinw", two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsinx", two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt"},

{"fsinhb", two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsinhd", two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsinhl", two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsinhp", two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsinhs", two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsinhw", two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsinhx", two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt"},

{"fsqrtb", two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsqrtd", two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsqrtl", two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsqrtp", two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsqrts", two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsqrtw", two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsqrtx", two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt"},

{"fsubb", two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"fsubd", two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"fsubl", two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"fsubp", two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"fsubs", two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"fsubw", two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7"},
{"fsubx", two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt"},

{"ftanb", two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"ftand", two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"ftanl", two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"ftanp", two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"ftans", two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"ftanw", two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7"},
{"ftanx", two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt"},

{"ftanhb", two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"ftanhd", two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"ftanhl", two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"ftanhp", two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"ftanhs", two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"ftanhw", two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7"},
{"ftanhx", two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt"},

{"ftentoxb", two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"ftentoxd", two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"ftentoxl", two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"ftentoxp", two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"ftentoxs", two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"ftentoxw", two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7"},
{"ftentoxx", two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt"},

{"ftrapeq", two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapf", two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapge", two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapgl", two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapgle", two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapgt", two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii"},
{"ftraple", two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii"},
{"ftraplt", two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapne", two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapnge", two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapngl", two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapngle", two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapngt", two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapnle", two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapnlt", two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapoge", two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapogl", two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapogt", two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapole", two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapolt", two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapor", two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapseq", two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapsf", two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapsne", two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapst", two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapt", two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapueq", two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapuge", two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapugt", two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapule", two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapult", two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii"},
{"ftrapun", two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii"},

{"ftrapeqw", two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapfw", two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapgew", two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapglw", two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapglew", two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapgtw", two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftraplew", two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapltw", two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapnew", two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapngew", two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapnglw", two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapnglew", two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapngtw", two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapnlew", two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapnltw", two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapogew", two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapoglw", two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapogtw", two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapolew", two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapoltw", two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftraporw", two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapseqw", two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapsfw", two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapsnew", two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapstw", two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftraptw", two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapueqw", two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapugew", two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapugtw", two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapulew", two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapultw", two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w"},
{"ftrapunw", two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w"},

{"ftrapeql", two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapfl", two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapgel", two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapgll", two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapglel", two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapgtl", two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftraplel", two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapltl", two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapnel", two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapngel", two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapngll", two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapnglel", two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapngtl", two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapnlel", two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapnltl", two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapogel", two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapogll", two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapogtl", two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapolel", two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapoltl", two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftraporl", two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapseql", two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapsfl", two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapsnel", two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapstl", two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftraptl", two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapueql", two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapugel", two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapugtl", two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapulel", two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapultl", two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l"},
{"ftrapunl", two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l"},

{"ftstb", two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b"},
{"ftstd", two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F"},
{"ftstl", two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l"},
{"ftstp", two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p"},
{"ftsts", two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f"},
{"ftstw", two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w"},
{"ftstx", two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8"},
{"ftstx", two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x"},

{"ftwotoxb", two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7"},
{"ftwotoxd", two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7"},
{"ftwotoxl", two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7"},
{"ftwotoxp", two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7"},
{"ftwotoxs", two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7"},
{"ftwotoxw", two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7"},
{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7"},
{"ftwotoxx", two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7"},
{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt"},


{"fjeq", one(0xF081), one(0xF1FF), "IdBc"},
{"fjf", one(0xF080), one(0xF1FF), "IdBc"},
{"fjge", one(0xF093), one(0xF1FF), "IdBc"},
{"fjgl", one(0xF096), one(0xF1FF), "IdBc"},
{"fjgle", one(0xF097), one(0xF1FF), "IdBc"},
{"fjgt", one(0xF092), one(0xF1FF), "IdBc"},
{"fjle", one(0xF095), one(0xF1FF), "IdBc"},
{"fjlt", one(0xF094), one(0xF1FF), "IdBc"},
{"fjne", one(0xF08E), one(0xF1FF), "IdBc"},
{"fjnge", one(0xF09C), one(0xF1FF), "IdBc"},
{"fjngl", one(0xF099), one(0xF1FF), "IdBc"},
{"fjngle", one(0xF098), one(0xF1FF), "IdBc"},
{"fjngt", one(0xF09D), one(0xF1FF), "IdBc"},
{"fjnle", one(0xF09A), one(0xF1FF), "IdBc"},
{"fjnlt", one(0xF09B), one(0xF1FF), "IdBc"},
{"fjoge", one(0xF083), one(0xF1FF), "IdBc"},
{"fjogl", one(0xF086), one(0xF1FF), "IdBc"},
{"fjogt", one(0xF082), one(0xF1FF), "IdBc"},
{"fjole", one(0xF085), one(0xF1FF), "IdBc"},
{"fjolt", one(0xF084), one(0xF1FF), "IdBc"},
{"fjor", one(0xF087), one(0xF1FF), "IdBc"},
{"fjseq", one(0xF091), one(0xF1FF), "IdBc"},
{"fjsf", one(0xF090), one(0xF1FF), "IdBc"},
{"fjsne", one(0xF09E), one(0xF1FF), "IdBc"},
{"fjst", one(0xF09F), one(0xF1FF), "IdBc"},
{"fjt", one(0xF08F), one(0xF1FF), "IdBc"},
{"fjueq", one(0xF089), one(0xF1FF), "IdBc"},
{"fjuge", one(0xF08B), one(0xF1FF), "IdBc"},
{"fjugt", one(0xF08A), one(0xF1FF), "IdBc"},
{"fjule", one(0xF08D), one(0xF1FF), "IdBc"},
{"fjult", one(0xF08C), one(0xF1FF), "IdBc"},
{"fjun", one(0xF088), one(0xF1FF), "IdBc"},

/* The assembler will ignore attempts to force a short offset */

{"bhis", one(0061000), one(0177400), "Bg"},
{"blss", one(0061400), one(0177400), "Bg"},
{"bccs", one(0062000), one(0177400), "Bg"},
{"bcss", one(0062400), one(0177400), "Bg"},
{"bnes", one(0063000), one(0177400), "Bg"},
{"beqs", one(0063400), one(0177400), "Bg"},
{"bvcs", one(0064000), one(0177400), "Bg"},
{"bvss", one(0064400), one(0177400), "Bg"},
{"bpls", one(0065000), one(0177400), "Bg"},
{"bmis", one(0065400), one(0177400), "Bg"},
{"bges", one(0066000), one(0177400), "Bg"},
{"blts", one(0066400), one(0177400), "Bg"},
{"bgts", one(0067000), one(0177400), "Bg"},
{"bles", one(0067400), one(0177400), "Bg"},

/* Alternate mnemonics for SUN */

{"jbsr", one(0060400), one(0177400), "Bg"},
{"jbsr", one(0047200), one(0177700), "!s"},
{"jra", one(0060000), one(0177400), "Bg"},
{"jra", one(0047300), one(0177700), "!s"},

{"jhi", one(0061000), one(0177400), "Bg"},
{"jls", one(0061400), one(0177400), "Bg"},
{"jcc", one(0062000), one(0177400), "Bg"},
{"jcs", one(0062400), one(0177400), "Bg"},
{"jne", one(0063000), one(0177400), "Bg"},
{"jeq", one(0063400), one(0177400), "Bg"},
{"jvc", one(0064000), one(0177400), "Bg"},
{"jvs", one(0064400), one(0177400), "Bg"},
{"jpl", one(0065000), one(0177400), "Bg"},
{"jmi", one(0065400), one(0177400), "Bg"},
{"jge", one(0066000), one(0177400), "Bg"},
{"jlt", one(0066400), one(0177400), "Bg"},
{"jgt", one(0067000), one(0177400), "Bg"},
{"jle", one(0067400), one(0177400), "Bg"},

/* Short offsets are ignored */

{"jbsrs", one(0060400), one(0177400), "Bg"},
{"jras", one(0060000), one(0177400), "Bg"},
{"jhis", one(0061000), one(0177400), "Bg"},
{"jlss", one(0061400), one(0177400), "Bg"},
{"jccs", one(0062000), one(0177400), "Bg"},
{"jcss", one(0062400), one(0177400), "Bg"},
{"jnes", one(0063000), one(0177400), "Bg"},
{"jeqs", one(0063400), one(0177400), "Bg"},
{"jvcs", one(0064000), one(0177400), "Bg"},
{"jvss", one(0064400), one(0177400), "Bg"},
{"jpls", one(0065000), one(0177400), "Bg"},
{"jmis", one(0065400), one(0177400), "Bg"},
{"jges", one(0066000), one(0177400), "Bg"},
{"jlts", one(0066400), one(0177400), "Bg"},
{"jgts", one(0067000), one(0177400), "Bg"},
{"jles", one(0067400), one(0177400), "Bg"},

{"movql", one(0070000), one(0170400), "MsDd"},
{"moveql", one(0070000), one(0170400), "MsDd"},
{"moval", one(0020100), one(0170700), "*lAd"},
{"movaw", one(0030100), one(0170700), "*wAd"},
{"movb", one(0010000), one(0170000), ";b$d"}, /* mov */
{"movl", one(0070000), one(0170400), "MsDd"}, /* movq written as mov */
{"movl", one(0020000), one(0170000), "*l$d"},
{"movl", one(0020100), one(0170700), "*lAd"},
{"movl", one(0047140), one(0177770), "AsUd"}, /* mov to USP */
{"movl", one(0047150), one(0177770), "UdAs"}, /* mov from USP */
{"movc", one(0047173), one(0177777), "R1Jj"},
{"movc", one(0047173), one(0177777), "R1#j"},
{"movc", one(0047172), one(0177777), "JjR1"},
{"movc", one(0047172), one(0177777), "#jR1"},
{"movml", one(0044300), one(0177700), "#w&s"}, /* movm reg to mem. */
{"movml", one(0044340), one(0177770), "#w-s"}, /* movm reg to autodecrement. */
{"movml", one(0046300), one(0177700), "!s#w"}, /* movm mem to reg. */
{"movml", one(0046330), one(0177770), "+s#w"}, /* movm autoinc to reg. */
{"movml", one(0044300), one(0177700), "Lw&s"}, /* movm reg to mem. */
{"movml", one(0044340), one(0177770), "lw-s"}, /* movm reg to autodecrement. */
{"movml", one(0046300), one(0177700), "!sLw"}, /* movm mem to reg. */
{"movml", one(0046330), one(0177770), "+sLw"}, /* movm autoinc to reg. */
{"movmw", one(0044200), one(0177700), "#w&s"}, /* movm reg to mem. */
{"movmw", one(0044240), one(0177770), "#w-s"}, /* movm reg to autodecrement. */
{"movmw", one(0046200), one(0177700), "!s#w"}, /* movm mem to reg. */
{"movmw", one(0046230), one(0177770), "+s#w"}, /* movm autoinc to reg. */
{"movmw", one(0044200), one(0177700), "Lw&s"}, /* movm reg to mem. */
{"movmw", one(0044240), one(0177770), "lw-s"}, /* movm reg to autodecrement. */
{"movmw", one(0046200), one(0177700), "!sLw"}, /* movm mem to reg. */
{"movmw", one(0046230), one(0177770), "+sLw"}, /* movm autoinc to reg. */
{"movpl", one(0000510), one(0170770), "dsDd"}, /* memory to register */
{"movpl", one(0000710), one(0170770), "Ddds"}, /* register to memory */
{"movpw", one(0000410), one(0170770), "dsDd"}, /* memory to register */
{"movpw", one(0000610), one(0170770), "Ddds"}, /* register to memory */
{"movq", one(0070000), one(0170400), "MsDd"},
{"movw", one(0030000), one(0170000), "*w$d"},
{"movw", one(0030100), one(0170700), "*wAd"}, /* mova, written as mov */
{"movw", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */
{"movw", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */
{"movw", one(0042300), one(0177700), ";wCd"}, /* mov to ccr */
{"movw", one(0043300), one(0177700), ";wSd"}, /* mov to sr */

{"movsb", two(0007000, 0), two(0177700, 07777), "~sR1"},
{"movsb", two(0007000, 04000), two(0177700, 07777), "R1~s"},
{"movsl", two(0007200, 0), two(0177700, 07777), "~sR1"},
{"movsl", two(0007200, 04000), two(0177700, 07777), "R1~s"},
{"movsw", two(0007100, 0), two(0177700, 07777), "~sR1"},
{"movsw", two(0007100, 04000), two(0177700, 07777), "R1~s"},

#ifdef m68851
/* name */ /* opcode */ /* match */ /* args */

{"pbac", one(0xf0c7), one(0xffbf), "Bc"},
{"pbacw", one(0xf087), one(0xffbf), "Bc"},
{"pbas", one(0xf0c6), one(0xffbf), "Bc"},
{"pbasw", one(0xf086), one(0xffbf), "Bc"},
{"pbbc", one(0xf0c1), one(0xffbf), "Bc"},
{"pbbcw", one(0xf081), one(0xffbf), "Bc"},
{"pbbs", one(0xf0c0), one(0xffbf), "Bc"},
{"pbbsw", one(0xf080), one(0xffbf), "Bc"},
{"pbcc", one(0xf0cf), one(0xffbf), "Bc"},
{"pbccw", one(0xf08f), one(0xffbf), "Bc"},
{"pbcs", one(0xf0ce), one(0xffbf), "Bc"},
{"pbcsw", one(0xf08e), one(0xffbf), "Bc"},
{"pbgc", one(0xf0cd), one(0xffbf), "Bc"},
{"pbgcw", one(0xf08d), one(0xffbf), "Bc"},
{"pbgs", one(0xf0cc), one(0xffbf), "Bc"},
{"pbgsw", one(0xf08c), one(0xffbf), "Bc"},
{"pbic", one(0xf0cb), one(0xffbf), "Bc"},
{"pbicw", one(0xf08b), one(0xffbf), "Bc"},
{"pbis", one(0xf0ca), one(0xffbf), "Bc"},
{"pbisw", one(0xf08a), one(0xffbf), "Bc"},
{"pblc", one(0xf0c3), one(0xffbf), "Bc"},
{"pblcw", one(0xf083), one(0xffbf), "Bc"},
{"pbls", one(0xf0c2), one(0xffbf), "Bc"},
{"pblsw", one(0xf082), one(0xffbf), "Bc"},
{"pbsc", one(0xf0c5), one(0xffbf), "Bc"},
{"pbscw", one(0xf085), one(0xffbf), "Bc"},
{"pbss", one(0xf0c4), one(0xffbf), "Bc"},
{"pbssw", one(0xf084), one(0xffbf), "Bc"},
{"pbwc", one(0xf0c9), one(0xffbf), "Bc"},
{"pbwcw", one(0xf089), one(0xffbf), "Bc"},
{"pbws", one(0xf0c8), one(0xffbf), "Bc"},
{"pbwsw", one(0xf088), one(0xffbf), "Bc"},


{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"},
{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"},
{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"},
{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"},
{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"},
{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"},
{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"},
{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"},
{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"},
{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"},
{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"},
{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"},
{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"},
{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"},
{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"},
{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"},

{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" },

{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" },
{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" },
{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" },
{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" },
{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" },
{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" },

{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" },
{"pflushs", two(0xf000, 0x3c10), two(0xfff8, 0xfe00), "T3T9&s" },
{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" },
{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" },
{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" },
{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"},

{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" },

{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" },
{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" },
{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" },
{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" },
{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" },
{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" },

/* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */
{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" },
{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" },
{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" },
{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" },

/* BADx, BACx */
{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" },
{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" },

/* PSR, PCSR */
/* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */
{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" },
{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" },
{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" },

{"prestore", one(0xf140), one(0xffc0), "&s"},
{"prestore", one(0xf158), one(0xfff8), "+s"},
{"psave", one(0xf100), one(0xffc0), "&s"},
{"psave", one(0xf100), one(0xffc0), "+s"},

{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"},
{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"},
{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"},
{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"},
{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"},
{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"},
{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"},
{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"},
{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"},
{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"},
{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"},
{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"},
{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"},
{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"},
{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"},
{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"},

{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" },
{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" },
{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" },
{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" },
{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" },
{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" },

{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" },
{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" },
{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" },
{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" },
{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" },
{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" },

{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"},
{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"},
{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""},

{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"},
{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"},
{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""},

{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"},
{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"},
{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""},

{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"},
{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"},
{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""},

{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"},
{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"},
{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""},

{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"},
{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"},
{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""},

{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"},
{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"},
{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""},

{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"},
{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"},
{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""},

{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"},
{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"},
{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""},

{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"},
{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"},
{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""},

{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"},
{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"},
{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""},

{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"},
{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"},
{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""},

{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"},
{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"},
{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""},

{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"},
{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"},
{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""},

{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"},
{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"},
{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""},

{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"},
{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"},
{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""},

{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"},
{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" },

#endif /* m68851 */

};

int numopcodes=sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]);

struct m68k_opcode *endop = m68k_opcodes+sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]);
gas-1.38/m-hpux.h 666 12412 0 1660 4432623111 11147 0ustar randy/* m-hpux.h -- Header to compile the 68020 assembler under HP-UX
Copyright (C) 1988 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 header file contains the #defines specific
to HPUX changes sent me by [email protected] */
#ifndef hpux
#define hpux
#endif
gas-1.38/m-sun3.h 666 12412 0 2136 4403071540 11053 0ustar randy/* m-sun3.h -- 68020 version of the assembler for the Sun-3
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 header file contains the #defines specific
to SUN computer SUN 3 series computers. (The only kind
we have around here, unfortunatly.)

Rumor has it that this file will work on the Sun-2 if the assembler
is called with -m68010 This is not tested. */


#define M_SUN 1
#define SUN_ASM_SYNTAX
gas-1.38/m-generic.h 666 12412 0 1456 4403071542 11605 0ustar randy/* m-generic.h Generic machine-specific 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. */

#define M_GENERIC 1
gas-1.38/i386.c 666 12412 0 166573 4712105374 10503 0ustar randy/* 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 ([email protected]).
Bugs & suggestions are completely welcome. This is free software.
Please help us make it better.
*/

#include
#include
#include

#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) {
/* (%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> (,) -- no base register with disp
Case 3: (, ) --- 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 %s where = 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 % 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);
}

gas-1.38/i386.h 666 12412 0 25253 4403071546 10455 0ustar randy/* 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 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;
gas-1.38/i386-opcode.h 644 11660 0 73263 4557127752 11534 0ustar hack/* 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},